mirror of
https://github.com/HifiExperiments/overte.git
synced 2025-04-11 05:43:04 +02:00
Merge branch 'master' into tony/neuron-plugin
This commit is contained in:
commit
878fe80040
163 changed files with 5320 additions and 1680 deletions
|
@ -197,6 +197,10 @@ if (WIN32)
|
|||
add_paths_to_fixup_libs("${QT_DIR}/bin")
|
||||
endif ()
|
||||
|
||||
if (NOT DEFINED SERVER_ONLY)
|
||||
set(SERVER_ONLY 0)
|
||||
endif()
|
||||
|
||||
# add subdirectories for all targets
|
||||
if (NOT ANDROID)
|
||||
add_subdirectory(assignment-client)
|
||||
|
@ -205,14 +209,16 @@ if (NOT ANDROID)
|
|||
set_target_properties(domain-server PROPERTIES FOLDER "Apps")
|
||||
add_subdirectory(ice-server)
|
||||
set_target_properties(ice-server PROPERTIES FOLDER "Apps")
|
||||
add_subdirectory(interface)
|
||||
set_target_properties(interface PROPERTIES FOLDER "Apps")
|
||||
add_subdirectory(stack-manager)
|
||||
set_target_properties(stack-manager PROPERTIES FOLDER "Apps")
|
||||
add_subdirectory(tests)
|
||||
add_subdirectory(plugins)
|
||||
if (NOT SERVER_ONLY)
|
||||
add_subdirectory(interface)
|
||||
set_target_properties(interface PROPERTIES FOLDER "Apps")
|
||||
add_subdirectory(tests)
|
||||
add_subdirectory(plugins)
|
||||
endif()
|
||||
add_subdirectory(tools)
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
if (ANDROID OR DESKTOP_GVR)
|
||||
add_subdirectory(gvr-interface)
|
||||
|
|
|
@ -33,7 +33,7 @@ bool OctreeQueryNode::packetIsDuplicate() const {
|
|||
// of the entire packet, we need to compare only the packet content...
|
||||
|
||||
if (_lastOctreePacketLength == _octreePacket->getPayloadSize()) {
|
||||
if (memcmp(&_lastOctreePayload + OCTREE_PACKET_EXTRA_HEADERS_SIZE,
|
||||
if (memcmp(_lastOctreePayload.data() + OCTREE_PACKET_EXTRA_HEADERS_SIZE,
|
||||
_octreePacket->getPayload() + OCTREE_PACKET_EXTRA_HEADERS_SIZE,
|
||||
_octreePacket->getPayloadSize() - OCTREE_PACKET_EXTRA_HEADERS_SIZE) == 0) {
|
||||
return true;
|
||||
|
@ -101,7 +101,7 @@ void OctreeQueryNode::resetOctreePacket() {
|
|||
// scene information, (e.g. the root node packet of a static scene), we can use this as a strategy for reducing
|
||||
// packet send rate.
|
||||
_lastOctreePacketLength = _octreePacket->getPayloadSize();
|
||||
memcpy(&_lastOctreePayload, _octreePacket->getPayload(), _lastOctreePacketLength);
|
||||
memcpy(_lastOctreePayload.data(), _octreePacket->getPayload(), _lastOctreePacketLength);
|
||||
|
||||
// If we're moving, and the client asked for low res, then we force monochrome, otherwise, use
|
||||
// the clients requested color state.
|
||||
|
|
77
cmake/externals/qxmpp/CMakeLists.txt
vendored
77
cmake/externals/qxmpp/CMakeLists.txt
vendored
|
@ -1,77 +0,0 @@
|
|||
set(EXTERNAL_NAME qxmpp)
|
||||
|
||||
# we need to find qmake inside QT_DIR
|
||||
find_program(QMAKE_COMMAND NAME qmake PATHS ${QT_DIR}/bin $ENV{QTTOOLDIR} NO_DEFAULT_PATH)
|
||||
|
||||
if (NOT QMAKE_COMMAND)
|
||||
message(FATAL_ERROR "Could not find qmake. Qxmpp cannot be compiled without qmake.")
|
||||
endif ()
|
||||
|
||||
if (ANDROID)
|
||||
set(ANDROID_CMAKE_ARGS "-DCMAKE_TOOLCHAIN_FILE=${CMAKE_TOOLCHAIN_FILE}" "-DANDROID_NATIVE_API_LEVEL=19")
|
||||
endif ()
|
||||
|
||||
if (WIN32)
|
||||
find_program(PLATFORM_BUILD_COMMAND nmake PATHS "C:/Program Files (x86)/Microsoft Visual Studio 12.0/VC/bin")
|
||||
|
||||
if (NOT PLATFORM_BUILD_COMMAND)
|
||||
message(FATAL_ERROR "You asked CMake to grap QXmpp and build it, but nmake was not found. Please make sure the folder containing nmake.exe is in your PATH.")
|
||||
endif ()
|
||||
else ()
|
||||
find_program(PLATFORM_BUILD_COMMAND make)
|
||||
endif ()
|
||||
|
||||
include(ExternalProject)
|
||||
ExternalProject_Add(
|
||||
${EXTERNAL_NAME}
|
||||
URL http://qxmpp.googlecode.com/files/qxmpp-0.7.6.tar.gz
|
||||
URL_MD5 ee45a97313306ded2ff0f6618a3ed1e1
|
||||
BUILD_IN_SOURCE 1
|
||||
PATCH_COMMAND patch -p2 -t -N --verbose < ${CMAKE_CURRENT_SOURCE_DIR}/qxmpp.patch
|
||||
CONFIGURE_COMMAND ${QMAKE_COMMAND} PREFIX=<INSTALL_DIR>
|
||||
BUILD_COMMAND ${PLATFORM_BUILD_COMMAND}
|
||||
INSTALL_COMMAND ${PLATFORM_BUILD_COMMAND} install
|
||||
LOG_DOWNLOAD 1
|
||||
LOG_CONFIGURE 1
|
||||
LOG_BUILD 1
|
||||
)
|
||||
|
||||
# Hide this external target (for ide users)
|
||||
set_target_properties(${EXTERNAL_NAME} PROPERTIES FOLDER "hidden/externals")
|
||||
|
||||
ExternalProject_Get_Property(${EXTERNAL_NAME} INSTALL_DIR)
|
||||
|
||||
if (CMAKE_GENERATOR STREQUAL Xcode)
|
||||
find_program(DITTO_COMMAND ditto)
|
||||
|
||||
ExternalProject_Add_Step(
|
||||
${EXTERNAL_NAME}
|
||||
copy-from-xcode-install
|
||||
COMMENT "Copying from /tmp/hifi.dst${INSTALL_DIR} to move install to proper location"
|
||||
COMMAND ${DITTO_COMMAND} /tmp/hifi.dst${INSTALL_DIR} ${INSTALL_DIR}
|
||||
DEPENDEES install
|
||||
LOG 1
|
||||
)
|
||||
endif ()
|
||||
|
||||
string(TOUPPER ${EXTERNAL_NAME} EXTERNAL_NAME_UPPER)
|
||||
set(${EXTERNAL_NAME_UPPER}_INCLUDE_DIRS ${INSTALL_DIR}/include CACHE FILEPATH "Path to Qxmpp include directory")
|
||||
|
||||
set(_LIB_DIR ${INSTALL_DIR}/lib)
|
||||
|
||||
if (WIN32)
|
||||
set(_LIB_EXT "0.lib")
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_DLL_PATH ${_LIB_DIR} CACHE PATH "Location of QXmpp DLL")
|
||||
else ()
|
||||
if (APPLE)
|
||||
set(_LIB_EXT ".dylib")
|
||||
else ()
|
||||
set(_LIB_EXT ".so")
|
||||
endif ()
|
||||
|
||||
set(_LIB_PREFIX "lib")
|
||||
endif ()
|
||||
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_RELEASE ${_LIB_DIR}/${_LIB_PREFIX}qxmpp${_LIB_EXT} CACHE FILEPATH "Path to QXmpp release library")
|
||||
set(${EXTERNAL_NAME_UPPER}_LIBRARY_DEBUG "" CACHE FILEPATH "Path to QXmpp debug library")
|
72
examples/acScripts/triggeredRecordingOnAC.js
Normal file
72
examples/acScripts/triggeredRecordingOnAC.js
Normal file
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// triggeredRecordingOnAC.js
|
||||
// examples/acScripts
|
||||
//
|
||||
// Created by Thijs Wenker on 12/21/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This is the triggered rocording script used in the winterSmashUp target practice game.
|
||||
// Change the CLIP_URL to your asset,
|
||||
// the RECORDING_CHANNEL and RECORDING_CHANNEL_MESSAGE are used to trigger it i.e.:
|
||||
// Messages.sendMessage("PlayBackOnAssignment", "BowShootingGameWelcome");
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
const CLIP_URL = "atp:3fbe82f2153c443f12f9a2b14ce2d7fa2fff81977263746d9e0885ea5aabed62.hfr";
|
||||
|
||||
const RECORDING_CHANNEL = 'PlayBackOnAssignment';
|
||||
const RECORDING_CHANNEL_MESSAGE = 'BowShootingGameWelcome'; // For each different assignment add a different message here.
|
||||
const PLAY_FROM_CURRENT_LOCATION = true;
|
||||
const USE_DISPLAY_NAME = true;
|
||||
const USE_ATTACHMENTS = true;
|
||||
const USE_AVATAR_MODEL = true;
|
||||
const AUDIO_OFFSET = 0.0;
|
||||
const STARTING_TIME = 0.0;
|
||||
const COOLDOWN_PERIOD = 0; // The period in ms that no animations can be played after one has been played already
|
||||
|
||||
var isPlaying = false;
|
||||
var isPlayable = true;
|
||||
|
||||
var playRecording = function() {
|
||||
if (!isPlayable || isPlaying) {
|
||||
return;
|
||||
}
|
||||
Agent.isAvatar = true;
|
||||
Recording.setPlayFromCurrentLocation(PLAY_FROM_CURRENT_LOCATION);
|
||||
Recording.setPlayerUseDisplayName(USE_DISPLAY_NAME);
|
||||
Recording.setPlayerUseAttachments(USE_ATTACHMENTS);
|
||||
Recording.setPlayerUseHeadModel(false);
|
||||
Recording.setPlayerUseSkeletonModel(USE_AVATAR_MODEL);
|
||||
Recording.setPlayerLoop(false);
|
||||
Recording.setPlayerTime(STARTING_TIME);
|
||||
Recording.setPlayerAudioOffset(AUDIO_OFFSET);
|
||||
Recording.loadRecording(CLIP_URL);
|
||||
Recording.startPlaying();
|
||||
isPlaying = true;
|
||||
isPlayable = false; // Set this true again after the cooldown period
|
||||
};
|
||||
|
||||
Script.update.connect(function(deltaTime) {
|
||||
if (isPlaying && !Recording.isPlaying()) {
|
||||
print('Reached the end of the recording. Resetting.');
|
||||
isPlaying = false;
|
||||
Agent.isAvatar = false;
|
||||
if (COOLDOWN_PERIOD === 0) {
|
||||
isPlayable = true;
|
||||
return;
|
||||
}
|
||||
Script.setTimeout(function () {
|
||||
isPlayable;
|
||||
}, COOLDOWN_PERIOD);
|
||||
}
|
||||
});
|
||||
|
||||
Messages.subscribe(RECORDING_CHANNEL);
|
||||
|
||||
Messages.messageReceived.connect(function (channel, message, senderID) {
|
||||
if (channel === RECORDING_CHANNEL && message === RECORDING_CHANNEL_MESSAGE) {
|
||||
playRecording();
|
||||
}
|
||||
});
|
|
@ -1,5 +1,4 @@
|
|||
// handControllerGrab.js
|
||||
// examples
|
||||
//
|
||||
// Created by Eric Levin on 9/2/15
|
||||
// Additions by James B. Pollack @imgntn on 9/24/2015
|
||||
|
@ -7,6 +6,7 @@
|
|||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Grabs physically moveable entities with hydra-like controllers; it works for either near or far objects.
|
||||
// Also supports touch and equipping objects.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
@ -14,7 +14,6 @@
|
|||
|
||||
Script.include("../libraries/utils.js");
|
||||
|
||||
|
||||
//
|
||||
// add lines where the hand ray picking is happening
|
||||
//
|
||||
|
@ -54,6 +53,7 @@ var LINE_ENTITY_DIMENSIONS = {
|
|||
y: 1000,
|
||||
z: 1000
|
||||
};
|
||||
|
||||
var LINE_LENGTH = 500;
|
||||
var PICK_MAX_DISTANCE = 500; // max length of pick-ray
|
||||
|
||||
|
@ -116,6 +116,17 @@ var DEFAULT_GRABBABLE_DATA = {
|
|||
invertSolidWhileHeld: false
|
||||
};
|
||||
|
||||
//we've created various ways of visualizing looking for and moving distant objects
|
||||
var USE_ENTITY_LINES_FOR_SEARCHING = false;
|
||||
var USE_OVERLAY_LINES_FOR_SEARCHING = false;
|
||||
var USE_PARTICLE_BEAM_FOR_SEARCHING = true;
|
||||
|
||||
var USE_ENTITY_LINES_FOR_MOVING = false;
|
||||
var USE_OVERLAY_LINES_FOR_MOVING = false;
|
||||
var USE_PARTICLE_BEAM_FOR_MOVING = true;
|
||||
|
||||
var USE_SPOTLIGHT = false;
|
||||
var USE_POINTLIGHT = false;
|
||||
|
||||
// states for the state machine
|
||||
var STATE_OFF = 0;
|
||||
|
@ -137,6 +148,7 @@ var STATE_WAITING_FOR_BUMPER_RELEASE = 15;
|
|||
var STATE_EQUIP_SPRING = 16;
|
||||
|
||||
|
||||
|
||||
function stateToName(state) {
|
||||
switch (state) {
|
||||
case STATE_OFF:
|
||||
|
@ -218,6 +230,7 @@ function getSpatialOffsetPosition(hand, spatialKey) {
|
|||
}
|
||||
|
||||
var yFlip = Quat.angleAxis(180, Vec3.UNIT_Y);
|
||||
|
||||
function getSpatialOffsetRotation(hand, spatialKey) {
|
||||
var rotation = Quat.IDENTITY;
|
||||
|
||||
|
@ -261,7 +274,13 @@ function MyController(hand) {
|
|||
this.triggerValue = 0; // rolling average of trigger value
|
||||
this.rawTriggerValue = 0;
|
||||
this.rawBumperValue = 0;
|
||||
//for visualizations
|
||||
this.overlayLine = null;
|
||||
this.particleBeam = null;
|
||||
|
||||
//for lights
|
||||
this.spotlight = null;
|
||||
this.pointlight = null;
|
||||
this.overlayLine = null;
|
||||
|
||||
this.ignoreIK = false;
|
||||
|
@ -329,7 +348,7 @@ function MyController(hand) {
|
|||
print("STATE: " + stateToName(this.state) + " --> " + stateToName(newState) + ", hand: " + this.hand);
|
||||
}
|
||||
this.state = newState;
|
||||
}
|
||||
};
|
||||
|
||||
this.debugLine = function(closePoint, farPoint, color) {
|
||||
Entities.addEntity({
|
||||
|
@ -349,7 +368,38 @@ function MyController(hand) {
|
|||
}
|
||||
})
|
||||
});
|
||||
};
|
||||
|
||||
this.lineOn = function(closePoint, farPoint, color) {
|
||||
// draw a line
|
||||
if (this.pointer === null) {
|
||||
this.pointer = Entities.addEntity({
|
||||
type: "Line",
|
||||
name: "grab pointer",
|
||||
dimensions: LINE_ENTITY_DIMENSIONS,
|
||||
visible: true,
|
||||
position: closePoint,
|
||||
linePoints: [ZERO_VEC, farPoint],
|
||||
color: color,
|
||||
lifetime: LIFETIME,
|
||||
collisionsWillMove: false,
|
||||
ignoreForCollisions: true,
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
grabbable: false
|
||||
}
|
||||
})
|
||||
});
|
||||
} else {
|
||||
var age = Entities.getEntityProperties(this.pointer, "age").age;
|
||||
this.pointer = Entities.editEntity(this.pointer, {
|
||||
position: closePoint,
|
||||
linePoints: [ZERO_VEC, farPoint],
|
||||
color: color,
|
||||
lifetime: age + LIFETIME
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.overlayLineOn = function(closePoint, farPoint, color) {
|
||||
if (this.overlayLine === null) {
|
||||
|
@ -376,36 +426,209 @@ function MyController(hand) {
|
|||
alpha: 1
|
||||
});
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.lineOn = function(closePoint, farPoint, color) {
|
||||
// draw a line
|
||||
if (this.pointer === null) {
|
||||
this.pointer = Entities.addEntity({
|
||||
type: "Line",
|
||||
name: "grab pointer",
|
||||
dimensions: LINE_ENTITY_DIMENSIONS,
|
||||
visible: true,
|
||||
position: closePoint,
|
||||
linePoints: [ZERO_VEC, farPoint],
|
||||
color: color,
|
||||
lifetime: LIFETIME,
|
||||
collisionsWillMove: false,
|
||||
ignoreForCollisions: true,
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
grabbable: false
|
||||
}
|
||||
})
|
||||
});
|
||||
this.handleParticleBeam = function(position, orientation, color) {
|
||||
|
||||
var rotation = Quat.angleAxis(0, {
|
||||
x: 1,
|
||||
y: 0,
|
||||
z: 0
|
||||
});
|
||||
|
||||
var finalRotation = Quat.multiply(orientation, rotation);
|
||||
var lifespan = LINE_LENGTH / 10;
|
||||
var speed = 5;
|
||||
var spread = 2;
|
||||
if (this.particleBeam === null) {
|
||||
this.createParticleBeam(position, finalRotation, color, speed, spread, lifespan);
|
||||
} else {
|
||||
var age = Entities.getEntityProperties(this.pointer, "age").age;
|
||||
this.pointer = Entities.editEntity(this.pointer, {
|
||||
position: closePoint,
|
||||
linePoints: [ZERO_VEC, farPoint],
|
||||
this.updateParticleBeam(position, finalRotation, color, speed, spread, lifespan);
|
||||
}
|
||||
};
|
||||
|
||||
this.handleDistantParticleBeam = function(handPosition, objectPosition, color) {
|
||||
|
||||
var handToObject = Vec3.subtract(objectPosition, handPosition);
|
||||
var finalRotation = Quat.rotationBetween(Vec3.multiply(-1, Vec3.UP), handToObject);
|
||||
|
||||
var distance = Vec3.distance(handPosition, objectPosition);
|
||||
var speed = 5;
|
||||
var spread = 0;
|
||||
|
||||
var lifespan = distance / speed;
|
||||
|
||||
|
||||
if (this.particleBeam === null) {
|
||||
this.createParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan);
|
||||
} else {
|
||||
this.updateParticleBeam(objectPosition, finalRotation, color, speed, spread, lifespan);
|
||||
}
|
||||
};
|
||||
|
||||
this.createParticleBeam = function(position, orientation, color, speed, spread, lifespan) {
|
||||
|
||||
var particleBeamProperties = {
|
||||
type: "ParticleEffect",
|
||||
isEmitting: true,
|
||||
position: position,
|
||||
visible: false,
|
||||
"name": "Particle Beam",
|
||||
"color": color,
|
||||
"maxParticles": 2000,
|
||||
"lifespan": lifespan,
|
||||
"emitRate": 50,
|
||||
"emitSpeed": speed,
|
||||
"speedSpread": spread,
|
||||
"emitOrientation": {
|
||||
"x": -1,
|
||||
"y": 0,
|
||||
"z": 0,
|
||||
"w": 1
|
||||
},
|
||||
"emitDimensions": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"emitRadiusStart": 0.5,
|
||||
"polarStart": 0,
|
||||
"polarFinish": 0,
|
||||
"azimuthStart": -3.1415927410125732,
|
||||
"azimuthFinish": 3.1415927410125732,
|
||||
"emitAcceleration": {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
"accelerationSpread": {
|
||||
"x": 0,
|
||||
"y": 0,
|
||||
"z": 0
|
||||
},
|
||||
"particleRadius": 0.015,
|
||||
"radiusSpread": 0.005,
|
||||
// "radiusStart": 0.01,
|
||||
// "radiusFinish": 0.01,
|
||||
// "colorSpread": {
|
||||
// "red": 0,
|
||||
// "green": 0,
|
||||
// "blue": 0
|
||||
// },
|
||||
// "colorStart": color,
|
||||
// "colorFinish": color,
|
||||
"alpha": 1,
|
||||
"alphaSpread": 0,
|
||||
"alphaStart": 1,
|
||||
"alphaFinish": 1,
|
||||
"additiveBlending": 0,
|
||||
"textures": "https://hifi-content.s3.amazonaws.com/alan/dev/textures/grabsprite-3.png"
|
||||
}
|
||||
|
||||
this.particleBeam = Entities.addEntity(particleBeamProperties);
|
||||
};
|
||||
|
||||
this.updateParticleBeam = function(position, orientation, color, speed, spread, lifespan) {
|
||||
Entities.editEntity(this.particleBeam, {
|
||||
rotation: orientation,
|
||||
position: position,
|
||||
visible: true,
|
||||
color: color,
|
||||
lifetime: age + LIFETIME
|
||||
emitSpeed: speed,
|
||||
speedSpread: spread,
|
||||
lifespan: lifespan
|
||||
})
|
||||
|
||||
};
|
||||
|
||||
this.evalLightWorldTransform = function(modelPos, modelRot) {
|
||||
|
||||
var MODEL_LIGHT_POSITION = {
|
||||
x: 0,
|
||||
y: -0.3,
|
||||
z: 0
|
||||
};
|
||||
|
||||
var MODEL_LIGHT_ROTATION = Quat.angleAxis(-90, {
|
||||
x: 1,
|
||||
y: 0,
|
||||
z: 0
|
||||
});
|
||||
|
||||
return {
|
||||
p: Vec3.sum(modelPos, Vec3.multiplyQbyV(modelRot, MODEL_LIGHT_POSITION)),
|
||||
q: Quat.multiply(modelRot, MODEL_LIGHT_ROTATION)
|
||||
};
|
||||
};
|
||||
|
||||
this.handleSpotlight = function(parentID, position) {
|
||||
var LIFETIME = 100;
|
||||
|
||||
var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']);
|
||||
|
||||
var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation);
|
||||
var lightProperties = {
|
||||
type: "Light",
|
||||
isSpotlight: true,
|
||||
dimensions: {
|
||||
x: 2,
|
||||
y: 2,
|
||||
z: 20
|
||||
},
|
||||
parentID: parentID,
|
||||
color: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
},
|
||||
intensity: 2,
|
||||
exponent: 0.3,
|
||||
cutoff: 20,
|
||||
lifetime: LIFETIME,
|
||||
position: lightTransform.p,
|
||||
};
|
||||
|
||||
if (this.spotlight === null) {
|
||||
this.spotlight = Entities.addEntity(lightProperties);
|
||||
} else {
|
||||
Entities.editEntity(this.spotlight, {
|
||||
//without this, this light would maintain rotation with its parent
|
||||
rotation: Quat.fromPitchYawRollDegrees(-90, 0, 0),
|
||||
})
|
||||
}
|
||||
};
|
||||
|
||||
this.handlePointLight = function(parentID, position) {
|
||||
var LIFETIME = 100;
|
||||
|
||||
var modelProperties = Entities.getEntityProperties(parentID, ['position', 'rotation']);
|
||||
var lightTransform = this.evalLightWorldTransform(modelProperties.position, modelProperties.rotation);
|
||||
|
||||
var lightProperties = {
|
||||
type: "Light",
|
||||
isSpotlight: false,
|
||||
dimensions: {
|
||||
x: 2,
|
||||
y: 2,
|
||||
z: 20
|
||||
},
|
||||
parentID: parentID,
|
||||
color: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
},
|
||||
intensity: 2,
|
||||
exponent: 0.3,
|
||||
cutoff: 20,
|
||||
lifetime: LIFETIME,
|
||||
position: lightTransform.p,
|
||||
};
|
||||
|
||||
if (this.pointlight === null) {
|
||||
this.pointlight = Entities.addEntity(lightProperties);
|
||||
} else {
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -423,6 +646,41 @@ function MyController(hand) {
|
|||
this.overlayLine = null;
|
||||
};
|
||||
|
||||
this.particleBeamOff = function() {
|
||||
if (this.particleBeam !== null) {
|
||||
Entities.editEntity(this.particleBeam, {
|
||||
visible: false
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
this.turnLightsOff = function() {
|
||||
if (this.spotlight !== null) {
|
||||
Entities.deleteEntity(this.spotlight);
|
||||
this.spotlight = null;
|
||||
}
|
||||
|
||||
if (this.pointlight !== null) {
|
||||
Entities.deleteEntity(this.pointlight);
|
||||
this.pointlight = null;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
this.turnOffVisualizations = function() {
|
||||
if (USE_ENTITY_LINES_FOR_SEARCHING === true || USE_ENTITY_LINES_FOR_MOVING === true) {
|
||||
this.lineOff();
|
||||
}
|
||||
|
||||
if (USE_OVERLAY_LINES_FOR_SEARCHING === true || USE_OVERLAY_LINES_FOR_MOVING === true) {
|
||||
this.overlayLineOff();
|
||||
}
|
||||
|
||||
if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) {
|
||||
this.particleBeamOff();
|
||||
}
|
||||
};
|
||||
|
||||
this.triggerPress = function(value) {
|
||||
_this.rawTriggerValue = value;
|
||||
};
|
||||
|
@ -431,7 +689,6 @@ function MyController(hand) {
|
|||
_this.rawBumperValue = value;
|
||||
};
|
||||
|
||||
|
||||
this.updateSmoothedTrigger = function() {
|
||||
var triggerValue = this.rawTriggerValue;
|
||||
// smooth out trigger value
|
||||
|
@ -454,12 +711,11 @@ function MyController(hand) {
|
|||
|
||||
this.bumperSqueezed = function() {
|
||||
return _this.rawBumperValue > BUMPER_ON_VALUE;
|
||||
}
|
||||
};
|
||||
|
||||
this.bumperReleased = function() {
|
||||
return _this.rawBumperValue < BUMPER_ON_VALUE;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.off = function() {
|
||||
if (this.triggerSmoothedSqueezed()) {
|
||||
|
@ -472,7 +728,7 @@ function MyController(hand) {
|
|||
this.setState(STATE_EQUIP_SEARCHING);
|
||||
return;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.search = function() {
|
||||
this.grabbedEntity = null;
|
||||
|
@ -671,8 +927,19 @@ function MyController(hand) {
|
|||
}
|
||||
}
|
||||
|
||||
//this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
|
||||
//search line visualizations
|
||||
if (USE_ENTITY_LINES_FOR_SEARCHING === true) {
|
||||
this.lineOn(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
|
||||
}
|
||||
|
||||
if (USE_OVERLAY_LINES_FOR_SEARCHING === true) {
|
||||
this.overlayLineOn(distantPickRay.origin, Vec3.sum(distantPickRay.origin, Vec3.multiply(distantPickRay.direction, LINE_LENGTH)), NO_INTERSECT_COLOR);
|
||||
}
|
||||
|
||||
if (USE_PARTICLE_BEAM_FOR_SEARCHING === true) {
|
||||
this.handleParticleBeam(distantPickRay.origin, this.getHandRotation(), NO_INTERSECT_COLOR);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
this.distanceHolding = function() {
|
||||
|
@ -725,7 +992,7 @@ function MyController(hand) {
|
|||
this.currentAvatarPosition = MyAvatar.position;
|
||||
this.currentAvatarOrientation = MyAvatar.orientation;
|
||||
|
||||
this.overlayLineOff();
|
||||
this.turnOffVisualizations();
|
||||
};
|
||||
|
||||
this.continueDistanceHolding = function() {
|
||||
|
@ -751,7 +1018,6 @@ function MyController(hand) {
|
|||
return;
|
||||
}
|
||||
|
||||
this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR);
|
||||
|
||||
// the action was set up on a previous call. update the targets.
|
||||
var radius = Vec3.distance(this.currentObjectPosition, handControllerPosition) *
|
||||
|
@ -815,17 +1081,43 @@ function MyController(hand) {
|
|||
this.currentObjectRotation = Quat.multiply(handChange, this.currentObjectRotation);
|
||||
|
||||
Entities.callEntityMethod(this.grabbedEntity, "continueDistantGrab");
|
||||
|
||||
// mix in head motion
|
||||
if (MOVE_WITH_HEAD) {
|
||||
var objDistance = Vec3.length(objectToAvatar);
|
||||
var before = Vec3.multiplyQbyV(this.currentCameraOrientation, { x: 0.0, y: 0.0, z: objDistance });
|
||||
var after = Vec3.multiplyQbyV(Camera.orientation, { x: 0.0, y: 0.0, z: objDistance });
|
||||
var before = Vec3.multiplyQbyV(this.currentCameraOrientation, {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: objDistance
|
||||
});
|
||||
var after = Vec3.multiplyQbyV(Camera.orientation, {
|
||||
x: 0.0,
|
||||
y: 0.0,
|
||||
z: objDistance
|
||||
});
|
||||
var change = Vec3.subtract(before, after);
|
||||
this.currentCameraOrientation = Camera.orientation;
|
||||
this.currentObjectPosition = Vec3.sum(this.currentObjectPosition, change);
|
||||
}
|
||||
|
||||
|
||||
//visualizations
|
||||
if (USE_ENTITY_LINES_FOR_MOVING === true) {
|
||||
this.lineOn(handPosition, Vec3.subtract(grabbedProperties.position, handPosition), INTERSECT_COLOR);
|
||||
}
|
||||
if (USE_OVERLAY_LINES_FOR_MOVING === true) {
|
||||
this.overlayLineOn(handPosition, grabbedProperties.position, INTERSECT_COLOR);
|
||||
}
|
||||
if (USE_PARTICLE_BEAM_FOR_MOVING === true) {
|
||||
this.handleDistantParticleBeam(handPosition, grabbedProperties.position, INTERSECT_COLOR)
|
||||
// this.handleDistantParticleBeam(handPosition, this.currentObjectPosition, INTERSECT_COLOR)
|
||||
}
|
||||
if (USE_POINTLIGHT === true) {
|
||||
this.handlePointLight(this.grabbedEntity);
|
||||
}
|
||||
if (USE_SPOTLIGHT === true) {
|
||||
this.handleSpotlight(this.grabbedEntity);
|
||||
}
|
||||
|
||||
Entities.updateAction(this.grabbedEntity, this.actionID, {
|
||||
targetPosition: this.currentObjectPosition,
|
||||
linearTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
|
||||
|
@ -833,6 +1125,7 @@ function MyController(hand) {
|
|||
angularTimeScale: DISTANCE_HOLDING_ACTION_TIMEFRAME,
|
||||
ttl: ACTION_TTL
|
||||
});
|
||||
|
||||
this.actionTimeout = now + (ACTION_TTL * MSEC_PER_SEC);
|
||||
};
|
||||
|
||||
|
@ -846,8 +1139,7 @@ function MyController(hand) {
|
|||
return;
|
||||
}
|
||||
|
||||
this.lineOff();
|
||||
this.overlayLineOff();
|
||||
this.turnOffVisualizations();
|
||||
|
||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
|
||||
this.activateEntity(this.grabbedEntity, grabbedProperties);
|
||||
|
@ -861,20 +1153,25 @@ function MyController(hand) {
|
|||
var handPosition = this.getHandPosition();
|
||||
|
||||
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
|
||||
|
||||
var objectRotation = grabbedProperties.rotation;
|
||||
var currentObjectPosition = grabbedProperties.position;
|
||||
var offset = Vec3.subtract(currentObjectPosition, handPosition);
|
||||
if (this.state != STATE_NEAR_GRABBING && grabbableData.spatialKey) {
|
||||
// if an object is "equipped" and has a spatialKey, use it.
|
||||
this.ignoreIK = grabbableData.spatialKey.ignoreIK ? grabbableData.spatialKey.ignoreIK : false;
|
||||
if (grabbableData.spatialKey.relativePosition) {
|
||||
this.offsetPosition = getSpatialOffsetPosition(this.hand, grabbableData.spatialKey);
|
||||
} else {
|
||||
this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset);
|
||||
}
|
||||
if (grabbableData.spatialKey.relativeRotation) {
|
||||
this.offsetRotation = getSpatialOffsetRotation(this.hand, grabbableData.spatialKey);
|
||||
} else {
|
||||
this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
|
||||
}
|
||||
} else {
|
||||
this.ignoreIK = false;
|
||||
|
||||
var objectRotation = grabbedProperties.rotation;
|
||||
this.offsetRotation = Quat.multiply(Quat.inverse(handRotation), objectRotation);
|
||||
|
||||
var currentObjectPosition = grabbedProperties.position;
|
||||
var offset = Vec3.subtract(currentObjectPosition, handPosition);
|
||||
this.offsetPosition = Vec3.multiplyQbyV(Quat.inverse(Quat.multiply(handRotation, this.offsetRotation)), offset);
|
||||
}
|
||||
|
||||
|
@ -984,13 +1281,12 @@ function MyController(hand) {
|
|||
Entities.callEntityMethod(this.grabbedEntity, "releaseGrab");
|
||||
Entities.callEntityMethod(this.grabbedEntity, "unequip");
|
||||
this.endHandGrasp();
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
this.pullTowardEquipPosition = function() {
|
||||
this.lineOff();
|
||||
this.overlayLineOff();
|
||||
|
||||
this.turnOffVisualizations();
|
||||
|
||||
var grabbedProperties = Entities.getEntityProperties(this.grabbedEntity, GRABBABLE_PROPERTIES);
|
||||
var grabbableData = getEntityCustomData(GRABBABLE_DATA_KEY, this.grabbedEntity, DEFAULT_GRABBABLE_DATA);
|
||||
|
@ -1108,11 +1404,15 @@ function MyController(hand) {
|
|||
}
|
||||
}
|
||||
|
||||
if (USE_ENTITY_LINES_FOR_MOVING === true) {
|
||||
this.lineOn(pickRay.origin, Vec3.multiply(pickRay.direction, LINE_LENGTH), NO_INTERSECT_COLOR);
|
||||
}
|
||||
|
||||
Entities.callEntityMethod(this.grabbedEntity, "continueFarTrigger");
|
||||
};
|
||||
|
||||
_this.allTouchedIDs = {};
|
||||
|
||||
this.touchTest = function() {
|
||||
var maxDistance = 0.05;
|
||||
var leftHandPosition = MyAvatar.getLeftPalmPosition();
|
||||
|
@ -1181,8 +1481,9 @@ function MyController(hand) {
|
|||
|
||||
this.release = function() {
|
||||
|
||||
this.lineOff();
|
||||
this.overlayLineOff();
|
||||
this.turnLightsOff();
|
||||
this.turnOffVisualizations();
|
||||
|
||||
if (this.grabbedEntity !== null) {
|
||||
if (this.actionID !== null) {
|
||||
Entities.deleteAction(this.grabbedEntity, this.actionID);
|
||||
|
@ -1199,6 +1500,9 @@ function MyController(hand) {
|
|||
this.cleanup = function() {
|
||||
this.release();
|
||||
this.endHandGrasp();
|
||||
Entities.deleteEntity(this.particleBeam);
|
||||
Entities.deleteEntity(this.spotLight);
|
||||
Entities.deleteEntity(this.pointLight);
|
||||
};
|
||||
|
||||
this.activateEntity = function(entityID, grabbedProperties) {
|
||||
|
@ -1269,27 +1573,34 @@ function MyController(hand) {
|
|||
}
|
||||
//return an object with our updated settings
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
this.graspHandler = null
|
||||
|
||||
this.startHandGrasp = function() {
|
||||
if (this.hand === RIGHT_HAND) {
|
||||
this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isRightHandGrab']);
|
||||
} else if (this.hand === LEFT_HAND) {
|
||||
this.graspHandler = MyAvatar.addAnimationStateHandler(this.graspHand, ['isLeftHandGrab']);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.endHandGrasp = function() {
|
||||
// Tell the animation system we don't need any more callbacks.
|
||||
MyAvatar.removeAnimationStateHandler(this.graspHandler);
|
||||
}
|
||||
};
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
var rightController = new MyController(RIGHT_HAND);
|
||||
var leftController = new MyController(LEFT_HAND);
|
||||
|
||||
//preload the particle beams so that they are full length when you start searching
|
||||
if (USE_PARTICLE_BEAM_FOR_SEARCHING === true || USE_PARTICLE_BEAM_FOR_MOVING === true) {
|
||||
rightController.createParticleBeam();
|
||||
leftController.createParticleBeam();
|
||||
}
|
||||
|
||||
var MAPPING_NAME = "com.highfidelity.handControllerGrab";
|
||||
|
||||
var mapping = Controller.newMapping(MAPPING_NAME);
|
||||
|
@ -1301,39 +1612,47 @@ mapping.from([Controller.Standard.LB]).peek().to(leftController.bumperPress);
|
|||
|
||||
Controller.enableMapping(MAPPING_NAME);
|
||||
|
||||
//the section below allows the grab script to listen for messages that disable either one or both hands. useful for two handed items
|
||||
var handToDisable = 'none';
|
||||
|
||||
function update() {
|
||||
if (handToDisable !== LEFT_HAND && handToDisable!=='both') {
|
||||
leftController.update();
|
||||
}
|
||||
if (handToDisable !== RIGHT_HAND && handToDisable!=='both') {
|
||||
if (handToDisable !== RIGHT_HAND && handToDisable !== 'both') {
|
||||
rightController.update();
|
||||
}
|
||||
}
|
||||
|
||||
Messages.subscribe('Hifi-Hand-Disabler');
|
||||
Messages.subscribe('Hifi-Hand-Grab');
|
||||
|
||||
handleHandDisablerMessages = function(channel, message, sender) {
|
||||
|
||||
handleHandMessages = function(channel, message, sender) {
|
||||
if (sender === MyAvatar.sessionUUID) {
|
||||
if (message === 'left') {
|
||||
handToDisable = LEFT_HAND;
|
||||
}
|
||||
if (message === 'right') {
|
||||
handToDisable = RIGHT_HAND;
|
||||
}
|
||||
if(message==='both'){
|
||||
handToDisable='both';
|
||||
}
|
||||
if(message==='none'){
|
||||
handToDisable='none';
|
||||
if (channel === 'Hifi-Hand-Disabler') {
|
||||
if (message === 'left') {
|
||||
handToDisable = LEFT_HAND;
|
||||
}
|
||||
if (message === 'right') {
|
||||
handToDisable = RIGHT_HAND;
|
||||
}
|
||||
if (message === 'both' || message === 'none') {
|
||||
handToDisable = message;
|
||||
}
|
||||
} else if (channel === 'Hifi-Hand-Grab') {
|
||||
try {
|
||||
var data = JSON.parse(message);
|
||||
var selectedController = (data.hand === 'left') ? leftController : rightController;
|
||||
selectedController.release();
|
||||
selectedController.setState(STATE_EQUIP);
|
||||
selectedController.grabbedEntity = data.entityID;
|
||||
|
||||
} catch (e) { }
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Messages.messageReceived.connect(handleHandDisablerMessages);
|
||||
Messages.messageReceived.connect(handleHandMessages);
|
||||
|
||||
function cleanup() {
|
||||
rightController.cleanup();
|
||||
|
@ -1342,4 +1661,4 @@ function cleanup() {
|
|||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
||||
Script.update.connect(update);
|
||||
Script.update.connect(update);
|
87
examples/controllers/philipsVersion.js
Normal file
87
examples/controllers/philipsVersion.js
Normal file
|
@ -0,0 +1,87 @@
|
|||
//
|
||||
// reticleTest.js
|
||||
// examples/controllers
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2015/12/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
|
||||
//
|
||||
|
||||
function length(posA, posB) {
|
||||
var dx = posA.x - posB.x;
|
||||
var dy = posA.y - posB.y;
|
||||
var length = Math.sqrt((dx*dx) + (dy*dy))
|
||||
return length;
|
||||
}
|
||||
|
||||
var PITCH_DEADZONE = 1.0;
|
||||
var PITCH_MAX = 20.0;
|
||||
var YAW_DEADZONE = 1.0;
|
||||
var YAW_MAX = 20.0;
|
||||
var PITCH_SCALING = 10.0;
|
||||
var YAW_SCALING = 10.0;
|
||||
|
||||
var EXPECTED_CHANGE = 50;
|
||||
var lastPos = Controller.getReticlePosition();
|
||||
function moveReticle(dY, dX) {
|
||||
var globalPos = Controller.getReticlePosition();
|
||||
|
||||
// some debugging to see if position is jumping around on us...
|
||||
var distanceSinceLastMove = length(lastPos, globalPos);
|
||||
if (distanceSinceLastMove > EXPECTED_CHANGE) {
|
||||
print("distanceSinceLastMove:" + distanceSinceLastMove + "----------------------------");
|
||||
}
|
||||
|
||||
if (Math.abs(dX) > EXPECTED_CHANGE) {
|
||||
print("UNEXPECTED dX:" + dX + "----------------------------");
|
||||
dX = 0;
|
||||
}
|
||||
if (Math.abs(dY) > EXPECTED_CHANGE) {
|
||||
print("UNEXPECTED dY:" + dY + "----------------------------");
|
||||
dY = 0;
|
||||
}
|
||||
|
||||
globalPos.x += dX;
|
||||
globalPos.y += dY;
|
||||
Controller.setReticlePosition(globalPos);
|
||||
lastPos = globalPos;
|
||||
}
|
||||
|
||||
|
||||
var MAPPING_NAME = "com.highfidelity.testing.reticleWithHand";
|
||||
var mapping = Controller.newMapping(MAPPING_NAME);
|
||||
|
||||
var lastHandPitch = 0;
|
||||
var lastHandYaw = 0;
|
||||
|
||||
mapping.from(Controller.Standard.LeftHand).peek().to(function(pose) {
|
||||
var handEulers = Quat.safeEulerAngles(pose.rotation);
|
||||
//Vec3.print("handEulers:", handEulers);
|
||||
|
||||
var handPitch = handEulers.y;
|
||||
var handYaw = handEulers.x;
|
||||
var changePitch = (handPitch - lastHandPitch) * PITCH_SCALING;
|
||||
var changeYaw = (handYaw - lastHandYaw) * YAW_SCALING;
|
||||
if (Math.abs(changePitch) > PITCH_MAX) {
|
||||
print("Pitch: " + changePitch);
|
||||
changePitch = 0;
|
||||
}
|
||||
if (Math.abs(changeYaw) > YAW_MAX) {
|
||||
print("Yaw: " + changeYaw);
|
||||
changeYaw = 0;
|
||||
}
|
||||
changePitch = Math.abs(changePitch) < PITCH_DEADZONE ? 0 : changePitch;
|
||||
changeYaw = Math.abs(changeYaw) < YAW_DEADZONE ? 0 : changeYaw;
|
||||
moveReticle(changePitch, changeYaw);
|
||||
lastHandPitch = handPitch;
|
||||
lastHandYaw = handYaw;
|
||||
|
||||
});
|
||||
mapping.enable();
|
||||
|
||||
|
||||
Script.scriptEnding.connect(function(){
|
||||
mapping.disable();
|
||||
});
|
76
examples/controllers/proceduralHandPoseExample.js
Normal file
76
examples/controllers/proceduralHandPoseExample.js
Normal file
|
@ -0,0 +1,76 @@
|
|||
//
|
||||
// proceduralHandPoseExample.js
|
||||
// examples/controllers
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2015/12/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
|
||||
//
|
||||
|
||||
|
||||
var MAPPING_NAME = "com.highfidelity.examples.proceduralHandPose";
|
||||
var mapping = Controller.newMapping(MAPPING_NAME);
|
||||
var translation = { x: 0, y: 0.1, z: 0 };
|
||||
var translationDx = 0.01;
|
||||
var translationDy = 0.01;
|
||||
var translationDz = -0.01;
|
||||
var TRANSLATION_LIMIT = 0.5;
|
||||
|
||||
var pitch = 45;
|
||||
var yaw = 0;
|
||||
var roll = 45;
|
||||
var pitchDelta = 1;
|
||||
var yawDelta = -1;
|
||||
var rollDelta = 1;
|
||||
var ROTATION_MIN = -90;
|
||||
var ROTATION_MAX = 90;
|
||||
|
||||
mapping.from(function() {
|
||||
|
||||
// adjust the hand translation in a periodic back and forth motion for each of the 3 axes
|
||||
translation.x = translation.x + translationDx;
|
||||
translation.y = translation.y + translationDy;
|
||||
translation.z = translation.z + translationDz;
|
||||
if ((translation.x > TRANSLATION_LIMIT) || (translation.x < (-1 * TRANSLATION_LIMIT))) {
|
||||
translationDx = translationDx * -1;
|
||||
}
|
||||
if ((translation.y > TRANSLATION_LIMIT) || (translation.y < (-1 * TRANSLATION_LIMIT))) {
|
||||
translationDy = translationDy * -1;
|
||||
}
|
||||
if ((translation.z > TRANSLATION_LIMIT) || (translation.z < (-1 * TRANSLATION_LIMIT))) {
|
||||
translationDz = translationDz * -1;
|
||||
}
|
||||
|
||||
// adjust the hand rotation in a periodic back and forth motion for each of pitch/yaw/roll
|
||||
pitch = pitch + pitchDelta;
|
||||
yaw = yaw + yawDelta;
|
||||
roll = roll + rollDelta;
|
||||
if ((pitch > ROTATION_MAX) || (pitch < ROTATION_MIN)) {
|
||||
pitchDelta = pitchDelta * -1;
|
||||
}
|
||||
if ((yaw > ROTATION_MAX) || (yaw < ROTATION_MIN)) {
|
||||
yawDelta = yawDelta * -1;
|
||||
}
|
||||
if ((roll > ROTATION_MAX) || (roll < ROTATION_MIN)) {
|
||||
rollDelta = rollDelta * -1;
|
||||
}
|
||||
|
||||
var rotation = Quat.fromPitchYawRollDegrees(pitch, yaw, roll);
|
||||
|
||||
var pose = {
|
||||
translation: translation,
|
||||
rotation: rotation,
|
||||
velocity: { x: 0, y: 0, z: 0 },
|
||||
angularVelocity: { x: 0, y: 0, z: 0 }
|
||||
};
|
||||
return pose;
|
||||
}).debug(true).to(Controller.Standard.LeftHand);
|
||||
|
||||
Controller.enableMapping(MAPPING_NAME);
|
||||
|
||||
|
||||
Script.scriptEnding.connect(function(){
|
||||
mapping.disable();
|
||||
});
|
121
examples/controllers/reticleHandAngularVelocityTest.js
Normal file
121
examples/controllers/reticleHandAngularVelocityTest.js
Normal file
|
@ -0,0 +1,121 @@
|
|||
//
|
||||
// reticleHandAngularVelocityTest.js
|
||||
// examples/controllers
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2015/12/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
|
||||
//
|
||||
|
||||
// If you set this to true, you will get the raw instantaneous angular velocity.
|
||||
// note: there is a LOT of noise in the hydra rotation, you will probably be very
|
||||
// frustrated with the level of jitter.
|
||||
var USE_INSTANTANEOUS_ANGULAR_VELOCITY = false;
|
||||
var whichHand = Controller.Standard.RightHand;
|
||||
var whichTrigger = Controller.Standard.RT;
|
||||
|
||||
|
||||
|
||||
function msecTimestampNow() {
|
||||
var d = new Date();
|
||||
return d.getTime();
|
||||
}
|
||||
|
||||
function length(posA, posB) {
|
||||
var dx = posA.x - posB.x;
|
||||
var dy = posA.y - posB.y;
|
||||
var length = Math.sqrt((dx*dx) + (dy*dy))
|
||||
return length;
|
||||
}
|
||||
|
||||
var EXPECTED_CHANGE = 50;
|
||||
var lastPos = Controller.getReticlePosition();
|
||||
function moveReticle(dX, dY) {
|
||||
var globalPos = Controller.getReticlePosition();
|
||||
|
||||
// some debugging to see if position is jumping around on us...
|
||||
var distanceSinceLastMove = length(lastPos, globalPos);
|
||||
if (distanceSinceLastMove > EXPECTED_CHANGE) {
|
||||
print("------------------ distanceSinceLastMove:" + distanceSinceLastMove + "----------------------------");
|
||||
}
|
||||
|
||||
if (Math.abs(dX) > EXPECTED_CHANGE) {
|
||||
print("surpressing unexpectedly large change dX:" + dX + "----------------------------");
|
||||
dX = 0;
|
||||
}
|
||||
if (Math.abs(dY) > EXPECTED_CHANGE) {
|
||||
print("surpressing unexpectedly large change dY:" + dY + "----------------------------");
|
||||
dY = 0;
|
||||
}
|
||||
|
||||
globalPos.x += dX;
|
||||
globalPos.y += dY;
|
||||
Controller.setReticlePosition(globalPos);
|
||||
lastPos = globalPos;
|
||||
}
|
||||
|
||||
var firstTime = true;
|
||||
var lastTime = msecTimestampNow();
|
||||
var previousRotation;
|
||||
|
||||
var MAPPING_NAME = "com.highfidelity.testing.reticleWithHand";
|
||||
var mapping = Controller.newMapping(MAPPING_NAME);
|
||||
mapping.from(whichTrigger).peek().constrainToInteger().to(Controller.Actions.ReticleClick);
|
||||
mapping.from(whichHand).peek().to(function(pose) {
|
||||
|
||||
var MSECS_PER_SECOND = 1000;
|
||||
var now = msecTimestampNow();
|
||||
var deltaMsecs = (now - lastTime);
|
||||
var deltaTime = deltaMsecs / MSECS_PER_SECOND;
|
||||
|
||||
if (firstTime) {
|
||||
previousRotation = pose.rotation;
|
||||
lastTime = msecTimestampNow();
|
||||
firstTime = false;
|
||||
}
|
||||
|
||||
// pose.angularVelocity - is the angularVelocity in a "physics" sense, that
|
||||
// means the direction of the vector is the axis of symetry of rotation
|
||||
// and the scale of the vector is the speed in radians/second of rotation
|
||||
// around that axis.
|
||||
//
|
||||
// we want to deconstruct that in the portion of the rotation on the Y axis
|
||||
// and make that portion move our reticle in the horizontal/X direction
|
||||
// and the portion of the rotation on the X axis and make that portion
|
||||
// move our reticle in the veritcle/Y direction
|
||||
var xPart = -pose.angularVelocity.y;
|
||||
var yPart = -pose.angularVelocity.x;
|
||||
|
||||
// pose.angularVelocity is "smoothed", we can calculate our own instantaneous
|
||||
// angular velocity as such:
|
||||
if (USE_INSTANTANEOUS_ANGULAR_VELOCITY) {
|
||||
var previousConjugate = Quat.conjugate(previousRotation);
|
||||
var deltaRotation = Quat.multiply(pose.rotation, previousConjugate);
|
||||
var normalizedDeltaRotation = Quat.normalize(deltaRotation);
|
||||
var axis = Quat.axis(normalizedDeltaRotation);
|
||||
var speed = Quat.angle(normalizedDeltaRotation) / deltaTime;
|
||||
var instantaneousAngularVelocity = Vec3.multiply(speed, axis);
|
||||
|
||||
xPart = -instantaneousAngularVelocity.y;
|
||||
yPart = -instantaneousAngularVelocity.x;
|
||||
|
||||
previousRotation = pose.rotation;
|
||||
}
|
||||
|
||||
var MOVE_SCALE = 1;
|
||||
lastTime = now;
|
||||
|
||||
var dX = (xPart * MOVE_SCALE) / deltaTime;
|
||||
var dY = (yPart * MOVE_SCALE) / deltaTime;
|
||||
|
||||
moveReticle(dX, dY);
|
||||
});
|
||||
mapping.enable();
|
||||
|
||||
Script.scriptEnding.connect(function(){
|
||||
mapping.disable();
|
||||
});
|
||||
|
||||
|
254
examples/controllers/reticleHandRotationTest.js
Normal file
254
examples/controllers/reticleHandRotationTest.js
Normal file
|
@ -0,0 +1,254 @@
|
|||
//
|
||||
// reticleHandRotationTest.js
|
||||
// examples/controllers
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 2015/12/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
|
||||
//
|
||||
|
||||
var DEBUGGING = false;
|
||||
|
||||
Math.clamp=function(a,b,c) {
|
||||
return Math.max(b,Math.min(c,a));
|
||||
}
|
||||
|
||||
function length(posA, posB) {
|
||||
var dx = posA.x - posB.x;
|
||||
var dy = posA.y - posB.y;
|
||||
var length = Math.sqrt((dx*dx) + (dy*dy))
|
||||
return length;
|
||||
}
|
||||
|
||||
var EXPECTED_CHANGE = 50;
|
||||
var lastPos = Controller.getReticlePosition();
|
||||
function moveReticleAbsolute(x, y) {
|
||||
var globalPos = Controller.getReticlePosition();
|
||||
var dX = x - globalPos.x;
|
||||
var dY = y - globalPos.y;
|
||||
|
||||
// some debugging to see if position is jumping around on us...
|
||||
var distanceSinceLastMove = length(lastPos, globalPos);
|
||||
if (distanceSinceLastMove > EXPECTED_CHANGE) {
|
||||
debugPrint("------------------ distanceSinceLastMove:" + distanceSinceLastMove + "----------------------------");
|
||||
}
|
||||
|
||||
if (Math.abs(dX) > EXPECTED_CHANGE) {
|
||||
debugPrint("surpressing unexpectedly large change dX:" + dX + "----------------------------");
|
||||
}
|
||||
if (Math.abs(dY) > EXPECTED_CHANGE) {
|
||||
debugPrint("surpressing unexpectedly large change dY:" + dY + "----------------------------");
|
||||
}
|
||||
|
||||
globalPos.x = x;
|
||||
globalPos.y = y;
|
||||
Controller.setReticlePosition(globalPos);
|
||||
lastPos = globalPos;
|
||||
}
|
||||
|
||||
|
||||
var MAPPING_NAME = "com.highfidelity.testing.reticleWithHandRotation";
|
||||
var mapping = Controller.newMapping(MAPPING_NAME);
|
||||
mapping.from(Controller.Standard.LT).peek().constrainToInteger().to(Controller.Actions.ReticleClick);
|
||||
mapping.from(Controller.Standard.RT).peek().constrainToInteger().to(Controller.Actions.ReticleClick);
|
||||
mapping.enable();
|
||||
|
||||
|
||||
var lastRotatedLeft = Vec3.UNIT_NEG_Y;
|
||||
var lastRotatedRight = Vec3.UNIT_NEG_Y;
|
||||
|
||||
function debugPrint(message) {
|
||||
if (DEBUGGING) {
|
||||
print(message);
|
||||
}
|
||||
}
|
||||
|
||||
var MAX_WAKE_UP_DISTANCE = 0.005;
|
||||
var MIN_WAKE_UP_DISTANCE = 0.001;
|
||||
var INITIAL_WAKE_UP_DISTANCE = MIN_WAKE_UP_DISTANCE;
|
||||
var INCREMENTAL_WAKE_UP_DISTANCE = 0.001;
|
||||
|
||||
var MAX_SLEEP_DISTANCE = 0.0004;
|
||||
var MIN_SLEEP_DISTANCE = 0.00001; //0.00002;
|
||||
var INITIAL_SLEEP_DISTANCE = MIN_SLEEP_DISTANCE;
|
||||
var INCREMENTAL_SLEEP_DISTANCE = 0.000002; // 0.00002;
|
||||
|
||||
var leftAsleep = true;
|
||||
var rightAsleep = true;
|
||||
|
||||
var leftWakeUpDistance = INITIAL_WAKE_UP_DISTANCE;
|
||||
var rightWakeUpDistance = INITIAL_WAKE_UP_DISTANCE;
|
||||
|
||||
var leftSleepDistance = INITIAL_SLEEP_DISTANCE;
|
||||
var rightSleepDistance = INITIAL_SLEEP_DISTANCE;
|
||||
|
||||
Script.update.connect(function(deltaTime) {
|
||||
|
||||
var poseRight = Controller.getPoseValue(Controller.Standard.RightHand);
|
||||
var poseLeft = Controller.getPoseValue(Controller.Standard.LeftHand);
|
||||
|
||||
// NOTE: hack for now
|
||||
var screenSizeX = 1920;
|
||||
var screenSizeY = 1080;
|
||||
|
||||
var rotatedRight = Vec3.multiplyQbyV(poseRight.rotation, Vec3.UNIT_NEG_Y);
|
||||
var rotatedLeft = Vec3.multiplyQbyV(poseLeft.rotation, Vec3.UNIT_NEG_Y);
|
||||
|
||||
var suppressRight = false;
|
||||
var suppressLeft = false;
|
||||
|
||||
// What I really want to do is to slowly increase the epsilon you have to move it
|
||||
// to wake up, the longer you go without moving it
|
||||
var leftDistance = Vec3.distance(rotatedLeft, lastRotatedLeft);
|
||||
var rightDistance = Vec3.distance(rotatedRight, lastRotatedRight);
|
||||
|
||||
// check to see if hand should wakeup or sleep
|
||||
if (leftAsleep) {
|
||||
if (leftDistance > leftWakeUpDistance) {
|
||||
leftAsleep = false;
|
||||
leftSleepDistance = INITIAL_SLEEP_DISTANCE;
|
||||
leftWakeUpDistance = INITIAL_WAKE_UP_DISTANCE;
|
||||
} else {
|
||||
// grow the wake up distance to make it harder to wake up
|
||||
leftWakeUpDistance = Math.min(leftWakeUpDistance + INCREMENTAL_WAKE_UP_DISTANCE, MAX_WAKE_UP_DISTANCE);
|
||||
}
|
||||
} else {
|
||||
// we are awake, determine if we should fall asleep, if we haven't moved
|
||||
// at least as much as our sleep distance then we sleep
|
||||
if (leftDistance < leftSleepDistance) {
|
||||
leftAsleep = true;
|
||||
leftSleepDistance = INITIAL_SLEEP_DISTANCE;
|
||||
leftWakeUpDistance = INITIAL_WAKE_UP_DISTANCE;
|
||||
} else {
|
||||
// if we moved more than the sleep amount, but we moved less than the max sleep
|
||||
// amount, then increase our liklihood of sleep.
|
||||
if (leftDistance < MAX_SLEEP_DISTANCE) {
|
||||
print("growing sleep....");
|
||||
leftSleepDistance = Math.max(leftSleepDistance + INCREMENTAL_SLEEP_DISTANCE, MAX_SLEEP_DISTANCE);
|
||||
} else {
|
||||
// otherwise reset it to initial
|
||||
leftSleepDistance = INITIAL_SLEEP_DISTANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (leftAsleep) {
|
||||
suppressLeft = true;
|
||||
debugPrint("suppressing left not moving enough");
|
||||
}
|
||||
|
||||
// check to see if hand should wakeup or sleep
|
||||
if (rightAsleep) {
|
||||
if (rightDistance > rightWakeUpDistance) {
|
||||
rightAsleep = false;
|
||||
rightSleepDistance = INITIAL_SLEEP_DISTANCE;
|
||||
rightWakeUpDistance = INITIAL_WAKE_UP_DISTANCE;
|
||||
} else {
|
||||
// grow the wake up distance to make it harder to wake up
|
||||
rightWakeUpDistance = Math.min(rightWakeUpDistance + INCREMENTAL_WAKE_UP_DISTANCE, MAX_WAKE_UP_DISTANCE);
|
||||
}
|
||||
} else {
|
||||
// we are awake, determine if we should fall asleep, if we haven't moved
|
||||
// at least as much as our sleep distance then we sleep
|
||||
if (rightDistance < rightSleepDistance) {
|
||||
rightAsleep = true;
|
||||
rightSleepDistance = INITIAL_SLEEP_DISTANCE;
|
||||
rightWakeUpDistance = INITIAL_WAKE_UP_DISTANCE;
|
||||
} else {
|
||||
// if we moved more than the sleep amount, but we moved less than the max sleep
|
||||
// amount, then increase our liklihood of sleep.
|
||||
if (rightDistance < MAX_SLEEP_DISTANCE) {
|
||||
print("growing sleep....");
|
||||
rightSleepDistance = Math.max(rightSleepDistance + INCREMENTAL_SLEEP_DISTANCE, MAX_SLEEP_DISTANCE);
|
||||
} else {
|
||||
// otherwise reset it to initial
|
||||
rightSleepDistance = INITIAL_SLEEP_DISTANCE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (rightAsleep) {
|
||||
suppressRight = true;
|
||||
debugPrint("suppressing right not moving enough");
|
||||
}
|
||||
|
||||
// check to see if hand is on base station
|
||||
if (Vec3.equal(rotatedLeft, Vec3.UNIT_NEG_Y)) {
|
||||
suppressLeft = true;
|
||||
debugPrint("suppressing left on base station");
|
||||
}
|
||||
if (Vec3.equal(rotatedRight, Vec3.UNIT_NEG_Y)) {
|
||||
suppressRight = true;
|
||||
debugPrint("suppressing right on base station");
|
||||
}
|
||||
|
||||
// Keep track of last rotations, to detect resting (but not on base station hands) in the future
|
||||
lastRotatedLeft = rotatedLeft;
|
||||
lastRotatedRight = rotatedRight;
|
||||
|
||||
if (suppressLeft && suppressRight) {
|
||||
debugPrint("both hands suppressed bail out early");
|
||||
return;
|
||||
}
|
||||
|
||||
if (suppressLeft) {
|
||||
debugPrint("right only");
|
||||
rotatedLeft = rotatedRight;
|
||||
}
|
||||
if (suppressRight) {
|
||||
debugPrint("left only");
|
||||
rotatedRight = rotatedLeft;
|
||||
}
|
||||
|
||||
// Average the two hand positions, if either hand is on base station, the
|
||||
// other hand becomes the only used hand and the average is the hand in use
|
||||
var rotated = Vec3.multiply(Vec3.sum(rotatedRight,rotatedLeft), 0.5);
|
||||
|
||||
if (DEBUGGING) {
|
||||
Vec3.print("rotatedRight:", rotatedRight);
|
||||
Vec3.print("rotatedLeft:", rotatedLeft);
|
||||
Vec3.print("rotated:", rotated);
|
||||
}
|
||||
|
||||
var absolutePitch = rotated.y; // from 1 down to -1 up ... but note: if you rotate down "too far" it starts to go up again...
|
||||
var absoluteYaw = -rotated.x; // from -1 left to 1 right
|
||||
|
||||
if (DEBUGGING) {
|
||||
print("absolutePitch:" + absolutePitch);
|
||||
print("absoluteYaw:" + absoluteYaw);
|
||||
Vec3.print("rotated:", rotated);
|
||||
}
|
||||
|
||||
var ROTATION_BOUND = 0.6;
|
||||
var clampYaw = Math.clamp(absoluteYaw, -ROTATION_BOUND, ROTATION_BOUND);
|
||||
var clampPitch = Math.clamp(absolutePitch, -ROTATION_BOUND, ROTATION_BOUND);
|
||||
if (DEBUGGING) {
|
||||
print("clampYaw:" + clampYaw);
|
||||
print("clampPitch:" + clampPitch);
|
||||
}
|
||||
|
||||
// using only from -ROTATION_BOUND to ROTATION_BOUND
|
||||
var xRatio = (clampYaw + ROTATION_BOUND) / (2 * ROTATION_BOUND);
|
||||
var yRatio = (clampPitch + ROTATION_BOUND) / (2 * ROTATION_BOUND);
|
||||
|
||||
if (DEBUGGING) {
|
||||
print("xRatio:" + xRatio);
|
||||
print("yRatio:" + yRatio);
|
||||
}
|
||||
|
||||
var x = screenSizeX * xRatio;
|
||||
var y = screenSizeY * yRatio;
|
||||
|
||||
if (DEBUGGING) {
|
||||
print("position x:" + x + " y:" + y);
|
||||
}
|
||||
if (!(xRatio == 0.5 && yRatio == 0)) {
|
||||
moveReticleAbsolute(x, y);
|
||||
}
|
||||
});
|
||||
|
||||
Script.scriptEnding.connect(function(){
|
||||
mapping.disable();
|
||||
});
|
||||
|
||||
|
|
@ -33,7 +33,6 @@ var mappingJSON = {
|
|||
|
||||
mapping = Controller.parseMapping(JSON.stringify(mappingJSON));
|
||||
mapping.enable();
|
||||
|
||||
Script.scriptEnding.connect(function(){
|
||||
mapping.disable();
|
||||
});
|
||||
|
|
|
@ -140,9 +140,33 @@ var importingSVOTextOverlay = Overlays.addOverlay("text", {
|
|||
});
|
||||
|
||||
var MARKETPLACE_URL = "https://metaverse.highfidelity.com/marketplace";
|
||||
var marketplaceWindow = new WebWindow('Marketplace', MARKETPLACE_URL, 900, 700, false);
|
||||
var marketplaceWindow = new OverlayWebWindow('Marketplace', "about:blank", 900, 700, false);
|
||||
marketplaceWindow.setVisible(false);
|
||||
|
||||
function showMarketplace(marketplaceID) {
|
||||
var url = MARKETPLACE_URL;
|
||||
if (marketplaceID) {
|
||||
url = url + "/items/" + marketplaceID;
|
||||
}
|
||||
print("setting marketplace URL to " + url);
|
||||
marketplaceWindow.setURL(url);
|
||||
marketplaceWindow.setVisible(true);
|
||||
marketplaceWindow.raise();
|
||||
}
|
||||
|
||||
function hideMarketplace() {
|
||||
marketplaceWindow.setVisible(false);
|
||||
marketplaceWindow.setURL("about:blank");
|
||||
}
|
||||
|
||||
function toggleMarketplace() {
|
||||
if (marketplaceWindow.visible) {
|
||||
hideMarketplace();
|
||||
} else {
|
||||
showMarketplace();
|
||||
}
|
||||
}
|
||||
|
||||
var toolBar = (function() {
|
||||
var that = {},
|
||||
toolBar,
|
||||
|
@ -413,12 +437,9 @@ var toolBar = (function() {
|
|||
newModelButtonDown = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (browseMarketplaceButton === toolBar.clicked(clickedOverlay)) {
|
||||
if (marketplaceWindow.url != MARKETPLACE_URL) {
|
||||
marketplaceWindow.setURL(MARKETPLACE_URL);
|
||||
}
|
||||
marketplaceWindow.setVisible(true);
|
||||
marketplaceWindow.raise();
|
||||
toggleMarketplace();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -1336,6 +1357,7 @@ function getPositionToCreateEntity() {
|
|||
}
|
||||
|
||||
function importSVO(importURL) {
|
||||
print("Import URL requested: " + importURL)
|
||||
if (!Entities.canAdjustLocks()) {
|
||||
Window.alert(INSUFFICIENT_PERMISSIONS_IMPORT_ERROR_MSG);
|
||||
return;
|
||||
|
@ -1574,11 +1596,7 @@ PropertiesTool = function(opts) {
|
|||
pushCommandForSelections();
|
||||
selectionManager._update();
|
||||
} else if (data.type == "showMarketplace") {
|
||||
if (marketplaceWindow.url != data.url) {
|
||||
marketplaceWindow.setURL(data.url);
|
||||
}
|
||||
marketplaceWindow.setVisible(true);
|
||||
marketplaceWindow.raise();
|
||||
showMarketplace();
|
||||
} else if (data.type == "action") {
|
||||
if (data.action == "moveSelectionToGrid") {
|
||||
if (selectionManager.hasSelection()) {
|
||||
|
@ -1859,12 +1877,7 @@ var propertyMenu = PopupMenu();
|
|||
|
||||
propertyMenu.onSelectMenuItem = function(name) {
|
||||
if (propertyMenu.marketplaceID) {
|
||||
var url = MARKETPLACE_URL + "/items/" + propertyMenu.marketplaceID;
|
||||
if (marketplaceWindow.url != url) {
|
||||
marketplaceWindow.setURL(url);
|
||||
}
|
||||
marketplaceWindow.setVisible(true);
|
||||
marketplaceWindow.raise();
|
||||
showMarketplace(propertyMenu.marketplaceID);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
145
examples/flowArts/arcBall/arcBall.js
Normal file
145
examples/flowArts/arcBall/arcBall.js
Normal file
|
@ -0,0 +1,145 @@
|
|||
//
|
||||
// arcBall.js
|
||||
// examples/arcBall
|
||||
//
|
||||
// Created by Eric Levin on 12/17/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This script creats a particle light ball which makes particle trails as you move it.
|
||||
//
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("../../libraries/utils.js");
|
||||
|
||||
|
||||
var scriptURL = Script.resolvePath("arcBallEntityScript.js?v1" + Math.random());
|
||||
ArcBall = function(spawnPosition) {
|
||||
|
||||
var colorPalette = [{
|
||||
red: 25,
|
||||
green: 20,
|
||||
blue: 162
|
||||
}];
|
||||
|
||||
|
||||
var containerBall = Entities.addEntity({
|
||||
type: "Sphere",
|
||||
name: "Arc Ball",
|
||||
script: scriptURL,
|
||||
position: Vec3.sum(spawnPosition, {
|
||||
x: 0,
|
||||
y: .7,
|
||||
z: 0
|
||||
}),
|
||||
dimensions: {
|
||||
x: .05,
|
||||
y: .05,
|
||||
z: .05
|
||||
},
|
||||
color: {
|
||||
red: 100,
|
||||
green: 10,
|
||||
blue: 150
|
||||
},
|
||||
ignoreForCollisions: true,
|
||||
damping: 0.8,
|
||||
collisionsWillMove: true,
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
spatialKey: {
|
||||
// relativePosition: {
|
||||
// x: 0,
|
||||
// y: -0.5,
|
||||
// z: 0.0
|
||||
// },
|
||||
},
|
||||
// invertSolidWhileHeld: true
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
var light = Entities.addEntity({
|
||||
type: 'Light',
|
||||
name: "ballLight",
|
||||
parentID: containerBall,
|
||||
dimensions: {
|
||||
x: 30,
|
||||
y: 30,
|
||||
z: 30
|
||||
},
|
||||
color: colorPalette[randInt(0, colorPalette.length)],
|
||||
intensity: 5
|
||||
});
|
||||
|
||||
|
||||
var arcBall = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
parentID: containerBall,
|
||||
isEmitting: true,
|
||||
name: "Arc Ball Particle Effect",
|
||||
colorStart: {
|
||||
red: 200,
|
||||
green: 20,
|
||||
blue: 40
|
||||
},
|
||||
color: {
|
||||
red: 200,
|
||||
green: 200,
|
||||
blue: 255
|
||||
},
|
||||
colorFinish: {
|
||||
red: 25,
|
||||
green: 20,
|
||||
blue: 255
|
||||
},
|
||||
maxParticles: 100000,
|
||||
lifespan: 2,
|
||||
emitRate: 400,
|
||||
emitSpeed: .1,
|
||||
lifetime: -1,
|
||||
speedSpread: 0.0,
|
||||
emitDimensions: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
polarStart: 0,
|
||||
polarFinish: Math.PI,
|
||||
azimuthStart: -Math.PI,
|
||||
azimuthFinish: Math.PI,
|
||||
emitAcceleration: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
accelerationSpread: {
|
||||
x: .00,
|
||||
y: .00,
|
||||
z: .00
|
||||
},
|
||||
particleRadius: 0.02,
|
||||
radiusSpread: 0,
|
||||
radiusStart: 0.03,
|
||||
radiusFinish: 0.0003,
|
||||
alpha: 0,
|
||||
alphaSpread: .5,
|
||||
alphaStart: 0,
|
||||
alphaFinish: 0.5,
|
||||
textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png",
|
||||
emitterShouldTrail: true
|
||||
})
|
||||
|
||||
|
||||
|
||||
function cleanup() {
|
||||
Entities.deleteEntity(arcBall);
|
||||
Entities.deleteEntity(containerBall);
|
||||
Entities.deleteEntity(light);
|
||||
}
|
||||
|
||||
this.cleanup = cleanup;
|
||||
}
|
155
examples/flowArts/arcBall/arcBallEntityScript.js
Normal file
155
examples/flowArts/arcBall/arcBallEntityScript.js
Normal file
|
@ -0,0 +1,155 @@
|
|||
// arcBallEntityScript.js
|
||||
//
|
||||
// Script Type: Entity
|
||||
// Created by Eric Levin on 12/17/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This entity script handles the logic for the arcBall rave toy
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function() {
|
||||
Script.include("../../libraries/utils.js");
|
||||
var _this;
|
||||
var ArcBall = function() {
|
||||
_this = this;
|
||||
this.colorPalette = [{
|
||||
red: 25,
|
||||
green: 20,
|
||||
blue: 162
|
||||
}, {
|
||||
red: 200,
|
||||
green: 10,
|
||||
blue: 10
|
||||
}];
|
||||
|
||||
this.searchRadius = 10;
|
||||
};
|
||||
|
||||
ArcBall.prototype = {
|
||||
isGrabbed: false,
|
||||
startDistantGrab: function() {
|
||||
this.searchForNearbyArcBalls();
|
||||
},
|
||||
|
||||
startNearGrab: function() {
|
||||
this.searchForNearbyArcBalls();
|
||||
},
|
||||
|
||||
searchForNearbyArcBalls: function() {
|
||||
//Search for nearby balls and create an arc to it if one is found
|
||||
var position = Entities.getEntityProperties(this.entityID, "position").position
|
||||
var entities = Entities.findEntities(position, this.searchRadius);
|
||||
entities.forEach(function(entity) {
|
||||
var props = Entities.getEntityProperties(entity, ["position", "name"]);
|
||||
if (props.name === "Arc Ball" && JSON.stringify(_this.entityID) !== JSON.stringify(entity)) {
|
||||
_this.target = entity;
|
||||
_this.createBeam(position, props.position);
|
||||
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
createBeam: function(startPosition, endPosition) {
|
||||
|
||||
// Creates particle arc from start position to end position
|
||||
var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation;
|
||||
var sourceToTargetVec = Vec3.subtract(endPosition, startPosition);
|
||||
var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec);
|
||||
emitOrientation = Quat.multiply(Quat.inverse(rotation), emitOrientation);
|
||||
|
||||
var color = this.colorPalette[randInt(0, this.colorPalette.length)];
|
||||
var props = {
|
||||
type: "ParticleEffect",
|
||||
name: "Particle Arc",
|
||||
parentID: this.entityID,
|
||||
parentJointIndex: -1,
|
||||
// position: startPosition,
|
||||
isEmitting: true,
|
||||
colorStart: color,
|
||||
color: {
|
||||
red: 200,
|
||||
green: 200,
|
||||
blue: 255
|
||||
},
|
||||
colorFinish: color,
|
||||
maxParticles: 100000,
|
||||
lifespan: 1,
|
||||
emitRate: 1000,
|
||||
emitOrientation: emitOrientation,
|
||||
emitSpeed: 1,
|
||||
speedSpread: 0.02,
|
||||
emitDimensions: {
|
||||
x: .01,
|
||||
y: .01,
|
||||
z: .01
|
||||
},
|
||||
polarStart: 0,
|
||||
polarFinish: 0,
|
||||
azimuthStart: 0.02,
|
||||
azimuthFinish: .01,
|
||||
emitAcceleration: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
accelerationSpread: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
radiusStart: 0.01,
|
||||
radiusFinish: 0.005,
|
||||
radiusSpread: 0.005,
|
||||
alpha: 0.5,
|
||||
alphaSpread: 0.1,
|
||||
alphaStart: 0.5,
|
||||
alphaFinish: 0.5,
|
||||
textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png",
|
||||
emitterShouldTrail: true
|
||||
}
|
||||
this.particleArc = Entities.addEntity(props);
|
||||
},
|
||||
|
||||
updateBeam: function() {
|
||||
if(!this.target) {
|
||||
return;
|
||||
}
|
||||
var startPosition = Entities.getEntityProperties(this.entityID, "position").position;
|
||||
var targetPosition = Entities.getEntityProperties(this.target, "position").position;
|
||||
var rotation = Entities.getEntityProperties(this.entityID, "rotation").rotation;
|
||||
var sourceToTargetVec = Vec3.subtract(targetPosition, startPosition);
|
||||
var emitOrientation = Quat.rotationBetween(Vec3.UNIT_Z, sourceToTargetVec);
|
||||
Entities.editEntity(this.particleArc, {
|
||||
emitOrientation: emitOrientation
|
||||
});
|
||||
},
|
||||
|
||||
continueNearGrab: function() {
|
||||
this.updateBeam();
|
||||
},
|
||||
|
||||
continueDistantGrab: function() {
|
||||
this.updateBeam();
|
||||
},
|
||||
|
||||
releaseGrab: function() {
|
||||
Entities.editEntity(this.particleArc, {
|
||||
isEmitting: false
|
||||
});
|
||||
this.target = null;
|
||||
},
|
||||
|
||||
unload: function() {
|
||||
if (this.particleArc) {
|
||||
Entities.deleteEntity(this.particleArc);
|
||||
}
|
||||
},
|
||||
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
},
|
||||
};
|
||||
return new ArcBall();
|
||||
});
|
91
examples/flowArts/flowArtsHutSpawner.js
Normal file
91
examples/flowArts/flowArtsHutSpawner.js
Normal file
|
@ -0,0 +1,91 @@
|
|||
//
|
||||
// flowArtsHutSpawner.js
|
||||
// examples/flowArts
|
||||
//
|
||||
// Created by Eric Levin on 12/17/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This script creates a special flow arts hut with a bunch of flow art toys people can go in and play with
|
||||
//
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
Script.include("../../libraries/utils.js");
|
||||
Script.include("lightBall/lightBall.js");
|
||||
Script.include("raveStick/raveStick.js");
|
||||
Script.include("lightSaber/lightSaber.js");
|
||||
Script.include("arcBall/arcBall.js");
|
||||
|
||||
|
||||
|
||||
var basePosition = Vec3.sum(MyAvatar.position, Vec3.multiply(1, Quat.getFront(Camera.getOrientation())));
|
||||
basePosition.y = MyAvatar.position.y + 1;
|
||||
|
||||
// RAVE ITEMS
|
||||
// var lightBall = new LightBall(basePosition);
|
||||
|
||||
var arcBall = new ArcBall(basePosition);
|
||||
var arcBall2 = new ArcBall(Vec3.sum(basePosition, {x: -1, y: 0, z: 0}));
|
||||
var raveStick = new RaveStick(Vec3.sum(basePosition, {x: 1, y: 0.5, z: 1}));
|
||||
var lightSaber = new LightSaber(Vec3.sum(basePosition, {x: 3, y: 0.5, z: 1}));
|
||||
|
||||
|
||||
var modelURL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/RaveRoom.fbx";
|
||||
|
||||
var roomDimensions = {x: 30.58, y: 15.29, z: 30.58};
|
||||
|
||||
var raveRoom = Entities.addEntity({
|
||||
type: "Model",
|
||||
name: "Rave Hut Room",
|
||||
modelURL: modelURL,
|
||||
position: basePosition,
|
||||
dimensions:roomDimensions,
|
||||
visible: true
|
||||
});
|
||||
|
||||
var floor = Entities.addEntity({
|
||||
type: "Box",
|
||||
name: "Rave Floor",
|
||||
position: Vec3.sum(basePosition, {x: 0, y: -1.2, z: 0}),
|
||||
dimensions: {x: roomDimensions.x, y: 0.6, z: roomDimensions.z},
|
||||
color: {red: 50, green: 10, blue: 100},
|
||||
shapeType: 'box'
|
||||
});
|
||||
|
||||
|
||||
|
||||
var lightZone = Entities.addEntity({
|
||||
type: "Zone",
|
||||
name: "Rave Hut Zone",
|
||||
shapeType: 'box',
|
||||
keyLightIntensity: 0.4,
|
||||
keyLightColor: {
|
||||
red: 50,
|
||||
green: 0,
|
||||
blue: 50
|
||||
},
|
||||
keyLightAmbientIntensity: .2,
|
||||
position: MyAvatar.position,
|
||||
dimensions: {
|
||||
x: 100,
|
||||
y: 100,
|
||||
z: 100
|
||||
}
|
||||
});
|
||||
|
||||
function cleanup() {
|
||||
|
||||
Entities.deleteEntity(raveRoom);
|
||||
Entities.deleteEntity(lightZone);
|
||||
Entities.deleteEntity(floor);
|
||||
// lightBall.cleanup();
|
||||
arcBall.cleanup();
|
||||
arcBall2.cleanup();
|
||||
raveStick.cleanup();
|
||||
lightSaber.cleanup();
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(cleanup);
|
145
examples/flowArts/lightBall/lightBall.js
Normal file
145
examples/flowArts/lightBall/lightBall.js
Normal file
|
@ -0,0 +1,145 @@
|
|||
//
|
||||
// LightBall.js
|
||||
// examples/lightBall
|
||||
//
|
||||
// Created by Eric Levin on 12/17/15.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// This script creats a particle light ball which makes particle trails as you move it.
|
||||
//
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("../../libraries/utils.js");
|
||||
|
||||
LightBall = function(spawnPosition) {
|
||||
|
||||
var colorPalette = [{
|
||||
red: 25,
|
||||
green: 20,
|
||||
blue: 162
|
||||
}];
|
||||
|
||||
|
||||
var containerBall = Entities.addEntity({
|
||||
type: "Sphere",
|
||||
name: "containerBall",
|
||||
position: Vec3.sum(spawnPosition, {
|
||||
x: 0,
|
||||
y: 0.5,
|
||||
z: 0
|
||||
}),
|
||||
dimensions: {
|
||||
x: 0.1,
|
||||
y: 0.1,
|
||||
z: 0.1
|
||||
},
|
||||
color: {
|
||||
red: 15,
|
||||
green: 10,
|
||||
blue: 150
|
||||
},
|
||||
collisionsWillMove: true,
|
||||
// gravity: {
|
||||
// x: 0,
|
||||
// y: -0.5,
|
||||
// z: 0
|
||||
// },
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
spatialKey: {
|
||||
relativePosition: {
|
||||
x: 0,
|
||||
y: 0.1,
|
||||
z: 0
|
||||
}
|
||||
},
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
|
||||
var light = Entities.addEntity({
|
||||
type: 'Light',
|
||||
name: "ballLight",
|
||||
parentID: containerBall,
|
||||
dimensions: {
|
||||
x: 30,
|
||||
y: 30,
|
||||
z: 30
|
||||
},
|
||||
color: colorPalette[randInt(0, colorPalette.length)],
|
||||
intensity: 5
|
||||
});
|
||||
|
||||
|
||||
var lightBall = Entities.addEntity({
|
||||
type: "ParticleEffect",
|
||||
parentID: containerBall,
|
||||
isEmitting: true,
|
||||
name: "particleBall",
|
||||
colorStart: {
|
||||
red: 200,
|
||||
green: 20,
|
||||
blue: 40
|
||||
},
|
||||
color: {
|
||||
red: 200,
|
||||
green: 200,
|
||||
blue: 255
|
||||
},
|
||||
colorFinish: {
|
||||
red: 25,
|
||||
green: 20,
|
||||
blue: 255
|
||||
},
|
||||
maxParticles: 100000,
|
||||
lifespan: 2,
|
||||
emitRate: 10000,
|
||||
emitSpeed: 0.1,
|
||||
lifetime: -1,
|
||||
speedSpread: 0.0,
|
||||
emitDimensions: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
polarStart: 0,
|
||||
polarFinish: Math.PI,
|
||||
azimuthStart: -Math.PI,
|
||||
azimuthFinish: Math.PI,
|
||||
emitAcceleration: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
accelerationSpread: {
|
||||
x: 0.00,
|
||||
y: 0.00,
|
||||
z: 0.00
|
||||
},
|
||||
particleRadius: 0.02,
|
||||
radiusSpread: 0,
|
||||
radiusStart: 0.03,
|
||||
radiusFinish: 0.0003,
|
||||
alpha: 0,
|
||||
alphaSpread: 0.5,
|
||||
alphaStart: 0,
|
||||
alphaFinish: 0.5,
|
||||
textures: "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png",
|
||||
emitterShouldTrail: true
|
||||
})
|
||||
|
||||
|
||||
|
||||
function cleanup() {
|
||||
Entities.deleteEntity(lightBall);
|
||||
Entities.deleteEntity(containerBall);
|
||||
Entities.deleteEntity(light);
|
||||
}
|
||||
|
||||
this.cleanup = cleanup;
|
||||
}
|
67
examples/flowArts/lightSaber/lightSaber.js
Normal file
67
examples/flowArts/lightSaber/lightSaber.js
Normal file
|
@ -0,0 +1,67 @@
|
|||
//
|
||||
// LightSaber.js
|
||||
// examples
|
||||
//
|
||||
// Created by Eric Levin on 12/17/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This script creates a lightsaber which activates on grab
|
||||
//
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("../../libraries/utils.js");
|
||||
var modelURL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/lightSaber.fbx";
|
||||
var scriptURL = Script.resolvePath("lightSaberEntityScript.js");
|
||||
LightSaber = function(spawnPosition) {
|
||||
|
||||
var saberHandle = Entities.addEntity({
|
||||
type: "Model",
|
||||
name: "LightSaber Handle",
|
||||
modelURL: modelURL,
|
||||
position: spawnPosition,
|
||||
shapeType: 'box',
|
||||
collisionsWillMove: true,
|
||||
script: scriptURL,
|
||||
dimensions: {
|
||||
x: 0.06,
|
||||
y: 0.06,
|
||||
z: 0.31
|
||||
},
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
spatialKey: {
|
||||
relativePosition: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: -0.1
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(180, 90, 0)
|
||||
},
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
var light = Entities.addEntity({
|
||||
type: 'Light',
|
||||
name: "raveLight",
|
||||
parentID: saberHandle,
|
||||
dimensions: {
|
||||
x: 30,
|
||||
y: 30,
|
||||
z: 30
|
||||
},
|
||||
color: {red: 200, green: 10, blue: 200},
|
||||
intensity: 5
|
||||
});
|
||||
|
||||
|
||||
function cleanup() {
|
||||
Entities.deleteEntity(saberHandle);
|
||||
}
|
||||
|
||||
this.cleanup = cleanup;
|
||||
}
|
116
examples/flowArts/lightSaber/lightSaberEntityScript.js
Normal file
116
examples/flowArts/lightSaber/lightSaberEntityScript.js
Normal file
|
@ -0,0 +1,116 @@
|
|||
// lightSaberEntityScript.js
|
||||
//
|
||||
// Script Type: Entity
|
||||
// Created by Eric Levin on 12/17/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This entity script creates the logic for displaying the lightsaber beam.
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function() {
|
||||
Script.include("../../libraries/utils.js");
|
||||
var _this;
|
||||
// this is the "constructor" for the entity as a JS object we don't do much here
|
||||
var LightSaber = function() {
|
||||
_this = this;
|
||||
this.colorPalette = [{
|
||||
red: 0,
|
||||
green: 200,
|
||||
blue: 40
|
||||
}, {
|
||||
red: 200,
|
||||
green: 10,
|
||||
blue: 40
|
||||
}];
|
||||
};
|
||||
|
||||
LightSaber.prototype = {
|
||||
isGrabbed: false,
|
||||
|
||||
startNearGrab: function() {
|
||||
Entities.editEntity(this.beam, {
|
||||
isEmitting: true,
|
||||
visible: true
|
||||
});
|
||||
},
|
||||
|
||||
releaseGrab: function() {
|
||||
Entities.editEntity(this.beam, {
|
||||
visible: false,
|
||||
isEmitting: false
|
||||
});
|
||||
},
|
||||
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
this.createBeam();
|
||||
},
|
||||
|
||||
unload: function() {
|
||||
Entities.deleteEntity(this.beam);
|
||||
},
|
||||
|
||||
createBeam: function() {
|
||||
|
||||
this.props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]);
|
||||
var forwardVec = Quat.getFront(Quat.multiply(this.props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0)));
|
||||
var forwardQuat = Quat.rotationBetween(Vec3.UNIT_Z, forwardVec);
|
||||
var position = this.props.position;
|
||||
|
||||
var color = this.colorPalette[randInt(0, this.colorPalette.length)];
|
||||
var props = {
|
||||
type: "ParticleEffect",
|
||||
name: "LightSaber Beam",
|
||||
position: position,
|
||||
parentID: this.entityID,
|
||||
isEmitting: false,
|
||||
colorStart: color,
|
||||
color: {
|
||||
red: 200,
|
||||
green: 200,
|
||||
blue: 255
|
||||
},
|
||||
colorFinish: color,
|
||||
maxParticles: 100000,
|
||||
lifespan: 2,
|
||||
emitRate: 1000,
|
||||
emitOrientation: forwardQuat,
|
||||
emitSpeed: 0.7,
|
||||
speedSpread: 0.0,
|
||||
emitDimensions: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
polarStart: 0,
|
||||
polarFinish: 0,
|
||||
azimuthStart: 0.1,
|
||||
azimuthFinish: 0.01,
|
||||
emitAcceleration: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: 0
|
||||
},
|
||||
accelerationSpread: {
|
||||
x: .00,
|
||||
y: .00,
|
||||
z: .00
|
||||
},
|
||||
radiusStart: 0.03,
|
||||
adiusFinish: 0.025,
|
||||
alpha: 0.7,
|
||||
alphaSpread: 0.1,
|
||||
alphaStart: 0.5,
|
||||
alphaFinish: 0.5,
|
||||
textures: "https://s3.amazonaws.com/hifi-public/eric/textures/particleSprites/beamParticle.png",
|
||||
emitterShouldTrail: false
|
||||
}
|
||||
this.beam = Entities.addEntity(props);
|
||||
|
||||
}
|
||||
};
|
||||
// entity scripts always need to return a newly constructed object of our type
|
||||
return new LightSaber();
|
||||
});
|
191
examples/flowArts/lightTrails.js
Normal file
191
examples/flowArts/lightTrails.js
Normal file
|
@ -0,0 +1,191 @@
|
|||
//
|
||||
// lightTrails.js
|
||||
// examples
|
||||
//
|
||||
// Created by Eric Levin on 5/14/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This script creates light trails as you move your hydra hands
|
||||
//
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("../libraries/utils.js");
|
||||
|
||||
var eraseTrail = true;
|
||||
var ugLSD = 25;
|
||||
// var eraseTrail = false;
|
||||
var LEFT = 0;
|
||||
var RIGHT = 1;
|
||||
var MAX_POINTS_PER_LINE = 50;
|
||||
|
||||
var LIFETIME = 6000;
|
||||
var DRAWING_DEPTH = 0.8;
|
||||
var LINE_DIMENSIONS = 100;
|
||||
|
||||
|
||||
var MIN_POINT_DISTANCE = 0.02;
|
||||
|
||||
|
||||
var colorPalette = [{
|
||||
red: 250,
|
||||
green: 137,
|
||||
blue: 162
|
||||
}, {
|
||||
red: 204,
|
||||
green: 244,
|
||||
blue: 249
|
||||
}, {
|
||||
red: 146,
|
||||
green: 206,
|
||||
blue: 116
|
||||
}, {
|
||||
red: 240,
|
||||
green: 87,
|
||||
blue: 129
|
||||
}];
|
||||
|
||||
var STROKE_WIDTH = 0.04;
|
||||
|
||||
function controller(side, triggerAction) {
|
||||
this.triggerHeld = false;
|
||||
this.triggerThreshold = 0.9;
|
||||
this.side = side;
|
||||
this.triggerAction = triggerAction;
|
||||
var texture = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/trails.png";
|
||||
|
||||
this.light = Entities.addEntity({
|
||||
type: 'Light',
|
||||
position: MyAvatar.position,
|
||||
dimensions: {
|
||||
x: 30,
|
||||
y: 30,
|
||||
z: 30
|
||||
},
|
||||
color: colorPalette[randInt(0, colorPalette.length)],
|
||||
intensity: 5
|
||||
});
|
||||
|
||||
this.trail = Entities.addEntity({
|
||||
type: "PolyLine",
|
||||
dimensions: {
|
||||
x: LINE_DIMENSIONS,
|
||||
y: LINE_DIMENSIONS,
|
||||
z: LINE_DIMENSIONS
|
||||
},
|
||||
color: {red: 255, green: 255, blue: 255},
|
||||
textures: texture,
|
||||
lifetime: LIFETIME
|
||||
});
|
||||
this.points = [];
|
||||
this.normals = [];
|
||||
this.strokeWidths = [];
|
||||
var self = this;
|
||||
|
||||
this.trailEraseInterval = Script.setInterval(function() {
|
||||
if (self.points.length > 0 && eraseTrail) {
|
||||
self.points.shift();
|
||||
self.normals.shift();
|
||||
self.strokeWidths.shift();
|
||||
Entities.editEntity(self.trail, {
|
||||
linePoints: self.points,
|
||||
strokeWidths: self.strokeWidths,
|
||||
normals: self.normals
|
||||
});
|
||||
}
|
||||
}, ugLSD);
|
||||
|
||||
|
||||
this.setTrailPosition = function(position) {
|
||||
this.trailPosition = position;
|
||||
Entities.editEntity(this.trail, {
|
||||
position: this.trailPosition
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
this.update = function(deltaTime) {
|
||||
this.updateControllerState();
|
||||
var newTrailPosOffset = Vec3.multiply(Vec3.normalize(Vec3.subtract(this.tipPosition, this.palmPosition)), DRAWING_DEPTH);
|
||||
var newTrailPos = Vec3.sum(this.palmPosition, newTrailPosOffset);
|
||||
Entities.editEntity(this.light, {
|
||||
position: newTrailPos
|
||||
});
|
||||
|
||||
|
||||
if (!this.drawing) {
|
||||
this.setTrailPosition(newTrailPos);
|
||||
this.drawing = true;
|
||||
}
|
||||
|
||||
if (this.drawing) {
|
||||
var localPoint = Vec3.subtract(newTrailPos, this.trailPosition);
|
||||
if (Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) {
|
||||
//Need a minimum distance to avoid binormal NANs
|
||||
return;
|
||||
}
|
||||
|
||||
if (this.points.length === MAX_POINTS_PER_LINE) {
|
||||
this.points.shift();
|
||||
this.normals.shift();
|
||||
this.strokeWidths.shift();
|
||||
}
|
||||
|
||||
this.points.push(localPoint);
|
||||
var normal = computeNormal(newTrailPos, Camera.getPosition());
|
||||
|
||||
this.normals.push(normal);
|
||||
this.strokeWidths.push(STROKE_WIDTH + Math.random() * 0.01);
|
||||
Entities.editEntity(this.trail, {
|
||||
linePoints: this.points,
|
||||
normals: this.normals,
|
||||
strokeWidths: this.strokeWidths,
|
||||
});
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
this.updateControllerState = function() {
|
||||
this.palmPosition = this.side == RIGHT ? MyAvatar.rightHandPose.translation : MyAvatar.leftHandPose.translation;
|
||||
this.tipPosition = this.side == RIGHT ? MyAvatar.rightHandTipPose.translation : MyAvatar.leftHandTipPose.translation;
|
||||
this.triggerValue = Controller.getActionValue(this.triggerAction);
|
||||
|
||||
}
|
||||
|
||||
this.cleanup = function() {
|
||||
Entities.deleteEntity(this.trail);
|
||||
Entities.deleteEntity(this.light);
|
||||
Script.clearInterval(this.trailEraseInterval);
|
||||
}
|
||||
}
|
||||
|
||||
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, Controller.findAction("RIGHT_HAND_CLICK"));
|
||||
var leftController = new controller(LEFT, Controller.findAction("LEFT_HAND_CLICK"));
|
||||
Script.update.connect(update);
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
||||
function map(value, min1, max1, min2, max2) {
|
||||
return min2 + (max2 - min2) * ((value - min1) / (max1 - min1));
|
||||
}
|
90
examples/flowArts/raveStick/raveStick.js
Normal file
90
examples/flowArts/raveStick/raveStick.js
Normal file
|
@ -0,0 +1,90 @@
|
|||
//
|
||||
// RaveStick.js
|
||||
// examples/flowArats/raveStick
|
||||
//
|
||||
// Created by Eric Levin on 12/17/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This script creates a rave stick which makes pretty light trails as you paint
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
Script.include("../../libraries/utils.js");
|
||||
var modelURL = "https://s3-us-west-1.amazonaws.com/hifi-content/eric/models/raveStick.fbx";
|
||||
var scriptURL = Script.resolvePath("raveStickEntityScript.js");
|
||||
RaveStick = function(spawnPosition) {
|
||||
var colorPalette = [{
|
||||
red: 0,
|
||||
green: 200,
|
||||
blue: 40
|
||||
}, {
|
||||
red: 200,
|
||||
green: 10,
|
||||
blue: 40
|
||||
}];
|
||||
var stick = Entities.addEntity({
|
||||
type: "Model",
|
||||
name: "raveStick",
|
||||
modelURL: modelURL,
|
||||
position: spawnPosition,
|
||||
shapeType: 'box',
|
||||
collisionsWillMove: true,
|
||||
script: scriptURL,
|
||||
dimensions: {
|
||||
x: 0.06,
|
||||
y: 0.06,
|
||||
z: 0.31
|
||||
},
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
spatialKey: {
|
||||
relativePosition: {
|
||||
x: 0,
|
||||
y: 0,
|
||||
z: -0.1
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(90, 90, 0)
|
||||
},
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
var light = Entities.addEntity({
|
||||
type: 'Light',
|
||||
name: "raveLight",
|
||||
parentID: stick,
|
||||
dimensions: {
|
||||
x: 30,
|
||||
y: 30,
|
||||
z: 30
|
||||
},
|
||||
color: colorPalette[randInt(0, colorPalette.length)],
|
||||
intensity: 5
|
||||
});
|
||||
|
||||
var rotation = Quat.fromPitchYawRollDegrees(0, 0, 0)
|
||||
var forwardVec = Quat.getFront(Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0)));
|
||||
forwardVec = Vec3.normalize(forwardVec);
|
||||
var forwardQuat = orientationOf(forwardVec);
|
||||
var position = Vec3.sum(spawnPosition, Vec3.multiply(Quat.getFront(rotation), 0.1));
|
||||
position.z += 0.1;
|
||||
position.x += -0.035;
|
||||
var color = {
|
||||
red: 0,
|
||||
green: 200,
|
||||
blue: 40
|
||||
};
|
||||
|
||||
|
||||
|
||||
|
||||
function cleanup() {
|
||||
Entities.deleteEntity(stick);
|
||||
Entities.deleteEntity(light);
|
||||
}
|
||||
|
||||
this.cleanup = cleanup;
|
||||
}
|
141
examples/flowArts/raveStick/raveStickEntityScript.js
Normal file
141
examples/flowArts/raveStick/raveStickEntityScript.js
Normal file
|
@ -0,0 +1,141 @@
|
|||
// raveStickEntityScript.js
|
||||
//
|
||||
// Script Type: Entity
|
||||
// Created by Eric Levin on 12/16/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This entity script create light trails on a given object as it moves.
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function() {
|
||||
Script.include("../../libraries/utils.js");
|
||||
var _this;
|
||||
var LIFETIME = 6000;
|
||||
var DRAWING_DEPTH = 0.8;
|
||||
var LINE_DIMENSIONS = 100;
|
||||
var MAX_POINTS_PER_LINE = 50;
|
||||
var MIN_POINT_DISTANCE = 0.02;
|
||||
var STROKE_WIDTH = 0.05
|
||||
var ugLSD = 35;
|
||||
var RaveStick = function() {
|
||||
_this = this;
|
||||
this.colorPalette = [{
|
||||
red: 0,
|
||||
green: 200,
|
||||
blue: 40
|
||||
}, {
|
||||
red: 200,
|
||||
green: 10,
|
||||
blue: 40
|
||||
}];
|
||||
var texture = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/trails.png";
|
||||
this.trail = Entities.addEntity({
|
||||
type: "PolyLine",
|
||||
dimensions: {
|
||||
x: LINE_DIMENSIONS,
|
||||
y: LINE_DIMENSIONS,
|
||||
z: LINE_DIMENSIONS
|
||||
},
|
||||
color: {
|
||||
red: 255,
|
||||
green: 255,
|
||||
blue: 255
|
||||
},
|
||||
textures: texture,
|
||||
lifetime: LIFETIME
|
||||
});
|
||||
|
||||
this.points = [];
|
||||
this.normals = [];
|
||||
this.strokeWidths = [];
|
||||
};
|
||||
|
||||
RaveStick.prototype = {
|
||||
isGrabbed: false,
|
||||
|
||||
startNearGrab: function() {
|
||||
this.trailBasePosition = Entities.getEntityProperties(this.entityID, "position").position;
|
||||
Entities.editEntity(this.trail, {
|
||||
position: this.trailBasePosition
|
||||
});
|
||||
this.points = [];
|
||||
this.normals = [];
|
||||
this.strokeWidths = [];
|
||||
this.setupEraseInterval();
|
||||
},
|
||||
|
||||
continueNearGrab: function() {
|
||||
var props = Entities.getEntityProperties(this.entityID, ["position", "rotation"]);
|
||||
var forwardVec = Quat.getFront(Quat.multiply(props.rotation, Quat.fromPitchYawRollDegrees(-90, 0, 0)));
|
||||
forwardVec = Vec3.normalize(forwardVec);
|
||||
var forwardQuat = orientationOf(forwardVec);
|
||||
var position = Vec3.sum(props.position, Vec3.multiply(Quat.getFront(props.rotation), 0.04));
|
||||
var localPoint = Vec3.subtract(position, this.trailBasePosition);
|
||||
if (this.points.length >= 1 && Vec3.distance(localPoint, this.points[this.points.length - 1]) < MIN_POINT_DISTANCE) {
|
||||
//Need a minimum distance to avoid binormal NANs
|
||||
return;
|
||||
}
|
||||
if (this.points.length === MAX_POINTS_PER_LINE) {
|
||||
this.points.shift();
|
||||
this.normals.shift();
|
||||
this.strokeWidths.shift();
|
||||
}
|
||||
|
||||
this.points.push(localPoint);
|
||||
var normal = Quat.getUp(props.rotation);
|
||||
this.normals.push(normal);
|
||||
this.strokeWidths.push(STROKE_WIDTH);
|
||||
Entities.editEntity(this.trail, {
|
||||
linePoints: this.points,
|
||||
normals: this.normals,
|
||||
strokeWidths: this.strokeWidths
|
||||
});
|
||||
|
||||
|
||||
},
|
||||
|
||||
setupEraseInterval: function() {
|
||||
this.trailEraseInterval = Script.setInterval(function() {
|
||||
if (_this.points.length > 0) {
|
||||
_this.points.shift();
|
||||
_this.normals.shift();
|
||||
_this.strokeWidths.shift();
|
||||
Entities.editEntity(_this.trail, {
|
||||
linePoints: _this.points,
|
||||
strokeWidths: _this.strokeWidths,
|
||||
normals: _this.normals
|
||||
});
|
||||
}
|
||||
}, ugLSD);
|
||||
},
|
||||
|
||||
releaseGrab: function() {
|
||||
if(!this.trailEraseInterval) {
|
||||
return;
|
||||
}
|
||||
Script.setTimeout(function() {
|
||||
Script.clearInterval(_this.trailEraseInterval);
|
||||
_this.trailEraseInterval = null;
|
||||
}, 3000);
|
||||
},
|
||||
|
||||
preload: function(entityID) {
|
||||
this.entityID = entityID;
|
||||
},
|
||||
|
||||
unload: function() {
|
||||
Entities.deleteEntity(this.beam);
|
||||
Entities.deleteEntity(this.trail);
|
||||
if (this.trailEraseInterval) {
|
||||
Script.clearInterval(this.trailEraseInterval);
|
||||
}
|
||||
}
|
||||
};
|
||||
return new RaveStick();
|
||||
|
||||
function computeNormal(p1, p2) {
|
||||
return Vec3.normalize(Vec3.subtract(p2, p1));
|
||||
}
|
||||
});
|
|
@ -43,6 +43,8 @@ var MAX_STROKE_WIDTH = 0.04;
|
|||
|
||||
var center = Vec3.sum(MyAvatar.position, Vec3.multiply(2, Quat.getFront(Camera.getOrientation())));
|
||||
|
||||
var textureURL = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/paintStroke.png";
|
||||
|
||||
|
||||
|
||||
function MyController(hand, triggerAction) {
|
||||
|
@ -148,7 +150,8 @@ function MyController(hand, triggerAction) {
|
|||
y: 50,
|
||||
z: 50
|
||||
},
|
||||
lifetime: 200
|
||||
lifetime: 200,
|
||||
textures: textureURL
|
||||
});
|
||||
this.strokePoints = [];
|
||||
this.strokeNormals = [];
|
||||
|
|
|
@ -29,6 +29,8 @@
|
|||
var MIN_STROKE_WIDTH = 0.0005;
|
||||
var MAX_STROKE_WIDTH = 0.03;
|
||||
|
||||
var textureURL = "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/paintStroke.png";
|
||||
|
||||
var TRIGGER_CONTROLS = [
|
||||
Controller.Standard.LT,
|
||||
Controller.Standard.RT,
|
||||
|
@ -168,6 +170,7 @@
|
|||
type: "PolyLine",
|
||||
name: "paintStroke",
|
||||
color: this.strokeColor,
|
||||
textures: "https://s3.amazonaws.com/hifi-public/eric/textures/paintStrokes/paintStroke.png",
|
||||
dimensions: {
|
||||
x: 50,
|
||||
y: 50,
|
||||
|
|
|
@ -241,9 +241,9 @@
|
|||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
grabbable: false
|
||||
}
|
||||
},
|
||||
creatorSessionUUID: MyAvatar.sessionUUID
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
var makeArrowStick = function(entityA, entityB, collision) {
|
||||
|
|
|
@ -38,6 +38,14 @@ var pingPongGun = Entities.addEntity({
|
|||
collisionSoundURL: COLLISION_SOUND_URL,
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
spatialKey: {
|
||||
relativePosition: {
|
||||
x: -0.05,
|
||||
y: 0,
|
||||
z: 0.0
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(0, -90, -90)
|
||||
},
|
||||
invertSolidWhileHeld: true
|
||||
}
|
||||
})
|
||||
|
|
|
@ -384,10 +384,10 @@ var CHECK_MARK_COLOR = {
|
|||
y: newY
|
||||
});
|
||||
Overlays.editOverlay(this.checkMark, {
|
||||
y: newY
|
||||
y: newY + (0.25 * this.thumbSize)
|
||||
});
|
||||
Overlays.editOverlay(this.unCheckMark, {
|
||||
y: newY
|
||||
y: newY + (0.25 * this.thumbSize)
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -399,10 +399,10 @@ var CHECK_MARK_COLOR = {
|
|||
y: this.y
|
||||
});
|
||||
Overlays.editOverlay(this.checkMark, {
|
||||
y: this.y
|
||||
y: this.y + (0.25 * this.thumbSize)
|
||||
});
|
||||
Overlays.editOverlay(this.unCheckMark, {
|
||||
y: this.y
|
||||
y: this.y+ (0.25 * this.thumbSize)
|
||||
});
|
||||
};
|
||||
|
||||
|
@ -814,12 +814,14 @@ var CHECK_MARK_COLOR = {
|
|||
});
|
||||
};
|
||||
|
||||
|
||||
CollapsablePanelItem.prototype.destroy = function() {
|
||||
Overlays.deleteOverlay(this.title);
|
||||
Overlays.deleteOverlay(this.thumb);
|
||||
};
|
||||
|
||||
CollapsablePanelItem.prototype.editTitle = function(opts) {
|
||||
Overlays.editOverlay(this.title, opts);
|
||||
};
|
||||
|
||||
CollapsablePanelItem.prototype.hide = function() {
|
||||
Overlays.editOverlay(this.title, {
|
||||
|
@ -1531,4 +1533,4 @@ Controller.captureKeyEvents({
|
|||
});
|
||||
Controller.captureKeyEvents({
|
||||
text: "right"
|
||||
});
|
||||
});
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
//
|
||||
// SunLightExample.js
|
||||
// examples
|
||||
// renderEngineDebug.js
|
||||
// examples/utilities/tools
|
||||
//
|
||||
// Sam Gateau
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
|
@ -10,78 +11,93 @@
|
|||
|
||||
Script.include("cookies.js");
|
||||
|
||||
var MENU = "Developer>Render>Debug Deferred Buffer";
|
||||
var ACTIONS = ["Off", "Diffuse", "Alpha", "Specular", "Roughness", "Normal", "Depth", "Lighting", "Custom"];
|
||||
var SETTINGS_KEY = "EngineDebugScript.DebugMode";
|
||||
|
||||
Number.prototype.clamp = function(min, max) {
|
||||
return Math.min(Math.max(this, min), max);
|
||||
};
|
||||
|
||||
var panel = new Panel(10, 100);
|
||||
|
||||
function CounterWidget(parentPanel, name, feedGetter, drawGetter, capSetter, capGetter) {
|
||||
this.subPanel = panel.newSubPanel(name);
|
||||
function CounterWidget(parentPanel, name, counter) {
|
||||
var subPanel = parentPanel.newSubPanel(name);
|
||||
var widget = parentPanel.items[name];
|
||||
widget.editTitle({ width: 270 });
|
||||
|
||||
this.subPanel.newSlider("Num Feed", 0, 1,
|
||||
function(value) { },
|
||||
feedGetter,
|
||||
function(value) { return (value); });
|
||||
this.subPanel.newSlider("Num Drawn", 0, 1,
|
||||
function(value) { },
|
||||
drawGetter,
|
||||
function(value) { return (value); });
|
||||
this.subPanel.newSlider("Max Drawn", -1, 1,
|
||||
capSetter,
|
||||
capGetter,
|
||||
function(value) { return (value); });
|
||||
subPanel.newSlider('Max Drawn', -1, 1,
|
||||
function(value) { counter.maxDrawn = value; }, // setter
|
||||
function() { return counter.maxDrawn; }, // getter
|
||||
function(value) { return value; });
|
||||
|
||||
this.update = function () {
|
||||
var numFeed = this.subPanel.get("Num Feed");
|
||||
this.subPanel.set("Num Feed", numFeed);
|
||||
this.subPanel.set("Num Drawn", this.subPanel.get("Num Drawn"));
|
||||
var slider = subPanel.getWidget('Max Drawn');
|
||||
|
||||
var numMax = Math.max(numFeed, 1);
|
||||
this.subPanel.getWidget("Num Feed").setMaxValue(numMax);
|
||||
this.subPanel.getWidget("Num Drawn").setMaxValue(numMax);
|
||||
this.subPanel.getWidget("Max Drawn").setMaxValue(numMax);
|
||||
this.update = function () {
|
||||
var numDrawn = counter.numDrawn; // avoid double polling
|
||||
var numMax = Math.max(numDrawn, 1);
|
||||
var title = [
|
||||
' ' + name,
|
||||
numDrawn + ' / ' + counter.numFeed
|
||||
].join('\t');
|
||||
|
||||
widget.editTitle({ text: title });
|
||||
slider.setMaxValue(numMax);
|
||||
};
|
||||
};
|
||||
|
||||
var opaquesCounter = new CounterWidget(panel, "Opaques",
|
||||
function () { return Scene.getEngineNumFeedOpaqueItems(); },
|
||||
function () { return Scene.getEngineNumDrawnOpaqueItems(); },
|
||||
function(value) { Scene.setEngineMaxDrawnOpaqueItems(value); },
|
||||
function () { return Scene.getEngineMaxDrawnOpaqueItems(); }
|
||||
);
|
||||
var opaquesCounter = new CounterWidget(panel, "Opaques", Render.opaque);
|
||||
var transparentsCounter = new CounterWidget(panel, "Transparents", Render.transparent);
|
||||
var overlaysCounter = new CounterWidget(panel, "Overlays", Render.overlay3D);
|
||||
|
||||
var transparentsCounter = new CounterWidget(panel, "Transparents",
|
||||
function () { return Scene.getEngineNumFeedTransparentItems(); },
|
||||
function () { return Scene.getEngineNumDrawnTransparentItems(); },
|
||||
function(value) { Scene.setEngineMaxDrawnTransparentItems(value); },
|
||||
function () { return Scene.getEngineMaxDrawnTransparentItems(); }
|
||||
);
|
||||
var resizing = false;
|
||||
var previousMode = Settings.getValue(SETTINGS_KEY, -1);
|
||||
Menu.addActionGroup(MENU, ACTIONS, ACTIONS[previousMode + 1]);
|
||||
Render.deferredDebugMode = previousMode;
|
||||
Render.deferredDebugSize = { x: 0.0, y: -1.0, z: 1.0, w: 1.0 }; // Reset to default size
|
||||
|
||||
var overlaysCounter = new CounterWidget(panel, "Overlays",
|
||||
function () { return Scene.getEngineNumFeedOverlay3DItems(); },
|
||||
function () { return Scene.getEngineNumDrawnOverlay3DItems(); },
|
||||
function(value) { Scene.setEngineMaxDrawnOverlay3DItems(value); },
|
||||
function () { return Scene.getEngineMaxDrawnOverlay3DItems(); }
|
||||
);
|
||||
function setEngineDeferredDebugSize(eventX) {
|
||||
var scaledX = (2.0 * (eventX / Window.innerWidth) - 1.0).clamp(-1.0, 1.0);
|
||||
Render.deferredDebugSize = { x: scaledX, y: -1.0, z: 1.0, w: 1.0 };
|
||||
}
|
||||
function shouldStartResizing(eventX) {
|
||||
var x = Math.abs(eventX - Window.innerWidth * (1.0 + Render.deferredDebugSize.x) / 2.0);
|
||||
var mode = Render.deferredDebugMode;
|
||||
return mode !== -1 && x < 20;
|
||||
}
|
||||
|
||||
function menuItemEvent(menuItem) {
|
||||
var index = ACTIONS.indexOf(menuItem);
|
||||
if (index >= 0) {
|
||||
Render.deferredDebugMode = (index - 1);
|
||||
}
|
||||
}
|
||||
|
||||
// see libraries/render/src/render/Engine.h
|
||||
var showDisplayStatusFlag = 1;
|
||||
var showNetworkStatusFlag = 2;
|
||||
|
||||
panel.newCheckbox("Display status",
|
||||
function(value) { Scene.setEngineDisplayItemStatus(value ?
|
||||
Scene.doEngineDisplayItemStatus() | showDisplayStatusFlag :
|
||||
Scene.doEngineDisplayItemStatus() & ~showDisplayStatusFlag); },
|
||||
function() { return (Scene.doEngineDisplayItemStatus() & showDisplayStatusFlag) > 0; },
|
||||
function(value) { Render.displayItemStatus = (value ?
|
||||
Render.displayItemStatus | showDisplayStatusFlag :
|
||||
Render.displayItemStatus & ~showDisplayStatusFlag); },
|
||||
function() { return (Render.displayItemStatus & showDisplayStatusFlag) > 0; },
|
||||
function(value) { return (value & showDisplayStatusFlag) > 0; }
|
||||
);
|
||||
|
||||
panel.newCheckbox("Network/Physics status",
|
||||
function(value) { Scene.setEngineDisplayItemStatus(value ?
|
||||
Scene.doEngineDisplayItemStatus() | showNetworkStatusFlag :
|
||||
Scene.doEngineDisplayItemStatus() & ~showNetworkStatusFlag); },
|
||||
function() { return (Scene.doEngineDisplayItemStatus() & showNetworkStatusFlag) > 0; },
|
||||
function(value) { Render.displayItemStatus = (value ?
|
||||
Render.displayItemStatus | showNetworkStatusFlag :
|
||||
Render.displayItemStatus & ~showNetworkStatusFlag); },
|
||||
function() { return (Render.displayItemStatus & showNetworkStatusFlag) > 0; },
|
||||
function(value) { return (value & showNetworkStatusFlag) > 0; }
|
||||
);
|
||||
|
||||
panel.newSlider("Tone Mapping Exposure", -10, 10,
|
||||
function (value) { Render.tone.exposure = value; },
|
||||
function() { return Render.tone.exposure; },
|
||||
function (value) { return (value); });
|
||||
|
||||
var tickTackPeriod = 500;
|
||||
|
||||
function updateCounters() {
|
||||
|
@ -91,11 +107,51 @@ function updateCounters() {
|
|||
}
|
||||
Script.setInterval(updateCounters, tickTackPeriod);
|
||||
|
||||
Controller.mouseMoveEvent.connect(function panelMouseMoveEvent(event) { return panel.mouseMoveEvent(event); });
|
||||
Controller.mousePressEvent.connect( function panelMousePressEvent(event) { return panel.mousePressEvent(event); });
|
||||
Controller.mouseReleaseEvent.connect(function(event) { return panel.mouseReleaseEvent(event); });
|
||||
function mouseMoveEvent(event) {
|
||||
if (resizing) {
|
||||
setEngineDeferredDebugSize(event.x);
|
||||
} else {
|
||||
panel.mouseMoveEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
function mousePressEvent(event) {
|
||||
if (shouldStartResizing(event.x)) {
|
||||
resizing = true;
|
||||
} else {
|
||||
panel.mousePressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
function mouseReleaseEvent(event) {
|
||||
if (resizing) {
|
||||
resizing = false;
|
||||
} else {
|
||||
panel.mouseReleaseEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
Controller.mouseMoveEvent.connect(mouseMoveEvent);
|
||||
Controller.mousePressEvent.connect(mousePressEvent);
|
||||
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
|
||||
|
||||
Menu.menuItemEvent.connect(menuItemEvent);
|
||||
|
||||
function scriptEnding() {
|
||||
panel.destroy();
|
||||
Menu.removeActionGroup(MENU);
|
||||
// Reset
|
||||
Settings.setValue(SETTINGS_KEY, Render.deferredDebugMode);
|
||||
Render.deferredDebugMode = -1;
|
||||
Render.deferredDebugSize = { x: 0.0, y: -1.0, z: 1.0, w: 1.0 };
|
||||
Render.opaque.maxDrawn = -1;
|
||||
Render.transparent.maxDrawn = -1;
|
||||
Render.overlay3D.maxDrawn = -1;
|
||||
}
|
||||
Script.scriptEnding.connect(scriptEnding);
|
||||
|
||||
|
||||
// Collapse items
|
||||
panel.mousePressEvent({ x: panel.x, y: panel.items["Overlays"].y});
|
||||
panel.mousePressEvent({ x: panel.x, y: panel.items["Transparents"].y});
|
||||
panel.mousePressEvent({ x: panel.x, y: panel.items["Opaques"].y});
|
||||
|
|
73
examples/winterSmashUp/targetPractice/shooterPlatform.js
Normal file
73
examples/winterSmashUp/targetPractice/shooterPlatform.js
Normal file
|
@ -0,0 +1,73 @@
|
|||
//
|
||||
// shooterPlatform.js
|
||||
// examples/winterSmashUp/targetPractice
|
||||
//
|
||||
// Created by Thijs Wenker on 12/21/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// The Winter Smash Up Target Practice Game using a bow.
|
||||
// This is the platform that spawns the bow and attaches it to the avatars hand,
|
||||
// then de-rez the bow on leaving to prevent walking up to the targets with the bow.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function() {
|
||||
var _this = this;
|
||||
|
||||
const GAME_CHANNEL = 'winterSmashUpGame';
|
||||
const SCRIPT_URL = Script.resolvePath('../../toybox/bow/bow.js');
|
||||
const MODEL_URL = "https://hifi-public.s3.amazonaws.com/models/bow/new/bow-deadly.fbx";
|
||||
const COLLISION_HULL_URL = "https://hifi-public.s3.amazonaws.com/models/bow/new/bow_collision_hull.obj";
|
||||
const RIGHT_HAND = 1;
|
||||
const LEFT_HAND = 0;
|
||||
|
||||
var bowEntity = undefined;
|
||||
|
||||
_this.enterEntity = function(entityID) {
|
||||
print('entered bow game entity');
|
||||
|
||||
// Triggers a recording on an assignment client:
|
||||
Messages.sendMessage('PlayBackOnAssignment', 'BowShootingGameExplaination');
|
||||
|
||||
bowEntity = Entities.addEntity({
|
||||
name: 'Hifi-Bow-For-Game',
|
||||
type: 'Model',
|
||||
modelURL: MODEL_URL,
|
||||
position: MyAvatar.position,
|
||||
dimensions: {x: 0.04, y: 1.3, z: 0.21},
|
||||
collisionsWillMove: true,
|
||||
gravity: {x: 0, y: 0, z: 0},
|
||||
shapeType: 'compound',
|
||||
compoundShapeURL: COLLISION_HULL_URL,
|
||||
script: SCRIPT_URL,
|
||||
userData: JSON.stringify({
|
||||
grabbableKey: {
|
||||
invertSolidWhileHeld: true,
|
||||
spatialKey: {
|
||||
leftRelativePosition: {
|
||||
x: 0.05,
|
||||
y: 0.06,
|
||||
z: -0.05
|
||||
},
|
||||
rightRelativePosition: {
|
||||
x: -0.05,
|
||||
y: 0.06,
|
||||
z: -0.05
|
||||
},
|
||||
relativeRotation: Quat.fromPitchYawRollDegrees(0, 90, -90)
|
||||
}
|
||||
}
|
||||
})
|
||||
});
|
||||
Messages.sendMessage('Hifi-Hand-Grab', JSON.stringify({hand: 'left', entityID: bowEntity}));
|
||||
};
|
||||
|
||||
_this.leaveEntity = function(entityID) {
|
||||
if (bowEntity !== undefined) {
|
||||
Entities.deleteEntity(bowEntity);
|
||||
bowEntity = undefined;
|
||||
}
|
||||
};
|
||||
});
|
93
examples/winterSmashUp/targetPractice/startTargetPractice.js
Normal file
93
examples/winterSmashUp/targetPractice/startTargetPractice.js
Normal file
|
@ -0,0 +1,93 @@
|
|||
//
|
||||
// startTargetPractice.js
|
||||
// examples/winterSmashUp/targetPractice
|
||||
//
|
||||
// Created by Thijs Wenker on 12/21/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// The Winter Smash Up Target Practice Game using a bow.
|
||||
// This script starts the game, when the entity that contains the script gets shot.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
(function() {
|
||||
var _this = this;
|
||||
var waitForScriptLoad = false;
|
||||
|
||||
const MAX_GAME_TIME = 60; //seconds
|
||||
const SCRIPT_URL = 'http://s3.amazonaws.com/hifi-public/scripts/winterSmashUp/targetPractice/targetPracticeGame.js';
|
||||
const GAME_CHANNEL = 'winterSmashUpGame';
|
||||
|
||||
var isScriptRunning = function(script) {
|
||||
script = script.toLowerCase().trim();
|
||||
var runningScripts = ScriptDiscoveryService.getRunning();
|
||||
for (i in runningScripts) {
|
||||
if (runningScripts[i].url.toLowerCase().trim() == script) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
var sendStartSignal = function() {
|
||||
Messages.sendMessage(GAME_CHANNEL, JSON.stringify({
|
||||
action: 'start',
|
||||
gameEntityID: _this.entityID,
|
||||
playerSessionUUID: MyAvatar.sessionUUID
|
||||
}));
|
||||
}
|
||||
|
||||
var startGame = function() {
|
||||
//TODO: check here if someone is already playing this game instance by verifying the userData for playerSessionID
|
||||
// and startTime with a maximum timeout of X seconds (30?)
|
||||
|
||||
|
||||
if (!isScriptRunning(SCRIPT_URL)) {
|
||||
// Loads the script for the player if this isn't yet loaded
|
||||
Script.load(SCRIPT_URL);
|
||||
waitForScriptLoad = true;
|
||||
return;
|
||||
}
|
||||
sendStartSignal();
|
||||
};
|
||||
|
||||
Messages.messageReceived.connect(function (channel, message, senderID) {
|
||||
if (channel == GAME_CHANNEL) {
|
||||
var data = JSON.parse(message);
|
||||
switch (data.action) {
|
||||
case 'scriptLoaded':
|
||||
if (waitForPing) {
|
||||
sendStartSignal();
|
||||
waitForPing = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
_this.preload = function(entityID) {
|
||||
_this.entityID = entityID;
|
||||
};
|
||||
|
||||
_this.collisionWithEntity = function(entityA, entityB, collisionInfo) {
|
||||
if (entityA == _this.entityID) {
|
||||
try {
|
||||
var data = JSON.parse(Entities.getEntityProperties(entityB).userData);
|
||||
if (data.creatorSessionUUID === MyAvatar.sessionUUID) {
|
||||
print('attempting to startGame by collisionWithEntity.');
|
||||
startGame();
|
||||
}
|
||||
} catch(e) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
_this.onShot = function(forceDirection) {
|
||||
print('attempting to startGame by onShot.');
|
||||
startGame();
|
||||
};
|
||||
|
||||
Messages.subscribe(GAME_CHANNEL);
|
||||
});
|
227
examples/winterSmashUp/targetPractice/targetPracticeGame.js
Normal file
227
examples/winterSmashUp/targetPractice/targetPracticeGame.js
Normal file
|
@ -0,0 +1,227 @@
|
|||
//
|
||||
// targetPracticeGame.js
|
||||
// examples/winterSmashUp/targetPractice
|
||||
//
|
||||
// Created by Thijs Wenker on 12/21/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// The Winter Smash Up Target Practice Game using a bow.
|
||||
// This script runs on the client side (it is loaded through the platform trigger entity)
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
const GAME_CHANNEL = 'winterSmashUpGame';
|
||||
const SCORE_POST_URL = 'https://script.google.com/macros/s/AKfycbwZAMx6cMBx6-8NGEhR8ELUA-dldtpa_4P55z38Q4vYHW6kneg/exec';
|
||||
const MODEL_URL = 'http://cdn.highfidelity.com/chris/production/winter/game/';
|
||||
const MAX_GAME_TIME = 120; //seconds
|
||||
const TARGET_CLOSE_OFFSET = 0.5;
|
||||
const MILLISECS_IN_SEC = 1000;
|
||||
const HIT_SOUND_URL = 'http://hifi-public.s3.amazonaws.com/sounds/Clay_Pigeon_02.L.wav';
|
||||
const GRAVITY = -9.8;
|
||||
const MESSAGE_WIDTH = 100;
|
||||
const MESSAGE_HEIGHT = 50;
|
||||
|
||||
const TARGETS = [
|
||||
{pitch: -1, yaw: -20, maxDistance: 17},
|
||||
{pitch: -1, yaw: -15, maxDistance: 17},
|
||||
{pitch: -1, yaw: -10, maxDistance: 17},
|
||||
{pitch: -2, yaw: -5, maxDistance: 17},
|
||||
{pitch: -1, yaw: 0, maxDistance: 17},
|
||||
{pitch: 3, yaw: 10, maxDistance: 17},
|
||||
{pitch: -1, yaw: 15, maxDistance: 17},
|
||||
{pitch: -1, yaw: 20, maxDistance: 17},
|
||||
{pitch: 2, yaw: 25, maxDistance: 17},
|
||||
{pitch: 0, yaw: 30, maxDistance: 17}
|
||||
];
|
||||
|
||||
var gameRunning = false;
|
||||
var gameStartTime;
|
||||
var gameEntityID;
|
||||
var gameTimeoutTimer;
|
||||
var targetEntities = [];
|
||||
var hitSound = SoundCache.getSound(HIT_SOUND_URL);
|
||||
var messageOverlay = undefined;
|
||||
var messageExpire = 0;
|
||||
|
||||
var clearMessage = function() {
|
||||
if (messageOverlay !== undefined) {
|
||||
Overlays.deleteOverlay(messageOverlay);
|
||||
messageOverlay = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
var displayMessage = function(message, timeout) {
|
||||
clearMessage();
|
||||
messageExpire = Date.now() + timeout;
|
||||
messageOverlay = Overlays.addOverlay('text', {
|
||||
text: message,
|
||||
x: (Window.innerWidth / 2) - (MESSAGE_WIDTH / 2),
|
||||
y: (Window.innerHeight / 2) - (MESSAGE_HEIGHT / 2),
|
||||
width: MESSAGE_WIDTH,
|
||||
height: MESSAGE_HEIGHT,
|
||||
alpha: 1,
|
||||
backgroundAlpha: 0.0,
|
||||
font: {size: 20}
|
||||
});
|
||||
};
|
||||
|
||||
var getStatsText = function() {
|
||||
var timeLeft = MAX_GAME_TIME - ((Date.now() - gameStartTime) / MILLISECS_IN_SEC);
|
||||
return 'Time remaining: ' + timeLeft.toFixed(1) + 's\nTargets hit: ' + (TARGETS.length - targetEntities.length) + '/' + TARGETS.length;
|
||||
};
|
||||
|
||||
const timerOverlayWidth = 50;
|
||||
var timerOverlay = Overlays.addOverlay('text', {
|
||||
text: '',
|
||||
x: Window.innerWidth / 2 - (timerOverlayWidth / 2),
|
||||
y: 100,
|
||||
width: timerOverlayWidth,
|
||||
alpha: 1,
|
||||
backgroundAlpha: 0.0,
|
||||
visible: false,
|
||||
font: {size: 20}
|
||||
});
|
||||
|
||||
var cleanRemainingTargets = function() {
|
||||
while (targetEntities.length > 0) {
|
||||
Entities.deleteEntity(targetEntities.pop());
|
||||
}
|
||||
};
|
||||
|
||||
var createTarget = function(position, rotation, scale) {
|
||||
var initialDimensions = {x: 1.8437, y: 0.1614, z: 1.8438};
|
||||
var dimensions = Vec3.multiply(initialDimensions, scale);
|
||||
return Entities.addEntity({
|
||||
type: 'Model',
|
||||
rotation: Quat.multiply(rotation, Quat.fromPitchYawRollDegrees(90, 0, 0)),
|
||||
lifetime: MAX_GAME_TIME,
|
||||
modelURL: MODEL_URL + 'target.fbx',
|
||||
shapeType: 'compound',
|
||||
compoundShapeURL: MODEL_URL + 'targetCollision.obj',
|
||||
dimensions: dimensions,
|
||||
position: position
|
||||
});
|
||||
};
|
||||
|
||||
var createTargetInDirection = function(startPosition, startRotation, pitch, yaw, maxDistance, scale) {
|
||||
var directionQuat = Quat.multiply(startRotation, Quat.fromPitchYawRollDegrees(pitch, yaw, 0.0));
|
||||
var directionVec = Vec3.multiplyQbyV(directionQuat, Vec3.FRONT);
|
||||
var intersection = Entities.findRayIntersection({direction: directionVec, origin: startPosition}, true);
|
||||
var distance = maxDistance;
|
||||
if (intersection.intersects && intersection.distance <= maxDistance) {
|
||||
distance = intersection.distance - TARGET_CLOSE_OFFSET;
|
||||
}
|
||||
return createTarget(Vec3.sum(startPosition, Vec3.multiplyQbyV(directionQuat, Vec3.multiply(Vec3.FRONT, distance))), startRotation, scale);
|
||||
};
|
||||
|
||||
var killTimer = function() {
|
||||
if (gameTimeoutTimer !== undefined) {
|
||||
Script.clearTimeout(gameTimeoutTimer);
|
||||
gameTimeoutTimer = undefined;
|
||||
}
|
||||
};
|
||||
|
||||
var submitScore = function() {
|
||||
gameRunning = false;
|
||||
killTimer();
|
||||
Overlays.editOverlay(timerOverlay, {visible: false});
|
||||
if (!GlobalServices.username) {
|
||||
displayMessage('Could not submit score, you are not logged in.', 5000);
|
||||
return;
|
||||
}
|
||||
var timeItTook = Date.now() - gameStartTime;
|
||||
var req = new XMLHttpRequest();
|
||||
req.open('POST', SCORE_POST_URL, false);
|
||||
req.send(JSON.stringify({
|
||||
username: GlobalServices.username,
|
||||
time: timeItTook / MILLISECS_IN_SEC
|
||||
}));
|
||||
displayMessage('Your score has been submitted!', 5000);
|
||||
};
|
||||
|
||||
var onTargetHit = function(targetEntity, projectileEntity, collision) {
|
||||
var targetIndex = targetEntities.indexOf(targetEntity);
|
||||
if (targetIndex !== -1) {
|
||||
try {
|
||||
var data = JSON.parse(Entities.getEntityProperties(projectileEntity).userData);
|
||||
if (data.creatorSessionUUID === MyAvatar.sessionUUID) {
|
||||
this.audioInjector = Audio.playSound(hitSound, {
|
||||
position: collision.contactPoint,
|
||||
volume: 0.5
|
||||
});
|
||||
// Attach arrow to target for the nice effect
|
||||
Entities.editEntity(projectileEntity, {
|
||||
ignoreForCollisions: true,
|
||||
parentID: targetEntity
|
||||
});
|
||||
Entities.editEntity(targetEntity, {
|
||||
collisionsWillMove: true,
|
||||
gravity: {x: 0, y: GRAVITY, z: 0},
|
||||
velocity: {x: 0, y: -0.01, z: 0}
|
||||
});
|
||||
targetEntities.splice(targetIndex, 1);
|
||||
if (targetEntities.length === 0) {
|
||||
submitScore();
|
||||
}
|
||||
}
|
||||
} catch(e) {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var startGame = function(entityID) {
|
||||
cleanRemainingTargets();
|
||||
killTimer();
|
||||
gameEntityID = entityID;
|
||||
targetEntities = [];
|
||||
var parentEntity = Entities.getEntityProperties(gameEntityID);
|
||||
for (var i in TARGETS) {
|
||||
var target = TARGETS[i];
|
||||
var targetEntity = createTargetInDirection(parentEntity.position, parentEntity.rotation, target.pitch, target.yaw, target.maxDistance, 0.67);
|
||||
Script.addEventHandler(targetEntity, 'collisionWithEntity', onTargetHit);
|
||||
targetEntities.push(targetEntity);
|
||||
}
|
||||
gameStartTime = Date.now();
|
||||
gameTimeoutTimer = Script.setTimeout(function() {
|
||||
cleanRemainingTargets();
|
||||
Overlays.editOverlay(timerOverlay, {visible: false});
|
||||
gameRunning = false;
|
||||
displayMessage('Game timed out.', 5000);
|
||||
}, MAX_GAME_TIME * MILLISECS_IN_SEC);
|
||||
gameRunning = true;
|
||||
Overlays.editOverlay(timerOverlay, {visible: true, text: getStatsText()});
|
||||
displayMessage('Game started! GO GO GO!', 3000);
|
||||
};
|
||||
|
||||
Messages.messageReceived.connect(function (channel, message, senderID) {
|
||||
if (channel == GAME_CHANNEL) {
|
||||
var data = JSON.parse(message);
|
||||
switch (data.action) {
|
||||
case 'start':
|
||||
if (data.playerSessionUUID === MyAvatar.sessionUUID) {
|
||||
startGame(data.gameEntityID);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
Messages.subscribe(GAME_CHANNEL);
|
||||
Messages.sendMessage(GAME_CHANNEL, JSON.stringify({action: 'scriptLoaded'}));
|
||||
|
||||
Script.update.connect(function(deltaTime) {
|
||||
if (gameRunning) {
|
||||
Overlays.editOverlay(timerOverlay, {text: getStatsText()});
|
||||
}
|
||||
if (messageOverlay !== undefined && Date.now() > messageExpire) {
|
||||
clearMessage();
|
||||
}
|
||||
});
|
||||
|
||||
Script.scriptEnding.connect(function() {
|
||||
Overlays.deleteOverlay(timerOverlay);
|
||||
cleanRemainingTargets();
|
||||
clearMessage();
|
||||
});
|
|
@ -13,12 +13,18 @@ VrDialog {
|
|||
HifiConstants { id: hifi }
|
||||
title: "WebWindow"
|
||||
resizable: true
|
||||
// Don't destroy on close... otherwise the JS/C++ will have a dangling pointer
|
||||
destroyOnCloseButton: false
|
||||
contentImplicitWidth: clientArea.implicitWidth
|
||||
contentImplicitHeight: clientArea.implicitHeight
|
||||
backgroundColor: "#7f000000"
|
||||
property url source: "about:blank"
|
||||
|
||||
signal navigating(string url)
|
||||
function stop() {
|
||||
webview.stop();
|
||||
}
|
||||
|
||||
|
||||
Component.onCompleted: {
|
||||
enabled = true
|
||||
|
@ -26,18 +32,14 @@ VrDialog {
|
|||
webview.javaScriptConsoleMessage.connect(function(level, message, lineNumber, sourceID) {
|
||||
console.log("Web Window JS message: " + sourceID + " " + lineNumber + " " + message);
|
||||
});
|
||||
|
||||
webview.loadingChanged.connect(handleWebviewLoading)
|
||||
}
|
||||
|
||||
|
||||
function handleWebviewLoading(loadRequest) {
|
||||
var HIFI_URL_PATTERN = /^hifi:\/\//;
|
||||
if (WebEngineView.LoadStartedStatus == loadRequest.status) {
|
||||
var newUrl = loadRequest.url.toString();
|
||||
if (newUrl.match(HIFI_URL_PATTERN)) {
|
||||
root.navigating(newUrl);
|
||||
}
|
||||
root.navigating(newUrl)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -54,9 +56,18 @@ VrDialog {
|
|||
id: webview
|
||||
url: root.source
|
||||
anchors.fill: parent
|
||||
profile: WebEngineProfile {
|
||||
httpUserAgent: "Mozilla/5.0 (HighFidelityInterface)"
|
||||
onUrlChanged: {
|
||||
var currentUrl = url.toString();
|
||||
var newUrl = urlFixer.fixupUrl(currentUrl);
|
||||
if (newUrl != currentUrl) {
|
||||
url = newUrl;
|
||||
}
|
||||
}
|
||||
profile: WebEngineProfile {
|
||||
id: webviewProfile
|
||||
httpUserAgent: "Mozilla/5.0 (HighFidelityInterface)"
|
||||
storageName: "qmlWebEngine"
|
||||
}
|
||||
}
|
||||
} // item
|
||||
} // dialog
|
||||
|
|
|
@ -89,6 +89,7 @@
|
|||
#include <RenderableWebEntityItem.h>
|
||||
#include <RenderDeferredTask.h>
|
||||
#include <ResourceCache.h>
|
||||
#include <RenderScriptingInterface.h>
|
||||
#include <SceneScriptingInterface.h>
|
||||
#include <RecordingScriptingInterface.h>
|
||||
#include <ScriptCache.h>
|
||||
|
@ -342,6 +343,7 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
#endif
|
||||
DependencyManager::set<DiscoverabilityManager>();
|
||||
DependencyManager::set<SceneScriptingInterface>();
|
||||
DependencyManager::set<RenderScriptingInterface>();
|
||||
DependencyManager::set<OffscreenUi>();
|
||||
DependencyManager::set<AutoUpdater>();
|
||||
DependencyManager::set<PathUtils>();
|
||||
|
@ -703,13 +705,37 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
} else if (action == controller::toInt(controller::Action::CONTEXT_MENU)) {
|
||||
VrMenu::toggle(); // show context menu even on non-stereo displays
|
||||
} else if (action == controller::toInt(controller::Action::RETICLE_X)) {
|
||||
auto globalPos = QCursor::pos();
|
||||
globalPos.setX(globalPos.x() + state);
|
||||
QCursor::setPos(globalPos);
|
||||
auto oldPos = QCursor::pos();
|
||||
auto newPos = oldPos;
|
||||
newPos.setX(oldPos.x() + state);
|
||||
QCursor::setPos(newPos);
|
||||
|
||||
|
||||
// NOTE: This is some debugging code we will leave in while debugging various reticle movement strategies,
|
||||
// remove it after we're done
|
||||
const float REASONABLE_CHANGE = 50.0f;
|
||||
glm::vec2 oldPosG = { oldPos.x(), oldPos.y() };
|
||||
glm::vec2 newPosG = { newPos.x(), newPos.y() };
|
||||
auto distance = glm::distance(oldPosG, newPosG);
|
||||
if (distance > REASONABLE_CHANGE) {
|
||||
qDebug() << "Action::RETICLE_X... UNREASONABLE CHANGE! distance:" << distance << " oldPos:" << oldPosG << " newPos:" << newPosG;
|
||||
}
|
||||
|
||||
} else if (action == controller::toInt(controller::Action::RETICLE_Y)) {
|
||||
auto globalPos = QCursor::pos();
|
||||
globalPos.setY(globalPos.y() + state);
|
||||
QCursor::setPos(globalPos);
|
||||
auto oldPos = QCursor::pos();
|
||||
auto newPos = oldPos;
|
||||
newPos.setY(oldPos.y() + state);
|
||||
QCursor::setPos(newPos);
|
||||
|
||||
// NOTE: This is some debugging code we will leave in while debugging various reticle movement strategies,
|
||||
// remove it after we're done
|
||||
const float REASONABLE_CHANGE = 50.0f;
|
||||
glm::vec2 oldPosG = { oldPos.x(), oldPos.y() };
|
||||
glm::vec2 newPosG = { newPos.x(), newPos.y() };
|
||||
auto distance = glm::distance(oldPosG, newPosG);
|
||||
if (distance > REASONABLE_CHANGE) {
|
||||
qDebug() << "Action::RETICLE_Y... UNREASONABLE CHANGE! distance:" << distance << " oldPos:" << oldPosG << " newPos:" << newPosG;
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -723,9 +749,9 @@ Application::Application(int& argc, char** argv, QElapsedTimer& startupTimer) :
|
|||
_applicationStateDevice->addInputVariant(QString("ComfortMode"), controller::StateController::ReadLambda([]() -> float {
|
||||
return (float)Menu::getInstance()->isOptionChecked(MenuOption::ComfortMode);
|
||||
}));
|
||||
_applicationStateDevice->addInputVariant(QString("Grounded"), controller::StateController::ReadLambda([]() -> float {
|
||||
return (float)qApp->getMyAvatar()->getCharacterController()->onGround();
|
||||
}));
|
||||
_applicationStateDevice->addInputVariant(QString("Grounded"), controller::StateController::ReadLambda([]() -> float {
|
||||
return (float)qApp->getMyAvatar()->getCharacterController()->onGround();
|
||||
}));
|
||||
|
||||
userInputMapper->registerDevice(_applicationStateDevice);
|
||||
|
||||
|
@ -1178,26 +1204,15 @@ void Application::paintGL() {
|
|||
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Mirror)) {
|
||||
PerformanceTimer perfTimer("Mirror");
|
||||
auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebufferDepthColor();
|
||||
auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebuffer();
|
||||
|
||||
renderArgs._renderMode = RenderArgs::MIRROR_RENDER_MODE;
|
||||
renderArgs._blitFramebuffer = DependencyManager::get<FramebufferCache>()->getSelfieFramebuffer();
|
||||
|
||||
renderRearViewMirror(&renderArgs, _mirrorViewRect);
|
||||
|
||||
renderArgs._blitFramebuffer.reset();
|
||||
renderArgs._renderMode = RenderArgs::DEFAULT_RENDER_MODE;
|
||||
|
||||
{
|
||||
float ratio = ((float)QApplication::desktop()->windowHandle()->devicePixelRatio() * getRenderResolutionScale());
|
||||
// Flip the src and destination rect horizontally to do the mirror
|
||||
auto mirrorRect = glm::ivec4(0, 0, _mirrorViewRect.width() * ratio, _mirrorViewRect.height() * ratio);
|
||||
auto mirrorRectDest = glm::ivec4(mirrorRect.z, mirrorRect.y, mirrorRect.x, mirrorRect.w);
|
||||
|
||||
auto selfieFbo = DependencyManager::get<FramebufferCache>()->getSelfieFramebuffer();
|
||||
gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) {
|
||||
batch.setFramebuffer(selfieFbo);
|
||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f));
|
||||
batch.blit(primaryFbo, mirrorRect, selfieFbo, mirrorRectDest);
|
||||
batch.setFramebuffer(nullptr);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
|
@ -1368,65 +1383,11 @@ void Application::paintGL() {
|
|||
renderArgs._context->setStereoProjections(eyeProjections);
|
||||
renderArgs._context->setStereoViews(eyeOffsets);
|
||||
}
|
||||
renderArgs._blitFramebuffer = finalFramebuffer;
|
||||
displaySide(&renderArgs, _myCamera);
|
||||
|
||||
renderArgs._blitFramebuffer.reset();
|
||||
renderArgs._context->enableStereo(false);
|
||||
|
||||
// Blit primary to final FBO
|
||||
auto primaryFbo = framebufferCache->getPrimaryFramebuffer();
|
||||
|
||||
if (renderArgs._renderMode == RenderArgs::MIRROR_RENDER_MODE) {
|
||||
if (displayPlugin->isStereo()) {
|
||||
gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) {
|
||||
gpu::Vec4i srcRectLeft;
|
||||
srcRectLeft.z = size.width() / 2;
|
||||
srcRectLeft.w = size.height();
|
||||
|
||||
gpu::Vec4i srcRectRight;
|
||||
srcRectRight.x = size.width() / 2;
|
||||
srcRectRight.z = size.width();
|
||||
srcRectRight.w = size.height();
|
||||
|
||||
gpu::Vec4i destRectLeft;
|
||||
destRectLeft.x = srcRectLeft.z;
|
||||
destRectLeft.z = srcRectLeft.x;
|
||||
destRectLeft.y = srcRectLeft.y;
|
||||
destRectLeft.w = srcRectLeft.w;
|
||||
|
||||
gpu::Vec4i destRectRight;
|
||||
destRectRight.x = srcRectRight.z;
|
||||
destRectRight.z = srcRectRight.x;
|
||||
destRectRight.y = srcRectRight.y;
|
||||
destRectRight.w = srcRectRight.w;
|
||||
|
||||
batch.setFramebuffer(finalFramebuffer);
|
||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, glm::vec4(0.0f, 0.0f, 1.0f, 0.0f));
|
||||
// BLit left to right and right to left in stereo
|
||||
batch.blit(primaryFbo, srcRectRight, finalFramebuffer, destRectLeft);
|
||||
batch.blit(primaryFbo, srcRectLeft, finalFramebuffer, destRectRight);
|
||||
});
|
||||
} else {
|
||||
gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) {
|
||||
gpu::Vec4i srcRect;
|
||||
srcRect.z = size.width();
|
||||
srcRect.w = size.height();
|
||||
gpu::Vec4i destRect;
|
||||
destRect.x = size.width();
|
||||
destRect.y = 0;
|
||||
destRect.z = 0;
|
||||
destRect.w = size.height();
|
||||
batch.setFramebuffer(finalFramebuffer);
|
||||
batch.blit(primaryFbo, srcRect, finalFramebuffer, destRect);
|
||||
});
|
||||
}
|
||||
} else {
|
||||
gpu::doInBatch(renderArgs._context, [=](gpu::Batch& batch) {
|
||||
gpu::Vec4i rect;
|
||||
rect.z = size.width();
|
||||
rect.w = size.height();
|
||||
batch.setFramebuffer(finalFramebuffer);
|
||||
batch.blit(primaryFbo, rect, finalFramebuffer, rect);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Overlay Composition, needs to occur after screen space effects have completed
|
||||
|
@ -1434,7 +1395,9 @@ void Application::paintGL() {
|
|||
{
|
||||
PROFILE_RANGE(__FUNCTION__ "/compositor");
|
||||
PerformanceTimer perfTimer("compositor");
|
||||
|
||||
auto primaryFbo = finalFramebuffer;
|
||||
|
||||
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, gpu::GLBackend::getFramebufferID(primaryFbo));
|
||||
if (displayPlugin->isStereo()) {
|
||||
QRect currentViewport(QPoint(0, 0), QSize(size.width() / 2, size.height()));
|
||||
|
@ -1459,7 +1422,9 @@ void Application::paintGL() {
|
|||
{
|
||||
PROFILE_RANGE(__FUNCTION__ "/pluginOutput");
|
||||
PerformanceTimer perfTimer("pluginOutput");
|
||||
|
||||
auto finalTexturePointer = finalFramebuffer->getRenderBuffer(0);
|
||||
|
||||
GLuint finalTexture = gpu::GLBackend::getTextureID(finalTexturePointer);
|
||||
Q_ASSERT(0 != finalTexture);
|
||||
|
||||
|
@ -2587,7 +2552,7 @@ void Application::init() {
|
|||
|
||||
_environment.init();
|
||||
|
||||
DependencyManager::get<DeferredLightingEffect>()->init(this);
|
||||
DependencyManager::get<DeferredLightingEffect>()->init();
|
||||
|
||||
DependencyManager::get<AvatarManager>()->init();
|
||||
_myCamera.setMode(CAMERA_MODE_FIRST_PERSON);
|
||||
|
@ -3420,7 +3385,7 @@ QImage Application::renderAvatarBillboard(RenderArgs* renderArgs) {
|
|||
renderArgs->_renderMode = RenderArgs::DEFAULT_RENDER_MODE;
|
||||
renderRearViewMirror(renderArgs, QRect(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE), true);
|
||||
|
||||
auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebufferDepthColor();
|
||||
auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebuffer();
|
||||
QImage image(BILLBOARD_SIZE, BILLBOARD_SIZE, QImage::Format_ARGB32);
|
||||
renderArgs->_context->downloadFramebuffer(primaryFbo, glm::ivec4(0, 0, BILLBOARD_SIZE, BILLBOARD_SIZE), image);
|
||||
|
||||
|
@ -3690,34 +3655,19 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
|||
// For now every frame pass the renderContext
|
||||
{
|
||||
PerformanceTimer perfTimer("EngineRun");
|
||||
render::RenderContext renderContext;
|
||||
|
||||
auto sceneInterface = DependencyManager::get<SceneScriptingInterface>();
|
||||
|
||||
renderContext._cullOpaque = sceneInterface->doEngineCullOpaque();
|
||||
renderContext._sortOpaque = sceneInterface->doEngineSortOpaque();
|
||||
renderContext._renderOpaque = sceneInterface->doEngineRenderOpaque();
|
||||
renderContext._cullTransparent = sceneInterface->doEngineCullTransparent();
|
||||
renderContext._sortTransparent = sceneInterface->doEngineSortTransparent();
|
||||
renderContext._renderTransparent = sceneInterface->doEngineRenderTransparent();
|
||||
|
||||
renderContext._maxDrawnOpaqueItems = sceneInterface->getEngineMaxDrawnOpaqueItems();
|
||||
renderContext._maxDrawnTransparentItems = sceneInterface->getEngineMaxDrawnTransparentItems();
|
||||
renderContext._maxDrawnOverlay3DItems = sceneInterface->getEngineMaxDrawnOverlay3DItems();
|
||||
|
||||
renderContext._drawItemStatus = sceneInterface->doEngineDisplayItemStatus();
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned)) {
|
||||
renderContext._drawItemStatus |= render::showNetworkStatusFlag;
|
||||
}
|
||||
renderContext._drawHitEffect = sceneInterface->doEngineDisplayHitEffect();
|
||||
|
||||
renderContext._occlusionStatus = Menu::getInstance()->isOptionChecked(MenuOption::DebugAmbientOcclusion);
|
||||
renderContext._fxaaStatus = Menu::getInstance()->isOptionChecked(MenuOption::Antialiasing);
|
||||
auto renderInterface = DependencyManager::get<RenderScriptingInterface>();
|
||||
auto renderContext = renderInterface->getRenderContext();
|
||||
|
||||
renderArgs->_shouldRender = LODManager::shouldRender;
|
||||
|
||||
renderContext.args = renderArgs;
|
||||
renderArgs->_viewFrustum = getDisplayViewFrustum();
|
||||
renderContext.setArgs(renderArgs);
|
||||
|
||||
bool occlusionStatus = Menu::getInstance()->isOptionChecked(MenuOption::DebugAmbientOcclusion);
|
||||
bool antialiasingStatus = Menu::getInstance()->isOptionChecked(MenuOption::Antialiasing);
|
||||
bool showOwnedStatus = Menu::getInstance()->isOptionChecked(MenuOption::PhysicsShowOwned);
|
||||
renderContext.setOptions(occlusionStatus, antialiasingStatus, showOwnedStatus);
|
||||
|
||||
_renderEngine->setRenderContext(renderContext);
|
||||
|
||||
// Before the deferred pass, let's try to use the render engine
|
||||
|
@ -3725,15 +3675,8 @@ void Application::displaySide(RenderArgs* renderArgs, Camera& theCamera, bool se
|
|||
_renderEngine->run();
|
||||
myAvatar->endRenderRun();
|
||||
|
||||
auto engineRC = _renderEngine->getRenderContext();
|
||||
sceneInterface->setEngineFeedOpaqueItems(engineRC->_numFeedOpaqueItems);
|
||||
sceneInterface->setEngineDrawnOpaqueItems(engineRC->_numDrawnOpaqueItems);
|
||||
|
||||
sceneInterface->setEngineFeedTransparentItems(engineRC->_numFeedTransparentItems);
|
||||
sceneInterface->setEngineDrawnTransparentItems(engineRC->_numDrawnTransparentItems);
|
||||
|
||||
sceneInterface->setEngineFeedOverlay3DItems(engineRC->_numFeedOverlay3DItems);
|
||||
sceneInterface->setEngineDrawnOverlay3DItems(engineRC->_numDrawnOverlay3DItems);
|
||||
auto engineContext = _renderEngine->getRenderContext();
|
||||
renderInterface->setItemCounts(engineContext->getItemsConfig());
|
||||
}
|
||||
|
||||
activeRenderingThread = nullptr;
|
||||
|
@ -4159,6 +4102,7 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
LocationScriptingInterface::locationSetter);
|
||||
|
||||
scriptEngine->registerFunction("WebWindow", WebWindowClass::constructor, 1);
|
||||
scriptEngine->registerFunction("OverlayWebWindow", QmlWebWindowClass::constructor);
|
||||
|
||||
scriptEngine->registerGlobalObject("Menu", MenuScriptingInterface::getInstance());
|
||||
scriptEngine->registerGlobalObject("Stats", Stats::getInstance());
|
||||
|
@ -4187,11 +4131,12 @@ void Application::registerScriptEngineWithApplicationServices(ScriptEngine* scri
|
|||
scriptEngine->registerFunction("HMD", "getHUDLookAtPosition3D", HMDScriptingInterface::getHUDLookAtPosition3D, 0);
|
||||
|
||||
scriptEngine->registerGlobalObject("Scene", DependencyManager::get<SceneScriptingInterface>().data());
|
||||
scriptEngine->registerGlobalObject("Render", DependencyManager::get<RenderScriptingInterface>().data());
|
||||
|
||||
scriptEngine->registerGlobalObject("ScriptDiscoveryService", this->getRunningScriptsWidget());
|
||||
}
|
||||
|
||||
bool Application::canAcceptURL(const QString& urlString) {
|
||||
bool Application::canAcceptURL(const QString& urlString) const {
|
||||
QUrl url(urlString);
|
||||
if (urlString.startsWith(HIFI_URL_SCHEME)) {
|
||||
return true;
|
||||
|
|
|
@ -38,6 +38,7 @@
|
|||
#include <SimpleMovingAverage.h>
|
||||
#include <StDev.h>
|
||||
#include <ViewFrustum.h>
|
||||
#include <AbstractUriHandler.h>
|
||||
|
||||
#include "avatar/AvatarUpdate.h"
|
||||
#include "avatar/MyAvatar.h"
|
||||
|
@ -88,7 +89,7 @@ class Application;
|
|||
#endif
|
||||
#define qApp (static_cast<Application*>(QCoreApplication::instance()))
|
||||
|
||||
class Application : public QApplication, public AbstractViewStateInterface, public AbstractScriptingServicesInterface {
|
||||
class Application : public QApplication, public AbstractViewStateInterface, public AbstractScriptingServicesInterface, public AbstractUriHandler {
|
||||
Q_OBJECT
|
||||
|
||||
// TODO? Get rid of those
|
||||
|
@ -219,8 +220,8 @@ public:
|
|||
QString getScriptsLocation();
|
||||
void setScriptsLocation(const QString& scriptsLocation);
|
||||
|
||||
bool canAcceptURL(const QString& url);
|
||||
bool acceptURL(const QString& url, bool defaultUpload = false);
|
||||
virtual bool canAcceptURL(const QString& url) const override;
|
||||
virtual bool acceptURL(const QString& url, bool defaultUpload = false) override;
|
||||
|
||||
void setMaxOctreePacketsPerSecond(int maxOctreePPS);
|
||||
int getMaxOctreePacketsPerSecond();
|
||||
|
|
|
@ -1085,6 +1085,26 @@ void Menu::setGroupingIsVisible(const QString& grouping, bool isVisible) {
|
|||
QMenuBar::repaint();
|
||||
}
|
||||
|
||||
void Menu::addActionGroup(const QString& groupName, const QStringList& actionList, const QString& selected) {
|
||||
auto menu = addMenu(groupName);
|
||||
|
||||
QActionGroup* actionGroup = new QActionGroup(menu);
|
||||
actionGroup->setExclusive(true);
|
||||
|
||||
auto menuScriptingInterface = MenuScriptingInterface::getInstance();
|
||||
for (auto action : actionList) {
|
||||
auto item = addCheckableActionToQMenuAndActionHash(menu, action, 0, action == selected,
|
||||
menuScriptingInterface,
|
||||
SLOT(menuItemTriggered()));
|
||||
actionGroup->addAction(item);
|
||||
}
|
||||
|
||||
QMenuBar::repaint();
|
||||
}
|
||||
|
||||
void Menu::removeActionGroup(const QString& groupName) {
|
||||
removeMenu(groupName);
|
||||
}
|
||||
|
||||
MenuWrapper::MenuWrapper(QMenu* menu) : _realMenu(menu) {
|
||||
VrMenu::executeOrQueue([=](VrMenu* vrMenu) {
|
||||
|
|
|
@ -105,6 +105,8 @@ public slots:
|
|||
void addMenuItem(const MenuItemProperties& properties);
|
||||
void removeMenuItem(const QString& menuName, const QString& menuitem);
|
||||
bool menuItemExists(const QString& menuName, const QString& menuitem);
|
||||
void addActionGroup(const QString& groupName, const QStringList& actionList, const QString& selected = QString());
|
||||
void removeActionGroup(const QString& groupName);
|
||||
bool isOptionChecked(const QString& menuOption) const;
|
||||
void setIsOptionChecked(const QString& menuOption, bool isChecked);
|
||||
|
||||
|
|
|
@ -84,6 +84,19 @@ bool MenuScriptingInterface::menuItemExists(const QString& menu, const QString&
|
|||
return result;
|
||||
}
|
||||
|
||||
void MenuScriptingInterface::addActionGroup(const QString& groupName, const QStringList& actionList,
|
||||
const QString& selected) {
|
||||
QMetaObject::invokeMethod(Menu::getInstance(), "addActionGroup",
|
||||
Q_ARG(const QString&, groupName),
|
||||
Q_ARG(const QStringList&, actionList),
|
||||
Q_ARG(const QString&, selected));
|
||||
}
|
||||
|
||||
void MenuScriptingInterface::removeActionGroup(const QString& groupName) {
|
||||
QMetaObject::invokeMethod(Menu::getInstance(), "removeActionGroup",
|
||||
Q_ARG(const QString&, groupName));
|
||||
}
|
||||
|
||||
bool MenuScriptingInterface::isOptionChecked(const QString& menuOption) {
|
||||
bool result;
|
||||
QMetaObject::invokeMethod(Menu::getInstance(), "isOptionChecked", Qt::BlockingQueuedConnection,
|
||||
|
|
|
@ -42,6 +42,10 @@ public slots:
|
|||
void removeMenuItem(const QString& menuName, const QString& menuitem);
|
||||
bool menuItemExists(const QString& menuName, const QString& menuitem);
|
||||
|
||||
void addActionGroup(const QString& groupName, const QStringList& actionList,
|
||||
const QString& selected = QString());
|
||||
void removeActionGroup(const QString& groupName);
|
||||
|
||||
bool isOptionChecked(const QString& menuOption);
|
||||
void setIsOptionChecked(const QString& menuOption, bool isChecked);
|
||||
|
||||
|
|
|
@ -289,7 +289,6 @@ uint64_t AudioInjector::injectNextFrame() {
|
|||
_currentSendOffset = 0;
|
||||
} else {
|
||||
// we weren't to loop, say that we're done now
|
||||
qDebug() << "AudioInjector::injectNextFrame has sent all data and was not asked to loop - calling finish().";
|
||||
finish();
|
||||
return NEXT_FRAME_DELTA_ERROR_OR_FINISHED;
|
||||
}
|
||||
|
|
|
@ -42,7 +42,22 @@ namespace controller {
|
|||
}
|
||||
|
||||
void Pose::fromScriptValue(const QScriptValue& object, Pose& pose) {
|
||||
// nothing for now...
|
||||
auto translation = object.property("translation");
|
||||
auto rotation = object.property("rotation");
|
||||
auto velocity = object.property("velocity");
|
||||
auto angularVelocity = object.property("angularVelocity");
|
||||
if (translation.isValid() &&
|
||||
rotation.isValid() &&
|
||||
velocity.isValid() &&
|
||||
angularVelocity.isValid()) {
|
||||
vec3FromScriptValue(translation, pose.translation);
|
||||
quatFromScriptValue(rotation, pose.rotation);
|
||||
vec3FromScriptValue(velocity, pose.velocity);
|
||||
vec3FromScriptValue(angularVelocity, pose.angularVelocity);
|
||||
pose.valid = true;
|
||||
} else {
|
||||
pose.valid = false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
#include <QCursor>
|
||||
#include <QThread>
|
||||
#include <QtCore/QObject>
|
||||
#include <QtCore/QVariant>
|
||||
|
@ -29,6 +30,7 @@
|
|||
#include <QtScript/QScriptValue>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <StreamUtils.h>
|
||||
|
||||
#include "UserInputMapper.h"
|
||||
#include "StandardControls.h"
|
||||
|
@ -87,6 +89,21 @@ namespace controller {
|
|||
Q_INVOKABLE QObject* parseMapping(const QString& json);
|
||||
Q_INVOKABLE QObject* loadMapping(const QString& jsonUrl);
|
||||
|
||||
Q_INVOKABLE glm::vec2 getReticlePosition() {
|
||||
return toGlm(QCursor::pos());
|
||||
}
|
||||
Q_INVOKABLE void setReticlePosition(glm::vec2 position) {
|
||||
// NOTE: This is some debugging code we will leave in while debugging various reticle movement strategies,
|
||||
// remove it after we're done
|
||||
const float REASONABLE_CHANGE = 50.0f;
|
||||
glm::vec2 oldPos = toGlm(QCursor::pos());
|
||||
auto distance = glm::distance(oldPos, position);
|
||||
if (distance > REASONABLE_CHANGE) {
|
||||
qDebug() << "Contrller::ScriptingInterface ---- UNREASONABLE CHANGE! distance:" << distance << " oldPos:" << oldPos << " newPos:" << position;
|
||||
}
|
||||
|
||||
QCursor::setPos(position.x, position.y);
|
||||
}
|
||||
|
||||
//Q_INVOKABLE bool isPrimaryButtonPressed() const;
|
||||
//Q_INVOKABLE glm::vec2 getPrimaryJoystickPosition() const;
|
||||
|
|
|
@ -10,6 +10,8 @@
|
|||
|
||||
#include <QtCore/QThread>
|
||||
|
||||
#include <StreamUtils.h>
|
||||
|
||||
using namespace controller;
|
||||
|
||||
float ScriptEndpoint::peek() const {
|
||||
|
@ -23,7 +25,16 @@ void ScriptEndpoint::updateValue() {
|
|||
return;
|
||||
}
|
||||
|
||||
_lastValueRead = (float)_callable.call().toNumber();
|
||||
QScriptValue result = _callable.call();
|
||||
|
||||
// If the callable ever returns a non-number, we assume it's a pose
|
||||
// and start reporting ourselves as a pose.
|
||||
if (result.isNumber()) {
|
||||
_lastValueRead = (float)_callable.call().toNumber();
|
||||
} else {
|
||||
Pose::fromScriptValue(result, _lastPoseRead);
|
||||
_returnPose = true;
|
||||
}
|
||||
}
|
||||
|
||||
void ScriptEndpoint::apply(float value, const Pointer& source) {
|
||||
|
@ -44,3 +55,36 @@ void ScriptEndpoint::internalApply(float value, int sourceID) {
|
|||
_callable.call(QScriptValue(),
|
||||
QScriptValueList({ QScriptValue(value), QScriptValue(sourceID) }));
|
||||
}
|
||||
|
||||
Pose ScriptEndpoint::peekPose() const {
|
||||
const_cast<ScriptEndpoint*>(this)->updatePose();
|
||||
return _lastPoseRead;
|
||||
}
|
||||
|
||||
void ScriptEndpoint::updatePose() {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "updatePose", Qt::QueuedConnection);
|
||||
return;
|
||||
}
|
||||
QScriptValue result = _callable.call();
|
||||
Pose::fromScriptValue(result, _lastPoseRead);
|
||||
}
|
||||
|
||||
void ScriptEndpoint::apply(const Pose& newPose, const Pointer& source) {
|
||||
if (newPose == _lastPoseWritten) {
|
||||
return;
|
||||
}
|
||||
internalApply(newPose, source->getInput().getID());
|
||||
}
|
||||
|
||||
void ScriptEndpoint::internalApply(const Pose& newPose, int sourceID) {
|
||||
_lastPoseWritten = newPose;
|
||||
if (QThread::currentThread() != thread()) {
|
||||
QMetaObject::invokeMethod(this, "internalApply", Qt::QueuedConnection,
|
||||
Q_ARG(const Pose&, newPose),
|
||||
Q_ARG(int, sourceID));
|
||||
return;
|
||||
}
|
||||
_callable.call(QScriptValue(),
|
||||
QScriptValueList({ Pose::toScriptValue(_callable.engine(), newPose), QScriptValue(sourceID) }));
|
||||
}
|
||||
|
|
|
@ -27,13 +27,26 @@ public:
|
|||
virtual float peek() const override;
|
||||
virtual void apply(float newValue, const Pointer& source) override;
|
||||
|
||||
|
||||
virtual Pose peekPose() const override;
|
||||
virtual void apply(const Pose& newValue, const Pointer& source) override;
|
||||
|
||||
virtual bool isPose() const override { return _returnPose; }
|
||||
|
||||
protected:
|
||||
Q_INVOKABLE void updateValue();
|
||||
Q_INVOKABLE virtual void internalApply(float newValue, int sourceID);
|
||||
|
||||
Q_INVOKABLE void updatePose();
|
||||
Q_INVOKABLE virtual void internalApply(const Pose& newValue, int sourceID);
|
||||
private:
|
||||
QScriptValue _callable;
|
||||
float _lastValueRead { 0.0f };
|
||||
float _lastValueWritten { 0.0f };
|
||||
|
||||
bool _returnPose { false };
|
||||
Pose _lastPoseRead;
|
||||
Pose _lastPoseWritten;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -256,33 +256,38 @@ void EntityTreeRenderer::forceRecheckEntities() {
|
|||
|
||||
void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityItem> zone) {
|
||||
QSharedPointer<SceneScriptingInterface> scene = DependencyManager::get<SceneScriptingInterface>();
|
||||
auto sceneStage = scene->getStage();
|
||||
auto sceneKeyLight = sceneStage->getKeyLight();
|
||||
auto sceneLocation = sceneStage->getLocation();
|
||||
auto sceneTime = sceneStage->getTime();
|
||||
|
||||
if (zone) {
|
||||
if (!_hasPreviousZone) {
|
||||
_previousKeyLightColor = scene->getKeyLightColor();
|
||||
_previousKeyLightIntensity = scene->getKeyLightIntensity();
|
||||
_previousKeyLightAmbientIntensity = scene->getKeyLightAmbientIntensity();
|
||||
_previousKeyLightDirection = scene->getKeyLightDirection();
|
||||
_previousStageSunModelEnabled = scene->isStageSunModelEnabled();
|
||||
_previousStageLongitude = scene->getStageLocationLongitude();
|
||||
_previousStageLatitude = scene->getStageLocationLatitude();
|
||||
_previousStageAltitude = scene->getStageLocationAltitude();
|
||||
_previousStageHour = scene->getStageDayTime();
|
||||
_previousStageDay = scene->getStageYearTime();
|
||||
_previousKeyLightColor = sceneKeyLight->getColor();
|
||||
_previousKeyLightIntensity = sceneKeyLight->getIntensity();
|
||||
_previousKeyLightAmbientIntensity = sceneKeyLight->getAmbientIntensity();
|
||||
_previousKeyLightDirection = sceneKeyLight->getDirection();
|
||||
_previousStageSunModelEnabled = sceneStage->isSunModelEnabled();
|
||||
_previousStageLongitude = sceneLocation->getLongitude();
|
||||
_previousStageLatitude = sceneLocation->getLatitude();
|
||||
_previousStageAltitude = sceneLocation->getAltitude();
|
||||
_previousStageHour = sceneTime->getHour();
|
||||
_previousStageDay = sceneTime->getDay();
|
||||
_hasPreviousZone = true;
|
||||
}
|
||||
scene->setKeyLightColor(ColorUtils::toVec3(zone->getKeyLightProperties().getColor()));
|
||||
scene->setKeyLightIntensity(zone->getKeyLightProperties().getIntensity());
|
||||
scene->setKeyLightAmbientIntensity(zone->getKeyLightProperties().getAmbientIntensity());
|
||||
scene->setKeyLightDirection(zone->getKeyLightProperties().getDirection());
|
||||
scene->setStageSunModelEnable(zone->getStageProperties().getSunModelEnabled());
|
||||
scene->setStageLocation(zone->getStageProperties().getLongitude(), zone->getStageProperties().getLatitude(),
|
||||
sceneKeyLight->setColor(ColorUtils::toVec3(zone->getKeyLightProperties().getColor()));
|
||||
sceneKeyLight->setIntensity(zone->getKeyLightProperties().getIntensity());
|
||||
sceneKeyLight->setAmbientIntensity(zone->getKeyLightProperties().getAmbientIntensity());
|
||||
sceneKeyLight->setDirection(zone->getKeyLightProperties().getDirection());
|
||||
sceneStage->setSunModelEnable(zone->getStageProperties().getSunModelEnabled());
|
||||
sceneStage->setLocation(zone->getStageProperties().getLongitude(), zone->getStageProperties().getLatitude(),
|
||||
zone->getStageProperties().getAltitude());
|
||||
scene->setStageDayTime(zone->getStageProperties().calculateHour());
|
||||
scene->setStageYearTime(zone->getStageProperties().calculateDay());
|
||||
sceneTime->setHour(zone->getStageProperties().calculateHour());
|
||||
sceneTime->setDay(zone->getStageProperties().calculateDay());
|
||||
|
||||
if (zone->getBackgroundMode() == BACKGROUND_MODE_ATMOSPHERE) {
|
||||
EnvironmentData data = zone->getEnvironmentData();
|
||||
glm::vec3 keyLightDirection = scene->getKeyLightDirection();
|
||||
glm::vec3 keyLightDirection = sceneKeyLight->getDirection();
|
||||
glm::vec3 inverseKeyLightDirection = keyLightDirection * -1.0f;
|
||||
|
||||
// NOTE: is this right? It seems like the "sun" should be based on the center of the
|
||||
|
@ -293,7 +298,7 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
data.setSunLocation(keyLightLocation);
|
||||
|
||||
const float KEY_LIGHT_INTENSITY_TO_SUN_BRIGHTNESS_RATIO = 20.0f;
|
||||
float sunBrightness = scene->getKeyLightIntensity() * KEY_LIGHT_INTENSITY_TO_SUN_BRIGHTNESS_RATIO;
|
||||
float sunBrightness = sceneKeyLight->getIntensity() * KEY_LIGHT_INTENSITY_TO_SUN_BRIGHTNESS_RATIO;
|
||||
data.setSunBrightness(sunBrightness);
|
||||
|
||||
_viewState->overrideEnvironmentData(data);
|
||||
|
@ -339,15 +344,15 @@ void EntityTreeRenderer::applyZonePropertiesToScene(std::shared_ptr<ZoneEntityIt
|
|||
} else {
|
||||
_pendingSkyboxTextureDownload = false;
|
||||
if (_hasPreviousZone) {
|
||||
scene->setKeyLightColor(_previousKeyLightColor);
|
||||
scene->setKeyLightIntensity(_previousKeyLightIntensity);
|
||||
scene->setKeyLightAmbientIntensity(_previousKeyLightAmbientIntensity);
|
||||
scene->setKeyLightDirection(_previousKeyLightDirection);
|
||||
scene->setStageSunModelEnable(_previousStageSunModelEnabled);
|
||||
scene->setStageLocation(_previousStageLongitude, _previousStageLatitude,
|
||||
sceneKeyLight->setColor(_previousKeyLightColor);
|
||||
sceneKeyLight->setIntensity(_previousKeyLightIntensity);
|
||||
sceneKeyLight->setAmbientIntensity(_previousKeyLightAmbientIntensity);
|
||||
sceneKeyLight->setDirection(_previousKeyLightDirection);
|
||||
sceneStage->setSunModelEnable(_previousStageSunModelEnabled);
|
||||
sceneStage->setLocation(_previousStageLongitude, _previousStageLatitude,
|
||||
_previousStageAltitude);
|
||||
scene->setStageDayTime(_previousStageHour);
|
||||
scene->setStageYearTime(_previousStageDay);
|
||||
sceneTime->setHour(_previousStageHour);
|
||||
sceneTime->setDay(_previousStageDay);
|
||||
_hasPreviousZone = false;
|
||||
}
|
||||
_viewState->endOverrideEnvironmentData();
|
||||
|
|
|
@ -385,7 +385,7 @@ Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) {
|
|||
_needsInitialSimulation = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -398,14 +398,14 @@ void RenderableModelEntityItem::update(const quint64& now) {
|
|||
EntityItemProperties properties;
|
||||
auto extents = _model->getMeshExtents();
|
||||
properties.setDimensions(extents.maximum - extents.minimum);
|
||||
|
||||
|
||||
qCDebug(entitiesrenderer) << "Autoresizing:" << (!getName().isEmpty() ? getName() : getModelURL());
|
||||
QMetaObject::invokeMethod(DependencyManager::get<EntityScriptingInterface>().data(), "editEntity",
|
||||
Qt::QueuedConnection,
|
||||
Q_ARG(QUuid, getEntityItemID()),
|
||||
Q_ARG(EntityItemProperties, properties));
|
||||
}
|
||||
|
||||
|
||||
ModelEntityItem::update(now);
|
||||
}
|
||||
|
||||
|
@ -427,7 +427,7 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori
|
|||
// << precisionPicking;
|
||||
|
||||
QString extraInfo;
|
||||
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance,
|
||||
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance,
|
||||
face, surfaceNormal, extraInfo, precisionPicking);
|
||||
}
|
||||
|
||||
|
@ -447,24 +447,22 @@ bool RenderableModelEntityItem::isReadyToComputeShape() {
|
|||
ShapeType type = getShapeType();
|
||||
|
||||
if (type == SHAPE_TYPE_COMPOUND) {
|
||||
if (!_model) {
|
||||
if (!_model || _model->getCollisionURL().isEmpty()) {
|
||||
EntityTreePointer tree = getTree();
|
||||
if (tree) {
|
||||
QMetaObject::invokeMethod(tree.get(), "callLoader", Qt::QueuedConnection, Q_ARG(EntityItemID, getID()));
|
||||
}
|
||||
return false; // hmm...
|
||||
return false;
|
||||
}
|
||||
|
||||
assert(!_model->getCollisionURL().isEmpty());
|
||||
|
||||
if (_model->getURL().isEmpty()) {
|
||||
// we need a render geometry with a scale to proceed, so give up.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry();
|
||||
const QSharedPointer<NetworkGeometry> renderNetworkGeometry = _model->getGeometry();
|
||||
|
||||
|
||||
if ((collisionNetworkGeometry && collisionNetworkGeometry->isLoaded()) &&
|
||||
(renderNetworkGeometry && renderNetworkGeometry->isLoaded())) {
|
||||
// we have both URLs AND both geometries AND they are both fully loaded.
|
||||
|
|
|
@ -223,10 +223,10 @@ void RenderableParticleEffectEntityItem::updateRenderItem() {
|
|||
particleUniforms.radius.middle = getParticleRadius();
|
||||
particleUniforms.radius.finish = getRadiusFinish();
|
||||
particleUniforms.radius.spread = getRadiusSpread();
|
||||
particleUniforms.color.start = toGlm(getColorStart(), getAlphaStart());
|
||||
particleUniforms.color.middle = toGlm(getXColor(), getAlpha());
|
||||
particleUniforms.color.finish = toGlm(getColorFinish(), getAlphaFinish());
|
||||
particleUniforms.color.spread = toGlm(getColorSpread(), getAlphaSpread());
|
||||
particleUniforms.color.start = glm::vec4(getColorStartRGB(), getAlphaStart());
|
||||
particleUniforms.color.middle = glm::vec4(getColorRGB(), getAlpha());
|
||||
particleUniforms.color.finish = glm::vec4(getColorFinishRGB(), getAlphaFinish());
|
||||
particleUniforms.color.spread = glm::vec4(getColorSpreadRGB(), getAlphaSpread());
|
||||
particleUniforms.lifespan = getLifespan();
|
||||
|
||||
// Build particle primitives
|
||||
|
@ -240,8 +240,11 @@ void RenderableParticleEffectEntityItem::updateRenderItem() {
|
|||
auto position = getPosition();
|
||||
auto rotation = getRotation();
|
||||
Transform transform;
|
||||
transform.setTranslation(position);
|
||||
transform.setRotation(rotation);
|
||||
if (!getEmitterShouldTrail()) {
|
||||
transform.setTranslation(position);
|
||||
transform.setRotation(rotation);
|
||||
}
|
||||
|
||||
|
||||
render::PendingChanges pendingChanges;
|
||||
pendingChanges.updateItem<ParticlePayloadData>(_renderItemId, [=](ParticlePayloadData& payload) {
|
||||
|
|
|
@ -23,6 +23,13 @@
|
|||
#include "paintStroke_frag.h"
|
||||
|
||||
|
||||
|
||||
struct PolyLineUniforms {
|
||||
glm::vec3 color;
|
||||
};
|
||||
|
||||
|
||||
|
||||
EntityItemPointer RenderablePolyLineEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
EntityItemPointer entity{ new RenderablePolyLineEntityItem(entityID) };
|
||||
entity->setProperties(properties);
|
||||
|
@ -30,9 +37,12 @@ EntityItemPointer RenderablePolyLineEntityItem::factory(const EntityItemID& enti
|
|||
}
|
||||
|
||||
RenderablePolyLineEntityItem::RenderablePolyLineEntityItem(const EntityItemID& entityItemID) :
|
||||
PolyLineEntityItem(entityItemID) {
|
||||
_numVertices = 0;
|
||||
PolyLineEntityItem(entityItemID),
|
||||
_numVertices(0)
|
||||
{
|
||||
_vertices = QVector<glm::vec3>(0.0f);
|
||||
PolyLineUniforms uniforms;
|
||||
_uniformBuffer = std::make_shared<gpu::Buffer>(sizeof(PolyLineUniforms), (const gpu::Byte*) &uniforms);
|
||||
}
|
||||
|
||||
gpu::PipelinePointer RenderablePolyLineEntityItem::_pipeline;
|
||||
|
@ -41,13 +51,11 @@ int32_t 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;
|
||||
static const int TEXTURE_OFFSET = 24;
|
||||
|
||||
_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::Shader::createVertex(std::string(paintStroke_vert));
|
||||
|
@ -72,47 +80,28 @@ void RenderablePolyLineEntityItem::updateGeometry() {
|
|||
_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 = _vertices.size() / 2 - numHeadStrips;
|
||||
uCoord = 0.0f;
|
||||
float uCoordInc = 1.0 / (_vertices.size() / 2);
|
||||
for (int i = 0; i < _vertices.size() / 2; 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;
|
||||
uCoord += uCoordInc;
|
||||
}
|
||||
_pointsChanged = false;
|
||||
_normalsChanged = false;
|
||||
|
@ -161,6 +150,16 @@ void RenderablePolyLineEntityItem::updateVertices() {
|
|||
|
||||
}
|
||||
|
||||
void RenderablePolyLineEntityItem::update(const quint64& now) {
|
||||
PolyLineUniforms uniforms;
|
||||
uniforms.color = toGlm(getXColor());
|
||||
memcpy(&_uniformBuffer.edit<PolyLineUniforms>(), &uniforms, sizeof(PolyLineUniforms));
|
||||
if (_pointsChanged || _strokeWidthsChanged || _normalsChanged) {
|
||||
updateVertices();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void RenderablePolyLineEntityItem::render(RenderArgs* args) {
|
||||
QWriteLocker lock(&_quadReadWriteLock);
|
||||
|
@ -181,17 +180,13 @@ void RenderablePolyLineEntityItem::render(RenderArgs* args) {
|
|||
|
||||
PerformanceTimer perfTimer("RenderablePolyLineEntityItem::render");
|
||||
Q_ASSERT(getType() == EntityTypes::PolyLine);
|
||||
|
||||
Q_ASSERT(args->_batch);
|
||||
if (_pointsChanged || _strokeWidthsChanged || _normalsChanged) {
|
||||
updateVertices();
|
||||
updateGeometry();
|
||||
}
|
||||
|
||||
gpu::Batch& batch = *args->_batch;
|
||||
Transform transform = Transform();
|
||||
transform.setTranslation(getPosition());
|
||||
transform.setRotation(getRotation());
|
||||
batch.setUniformBuffer(0, _uniformBuffer);
|
||||
batch.setModelTransform(transform);
|
||||
|
||||
batch.setPipeline(_pipeline);
|
||||
|
@ -200,7 +195,7 @@ void RenderablePolyLineEntityItem::render(RenderArgs* args) {
|
|||
} else {
|
||||
batch.setResourceTexture(PAINTSTROKE_GPU_SLOT, args->_whiteTexture);
|
||||
}
|
||||
|
||||
|
||||
batch.setInputFormat(_format);
|
||||
batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride);
|
||||
|
||||
|
|
|
@ -29,6 +29,8 @@ public:
|
|||
RenderablePolyLineEntityItem(const EntityItemID& entityItemID);
|
||||
|
||||
virtual void render(RenderArgs* args);
|
||||
virtual void update(const quint64& now) override;
|
||||
virtual bool needsToCallUpdate() const { return true; };
|
||||
|
||||
SIMPLE_RENDERABLE();
|
||||
|
||||
|
@ -42,6 +44,7 @@ protected:
|
|||
void updateGeometry();
|
||||
void updateVertices();
|
||||
gpu::BufferPointer _verticesBuffer;
|
||||
gpu::BufferView _uniformBuffer;
|
||||
unsigned int _numVertices;
|
||||
QVector<glm::vec3> _vertices;
|
||||
|
||||
|
|
|
@ -23,8 +23,6 @@ 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;
|
||||
|
@ -318,8 +316,8 @@ const QString SHADER_TEMPLATE_V1 = SHADER_COMMON + R"SCRIBE(
|
|||
void main(void) {
|
||||
vec4 emissive = getProceduralColor();
|
||||
|
||||
float alpha = glowIntensity * emissive.a;
|
||||
if (alpha != glowIntensity) {
|
||||
float alpha = emissive.a;
|
||||
if (alpha != 1.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
|
|
|
@ -23,23 +23,24 @@ 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);
|
||||
}
|
||||
|
||||
struct PolyLineUniforms {
|
||||
vec3 color;
|
||||
};
|
||||
|
||||
uniform polyLineBuffer {
|
||||
PolyLineUniforms polyline;
|
||||
};
|
||||
|
||||
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
|
||||
vec3 color = varColor.rgb;
|
||||
packDeferredFragmentTranslucent(
|
||||
interpolatedNormal * frontCondition,
|
||||
texel.a,
|
||||
color *texel.rgb,
|
||||
polyline.color * texel.rgb,
|
||||
vec3(0.01, 0.01, 0.01),
|
||||
10.0);
|
||||
}
|
||||
|
|
|
@ -13,8 +13,8 @@
|
|||
//
|
||||
|
||||
<@include gpu/Inputs.slh@>
|
||||
<@include gpu/Color.slh@>
|
||||
<@include gpu/Transform.slh@>
|
||||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
// the interpolated normal
|
||||
|
@ -30,7 +30,8 @@ void main(void) {
|
|||
varTexcoord = inTexCoord0.st;
|
||||
|
||||
// pass along the diffuse color
|
||||
varColor = inColor;
|
||||
varColor = colorToLinearRGBA(inColor);
|
||||
|
||||
|
||||
// standard transform
|
||||
TransformCamera cam = getTransformCamera();
|
||||
|
|
|
@ -9,16 +9,15 @@
|
|||
//
|
||||
|
||||
<@include gpu/Inputs.slh@>
|
||||
|
||||
<@include gpu/Color.slh@>
|
||||
<@include gpu/Transform.slh@>
|
||||
|
||||
<$declareStandardTransform()$>
|
||||
|
||||
out vec4 _color;
|
||||
|
||||
void main(void) {
|
||||
// pass along the diffuse color
|
||||
_color = inColor;
|
||||
_color = colorToLinearRGBA(inColor);
|
||||
|
||||
TransformCamera cam = getTransformCamera();
|
||||
TransformObject obj = getTransformObject();
|
||||
|
|
|
@ -195,7 +195,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_ALPHA_SPREAD, alphaSpread);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ALPHA_START, alphaStart);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ALPHA_FINISH, alphaFinish);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ADDITIVE_BLENDING, additiveBlending);
|
||||
CHECK_PROPERTY_CHANGE(PROP_EMITTER_SHOULD_TRAIL, emitterShouldTrail);
|
||||
CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_VISIBLE, visible);
|
||||
|
@ -354,7 +354,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_SPREAD, alphaSpread);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_START, alphaStart);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ALPHA_FINISH, alphaFinish);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_ADDITIVE_BLENDING, additiveBlending);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_EMITTER_SHOULD_TRAIL, emitterShouldTrail);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_POSITION, localPosition);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(PROP_LOCAL_ROTATION, localRotation);
|
||||
}
|
||||
|
@ -515,7 +515,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object, bool
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaSpread, float, setAlphaSpread);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaStart, float, setAlphaStart);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(alphaFinish, float, setAlphaFinish);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(additiveBlending, bool, setAdditiveBlending);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(emitterShouldTrail , bool, setEmitterShouldTrail);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(modelURL, QString, setModelURL);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(compoundShapeURL, QString, setCompoundShapeURL);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE(glowLevel, float, setGlowLevel);
|
||||
|
@ -670,7 +670,7 @@ void EntityItemProperties::entityPropertyFlagsFromScriptValue(const QScriptValue
|
|||
ADD_PROPERTY_TO_MAP(PROP_ALPHA_SPREAD, AlphaSpread, alphaSpread, float);
|
||||
ADD_PROPERTY_TO_MAP(PROP_ALPHA_START, AlphaStart, alphaStart, float);
|
||||
ADD_PROPERTY_TO_MAP(PROP_ALPHA_FINISH, AlphaFinish, alphaFinish, float);
|
||||
ADD_PROPERTY_TO_MAP(PROP_ADDITIVE_BLENDING, AdditiveBlending, additiveBlending, bool);
|
||||
ADD_PROPERTY_TO_MAP(PROP_EMITTER_SHOULD_TRAIL, EmitterShouldTrail, emitterShouldTrail, bool);
|
||||
ADD_PROPERTY_TO_MAP(PROP_MODEL_URL, ModelURL, modelURL, QString);
|
||||
ADD_PROPERTY_TO_MAP(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString);
|
||||
ADD_PROPERTY_TO_MAP(PROP_REGISTRATION_POINT, RegistrationPoint, registrationPoint, glm::vec3);
|
||||
|
@ -980,7 +980,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
|
|||
APPEND_ENTITY_PROPERTY(PROP_ALPHA_SPREAD, properties.getAlphaSpread());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ALPHA_START, properties.getAlphaStart());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ALPHA_FINISH, properties.getAlphaFinish());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ADDITIVE_BLENDING, properties.getAdditiveBlending());
|
||||
APPEND_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, properties.getEmitterShouldTrail());
|
||||
}
|
||||
|
||||
if (properties.getType() == EntityTypes::Zone) {
|
||||
|
@ -1265,7 +1265,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_SPREAD, float, setAlphaSpread);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_START, float, setAlphaStart);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ALPHA_FINISH, float, setAlphaFinish);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ADDITIVE_BLENDING, bool, setAdditiveBlending);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail);
|
||||
}
|
||||
|
||||
if (properties.getType() == EntityTypes::Zone) {
|
||||
|
@ -1608,8 +1608,8 @@ QList<QString> EntityItemProperties::listChangedProperties() {
|
|||
if (alphaFinishChanged()) {
|
||||
out += "alphaFinish";
|
||||
}
|
||||
if (additiveBlendingChanged()) {
|
||||
out += "additiveBlending";
|
||||
if (emitterShouldTrailChanged()) {
|
||||
out += "emitterShouldTrail";
|
||||
}
|
||||
if (modelURLChanged()) {
|
||||
out += "modelURL";
|
||||
|
|
|
@ -161,7 +161,7 @@ public:
|
|||
DEFINE_PROPERTY(PROP_RADIUS_SPREAD, RadiusSpread, radiusSpread, float, ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD);
|
||||
DEFINE_PROPERTY(PROP_RADIUS_START, RadiusStart, radiusStart, float, ParticleEffectEntityItem::DEFAULT_RADIUS_START);
|
||||
DEFINE_PROPERTY(PROP_RADIUS_FINISH, RadiusFinish, radiusFinish, float, ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH);
|
||||
DEFINE_PROPERTY(PROP_ADDITIVE_BLENDING, AdditiveBlending, additiveBlending, bool, ParticleEffectEntityItem::DEFAULT_ADDITIVE_BLENDING);
|
||||
DEFINE_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, EmitterShouldTrail, emitterShouldTrail, bool, ParticleEffectEntityItem::DEFAULT_EMITTER_SHOULD_TRAIL);
|
||||
DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID);
|
||||
DEFINE_PROPERTY_GROUP(KeyLight, keyLight, KeyLightPropertyGroup);
|
||||
DEFINE_PROPERTY_REF(PROP_VOXEL_VOLUME_SIZE, VoxelVolumeSize, voxelVolumeSize, glm::vec3, PolyVoxEntityItem::DEFAULT_VOXEL_VOLUME_SIZE);
|
||||
|
|
|
@ -149,7 +149,7 @@ enum EntityPropertyList {
|
|||
PROP_ANIMATION_HOLD,
|
||||
PROP_ANIMATION_START_AUTOMATICALLY,
|
||||
|
||||
PROP_ADDITIVE_BLENDING,
|
||||
PROP_EMITTER_SHOULD_TRAIL,
|
||||
|
||||
PROP_PARENT_ID,
|
||||
PROP_PARENT_JOINT_INDEX,
|
||||
|
|
|
@ -52,13 +52,13 @@ const float ParticleEffectEntityItem::MINIMUM_ALPHA = 0.0f;
|
|||
const float ParticleEffectEntityItem::MAXIMUM_ALPHA = 1.0f;
|
||||
const quint32 ParticleEffectEntityItem::DEFAULT_MAX_PARTICLES = 1000;
|
||||
const quint32 ParticleEffectEntityItem::MINIMUM_MAX_PARTICLES = 1;
|
||||
const quint32 ParticleEffectEntityItem::MAXIMUM_MAX_PARTICLES = 10000;
|
||||
const quint32 ParticleEffectEntityItem::MAXIMUM_MAX_PARTICLES = 100000;
|
||||
const float ParticleEffectEntityItem::DEFAULT_LIFESPAN = 3.0f;
|
||||
const float ParticleEffectEntityItem::MINIMUM_LIFESPAN = 0.0f;
|
||||
const float ParticleEffectEntityItem::MAXIMUM_LIFESPAN = 86400.0f; // 1 day
|
||||
const float ParticleEffectEntityItem::DEFAULT_EMIT_RATE = 15.0f;
|
||||
const float ParticleEffectEntityItem::MINIMUM_EMIT_RATE = 0.0f;
|
||||
const float ParticleEffectEntityItem::MAXIMUM_EMIT_RATE = 1000.0f;
|
||||
const float ParticleEffectEntityItem::MAXIMUM_EMIT_RATE = 100000.0f;
|
||||
const float ParticleEffectEntityItem::DEFAULT_EMIT_SPEED = 5.0f;
|
||||
const float ParticleEffectEntityItem::MINIMUM_EMIT_SPEED = 0.0f;
|
||||
const float ParticleEffectEntityItem::MAXIMUM_EMIT_SPEED = 1000.0f; // Approx mach 3
|
||||
|
@ -91,7 +91,7 @@ const float ParticleEffectEntityItem::DEFAULT_RADIUS_SPREAD = 0.0f;
|
|||
const float ParticleEffectEntityItem::DEFAULT_RADIUS_START = DEFAULT_PARTICLE_RADIUS;
|
||||
const float ParticleEffectEntityItem::DEFAULT_RADIUS_FINISH = DEFAULT_PARTICLE_RADIUS;
|
||||
const QString ParticleEffectEntityItem::DEFAULT_TEXTURES = "";
|
||||
const bool ParticleEffectEntityItem::DEFAULT_ADDITIVE_BLENDING = false;
|
||||
const bool ParticleEffectEntityItem::DEFAULT_EMITTER_SHOULD_TRAIL = false;
|
||||
|
||||
|
||||
EntityItemPointer ParticleEffectEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
|
@ -331,7 +331,7 @@ EntityItemProperties ParticleEffectEntityItem::getProperties(EntityPropertyFlags
|
|||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaStart, getAlphaStart);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(alphaFinish, getAlphaFinish);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(textures, getTextures);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(additiveBlending, getAdditiveBlending);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(emitterShouldTrail, getEmitterShouldTrail);
|
||||
|
||||
|
||||
return properties;
|
||||
|
@ -370,7 +370,7 @@ bool ParticleEffectEntityItem::setProperties(const EntityItemProperties& propert
|
|||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaStart, setAlphaStart);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(alphaFinish, setAlphaFinish);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(textures, setTextures);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(additiveBlending, setAdditiveBlending);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(emitterShouldTrail, setEmitterShouldTrail);
|
||||
|
||||
if (somethingChanged) {
|
||||
bool wantDebug = false;
|
||||
|
@ -463,7 +463,7 @@ int ParticleEffectEntityItem::readEntitySubclassDataFromBuffer(const unsigned ch
|
|||
}
|
||||
|
||||
if (args.bitstreamVersion >= VERSION_ENTITIES_PARTICLES_ADDITIVE_BLENDING) {
|
||||
READ_ENTITY_PROPERTY(PROP_ADDITIVE_BLENDING, bool, setAdditiveBlending);
|
||||
READ_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, bool, setEmitterShouldTrail);
|
||||
}
|
||||
|
||||
return bytesRead;
|
||||
|
@ -503,7 +503,7 @@ EntityPropertyFlags ParticleEffectEntityItem::getEntityProperties(EncodeBitstrea
|
|||
requestedProperties += PROP_POLAR_FINISH;
|
||||
requestedProperties += PROP_AZIMUTH_START;
|
||||
requestedProperties += PROP_AZIMUTH_FINISH;
|
||||
requestedProperties += PROP_ADDITIVE_BLENDING;
|
||||
requestedProperties += PROP_EMITTER_SHOULD_TRAIL;
|
||||
|
||||
return requestedProperties;
|
||||
}
|
||||
|
@ -546,7 +546,7 @@ void ParticleEffectEntityItem::appendSubclassData(OctreePacketData* packetData,
|
|||
APPEND_ENTITY_PROPERTY(PROP_POLAR_FINISH, getPolarFinish());
|
||||
APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_START, getAzimuthStart());
|
||||
APPEND_ENTITY_PROPERTY(PROP_AZIMUTH_FINISH, getAzimuthFinish());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ADDITIVE_BLENDING, getAdditiveBlending());
|
||||
APPEND_ENTITY_PROPERTY(PROP_EMITTER_SHOULD_TRAIL, getEmitterShouldTrail());
|
||||
}
|
||||
|
||||
bool ParticleEffectEntityItem::isEmittingParticles() const {
|
||||
|
@ -641,13 +641,17 @@ void ParticleEffectEntityItem::stepSimulation(float deltaTime) {
|
|||
|
||||
ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() {
|
||||
Particle particle;
|
||||
|
||||
particle.seed = randFloatInRange(0.0f, 1.0f);
|
||||
|
||||
|
||||
|
||||
particle.seed = randFloatInRange(-1.0f, 1.0f);
|
||||
if (getEmitterShouldTrail()) {
|
||||
particle.position = getPosition();
|
||||
}
|
||||
// Position, velocity, and acceleration
|
||||
if (_polarStart == 0.0f && _polarFinish == 0.0f && _emitDimensions.z == 0.0f) {
|
||||
// Emit along z-axis from position
|
||||
particle.velocity = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * Vectors::UNIT_Z);
|
||||
|
||||
particle.velocity = (_emitSpeed + 0.2f * _speedSpread) * (_emitOrientation * Vectors::UNIT_Z);
|
||||
particle.acceleration = _emitAcceleration + randFloatInRange(-1.0f, 1.0f) * _accelerationSpread;
|
||||
|
||||
} else {
|
||||
|
@ -658,11 +662,12 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() {
|
|||
|
||||
float elevationMinZ = sin(PI_OVER_TWO - _polarFinish);
|
||||
float elevationMaxZ = sin(PI_OVER_TWO - _polarStart);
|
||||
float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) * randFloat());
|
||||
// float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) * randFloat());
|
||||
float elevation = asin(elevationMinZ + (elevationMaxZ - elevationMinZ) *randFloat());
|
||||
|
||||
float azimuth;
|
||||
if (_azimuthFinish >= _azimuthStart) {
|
||||
azimuth = _azimuthStart + (_azimuthFinish - _azimuthStart) * randFloat();
|
||||
azimuth = _azimuthStart + (_azimuthFinish - _azimuthStart) * randFloat();
|
||||
} else {
|
||||
azimuth = _azimuthStart + (TWO_PI + _azimuthFinish - _azimuthStart) * randFloat();
|
||||
}
|
||||
|
@ -693,7 +698,12 @@ ParticleEffectEntityItem::Particle ParticleEffectEntityItem::createParticle() {
|
|||
radii.z > 0.0f ? z / (radii.z * radii.z) : 0.0f
|
||||
));
|
||||
|
||||
particle.position = _emitOrientation * emitPosition;
|
||||
if (getEmitterShouldTrail()) {
|
||||
particle.position += _emitOrientation * emitPosition;
|
||||
}
|
||||
else {
|
||||
particle.position = _emitOrientation * emitPosition;
|
||||
}
|
||||
}
|
||||
|
||||
particle.velocity = (_emitSpeed + randFloatInRange(-1.0f, 1.0f) * _speedSpread) * (_emitOrientation * emitDirection);
|
||||
|
|
|
@ -15,6 +15,8 @@
|
|||
|
||||
#include "EntityItem.h"
|
||||
|
||||
#include "ColorUtils.h"
|
||||
|
||||
class ParticleEffectEntityItem : public EntityItem {
|
||||
public:
|
||||
ALLOW_INSTANTIATION // This class can be instantiated
|
||||
|
@ -47,6 +49,7 @@ public:
|
|||
|
||||
const rgbColor& getColor() const { return _color; }
|
||||
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
|
||||
glm::vec3 getColorRGB() const { return ColorUtils::toLinearVec3(toGlm(getXColor())); }
|
||||
|
||||
static const xColor DEFAULT_COLOR;
|
||||
void setColor(const rgbColor& value) { memcpy(_color, value, sizeof(_color)); }
|
||||
|
@ -59,14 +62,17 @@ public:
|
|||
bool _isColorStartInitialized = false;
|
||||
void setColorStart(const xColor& colorStart) { _colorStart = colorStart; _isColorStartInitialized = true; }
|
||||
xColor getColorStart() const { return _isColorStartInitialized ? _colorStart : getXColor(); }
|
||||
glm::vec3 getColorStartRGB() const { return _isColorStartInitialized ? ColorUtils::toLinearVec3(toGlm(_colorStart)) : getColorRGB(); }
|
||||
|
||||
bool _isColorFinishInitialized = false;
|
||||
void setColorFinish(const xColor& colorFinish) { _colorFinish = colorFinish; _isColorFinishInitialized = true; }
|
||||
xColor getColorFinish() const { return _isColorFinishInitialized ? _colorFinish : getXColor(); }
|
||||
glm::vec3 getColorFinishRGB() const { return _isColorStartInitialized ? ColorUtils::toLinearVec3(toGlm(_colorFinish)) : getColorRGB(); }
|
||||
|
||||
static const xColor DEFAULT_COLOR_SPREAD;
|
||||
void setColorSpread(const xColor& colorSpread) { _colorSpread = colorSpread; }
|
||||
xColor getColorSpread() const { return _colorSpread; }
|
||||
glm::vec3 getColorSpreadRGB() const { return ColorUtils::toLinearVec3(toGlm(_colorSpread)); }
|
||||
|
||||
static const float MAXIMUM_ALPHA;
|
||||
static const float MINIMUM_ALPHA;
|
||||
|
@ -207,10 +213,10 @@ public:
|
|||
}
|
||||
}
|
||||
|
||||
static const bool DEFAULT_ADDITIVE_BLENDING;
|
||||
bool getAdditiveBlending() const { return _additiveBlending; }
|
||||
void setAdditiveBlending(bool additiveBlending) {
|
||||
_additiveBlending = additiveBlending;
|
||||
static const bool DEFAULT_EMITTER_SHOULD_TRAIL;
|
||||
bool getEmitterShouldTrail() const { return _emitterShouldTrail; }
|
||||
void setEmitterShouldTrail(bool emitterShouldTrail) {
|
||||
_emitterShouldTrail = emitterShouldTrail;
|
||||
}
|
||||
|
||||
virtual bool supportsDetailedRayIntersection() const { return false; }
|
||||
|
@ -280,7 +286,7 @@ protected:
|
|||
float _timeUntilNextEmit { 0.0f };
|
||||
|
||||
|
||||
bool _additiveBlending { DEFAULT_ADDITIVE_BLENDING };
|
||||
bool _emitterShouldTrail { DEFAULT_EMITTER_SHOULD_TRAIL };
|
||||
};
|
||||
|
||||
#endif // hifi_ParticleEffectEntityItem_h
|
||||
|
|
|
@ -89,6 +89,7 @@ bool PolyLineEntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
return somethingChanged;
|
||||
}
|
||||
|
||||
|
||||
bool PolyLineEntityItem::appendPoint(const glm::vec3& point) {
|
||||
if (_points.size() > MAX_POINTS_PER_LINE - 1) {
|
||||
qDebug() << "MAX POINTS REACHED!";
|
||||
|
@ -104,6 +105,7 @@ bool PolyLineEntityItem::appendPoint(const glm::vec3& point) {
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool PolyLineEntityItem::setStrokeWidths(const QVector<float>& strokeWidths) {
|
||||
_strokeWidths = strokeWidths;
|
||||
_strokeWidthsChanged = true;
|
||||
|
|
|
@ -49,7 +49,7 @@ class PolyLineEntityItem : public EntityItem {
|
|||
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;
|
||||
|
@ -75,7 +75,9 @@ class PolyLineEntityItem : public EntityItem {
|
|||
_texturesChangedFlag = true;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
virtual bool needsToCallUpdate() const { return true; }
|
||||
|
||||
virtual ShapeType getShapeType() const { return SHAPE_TYPE_LINE; }
|
||||
|
||||
// never have a ray intersection pick a PolyLineEntityItem.
|
||||
|
|
|
@ -311,6 +311,12 @@ void Batch::blit(const FramebufferPointer& src, const Vec4i& srcViewport,
|
|||
_params.push_back(dstViewport.w);
|
||||
}
|
||||
|
||||
void Batch::generateTextureMips(const TexturePointer& texture) {
|
||||
ADD_COMMAND(generateTextureMips);
|
||||
|
||||
_params.push_back(_textures.cache(texture));
|
||||
}
|
||||
|
||||
void Batch::beginQuery(const QueryPointer& query) {
|
||||
ADD_COMMAND(beginQuery);
|
||||
|
||||
|
|
|
@ -211,6 +211,9 @@ public:
|
|||
// with xy and zw the bounding corners of the rect region.
|
||||
void blit(const FramebufferPointer& src, const Vec4i& srcRect, const FramebufferPointer& dst, const Vec4i& dstRect);
|
||||
|
||||
// Generate the mips for a texture
|
||||
void generateTextureMips(const TexturePointer& texture);
|
||||
|
||||
// Query Section
|
||||
void beginQuery(const QueryPointer& query);
|
||||
void endQuery(const QueryPointer& query);
|
||||
|
@ -292,6 +295,7 @@ public:
|
|||
COMMAND_setFramebuffer,
|
||||
COMMAND_clearFramebuffer,
|
||||
COMMAND_blit,
|
||||
COMMAND_generateTextureMips,
|
||||
|
||||
COMMAND_beginQuery,
|
||||
COMMAND_endQuery,
|
||||
|
|
52
libraries/gpu/src/gpu/Color.slh
Normal file
52
libraries/gpu/src/gpu/Color.slh
Normal file
|
@ -0,0 +1,52 @@
|
|||
<!
|
||||
// Color.slh
|
||||
// libraries/gpu/src
|
||||
//
|
||||
// Created by Sam Gateau on 2015/12/18.
|
||||
// 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
|
||||
!>
|
||||
<@if not GPU_COLOR_SLH@>
|
||||
<@def GPU_COLOR_SLH@>
|
||||
<!
|
||||
float colorComponentToLinear(float cs) {
|
||||
// sRGB to linear conversion
|
||||
// { cs / 12.92, cs <= 0.04045
|
||||
// cl = {
|
||||
// { ((cs + 0.055)/1.055)^2.4, cs > 0.04045
|
||||
// constants:
|
||||
// T = 0.04045
|
||||
// A = 1 / 1.055 = 0.94786729857
|
||||
// B = 0.055 * A = 0.05213270142
|
||||
// C = 1 / 12.92 = 0.0773993808
|
||||
// G = 2.4
|
||||
const float T = 0.04045;
|
||||
const float A = 0.947867;
|
||||
const float B = 0.052132;
|
||||
const float C = 0.077399;
|
||||
const float G = 2.4;
|
||||
|
||||
if (cs > T) {
|
||||
return pow((cs * A + B), G);
|
||||
} else {
|
||||
return cs * C;
|
||||
}
|
||||
}
|
||||
|
||||
vec3 colorToLinear(vec3 srgb) {
|
||||
return vec3(colorComponentToLinear(srgb.x), colorComponentToLinear(srgb.y), colorComponentToLinear(srgb.z));
|
||||
}
|
||||
!>
|
||||
|
||||
vec3 colorToLinearRGB(vec3 srgb) {
|
||||
const float GAMMA_22 = 2.2;
|
||||
return pow(srgb, vec3(GAMMA_22));
|
||||
}
|
||||
|
||||
vec4 colorToLinearRGBA(vec4 srgba) {
|
||||
return vec4(colorToLinearRGB(srgba.xyz), srgba.w);
|
||||
}
|
||||
|
||||
<@endif@>
|
|
@ -160,6 +160,7 @@ enum Semantic {
|
|||
RGB,
|
||||
RGBA,
|
||||
BGRA,
|
||||
|
||||
XY,
|
||||
XYZ,
|
||||
XYZW,
|
||||
|
@ -176,6 +177,8 @@ enum Semantic {
|
|||
SRGBA,
|
||||
SBGRA,
|
||||
|
||||
R11G11B10,
|
||||
|
||||
UNIFORM,
|
||||
UNIFORM_BUFFER,
|
||||
SAMPLER,
|
||||
|
|
|
@ -52,6 +52,7 @@ GLBackend::CommandCall GLBackend::_commandCalls[Batch::NUM_COMMANDS] =
|
|||
(&::gpu::GLBackend::do_setFramebuffer),
|
||||
(&::gpu::GLBackend::do_clearFramebuffer),
|
||||
(&::gpu::GLBackend::do_blit),
|
||||
(&::gpu::GLBackend::do_generateTextureMips),
|
||||
|
||||
(&::gpu::GLBackend::do_beginQuery),
|
||||
(&::gpu::GLBackend::do_endQuery),
|
||||
|
|
|
@ -376,12 +376,16 @@ protected:
|
|||
|
||||
// Resource Stage
|
||||
void do_setResourceTexture(Batch& batch, size_t paramOffset);
|
||||
|
||||
|
||||
// update resource cache and do the gl unbind call with the current gpu::Texture cached at slot s
|
||||
void releaseResourceTexture(uint32_t slot);
|
||||
|
||||
void resetResourceStage();
|
||||
struct ResourceStageState {
|
||||
Textures _textures;
|
||||
|
||||
int findEmptyTextureSlot() const;
|
||||
|
||||
ResourceStageState():
|
||||
_textures(MAX_NUM_RESOURCE_TEXTURES, nullptr)
|
||||
{}
|
||||
|
@ -432,6 +436,7 @@ protected:
|
|||
void do_setFramebuffer(Batch& batch, size_t paramOffset);
|
||||
void do_clearFramebuffer(Batch& batch, size_t paramOffset);
|
||||
void do_blit(Batch& batch, size_t paramOffset);
|
||||
void do_generateTextureMips(Batch& batch, size_t paramOffset);
|
||||
|
||||
// Synchronize the state cache of this Backend with the actual real state of the GL Context
|
||||
void syncOutputStateCache();
|
||||
|
|
|
@ -361,4 +361,4 @@ void GLBackend::downloadFramebuffer(const FramebufferPointer& srcFramebuffer, co
|
|||
glBindFramebuffer(GL_READ_FRAMEBUFFER, 0);
|
||||
|
||||
(void) CHECK_GL_ERROR();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -231,6 +231,7 @@ void GLBackend::releaseResourceTexture(uint32_t slot) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void GLBackend::resetResourceStage() {
|
||||
for (uint32_t i = 0; i < _resource._textures.size(); i++) {
|
||||
releaseResourceTexture(i);
|
||||
|
@ -268,3 +269,13 @@ void GLBackend::do_setResourceTexture(Batch& batch, size_t paramOffset) {
|
|||
}
|
||||
}
|
||||
|
||||
int GLBackend::ResourceStageState::findEmptyTextureSlot() const {
|
||||
// start from the end of the slots, try to find an empty one that can be used
|
||||
for (auto i = MAX_NUM_RESOURCE_TEXTURES - 1; i > 0; i--) {
|
||||
if (!_textures[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
|
|
@ -224,6 +224,11 @@ public:
|
|||
case gpu::SRGBA:
|
||||
texel.internalFormat = GL_SRGB; // standard 2.2 gamma correction color
|
||||
break;
|
||||
case gpu::R11G11B10: {
|
||||
// the type should be float
|
||||
texel.internalFormat = GL_R11F_G11F_B10F;
|
||||
break;
|
||||
}
|
||||
default:
|
||||
qCDebug(gpulogging) << "Unknown combination of texel format";
|
||||
}
|
||||
|
@ -240,6 +245,59 @@ public:
|
|||
break;
|
||||
case gpu::RGBA:
|
||||
texel.internalFormat = GL_RGBA;
|
||||
switch (dstFormat.getType()) {
|
||||
case gpu::UINT32:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA32UI;
|
||||
break;
|
||||
case gpu::INT32:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA32I;
|
||||
break;
|
||||
case gpu::FLOAT:
|
||||
texel.internalFormat = GL_RGBA32F;
|
||||
break;
|
||||
case gpu::UINT16:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA16UI;
|
||||
break;
|
||||
case gpu::INT16:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA16I;
|
||||
break;
|
||||
case gpu::NUINT16:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_RGBA16;
|
||||
break;
|
||||
case gpu::NINT16:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_RGBA16_SNORM;
|
||||
break;
|
||||
case gpu::HALF:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_RGBA16F;
|
||||
break;
|
||||
case gpu::UINT8:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA8UI;
|
||||
break;
|
||||
case gpu::INT8:
|
||||
texel.format = GL_RGBA_INTEGER;
|
||||
texel.internalFormat = GL_RGBA8I;
|
||||
break;
|
||||
case gpu::NUINT8:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_RGBA8;
|
||||
break;
|
||||
case gpu::NINT8:
|
||||
texel.format = GL_RGBA;
|
||||
texel.internalFormat = GL_RGBA8_SNORM;
|
||||
break;
|
||||
case gpu::NUINT32:
|
||||
case gpu::NINT32:
|
||||
case gpu::NUM_TYPES: // quiet compiler
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
case gpu::SRGB:
|
||||
texel.internalFormat = GL_SRGB;
|
||||
|
@ -347,7 +405,6 @@ GLBackend::GLTexture* GLBackend::syncGPUObject(const Texture& texture) {
|
|||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||
}
|
||||
|
||||
object->_target = GL_TEXTURE_2D;
|
||||
|
||||
syncSampler(texture.getSampler(), texture.getType(), object);
|
||||
|
@ -530,3 +587,37 @@ void GLBackend::syncSampler(const Sampler& sampler, Texture::Type type, GLTextur
|
|||
glTexParameterf(object->_target, GL_TEXTURE_MAX_ANISOTROPY_EXT, sampler.getMaxAnisotropy());
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
void GLBackend::do_generateTextureMips(Batch& batch, size_t paramOffset) {
|
||||
TexturePointer resourceTexture = batch._textures.get(batch._params[paramOffset + 0]._uint);
|
||||
if (!resourceTexture) {
|
||||
return;
|
||||
}
|
||||
|
||||
GLTexture* object = GLBackend::syncGPUObject(*resourceTexture);
|
||||
if (!object) {
|
||||
return;
|
||||
}
|
||||
|
||||
// IN 4.1 we still need to find an available slot
|
||||
auto freeSlot = _resource.findEmptyTextureSlot();
|
||||
auto bindingSlot = (freeSlot < 0 ? 0 : freeSlot);
|
||||
glActiveTexture(GL_TEXTURE0 + bindingSlot);
|
||||
glBindTexture(object->_target, object->_texture);
|
||||
|
||||
glGenerateMipmap(object->_target);
|
||||
|
||||
if (freeSlot < 0) {
|
||||
// If had to use slot 0 then restore state
|
||||
GLTexture* boundObject = GLBackend::syncGPUObject(*_resource._textures[0]);
|
||||
if (boundObject) {
|
||||
glBindTexture(boundObject->_target, boundObject->_texture);
|
||||
}
|
||||
} else {
|
||||
// clean up
|
||||
glBindTexture(object->_target, 0);
|
||||
}
|
||||
(void)CHECK_GL_ERROR();
|
||||
}
|
||||
|
|
|
@ -23,7 +23,7 @@ Shader::Shader(Type type, const Source& source):
|
|||
{
|
||||
}
|
||||
|
||||
Shader::Shader(Type type, Pointer& vertex, Pointer& pixel):
|
||||
Shader::Shader(Type type, const Pointer& vertex, const Pointer& pixel):
|
||||
_type(type)
|
||||
{
|
||||
_shaders.resize(2);
|
||||
|
@ -44,7 +44,7 @@ Shader::Pointer Shader::createPixel(const Source& source) {
|
|||
return Pointer(new Shader(PIXEL, source));
|
||||
}
|
||||
|
||||
Shader::Pointer Shader::createProgram(Pointer& vertexShader, Pointer& pixelShader) {
|
||||
Shader::Pointer Shader::createProgram(const Pointer& vertexShader, const Pointer& pixelShader) {
|
||||
if (vertexShader && vertexShader->getType() == VERTEX &&
|
||||
pixelShader && pixelShader->getType() == PIXEL) {
|
||||
return Pointer(new Shader(PROGRAM, vertexShader, pixelShader));
|
||||
|
|
|
@ -111,7 +111,7 @@ public:
|
|||
static Pointer createVertex(const Source& source);
|
||||
static Pointer createPixel(const Source& source);
|
||||
|
||||
static Pointer createProgram(Pointer& vertexShader, Pointer& pixelShader);
|
||||
static Pointer createProgram(const Pointer& vertexShader, const Pointer& pixelShader);
|
||||
|
||||
|
||||
~Shader();
|
||||
|
@ -157,7 +157,7 @@ public:
|
|||
|
||||
protected:
|
||||
Shader(Type type, const Source& source);
|
||||
Shader(Type type, Pointer& vertex, Pointer& pixel);
|
||||
Shader(Type type, const Pointer& vertex, const Pointer& pixel);
|
||||
|
||||
Shader(const Shader& shader); // deep copy of the sysmem shader
|
||||
Shader& operator=(const Shader& shader); // deep copy of the sysmem texture
|
||||
|
|
|
@ -407,7 +407,7 @@ public:
|
|||
|
||||
TexturePointer _texture = TexturePointer(NULL);
|
||||
uint16 _subresource = 0;
|
||||
Element _element = Element(gpu::VEC4, gpu::UINT8, gpu::RGBA);
|
||||
Element _element = Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA);
|
||||
|
||||
TextureView() {};
|
||||
|
||||
|
|
|
@ -308,10 +308,9 @@ static NetworkMaterial* buildNetworkMaterial(const FBXMaterial& material, const
|
|||
material._material->setTextureMap(model::MaterialKey::GLOSS_MAP, glossMap);
|
||||
}
|
||||
if (!material.emissiveTexture.filename.isEmpty()) {
|
||||
networkMaterial->emissiveTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.emissiveTexture.filename)), EMISSIVE_TEXTURE, material.emissiveTexture.content);
|
||||
networkMaterial->emissiveTexture = textureCache->getTexture(textureBaseUrl.resolved(QUrl(material.emissiveTexture.filename)), LIGHTMAP_TEXTURE, material.emissiveTexture.content);
|
||||
networkMaterial->emissiveTextureName = material.emissiveTexture.name;
|
||||
|
||||
//checkForTexcoordLightmap = true;
|
||||
|
||||
auto lightmapMap = model::TextureMapPointer(new model::TextureMap());
|
||||
lightmapMap->setTextureSource(networkMaterial->emissiveTexture->_textureSource);
|
||||
|
|
|
@ -85,7 +85,7 @@ const gpu::TexturePointer& TextureCache::getPermutationNormalTexture() {
|
|||
data[i + 2] = ((randvec.z + 1.0f) / 2.0f) * 255.0f;
|
||||
}
|
||||
|
||||
_permutationNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB), 256, 2));
|
||||
_permutationNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB), 256, 2));
|
||||
_permutationNormalTexture->assignStoredMip(0, _blueTexture->getTexelFormat(), sizeof(data), data);
|
||||
}
|
||||
return _permutationNormalTexture;
|
||||
|
@ -98,7 +98,7 @@ const unsigned char OPAQUE_BLACK[] = { 0x00, 0x00, 0x00, 0xFF };
|
|||
|
||||
const gpu::TexturePointer& TextureCache::getWhiteTexture() {
|
||||
if (!_whiteTexture) {
|
||||
_whiteTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1));
|
||||
_whiteTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1));
|
||||
_whiteTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_WHITE), OPAQUE_WHITE);
|
||||
}
|
||||
return _whiteTexture;
|
||||
|
@ -106,7 +106,7 @@ const gpu::TexturePointer& TextureCache::getWhiteTexture() {
|
|||
|
||||
const gpu::TexturePointer& TextureCache::getGrayTexture() {
|
||||
if (!_grayTexture) {
|
||||
_grayTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1));
|
||||
_grayTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1));
|
||||
_grayTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_WHITE), OPAQUE_GRAY);
|
||||
}
|
||||
return _grayTexture;
|
||||
|
@ -114,7 +114,7 @@ const gpu::TexturePointer& TextureCache::getGrayTexture() {
|
|||
|
||||
const gpu::TexturePointer& TextureCache::getBlueTexture() {
|
||||
if (!_blueTexture) {
|
||||
_blueTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1));
|
||||
_blueTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1));
|
||||
_blueTexture->assignStoredMip(0, _blueTexture->getTexelFormat(), sizeof(OPAQUE_BLUE), OPAQUE_BLUE);
|
||||
}
|
||||
return _blueTexture;
|
||||
|
@ -122,7 +122,7 @@ const gpu::TexturePointer& TextureCache::getBlueTexture() {
|
|||
|
||||
const gpu::TexturePointer& TextureCache::getBlackTexture() {
|
||||
if (!_blackTexture) {
|
||||
_blackTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA), 1, 1));
|
||||
_blackTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, 1, 1));
|
||||
_blackTexture->assignStoredMip(0, _whiteTexture->getTexelFormat(), sizeof(OPAQUE_BLACK), OPAQUE_BLACK);
|
||||
}
|
||||
return _blackTexture;
|
||||
|
@ -151,11 +151,11 @@ NetworkTexturePointer TextureCache::getTexture(const QUrl& url, TextureType type
|
|||
/// Returns a texture version of an image file
|
||||
gpu::TexturePointer TextureCache::getImageTexture(const QString& 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);
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB);
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB);
|
||||
if (image.hasAlphaChannel()) {
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA);
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, gpu::BGRA);
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA);
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::BGRA);
|
||||
}
|
||||
gpu::TexturePointer texture = gpu::TexturePointer(
|
||||
gpu::Texture::create2D(formatGPU, image.width(), image.height(),
|
||||
|
|
|
@ -29,7 +29,7 @@ class NetworkTexture;
|
|||
|
||||
typedef QSharedPointer<NetworkTexture> NetworkTexturePointer;
|
||||
|
||||
enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, BUMP_TEXTURE, SPECULAR_TEXTURE, EMISSIVE_TEXTURE, CUBE_TEXTURE, CUSTOM_TEXTURE };
|
||||
enum TextureType { DEFAULT_TEXTURE, NORMAL_TEXTURE, BUMP_TEXTURE, SPECULAR_TEXTURE, EMISSIVE_TEXTURE, CUBE_TEXTURE, LIGHTMAP_TEXTURE, CUSTOM_TEXTURE };
|
||||
|
||||
/// Stores cached textures, including render-to-texture targets.
|
||||
class TextureCache : public ResourceCache, public Dependency {
|
||||
|
|
|
@ -44,9 +44,9 @@ Material& Material::operator= (const Material& material) {
|
|||
Material::~Material() {
|
||||
}
|
||||
|
||||
void Material::setDiffuse(const Color& diffuse) {
|
||||
void Material::setDiffuse(const Color& diffuse, bool isSRGB) {
|
||||
_key.setDiffuse(glm::any(glm::greaterThan(diffuse, Color(0.0f))));
|
||||
_schemaBuffer.edit<Schema>()._diffuse = diffuse;
|
||||
_schemaBuffer.edit<Schema>()._diffuse = (isSRGB ? ColorUtils::toLinearVec3(diffuse) : diffuse);
|
||||
}
|
||||
|
||||
void Material::setMetallic(float metallic) {
|
||||
|
@ -54,9 +54,9 @@ void Material::setMetallic(float metallic) {
|
|||
_schemaBuffer.edit<Schema>()._metallic = glm::vec3(metallic);
|
||||
}
|
||||
|
||||
void Material::setEmissive(const Color& emissive) {
|
||||
void Material::setEmissive(const Color& emissive, bool isSRGB) {
|
||||
_key.setEmissive(glm::any(glm::greaterThan(emissive, Color(0.0f))));
|
||||
_schemaBuffer.edit<Schema>()._emissive = emissive;
|
||||
_schemaBuffer.edit<Schema>()._emissive = (isSRGB ? ColorUtils::toLinearVec3(emissive) : emissive);
|
||||
}
|
||||
|
||||
void Material::setGloss(float gloss) {
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
#include <bitset>
|
||||
#include <map>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <ColorUtils.h>
|
||||
|
||||
#include <gpu/Resource.h>
|
||||
|
||||
|
@ -219,28 +219,31 @@ public:
|
|||
virtual ~Material();
|
||||
|
||||
const MaterialKey& getKey() const { return _key; }
|
||||
|
||||
const Color& getEmissive() const { return _schemaBuffer.get<Schema>()._emissive; }
|
||||
const Color& getDiffuse() const { return _schemaBuffer.get<Schema>()._diffuse; }
|
||||
float getMetallic() const { return _schemaBuffer.get<Schema>()._metallic.x; }
|
||||
float getGloss() const { return _schemaBuffer.get<Schema>()._gloss; }
|
||||
float getOpacity() const { return _schemaBuffer.get<Schema>()._opacity; }
|
||||
|
||||
void setEmissive(const Color& emissive);
|
||||
void setDiffuse(const Color& diffuse);
|
||||
void setEmissive(const Color& emissive, bool isSRGB = true);
|
||||
Color getEmissive(bool SRGB = true) const { return (SRGB ? ColorUtils::toGamma22Vec3(_schemaBuffer.get<Schema>()._emissive) : _schemaBuffer.get<Schema>()._emissive); }
|
||||
|
||||
void setDiffuse(const Color& diffuse, bool isSRGB = true);
|
||||
Color getDiffuse(bool SRGB = true) const { return (SRGB ? ColorUtils::toGamma22Vec3(_schemaBuffer.get<Schema>()._diffuse) : _schemaBuffer.get<Schema>()._diffuse); }
|
||||
|
||||
void setMetallic(float metallic);
|
||||
float getMetallic() const { return _schemaBuffer.get<Schema>()._metallic.x; }
|
||||
|
||||
void setGloss(float gloss);
|
||||
float getGloss() const { return _schemaBuffer.get<Schema>()._gloss; }
|
||||
|
||||
void setOpacity(float opacity);
|
||||
float getOpacity() const { return _schemaBuffer.get<Schema>()._opacity; }
|
||||
|
||||
// Schema to access the attribute values of the material
|
||||
class Schema {
|
||||
public:
|
||||
|
||||
Color _diffuse{0.5f};
|
||||
glm::vec3 _diffuse{ 0.5f };
|
||||
float _opacity{1.f};
|
||||
Color _metallic{0.03f};
|
||||
glm::vec3 _metallic{ 0.03f };
|
||||
float _gloss{0.1f};
|
||||
Color _emissive{0.0f};
|
||||
glm::vec3 _emissive{ 0.0f };
|
||||
float _spare0{0.0f};
|
||||
glm::vec4 _spareVec4{0.0f}; // for alignment beauty, Material size == Mat4x4
|
||||
|
||||
|
|
|
@ -52,8 +52,7 @@ void main(void) {
|
|||
}
|
||||
}
|
||||
|
||||
vec3 pixel = pow(color, vec3(1.0/2.2)); // manual Gamma correction
|
||||
_fragColor = vec4(pixel, 0.0);
|
||||
_fragColor = vec4(color, 0.0);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -225,6 +225,21 @@ void SunSkyStage::setOriginOrientation(const Quat& orientation) {
|
|||
invalidate();
|
||||
}
|
||||
|
||||
void SunSkyStage::setOriginLongitude(float longitude) {
|
||||
_earthSunModel.setLongitude(longitude);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void SunSkyStage::setOriginLatitude(float latitude) {
|
||||
_earthSunModel.setLatitude(latitude);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void SunSkyStage::setOriginSurfaceAltitude(float altitude) {
|
||||
_earthSunModel.setAltitude(altitude);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
void SunSkyStage::setOriginLocation(float longitude, float latitude, float altitude) {
|
||||
_earthSunModel.setLongitude(longitude);
|
||||
_earthSunModel.setLatitude(latitude);
|
||||
|
|
|
@ -184,6 +184,9 @@ public:
|
|||
const Quat& getOriginOrientation() const { return _earthSunModel.getSurfaceOrientation(); }
|
||||
|
||||
// Location used to define the sun & sky is a longitude and latitude [rad] and a earth surface altitude [km]
|
||||
void setOriginLatitude(float latitude);
|
||||
void setOriginLongitude(float longitude);
|
||||
void setOriginSurfaceAltitude(float surfaceAltitude);
|
||||
void setOriginLocation(float longitude, float latitude, float surfaceAltitude);
|
||||
float getOriginLatitude() const { return _earthSunModel.getLatitude(); }
|
||||
float getOriginLongitude() const { return _earthSunModel.getLongitude(); }
|
||||
|
|
|
@ -119,13 +119,13 @@ gpu::Texture* TextureUsage::create2DTextureFromImage(const QImage& srcImage, con
|
|||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
|
||||
// bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
bool isLinearRGB = false; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
if (image.hasAlphaChannel()) {
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
}
|
||||
|
||||
|
||||
|
@ -156,11 +156,11 @@ gpu::Texture* TextureUsage::createNormalTextureFromNormalImage(const QImage& src
|
|||
|
||||
bool isLinearRGB = true;
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
if (image.hasAlphaChannel()) {
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
}
|
||||
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
|
@ -246,11 +246,11 @@ gpu::Texture* TextureUsage::createNormalTextureFromBumpImage(const QImage& srcIm
|
|||
// bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
if (image.hasAlphaChannel()) {
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
}
|
||||
|
||||
|
||||
|
@ -368,11 +368,11 @@ gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, c
|
|||
// bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
bool isLinearRGB = false; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
if (image.hasAlphaChannel()) {
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
}
|
||||
|
||||
|
||||
|
@ -520,3 +520,89 @@ gpu::Texture* TextureUsage::createCubeTextureFromImage(const QImage& srcImage, c
|
|||
|
||||
return theTexture;
|
||||
}
|
||||
|
||||
|
||||
gpu::Texture* TextureUsage::createLightmapTextureFromImage(const QImage& srcImage, const std::string& srcImageName) {
|
||||
QImage image = srcImage;
|
||||
|
||||
int imageArea = image.width() * image.height();
|
||||
|
||||
int opaquePixels = 0;
|
||||
int translucentPixels = 0;
|
||||
//bool isTransparent = false;
|
||||
int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
|
||||
const int EIGHT_BIT_MAXIMUM = 255;
|
||||
QColor averageColor(EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM, EIGHT_BIT_MAXIMUM);
|
||||
|
||||
if (!image.hasAlphaChannel()) {
|
||||
if (image.format() != QImage::Format_RGB888) {
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
// int redTotal = 0, greenTotal = 0, blueTotal = 0;
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
for (int x = 0; x < image.width(); x++) {
|
||||
QRgb rgb = image.pixel(x, y);
|
||||
redTotal += qRed(rgb);
|
||||
greenTotal += qGreen(rgb);
|
||||
blueTotal += qBlue(rgb);
|
||||
}
|
||||
}
|
||||
if (imageArea > 0) {
|
||||
averageColor.setRgb(redTotal / imageArea, greenTotal / imageArea, blueTotal / imageArea);
|
||||
}
|
||||
} else {
|
||||
if (image.format() != QImage::Format_ARGB32) {
|
||||
image = image.convertToFormat(QImage::Format_ARGB32);
|
||||
}
|
||||
|
||||
// check for translucency/false transparency
|
||||
// int opaquePixels = 0;
|
||||
// int translucentPixels = 0;
|
||||
// int redTotal = 0, greenTotal = 0, blueTotal = 0, alphaTotal = 0;
|
||||
for (int y = 0; y < image.height(); y++) {
|
||||
for (int x = 0; x < image.width(); x++) {
|
||||
QRgb rgb = image.pixel(x, y);
|
||||
redTotal += qRed(rgb);
|
||||
greenTotal += qGreen(rgb);
|
||||
blueTotal += qBlue(rgb);
|
||||
int alpha = qAlpha(rgb);
|
||||
alphaTotal += alpha;
|
||||
if (alpha == EIGHT_BIT_MAXIMUM) {
|
||||
opaquePixels++;
|
||||
} else if (alpha != 0) {
|
||||
translucentPixels++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (opaquePixels == imageArea) {
|
||||
qCDebug(modelLog) << "Image with alpha channel is completely opaque:" << QString(srcImageName.c_str());
|
||||
image = image.convertToFormat(QImage::Format_RGB888);
|
||||
}
|
||||
|
||||
averageColor = QColor(redTotal / imageArea,
|
||||
greenTotal / imageArea, blueTotal / imageArea, alphaTotal / imageArea);
|
||||
|
||||
//isTransparent = (translucentPixels >= imageArea / 2);
|
||||
}
|
||||
|
||||
gpu::Texture* theTexture = nullptr;
|
||||
if ((image.width() > 0) && (image.height() > 0)) {
|
||||
|
||||
// bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
bool isLinearRGB = true; //(_type == NORMAL_TEXTURE) || (_type == EMISSIVE_TEXTURE);
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::NUINT8, (isLinearRGB ? gpu::RGB : gpu::SRGB));
|
||||
if (image.hasAlphaChannel()) {
|
||||
formatGPU = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::RGBA : gpu::SRGBA));
|
||||
formatMip = gpu::Element(gpu::VEC4, gpu::NUINT8, (isLinearRGB ? gpu::BGRA : gpu::SBGRA));
|
||||
}
|
||||
|
||||
|
||||
theTexture = (gpu::Texture::create2D(formatGPU, image.width(), image.height(), gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR)));
|
||||
theTexture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits());
|
||||
theTexture->autoGenerateMips(-1);
|
||||
}
|
||||
|
||||
return theTexture;
|
||||
}
|
||||
|
|
|
@ -35,6 +35,8 @@ public:
|
|||
static gpu::Texture* createNormalTextureFromNormalImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createNormalTextureFromBumpImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createCubeTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||
static gpu::Texture* createLightmapTextureFromImage(const QImage& image, const std::string& srcImageName);
|
||||
|
||||
};
|
||||
|
||||
|
||||
|
|
19
libraries/networking/src/AbstractUriHandler.h
Normal file
19
libraries/networking/src/AbstractUriHandler.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
//
|
||||
// Created by Bradley Austin Davis on 2015/12/17
|
||||
// Copyright 2013-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
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_network_AbstractUriHandler_h
|
||||
#define hifi_network_AbstractUriHandler_h
|
||||
|
||||
class AbstractUriHandler {
|
||||
public:
|
||||
virtual bool canAcceptURL(const QString& url) const = 0;
|
||||
virtual bool acceptURL(const QString& url, bool defaultUpload = false) = 0;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -94,7 +94,7 @@ NodeList::NodeList(char newOwnerType, unsigned short socketListenPort, unsigned
|
|||
_keepAlivePingTimer.setInterval(KEEPALIVE_PING_INTERVAL_MS);
|
||||
connect(&_keepAlivePingTimer, &QTimer::timeout, this, &NodeList::sendKeepAlivePings);
|
||||
connect(&_domainHandler, SIGNAL(connectedToDomain(QString)), &_keepAlivePingTimer, SLOT(start()));
|
||||
connect(&_domainHandler, &DomainHandler::disconnectedFromDomain, this, &NodeList::stopKeepalivePingTimer);
|
||||
connect(&_domainHandler, &DomainHandler::disconnectedFromDomain, &_keepAlivePingTimer, &QTimer::stop);
|
||||
|
||||
// we definitely want STUN to update our public socket, so call the LNL to kick that off
|
||||
startSTUNPublicSocketUpdate();
|
||||
|
|
|
@ -122,8 +122,10 @@ void ThreadedAssignment::startSendingStats() {
|
|||
}
|
||||
|
||||
void ThreadedAssignment::stopSendingStats() {
|
||||
// stop sending stats, we just disconnected from domain
|
||||
_statsTimer->stop();
|
||||
if (_statsTimer) {
|
||||
// stop sending stats, we just disconnected from domain
|
||||
_statsTimer->stop();
|
||||
}
|
||||
}
|
||||
|
||||
void ThreadedAssignment::checkInWithDomainServerOrExit() {
|
||||
|
|
|
@ -1867,7 +1867,7 @@ bool Octree::readJSONFromStream(unsigned long streamLength, QDataStream& inputSt
|
|||
|
||||
QByteArray jsonBuffer;
|
||||
char* rawData = new char[READ_JSON_BUFFER_SIZE];
|
||||
while (true) {
|
||||
while (!inputStream.atEnd()) {
|
||||
int got = inputStream.readRawData(rawData, READ_JSON_BUFFER_SIZE - 1);
|
||||
if (got < 0) {
|
||||
qCritical() << "error while reading from json stream";
|
||||
|
|
|
@ -44,7 +44,7 @@ void PhysicalEntitySimulation::updateEntitiesInternal(const quint64& now) {
|
|||
|
||||
void PhysicalEntitySimulation::addEntityInternal(EntityItemPointer entity) {
|
||||
assert(entity);
|
||||
if (entity->shouldBePhysical()) {
|
||||
if (entity->shouldBePhysical()) {
|
||||
EntityMotionState* motionState = static_cast<EntityMotionState*>(entity->getPhysicsInfo());
|
||||
if (!motionState) {
|
||||
_pendingAdds.insert(entity);
|
||||
|
@ -117,6 +117,7 @@ void PhysicalEntitySimulation::clearEntitiesInternal() {
|
|||
_pendingRemoves.clear();
|
||||
_pendingAdds.clear();
|
||||
_pendingChanges.clear();
|
||||
_outgoingChanges.clear();
|
||||
}
|
||||
// end EntitySimulation overrides
|
||||
|
||||
|
|
|
@ -35,6 +35,8 @@ void main(void) {
|
|||
#ifdef PROCEDURAL
|
||||
|
||||
vec3 color = getSkyboxColor();
|
||||
// Procedural Shaders are expected to be Gamma corrected so let's bring back the RGB in linear space for the rest of the pipeline
|
||||
color = pow(color, vec3(2.2));
|
||||
_fragColor = vec4(color, 0.0);
|
||||
|
||||
#else
|
||||
|
@ -42,8 +44,7 @@ void main(void) {
|
|||
vec3 coord = normalize(_normal);
|
||||
vec3 texel = texture(cubeMap, coord).rgb;
|
||||
vec3 color = texel * _skybox._color.rgb;
|
||||
vec3 pixel = pow(color, vec3(1.0/2.2)); // manual Gamma correction
|
||||
_fragColor = vec4(pixel, 0.0);
|
||||
_fragColor = vec4(color, 0.0);
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -175,10 +175,10 @@ const gpu::PipelinePointer& AmbientOcclusion::getBlendPipeline() {
|
|||
}
|
||||
|
||||
void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->_viewFrustum);
|
||||
assert(renderContext->getArgs());
|
||||
assert(renderContext->getArgs()->_viewFrustum);
|
||||
|
||||
RenderArgs* args = renderContext->args;
|
||||
RenderArgs* args = renderContext->getArgs();
|
||||
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
QSize framebufferSize = framebufferCache->getFrameBufferSize();
|
||||
|
@ -201,7 +201,7 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons
|
|||
// Occlusion step
|
||||
getOcclusionPipeline();
|
||||
batch.setResourceTexture(0, framebufferCache->getPrimaryDepthTexture());
|
||||
batch.setResourceTexture(1, framebufferCache->getPrimaryNormalTexture());
|
||||
batch.setResourceTexture(1, framebufferCache->getDeferredNormalTexture());
|
||||
_occlusionBuffer->setRenderBuffer(0, _occlusionTexture);
|
||||
batch.setFramebuffer(_occlusionBuffer);
|
||||
|
||||
|
@ -276,7 +276,7 @@ void AmbientOcclusion::run(const render::SceneContextPointer& sceneContext, cons
|
|||
// Blend step
|
||||
getBlendPipeline();
|
||||
batch.setResourceTexture(0, _hBlurTexture);
|
||||
batch.setFramebuffer(framebufferCache->getPrimaryFramebuffer());
|
||||
batch.setFramebuffer(framebufferCache->getDeferredFramebuffer());
|
||||
|
||||
// Bind the fourth gpu::Pipeline we need - for blending the primary color buffer with blurred occlusion texture
|
||||
batch.setPipeline(getBlendPipeline());
|
||||
|
|
|
@ -93,14 +93,14 @@ const gpu::PipelinePointer& Antialiasing::getBlendPipeline() {
|
|||
}
|
||||
|
||||
void Antialiasing::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->_viewFrustum);
|
||||
assert(renderContext->getArgs());
|
||||
assert(renderContext->getArgs()->_viewFrustum);
|
||||
|
||||
if (renderContext->args->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
|
||||
if (renderContext->getArgs()->_renderMode == RenderArgs::MIRROR_RENDER_MODE) {
|
||||
return;
|
||||
}
|
||||
|
||||
RenderArgs* args = renderContext->args;
|
||||
RenderArgs* args = renderContext->getArgs();
|
||||
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
|
||||
|
@ -123,7 +123,7 @@ void Antialiasing::run(const render::SceneContextPointer& sceneContext, const re
|
|||
|
||||
// FXAA step
|
||||
getAntialiasingPipeline();
|
||||
batch.setResourceTexture(0, framebufferCache->getPrimaryColorTexture());
|
||||
batch.setResourceTexture(0, framebufferCache->getDeferredColorTexture());
|
||||
_antialiasingBuffer->setRenderBuffer(0, _antialiasingTexture);
|
||||
batch.setFramebuffer(_antialiasingBuffer);
|
||||
batch.setPipeline(getAntialiasingPipeline());
|
||||
|
@ -153,7 +153,7 @@ void Antialiasing::run(const render::SceneContextPointer& sceneContext, const re
|
|||
// Blend step
|
||||
getBlendPipeline();
|
||||
batch.setResourceTexture(0, _antialiasingTexture);
|
||||
batch.setFramebuffer(framebufferCache->getPrimaryFramebuffer());
|
||||
batch.setFramebuffer(framebufferCache->getDeferredFramebuffer());
|
||||
batch.setPipeline(getBlendPipeline());
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(batch, bottomLeft, topRight, texCoordTopLeft, texCoordBottomRight, color);
|
||||
|
|
214
libraries/render-utils/src/DebugDeferredBuffer.cpp
Normal file
214
libraries/render-utils/src/DebugDeferredBuffer.cpp
Normal file
|
@ -0,0 +1,214 @@
|
|||
//
|
||||
// DebugDeferredBuffer.cpp
|
||||
// libraries/render-utils/src
|
||||
//
|
||||
// Created by Clement on 12/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
|
||||
//
|
||||
|
||||
#include "DebugDeferredBuffer.h"
|
||||
|
||||
#include <QFile>
|
||||
|
||||
#include <gpu/Batch.h>
|
||||
#include <gpu/Context.h>
|
||||
#include <render/Scene.h>
|
||||
#include <ViewFrustum.h>
|
||||
|
||||
#include "GeometryCache.h"
|
||||
#include "FramebufferCache.h"
|
||||
|
||||
#include "debug_deferred_buffer_vert.h"
|
||||
#include "debug_deferred_buffer_frag.h"
|
||||
|
||||
using namespace render;
|
||||
|
||||
enum Slots {
|
||||
Diffuse = 0,
|
||||
Normal,
|
||||
Specular,
|
||||
Depth,
|
||||
Lighting
|
||||
};
|
||||
|
||||
static const std::string DEEFAULT_DIFFUSE_SHADER {
|
||||
"vec4 getFragmentColor() {"
|
||||
" return vec4(pow(texture(diffuseMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);"
|
||||
" }"
|
||||
};
|
||||
static const std::string DEEFAULT_ALPHA_SHADER {
|
||||
"vec4 getFragmentColor() {"
|
||||
" return vec4(vec3(texture(diffuseMap, uv).a), 1.0);"
|
||||
" }"
|
||||
};
|
||||
static const std::string DEEFAULT_SPECULAR_SHADER {
|
||||
"vec4 getFragmentColor() {"
|
||||
" return vec4(texture(specularMap, uv).xyz, 1.0);"
|
||||
" }"
|
||||
};
|
||||
static const std::string DEEFAULT_ROUGHNESS_SHADER {
|
||||
"vec4 getFragmentColor() {"
|
||||
" return vec4(vec3(texture(specularMap, uv).a), 1.0);"
|
||||
" }"
|
||||
};
|
||||
static const std::string DEEFAULT_NORMAL_SHADER {
|
||||
"vec4 getFragmentColor() {"
|
||||
" return vec4(normalize(texture(normalMap, uv).xyz), 1.0);"
|
||||
" }"
|
||||
};
|
||||
static const std::string DEEFAULT_DEPTH_SHADER {
|
||||
"vec4 getFragmentColor() {"
|
||||
" return vec4(vec3(texture(depthMap, uv).x), 1.0);"
|
||||
" }"
|
||||
};
|
||||
static const std::string DEEFAULT_LIGHTING_SHADER {
|
||||
"vec4 getFragmentColor() {"
|
||||
" return vec4(pow(texture(lightingMap, uv).xyz, vec3(1.0 / 2.2)), 1.0);"
|
||||
" }"
|
||||
};
|
||||
static const std::string DEEFAULT_CUSTOM_SHADER {
|
||||
"vec4 getFragmentColor() {"
|
||||
" return vec4(1.0, 0.0, 0.0, 1.0);"
|
||||
" }"
|
||||
};
|
||||
|
||||
static std::string getFileContent(std::string fileName, std::string defaultContent = std::string()) {
|
||||
QFile customFile(QString::fromStdString(fileName));
|
||||
if (customFile.open(QIODevice::ReadOnly)) {
|
||||
return customFile.readAll().toStdString();
|
||||
}
|
||||
qWarning() << "DebugDeferredBuffer::getFileContent(): Could not open"
|
||||
<< QString::fromStdString(fileName);
|
||||
return defaultContent;
|
||||
}
|
||||
|
||||
#include <QStandardPaths> // TODO REMOVE: Temporary until UI
|
||||
DebugDeferredBuffer::DebugDeferredBuffer() {
|
||||
// TODO REMOVE: Temporary until UI
|
||||
static const auto DESKTOP_PATH = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
|
||||
static const auto CUSTOM_FILE = DESKTOP_PATH.toStdString() + "/custom.slh";
|
||||
CustomPipeline pipeline;
|
||||
pipeline.info = QFileInfo(QString::fromStdString(CUSTOM_FILE));
|
||||
_customPipelines.emplace(CUSTOM_FILE, pipeline);
|
||||
}
|
||||
|
||||
std::string DebugDeferredBuffer::getShaderSourceCode(Modes mode, std::string customFile) {
|
||||
switch (mode) {
|
||||
case DiffuseMode:
|
||||
return DEEFAULT_DIFFUSE_SHADER;
|
||||
case AlphaMode:
|
||||
return DEEFAULT_ALPHA_SHADER;
|
||||
case SpecularMode:
|
||||
return DEEFAULT_SPECULAR_SHADER;
|
||||
case RoughnessMode:
|
||||
return DEEFAULT_ROUGHNESS_SHADER;
|
||||
case NormalMode:
|
||||
return DEEFAULT_NORMAL_SHADER;
|
||||
case DepthMode:
|
||||
return DEEFAULT_DEPTH_SHADER;
|
||||
case LightingMode:
|
||||
return DEEFAULT_LIGHTING_SHADER;
|
||||
case CustomMode:
|
||||
return getFileContent(customFile, DEEFAULT_CUSTOM_SHADER);
|
||||
}
|
||||
Q_UNREACHABLE();
|
||||
return std::string();
|
||||
}
|
||||
|
||||
bool DebugDeferredBuffer::pipelineNeedsUpdate(Modes mode, std::string customFile) const {
|
||||
if (mode != CustomMode) {
|
||||
return !_pipelines[mode];
|
||||
}
|
||||
|
||||
auto it = _customPipelines.find(customFile);
|
||||
if (it != _customPipelines.end() && it->second.pipeline) {
|
||||
auto& info = it->second.info;
|
||||
|
||||
auto lastModified = info.lastModified();
|
||||
info.refresh();
|
||||
return lastModified != info.lastModified();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
const gpu::PipelinePointer& DebugDeferredBuffer::getPipeline(Modes mode, std::string customFile) {
|
||||
if (pipelineNeedsUpdate(mode, customFile)) {
|
||||
static const std::string VERTEX_SHADER { debug_deferred_buffer_vert };
|
||||
static const std::string FRAGMENT_SHADER { debug_deferred_buffer_frag };
|
||||
static const std::string SOURCE_PLACEHOLDER { "//SOURCE_PLACEHOLDER" };
|
||||
static const auto SOURCE_PLACEHOLDER_INDEX = FRAGMENT_SHADER.find(SOURCE_PLACEHOLDER);
|
||||
Q_ASSERT_X(SOURCE_PLACEHOLDER_INDEX != std::string::npos, Q_FUNC_INFO,
|
||||
"Could not find source placeholder");
|
||||
|
||||
auto bakedFragmentShader = FRAGMENT_SHADER;
|
||||
bakedFragmentShader.replace(SOURCE_PLACEHOLDER_INDEX, SOURCE_PLACEHOLDER.size(),
|
||||
getShaderSourceCode(mode, customFile));
|
||||
|
||||
static const auto vs = gpu::Shader::createVertex(VERTEX_SHADER);
|
||||
const auto ps = gpu::Shader::createPixel(bakedFragmentShader);
|
||||
const auto program = gpu::Shader::createProgram(vs, ps);
|
||||
|
||||
gpu::Shader::BindingSet slotBindings;
|
||||
slotBindings.insert(gpu::Shader::Binding("diffuseMap", Diffuse));
|
||||
slotBindings.insert(gpu::Shader::Binding("normalMap", Normal));
|
||||
slotBindings.insert(gpu::Shader::Binding("specularMap", Specular));
|
||||
slotBindings.insert(gpu::Shader::Binding("depthMap", Depth));
|
||||
slotBindings.insert(gpu::Shader::Binding("lightingMap", Lighting));
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
auto pipeline = gpu::Pipeline::create(program, std::make_shared<gpu::State>());
|
||||
|
||||
// Good to go add the brand new pipeline
|
||||
if (mode != CustomMode) {
|
||||
_pipelines[mode] = pipeline;
|
||||
} else {
|
||||
_customPipelines[customFile].pipeline = pipeline;
|
||||
}
|
||||
}
|
||||
|
||||
if (mode != CustomMode) {
|
||||
return _pipelines[mode];
|
||||
} else {
|
||||
return _customPipelines[customFile].pipeline;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DebugDeferredBuffer::run(const SceneContextPointer& sceneContext, const RenderContextPointer& renderContext) {
|
||||
assert(renderContext->getArgs());
|
||||
assert(renderContext->getArgs()->_viewFrustum);
|
||||
RenderArgs* args = renderContext->getArgs();
|
||||
gpu::doInBatch(args->_context, [&](gpu::Batch& batch) {
|
||||
const auto geometryBuffer = DependencyManager::get<GeometryCache>();
|
||||
const auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
|
||||
|
||||
glm::mat4 projMat;
|
||||
Transform viewMat;
|
||||
args->_viewFrustum->evalProjectionMatrix(projMat);
|
||||
args->_viewFrustum->evalViewTransform(viewMat);
|
||||
batch.setProjectionTransform(projMat);
|
||||
batch.setViewTransform(viewMat);
|
||||
batch.setModelTransform(Transform());
|
||||
|
||||
// TODO REMOVE: Temporary until UI
|
||||
auto first = _customPipelines.begin()->first;
|
||||
|
||||
batch.setPipeline(getPipeline(Modes(renderContext->_deferredDebugMode), first));
|
||||
|
||||
batch.setResourceTexture(Diffuse, framebufferCache->getDeferredColorTexture());
|
||||
batch.setResourceTexture(Normal, framebufferCache->getDeferredNormalTexture());
|
||||
batch.setResourceTexture(Specular, framebufferCache->getDeferredSpecularTexture());
|
||||
batch.setResourceTexture(Depth, framebufferCache->getPrimaryDepthTexture());
|
||||
batch.setResourceTexture(Lighting, framebufferCache->getLightingTexture());
|
||||
|
||||
const glm::vec4 color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
const glm::vec2 bottomLeft(renderContext->_deferredDebugSize.x, renderContext->_deferredDebugSize.y);
|
||||
const glm::vec2 topRight(renderContext->_deferredDebugSize.z, renderContext->_deferredDebugSize.w);
|
||||
geometryBuffer->renderQuad(batch, bottomLeft, topRight, color);
|
||||
});
|
||||
}
|
54
libraries/render-utils/src/DebugDeferredBuffer.h
Normal file
54
libraries/render-utils/src/DebugDeferredBuffer.h
Normal file
|
@ -0,0 +1,54 @@
|
|||
//
|
||||
// DebugDeferredBuffer.h
|
||||
// libraries/render-utils/src
|
||||
//
|
||||
// Created by Clement on 12/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_DebugDeferredBuffer_h
|
||||
#define hifi_DebugDeferredBuffer_h
|
||||
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <render/DrawTask.h>
|
||||
|
||||
class DebugDeferredBuffer {
|
||||
public:
|
||||
using JobModel = render::Job::Model<DebugDeferredBuffer>;
|
||||
|
||||
DebugDeferredBuffer();
|
||||
|
||||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||
|
||||
private:
|
||||
enum Modes : uint8_t {
|
||||
DiffuseMode = 0,
|
||||
AlphaMode,
|
||||
SpecularMode,
|
||||
RoughnessMode,
|
||||
NormalMode,
|
||||
DepthMode,
|
||||
LightingMode,
|
||||
|
||||
CustomMode // Needs to stay last
|
||||
};
|
||||
struct CustomPipeline {
|
||||
gpu::PipelinePointer pipeline;
|
||||
mutable QFileInfo info;
|
||||
};
|
||||
using StandardPipelines = std::array<gpu::PipelinePointer, CustomMode>;
|
||||
using CustomPipelines = std::unordered_map<std::string, CustomPipeline>;
|
||||
|
||||
bool pipelineNeedsUpdate(Modes mode, std::string customFile = std::string()) const;
|
||||
const gpu::PipelinePointer& getPipeline(Modes mode, std::string customFile = std::string());
|
||||
std::string getShaderSourceCode(Modes mode, std::string customFile = std::string());
|
||||
|
||||
StandardPipelines _pipelines;
|
||||
CustomPipelines _customPipelines;
|
||||
};
|
||||
|
||||
#endif // hifi_DebugDeferredBuffer_h
|
|
@ -24,6 +24,9 @@ uniform sampler2D specularMap;
|
|||
// the depth texture
|
||||
uniform sampler2D depthMap;
|
||||
|
||||
// the lighting texture
|
||||
uniform sampler2D lightingMap;
|
||||
|
||||
|
||||
struct DeferredTransform {
|
||||
mat4 projection;
|
||||
|
|
|
@ -15,12 +15,6 @@ 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) {
|
||||
|
@ -39,36 +33,38 @@ vec3 bestFitNormal(vec3 normal) {
|
|||
return (cN * 0.5 + 0.5);
|
||||
}
|
||||
|
||||
|
||||
// the alpha threshold
|
||||
const float alphaThreshold = 0.5;
|
||||
float evalOpaqueFinalAlpha(float alpha, float mapAlpha) {
|
||||
return mix(alpha * glowIntensity, 1.0 - alpha * glowIntensity, step(mapAlpha, alphaThreshold));
|
||||
return mix(alpha, 1.0 - alpha, 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) {
|
||||
if (alpha != 1.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
_fragColor0 = vec4(diffuse.rgb, alpha);
|
||||
_fragColor0 = vec4(diffuse.rgb, 1.0); // Opaque
|
||||
_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) {
|
||||
if (alpha != 1.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
_fragColor0 = vec4(diffuse.rgb, alpha);
|
||||
//_fragColor1 = vec4(normal, 0.0) * 0.5 + vec4(0.5, 0.5, 0.5, 1.0);
|
||||
_fragColor0 = vec4(diffuse.rgb, 0.5);
|
||||
_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) {
|
||||
if (alpha <= 0.0) {
|
||||
discard;
|
||||
}
|
||||
|
||||
|
|
|
@ -83,7 +83,7 @@ vec3 evalAmbienGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 positi
|
|||
|
||||
vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss);
|
||||
|
||||
color += vec3(diffuse + shading.rgb) * shading.w * shadowAttenuation * getLightColor(light) * getLightIntensity(light);
|
||||
color += vec3(diffuse * shading.w + shading.rgb) * shadowAttenuation * getLightColor(light) * getLightIntensity(light);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
@ -106,7 +106,7 @@ vec3 evalAmbienSphereGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3
|
|||
|
||||
vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss);
|
||||
|
||||
color += vec3(diffuse + shading.rgb) * shading.w * shadowAttenuation * getLightColor(light) * getLightIntensity(light);
|
||||
color += vec3(diffuse * shading.w + shading.rgb) * shadowAttenuation * getLightColor(light) * getLightIntensity(light);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
@ -129,7 +129,7 @@ vec3 evalSkyboxGlobalColor(mat4 invViewMat, float shadowAttenuation, vec3 positi
|
|||
|
||||
vec4 shading = evalFragShading(fragNormal, -getLightDirection(light), fragEyeDir, specular, gloss);
|
||||
|
||||
color += vec3(diffuse + shading.rgb) * shading.w * shadowAttenuation * getLightColor(light) * getLightIntensity(light);
|
||||
color += vec3(diffuse * shading.w + shading.rgb) * shadowAttenuation * getLightColor(light) * getLightIntensity(light);
|
||||
|
||||
return color;
|
||||
}
|
||||
|
|
|
@ -23,17 +23,16 @@ vec4 evalPBRShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3 sp
|
|||
// Specular Lighting depends on the half vector and the gloss
|
||||
vec3 halfDir = normalize(fragEyeDir + fragLightDir);
|
||||
|
||||
// float specularPower = pow(facingLight * max(0.0, dot(halfDir, fragNormal)), gloss * 128.0);
|
||||
float specularPower = pow(max(0.0, dot(halfDir, fragNormal)), gloss * 128.0);
|
||||
specularPower *= (gloss * 128.0 * 0.125 + 0.25);
|
||||
|
||||
float shlickPower = (1.0 - dot(fragLightDir,halfDir));
|
||||
float shlickPower2 = shlickPower * shlickPower;
|
||||
float shlickPower5 = shlickPower2 * shlickPower2 * shlickPower;
|
||||
vec3 schlick = specular * (1.0 - shlickPower5) + vec3(shlickPower5);
|
||||
vec3 reflect = specularPower * schlick;
|
||||
vec3 fresnel = specular * (1.0 - shlickPower5) + vec3(shlickPower5);
|
||||
vec3 reflect = specularPower * fresnel * diffuse;
|
||||
|
||||
return vec4(reflect, diffuse);
|
||||
return vec4(reflect, diffuse * (1 - fresnel.x));
|
||||
}
|
||||
<@endfunc@>
|
||||
|
||||
|
@ -49,7 +48,7 @@ vec4 evalBlinnShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3
|
|||
vec3 halfDir = normalize(fragEyeDir + fragLightDir);
|
||||
|
||||
float specularPower = pow(facingLight * max(0.0, dot(halfDir, fragNormal)), gloss * 128.0);
|
||||
vec3 reflect = specularPower * specular;
|
||||
vec3 reflect = specularPower * specular * diffuse;
|
||||
|
||||
return vec4(reflect, diffuse);
|
||||
}
|
||||
|
@ -59,14 +58,9 @@ vec4 evalBlinnShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3
|
|||
|
||||
<$declareEvalPBRShading()$>
|
||||
|
||||
|
||||
// Return xyz the specular/reflection component and w the diffuse component
|
||||
vec4 evalFragShading(vec3 fragNormal, vec3 fragLightDir, vec3 fragEyeDir, vec3 specular, float gloss) {
|
||||
|
||||
/*if (gl_FragCoord.x > 1000) {
|
||||
return evalBlinnShading(fragNormal, fragLightDir, fragEyeDir, specular, gloss);
|
||||
} else {*/
|
||||
return evalPBRShading(fragNormal, fragLightDir, fragEyeDir, specular, gloss);
|
||||
//}
|
||||
return evalPBRShading(fragNormal, fragLightDir, fragEyeDir, specular, gloss);
|
||||
}
|
||||
|
||||
<@endif@>
|
||||
|
|
|
@ -34,25 +34,13 @@
|
|||
#include "deferred_light_spot_vert.h"
|
||||
|
||||
#include "directional_light_frag.h"
|
||||
#include "directional_light_shadow_map_frag.h"
|
||||
#include "directional_light_cascaded_shadow_map_frag.h"
|
||||
|
||||
#include "directional_ambient_light_frag.h"
|
||||
#include "directional_ambient_light_shadow_map_frag.h"
|
||||
#include "directional_ambient_light_cascaded_shadow_map_frag.h"
|
||||
|
||||
#include "directional_skybox_light_frag.h"
|
||||
#include "directional_skybox_light_shadow_map_frag.h"
|
||||
#include "directional_skybox_light_cascaded_shadow_map_frag.h"
|
||||
|
||||
#include "point_light_frag.h"
|
||||
#include "spot_light_frag.h"
|
||||
|
||||
static const std::string glowIntensityShaderHandle = "glowIntensity";
|
||||
|
||||
struct LightLocations {
|
||||
int shadowDistances;
|
||||
int shadowScale;
|
||||
int radius;
|
||||
int ambientSphere;
|
||||
int lightBufferUnit;
|
||||
|
@ -92,7 +80,7 @@ gpu::PipelinePointer DeferredLightingEffect::getPipeline(SimpleProgramKey config
|
|||
return pipeline;
|
||||
}
|
||||
|
||||
void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
|
||||
void DeferredLightingEffect::init() {
|
||||
auto VS = gpu::Shader::createVertex(std::string(simple_vert));
|
||||
auto PS = gpu::Shader::createPixel(std::string(simple_textured_frag));
|
||||
auto PSEmissive = gpu::Shader::createPixel(std::string(simple_textured_emisive_frag));
|
||||
|
@ -105,54 +93,23 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
|
|||
gpu::Shader::makeProgram(*_simpleShader, slotBindings);
|
||||
gpu::Shader::makeProgram(*_emissiveShader, slotBindings);
|
||||
|
||||
_viewState = viewState;
|
||||
|
||||
_directionalLightLocations = std::make_shared<LightLocations>();
|
||||
_directionalLightShadowMapLocations = std::make_shared<LightLocations>();
|
||||
_directionalLightCascadedShadowMapLocations = std::make_shared<LightLocations>();
|
||||
_directionalAmbientSphereLightLocations = std::make_shared<LightLocations>();
|
||||
_directionalAmbientSphereLightShadowMapLocations = std::make_shared<LightLocations>();
|
||||
_directionalAmbientSphereLightCascadedShadowMapLocations = std::make_shared<LightLocations>();
|
||||
_directionalSkyboxLightLocations = std::make_shared<LightLocations>();
|
||||
_directionalSkyboxLightShadowMapLocations = std::make_shared<LightLocations>();
|
||||
_directionalSkyboxLightCascadedShadowMapLocations = std::make_shared<LightLocations>();
|
||||
_pointLightLocations = std::make_shared<LightLocations>();
|
||||
_spotLightLocations = std::make_shared<LightLocations>();
|
||||
|
||||
loadLightProgram(deferred_light_vert, directional_light_frag, false, _directionalLight, _directionalLightLocations);
|
||||
loadLightProgram(deferred_light_vert, directional_light_shadow_map_frag, false, _directionalLightShadowMap,
|
||||
_directionalLightShadowMapLocations);
|
||||
loadLightProgram(deferred_light_vert, directional_light_cascaded_shadow_map_frag, false, _directionalLightCascadedShadowMap,
|
||||
_directionalLightCascadedShadowMapLocations);
|
||||
|
||||
loadLightProgram(deferred_light_vert, directional_ambient_light_frag, false, _directionalAmbientSphereLight, _directionalAmbientSphereLightLocations);
|
||||
loadLightProgram(deferred_light_vert, directional_ambient_light_shadow_map_frag, false, _directionalAmbientSphereLightShadowMap,
|
||||
_directionalAmbientSphereLightShadowMapLocations);
|
||||
loadLightProgram(deferred_light_vert, directional_ambient_light_cascaded_shadow_map_frag, false, _directionalAmbientSphereLightCascadedShadowMap,
|
||||
_directionalAmbientSphereLightCascadedShadowMapLocations);
|
||||
|
||||
loadLightProgram(deferred_light_vert, directional_skybox_light_frag, false, _directionalSkyboxLight, _directionalSkyboxLightLocations);
|
||||
loadLightProgram(deferred_light_vert, directional_skybox_light_shadow_map_frag, false, _directionalSkyboxLightShadowMap,
|
||||
_directionalSkyboxLightShadowMapLocations);
|
||||
loadLightProgram(deferred_light_vert, directional_skybox_light_cascaded_shadow_map_frag, false, _directionalSkyboxLightCascadedShadowMap,
|
||||
_directionalSkyboxLightCascadedShadowMapLocations);
|
||||
|
||||
|
||||
loadLightProgram(deferred_light_limited_vert, point_light_frag, true, _pointLight, _pointLightLocations);
|
||||
loadLightProgram(deferred_light_spot_vert, spot_light_frag, true, _spotLight, _spotLightLocations);
|
||||
|
||||
{
|
||||
//auto VSFS = gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS();
|
||||
//auto PSBlit = gpu::StandardShaderLib::getDrawTexturePS();
|
||||
auto blitProgram = gpu::StandardShaderLib::getProgram(gpu::StandardShaderLib::getDrawViewportQuadTransformTexcoordVS, gpu::StandardShaderLib::getDrawTexturePS);
|
||||
gpu::Shader::makeProgram(*blitProgram);
|
||||
auto blitState = std::make_shared<gpu::State>();
|
||||
blitState->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);
|
||||
blitState->setColorWriteMask(true, true, true, false);
|
||||
_blitLightBuffer = gpu::Pipeline::create(blitProgram, blitState);
|
||||
}
|
||||
|
||||
// Allocate a global light representing the Global Directional light casting shadow (the sun) and the ambient light
|
||||
_globalLights.push_back(0);
|
||||
_allocatedLights.push_back(std::make_shared<model::Light>());
|
||||
|
@ -175,8 +132,6 @@ gpu::PipelinePointer DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch
|
|||
batch.setPipeline(pipeline);
|
||||
|
||||
gpu::ShaderPointer program = (config.isEmissive()) ? _emissiveShader : _simpleShader;
|
||||
int glowIntensity = program->getUniforms().findLocation("glowIntensity");
|
||||
batch._glUniform1f(glowIntensity, 1.0f);
|
||||
|
||||
if (!config.isTextured()) {
|
||||
// If it is not textured, bind white texture and keep using textured pipeline
|
||||
|
@ -342,11 +297,27 @@ void DeferredLightingEffect::addSpotLight(const glm::vec3& position, float radiu
|
|||
void DeferredLightingEffect::prepare(RenderArgs* args) {
|
||||
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setStateScissorRect(args->_viewport);
|
||||
|
||||
auto primaryFbo = DependencyManager::get<FramebufferCache>()->getPrimaryFramebuffer();
|
||||
// Clear Lighting buffer
|
||||
auto lightingFbo = DependencyManager::get<FramebufferCache>()->getLightingFramebuffer();
|
||||
|
||||
batch.setFramebuffer(lightingFbo);
|
||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR0, vec4(vec3(0), 0), true);
|
||||
|
||||
// Clear deferred
|
||||
auto deferredFbo = DependencyManager::get<FramebufferCache>()->getDeferredFramebuffer();
|
||||
|
||||
batch.setFramebuffer(deferredFbo);
|
||||
|
||||
// Clear Color, Depth and Stencil
|
||||
batch.clearFramebuffer(
|
||||
gpu::Framebuffer::BUFFER_COLOR0 |
|
||||
gpu::Framebuffer::BUFFER_DEPTH |
|
||||
gpu::Framebuffer::BUFFER_STENCIL,
|
||||
vec4(vec3(0), 1), 1.0, 0.0, true);
|
||||
|
||||
batch.setFramebuffer(primaryFbo);
|
||||
// clear the normal and specular buffers
|
||||
batch.clearColorFramebuffer(gpu::Framebuffer::BUFFER_COLOR1, glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true);
|
||||
const float MAX_SPECULAR_EXPONENT = 128.0f;
|
||||
|
@ -354,8 +325,6 @@ void DeferredLightingEffect::prepare(RenderArgs* args) {
|
|||
});
|
||||
}
|
||||
|
||||
gpu::FramebufferPointer _copyFBO;
|
||||
|
||||
void DeferredLightingEffect::render(RenderArgs* args) {
|
||||
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
||||
|
||||
|
@ -375,18 +344,16 @@ void DeferredLightingEffect::render(RenderArgs* args) {
|
|||
QSize framebufferSize = framebufferCache->getFrameBufferSize();
|
||||
|
||||
// binding the first framebuffer
|
||||
_copyFBO = framebufferCache->getFramebuffer();
|
||||
batch.setFramebuffer(_copyFBO);
|
||||
auto lightingFBO = framebufferCache->getLightingFramebuffer();
|
||||
batch.setFramebuffer(lightingFBO);
|
||||
|
||||
// Clearing it
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setStateScissorRect(args->_viewport);
|
||||
batch.clearColorFramebuffer(_copyFBO->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f), true);
|
||||
|
||||
// BInd the G-Buffer surfaces
|
||||
batch.setResourceTexture(0, framebufferCache->getPrimaryColorTexture());
|
||||
batch.setResourceTexture(1, framebufferCache->getPrimaryNormalTexture());
|
||||
batch.setResourceTexture(2, framebufferCache->getPrimarySpecularTexture());
|
||||
batch.setResourceTexture(0, framebufferCache->getDeferredColorTexture());
|
||||
batch.setResourceTexture(1, framebufferCache->getDeferredNormalTexture());
|
||||
batch.setResourceTexture(2, framebufferCache->getDeferredSpecularTexture());
|
||||
batch.setResourceTexture(3, framebufferCache->getPrimaryDepthTexture());
|
||||
|
||||
// THe main viewport is assumed to be the mono viewport (or the 2 stereo faces side by side within that viewport)
|
||||
|
@ -679,42 +646,6 @@ void DeferredLightingEffect::render(RenderArgs* args) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void DeferredLightingEffect::copyBack(RenderArgs* args) {
|
||||
auto framebufferCache = DependencyManager::get<FramebufferCache>();
|
||||
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
||||
batch.enableStereo(false);
|
||||
QSize framebufferSize = framebufferCache->getFrameBufferSize();
|
||||
|
||||
// TODO why doesn't this blit work? It only seems to affect a small area below the rear view mirror.
|
||||
// auto destFbo = framebufferCache->getPrimaryFramebuffer();
|
||||
auto destFbo = framebufferCache->getPrimaryFramebufferDepthColor();
|
||||
// gpu::Vec4i vp = args->_viewport;
|
||||
// batch.blit(_copyFBO, vp, framebufferCache->getPrimaryFramebuffer(), vp);
|
||||
batch.setFramebuffer(destFbo);
|
||||
batch.setViewportTransform(args->_viewport);
|
||||
batch.setProjectionTransform(glm::mat4());
|
||||
batch.setViewTransform(Transform());
|
||||
{
|
||||
float sMin = args->_viewport.x / (float)framebufferSize.width();
|
||||
float sWidth = args->_viewport.z / (float)framebufferSize.width();
|
||||
float tMin = args->_viewport.y / (float)framebufferSize.height();
|
||||
float tHeight = args->_viewport.w / (float)framebufferSize.height();
|
||||
Transform model;
|
||||
batch.setPipeline(_blitLightBuffer);
|
||||
model.setTranslation(glm::vec3(sMin, tMin, 0.0));
|
||||
model.setScale(glm::vec3(sWidth, tHeight, 1.0));
|
||||
batch.setModelTransform(model);
|
||||
}
|
||||
|
||||
batch.setResourceTexture(0, _copyFBO->getRenderBuffer(0));
|
||||
batch.draw(gpu::TRIANGLE_STRIP, 4);
|
||||
|
||||
args->_context->render(batch);
|
||||
});
|
||||
framebufferCache->releaseFramebuffer(_copyFBO);
|
||||
}
|
||||
|
||||
void DeferredLightingEffect::setupTransparent(RenderArgs* args, int lightBufferUnit) {
|
||||
auto globalLight = _allocatedLights[_globalLights.front()];
|
||||
args->_batch->setUniformBuffer(lightBufferUnit, globalLight->getSchemaBuffer());
|
||||
|
@ -731,7 +662,6 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo
|
|||
slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), 1));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("specularMap"), 2));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("depthMap"), 3));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("shadowMap"), 4));
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("skyboxMap"), 5));
|
||||
const int LIGHT_GPU_SLOT = 3;
|
||||
slotBindings.insert(gpu::Shader::Binding(std::string("lightBuffer"), LIGHT_GPU_SLOT));
|
||||
|
@ -742,8 +672,6 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo
|
|||
|
||||
gpu::Shader::makeProgram(*program, slotBindings);
|
||||
|
||||
locations->shadowDistances = program->getUniforms().findLocation("shadowDistances");
|
||||
locations->shadowScale = program->getUniforms().findLocation("shadowScale");
|
||||
|
||||
locations->radius = program->getUniforms().findLocation("radius");
|
||||
locations->ambientSphere = program->getUniforms().findLocation("ambientSphere.L00");
|
||||
|
@ -756,6 +684,11 @@ static void loadLightProgram(const char* vertSource, const char* fragSource, boo
|
|||
locations->deferredTransformBuffer = program->getBuffers().findLocation("deferredTransformBuffer");
|
||||
|
||||
auto state = std::make_shared<gpu::State>();
|
||||
state->setColorWriteMask(true, true, true, false);
|
||||
|
||||
// Stencil test all the light passes for objects pixels only, not the background
|
||||
state->setStencilTest(true, 0xFF, gpu::State::StencilTest(0, 0xFF, gpu::NOT_EQUAL, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP, gpu::State::STENCIL_OP_KEEP));
|
||||
|
||||
if (lightVolume) {
|
||||
state->setCullMode(gpu::State::CULL_BACK);
|
||||
|
||||
|
|
|
@ -21,7 +21,6 @@
|
|||
#include "model/Stage.h"
|
||||
#include "model/Geometry.h"
|
||||
|
||||
class AbstractViewStateInterface;
|
||||
class RenderArgs;
|
||||
class SimpleProgramKey;
|
||||
struct LightLocations;
|
||||
|
@ -34,7 +33,7 @@ public:
|
|||
static const int NORMAL_FITTING_MAP_SLOT = 10;
|
||||
static const int DEFERRED_TRANSFORM_BUFFER_SLOT = 2;
|
||||
|
||||
void init(AbstractViewStateInterface* viewState);
|
||||
void init();
|
||||
|
||||
/// Sets up the state necessary to render static untextured geometry with the simple program.
|
||||
gpu::PipelinePointer bindSimpleProgram(gpu::Batch& batch, bool textured = false, bool culled = true,
|
||||
|
@ -78,7 +77,6 @@ public:
|
|||
|
||||
void prepare(RenderArgs* args);
|
||||
void render(RenderArgs* args);
|
||||
void copyBack(RenderArgs* args);
|
||||
|
||||
void setupTransparent(RenderArgs* args, int lightBufferUnit);
|
||||
|
||||
|
@ -101,29 +99,15 @@ private:
|
|||
gpu::ShaderPointer _simpleShader;
|
||||
gpu::ShaderPointer _emissiveShader;
|
||||
QHash<SimpleProgramKey, gpu::PipelinePointer> _simplePrograms;
|
||||
|
||||
gpu::PipelinePointer _blitLightBuffer;
|
||||
|
||||
|
||||
gpu::PipelinePointer _directionalSkyboxLight;
|
||||
LightLocationsPtr _directionalSkyboxLightLocations;
|
||||
gpu::PipelinePointer _directionalSkyboxLightShadowMap;
|
||||
LightLocationsPtr _directionalSkyboxLightShadowMapLocations;
|
||||
gpu::PipelinePointer _directionalSkyboxLightCascadedShadowMap;
|
||||
LightLocationsPtr _directionalSkyboxLightCascadedShadowMapLocations;
|
||||
|
||||
gpu::PipelinePointer _directionalAmbientSphereLight;
|
||||
LightLocationsPtr _directionalAmbientSphereLightLocations;
|
||||
gpu::PipelinePointer _directionalAmbientSphereLightShadowMap;
|
||||
LightLocationsPtr _directionalAmbientSphereLightShadowMapLocations;
|
||||
gpu::PipelinePointer _directionalAmbientSphereLightCascadedShadowMap;
|
||||
LightLocationsPtr _directionalAmbientSphereLightCascadedShadowMapLocations;
|
||||
|
||||
gpu::PipelinePointer _directionalLight;
|
||||
LightLocationsPtr _directionalLightLocations;
|
||||
gpu::PipelinePointer _directionalLightShadowMap;
|
||||
LightLocationsPtr _directionalLightShadowMapLocations;
|
||||
gpu::PipelinePointer _directionalLightCascadedShadowMap;
|
||||
LightLocationsPtr _directionalLightCascadedShadowMapLocations;
|
||||
|
||||
gpu::PipelinePointer _pointLight;
|
||||
LightLocationsPtr _pointLightLocations;
|
||||
|
@ -155,8 +139,6 @@ private:
|
|||
std::vector<int> _globalLights;
|
||||
std::vector<int> _pointLights;
|
||||
std::vector<int> _spotLights;
|
||||
|
||||
AbstractViewStateInterface* _viewState;
|
||||
|
||||
int _ambientLightMode = 0;
|
||||
model::AtmospherePointer _atmosphere;
|
||||
|
|
|
@ -33,61 +33,76 @@ void FramebufferCache::setFrameBufferSize(QSize frameBufferSize) {
|
|||
//If the size changed, we need to delete our FBOs
|
||||
if (_frameBufferSize != frameBufferSize) {
|
||||
_frameBufferSize = frameBufferSize;
|
||||
_primaryFramebufferFull.reset();
|
||||
_primaryFramebufferDepthColor.reset();
|
||||
_primaryFramebuffer.reset();
|
||||
_primaryDepthTexture.reset();
|
||||
_primaryColorTexture.reset();
|
||||
_primaryNormalTexture.reset();
|
||||
_primarySpecularTexture.reset();
|
||||
_deferredFramebuffer.reset();
|
||||
_deferredFramebufferDepthColor.reset();
|
||||
_deferredColorTexture.reset();
|
||||
_deferredNormalTexture.reset();
|
||||
_deferredSpecularTexture.reset();
|
||||
_selfieFramebuffer.reset();
|
||||
_cachedFramebuffers.clear();
|
||||
_lightingTexture.reset();
|
||||
_lightingFramebuffer.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void FramebufferCache::createPrimaryFramebuffer() {
|
||||
_primaryFramebufferFull = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||
_primaryFramebufferDepthColor = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||
_primaryFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||
_deferredFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||
_deferredFramebufferDepthColor = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||
|
||||
auto colorFormat = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA);
|
||||
auto colorFormat = gpu::Element::COLOR_RGBA_32;
|
||||
auto width = _frameBufferSize.width();
|
||||
auto height = _frameBufferSize.height();
|
||||
|
||||
auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT);
|
||||
_primaryColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler));
|
||||
_primaryNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler));
|
||||
_primarySpecularTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler));
|
||||
|
||||
_primaryFramebufferFull->setRenderBuffer(0, _primaryColorTexture);
|
||||
_primaryFramebufferFull->setRenderBuffer(1, _primaryNormalTexture);
|
||||
_primaryFramebufferFull->setRenderBuffer(2, _primarySpecularTexture);
|
||||
_primaryFramebuffer->setRenderBuffer(0, _primaryColorTexture);
|
||||
|
||||
_primaryFramebufferDepthColor->setRenderBuffer(0, _primaryColorTexture);
|
||||
_deferredColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler));
|
||||
_deferredNormalTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler));
|
||||
_deferredSpecularTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler));
|
||||
|
||||
_deferredFramebuffer->setRenderBuffer(0, _deferredColorTexture);
|
||||
_deferredFramebuffer->setRenderBuffer(1, _deferredNormalTexture);
|
||||
_deferredFramebuffer->setRenderBuffer(2, _deferredSpecularTexture);
|
||||
|
||||
_deferredFramebufferDepthColor->setRenderBuffer(0, _deferredColorTexture);
|
||||
|
||||
// auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH);
|
||||
auto depthFormat = gpu::Element(gpu::SCALAR, gpu::UINT32, gpu::DEPTH_STENCIL); // Depth24_Stencil8 texel format
|
||||
_primaryDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height, defaultSampler));
|
||||
|
||||
_primaryFramebufferFull->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
||||
|
||||
_primaryFramebufferDepthColor->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
||||
|
||||
_primaryFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
||||
|
||||
_deferredFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
||||
|
||||
_deferredFramebufferDepthColor->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
||||
|
||||
|
||||
_selfieFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||
auto tex = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width * 0.5, height * 0.5, defaultSampler));
|
||||
_selfieFramebuffer->setRenderBuffer(0, tex);
|
||||
|
||||
auto smoothSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_MIP_LINEAR);
|
||||
|
||||
// FIXME: Decide on the proper one, let s stick to R11G11B10 for now
|
||||
//_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element::COLOR_RGBA_32, width, height, defaultSampler));
|
||||
_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::R11G11B10), width, height, defaultSampler));
|
||||
//_lightingTexture = gpu::TexturePointer(gpu::Texture::create2D(gpu::Element(gpu::VEC4, gpu::HALF, gpu::RGBA), width, height, defaultSampler));
|
||||
_lightingFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create());
|
||||
_lightingFramebuffer->setRenderBuffer(0, _lightingTexture);
|
||||
_lightingFramebuffer->setDepthStencilBuffer(_primaryDepthTexture, depthFormat);
|
||||
}
|
||||
|
||||
gpu::FramebufferPointer FramebufferCache::getPrimaryFramebuffer() {
|
||||
if (!_primaryFramebufferFull) {
|
||||
if (!_primaryFramebuffer) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _primaryFramebufferFull;
|
||||
}
|
||||
|
||||
gpu::FramebufferPointer FramebufferCache::getPrimaryFramebufferDepthColor() {
|
||||
if (!_primaryFramebufferDepthColor) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _primaryFramebufferDepthColor;
|
||||
return _primaryFramebuffer;
|
||||
}
|
||||
|
||||
gpu::TexturePointer FramebufferCache::getPrimaryDepthTexture() {
|
||||
|
@ -104,18 +119,53 @@ gpu::TexturePointer FramebufferCache::getPrimaryColorTexture() {
|
|||
return _primaryColorTexture;
|
||||
}
|
||||
|
||||
gpu::TexturePointer FramebufferCache::getPrimaryNormalTexture() {
|
||||
if (!_primaryNormalTexture) {
|
||||
gpu::FramebufferPointer FramebufferCache::getDeferredFramebuffer() {
|
||||
if (!_deferredFramebuffer) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _primaryNormalTexture;
|
||||
return _deferredFramebuffer;
|
||||
}
|
||||
|
||||
gpu::TexturePointer FramebufferCache::getPrimarySpecularTexture() {
|
||||
if (!_primarySpecularTexture) {
|
||||
gpu::FramebufferPointer FramebufferCache::getDeferredFramebufferDepthColor() {
|
||||
if (!_deferredFramebufferDepthColor) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _primarySpecularTexture;
|
||||
return _deferredFramebufferDepthColor;
|
||||
}
|
||||
|
||||
gpu::TexturePointer FramebufferCache::getDeferredColorTexture() {
|
||||
if (!_deferredColorTexture) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _deferredColorTexture;
|
||||
}
|
||||
|
||||
gpu::TexturePointer FramebufferCache::getDeferredNormalTexture() {
|
||||
if (!_deferredNormalTexture) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _deferredNormalTexture;
|
||||
}
|
||||
|
||||
gpu::TexturePointer FramebufferCache::getDeferredSpecularTexture() {
|
||||
if (!_deferredSpecularTexture) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _deferredSpecularTexture;
|
||||
}
|
||||
|
||||
gpu::FramebufferPointer FramebufferCache::getLightingFramebuffer() {
|
||||
if (!_lightingFramebuffer) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _lightingFramebuffer;
|
||||
}
|
||||
|
||||
gpu::TexturePointer FramebufferCache::getLightingTexture() {
|
||||
if (!_lightingTexture) {
|
||||
createPrimaryFramebuffer();
|
||||
}
|
||||
return _lightingTexture;
|
||||
}
|
||||
|
||||
gpu::FramebufferPointer FramebufferCache::getFramebuffer() {
|
||||
|
|
|
@ -30,12 +30,20 @@ public:
|
|||
/// Returns a pointer to the primary framebuffer object. This render target includes a depth component, and is
|
||||
/// used for scene rendering.
|
||||
gpu::FramebufferPointer getPrimaryFramebuffer();
|
||||
gpu::FramebufferPointer getPrimaryFramebufferDepthColor();
|
||||
|
||||
gpu::TexturePointer getPrimaryDepthTexture();
|
||||
gpu::TexturePointer getPrimaryColorTexture();
|
||||
gpu::TexturePointer getPrimaryNormalTexture();
|
||||
gpu::TexturePointer getPrimarySpecularTexture();
|
||||
|
||||
gpu::FramebufferPointer getDeferredFramebuffer();
|
||||
gpu::FramebufferPointer getDeferredFramebufferDepthColor();
|
||||
|
||||
gpu::TexturePointer getDeferredColorTexture();
|
||||
gpu::TexturePointer getDeferredNormalTexture();
|
||||
gpu::TexturePointer getDeferredSpecularTexture();
|
||||
|
||||
|
||||
gpu::TexturePointer getLightingTexture();
|
||||
gpu::FramebufferPointer getLightingFramebuffer();
|
||||
|
||||
/// Returns the framebuffer object used to render shadow maps;
|
||||
gpu::FramebufferPointer getShadowFramebuffer();
|
||||
|
@ -56,14 +64,21 @@ private:
|
|||
|
||||
void createPrimaryFramebuffer();
|
||||
|
||||
gpu::FramebufferPointer _primaryFramebufferFull;
|
||||
gpu::FramebufferPointer _primaryFramebufferDepthColor;
|
||||
gpu::FramebufferPointer _primaryFramebuffer;
|
||||
|
||||
gpu::TexturePointer _primaryDepthTexture;
|
||||
gpu::TexturePointer _primaryColorTexture;
|
||||
gpu::TexturePointer _primaryNormalTexture;
|
||||
gpu::TexturePointer _primarySpecularTexture;
|
||||
|
||||
|
||||
gpu::FramebufferPointer _deferredFramebuffer;
|
||||
gpu::FramebufferPointer _deferredFramebufferDepthColor;
|
||||
|
||||
gpu::TexturePointer _deferredColorTexture;
|
||||
gpu::TexturePointer _deferredNormalTexture;
|
||||
gpu::TexturePointer _deferredSpecularTexture;
|
||||
|
||||
gpu::TexturePointer _lightingTexture;
|
||||
gpu::FramebufferPointer _lightingFramebuffer;
|
||||
|
||||
gpu::FramebufferPointer _shadowFramebuffer;
|
||||
|
||||
gpu::FramebufferPointer _selfieFramebuffer;
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
|
||||
#include <glm/gtc/random.hpp>
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <PathUtils.h>
|
||||
#include <SharedUtil.h>
|
||||
|
||||
|
@ -60,9 +61,9 @@ const gpu::PipelinePointer& HitEffect::getHitEffectPipeline() {
|
|||
}
|
||||
|
||||
void HitEffect::run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext) {
|
||||
assert(renderContext->args);
|
||||
assert(renderContext->args->_viewFrustum);
|
||||
RenderArgs* args = renderContext->args;
|
||||
assert(renderContext->getArgs());
|
||||
assert(renderContext->getArgs()->_viewFrustum);
|
||||
RenderArgs* args = renderContext->getArgs();
|
||||
gpu::doInBatch(args->_context, [=](gpu::Batch& batch) {
|
||||
|
||||
glm::mat4 projMat;
|
||||
|
|
|
@ -9,11 +9,7 @@
|
|||
#ifndef hifi_hitEffect_h
|
||||
#define hifi_hitEffect_h
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include "render/DrawTask.h"
|
||||
|
||||
class AbstractViewStateInterface;
|
||||
class ProgramObject;
|
||||
#include <render/DrawTask.h>
|
||||
|
||||
class HitEffect {
|
||||
public:
|
||||
|
@ -23,7 +19,7 @@ public:
|
|||
void run(const render::SceneContextPointer& sceneContext, const render::RenderContextPointer& renderContext);
|
||||
typedef render::Job::Model<HitEffect> JobModel;
|
||||
|
||||
const gpu::PipelinePointer& getHitEffectPipeline();
|
||||
const gpu::PipelinePointer& getHitEffectPipeline();
|
||||
|
||||
private:
|
||||
gpu::PipelinePointer _hitEffectPipeline;
|
||||
|
|
|
@ -199,8 +199,6 @@ void MeshPartPayload::render(RenderArgs* args) const {
|
|||
gpu::Batch& batch = *(args->_batch);
|
||||
auto mode = args->_renderMode;
|
||||
|
||||
auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME
|
||||
|
||||
model::MaterialKey drawMaterialKey;
|
||||
if (_drawMaterial) {
|
||||
drawMaterialKey = _drawMaterial->getKey();
|
||||
|
@ -217,7 +215,7 @@ void MeshPartPayload::render(RenderArgs* args) const {
|
|||
}
|
||||
|
||||
ModelRender::Locations* locations = nullptr;
|
||||
ModelRender::pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
|
||||
ModelRender::pickPrograms(batch, mode, translucentMesh, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
|
||||
args, locations);
|
||||
|
||||
|
||||
|
@ -395,9 +393,7 @@ void ModelMeshPartPayload::render(RenderArgs* args) const {
|
|||
|
||||
gpu::Batch& batch = *(args->_batch);
|
||||
auto mode = args->_renderMode;
|
||||
|
||||
auto alphaThreshold = args->_alphaThreshold; //translucent ? TRANSPARENT_ALPHA_THRESHOLD : OPAQUE_ALPHA_THRESHOLD; // FIX ME
|
||||
|
||||
|
||||
const FBXGeometry& geometry = _model->_geometry->getFBXGeometry();
|
||||
const std::vector<std::unique_ptr<NetworkMesh>>& networkMeshes = _model->_geometry->getMeshes();
|
||||
|
||||
|
@ -467,9 +463,12 @@ void ModelMeshPartPayload::render(RenderArgs* args) const {
|
|||
}
|
||||
|
||||
ModelRender::Locations* locations = nullptr;
|
||||
ModelRender::pickPrograms(batch, mode, translucentMesh, alphaThreshold, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
|
||||
ModelRender::pickPrograms(batch, mode, translucentMesh, hasLightmap, hasTangents, hasSpecular, isSkinned, wireframe,
|
||||
args, locations);
|
||||
|
||||
if (!locations) { // the pipeline could not be found
|
||||
return;
|
||||
}
|
||||
|
||||
// Bind the model transform and the skinCLusterMatrices if needed
|
||||
bindTransform(batch, locations);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue