Merge branch 'master' of github.com:highfidelity/hifi into grab-fixes

This commit is contained in:
Seth Alves 2016-05-01 17:28:20 -07:00
commit ec554c3c0b
673 changed files with 6387 additions and 1510 deletions

View file

@ -19,7 +19,7 @@ macro(GENERATE_INSTALLERS)
set(CPACK_PACKAGE_NAME ${_DISPLAY_NAME}) set(CPACK_PACKAGE_NAME ${_DISPLAY_NAME})
set(CPACK_PACKAGE_VENDOR "High Fidelity") set(CPACK_PACKAGE_VENDOR "High Fidelity")
set(CPACK_PACKAGE_VERSION ${BUILD_VERSION}) set(CPACK_PACKAGE_VERSION ${BUILD_VERSION})
set(CPACK_PACKAGE_FILE_NAME "HighFidelity-Alpha-${BUILD_VERSION}") set(CPACK_PACKAGE_FILE_NAME "HighFidelity-Beta-${BUILD_VERSION}")
set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME}) set(CPACK_NSIS_DISPLAY_NAME ${_DISPLAY_NAME})
set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME}) set(CPACK_NSIS_PACKAGE_NAME ${_DISPLAY_NAME})
set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME}) set(CPACK_PACKAGE_INSTALL_DIRECTORY ${_DISPLAY_NAME})

View file

@ -1,148 +0,0 @@
//
// clap.js
// examples
//
// Copyright 2014 High Fidelity, Inc.
//
// This sample script watches your hydra hands and makes clapping sound when they come close together fast,
// and also watches for the 'shift' key and claps when that key is pressed. Clapping multiple times by pressing
// the shift key again makes the animation and sound match your pace of clapping.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var clapAnimation = HIFI_PUBLIC_BUCKET + "animations/ClapAnimations/ClapHands_Standing.fbx";
var ANIMATION_FRAMES_PER_CLAP = 10.0;
var startEndFrames = [];
startEndFrames.push({ start: 0, end: 10});
startEndFrames.push({ start: 10, end: 20});
startEndFrames.push({ start: 20, end: 30});
startEndFrames.push({ start: 30, end: 40});
startEndFrames.push({ start: 41, end: 51});
startEndFrames.push({ start: 53, end: 0});
var lastClapFrame = 0;
var lastAnimFrame = 0;
var claps = [];
claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap1Rvb.wav"));
claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap2Rvb.wav"));
claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap3Rvb.wav"));
claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap4Rvb.wav"));
claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap5Rvb.wav"));
claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap6Rvb.wav"));
claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap7Rvb.wav"));
claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap8Rvb.wav"));
claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap9Rvb.wav"));
claps.push(SoundCache.getSound(HIFI_PUBLIC_BUCKET + "sounds/claps/BClap10Rvb.wav"));
var numberOfSounds = claps.length;
var clappingNow = false;
var collectedClicks = 0;
var clickStartTime, clickEndTime;
var clickClappingNow = false;
var CLAP_START_RATE = 15.0;
var clapRate = CLAP_START_RATE;
var startedTimer = false;
function maybePlaySound(deltaTime) {
// Set the location and other info for the sound to play
var animationDetails = MyAvatar.getAnimationDetails(clapAnimation);
var frame = Math.floor(animationDetails.frameIndex);
if (frame != lastAnimFrame) {
lastAnimFrame = frame;
}
for (var i = 0; i < startEndFrames.length; i++) {
if (frame == startEndFrames[i].start && (frame != lastClapFrame)) {
playClap(1.0, Camera.getPosition());
lastClapFrame = frame;
}
}
var palm1Position = MyAvatar.getLeftPalmPosition();
var palm2Position = MyAvatar.getRightPalmPosition();
var distanceBetween = Vec3.length(Vec3.subtract(palm1Position, palm2Position));
var palm1Velocity = Controller.getPoseValue(Controller.Standard.LeftHand).velocity;
var palm2Velocity = Controller.getPoseValue(Controller.Standard.RightHand).velocity;
var closingVelocity = Vec3.length(Vec3.subtract(palm1Velocity, palm2Velocity));
const CLAP_SPEED = 0.7;
const CLAP_DISTANCE = 0.15;
if ((closingVelocity > CLAP_SPEED) && (distanceBetween < CLAP_DISTANCE) && !clappingNow) {
var volume = closingVelocity / 2.0;
if (volume > 1.0) volume = 1.0;
playClap(volume, palm1Position);
clappingNow = true;
} else if (clappingNow && (distanceBetween > CLAP_DISTANCE * 1.2)) {
clappingNow = false;
}
}
function playClap(volume, position) {
var clip = Math.floor(Math.random() * numberOfSounds);
Audio.playSound(claps[clip], {
position: position,
volume: volume
});
}
var FASTEST_CLAP_INTERVAL = 150.0;
var SLOWEST_CLAP_INTERVAL = 750.0;
Controller.keyPressEvent.connect(function(event) {
if(event.text == "SHIFT") {
if (!clickClappingNow) {
clickClappingNow = true;
clickStartTime = new Date();
lastClapFrame = 0;
} else {
// start or adjust clapping speed based on the duration between clicks
clickEndTime = new Date();
var milliseconds = Math.max(clickEndTime - clickStartTime, FASTEST_CLAP_INTERVAL);
clickStartTime = new Date();
if (milliseconds < SLOWEST_CLAP_INTERVAL) {
clapRate = ANIMATION_FRAMES_PER_CLAP * (1000.0 / milliseconds);
playClap(1.0, Camera.getPosition());
MyAvatar.stopAnimation(clapAnimation);
MyAvatar.startAnimation(clapAnimation, clapRate, 1.0, true, false);
}
collectedClicks = collectedClicks + 1;
}
}
});
var CLAP_END_WAIT_MSECS = 300;
Controller.keyReleaseEvent.connect(function(event) {
if (event.text == "SHIFT") {
collectedClicks = 0;
if (!startedTimer) {
collectedClicks = 0;
Script.setTimeout(stopClapping, CLAP_END_WAIT_MSECS);
startedTimer = true;
}
}
});
function stopClapping() {
if (collectedClicks == 0) {
startedTimer = false;
MyAvatar.stopAnimation(clapAnimation);
clapRate = CLAP_START_RATE;
clickClappingNow = false;
} else {
startedTimer = false;
}
}
// Connect a call back that happens every frame
Script.update.connect(maybePlaySound);

View file

@ -1,68 +0,0 @@
// cowEntityScript.js
// examples/cows
//
// Created by Eric Levin on 3/25/16
// Copyright 2016 High Fidelity, Inc.
//
// This entity script handles the logic for untipping a cow after it collides with something
//
// 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;
_this.COLLISION_COOLDOWN_TIME = 5000;
this.preload = function(entityID) {
print("EBL Preload!!");
_this.entityID = entityID;
_this.mooSound = SoundCache.getSound("https://s3-us-west-1.amazonaws.com/hifi-content/eric/Sounds/moo.wav")
_this.mooSoundOptions = {volume: 0.7, loop: false};
_this.timeSinceLastCollision = 0;
_this.shouldUntipCow = true;
}
this.collisionWithEntity = function(myID, otherID, collisionInfo) {
if(_this.shouldUntipCow) {
Script.setTimeout(function() {
_this.untipCow();
_this.shouldUntipCow = true;
}, _this.COLLISION_COOLDOWN_TIME);
}
_this.shouldUntipCow = false;
}
this.untipCow = function() {
// keep yaw but reset pitch and roll
var cowProps = Entities.getEntityProperties(_this.entityID, ["rotation", "position"]);
var eulerRotation = Quat.safeEulerAngles(cowProps.rotation);
eulerRotation.x = 0;
eulerRotation.z = 0;
var newRotation = Quat.fromVec3Degrees(eulerRotation);
Entities.editEntity(_this.entityID, {
rotation: newRotation,
velocity: {x: 0, y: 0, z: 0},
angularVelocity: {x: 0, y: 0, z:0}
});
_this.mooSoundOptions.position = cowProps.position;
if (!_this.soundInjector) {
_this.soundInjector = Audio.playSound(_this.mooSound, _this.mooSoundOptions);
} else {
_this.soundInjector.setOptions(_this.mooSoundOptions);
_this.soundInjector.restart();
}
}
});

View file

@ -1,53 +0,0 @@
// cowSpawner.js
// examples/cows
//
// Created by Eric Levin on 3/25/16
// Copyright 2016 High Fidelity, Inc.
//
// This spawns a cow which will untip itself
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
var orientation = MyAvatar.orientation;
orientation = Quat.safeEulerAngles(orientation);
orientation.x = 0;
orientation = Quat.fromVec3Degrees(orientation);
var center = Vec3.sum(MyAvatar.getHeadPosition(), Vec3.multiply(2, Quat.getFront(orientation)));
var SCRIPT_URL = Script.resolvePath("cowEntityScript.js?");
var cow = Entities.addEntity({
type: "Model",
modelURL: "http://hifi-content.s3.amazonaws.com/DomainContent/production/cow/newMooCow.fbx",
name: "playa_model_throwinCow",
position: center,
animation: {
currentFrame: 278,
running: true,
url: "http://hifi-content.s3.amazonaws.com/DomainContent/Junkyard/Playa/newMooCow.fbx"
},
dimensions: {
x: 0.739,
y: 1.613,
z: 2.529
},
dynamic: true,
gravity: {
x: 0,
y: -5,
z: 0
},
shapeType: "box",
script: SCRIPT_URL,
userData: "{\"grabbableKey\":{\"grabbable\":true}}"
});
function cleanup() {
Entities.deleteEntity(cow);
}
Script.scriptEnding.connect(cleanup);

View file

@ -1,22 +0,0 @@
//
// defaultScripts.js
// examples
//
// Copyright 2014 High Fidelity, Inc.
//
// Distributed under the Apache License, Version 2.0.
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
Script.load("away.js");
Script.load("progress.js");
Script.load("edit.js");
Script.load("examples.js");
Script.load("selectAudioDevice.js");
Script.load("notifications.js");
Script.load("controllers/handControllerGrab.js");
Script.load("controllers/squeezeHands.js");
Script.load("grab.js");
Script.load("directory.js");
Script.load("dialTone.js");
Script.load("depthReticle.js");

View file

@ -1,477 +0,0 @@
//
// pistol.js
// examples
//
// Created by Eric Levin on 11/12/2015
// Copyright 2013 High Fidelity, Inc.
//
// This is an example script that turns the hydra controllers and mouse into a entity gun.
// It reads the controller, watches for trigger pulls, and adds a force to any entity it hits
// 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("../../../libraries/constants.js");
var GUN_FORCE =20;
Messages.sendMessage('Hifi-Hand-Disabler', "both");
var gameName = "Kill All The Rats!"
// var HOST = "localhost:5000"
var HOST = "desolate-bastion-1742.herokuapp.com";
var socketClient = new WebSocket("ws://" + HOST);
var username = GlobalServices.username;
var currentScore = 0;
function score() {
currentScore++;
socketClient.send(JSON.stringify({
username: username,
score: currentScore,
gameName: gameName
}))
}
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
var fireSound = SoundCache.getSound("https://s3.amazonaws.com/hifi-public/sounds/Guns/GUN-SHOT2.raw");
var LASER_LENGTH = 100;
var LASER_WIDTH = 2;
var POSE_CONTROLS = [Controller.Standard.LeftHand, Controller.Standard.RightHand];
var TRIGGER_CONTROLS = [Controller.Standard.LT, Controller.Standard.RT];
var MIN_THROWER_DELAY = 1000;
var MAX_THROWER_DELAY = 1000;
var RELOAD_INTERVAL = 5;
var GUN_MODEL = HIFI_PUBLIC_BUCKET + "cozza13/gun/m1911-handgun+1.fbx?v=4";
var BULLET_VELOCITY = 10.0;
var GUN_OFFSETS = [{
x: 0.04,
y: 0.26,
z: 0.04
}, {
x: 0.04,
y: 0.26,
z: 0.04
}];
var GUN_ORIENTATIONS = [Quat.fromPitchYawRollDegrees(0, 90, 90), Quat.fromPitchYawRollDegrees(0, -90, 270)];
//x -> y
//y -> z
// z -> x
var BARREL_OFFSETS = [ {
x: -0.12,
y: 0.12,
z: 0.04
}, {
x: 0.12,
y: 0.12,
z: 0.04
} ];
var pointers = [];
pointers.push(Overlays.addOverlay("line3d", {
start: ZERO_VECTOR,
end: ZERO_VECTOR,
color: COLORS.RED,
alpha: 1,
visible: true,
lineWidth: LASER_WIDTH
}));
pointers.push(Overlays.addOverlay("line3d", {
start: ZERO_VECTOR,
end: ZERO_VECTOR,
color: COLORS.RED,
alpha: 1,
visible: true,
lineWidth: LASER_WIDTH
}));
var mapping = Controller.newMapping();
var validPoses = [false, false];
var barrelVectors = [0, 0];
var barrelTips = [0, 0];
// If enabled, anything can be shot, otherwise, an entity needs to have "isShootable" set in its userData
var shootAnything = true;
function update(deltaTime) {
// FIXME we should also expose MyAvatar.handPoses[2], MyAvatar.tipPoses[2]
var tipPoses = [MyAvatar.leftHandTipPose, MyAvatar.rightHandTipPose];
for (var side = 0; side < 2; side++) {
// First check if the controller is valid
var controllerPose = Controller.getPoseValue(POSE_CONTROLS[side]);
validPoses[side] = controllerPose.valid;
// Need to adjust the laser
var tipPose = tipPoses[side];
var handRotation = tipPoses[side].rotation;
var barrelOffset = Vec3.multiplyQbyV(handRotation, BARREL_OFFSETS[side]);
barrelTips[side] = Vec3.sum(tipPose.translation, barrelOffset);
barrelVectors[side] = Vec3.multiplyQbyV(handRotation, {
x: 0,
y: 1,
z: 0
});
var laserTip = Vec3.sum(Vec3.multiply(LASER_LENGTH, barrelVectors[side]), barrelTips[side]);
// Update Lasers
Overlays.editOverlay(pointers[side], {
start: barrelTips[side],
end: laserTip,
alpha: 1,
});
}
}
function displayPointer(side) {
Overlays.editOverlay(pointers[side], {
visible: true
});
}
function hidePointer(side) {
Overlays.editOverlay(pointers[side], {
visible: false
});
}
function fire(side, value) {
if (value == 0) {
return;
}
Audio.playSound(fireSound, {
position: barrelTips[side],
volume: 0.5
});
var shotDirection = Vec3.normalize(barrelVectors[side]);
var pickRay = {
origin: barrelTips[side],
direction: shotDirection
};
createMuzzleFlash(barrelTips[side]);
var intersection = Entities.findRayIntersectionBlocking(pickRay, true);
if (intersection.intersects) {
Script.setTimeout(function() {
createEntityHitEffect(intersection.intersection);
if (shootAnything && intersection.properties.dynamic === 1) {
// Any dynamic entity can be shot
Entities.editEntity(intersection.entityID, {
velocity: Vec3.multiply(shotDirection, GUN_FORCE)
});
}
if (intersection.properties.name === "rat") {
score();
createBloodSplatter(intersection.intersection);
Entities.deleteEntity(intersection.entityID);
}
//Attempt to call entity method's shot method
var forceDirection = JSON.stringify({
forceDirection: shotDirection
});
Entities.callEntityMethod(intersection.entityID, 'onShot', [forceDirection]);
}, 0);
}
}
function scriptEnding() {
Messages.sendMessage('Hifi-Hand-Disabler', 'none');
mapping.disable();
for (var i = 0; i < pointers.length; ++i) {
Overlays.deleteOverlay(pointers[i]);
}
MyAvatar.detachOne(GUN_MODEL);
MyAvatar.detachOne(GUN_MODEL);
clearPose();
}
MyAvatar.attach(GUN_MODEL, "LeftHand", GUN_OFFSETS[0], GUN_ORIENTATIONS[0], 0.40);
MyAvatar.attach(GUN_MODEL, "RightHand", GUN_OFFSETS[1], GUN_ORIENTATIONS[1], 0.40);
function showPointer(side) {
Overlays.editOverlay(pointers[side], {
visible: true
});
}
mapping.from(Controller.Standard.LT).hysteresis(0.0, 0.5).to(function(value) {
fire(0, value);
});
mapping.from(Controller.Standard.RT).hysteresis(0.0, 0.5).to(function(value) {
fire(1, value);
});
mapping.enable();
Script.scriptEnding.connect(scriptEnding);
Script.update.connect(update);
function createEntityHitEffect(position) {
var flash = Entities.addEntity({
type: "ParticleEffect",
position: position,
lifetime: 4,
"name": "Flash Emitter",
"color": {
red: 228,
green: 128,
blue: 12
},
"maxParticles": 1000,
"lifespan": 0.15,
"emitRate": 1000,
"emitSpeed": 1,
"speedSpread": 0,
"emitOrientation": {
"x": -0.4,
"y": 1,
"z": -0.2,
"w": 0.7071068286895752
},
"emitDimensions": {
"x": 0,
"y": 0,
"z": 0
},
"polarStart": 0,
"polarFinish": Math.PI,
"azimuthStart": -3.1415927410125732,
"azimuthFinish": 2,
"emitAcceleration": {
"x": 0,
"y": 0,
"z": 0
},
"accelerationSpread": {
"x": 0,
"y": 0,
"z": 0
},
"particleRadius": 0.03,
"radiusSpread": 0.02,
"radiusStart": 0.02,
"radiusFinish": 0.03,
"colorSpread": {
red: 100,
green: 100,
blue: 20
},
"alpha": 1,
"alphaSpread": 0,
"alphaStart": 0,
"alphaFinish": 0,
"additiveBlending": true,
"textures": "http://ericrius1.github.io/PartiArt/assets/star.png"
});
Script.setTimeout(function() {
Entities.editEntity(flash, {
isEmitting: false
});
}, 100);
}
function createBloodSplatter(position) {
var splatter = Entities.addEntity({
type: "ParticleEffect",
position: position,
lifetime: 4,
"name": "Blood Splatter",
"color": {
red: 230,
green: 2,
blue: 30
},
"maxParticles": 1000,
"lifespan": 0.3,
"emitRate": 1000,
"emitSpeed": 0.5,
"speedSpread": 0,
"emitOrientation": {
"x": -0.4,
"y": 1,
"z": -0.2,
"w": 0.7071068286895752
},
"emitDimensions": {
"x": 0,
"y": 0,
"z": 0
},
"polarStart": 0,
"polarFinish": Math.PI,
"azimuthStart": -3.1415927410125732,
"azimuthFinish": 2,
"emitAcceleration": {
"x": 0,
"y": -5,
"z": 0
},
"accelerationSpread": {
"x": 0,
"y": 0,
"z": 0
},
"particleRadius": 0.05,
"radiusSpread": 0.03,
"radiusStart": 0.05,
"radiusFinish": 0.05,
"colorSpread": {
red: 40,
green: 0,
blue: 30
},
"alpha": 1,
"alphaSpread": 0,
"alphaStart": 0,
"alphaFinish": 0,
"textures": "http://ericrius1.github.io/PartiArt/assets/star.png"
});
Script.setTimeout(function() {
Entities.editEntity(splatter, {
isEmitting: false
});
}, 100)
}
function createMuzzleFlash(position) {
var smoke = Entities.addEntity({
type: "ParticleEffect",
position: position,
lifetime: 1,
"name": "Smoke Hit Emitter",
"maxParticles": 1000,
"lifespan": 4,
"emitRate": 20,
emitSpeed: 0,
"speedSpread": 0,
"emitDimensions": {
"x": 0,
"y": 0,
"z": 0
},
"polarStart": 0,
"polarFinish": 0,
"azimuthStart": -3.1415927410125732,
"azimuthFinish": 3.14,
"emitAcceleration": {
"x": 0,
"y": 0.5,
"z": 0
},
"accelerationSpread": {
"x": .2,
"y": 0,
"z": .2
},
"radiusSpread": .04,
"particleRadius": 0.07,
"radiusStart": 0.07,
"radiusFinish": 0.07,
"alpha": 0.7,
"alphaSpread": 0,
"alphaStart": 0,
"alphaFinish": 0,
"additiveBlending": 0,
"textures": "https://hifi-public.s3.amazonaws.com/alan/Particles/Particle-Sprite-Smoke-1.png"
});
Script.setTimeout(function() {
Entities.editEntity(smoke, {
isEmitting: false
});
}, 100);
var flash = Entities.addEntity({
type: "ParticleEffect",
position: position,
lifetime: 4,
"name": "Muzzle Flash",
"color": {
red: 228,
green: 128,
blue: 12
},
"maxParticles": 1000,
"lifespan": 0.1,
"emitRate": 1000,
"emitSpeed": 0.5,
"speedSpread": 0,
"emitOrientation": {
"x": -0.4,
"y": 1,
"z": -0.2,
"w": 0.7071068286895752
},
"emitDimensions": {
"x": 0,
"y": 0,
"z": 0
},
"polarStart": 0,
"polarFinish": Math.PI,
"azimuthStart": -3.1415927410125732,
"azimuthFinish": 2,
"emitAcceleration": {
"x": 0,
"y": 0,
"z": 0
},
"accelerationSpread": {
"x": 0,
"y": 0,
"z": 0
},
"particleRadius": 0.05,
"radiusSpread": 0.01,
"radiusStart": 0.05,
"radiusFinish": 0.05,
"colorSpread": {
red: 100,
green: 100,
blue: 20
},
"alpha": 1,
"alphaSpread": 0,
"alphaStart": 0,
"alphaFinish": 0,
"additiveBlending": true,
"textures": "http://ericrius1.github.io/PartiArt/assets/star.png"
});
Script.setTimeout(function() {
Entities.editEntity(flash, {
isEmitting: false
});
}, 100)
}

View file

@ -1,37 +0,0 @@
//
// Rat.js
// examples/toybox/entityScripts
//
// Created by Eric Levin on11/11/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
/*global print, MyAvatar, Entities, AnimationCache, SoundCache, Scene, Camera, Overlays, Audio, HMD, AvatarList, AvatarManager, Controller, UndoStack, Window, Account, GlobalServices, Script, ScriptDiscoveryService, LODManager, Menu, Vec3, Quat, AudioDevice, Paths, Clipboard, Settings, XMLHttpRequest, randFloat, randInt */
(function() {
var scriptURL = Script.resolvePath('pistol.js');
var _this;
PistolScriptSpawner = function() {
_this = this;
this.forceMultiplier = 1;
};
PistolScriptSpawner.prototype = {
enterEntity: function() {
Script.load(scriptURL);
},
preload: function(entityID) {
this.entityID = entityID;
},
};
// entity scripts always need to return a newly constructed object of our type
return new PistolScriptSpawner();
});

View file

@ -243,7 +243,7 @@ else (APPLE)
"${PROJECT_SOURCE_DIR}/resources" "${PROJECT_SOURCE_DIR}/resources"
$<TARGET_FILE_DIR:${TARGET_NAME}>/resources $<TARGET_FILE_DIR:${TARGET_NAME}>/resources
COMMAND "${CMAKE_COMMAND}" -E copy_directory COMMAND "${CMAKE_COMMAND}" -E copy_directory
"${CMAKE_SOURCE_DIR}/examples" "${CMAKE_SOURCE_DIR}/scripts"
$<TARGET_FILE_DIR:${TARGET_NAME}>/scripts $<TARGET_FILE_DIR:${TARGET_NAME}>/scripts
) )
@ -269,7 +269,7 @@ endif (APPLE)
if (SCRIPTS_INSTALL_DIR) if (SCRIPTS_INSTALL_DIR)
# setup install of scripts beside interface executable # setup install of scripts beside interface executable
install( install(
DIRECTORY "${CMAKE_SOURCE_DIR}/examples/" DIRECTORY "${CMAKE_SOURCE_DIR}/scripts/"
DESTINATION ${SCRIPTS_INSTALL_DIR}/scripts DESTINATION ${SCRIPTS_INSTALL_DIR}/scripts
COMPONENT ${CLIENT_COMPONENT} COMPONENT ${CLIENT_COMPONENT}
) )

View file

@ -24,7 +24,6 @@ Window {
title: "Asset Browser" title: "Asset Browser"
resizable: true resizable: true
destroyOnInvisible: true destroyOnInvisible: true
x: 40; y: 40
implicitWidth: 384; implicitHeight: 640 implicitWidth: 384; implicitHeight: 640
minSize: Qt.vector2d(200, 300) minSize: Qt.vector2d(200, 300)

View file

@ -25,7 +25,7 @@ Hifi.AvatarInputs {
readonly property int iconPadding: 5 readonly property int iconPadding: 5
readonly property bool shouldReposition: true readonly property bool shouldReposition: true
Settings { Settings {
category: "Overlay.AvatarInputs" category: "Overlay.AvatarInputs"
property alias x: root.x property alias x: root.x

View file

@ -22,4 +22,19 @@ Windows.Window {
url: infoView.url url: infoView.url
} }
} }
Component.onCompleted: {
centerWindow(root);
}
onVisibleChanged: {
if (visible) {
centerWindow(root);
}
}
function centerWindow() {
desktop.centerOnVisible(root);
}
} }

View file

@ -21,7 +21,9 @@ FocusScope {
objectName: "desktop" objectName: "desktop"
anchors.fill: parent anchors.fill: parent
property rect recommendedRect: rect(0,0,0,0); readonly property int invalid_position: -9999;
property rect recommendedRect: Qt.rect(0,0,0,0);
property var expectedChildren;
onHeightChanged: d.handleSizeChanged(); onHeightChanged: d.handleSizeChanged();
@ -55,13 +57,18 @@ FocusScope {
function handleSizeChanged() { function handleSizeChanged() {
var oldRecommendedRect = recommendedRect; var oldRecommendedRect = recommendedRect;
var newRecommendedRectJS = Controller.getRecommendedOverlayRect(); var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedOverlayRect();
var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y, var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y,
newRecommendedRectJS.width, newRecommendedRectJS.width,
newRecommendedRectJS.height); newRecommendedRectJS.height);
if (oldRecommendedRect != Qt.rect(0,0,0,0) var oldChildren = expectedChildren;
&& oldRecommendedRect != newRecommendedRect) { var newChildren = d.getRepositionChildren();
if (oldRecommendedRect != Qt.rect(0,0,0,0)
&& (oldRecommendedRect != newRecommendedRect
|| oldChildren != newChildren)
) {
expectedChildren = newChildren;
d.repositionAll(); d.repositionAll();
} }
recommendedRect = newRecommendedRect; recommendedRect = newRecommendedRect;
@ -279,13 +286,56 @@ FocusScope {
targetWindow.focus = true; targetWindow.focus = true;
} }
showDesktop();
}
function centerOnVisible(item) {
var targetWindow = d.getDesktopWindow(item);
if (!targetWindow) {
console.warn("Could not find top level window for " + item);
return;
}
if (typeof Controller === "undefined") {
console.warn("Controller not yet available... can't center");
return;
}
var newRecommendedRectJS = (typeof Controller === "undefined") ? Qt.rect(0,0,0,0) : Controller.getRecommendedOverlayRect();
var newRecommendedRect = Qt.rect(newRecommendedRectJS.x, newRecommendedRectJS.y,
newRecommendedRectJS.width,
newRecommendedRectJS.height);
var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height };
var newX = newRecommendedRect.x + ((newRecommendedRect.width - targetWindow.width) / 2);
var newY = newRecommendedRect.y + ((newRecommendedRect.height - targetWindow.height) / 2);
targetWindow.x = newX;
targetWindow.y = newY;
// If we've noticed that our recommended desktop rect has changed, record that change here.
if (recommendedRect != newRecommendedRect) {
recommendedRect = newRecommendedRect;
}
}
function repositionOnVisible(item) {
var targetWindow = d.getDesktopWindow(item);
if (!targetWindow) {
console.warn("Could not find top level window for " + item);
return;
}
if (typeof Controller === "undefined") {
console.warn("Controller not yet available... can't reposition targetWindow:" + targetWindow);
return;
}
var oldRecommendedRect = recommendedRect; var oldRecommendedRect = recommendedRect;
var oldRecommendedDimmensions = { x: oldRecommendedRect.width, y: oldRecommendedRect.height }; var oldRecommendedDimmensions = { x: oldRecommendedRect.width, y: oldRecommendedRect.height };
var newRecommendedRect = Controller.getRecommendedOverlayRect(); var newRecommendedRect = Controller.getRecommendedOverlayRect();
var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height }; var newRecommendedDimmensions = { x: newRecommendedRect.width, y: newRecommendedRect.height };
repositionWindow(targetWindow, false, oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions); repositionWindow(targetWindow, false, oldRecommendedRect, oldRecommendedDimmensions, newRecommendedRect, newRecommendedDimmensions);
showDesktop();
} }
function repositionWindow(targetWindow, forceReposition, function repositionWindow(targetWindow, forceReposition,
@ -324,10 +374,8 @@ FocusScope {
} }
var fractionX = Utils.clamp(originRelativeX / oldRecommendedDimmensions.x, 0, 1); var fractionX = Utils.clamp(originRelativeX / oldRecommendedDimmensions.x, 0, 1);
var fractionY = Utils.clamp(originRelativeY / oldRecommendedDimmensions.y, 0, 1); var fractionY = Utils.clamp(originRelativeY / oldRecommendedDimmensions.y, 0, 1);
var newX = (fractionX * newRecommendedDimmensions.x) + newRecommendedRect.x; var newX = (fractionX * newRecommendedDimmensions.x) + newRecommendedRect.x;
var newY = (fractionY * newRecommendedDimmensions.y) + newRecommendedRect.y; var newY = (fractionY * newRecommendedDimmensions.y) + newRecommendedRect.y;
newPosition = Qt.vector2d(newX, newY); newPosition = Qt.vector2d(newX, newY);
} }
targetWindow.x = newPosition.x; targetWindow.x = newPosition.x;

View file

@ -23,7 +23,6 @@ Window {
title: "Running Scripts" title: "Running Scripts"
resizable: true resizable: true
destroyOnInvisible: true destroyOnInvisible: true
x: 40; y: 40
implicitWidth: 400 implicitWidth: 400
implicitHeight: isHMD ? 695 : 728 implicitHeight: isHMD ? 695 : 728
minSize: Qt.vector2d(200, 300) minSize: Qt.vector2d(200, 300)

View file

@ -31,7 +31,7 @@ Fadable {
// decorations can extend outside it. // decorations can extend outside it.
implicitHeight: content ? content.height : 0 implicitHeight: content ? content.height : 0
implicitWidth: content ? content.width : 0 implicitWidth: content ? content.width : 0
x: -1; y: -1 x: desktop.invalid_position; y: desktop.invalid_position;
enabled: visible enabled: visible
signal windowDestroyed(); signal windowDestroyed();
@ -252,6 +252,7 @@ Fadable {
window.parentChanged.connect(raise); window.parentChanged.connect(raise);
raise(); raise();
setDefaultFocus(); setDefaultFocus();
centerOrReposition();
} }
Component.onDestruction: { Component.onDestruction: {
window.parentChanged.disconnect(raise); // Prevent warning on shutdown window.parentChanged.disconnect(raise); // Prevent warning on shutdown
@ -267,6 +268,18 @@ Fadable {
raise(); raise();
} }
enabled = visible enabled = visible
if (visible && parent) {
centerOrReposition();
}
}
function centerOrReposition() {
if (x == desktop.invalid_position && y == desktop.invalid_position) {
desktop.centerOnVisible(window);
} else {
desktop.repositionOnVisible(window);
}
} }
function raise() { function raise() {

View file

@ -19,7 +19,7 @@ Fadable {
// decorations can extend outside it. // decorations can extend outside it.
implicitHeight: content ? content.height : 0 implicitHeight: content ? content.height : 0
implicitWidth: content ? content.width : 0 implicitWidth: content ? content.width : 0
x: -1; y: -1 x: desktop.invalid_position; y: desktop.invalid_position;
enabled: visible enabled: visible
signal windowDestroyed(); signal windowDestroyed();
@ -117,12 +117,21 @@ Fadable {
Component.onCompleted: { Component.onCompleted: {
window.parentChanged.connect(raise); window.parentChanged.connect(raise);
raise(); raise();
centerOrReposition();
} }
Component.onDestruction: { Component.onDestruction: {
window.parentChanged.disconnect(raise); // Prevent warning on shutdown window.parentChanged.disconnect(raise); // Prevent warning on shutdown
windowDestroyed(); windowDestroyed();
} }
function centerOrReposition() {
if (x == desktop.invalid_position && y == desktop.invalid_position) {
desktop.centerOnVisible(window);
} else {
desktop.repositionOnVisible(window);
}
}
onVisibleChanged: { onVisibleChanged: {
if (!visible && destroyOnInvisible) { if (!visible && destroyOnInvisible) {
destroy(); destroy();
@ -132,6 +141,10 @@ Fadable {
raise(); raise();
} }
enabled = visible enabled = visible
if (visible && parent) {
centerOrReposition();
}
} }
function raise() { function raise() {

View file

@ -4315,6 +4315,7 @@ void Application::nodeKilled(SharedNodePointer node) {
} }
} }
} }
void Application::trackIncomingOctreePacket(ReceivedMessage& message, SharedNodePointer sendingNode, bool wasStatsPacket) { void Application::trackIncomingOctreePacket(ReceivedMessage& message, SharedNodePointer sendingNode, bool wasStatsPacket) {
// Attempt to identify the sender from its address. // Attempt to identify the sender from its address.
if (sendingNode) { if (sendingNode) {

View file

@ -235,7 +235,12 @@ QByteArray MyAvatar::toByteArray(bool cullSmallChanges, bool sendAll) {
return AvatarData::toByteArray(cullSmallChanges, sendAll); return AvatarData::toByteArray(cullSmallChanges, sendAll);
} }
void MyAvatar::reset(bool andReload) { void MyAvatar::reset(bool andRecenter) {
if (QThread::currentThread() != thread()) {
QMetaObject::invokeMethod(this, "reset", Q_ARG(bool, andRecenter));
return;
}
// Reset dynamic state. // Reset dynamic state.
_wasPushing = _isPushing = _isBraking = false; _wasPushing = _isPushing = _isBraking = false;
@ -245,7 +250,7 @@ void MyAvatar::reset(bool andReload) {
_targetVelocity = glm::vec3(0.0f); _targetVelocity = glm::vec3(0.0f);
setThrust(glm::vec3(0.0f)); setThrust(glm::vec3(0.0f));
if (andReload) { if (andRecenter) {
// derive the desired body orientation from the *old* hmd orientation, before the sensor reset. // derive the desired body orientation from the *old* hmd orientation, before the sensor reset.
auto newBodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation.. auto newBodySensorMatrix = deriveBodyFromHMDSensor(); // Based on current cached HMD position/rotation..
@ -911,7 +916,8 @@ void MyAvatar::updateLookAtTargetAvatar() {
avatar->setIsLookAtTarget(false); avatar->setIsLookAtTarget(false);
if (!avatar->isMyAvatar() && avatar->isInitialized() && if (!avatar->isMyAvatar() && avatar->isInitialized() &&
(distanceTo < GREATEST_LOOKING_AT_DISTANCE * getUniformScale())) { (distanceTo < GREATEST_LOOKING_AT_DISTANCE * getUniformScale())) {
float angleTo = glm::angle(lookForward, glm::normalize(avatar->getHead()->getEyePosition() - getHead()->getEyePosition())); float radius = glm::length(avatar->getHead()->getEyePosition() - avatar->getHead()->getRightEyePosition());
float angleTo = coneSphereAngle(getHead()->getEyePosition(), lookForward, avatar->getHead()->getEyePosition(), radius);
if (angleTo < (smallestAngleTo * (isCurrentTarget ? KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR : 1.0f))) { if (angleTo < (smallestAngleTo * (isCurrentTarget ? KEEP_LOOKING_AT_CURRENT_ANGLE_FACTOR : 1.0f))) {
_lookAtTargetAvatar = avatarPointer; _lookAtTargetAvatar = avatarPointer;
_targetAvatarPosition = avatarPointer->getPosition(); _targetAvatarPosition = avatarPointer->getPosition();

View file

@ -93,7 +93,7 @@ public:
AudioListenerMode getAudioListenerModeCamera() const { return FROM_CAMERA; } AudioListenerMode getAudioListenerModeCamera() const { return FROM_CAMERA; }
AudioListenerMode getAudioListenerModeCustom() const { return CUSTOM; } AudioListenerMode getAudioListenerModeCustom() const { return CUSTOM; }
void reset(bool andReload = false); Q_INVOKABLE void reset(bool andRecenter = false);
void update(float deltaTime); void update(float deltaTime);
void preRender(RenderArgs* renderArgs); void preRender(RenderArgs* renderArgs);

View file

@ -292,6 +292,8 @@ void AssetMappingModel::refresh() {
} else { } else {
emit errorGettingMappings(request->getErrorString()); emit errorGettingMappings(request->getErrorString());
} }
request->deleteLater();
}); });
request->start(); request->start();

View file

@ -110,7 +110,14 @@ void Text3DOverlay::render(RenderArgs* args) {
glm::vec4 textColor = { _color.red / MAX_COLOR, _color.green / MAX_COLOR, glm::vec4 textColor = { _color.red / MAX_COLOR, _color.green / MAX_COLOR,
_color.blue / MAX_COLOR, getTextAlpha() }; _color.blue / MAX_COLOR, getTextAlpha() };
// FIXME: Factor out textRenderer so that Text3DOverlay overlay parts can be grouped by pipeline
// for a gpu performance increase. Currently,
// Text renderer sets its own pipeline,
_textRenderer->draw(batch, 0, 0, _text, textColor, glm::vec2(-1.0f), getDrawInFront()); _textRenderer->draw(batch, 0, 0, _text, textColor, glm::vec2(-1.0f), getDrawInFront());
// so before we continue, we must reset the pipeline
batch.setPipeline(args->_pipeline->pipeline);
args->_pipeline->prepare(batch);
} }
const render::ShapeKey Text3DOverlay::getShapeKey() { const render::ShapeKey Text3DOverlay::getShapeKey() {

View file

@ -339,15 +339,16 @@ void RenderableModelEntityItem::updateModelBounds() {
return; return;
} }
bool movingOrAnimating = isMovingRelativeToParent() || isAnimatingSomething(); bool movingOrAnimating = isMovingRelativeToParent() || isAnimatingSomething();
glm::vec3 dimensions = getDimensions();
if ((movingOrAnimating || if ((movingOrAnimating ||
_needsInitialSimulation || _needsInitialSimulation ||
_needsJointSimulation || _needsJointSimulation ||
_model->getTranslation() != getPosition() || _model->getTranslation() != getPosition() ||
_model->getScaleToFitDimensions() != getDimensions() || _model->getScaleToFitDimensions() != dimensions ||
_model->getRotation() != getRotation() || _model->getRotation() != getRotation() ||
_model->getRegistrationPoint() != getRegistrationPoint()) _model->getRegistrationPoint() != getRegistrationPoint())
&& _model->isActive() && _dimensionsInitialized) { && _model->isActive() && _dimensionsInitialized) {
_model->setScaleToFit(true, getDimensions()); _model->setScaleToFit(true, dimensions);
_model->setSnapModelToRegistrationPoint(true, getRegistrationPoint()); _model->setSnapModelToRegistrationPoint(true, getRegistrationPoint());
_model->setRotation(getRotation()); _model->setRotation(getRotation());
_model->setTranslation(getPosition()); _model->setTranslation(getPosition());
@ -518,6 +519,7 @@ void RenderableModelEntityItem::update(const quint64& now) {
if (!_dimensionsInitialized && _model && _model->isActive()) { if (!_dimensionsInitialized && _model && _model->isActive()) {
if (_model->isLoaded()) { if (_model->isLoaded()) {
EntityItemProperties properties; EntityItemProperties properties;
properties.setLastEdited(usecTimestampNow()); // we must set the edit time since we're editing it
auto extents = _model->getMeshExtents(); auto extents = _model->getMeshExtents();
properties.setDimensions(extents.maximum - extents.minimum); properties.setDimensions(extents.maximum - extents.minimum);
qCDebug(entitiesrenderer) << "Autoresizing:" << (!getName().isEmpty() ? getName() : getModelURL()); qCDebug(entitiesrenderer) << "Autoresizing:" << (!getName().isEmpty() ? getName() : getModelURL());

View file

@ -206,13 +206,14 @@ glm::mat4 RenderablePolyVoxEntityItem::voxelToLocalMatrix() const {
voxelVolumeSize = _voxelVolumeSize; voxelVolumeSize = _voxelVolumeSize;
}); });
glm::vec3 scale = getDimensions() / voxelVolumeSize; // meters / voxel-units glm::vec3 dimensions = getDimensions();
glm::vec3 scale = dimensions / voxelVolumeSize; // meters / voxel-units
bool success; // TODO -- Does this actually have to happen in world space? bool success; // TODO -- Does this actually have to happen in world space?
glm::vec3 center = getCenterPosition(success); // this handles registrationPoint changes glm::vec3 center = getCenterPosition(success); // this handles registrationPoint changes
glm::vec3 position = getPosition(success); glm::vec3 position = getPosition(success);
glm::vec3 positionToCenter = center - position; glm::vec3 positionToCenter = center - position;
positionToCenter -= getDimensions() * Vectors::HALF - getSurfacePositionAdjustment(); positionToCenter -= dimensions * Vectors::HALF - getSurfacePositionAdjustment();
glm::mat4 centerToCorner = glm::translate(glm::mat4(), positionToCenter); glm::mat4 centerToCorner = glm::translate(glm::mat4(), positionToCenter);
glm::mat4 scaled = glm::scale(centerToCorner, scale); glm::mat4 scaled = glm::scale(centerToCorner, scale);
return scaled; return scaled;
@ -445,7 +446,8 @@ bool RenderablePolyVoxEntityItem::findDetailedRayIntersection(const glm::vec3& o
// the PolyVox ray intersection code requires a near and far point. // the PolyVox ray intersection code requires a near and far point.
// set ray cast length to long enough to cover all of the voxel space // set ray cast length to long enough to cover all of the voxel space
float distanceToEntity = glm::distance(origin, getPosition()); float distanceToEntity = glm::distance(origin, getPosition());
float largestDimension = glm::max(getDimensions().x, getDimensions().y, getDimensions().z) * 2.0f; glm::vec3 dimensions = getDimensions();
float largestDimension = glm::max(dimensions.x, dimensions.y, dimensions.z) * 2.0f;
glm::vec3 farPoint = origin + normDirection * (distanceToEntity + largestDimension); glm::vec3 farPoint = origin + normDirection * (distanceToEntity + largestDimension);
glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f); glm::vec4 originInVoxel = wtvMatrix * glm::vec4(origin, 1.0f);

View file

@ -119,12 +119,13 @@ bool RenderableWebEntityItem::buildWebSurface(EntityTreeRenderer* renderer) {
// Map the intersection point to an actual offscreen pixel // Map the intersection point to an actual offscreen pixel
glm::vec3 point = intersection.intersection; glm::vec3 point = intersection.intersection;
glm::vec3 dimensions = getDimensions();
point -= getPosition(); point -= getPosition();
point = glm::inverse(getRotation()) * point; point = glm::inverse(getRotation()) * point;
point /= getDimensions(); point /= dimensions;
point += 0.5f; point += 0.5f;
point.y = 1.0f - point.y; point.y = 1.0f - point.y;
point *= getDimensions() * METERS_TO_INCHES * DPI; point *= dimensions * (METERS_TO_INCHES * DPI);
if (event->button() == Qt::MouseButton::LeftButton) { if (event->button() == Qt::MouseButton::LeftButton) {
if (event->type() == QEvent::MouseButtonPress) { if (event->type() == QEvent::MouseButtonPress) {

View file

@ -781,7 +781,8 @@ void EntityItem::adjustEditPacketForClockSkew(QByteArray& buffer, qint64 clockSk
} }
float EntityItem::computeMass() const { float EntityItem::computeMass() const {
return _density * _volumeMultiplier * getDimensions().x * getDimensions().y * getDimensions().z; glm::vec3 dimensions = getDimensions();
return _density * _volumeMultiplier * dimensions.x * dimensions.y * dimensions.z;
} }
void EntityItem::setDensity(float density) { void EntityItem::setDensity(float density) {
@ -801,7 +802,8 @@ void EntityItem::setMass(float mass) {
// we must protect the density range to help maintain stability of physics simulation // we must protect the density range to help maintain stability of physics simulation
// therefore this method might not accept the mass that is supplied. // therefore this method might not accept the mass that is supplied.
float volume = _volumeMultiplier * getDimensions().x * getDimensions().y * getDimensions().z; glm::vec3 dimensions = getDimensions();
float volume = _volumeMultiplier * dimensions.x * dimensions.y * dimensions.z;
// compute new density // compute new density
const float MIN_VOLUME = 1.0e-6f; // 0.001mm^3 const float MIN_VOLUME = 1.0e-6f; // 0.001mm^3
@ -1222,11 +1224,13 @@ AACube EntityItem::getMaximumAACube(bool& success) const {
// * we know that the position is the center of rotation // * we know that the position is the center of rotation
glm::vec3 centerOfRotation = getPosition(success); // also where _registration point is glm::vec3 centerOfRotation = getPosition(success); // also where _registration point is
if (success) { if (success) {
_recalcMaxAACube = false;
// * we know that the registration point is the center of rotation // * we know that the registration point is the center of rotation
// * we can calculate the length of the furthest extent from the registration point // * we can calculate the length of the furthest extent from the registration point
// as the dimensions * max (registrationPoint, (1.0,1.0,1.0) - registrationPoint) // as the dimensions * max (registrationPoint, (1.0,1.0,1.0) - registrationPoint)
glm::vec3 registrationPoint = (getDimensions() * getRegistrationPoint()); glm::vec3 dimensions = getDimensions();
glm::vec3 registrationRemainder = (getDimensions() * (glm::vec3(1.0f, 1.0f, 1.0f) - getRegistrationPoint())); glm::vec3 registrationPoint = (dimensions * _registrationPoint);
glm::vec3 registrationRemainder = (dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint));
glm::vec3 furthestExtentFromRegistration = glm::max(registrationPoint, registrationRemainder); glm::vec3 furthestExtentFromRegistration = glm::max(registrationPoint, registrationRemainder);
// * we know that if you rotate in any direction you would create a sphere // * we know that if you rotate in any direction you would create a sphere
@ -1238,7 +1242,6 @@ AACube EntityItem::getMaximumAACube(bool& success) const {
glm::vec3 minimumCorner = centerOfRotation - glm::vec3(radius, radius, radius); glm::vec3 minimumCorner = centerOfRotation - glm::vec3(radius, radius, radius);
_maxAACube = AACube(minimumCorner, radius * 2.0f); _maxAACube = AACube(minimumCorner, radius * 2.0f);
_recalcMaxAACube = false;
} }
} else { } else {
success = true; success = true;
@ -1251,28 +1254,27 @@ AACube EntityItem::getMaximumAACube(bool& success) const {
/// ///
AACube EntityItem::getMinimumAACube(bool& success) const { AACube EntityItem::getMinimumAACube(bool& success) const {
if (_recalcMinAACube) { if (_recalcMinAACube) {
// _position represents the position of the registration point. // position represents the position of the registration point.
glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint; glm::vec3 position = getPosition(success);
glm::vec3 unrotatedMinRelativeToEntity = - (getDimensions() * getRegistrationPoint());
glm::vec3 unrotatedMaxRelativeToEntity = getDimensions() * registrationRemainder;
Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
Extents rotatedExtentsRelativeToRegistrationPoint =
unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation());
// shift the extents to be relative to the position/registration point
rotatedExtentsRelativeToRegistrationPoint.shiftBy(getPosition(success));
if (success) { if (success) {
_recalcMinAACube = false;
glm::vec3 dimensions = getDimensions();
glm::vec3 unrotatedMinRelativeToEntity = - (dimensions * _registrationPoint);
glm::vec3 unrotatedMaxRelativeToEntity = dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint);
Extents extents = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
extents.rotate(getRotation());
// shift the extents to be relative to the position/registration point
extents.shiftBy(position);
// the cube that best encompasses extents is... // the cube that best encompasses extents is...
AABox box(rotatedExtentsRelativeToRegistrationPoint); AABox box(extents);
glm::vec3 centerOfBox = box.calcCenter(); glm::vec3 centerOfBox = box.calcCenter();
float longestSide = box.getLargestDimension(); float longestSide = box.getLargestDimension();
float halfLongestSide = longestSide / 2.0f; float halfLongestSide = longestSide / 2.0f;
glm::vec3 cornerOfCube = centerOfBox - glm::vec3(halfLongestSide, halfLongestSide, halfLongestSide); glm::vec3 cornerOfCube = centerOfBox - glm::vec3(halfLongestSide, halfLongestSide, halfLongestSide);
_minAACube = AACube(cornerOfCube, longestSide); _minAACube = AACube(cornerOfCube, longestSide);
_recalcMinAACube = false;
} }
} else { } else {
success = true; success = true;
@ -1282,21 +1284,20 @@ AACube EntityItem::getMinimumAACube(bool& success) const {
AABox EntityItem::getAABox(bool& success) const { AABox EntityItem::getAABox(bool& success) const {
if (_recalcAABox) { if (_recalcAABox) {
// _position represents the position of the registration point. // position represents the position of the registration point.
glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint; glm::vec3 position = getPosition(success);
glm::vec3 unrotatedMinRelativeToEntity = - (getDimensions() * _registrationPoint);
glm::vec3 unrotatedMaxRelativeToEntity = getDimensions() * registrationRemainder;
Extents unrotatedExtentsRelativeToRegistrationPoint = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
Extents rotatedExtentsRelativeToRegistrationPoint =
unrotatedExtentsRelativeToRegistrationPoint.getRotated(getRotation());
// shift the extents to be relative to the position/registration point
rotatedExtentsRelativeToRegistrationPoint.shiftBy(getPosition(success));
if (success) { if (success) {
_cachedAABox = AABox(rotatedExtentsRelativeToRegistrationPoint);
_recalcAABox = false; _recalcAABox = false;
glm::vec3 dimensions = getDimensions();
glm::vec3 unrotatedMinRelativeToEntity = - (dimensions * _registrationPoint);
glm::vec3 unrotatedMaxRelativeToEntity = dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint);
Extents extents = { unrotatedMinRelativeToEntity, unrotatedMaxRelativeToEntity };
extents.rotate(getRotation());
// shift the extents to be relative to the position/registration point
extents.shiftBy(position);
_cachedAABox = AABox(extents);
} }
} else { } else {
success = true; success = true;
@ -1373,6 +1374,11 @@ void EntityItem::computeShapeInfo(ShapeInfo& info) {
adjustShapeInfoByRegistration(info); adjustShapeInfoByRegistration(info);
} }
float EntityItem::getVolumeEstimate() const {
glm::vec3 dimensions = getDimensions();
return dimensions.x * dimensions.y * dimensions.z;
}
void EntityItem::updateRegistrationPoint(const glm::vec3& value) { void EntityItem::updateRegistrationPoint(const glm::vec3& value) {
if (value != _registrationPoint) { if (value != _registrationPoint) {
setRegistrationPoint(value); setRegistrationPoint(value);
@ -1433,7 +1439,8 @@ void EntityItem::updateMass(float mass) {
// we must protect the density range to help maintain stability of physics simulation // we must protect the density range to help maintain stability of physics simulation
// therefore this method might not accept the mass that is supplied. // therefore this method might not accept the mass that is supplied.
float volume = _volumeMultiplier * getDimensions().x * getDimensions().y * getDimensions().z; glm::vec3 dimensions = getDimensions();
float volume = _volumeMultiplier * dimensions.x * dimensions.y * dimensions.z;
// compute new density // compute new density
float newDensity = _density; float newDensity = _density;

View file

@ -314,7 +314,7 @@ public:
virtual bool isReadyToComputeShape() { return !isDead(); } virtual bool isReadyToComputeShape() { return !isDead(); }
virtual void computeShapeInfo(ShapeInfo& info); virtual void computeShapeInfo(ShapeInfo& info);
virtual float getVolumeEstimate() const { return getDimensions().x * getDimensions().y * getDimensions().z; } virtual float getVolumeEstimate() const;
/// return preferred shape type (actual physical shape may differ) /// return preferred shape type (actual physical shape may differ)
virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; } virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; }

View file

@ -1459,10 +1459,12 @@ void EntityTree::trackIncomingEntityLastEdited(quint64 lastEditedTime, int bytes
void EntityTree::callLoader(EntityItemID entityID) { void EntityTree::callLoader(EntityItemID entityID) {
// this is used to bounce from the networking thread to the main thread // this is used to bounce from the networking thread to the main thread
EntityItemPointer entity = findEntityByEntityItemID(entityID); this->withWriteLock([&] {
if (entity) { EntityItemPointer entity = findEntityByEntityItemID(entityID);
entity->loader(); if (entity) {
} entity->loader();
}
});
} }
int EntityTree::getJointIndex(const QUuid& entityID, const QString& name) const { int EntityTree::getJointIndex(const QUuid& entityID, const QString& name) const {

View file

@ -76,12 +76,13 @@ void LightEntityItem::setIsSpotlight(bool value) {
if (value != _isSpotlight) { if (value != _isSpotlight) {
_isSpotlight = value; _isSpotlight = value;
glm::vec3 dimensions = getDimensions();
if (_isSpotlight) { if (_isSpotlight) {
const float length = getDimensions().z; const float length = dimensions.z;
const float width = length * glm::sin(glm::radians(_cutoff)); const float width = length * glm::sin(glm::radians(_cutoff));
setDimensions(glm::vec3(width, width, length)); setDimensions(glm::vec3(width, width, length));
} else { } else {
float maxDimension = glm::max(getDimensions().x, getDimensions().y, getDimensions().z); float maxDimension = glm::max(dimensions.x, dimensions.y, dimensions.z);
setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension)); setDimensions(glm::vec3(maxDimension, maxDimension, maxDimension));
} }
} }

View file

@ -101,15 +101,13 @@ bool LineEntityItem::setLinePoints(const QVector<glm::vec3>& points) {
if (points.size() > MAX_POINTS_PER_LINE) { if (points.size() > MAX_POINTS_PER_LINE) {
return false; return false;
} }
glm::vec3 halfBox = getDimensions() * 0.5f;
for (int i = 0; i < points.size(); i++) { for (int i = 0; i < points.size(); i++) {
glm::vec3 point = points.at(i); glm::vec3 point = points.at(i);
// glm::vec3 pos = getPosition();
glm::vec3 halfBox = getDimensions() * 0.5f;
if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) { if ( (point.x < - halfBox.x || point.x > halfBox.x) || (point.y < -halfBox.y || point.y > halfBox.y) || (point.z < - halfBox.z || point.z > halfBox.z) ) {
qDebug() << "Point is outside entity's bounding box"; qDebug() << "Point is outside entity's bounding box";
return false; return false;
} }
} }
_points = points; _points = points;
_pointsChanged = true; _pointsChanged = true;

View file

@ -18,13 +18,15 @@ using namespace gpu;
Material::Material() : Material::Material() :
_key(0), _key(0),
_schemaBuffer(), _schemaBuffer(),
_texMapArrayBuffer(),
_textureMaps() _textureMaps()
{ {
// created from nothing: create the Buffer to store the properties // created from nothing: create the Buffer to store the properties
Schema schema; Schema schema;
_schemaBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema)); _schemaBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema));
TexMapArraySchema TexMapArraySchema;
_texMapArrayBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(TexMapArraySchema), (const gpu::Byte*) &TexMapArraySchema));
} }
Material::Material(const Material& material) : Material::Material(const Material& material) :
@ -35,6 +37,10 @@ Material::Material(const Material& material) :
Schema schema; Schema schema;
_schemaBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema)); _schemaBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema));
_schemaBuffer.edit<Schema>() = material._schemaBuffer.get<Schema>(); _schemaBuffer.edit<Schema>() = material._schemaBuffer.get<Schema>();
TexMapArraySchema texMapArraySchema;
_texMapArrayBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(TexMapArraySchema), (const gpu::Byte*) &texMapArraySchema));
_texMapArrayBuffer.edit<TexMapArraySchema>() = material._texMapArrayBuffer.get<TexMapArraySchema>();
} }
Material& Material::operator= (const Material& material) { Material& Material::operator= (const Material& material) {
@ -46,6 +52,10 @@ Material& Material::operator= (const Material& material) {
_schemaBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema)); _schemaBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(Schema), (const gpu::Byte*) &schema));
_schemaBuffer.edit<Schema>() = material._schemaBuffer.get<Schema>(); _schemaBuffer.edit<Schema>() = material._schemaBuffer.get<Schema>();
TexMapArraySchema texMapArraySchema;
_texMapArrayBuffer = gpu::BufferView(std::make_shared<gpu::Buffer>(sizeof(TexMapArraySchema), (const gpu::Byte*) &texMapArraySchema));
_texMapArrayBuffer.edit<TexMapArraySchema>() = material._texMapArrayBuffer.get<TexMapArraySchema>();
return (*this); return (*this);
} }
@ -101,6 +111,15 @@ void Material::setTextureMap(MapChannel channel, const TextureMapPointer& textur
if (channel == MaterialKey::ALBEDO_MAP) { if (channel == MaterialKey::ALBEDO_MAP) {
resetOpacityMap(); resetOpacityMap();
// update the texcoord0 with albedo
_texMapArrayBuffer.edit<TexMapArraySchema>()._texcoordTransforms[0] = (textureMap ? textureMap->getTextureTransform().getMatrix() : glm::mat4());
}
if (channel == MaterialKey::LIGHTMAP_MAP) {
// update the texcoord1 with lightmap
_texMapArrayBuffer.edit<TexMapArraySchema>()._texcoordTransforms[1] = (textureMap ? textureMap->getTextureTransform().getMatrix() : glm::mat4());
_texMapArrayBuffer.edit<TexMapArraySchema>()._lightmapParams = (textureMap ? glm::vec4(textureMap->getLightmapOffsetScale(), 0.0, 0.0) : glm::vec4(0.0, 1.0, 0.0, 0.0));
} }
_schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong(); _schemaBuffer.edit<Schema>()._key = (uint32)_key._flags.to_ulong();

View file

@ -298,9 +298,21 @@ public:
// conversion from legacy material properties to PBR equivalent // conversion from legacy material properties to PBR equivalent
static float shininessToRoughness(float shininess) { return 1.0f - shininess / 100.0f; } static float shininessToRoughness(float shininess) { return 1.0f - shininess / 100.0f; }
// Texture Map Array Schema
static const int NUM_TEXCOORD_TRANSFORMS{ 2 };
class TexMapArraySchema {
public:
glm::mat4 _texcoordTransforms[NUM_TEXCOORD_TRANSFORMS];
glm::vec4 _lightmapParams{ 0.0, 1.0, 0.0, 0.0 };
TexMapArraySchema() {}
};
const UniformBufferView& getTexMapArrayBuffer() const { return _texMapArrayBuffer; }
private: private:
mutable MaterialKey _key; mutable MaterialKey _key;
mutable UniformBufferView _schemaBuffer; mutable UniformBufferView _schemaBuffer;
mutable UniformBufferView _texMapArrayBuffer;
TextureMaps _textureMaps; TextureMaps _textureMaps;
}; };
typedef std::shared_ptr< Material > MaterialPointer; typedef std::shared_ptr< Material > MaterialPointer;

View file

@ -413,9 +413,15 @@ gpu::Texture* TextureUsage::createMetallicTextureFromImage(const QImage& srcImag
class CubeLayout { class CubeLayout {
public: public:
enum SourceProjection {
FLAT = 0,
EQUIRECTANGULAR,
};
int _type = FLAT;
int _widthRatio = 1; int _widthRatio = 1;
int _heightRatio = 1; int _heightRatio = 1;
class Face { class Face {
public: public:
int _x = 0; int _x = 0;
@ -435,6 +441,7 @@ public:
Face _faceZNeg; Face _faceZNeg;
CubeLayout(int wr, int hr, Face fXP, Face fXN, Face fYP, Face fYN, Face fZP, Face fZN) : CubeLayout(int wr, int hr, Face fXP, Face fXN, Face fYP, Face fYN, Face fZP, Face fZN) :
_type(FLAT),
_widthRatio(wr), _widthRatio(wr),
_heightRatio(hr), _heightRatio(hr),
_faceXPos(fXP), _faceXPos(fXP),
@ -444,6 +451,11 @@ public:
_faceZPos(fZP), _faceZPos(fZP),
_faceZNeg(fZN) {} _faceZNeg(fZN) {}
CubeLayout(int wr, int hr) :
_type(EQUIRECTANGULAR),
_widthRatio(wr),
_heightRatio(hr) {}
static const CubeLayout CUBEMAP_LAYOUTS[]; static const CubeLayout CUBEMAP_LAYOUTS[];
static const int NUM_CUBEMAP_LAYOUTS; static const int NUM_CUBEMAP_LAYOUTS;
@ -459,9 +471,102 @@ public:
} }
return foundLayout; return foundLayout;
} }
static QImage extractEquirectangularFace(const QImage& source, gpu::Texture::CubeFace face, int faceWidth) {
QImage image(faceWidth, faceWidth, source.format());
glm::vec2 dstInvSize(1.0f / (float)image.width(), 1.0f / (float)image.height());
struct CubeToXYZ {
gpu::Texture::CubeFace _face;
CubeToXYZ(gpu::Texture::CubeFace face) : _face(face) {}
glm::vec3 xyzFrom(const glm::vec2& uv) {
auto faceDir = glm::normalize(glm::vec3(-1.0f + 2.0f * uv.x, -1.0f + 2.0f * uv.y, 1.0f));
switch (_face) {
case gpu::Texture::CubeFace::CUBE_FACE_BACK_POS_Z:
return glm::vec3(-faceDir.x, faceDir.y, faceDir.z);
case gpu::Texture::CubeFace::CUBE_FACE_FRONT_NEG_Z:
return glm::vec3(faceDir.x, faceDir.y, -faceDir.z);
case gpu::Texture::CubeFace::CUBE_FACE_LEFT_NEG_X:
return glm::vec3(faceDir.z, faceDir.y, faceDir.x);
case gpu::Texture::CubeFace::CUBE_FACE_RIGHT_POS_X:
return glm::vec3(-faceDir.z, faceDir.y, -faceDir.x);
case gpu::Texture::CubeFace::CUBE_FACE_BOTTOM_NEG_Y:
return glm::vec3(-faceDir.x, -faceDir.z, faceDir.y);
case gpu::Texture::CubeFace::CUBE_FACE_TOP_POS_Y:
default:
return glm::vec3(-faceDir.x, faceDir.z, -faceDir.y);
}
}
};
CubeToXYZ cubeToXYZ(face);
struct RectToXYZ {
RectToXYZ() {}
glm::vec2 uvFrom(const glm::vec3& xyz) {
auto flatDir = glm::normalize(glm::vec2(xyz.x, xyz.z));
auto uvRad = glm::vec2(atan2(flatDir.x, flatDir.y), asin(xyz.y));
const float LON_TO_RECT_U = 1.0f / (glm::pi<float>());
const float LAT_TO_RECT_V = 2.0f / glm::pi<float>();
return glm::vec2(0.5f * uvRad.x * LON_TO_RECT_U + 0.5f, 0.5f * uvRad.y * LAT_TO_RECT_V + 0.5f);
}
};
RectToXYZ rectToXYZ;
int srcFaceHeight = source.height();
int srcFaceWidth = source.width();
glm::vec2 dstCoord;
glm::ivec2 srcPixel;
for (int y = 0; y < faceWidth; ++y) {
dstCoord.y = 1.0f - (y + 0.5f) * dstInvSize.y; // Fill cube face images from top to bottom
for (int x = 0; x < faceWidth; ++x) {
dstCoord.x = (x + 0.5f) * dstInvSize.x;
auto xyzDir = cubeToXYZ.xyzFrom(dstCoord);
auto srcCoord = rectToXYZ.uvFrom(xyzDir);
srcPixel.x = floor(srcCoord.x * srcFaceWidth);
// Flip the vertical axis to QImage going top to bottom
srcPixel.y = floor((1.0f - srcCoord.y) * srcFaceHeight);
if (((uint32) srcPixel.x < (uint32) source.width()) && ((uint32) srcPixel.y < (uint32) source.height())) {
image.setPixel(x, y, source.pixel(QPoint(srcPixel.x, srcPixel.y)));
// Keep for debug, this is showing the dir as a color
// glm::u8vec4 rgba((xyzDir.x + 1.0)*0.5 * 256, (xyzDir.y + 1.0)*0.5 * 256, (xyzDir.z + 1.0)*0.5 * 256, 256);
// unsigned int val = 0xff000000 | (rgba.r) | (rgba.g << 8) | (rgba.b << 16);
// image.setPixel(x, y, val);
}
}
}
return image;
}
}; };
const CubeLayout CubeLayout::CUBEMAP_LAYOUTS[] = { const CubeLayout CubeLayout::CUBEMAP_LAYOUTS[] = {
// Here is the expected layout for the faces in an image with the 2/1 aspect ratio:
// THis is detected as an Equirectangular projection
// WIDTH
// <--------------------------->
// ^ +------+------+------+------+
// H | | | | |
// E | | | | |
// I | | | | |
// G +------+------+------+------+
// H | | | | |
// T | | | | |
// | | | | | |
// v +------+------+------+------+
//
// FaceWidth = width = height / 6
{ 2, 1 },
// Here is the expected layout for the faces in an image with the 1/6 aspect ratio: // Here is the expected layout for the faces in an image with the 1/6 aspect ratio:
// //
// WIDTH // WIDTH
@ -582,14 +687,25 @@ gpu::Texture* TextureUsage::processCubeTextureColorFromImage(const QImage& srcIm
// If found, go extract the faces as separate images // If found, go extract the faces as separate images
if (foundLayout >= 0) { if (foundLayout >= 0) {
auto& layout = CubeLayout::CUBEMAP_LAYOUTS[foundLayout]; auto& layout = CubeLayout::CUBEMAP_LAYOUTS[foundLayout];
int faceWidth = image.width() / layout._widthRatio; if (layout._type == CubeLayout::FLAT) {
int faceWidth = image.width() / layout._widthRatio;
faces.push_back(image.copy(QRect(layout._faceXPos._x * faceWidth, layout._faceXPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXPos._horizontalMirror, layout._faceXPos._verticalMirror)); faces.push_back(image.copy(QRect(layout._faceXPos._x * faceWidth, layout._faceXPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXPos._horizontalMirror, layout._faceXPos._verticalMirror));
faces.push_back(image.copy(QRect(layout._faceXNeg._x * faceWidth, layout._faceXNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXNeg._horizontalMirror, layout._faceXNeg._verticalMirror)); faces.push_back(image.copy(QRect(layout._faceXNeg._x * faceWidth, layout._faceXNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceXNeg._horizontalMirror, layout._faceXNeg._verticalMirror));
faces.push_back(image.copy(QRect(layout._faceYPos._x * faceWidth, layout._faceYPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYPos._horizontalMirror, layout._faceYPos._verticalMirror)); faces.push_back(image.copy(QRect(layout._faceYPos._x * faceWidth, layout._faceYPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYPos._horizontalMirror, layout._faceYPos._verticalMirror));
faces.push_back(image.copy(QRect(layout._faceYNeg._x * faceWidth, layout._faceYNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYNeg._horizontalMirror, layout._faceYNeg._verticalMirror)); faces.push_back(image.copy(QRect(layout._faceYNeg._x * faceWidth, layout._faceYNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceYNeg._horizontalMirror, layout._faceYNeg._verticalMirror));
faces.push_back(image.copy(QRect(layout._faceZPos._x * faceWidth, layout._faceZPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZPos._horizontalMirror, layout._faceZPos._verticalMirror)); faces.push_back(image.copy(QRect(layout._faceZPos._x * faceWidth, layout._faceZPos._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZPos._horizontalMirror, layout._faceZPos._verticalMirror));
faces.push_back(image.copy(QRect(layout._faceZNeg._x * faceWidth, layout._faceZNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZNeg._horizontalMirror, layout._faceZNeg._verticalMirror)); faces.push_back(image.copy(QRect(layout._faceZNeg._x * faceWidth, layout._faceZNeg._y * faceWidth, faceWidth, faceWidth)).mirrored(layout._faceZNeg._horizontalMirror, layout._faceZNeg._verticalMirror));
} else if (layout._type == CubeLayout::EQUIRECTANGULAR) {
// THe face width is estimated from the input image
const int EQUIRECT_FACE_RATIO_TO_WIDTH = 4;
const int EQUIRECT_MAX_FACE_WIDTH = 2048;
int faceWidth = std::min(image.width() / EQUIRECT_FACE_RATIO_TO_WIDTH, EQUIRECT_MAX_FACE_WIDTH);
for (int face = gpu::Texture::CUBE_FACE_RIGHT_POS_X; face < gpu::Texture::NUM_CUBE_FACES; face++) {
QImage faceImage = CubeLayout::extractEquirectangularFace(image, (gpu::Texture::CubeFace) face, faceWidth);
faces.push_back(faceImage);
}
}
} else { } else {
qCDebug(modelLog) << "Failed to find a known cube map layout from this image:" << QString(srcImageName.c_str()); qCDebug(modelLog) << "Failed to find a known cube map layout from this image:" << QString(srcImageName.c_str());
return nullptr; return nullptr;

View file

@ -325,47 +325,117 @@ void AssetClient::handleAssetGetReply(QSharedPointer<ReceivedMessage> message, S
// Check if we have any pending requests for this node // Check if we have any pending requests for this node
auto messageMapIt = _pendingRequests.find(senderNode); auto messageMapIt = _pendingRequests.find(senderNode);
if (messageMapIt != _pendingRequests.end()) { if (messageMapIt == _pendingRequests.end()) {
return;
}
// Found the node, get the MessageID -> Callback map // Found the node, get the MessageID -> Callback map
auto& messageCallbackMap = messageMapIt->second; auto& messageCallbackMap = messageMapIt->second;
// Check if we have this pending request
auto requestIt = messageCallbackMap.find(messageID);
if (requestIt != messageCallbackMap.end()) {
auto& callbacks = requestIt->second;
// Store message in case we need to disconnect from it later.
callbacks.message = message;
if (message->isComplete()) {
callbacks.completeCallback(true, error, message->readAll());
messageCallbackMap.erase(requestIt);
} else {
connect(message.data(), &ReceivedMessage::progress, this, [this, length, message, &callbacks]() {
callbacks.progressCallback(message->getSize(), length);
});
connect(message.data(), &ReceivedMessage::completed, this, [this, messageID, message, &messageCallbackMap, &callbacks]() {
if (message->failed()) {
callbacks.completeCallback(false, AssetServerError::NoError, QByteArray());
} else {
callbacks.completeCallback(true, AssetServerError::NoError, message->readAll());
}
// We should never get to this point without the associated senderNode and messageID
// in our list of pending requests. If the senderNode had disconnected or the message
// had been canceled, we should have been disconnected from the ReceivedMessage
// signals and thus never had this lambda called.
messageCallbackMap.erase(messageID);
});
}
}
// Check if we have this pending request
auto requestIt = messageCallbackMap.find(messageID);
if (requestIt == messageCallbackMap.end()) {
// Although the messageCallbackMap may now be empty, we won't delete the node until we have disconnected from // Although the messageCallbackMap may now be empty, we won't delete the node until we have disconnected from
// it to avoid constantly creating/deleting the map on subsequent requests. // it to avoid constantly creating/deleting the map on subsequent requests.
return;
}
auto& callbacks = requestIt->second;
// Store message in case we need to disconnect from it later.
callbacks.message = message;
if (message->isComplete()) {
callbacks.completeCallback(true, error, message->readAll());
messageCallbackMap.erase(requestIt);
} else {
auto weakNode = senderNode.toWeakRef();
connect(message.data(), &ReceivedMessage::progress, this, [this, weakNode, messageID, length]() {
handleProgressCallback(weakNode, messageID, length);
});
connect(message.data(), &ReceivedMessage::completed, this, [this, weakNode, messageID]() {
handleCompleteCallback(weakNode, messageID);
});
} }
} }
void AssetClient::handleProgressCallback(const QWeakPointer<Node>& node, MessageID messageID, DataOffset length) {
auto senderNode = node.toStrongRef();
if (!senderNode) {
return;
}
// Check if we have any pending requests for this node
auto messageMapIt = _pendingRequests.find(senderNode);
if (messageMapIt == _pendingRequests.end()) {
return;
}
// Found the node, get the MessageID -> Callback map
auto& messageCallbackMap = messageMapIt->second;
// Check if we have this pending request
auto requestIt = messageCallbackMap.find(messageID);
if (requestIt == messageCallbackMap.end()) {
return;
}
auto& callbacks = requestIt->second;
auto& message = callbacks.message;
if (!message) {
return;
}
callbacks.progressCallback(message->getSize(), length);
}
void AssetClient::handleCompleteCallback(const QWeakPointer<Node>& node, MessageID messageID) {
auto senderNode = node.toStrongRef();
if (!senderNode) {
return;
}
// Check if we have any pending requests for this node
auto messageMapIt = _pendingRequests.find(senderNode);
if (messageMapIt == _pendingRequests.end()) {
return;
}
// Found the node, get the MessageID -> Callback map
auto& messageCallbackMap = messageMapIt->second;
// Check if we have this pending request
auto requestIt = messageCallbackMap.find(messageID);
if (requestIt == messageCallbackMap.end()) {
return;
}
auto& callbacks = requestIt->second;
auto& message = callbacks.message;
if (!message) {
return;
}
if (message->failed()) {
callbacks.completeCallback(false, AssetServerError::NoError, QByteArray());
} else {
callbacks.completeCallback(true, AssetServerError::NoError, message->readAll());
}
// We should never get to this point without the associated senderNode and messageID
// in our list of pending requests. If the senderNode had disconnected or the message
// had been canceled, we should have been disconnected from the ReceivedMessage
// signals and thus never had this lambda called.
messageCallbackMap.erase(messageID);
}
MessageID AssetClient::getAssetMapping(const AssetPath& path, MappingOperationCallback callback) { MessageID AssetClient::getAssetMapping(const AssetPath& path, MappingOperationCallback callback) {
Q_ASSERT(QThread::currentThread() == thread()); Q_ASSERT(QThread::currentThread() == thread());

View file

@ -93,6 +93,9 @@ private:
bool cancelGetAssetRequest(MessageID id); bool cancelGetAssetRequest(MessageID id);
bool cancelUploadAssetRequest(MessageID id); bool cancelUploadAssetRequest(MessageID id);
void handleProgressCallback(const QWeakPointer<Node>& node, MessageID messageID, DataOffset length);
void handleCompleteCallback(const QWeakPointer<Node>& node, MessageID messageID);
struct GetAssetRequestData { struct GetAssetRequestData {
QSharedPointer<ReceivedMessage> message; QSharedPointer<ReceivedMessage> message;
ReceivedAssetCallback completeCallback; ReceivedAssetCallback completeCallback;

View file

@ -25,15 +25,12 @@ UserActivityLogger& UserActivityLogger::getInstance() {
return sharedInstance; return sharedInstance;
} }
UserActivityLogger::UserActivityLogger() : _disabled(false) {
}
void UserActivityLogger::disable(bool disable) { void UserActivityLogger::disable(bool disable) {
_disabled = disable; _disabled.set(disable);
} }
void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCallbackParameters params) { void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCallbackParameters params) {
if (_disabled) { if (_disabled.get()) {
return; return;
} }
@ -63,7 +60,7 @@ void UserActivityLogger::logAction(QString action, QJsonObject details, JSONCall
} }
accountManager.sendRequest(USER_ACTIVITY_URL, accountManager.sendRequest(USER_ACTIVITY_URL,
AccountManagerAuth::Required, AccountManagerAuth::Optional,
QNetworkAccessManager::PostOperation, QNetworkAccessManager::PostOperation,
params, NULL, multipart); params, NULL, multipart);
} }

View file

@ -19,6 +19,8 @@
#include <QJsonObject> #include <QJsonObject>
#include <QNetworkReply> #include <QNetworkReply>
#include <SettingHandle.h>
class UserActivityLogger : public QObject { class UserActivityLogger : public QObject {
Q_OBJECT Q_OBJECT
@ -44,8 +46,8 @@ private slots:
void requestError(QNetworkReply& errorReply); void requestError(QNetworkReply& errorReply);
private: private:
UserActivityLogger(); UserActivityLogger() {};
bool _disabled; Setting::Handle<bool> _disabled { "UserActivityLoggerDisabled", false };
}; };
#endif // hifi_UserActivityLogger_h #endif // hifi_UserActivityLogger_h

View file

@ -107,7 +107,8 @@ public:
// The recommended bounds for primary overlay placement // The recommended bounds for primary overlay placement
virtual QRect getRecommendedOverlayRect() const { virtual QRect getRecommendedOverlayRect() const {
auto recommendedSize = getRecommendedUiSize(); const int DESKTOP_SCREEN_PADDING = 50;
auto recommendedSize = getRecommendedUiSize() - glm::uvec2(DESKTOP_SCREEN_PADDING);
return QRect(0, 0, recommendedSize.x, recommendedSize.y); return QRect(0, 0, recommendedSize.x, recommendedSize.y);
} }

View file

@ -11,6 +11,39 @@
<@if not MODEL_MATERIAL_TEXTURES_SLH@> <@if not MODEL_MATERIAL_TEXTURES_SLH@>
<@def MODEL_MATERIAL_TEXTURES_SLH@> <@def MODEL_MATERIAL_TEXTURES_SLH@>
<@func declareMaterialTexMapArrayBuffer()@>
const int MAX_TEXCOORDS = 2;
struct TexMapArray {
mat4 _texcoordTransforms[MAX_TEXCOORDS];
vec4 _lightmapParams;
};
uniform texMapArrayBuffer {
TexMapArray _texMapArray;
};
TexMapArray getTexMapArray() {
return _texMapArray;
}
<@func evalTexMapArrayTexcoord0(texMapArray, inTexcoord0, outTexcoord0)@>
{
<$outTexcoord0$> = (<$texMapArray$>._texcoordTransforms[0] * vec4(<$inTexcoord0$>.st, 0.0, 1.0)).st;
}
<@endfunc@>
<@func evalTexMapArrayTexcoord1(texMapArray, inTexcoord1, outTexcoord1)@>
{
<$outTexcoord1$> = (<$texMapArray$>._texcoordTransforms[1] * vec4(<$inTexcoord1$>.st, 0.0, 1.0)).st;
}
<@endfunc@>
<@endfunc@>
<@func declareMaterialTextures(withAlbedo, withRoughness, withNormal, withMetallic, withEmissive, withOcclusion)@> <@func declareMaterialTextures(withAlbedo, withRoughness, withNormal, withMetallic, withEmissive, withOcclusion)@>
<@if withAlbedo@> <@if withAlbedo@>
@ -80,9 +113,12 @@ float fetchOcclusionMap(vec2 uv) {
<@func declareMaterialLightmap()@> <@func declareMaterialLightmap()@>
<$declareMaterialTexMapArrayBuffer()$>
uniform sampler2D emissiveMap; uniform sampler2D emissiveMap;
uniform vec2 emissiveParams;
vec3 fetchLightmapMap(vec2 uv) { vec3 fetchLightmapMap(vec2 uv) {
vec2 emissiveParams = getTexMapArray()._lightmapParams.xy;
return (vec3(emissiveParams.x) + emissiveParams.y * texture(emissiveMap, uv).rgb); return (vec3(emissiveParams.x) + emissiveParams.y * texture(emissiveMap, uv).rgb);
} }
<@endfunc@> <@endfunc@>

View file

@ -138,21 +138,17 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
auto textureCache = DependencyManager::get<TextureCache>(); auto textureCache = DependencyManager::get<TextureCache>();
batch.setUniformBuffer(ShapePipeline::Slot::MATERIAL_GPU, _drawMaterial->getSchemaBuffer()); batch.setUniformBuffer(ShapePipeline::Slot::MATERIAL_BUFFER, _drawMaterial->getSchemaBuffer());
batch.setUniformBuffer(ShapePipeline::Slot::TEXMAPARRAY_BUFFER, _drawMaterial->getTexMapArrayBuffer());
auto materialKey = _drawMaterial->getKey(); auto materialKey = _drawMaterial->getKey();
auto textureMaps = _drawMaterial->getTextureMaps(); auto textureMaps = _drawMaterial->getTextureMaps();
glm::mat4 texcoordTransform[2];
// Albedo // Albedo
if (materialKey.isAlbedoMap()) { if (materialKey.isAlbedoMap()) {
auto albedoMap = textureMaps[model::MaterialKey::ALBEDO_MAP]; auto albedoMap = textureMaps[model::MaterialKey::ALBEDO_MAP];
if (albedoMap && albedoMap->isDefined()) { if (albedoMap && albedoMap->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO_MAP, albedoMap->getTextureView()); batch.setResourceTexture(ShapePipeline::Slot::ALBEDO_MAP, albedoMap->getTextureView());
if (!albedoMap->getTextureTransform().isIdentity()) {
albedoMap->getTextureTransform().getMatrix(texcoordTransform[0]);
}
} else { } else {
batch.setResourceTexture(ShapePipeline::Slot::ALBEDO_MAP, textureCache->getGrayTexture()); batch.setResourceTexture(ShapePipeline::Slot::ALBEDO_MAP, textureCache->getGrayTexture());
} }
@ -222,13 +218,6 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
if (lightmapMap && lightmapMap->isDefined()) { if (lightmapMap && lightmapMap->isDefined()) {
batch.setResourceTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP_MAP, lightmapMap->getTextureView()); batch.setResourceTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP_MAP, lightmapMap->getTextureView());
auto lightmapOffsetScale = lightmapMap->getLightmapOffsetScale();
batch._glUniform2f(locations->emissiveParams, lightmapOffsetScale.x, lightmapOffsetScale.y);
if (!lightmapMap->getTextureTransform().isIdentity()) {
lightmapMap->getTextureTransform().getMatrix(texcoordTransform[1]);
}
} else { } else {
batch.setResourceTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP_MAP, textureCache->getGrayTexture()); batch.setResourceTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP_MAP, textureCache->getGrayTexture());
} }
@ -243,12 +232,6 @@ void MeshPartPayload::bindMaterial(gpu::Batch& batch, const ShapePipeline::Locat
} else { } else {
batch.setResourceTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP_MAP, nullptr); batch.setResourceTexture(ShapePipeline::Slot::EMISSIVE_LIGHTMAP_MAP, nullptr);
} }
// Texcoord transforms ?
if (locations->texcoordMatrices >= 0) {
batch._glUniformMatrix4fv(locations->texcoordMatrices, 2, false, (const float*)&texcoordTransform);
// batch._glUniformMatrix4fv(locations->texcoordMatrices, (materialKey.isLightmapMap() ? 2 : 1), false, (const float*)&texcoordTransform);
}
} }
void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, bool canCauterize) const { void MeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline::LocationsPointer locations, bool canCauterize) const {
@ -491,9 +474,9 @@ void ModelMeshPartPayload::bindTransform(gpu::Batch& batch, const ShapePipeline:
Transform transform; Transform transform;
if (state.clusterBuffer) { if (state.clusterBuffer) {
if (canCauterize && _model->getCauterizeBones()) { if (canCauterize && _model->getCauterizeBones()) {
batch.setUniformBuffer(ShapePipeline::Slot::SKINNING_GPU, state.cauterizedClusterBuffer); batch.setUniformBuffer(ShapePipeline::Slot::SKINNING_BUFFER, state.cauterizedClusterBuffer);
} else { } else {
batch.setUniformBuffer(ShapePipeline::Slot::SKINNING_GPU, state.clusterBuffer); batch.setUniformBuffer(ShapePipeline::Slot::SKINNING_BUFFER, state.clusterBuffer);
} }
} else { } else {
if (canCauterize && _model->getCauterizeBones()) { if (canCauterize && _model->getCauterizeBones()) {

View file

@ -80,15 +80,11 @@ void batchSetter(const ShapePipeline& pipeline, gpu::Batch& batch) {
// Set a default normal map // Set a default normal map
batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP, batch.setResourceTexture(render::ShapePipeline::Slot::NORMAL_FITTING_MAP,
DependencyManager::get<TextureCache>()->getNormalFittingTexture()); DependencyManager::get<TextureCache>()->getNormalFittingTexture());
// Set default coordinates
if (pipeline.locations->texcoordMatrices >= 0) {
static const glm::mat4 TEX_COORDS[2];
batch._glUniformMatrix4fv(pipeline.locations->texcoordMatrices, 2, false, (const float*)&TEX_COORDS);
}
// Set a default material // Set a default material
if (pipeline.locations->materialBufferUnit >= 0) { if (pipeline.locations->materialBufferUnit >= 0) {
static const gpu::BufferView OPAQUE_SCHEMA_BUFFER = getDefaultMaterialBuffer(); static const gpu::BufferView OPAQUE_SCHEMA_BUFFER = getDefaultMaterialBuffer();
batch.setUniformBuffer(ShapePipeline::Slot::MATERIAL_GPU, OPAQUE_SCHEMA_BUFFER); batch.setUniformBuffer(ShapePipeline::Slot::MATERIAL_BUFFER, OPAQUE_SCHEMA_BUFFER);
} }
} }

View file

@ -11,7 +11,6 @@
<@if not SKINNING_SLH@> <@if not SKINNING_SLH@>
<@def SKINNING_SLH@> <@def SKINNING_SLH@>
const int MAX_TEXCOORDS = 2;
const int MAX_CLUSTERS = 128; const int MAX_CLUSTERS = 128;
const int INDICES_PER_VERTEX = 4; const int INDICES_PER_VERTEX = 4;

View file

@ -16,8 +16,8 @@
<@include gpu/Transform.slh@> <@include gpu/Transform.slh@>
<$declareStandardTransform()$> <$declareStandardTransform()$>
const int MAX_TEXCOORDS = 2; <@include MaterialTextures.slh@>
uniform mat4 texcoordMatrices[MAX_TEXCOORDS]; <$declareMaterialTexMapArrayBuffer()$>
out vec3 _color; out vec3 _color;
out float _alpha; out float _alpha;
@ -29,7 +29,8 @@ void main(void) {
_color = colorToLinearRGB(inColor.xyz); _color = colorToLinearRGB(inColor.xyz);
_alpha = inColor.w; _alpha = inColor.w;
_texCoord0 = (texcoordMatrices[0] * vec4(inTexCoord0.st, 0.0, 1.0)).st; TexMapArray texMapArray = getTexMapArray();
<$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
// standard transform // standard transform
TransformCamera cam = getTransformCamera(); TransformCamera cam = getTransformCamera();

View file

@ -30,7 +30,7 @@ void main(void) {
Material mat = getMaterial(); Material mat = getMaterial();
int matKey = getMaterialKey(mat); int matKey = getMaterialKey(mat);
<$fetchMaterialTextures(matKey, _texCoord0, albedo, roughness)$> <$fetchMaterialTextures(matKey, _texCoord0, albedo, roughness)$>
<$fetchMaterialLightmap(_texCoord1, emissive)$> <$fetchMaterialLightmap(_texCoord1, lightmapVal)$>
packDeferredFragmentLightmap( packDeferredFragmentLightmap(
@ -40,5 +40,5 @@ void main(void) {
getMaterialRoughness(mat) * roughness, getMaterialRoughness(mat) * roughness,
getMaterialMetallic(mat), getMaterialMetallic(mat),
getMaterialFresnel(mat), getMaterialFresnel(mat),
(vec3(emissiveParams.x) + emissiveParams.y * emissive.rgb)); lightmapVal);
} }

View file

@ -17,9 +17,8 @@
<@include gpu/Transform.slh@> <@include gpu/Transform.slh@>
<$declareStandardTransform()$> <$declareStandardTransform()$>
const int MAX_TEXCOORDS = 2; <@include MaterialTextures.slh@>
<$declareMaterialTexMapArrayBuffer()$>
uniform mat4 texcoordMatrices[MAX_TEXCOORDS];
out vec4 _position; out vec4 _position;
out vec2 _texCoord0; out vec2 _texCoord0;
@ -32,8 +31,9 @@ void main(void) {
_color = colorToLinearRGB(inColor.xyz); _color = colorToLinearRGB(inColor.xyz);
// and the texture coordinates // and the texture coordinates
_texCoord0 = (texcoordMatrices[0] * vec4(inTexCoord0.st, 0.0, 1.0)).st; TexMapArray texMapArray = getTexMapArray();
_texCoord1 = (texcoordMatrices[1] * vec4(inTexCoord1.st, 0.0, 1.0)).st; <$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
<$evalTexMapArrayTexcoord1(texMapArray, inTexCoord1, _texCoord1)$>
// standard transform // standard transform
TransformCamera cam = getTransformCamera(); TransformCamera cam = getTransformCamera();

View file

@ -17,9 +17,8 @@
<@include gpu/Transform.slh@> <@include gpu/Transform.slh@>
<$declareStandardTransform()$> <$declareStandardTransform()$>
const int MAX_TEXCOORDS = 2; <@include MaterialTextures.slh@>
<$declareMaterialTexMapArrayBuffer()$>
uniform mat4 texcoordMatrices[MAX_TEXCOORDS];
out vec4 _position; out vec4 _position;
out vec2 _texCoord0; out vec2 _texCoord0;
@ -32,9 +31,9 @@ void main(void) {
// pass along the color in linear space // pass along the color in linear space
_color = colorToLinearRGB(inColor.xyz); _color = colorToLinearRGB(inColor.xyz);
// and the texture coordinates TexMapArray texMapArray = getTexMapArray();
_texCoord0 = (texcoordMatrices[0] * vec4(inTexCoord0.st, 0.0, 1.0)).st; <$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
_texCoord1 = (texcoordMatrices[1] * vec4(inTexCoord1.st, 0.0, 1.0)).st; <$evalTexMapArrayTexcoord1(texMapArray, inTexCoord1, _texCoord1)$>
// standard transform // standard transform
TransformCamera cam = getTransformCamera(); TransformCamera cam = getTransformCamera();

View file

@ -17,9 +17,8 @@
<@include gpu/Transform.slh@> <@include gpu/Transform.slh@>
<$declareStandardTransform()$> <$declareStandardTransform()$>
const int MAX_TEXCOORDS = 2; <@include MaterialTextures.slh@>
<$declareMaterialTexMapArrayBuffer()$>
uniform mat4 texcoordMatrices[MAX_TEXCOORDS];
out vec4 _position; out vec4 _position;
out vec2 _texCoord0; out vec2 _texCoord0;
@ -33,8 +32,8 @@ void main(void) {
_color = colorToLinearRGB(inColor.rgb); _color = colorToLinearRGB(inColor.rgb);
_alpha = inColor.a; _alpha = inColor.a;
// and the texture coordinates TexMapArray texMapArray = getTexMapArray();
_texCoord0 = (texcoordMatrices[0] * vec4(inTexCoord0.xy, 0.0, 1.0)).st; <$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
// standard transform // standard transform
TransformCamera cam = getTransformCamera(); TransformCamera cam = getTransformCamera();

View file

@ -19,7 +19,8 @@
<@include Skinning.slh@> <@include Skinning.slh@>
uniform mat4 texcoordMatrices[MAX_TEXCOORDS]; <@include MaterialTextures.slh@>
<$declareMaterialTexMapArrayBuffer()$>
out vec4 _position; out vec4 _position;
out vec2 _texCoord0; out vec2 _texCoord0;
@ -37,9 +38,9 @@ void main(void) {
_color = colorToLinearRGB(inColor.rgb); _color = colorToLinearRGB(inColor.rgb);
_alpha = inColor.a; _alpha = inColor.a;
// and the texture coordinates TexMapArray texMapArray = getTexMapArray();
_texCoord0 = (texcoordMatrices[0] * vec4(inTexCoord0.st, 0.0, 1.0)).st; <$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
// standard transform // standard transform
TransformCamera cam = getTransformCamera(); TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject(); TransformObject obj = getTransformObject();

View file

@ -19,7 +19,8 @@
<@include Skinning.slh@> <@include Skinning.slh@>
uniform mat4 texcoordMatrices[MAX_TEXCOORDS]; <@include MaterialTextures.slh@>
<$declareMaterialTexMapArrayBuffer()$>
out vec4 _position; out vec4 _position;
out vec2 _texCoord0; out vec2 _texCoord0;
@ -39,9 +40,9 @@ void main(void) {
_color = colorToLinearRGB(inColor.rgb); _color = colorToLinearRGB(inColor.rgb);
_alpha = inColor.a; _alpha = inColor.a;
// and the texture coordinates TexMapArray texMapArray = getTexMapArray();
_texCoord0 = (texcoordMatrices[0] * vec4(inTexCoord0.st, 0.0, 1.0)).st; <$evalTexMapArrayTexcoord0(texMapArray, inTexCoord0, _texCoord0)$>
interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0); interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0);
interpolatedTangent = vec4(normalize(interpolatedTangent.xyz), 0.0); interpolatedTangent = vec4(normalize(interpolatedTangent.xyz), 0.0);

View file

@ -51,8 +51,9 @@ void ShapePlumber::addPipeline(const Key& key, const gpu::ShaderPointer& program
void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state, void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& program, const gpu::StatePointer& state,
BatchSetter batchSetter) { BatchSetter batchSetter) {
gpu::Shader::BindingSet slotBindings; gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::SKINNING_GPU)); slotBindings.insert(gpu::Shader::Binding(std::string("skinClusterBuffer"), Slot::SKINNING_BUFFER));
slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), Slot::MATERIAL_GPU)); slotBindings.insert(gpu::Shader::Binding(std::string("materialBuffer"), Slot::MATERIAL_BUFFER));
slotBindings.insert(gpu::Shader::Binding(std::string("texMapArrayBuffer"), Slot::TEXMAPARRAY_BUFFER));
slotBindings.insert(gpu::Shader::Binding(std::string("albedoMap"), Slot::ALBEDO_MAP)); slotBindings.insert(gpu::Shader::Binding(std::string("albedoMap"), Slot::ALBEDO_MAP));
slotBindings.insert(gpu::Shader::Binding(std::string("roughnessMap"), Slot::ROUGHNESS_MAP)); slotBindings.insert(gpu::Shader::Binding(std::string("roughnessMap"), Slot::ROUGHNESS_MAP));
slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), Slot::NORMAL_MAP)); slotBindings.insert(gpu::Shader::Binding(std::string("normalMap"), Slot::NORMAL_MAP));
@ -65,8 +66,6 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
gpu::Shader::makeProgram(*program, slotBindings); gpu::Shader::makeProgram(*program, slotBindings);
auto locations = std::make_shared<Locations>(); auto locations = std::make_shared<Locations>();
locations->texcoordMatrices = program->getUniforms().findLocation("texcoordMatrices");
locations->emissiveParams = program->getUniforms().findLocation("emissiveParams");
locations->normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap"); locations->normalFittingMapUnit = program->getTextures().findLocation("normalFittingMap");
locations->albedoTextureUnit = program->getTextures().findLocation("albedoMap"); locations->albedoTextureUnit = program->getTextures().findLocation("albedoMap");
locations->roughnessTextureUnit = program->getTextures().findLocation("roughnessMap"); locations->roughnessTextureUnit = program->getTextures().findLocation("roughnessMap");
@ -76,6 +75,7 @@ void ShapePlumber::addPipeline(const Filter& filter, const gpu::ShaderPointer& p
locations->occlusionTextureUnit = program->getTextures().findLocation("occlusionMap"); locations->occlusionTextureUnit = program->getTextures().findLocation("occlusionMap");
locations->skinClusterBufferUnit = program->getBuffers().findLocation("skinClusterBuffer"); locations->skinClusterBufferUnit = program->getBuffers().findLocation("skinClusterBuffer");
locations->materialBufferUnit = program->getBuffers().findLocation("materialBuffer"); locations->materialBufferUnit = program->getBuffers().findLocation("materialBuffer");
locations->texMapArrayBufferUnit = program->getBuffers().findLocation("texMapArrayBuffer");
locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer"); locations->lightBufferUnit = program->getBuffers().findLocation("lightBuffer");
ShapeKey key{filter._flags}; ShapeKey key{filter._flags};

View file

@ -193,8 +193,9 @@ class ShapePipeline {
public: public:
class Slot { class Slot {
public: public:
static const int SKINNING_GPU = 2; static const int SKINNING_BUFFER = 2;
static const int MATERIAL_GPU = 3; static const int MATERIAL_BUFFER = 3;
static const int TEXMAPARRAY_BUFFER = 4;
static const int ALBEDO_MAP = 0; static const int ALBEDO_MAP = 0;
static const int NORMAL_MAP = 1; static const int NORMAL_MAP = 1;
static const int METALLIC_MAP = 2; static const int METALLIC_MAP = 2;
@ -202,23 +203,22 @@ public:
static const int ROUGHNESS_MAP = 4; static const int ROUGHNESS_MAP = 4;
static const int OCCLUSION_MAP = 5; static const int OCCLUSION_MAP = 5;
static const int LIGHT_BUFFER = 4; static const int LIGHT_BUFFER = 5;
static const int NORMAL_FITTING_MAP = 10; static const int NORMAL_FITTING_MAP = 10;
}; };
class Locations { class Locations {
public: public:
int texcoordMatrices;
int albedoTextureUnit; int albedoTextureUnit;
int normalTextureUnit; int normalTextureUnit;
int roughnessTextureUnit; int roughnessTextureUnit;
int metallicTextureUnit; int metallicTextureUnit;
int emissiveTextureUnit; int emissiveTextureUnit;
int occlusionTextureUnit; int occlusionTextureUnit;
int emissiveParams;
int normalFittingMapUnit; int normalFittingMapUnit;
int skinClusterBufferUnit; int skinClusterBufferUnit;
int materialBufferUnit; int materialBufferUnit;
int texMapArrayBufferUnit;
int lightBufferUnit; int lightBufferUnit;
}; };
using LocationsPointer = std::shared_ptr<Locations>; using LocationsPointer = std::shared_ptr<Locations>;

View file

@ -147,7 +147,7 @@ GPUIdent* GPUIdent::ensureQuery(const QString& vendor, const QString& renderer)
_isValid = true; _isValid = true;
} }
hr = spEnumInst->Next(WBEM_INFINITE, 1, &spInstance, &uNumOfInstances); hr = spEnumInst->Next(WBEM_INFINITE, 1, &spInstance.p, &uNumOfInstances);
} }
#endif #endif
return this; return this;

View file

@ -564,3 +564,17 @@ void swingTwistDecomposition(const glm::quat& rotation,
// rotation = swing * twist --> swing = rotation * invTwist // rotation = swing * twist --> swing = rotation * invTwist
swing = rotation * glm::inverse(twist); swing = rotation * glm::inverse(twist);
} }
// calculate the minimum angle between a point and a sphere.
float coneSphereAngle(const glm::vec3& coneCenter, const glm::vec3& coneDirection, const glm::vec3& sphereCenter, float sphereRadius) {
glm::vec3 d = sphereCenter - coneCenter;
float dLen = glm::length(d);
// theta is the angle between the coneDirection normal and the center of the sphere.
float theta = acosf(glm::dot(d, coneDirection) / dLen);
// phi is the deflection angle from the center of the sphere to a point tangent to the sphere.
float phi = atanf(sphereRadius / dLen);
return glm::max(0.0f, theta - phi);
}

View file

@ -110,6 +110,8 @@ bool doLineSegmentsIntersect(glm::vec2 r1p1, glm::vec2 r1p2, glm::vec2 r2p1, glm
bool isOnSegment(float xi, float yi, float xj, float yj, float xk, float yk); bool isOnSegment(float xi, float yi, float xj, float yj, float xk, float yk);
int computeDirection(float xi, float yi, float xj, float yj, float xk, float yk); int computeDirection(float xi, float yi, float xj, float yj, float xk, float yk);
// calculate the angle between a point on a sphere that is closest to the cone.
float coneSphereAngle(const glm::vec3& coneCenter, const glm::vec3& coneDirection, const glm::vec3& sphereCenter, float sphereRadius);
typedef glm::vec2 LineSegment2[2]; typedef glm::vec2 LineSegment2[2];

Some files were not shown because too many files have changed in this diff Show more