merge upstream/master -> andrew/inertia
68
examples/avatarCollision.js
Normal file
|
@ -0,0 +1,68 @@
|
|||
//
|
||||
// avatarCollision.js
|
||||
// examples
|
||||
//
|
||||
// Created by Andrew Meadows on 2014-04-09
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Play a sound on collisions with your avatar
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
var SOUND_TRIGGER_CLEAR = 1000; // milliseconds
|
||||
var SOUND_TRIGGER_DELAY = 200; // milliseconds
|
||||
var soundExpiry = 0;
|
||||
var DateObj = new Date();
|
||||
var audioOptions = new AudioInjectionOptions();
|
||||
audioOptions.volume = 0.5;
|
||||
audioOptions.position = { x: 0, y: 0, z: 0 };
|
||||
|
||||
var hitSounds = new Array();
|
||||
hitSounds[0] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit1.raw");
|
||||
hitSounds[1] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit2.raw");
|
||||
hitSounds[2] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit3.raw");
|
||||
hitSounds[3] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit4.raw");
|
||||
hitSounds[4] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit5.raw");
|
||||
hitSounds[5] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit6.raw");
|
||||
hitSounds[6] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit7.raw");
|
||||
hitSounds[7] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit8.raw");
|
||||
hitSounds[8] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit9.raw");
|
||||
hitSounds[9] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit10.raw");
|
||||
hitSounds[10] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit11.raw");
|
||||
hitSounds[11] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit12.raw");
|
||||
hitSounds[12] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit13.raw");
|
||||
hitSounds[13] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit14.raw");
|
||||
hitSounds[14] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit15.raw");
|
||||
hitSounds[15] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit16.raw");
|
||||
hitSounds[16] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit17.raw");
|
||||
hitSounds[17] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit18.raw");
|
||||
hitSounds[18] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit19.raw");
|
||||
hitSounds[19] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit20.raw");
|
||||
hitSounds[20] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit21.raw");
|
||||
hitSounds[21] = new Sound("http://highfidelity-public.s3-us-west-1.amazonaws.com/sounds/Collisions-hitsandslaps/Hit22.raw");
|
||||
|
||||
function playHitSound(mySessionID, theirSessionID, collision) {
|
||||
var now = new Date();
|
||||
var msec = now.getTime();
|
||||
if (msec > soundExpiry) {
|
||||
// this is a new contact --> play a new sound
|
||||
var soundIndex = Math.floor((Math.random() * hitSounds.length) % hitSounds.length);
|
||||
audioOptions.position = collision.contactPoint;
|
||||
Audio.playSound(hitSounds[soundIndex], audioOptions);
|
||||
|
||||
// bump the expiry
|
||||
soundExpiry = msec + SOUND_TRIGGER_CLEAR;
|
||||
|
||||
// log the collision info
|
||||
Uuid.print("my sessionID = ", mySessionID);
|
||||
Uuid.print(" their sessionID = ", theirSessionID);
|
||||
Vec3.print(" penetration = ", collision.penetration);
|
||||
Vec3.print(" contactPoint = ", collision.contactPoint);
|
||||
} else {
|
||||
// this is a recurring contact --> continue to delay sound trigger
|
||||
soundExpiry = msec + SOUND_TRIGGER_DELAY;
|
||||
}
|
||||
}
|
||||
MyAvatar.collisionWithAvatar.connect(playHitSound);
|
274
interface/interface_en.ts
Normal file
|
@ -0,0 +1,274 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!DOCTYPE TS>
|
||||
<TS version="2.1" language="en_US">
|
||||
<context>
|
||||
<name>Application</name>
|
||||
<message>
|
||||
<location filename="src/Application.cpp" line="1380"/>
|
||||
<source>Export Voxels</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/Application.cpp" line="1381"/>
|
||||
<source>Sparse Voxel Octree Files (*.svo)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/Application.cpp" line="3608"/>
|
||||
<source>Open Script</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/Application.cpp" line="3609"/>
|
||||
<source>JavaScript Files (*.js)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>ChatWindow</name>
|
||||
<message>
|
||||
<location filename="ui/chatWindow.ui" line="20"/>
|
||||
<location filename="../build/interface/ui_chatWindow.h" line="143"/>
|
||||
<source>Chat</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/chatWindow.ui" line="50"/>
|
||||
<location filename="../build/interface/ui_chatWindow.h" line="144"/>
|
||||
<source>Connecting to XMPP...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/chatWindow.ui" line="71"/>
|
||||
<location filename="../build/interface/ui_chatWindow.h" line="145"/>
|
||||
<source> online now:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="src/ui/ChatWindow.cpp" line="128"/>
|
||||
<source>day</source>
|
||||
<translation>
|
||||
<numerusform>%n day</numerusform>
|
||||
<numerusform>%n days</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="src/ui/ChatWindow.cpp" line="128"/>
|
||||
<source>hour</source>
|
||||
<translation>
|
||||
<numerusform>%n hour</numerusform>
|
||||
<numerusform>%n hours</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<location filename="src/ui/ChatWindow.cpp" line="128"/>
|
||||
<source>minute</source>
|
||||
<translation>
|
||||
<numerusform>%n minute</numerusform>
|
||||
<numerusform>%n minutes</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message numerus="yes">
|
||||
<source>second</source>
|
||||
<translation type="vanished">
|
||||
<numerusform>%n second</numerusform>
|
||||
<numerusform>%n seconds</numerusform>
|
||||
</translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/ui/ChatWindow.cpp" line="183"/>
|
||||
<source>%1 online now:</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Dialog</name>
|
||||
<message>
|
||||
<location filename="ui/updateDialog.ui" line="20"/>
|
||||
<location filename="ui/updateDialog.ui" line="73"/>
|
||||
<location filename="../build/interface/ui_updateDialog.h" line="137"/>
|
||||
<location filename="../build/interface/ui_updateDialog.h" line="138"/>
|
||||
<source>Update Required</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/updateDialog.ui" line="129"/>
|
||||
<location filename="../build/interface/ui_updateDialog.h" line="140"/>
|
||||
<source>Download</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/updateDialog.ui" line="151"/>
|
||||
<location filename="../build/interface/ui_updateDialog.h" line="141"/>
|
||||
<source>Skip Version</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/updateDialog.ui" line="173"/>
|
||||
<location filename="../build/interface/ui_updateDialog.h" line="142"/>
|
||||
<source>Close</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>Menu</name>
|
||||
<message>
|
||||
<location filename="src/Menu.cpp" line="460"/>
|
||||
<source>Open .ini config file</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/Menu.cpp" line="462"/>
|
||||
<location filename="src/Menu.cpp" line="474"/>
|
||||
<source>Text files (*.ini)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/Menu.cpp" line="472"/>
|
||||
<source>Save .ini config file</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>PreferencesDialog</name>
|
||||
<message>
|
||||
<location filename="ui/preferencesDialog.ui" line="90"/>
|
||||
<location filename="../build/interface/ui_preferencesDialog.h" line="618"/>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/preferencesDialog.ui" line="125"/>
|
||||
<location filename="../build/interface/ui_preferencesDialog.h" line="619"/>
|
||||
<source>Save all changes</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/preferencesDialog.ui" line="196"/>
|
||||
<location filename="ui/preferencesDialog.ui" line="573"/>
|
||||
<location filename="../build/interface/ui_preferencesDialog.h" line="620"/>
|
||||
<location filename="../build/interface/ui_preferencesDialog.h" line="629"/>
|
||||
<source>Avatar</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/preferencesDialog.ui" line="230"/>
|
||||
<location filename="../build/interface/ui_preferencesDialog.h" line="621"/>
|
||||
<source><html><head/><body><p>Avatar display name <span style=" color:#909090;">(optional)</span></p></body></html></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/preferencesDialog.ui" line="266"/>
|
||||
<location filename="../build/interface/ui_preferencesDialog.h" line="622"/>
|
||||
<source>Not showing a name</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/preferencesDialog.ui" line="294"/>
|
||||
<location filename="../build/interface/ui_preferencesDialog.h" line="623"/>
|
||||
<source>Head</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/preferencesDialog.ui" line="395"/>
|
||||
<location filename="../build/interface/ui_preferencesDialog.h" line="625"/>
|
||||
<source>Body</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/preferencesDialog.ui" line="506"/>
|
||||
<location filename="../build/interface/ui_preferencesDialog.h" line="627"/>
|
||||
<source>Advanced Tuning</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/preferencesDialog.ui" line="537"/>
|
||||
<location filename="../build/interface/ui_preferencesDialog.h" line="628"/>
|
||||
<source>It's not recomended that you play with these settings unless you've looked into exactly what they do.</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/preferencesDialog.ui" line="605"/>
|
||||
<location filename="../build/interface/ui_preferencesDialog.h" line="630"/>
|
||||
<source>Vertical field of view</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/preferencesDialog.ui" line="708"/>
|
||||
<location filename="../build/interface/ui_preferencesDialog.h" line="631"/>
|
||||
<source>Lean scale (applies to Faceshift users)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/preferencesDialog.ui" line="793"/>
|
||||
<location filename="../build/interface/ui_preferencesDialog.h" line="632"/>
|
||||
<source>Avatar scale <span style=" color:#909090;">(default is 1.0)</span></source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/preferencesDialog.ui" line="875"/>
|
||||
<location filename="../build/interface/ui_preferencesDialog.h" line="633"/>
|
||||
<source>Pupil dillation</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/preferencesDialog.ui" line="954"/>
|
||||
<location filename="../build/interface/ui_preferencesDialog.h" line="634"/>
|
||||
<source>Audio Jitter Buffer Samples (0 for automatic)</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/preferencesDialog.ui" line="1045"/>
|
||||
<location filename="../build/interface/ui_preferencesDialog.h" line="635"/>
|
||||
<source>Faceshift eye detection</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/preferencesDialog.ui" line="1125"/>
|
||||
<location filename="../build/interface/ui_preferencesDialog.h" line="636"/>
|
||||
<source>Voxels</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/preferencesDialog.ui" line="1157"/>
|
||||
<location filename="../build/interface/ui_preferencesDialog.h" line="637"/>
|
||||
<source>Maximum voxels</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="ui/preferencesDialog.ui" line="1236"/>
|
||||
<location filename="../build/interface/ui_preferencesDialog.h" line="638"/>
|
||||
<source>Max voxels sent each second</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
<name>QObject</name>
|
||||
<message>
|
||||
<location filename="src/ui/ImportDialog.cpp" line="22"/>
|
||||
<location filename="src/ui/ImportDialog.cpp" line="23"/>
|
||||
<source>Import Voxels</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/ui/ImportDialog.cpp" line="24"/>
|
||||
<source>Loading ...</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/ui/ImportDialog.cpp" line="25"/>
|
||||
<source>Place voxels</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/ui/ImportDialog.cpp" line="26"/>
|
||||
<source><b>Import</b> %1 as voxels</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
<message>
|
||||
<location filename="src/ui/ImportDialog.cpp" line="27"/>
|
||||
<source>Cancel</source>
|
||||
<translation type="unfinished"></translation>
|
||||
</message>
|
||||
</context>
|
||||
</TS>
|
98
interface/resources/images/pin.svg
Normal file
|
@ -0,0 +1,98 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="44px"
|
||||
height="44px"
|
||||
viewBox="0 0 44 44"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
sodipodi:docname="close.svg">
|
||||
<metadata
|
||||
id="metadata16">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>Slice 1</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="640"
|
||||
inkscape:window-height="480"
|
||||
id="namedview14"
|
||||
showgrid="false"
|
||||
inkscape:zoom="3.7926636"
|
||||
inkscape:cx="57.156875"
|
||||
inkscape:cy="33.978935"
|
||||
inkscape:window-x="536"
|
||||
inkscape:window-y="258"
|
||||
inkscape:window-maximized="0"
|
||||
inkscape:current-layer="svg2" />
|
||||
<title
|
||||
id="title4">Slice 1</title>
|
||||
<description
|
||||
id="description6">Created with Sketch (http://www.bohemiancoding.com/sketch)</description>
|
||||
<defs
|
||||
id="defs8" />
|
||||
<g
|
||||
id="Page-1"
|
||||
sketch:type="MSPage"
|
||||
transform="translate(0.52733383,0.52733392)"
|
||||
style="fill:none;stroke:none" />
|
||||
<rect
|
||||
id="rect2993"
|
||||
width="5.7796612"
|
||||
height="26.101694"
|
||||
x="19.730724"
|
||||
y="16.374792"
|
||||
ry="3.371469" />
|
||||
<rect
|
||||
id="rect2995"
|
||||
width="35.423729"
|
||||
height="2.9830508"
|
||||
x="4.6290293"
|
||||
y="2.3917408"
|
||||
ry="1.4915254" />
|
||||
<rect
|
||||
id="rect2999"
|
||||
width="31.135593"
|
||||
height="21.067797"
|
||||
x="6.6798768"
|
||||
y="4.0697069"
|
||||
ry="1.4915254" />
|
||||
<rect
|
||||
style="fill:#ff0000"
|
||||
id="rect3003"
|
||||
width="27.779657"
|
||||
height="17.711861"
|
||||
x="8.171401"
|
||||
y="5.3747911"
|
||||
ry="0.46610171" />
|
||||
<rect
|
||||
style="fill:#999999"
|
||||
id="rect3011"
|
||||
width="3.1694915"
|
||||
height="13.983051"
|
||||
x="21.035809"
|
||||
y="25.883266"
|
||||
ry="0.46610171" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.5 KiB |
106
interface/resources/images/pinned.svg
Normal file
|
@ -0,0 +1,106 @@
|
|||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
width="44px"
|
||||
height="44px"
|
||||
viewBox="0 0 44 44"
|
||||
version="1.1"
|
||||
id="svg2"
|
||||
inkscape:version="0.48.3.1 r9886"
|
||||
sodipodi:docname="pin.svg">
|
||||
<metadata
|
||||
id="metadata16">
|
||||
<rdf:RDF>
|
||||
<cc:Work
|
||||
rdf:about="">
|
||||
<dc:format>image/svg+xml</dc:format>
|
||||
<dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
|
||||
<dc:title>Slice 1</dc:title>
|
||||
</cc:Work>
|
||||
</rdf:RDF>
|
||||
</metadata>
|
||||
<sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1058"
|
||||
id="namedview14"
|
||||
showgrid="false"
|
||||
inkscape:zoom="3.7926636"
|
||||
inkscape:cx="39.754857"
|
||||
inkscape:cy="33.978935"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="svg2" />
|
||||
<title
|
||||
id="title4">Slice 1</title>
|
||||
<description
|
||||
id="description6">Created with Sketch (http://www.bohemiancoding.com/sketch)</description>
|
||||
<defs
|
||||
id="defs8" />
|
||||
<g
|
||||
id="Page-1"
|
||||
sketch:type="MSPage"
|
||||
transform="translate(0.52733383,0.52733392)"
|
||||
style="fill:none;stroke:none" />
|
||||
<rect
|
||||
style="fill:#b3b3b3"
|
||||
id="rect3013"
|
||||
width="43.768692"
|
||||
height="44.296078"
|
||||
x="0.26366693"
|
||||
y="-0.032378189"
|
||||
ry="0.46610171" />
|
||||
<rect
|
||||
id="rect2993"
|
||||
width="5.7796612"
|
||||
height="26.101694"
|
||||
x="19.730724"
|
||||
y="16.374792"
|
||||
ry="3.371469" />
|
||||
<rect
|
||||
id="rect2995"
|
||||
width="35.423729"
|
||||
height="2.9830508"
|
||||
x="4.6290293"
|
||||
y="2.3917408"
|
||||
ry="1.4915254" />
|
||||
<rect
|
||||
id="rect2999"
|
||||
width="31.135593"
|
||||
height="21.067797"
|
||||
x="6.6798768"
|
||||
y="4.0697069"
|
||||
ry="1.4915254" />
|
||||
<rect
|
||||
style="fill:#ff0000"
|
||||
id="rect3003"
|
||||
width="27.779657"
|
||||
height="17.711861"
|
||||
x="8.171401"
|
||||
y="5.3747911"
|
||||
ry="0.46610171" />
|
||||
<rect
|
||||
style="fill:#999999"
|
||||
id="rect3011"
|
||||
width="3.1694915"
|
||||
height="13.983051"
|
||||
x="21.035809"
|
||||
y="25.883266"
|
||||
ry="0.46610171" />
|
||||
</svg>
|
After Width: | Height: | Size: 2.7 KiB |
|
@ -1,8 +1,11 @@
|
|||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<qresource prefix="/">
|
||||
<file>styles/search.svg</file>
|
||||
<file>images/close.svg</file>
|
||||
<file>images/kill-script.svg</file>
|
||||
<file>images/reload.svg</file>
|
||||
<file>images/stop.svg</file>
|
||||
<file>images/pin.svg</file>
|
||||
<file>images/pinned.svg</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
|
27
interface/resources/styles/avatar.svg
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 20.6 25.5" enable-background="new 0 0 20.6 25.5" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#0E7077" d="M18,11.8c0.3-1.1,0.1-2.1-0.3-2.2c-0.4-0.1-0.9,0.8-1.2,1.9c-0.1-1-0.1-1.8,0-2.4l0,0
|
||||
c-1.3-0.4-2.4-1.5-3.1-2.7c-0.6,1.1-2,2.3-3.8,3.4c-0.1,0-0.2,0.1-0.2,0.1c1,0.9,0.6,1.6-0.6,0.3c-0.3,0.2-0.6,0.3-0.9,0.4
|
||||
c0.2,0,0.4,0.1,0.7,0.1c0.9,0.3,1.1,0.7,1.3,1.4c-0.2-0.3-0.5-0.6-0.9-0.8c0,0.1,0.1,0.2,0.1,0.3c0,0.3-0.3,0.6-0.6,0.6
|
||||
c-0.3,0-0.6-0.3-0.6-0.6c0-0.2,0.1-0.4,0.3-0.5c-0.3,0-0.6,0-1.1,0c0.2,0.3,0.3,0.8,0.7,1.1c-0.5-0.2-0.9-0.7-1.2-1.2
|
||||
c-0.3,0.1-0.6,0.2-0.9,0.2c-0.6,0.1-1.1,0.1-1.5,0c0,0.1,0,0.3,0.1,0.4c0.3,1.1,0.8,2,1.2,1.9c0.2,0,0.3-0.3,0.4-0.7
|
||||
c0.1,0.7,0.2,1.5,0.3,2.4c0.2,1.8,4.2,4.8,4.2,4.8h1.5c0,0,4-3.1,4.2-4.8c0.1-0.9,0.2-1.8,0.3-2.4c0.1,0.4,0.2,0.6,0.4,0.7
|
||||
C17.2,13.8,17.7,12.9,18,11.8L18,11.8z M8.4,11.6c0,0.1,0.1,0.2,0.2,0.2c0.1,0,0.2-0.1,0.2-0.2c0-0.1-0.1-0.2-0.2-0.2
|
||||
C8.5,11.4,8.4,11.5,8.4,11.6L8.4,11.6z M7.8,1.1c3.4-1.7,6.4-1.4,6.9,0.7c0.7-0.5,1.3-0.6,2-0.3c2.6,1.4,3.8,9.8,3.9,18.8
|
||||
c0,1.8,0,3.3,0,4.7c-1.8-0.5-4.2-1.3-4.7-1.6c-1.3-0.6-1.6-3.1-1.6-5c-0.9,0.9-1.9,1.7-2.4,2h-1.7c0,0-1.1-0.8-2.1-1.8
|
||||
c-0.1-0.1-0.2-0.2-0.3-0.3c0,1.9-0.2,4.4-1.5,5.1c-0.7,0.3-4.7,1.6-6.2,2C0.3,13.9,1.7,4.2,7.8,1.1L7.8,1.1z M12,18
|
||||
C12.1,17.9,12.1,17.9,12,18c0-0.1,0-0.2,0-0.2c0,0-0.1,0.1-0.1,0.1C11.9,17.9,12,18,12,18L12,18z M11.8,18c0,0,0.1-0.1,0.1-0.1
|
||||
c0,0-0.1-0.1-0.1-0.1l-0.1,0c0,0-0.1,0.1-0.1,0.1C11.7,18.1,11.7,18.1,11.8,18L11.8,18L11.8,18z M11,17.4L11,17.4
|
||||
c0.5,0,1-0.3,0.6-0.3H11h-0.6C10,17.1,10.5,17.4,11,17.4L11,17.4z M12.6,16.6c0.4,0.1,0.8,0,0.7,0c-0.1,0.1-0.6,0.5-0.6,0.5l0,0.1
|
||||
c0,0.6-0.7,1.2-1.7,1.2c-0.9,0-1.7-0.5-1.7-1.2l0-0.1c0,0-0.5-0.4-0.6-0.5c0,0,0.3,0.2,0.7,0c1-0.3,1.4-0.1,1.6,0.1
|
||||
C11.2,16.5,11.6,16.3,12.6,16.6L12.6,16.6z M13.5,10.9c1-0.3,1.4,0.1,2.3-0.4c0,0-0.5,1.6-1.5,1.9c0.4-0.3,0.6-0.8,0.7-1.1
|
||||
c-0.4,0-0.7-0.1-1.1,0c0.2,0.1,0.3,0.3,0.3,0.5c0,0.3-0.3,0.6-0.6,0.6c-0.3,0-0.6-0.3-0.6-0.6c0-0.1,0-0.2,0.1-0.3
|
||||
c-0.4,0.2-0.7,0.5-0.9,0.8C12.5,11.6,12.7,11.2,13.5,10.9L13.5,10.9z M14.1,11.6c0-0.1-0.1-0.2-0.2-0.2c-0.1,0-0.2,0.1-0.2,0.2
|
||||
c0,0.1,0.1,0.2,0.2,0.2C14,11.8,14.1,11.7,14.1,11.6L14.1,11.6z M14,9c1.2-0.6,1.8,0.4,1.8,0.4s-1.2-0.8-2.1,0.3
|
||||
C11.8,12.2,11.3,10.5,14,9L14,9z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 2.6 KiB |
14
interface/resources/styles/close.svg
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 15.9 15.9" enable-background="new 0 0 15.9 15.9" xml:space="preserve">
|
||||
<g>
|
||||
<g>
|
||||
<path fill="#666666" d="M15.5,13.7l-1.8,1.8c-0.2,0.2-0.6,0.4-0.9,0.4s-0.7-0.1-0.9-0.4L8,11.6L4,15.5c-0.2,0.2-0.6,0.4-0.9,0.4
|
||||
s-0.7-0.1-0.9-0.4l-1.8-1.8C0.1,13.5,0,13.1,0,12.8s0.1-0.7,0.4-0.9L4.3,8L0.4,4C0.1,3.8,0,3.4,0,3.1s0.1-0.7,0.4-0.9l1.8-1.8
|
||||
C2.4,0.1,2.8,0,3.1,0S3.8,0.1,4,0.4L8,4.3l3.9-3.9C12.1,0.1,12.5,0,12.8,0s0.7,0.1,0.9,0.4l1.8,1.8c0.2,0.2,0.4,0.6,0.4,0.9
|
||||
S15.8,3.8,15.5,4L11.6,8l3.9,3.9c0.2,0.2,0.4,0.6,0.4,0.9S15.8,13.5,15.5,13.7z"/>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 944 B |
9
interface/resources/styles/down.svg
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 13.9 8.8" enable-background="new 0 0 13.9 8.8" xml:space="preserve">
|
||||
<path fill="#666666" d="M13.6,2.6L7.8,8.4C7.6,8.6,7.3,8.8,7,8.8S6.4,8.6,6.2,8.4L0.3,2.6C0.1,2.4,0,2.1,0,1.8S0.1,1.2,0.3,1L1,0.3
|
||||
C1.2,0.1,1.5,0,1.8,0s0.6,0.1,0.8,0.3L7,4.7l4.3-4.3C11.5,0.1,11.8,0,12.1,0s0.6,0.1,0.8,0.3L13.6,1c0.2,0.2,0.3,0.5,0.3,0.8
|
||||
S13.8,2.4,13.6,2.6z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 733 B |
113
interface/resources/styles/global.qss
Normal file
|
@ -0,0 +1,113 @@
|
|||
* {
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
FramelessDialog {
|
||||
font-family: Helvetica, Arial, sans-serif;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
QLineEdit {
|
||||
background-color: rgba(255, 255, 255, 1);
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: #ccc;
|
||||
padding: 8px;
|
||||
font-size: 16px;
|
||||
color: rgb(51, 51, 51);
|
||||
}
|
||||
|
||||
QLabel p {
|
||||
color: #0e7077;
|
||||
font-size: 23px;
|
||||
}
|
||||
|
||||
QPushButton {
|
||||
border-width: 0;
|
||||
border-radius: 9px;
|
||||
font-family: Arial;
|
||||
font-size: 18px;
|
||||
color: #ffffff;
|
||||
padding: 10px 0px;
|
||||
}
|
||||
|
||||
QSpinBox, QDoubleSpinBox {
|
||||
padding: 5px;
|
||||
border-width: 1;
|
||||
font-size: 16px;
|
||||
color: rgb(51, 51, 51);
|
||||
}
|
||||
|
||||
QDoubleSpinBox::up-arrow,
|
||||
QSpinBox::up-arrow {
|
||||
background-image: url(styles/up.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
QDoubleSpinBox::down-arrow,
|
||||
QSpinBox::down-arrow {
|
||||
background-image: url(styles/down.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
QDoubleSpinBox::up-button,
|
||||
QSpinBox::up-button,
|
||||
QDoubleSpinBox::down-button,
|
||||
QSpinBox::down-button {
|
||||
width: 26px;
|
||||
height: 13px;
|
||||
|
||||
background-color: #f2f2f2;
|
||||
border-color: #ccc;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
QDoubleSpinBox::up-button,
|
||||
QSpinBox::up-button {
|
||||
|
||||
margin-top:2px;
|
||||
border-top-left-radius: 4px;
|
||||
border-top-right-radius: 4px;
|
||||
}
|
||||
|
||||
QDoubleSpinBox::down-button,
|
||||
QSpinBox::down-button {
|
||||
margin-bottom:3px;
|
||||
border-bottom-left-radius: 4px;
|
||||
border-bottom-right-radius: 4px;
|
||||
}
|
||||
|
||||
QSlider {
|
||||
width: 125px;
|
||||
height: 18px;
|
||||
}
|
||||
|
||||
QSlider::groove:horizontal {
|
||||
border: none;
|
||||
background-image: url(styles/slider-bg.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
QSlider::handle:horizontal {
|
||||
width: 18px;
|
||||
height: 18px;
|
||||
background-image: url(styles/slider-handle.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
}
|
||||
|
||||
QPushButton#closeButton {
|
||||
border-color: #ccc;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-radius: 0;
|
||||
background-color: #fff;
|
||||
background-image: url(styles/close.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
}
|
21
interface/resources/styles/preferences.qss
Normal file
|
@ -0,0 +1,21 @@
|
|||
QLabel#avatarLabel {
|
||||
background-image: url(styles/avatar.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-position: left center;
|
||||
}
|
||||
|
||||
QLabel#advancedTuningLabel {
|
||||
background-image: url(styles/wrench.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-position: left center;
|
||||
}
|
||||
|
||||
QPushButton#buttonBrowseHead,
|
||||
QPushButton#buttonBrowseBody {
|
||||
background-image: url(styles/search.svg);
|
||||
background-repeat: no-repeat;
|
||||
background-position: center center;
|
||||
background-color: #fff;
|
||||
border-radius: 0;
|
||||
padding: 0;
|
||||
}
|
10
interface/resources/styles/slider-bg.svg
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 125 9" enable-background="new 0 0 125 9" xml:space="preserve">
|
||||
<g>
|
||||
<path fill="#CCCCCC" d="M120.5,9H4.5C2,9,0,7,0,4.5S2,0,4.5,0h116c2.5,0,4.5,2,4.5,4.5S123,9,120.5,9z M4.5,1C2.6,1,1,2.6,1,4.5
|
||||
S2.6,8,4.5,8h116c1.9,0,3.5-1.6,3.5-3.5S122.4,1,120.5,1H4.5z"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 654 B |
10
interface/resources/styles/slider-handle.svg
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 17 17" enable-background="new 0 0 17 17" xml:space="preserve">
|
||||
<g>
|
||||
<circle fill="#0E7077" cx="8.5" cy="8.5" r="8.5"/>
|
||||
<circle fill="#669999" cx="8.5" cy="8.5" r="5.5"/>
|
||||
</g>
|
||||
</svg>
|
After Width: | Height: | Size: 567 B |
9
interface/resources/styles/up.svg
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 13.9 8.8" enable-background="new 0 0 13.9 8.8" xml:space="preserve">
|
||||
<path fill="#666666" d="M13.6,7.8l-0.7,0.7c-0.2,0.2-0.5,0.3-0.8,0.3s-0.6-0.1-0.8-0.3L7,4.1L2.6,8.4C2.4,8.6,2.1,8.8,1.8,8.8
|
||||
S1.2,8.6,1,8.4L0.3,7.8C0.1,7.6,0,7.3,0,7s0.1-0.6,0.3-0.8l5.8-5.8C6.4,0.1,6.6,0,7,0s0.6,0.1,0.8,0.3l5.8,5.8
|
||||
c0.2,0.2,0.3,0.5,0.3,0.8S13.8,7.6,13.6,7.8z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 738 B |
9
interface/resources/styles/wrench.svg
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Generator: Adobe Illustrator 17.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
|
||||
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
|
||||
viewBox="0 0 19.2 19.9" enable-background="new 0 0 19.2 19.9" xml:space="preserve">
|
||||
<path fill="#0E7077" d="M1.3,7.7C2.6,9,4.5,9.3,6.1,8.6l10.4,10.8c0.6,0.6,1.6,0.6,2.2,0c0.6-0.6,0.6-1.7,0-2.3L8.3,6.3
|
||||
c0.7-1.6,0.4-3.6-0.9-5c-1.1-1.1-2.6-1.5-4-1.2L4,0.8l0.7,0.7L6,2.8L5.3,5.5L4,5.9L2.7,6.2l-1-1L1.4,4.9L0.1,3.5
|
||||
C-0.2,5,0.2,6.5,1.3,7.7z M16.6,18.2c0-0.6,0.4-1,0.9-1c0.5,0,0.9,0.5,0.9,1c0,0.6-0.4,1-0.9,1C17,19.2,16.6,18.7,16.6,18.2z"/>
|
||||
</svg>
|
After Width: | Height: | Size: 813 B |
|
@ -151,6 +151,7 @@ Application::Application(int& argc, char** argv, timeval &startup_time) :
|
|||
_lastQueriedViewFrustum(),
|
||||
_lastQueriedTime(usecTimestampNow()),
|
||||
_mirrorViewRect(QRect(MIRROR_VIEW_LEFT_PADDING, MIRROR_VIEW_TOP_PADDING, MIRROR_VIEW_WIDTH, MIRROR_VIEW_HEIGHT)),
|
||||
_cameraPushback(0.0f),
|
||||
_mouseX(0),
|
||||
_mouseY(0),
|
||||
_lastMouseMove(usecTimestampNow()),
|
||||
|
@ -521,6 +522,8 @@ void Application::paintGL() {
|
|||
|
||||
glEnable(GL_LINE_SMOOTH);
|
||||
|
||||
float pushback = 0.0f;
|
||||
float pushbackFocalLength = 0.0f;
|
||||
if (OculusManager::isConnected()) {
|
||||
_myCamera.setUpShift(0.0f);
|
||||
_myCamera.setDistance(0.0f);
|
||||
|
@ -533,6 +536,41 @@ void Application::paintGL() {
|
|||
_myCamera.setTargetPosition(_myAvatar->getHead()->calculateAverageEyePosition());
|
||||
_myCamera.setTargetRotation(_myAvatar->getHead()->getCameraOrientation());
|
||||
|
||||
glm::vec3 planeNormal = _myCamera.getTargetRotation() * IDENTITY_FRONT;
|
||||
const float BASE_PUSHBACK_RADIUS = 0.25f;
|
||||
float pushbackRadius = _myCamera.getNearClip() + _myAvatar->getScale() * BASE_PUSHBACK_RADIUS;
|
||||
glm::vec4 plane(planeNormal, -glm::dot(planeNormal, _myCamera.getTargetPosition()) - pushbackRadius);
|
||||
|
||||
// push camera out of any intersecting avatars
|
||||
foreach (const AvatarSharedPointer& avatarData, _avatarManager.getAvatarHash()) {
|
||||
Avatar* avatar = static_cast<Avatar*>(avatarData.data());
|
||||
if (avatar->isMyAvatar()) {
|
||||
continue;
|
||||
}
|
||||
if (glm::distance(avatar->getPosition(), _myCamera.getTargetPosition()) >
|
||||
avatar->getBoundingRadius() + pushbackRadius) {
|
||||
continue;
|
||||
}
|
||||
float angle = angleBetween(avatar->getPosition() - _myCamera.getTargetPosition(), planeNormal);
|
||||
if (angle > PI_OVER_TWO) {
|
||||
continue;
|
||||
}
|
||||
float scale = 1.0f - angle / PI_OVER_TWO;
|
||||
scale = qMin(1.0f, scale * 2.5f);
|
||||
static CollisionList collisions(64);
|
||||
collisions.clear();
|
||||
if (!avatar->findPlaneCollisions(plane, collisions)) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < collisions.size(); i++) {
|
||||
pushback = qMax(pushback, glm::length(collisions.getCollision(i)->_penetration) * scale);
|
||||
}
|
||||
}
|
||||
const float MAX_PUSHBACK = 0.35f;
|
||||
pushback = qMin(pushback, MAX_PUSHBACK * _myAvatar->getScale());
|
||||
const float BASE_PUSHBACK_FOCAL_LENGTH = 0.5f;
|
||||
pushbackFocalLength = BASE_PUSHBACK_FOCAL_LENGTH * _myAvatar->getScale();
|
||||
|
||||
} else if (_myCamera.getMode() == CAMERA_MODE_THIRD_PERSON) {
|
||||
_myCamera.setTightness(0.0f); // Camera is directly connected to head without smoothing
|
||||
_myCamera.setTargetPosition(_myAvatar->getUprightHeadPosition());
|
||||
|
@ -549,13 +587,26 @@ void Application::paintGL() {
|
|||
// if the head would intersect the near clip plane, we must push the camera out
|
||||
glm::vec3 relativePosition = glm::inverse(_myCamera.getTargetRotation()) *
|
||||
(eyePosition - _myCamera.getTargetPosition());
|
||||
const float PUSHBACK_RADIUS = 0.2f;
|
||||
float pushback = relativePosition.z + _myCamera.getNearClip() +
|
||||
_myAvatar->getScale() * PUSHBACK_RADIUS - _myCamera.getDistance();
|
||||
if (pushback > 0.0f) {
|
||||
const float BASE_PUSHBACK_RADIUS = 0.2f;
|
||||
float pushbackRadius = _myCamera.getNearClip() + _myAvatar->getScale() * BASE_PUSHBACK_RADIUS;
|
||||
pushback = relativePosition.z + pushbackRadius - _myCamera.getDistance();
|
||||
pushbackFocalLength = _myCamera.getDistance();
|
||||
}
|
||||
|
||||
// handle pushback, if any
|
||||
if (pushbackFocalLength > 0.0f) {
|
||||
const float PUSHBACK_DECAY = 0.5f;
|
||||
_cameraPushback = qMax(pushback, _cameraPushback * PUSHBACK_DECAY);
|
||||
if (_cameraPushback > EPSILON) {
|
||||
_myCamera.setTargetPosition(_myCamera.getTargetPosition() +
|
||||
_myCamera.getTargetRotation() * glm::vec3(0.0f, 0.0f, pushback));
|
||||
_myCamera.getTargetRotation() * glm::vec3(0.0f, 0.0f, _cameraPushback));
|
||||
float enlargement = pushbackFocalLength / (pushbackFocalLength + _cameraPushback);
|
||||
_myCamera.setFieldOfView(glm::degrees(2.0f * atanf(enlargement * tanf(
|
||||
glm::radians(Menu::getInstance()->getFieldOfView() * 0.5f)))));
|
||||
} else {
|
||||
_myCamera.setFieldOfView(Menu::getInstance()->getFieldOfView());
|
||||
}
|
||||
updateProjectionMatrix(_myCamera, true);
|
||||
}
|
||||
|
||||
// Update camera position
|
||||
|
@ -2563,6 +2614,12 @@ void Application::displayOverlay() {
|
|||
}
|
||||
|
||||
bool isClipping = ((_audio.getTimeSinceLastClip() > 0.f) && (_audio.getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME));
|
||||
|
||||
if ((_audio.getTimeSinceLastClip() > 0.f) && (_audio.getTimeSinceLastClip() < CLIPPING_INDICATOR_TIME)) {
|
||||
const float MAX_MAGNITUDE = 0.7f;
|
||||
float magnitude = MAX_MAGNITUDE * (1 - _audio.getTimeSinceLastClip() / CLIPPING_INDICATOR_TIME);
|
||||
renderCollisionOverlay(_glWidget->width(), _glWidget->height(), magnitude, 1.0f);
|
||||
}
|
||||
|
||||
_audio.renderToolBox(MIRROR_VIEW_LEFT_PADDING + AUDIO_METER_GAP,
|
||||
audioMeterY,
|
||||
|
|
|
@ -435,6 +435,7 @@ private:
|
|||
QRect _mirrorViewRect;
|
||||
RearMirrorTools* _rearMirrorTools;
|
||||
|
||||
float _cameraPushback;
|
||||
glm::mat4 _untranslatedViewMatrix;
|
||||
glm::vec3 _viewMatrixTranslation;
|
||||
glm::mat4 _projectionMatrix;
|
||||
|
|
|
@ -86,7 +86,8 @@ Menu::Menu() :
|
|||
_lastAvatarDetailDrop(usecTimestampNow()),
|
||||
_fpsAverage(FIVE_SECONDS_OF_FRAMES),
|
||||
_fastFPSAverage(ONE_SECOND_OF_FRAMES),
|
||||
_loginAction(NULL)
|
||||
_loginAction(NULL),
|
||||
_preferencesDialog(NULL)
|
||||
{
|
||||
Application *appInstance = Application::getInstance();
|
||||
|
||||
|
@ -708,7 +709,12 @@ bool Menu::isOptionChecked(const QString& menuOption) {
|
|||
}
|
||||
|
||||
void Menu::triggerOption(const QString& menuOption) {
|
||||
_actionHash.value(menuOption)->trigger();
|
||||
QAction* action = _actionHash.value(menuOption);
|
||||
if (action) {
|
||||
action->trigger();
|
||||
} else {
|
||||
qDebug() << "NULL Action for menuOption '" << menuOption << "'";
|
||||
}
|
||||
}
|
||||
|
||||
QAction* Menu::getActionForOption(const QString& menuOption) {
|
||||
|
@ -767,165 +773,12 @@ void Menu::loginForCurrentDomain() {
|
|||
}
|
||||
|
||||
void Menu::editPreferences() {
|
||||
Application* applicationInstance = Application::getInstance();
|
||||
ModelsBrowser headBrowser(Head);
|
||||
ModelsBrowser skeletonBrowser(Skeleton);
|
||||
|
||||
const QString BROWSE_BUTTON_TEXT = "Browse";
|
||||
|
||||
QDialog dialog(applicationInstance->getWindow());
|
||||
dialog.setWindowTitle("Interface Preferences");
|
||||
|
||||
QBoxLayout* layout = new QBoxLayout(QBoxLayout::TopToBottom);
|
||||
dialog.setLayout(layout);
|
||||
|
||||
QFormLayout* form = new QFormLayout();
|
||||
layout->addLayout(form, 1);
|
||||
|
||||
|
||||
QHBoxLayout headModelLayout;
|
||||
QString faceURLString = applicationInstance->getAvatar()->getHead()->getFaceModel().getURL().toString();
|
||||
QLineEdit headURLEdit(faceURLString);
|
||||
QPushButton headBrowseButton(BROWSE_BUTTON_TEXT);
|
||||
connect(&headBrowseButton, SIGNAL(clicked()), &headBrowser, SLOT(browse()));
|
||||
connect(&headBrowser, SIGNAL(selected(QString)), &headURLEdit, SLOT(setText(QString)));
|
||||
headURLEdit.setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
||||
headURLEdit.setPlaceholderText(DEFAULT_HEAD_MODEL_URL.toString());
|
||||
headModelLayout.addWidget(&headURLEdit);
|
||||
headModelLayout.addWidget(&headBrowseButton);
|
||||
form->addRow("Head URL:", &headModelLayout);
|
||||
|
||||
QHBoxLayout skeletonModelLayout;
|
||||
QString skeletonURLString = applicationInstance->getAvatar()->getSkeletonModel().getURL().toString();
|
||||
QLineEdit skeletonURLEdit(skeletonURLString);
|
||||
QPushButton SkeletonBrowseButton(BROWSE_BUTTON_TEXT);
|
||||
connect(&SkeletonBrowseButton, SIGNAL(clicked()), &skeletonBrowser, SLOT(browse()));
|
||||
connect(&skeletonBrowser, SIGNAL(selected(QString)), &skeletonURLEdit, SLOT(setText(QString)));
|
||||
skeletonURLEdit.setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
||||
skeletonURLEdit.setPlaceholderText(DEFAULT_BODY_MODEL_URL.toString());
|
||||
skeletonModelLayout.addWidget(&skeletonURLEdit);
|
||||
skeletonModelLayout.addWidget(&SkeletonBrowseButton);
|
||||
form->addRow("Skeleton URL:", &skeletonModelLayout);
|
||||
|
||||
|
||||
QString displayNameString = applicationInstance->getAvatar()->getDisplayName();
|
||||
QLineEdit* displayNameEdit = new QLineEdit(displayNameString);
|
||||
displayNameEdit->setMinimumWidth(QLINE_MINIMUM_WIDTH);
|
||||
form->addRow("Display name:", displayNameEdit);
|
||||
|
||||
QSlider* pupilDilation = new QSlider(Qt::Horizontal);
|
||||
pupilDilation->setValue(applicationInstance->getAvatar()->getHead()->getPupilDilation() * pupilDilation->maximum());
|
||||
form->addRow("Pupil Dilation:", pupilDilation);
|
||||
|
||||
QSlider* faceshiftEyeDeflection = new QSlider(Qt::Horizontal);
|
||||
faceshiftEyeDeflection->setValue(_faceshiftEyeDeflection * faceshiftEyeDeflection->maximum());
|
||||
form->addRow("Faceshift Eye Deflection:", faceshiftEyeDeflection);
|
||||
|
||||
QSpinBox* fieldOfView = new QSpinBox();
|
||||
fieldOfView->setMaximum(180.f);
|
||||
fieldOfView->setMinimum(1.f);
|
||||
fieldOfView->setValue(_fieldOfView);
|
||||
form->addRow("Vertical Field of View (Degrees):", fieldOfView);
|
||||
|
||||
QDoubleSpinBox* leanScale = new QDoubleSpinBox();
|
||||
leanScale->setValue(applicationInstance->getAvatar()->getLeanScale());
|
||||
form->addRow("Lean Scale:", leanScale);
|
||||
|
||||
QDoubleSpinBox* avatarScale = new QDoubleSpinBox();
|
||||
avatarScale->setValue(applicationInstance->getAvatar()->getScale());
|
||||
form->addRow("Avatar Scale:", avatarScale);
|
||||
|
||||
QSpinBox* audioJitterBufferSamples = new QSpinBox();
|
||||
audioJitterBufferSamples->setMaximum(10000);
|
||||
audioJitterBufferSamples->setMinimum(-10000);
|
||||
audioJitterBufferSamples->setValue(_audioJitterBufferSamples);
|
||||
form->addRow("Audio Jitter Buffer Samples (0 for automatic):", audioJitterBufferSamples);
|
||||
|
||||
QSpinBox* maxVoxels = new QSpinBox();
|
||||
const int MAX_MAX_VOXELS = 5000000;
|
||||
const int MIN_MAX_VOXELS = 0;
|
||||
const int STEP_MAX_VOXELS = 50000;
|
||||
maxVoxels->setMaximum(MAX_MAX_VOXELS);
|
||||
maxVoxels->setMinimum(MIN_MAX_VOXELS);
|
||||
maxVoxels->setSingleStep(STEP_MAX_VOXELS);
|
||||
maxVoxels->setValue(_maxVoxels);
|
||||
form->addRow("Maximum Voxels:", maxVoxels);
|
||||
|
||||
QSpinBox* maxVoxelsPPS = new QSpinBox();
|
||||
const int MAX_MAX_VOXELS_PPS = 6000;
|
||||
const int MIN_MAX_VOXELS_PPS = 60;
|
||||
const int STEP_MAX_VOXELS_PPS = 10;
|
||||
maxVoxelsPPS->setMaximum(MAX_MAX_VOXELS_PPS);
|
||||
maxVoxelsPPS->setMinimum(MIN_MAX_VOXELS_PPS);
|
||||
maxVoxelsPPS->setSingleStep(STEP_MAX_VOXELS_PPS);
|
||||
maxVoxelsPPS->setValue(_maxVoxelPacketsPerSecond);
|
||||
form->addRow("Maximum Voxels Packets Per Second:", maxVoxelsPPS);
|
||||
|
||||
QDialogButtonBox* buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
dialog.connect(buttons, SIGNAL(accepted()), SLOT(accept()));
|
||||
dialog.connect(buttons, SIGNAL(rejected()), SLOT(reject()));
|
||||
layout->addWidget(buttons);
|
||||
|
||||
int ret = dialog.exec();
|
||||
if (ret == QDialog::Accepted) {
|
||||
bool shouldDispatchIdentityPacket = false;
|
||||
|
||||
if (headURLEdit.text() != faceURLString) {
|
||||
// change the faceModelURL in the profile, it will also update this user's BlendFace
|
||||
if (headURLEdit.text().isEmpty()) {
|
||||
applicationInstance->getAvatar()->setFaceModelURL(QUrl(headURLEdit.placeholderText()));
|
||||
} else {
|
||||
applicationInstance->getAvatar()->setFaceModelURL(QUrl(headURLEdit.text()));
|
||||
}
|
||||
shouldDispatchIdentityPacket = true;
|
||||
}
|
||||
|
||||
if (skeletonURLEdit.text() != skeletonURLString) {
|
||||
// change the skeletonModelURL in the profile, it will also update this user's Body
|
||||
if (skeletonURLEdit.text().isEmpty()) {
|
||||
applicationInstance->getAvatar()->setSkeletonModelURL(QUrl(skeletonURLEdit.placeholderText()));
|
||||
} else {
|
||||
applicationInstance->getAvatar()->setSkeletonModelURL(QUrl(skeletonURLEdit.text()));
|
||||
}
|
||||
shouldDispatchIdentityPacket = true;
|
||||
}
|
||||
|
||||
QString displayNameStr(displayNameEdit->text());
|
||||
|
||||
if (displayNameStr != displayNameString) {
|
||||
applicationInstance->getAvatar()->setDisplayName(displayNameStr);
|
||||
shouldDispatchIdentityPacket = true;
|
||||
}
|
||||
|
||||
if (shouldDispatchIdentityPacket) {
|
||||
applicationInstance->getAvatar()->sendIdentityPacket();
|
||||
applicationInstance->bumpSettings();
|
||||
}
|
||||
|
||||
applicationInstance->getAvatar()->getHead()->setPupilDilation(pupilDilation->value() / (float)pupilDilation->maximum());
|
||||
|
||||
_maxVoxels = maxVoxels->value();
|
||||
applicationInstance->getVoxels()->setMaxVoxels(_maxVoxels);
|
||||
|
||||
_maxVoxelPacketsPerSecond = maxVoxelsPPS->value();
|
||||
|
||||
applicationInstance->getAvatar()->setLeanScale(leanScale->value());
|
||||
applicationInstance->getAvatar()->setClampedTargetScale(avatarScale->value());
|
||||
|
||||
_audioJitterBufferSamples = audioJitterBufferSamples->value();
|
||||
|
||||
if (_audioJitterBufferSamples != 0) {
|
||||
applicationInstance->getAudio()->setJitterBufferSamples(_audioJitterBufferSamples);
|
||||
}
|
||||
|
||||
_fieldOfView = fieldOfView->value();
|
||||
applicationInstance->resizeGL(applicationInstance->getGLWidget()->width(), applicationInstance->getGLWidget()->height());
|
||||
|
||||
_faceshiftEyeDeflection = faceshiftEyeDeflection->value() / (float)faceshiftEyeDeflection->maximum();
|
||||
if (!_preferencesDialog) {
|
||||
_preferencesDialog = new PreferencesDialog(Application::getInstance()->getWindow());
|
||||
_preferencesDialog->show();
|
||||
} else {
|
||||
_preferencesDialog->close();
|
||||
}
|
||||
QMetaObject::invokeMethod(applicationInstance->getAudio(), "reset", Qt::QueuedConnection);
|
||||
|
||||
sendFakeEnterEvent();
|
||||
}
|
||||
|
||||
void Menu::goToDomain(const QString newDomain) {
|
||||
|
@ -1208,7 +1061,7 @@ void Menu::showMetavoxelEditor() {
|
|||
void Menu::showChat() {
|
||||
QMainWindow* mainWindow = Application::getInstance()->getWindow();
|
||||
if (!_chatWindow) {
|
||||
mainWindow->addDockWidget(Qt::NoDockWidgetArea, _chatWindow = new ChatWindow());
|
||||
mainWindow->addDockWidget(Qt::RightDockWidgetArea, _chatWindow = new ChatWindow());
|
||||
}
|
||||
if (!_chatWindow->toggleViewAction()->isChecked()) {
|
||||
int width = _chatWindow->width();
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
#include <OctreeConstants.h>
|
||||
|
||||
#include "location/LocationManager.h"
|
||||
#include "ui/PreferencesDialog.h"
|
||||
#include "ui/ChatWindow.h"
|
||||
|
||||
const float ADJUST_LOD_DOWN_FPS = 40.0;
|
||||
|
@ -71,10 +72,13 @@ public:
|
|||
|
||||
void triggerOption(const QString& menuOption);
|
||||
QAction* getActionForOption(const QString& menuOption);
|
||||
|
||||
|
||||
float getAudioJitterBufferSamples() const { return _audioJitterBufferSamples; }
|
||||
void setAudioJitterBufferSamples(float audioJitterBufferSamples) { _audioJitterBufferSamples = audioJitterBufferSamples; }
|
||||
float getFieldOfView() const { return _fieldOfView; }
|
||||
void setFieldOfView(float fieldOfView) { _fieldOfView = fieldOfView; }
|
||||
float getFaceshiftEyeDeflection() const { return _faceshiftEyeDeflection; }
|
||||
void setFaceshiftEyeDeflection(float faceshiftEyeDeflection) { _faceshiftEyeDeflection = faceshiftEyeDeflection; }
|
||||
BandwidthDialog* getBandwidthDialog() const { return _bandwidthDialog; }
|
||||
FrustumDrawMode getFrustumDrawMode() const { return _frustumDrawMode; }
|
||||
ViewFrustumOffset getViewFrustumOffset() const { return _viewFrustumOffset; }
|
||||
|
@ -97,6 +101,7 @@ public:
|
|||
|
||||
// User Tweakable PPS from Voxel Server
|
||||
int getMaxVoxelPacketsPerSecond() const { return _maxVoxelPacketsPerSecond; }
|
||||
void setMaxVoxelPacketsPerSecond(int maxVoxelPacketsPerSecond) { _maxVoxelPacketsPerSecond = maxVoxelPacketsPerSecond; }
|
||||
|
||||
QAction* addActionToQMenuAndActionHash(QMenu* destinationMenu,
|
||||
const QString& actionName,
|
||||
|
@ -222,6 +227,7 @@ private:
|
|||
SimpleMovingAverage _fpsAverage;
|
||||
SimpleMovingAverage _fastFPSAverage;
|
||||
QAction* _loginAction;
|
||||
QPointer<PreferencesDialog> _preferencesDialog;
|
||||
QAction* _chatAction;
|
||||
};
|
||||
|
||||
|
|
|
@ -307,13 +307,13 @@ bool ModelUploader::addTextures(const QString& texdir, const QString fbxFile) {
|
|||
foreach (FBXMesh mesh, geometry.meshes) {
|
||||
foreach (FBXMeshPart part, mesh.parts) {
|
||||
if (!part.diffuseFilename.isEmpty()) {
|
||||
if (!addPart(QFileInfo(fbxFile).path() + "/" + part.diffuseFilename,
|
||||
if (!addPart(texdir + "/" + part.diffuseFilename,
|
||||
QString("texture%1").arg(++_texturesCount))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if (!part.normalFilename.isEmpty()) {
|
||||
if (!addPart(QFileInfo(fbxFile).path() + "/" + part.normalFilename,
|
||||
if (!addPart(texdir + "/" + part.normalFilename,
|
||||
QString("texture%1").arg(++_texturesCount))) {
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -351,10 +351,10 @@ void drawvec3(int x, int y, float scale, float radians, float thick, int mono, g
|
|||
glPopMatrix();
|
||||
}
|
||||
|
||||
void renderCollisionOverlay(int width, int height, float magnitude) {
|
||||
void renderCollisionOverlay(int width, int height, float magnitude, float red, float blue, float green) {
|
||||
const float MIN_VISIBLE_COLLISION = 0.01f;
|
||||
if (magnitude > MIN_VISIBLE_COLLISION) {
|
||||
glColor4f(0, 0, 0, magnitude);
|
||||
glColor4f(red, blue, green, magnitude);
|
||||
glBegin(GL_QUADS);
|
||||
glVertex2f(0, 0);
|
||||
glVertex2d(width, 0);
|
||||
|
|
|
@ -62,7 +62,7 @@ float extractUniformScale(const glm::vec3& scale);
|
|||
|
||||
double diffclock(timeval *clock1,timeval *clock2);
|
||||
|
||||
void renderCollisionOverlay(int width, int height, float magnitude);
|
||||
void renderCollisionOverlay(int width, int height, float magnitude, float red = 0, float blue = 0, float green = 0);
|
||||
|
||||
void renderOrientationDirections( glm::vec3 position, const glm::quat& orientation, float size );
|
||||
|
||||
|
|
|
@ -210,7 +210,14 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
|
|||
{
|
||||
// glow when moving far away
|
||||
const float GLOW_DISTANCE = 20.0f;
|
||||
Glower glower(_moving && distanceToTarget > GLOW_DISTANCE && renderMode == NORMAL_RENDER_MODE ? 1.0f : 0.0f);
|
||||
const float GLOW_MAX_LOUDNESS = 2500.0f;
|
||||
const float MAX_GLOW = 0.5f;
|
||||
const float GLOW_FROM_AVERAGE_LOUDNESS = ((this == Application::getInstance()->getAvatar())
|
||||
? 0.0f
|
||||
: MAX_GLOW * getHeadData()->getAudioLoudness() / GLOW_MAX_LOUDNESS);
|
||||
Glower glower(_moving && distanceToTarget > GLOW_DISTANCE && renderMode == NORMAL_RENDER_MODE
|
||||
? 1.0f
|
||||
: GLOW_FROM_AVERAGE_LOUDNESS);
|
||||
|
||||
// render body
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::Avatars)) {
|
||||
|
@ -233,22 +240,22 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
|
|||
|
||||
// quick check before falling into the code below:
|
||||
// (a 10 degree breadth of an almost 2 meter avatar kicks in at about 12m)
|
||||
const float MIN_VOICE_SPHERE_DISTANCE = 12.f;
|
||||
const float MIN_VOICE_SPHERE_DISTANCE = 12.0f;
|
||||
if (distanceToTarget > MIN_VOICE_SPHERE_DISTANCE) {
|
||||
// render voice intensity sphere for avatars that are farther away
|
||||
const float MAX_SPHERE_ANGLE = 10.f * RADIANS_PER_DEGREE;
|
||||
const float MIN_SPHERE_ANGLE = 1.f * RADIANS_PER_DEGREE;
|
||||
const float MAX_SPHERE_ANGLE = 10.0f * RADIANS_PER_DEGREE;
|
||||
const float MIN_SPHERE_ANGLE = 1.0f * RADIANS_PER_DEGREE;
|
||||
const float MIN_SPHERE_SIZE = 0.01f;
|
||||
const float SPHERE_LOUDNESS_SCALING = 0.0005f;
|
||||
const float SPHERE_COLOR[] = { 0.5f, 0.8f, 0.8f };
|
||||
float height = getSkeletonHeight();
|
||||
glm::vec3 delta = height * (getHead()->getCameraOrientation() * IDENTITY_UP) / 2.f;
|
||||
glm::vec3 delta = height * (getHead()->getCameraOrientation() * IDENTITY_UP) / 2.0f;
|
||||
float angle = abs(angleBetween(toTarget + delta, toTarget - delta));
|
||||
float sphereRadius = getHead()->getAverageLoudness() * SPHERE_LOUDNESS_SCALING;
|
||||
|
||||
if (renderMode == NORMAL_RENDER_MODE && (sphereRadius > MIN_SPHERE_SIZE) &&
|
||||
(angle < MAX_SPHERE_ANGLE) && (angle > MIN_SPHERE_ANGLE)) {
|
||||
glColor4f(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.f - angle / MAX_SPHERE_ANGLE);
|
||||
glColor4f(SPHERE_COLOR[0], SPHERE_COLOR[1], SPHERE_COLOR[2], 1.0f - angle / MAX_SPHERE_ANGLE);
|
||||
glPushMatrix();
|
||||
glTranslatef(_position.x, _position.y, _position.z);
|
||||
glScalef(height, height, height);
|
||||
|
@ -280,9 +287,9 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
|
|||
glm::vec3 chatAxis = glm::axis(chatRotation);
|
||||
glRotatef(glm::degrees(glm::angle(chatRotation)), chatAxis.x, chatAxis.y, chatAxis.z);
|
||||
|
||||
glColor3f(0.f, 0.8f, 0.f);
|
||||
glRotatef(180.f, 0.f, 1.f, 0.f);
|
||||
glRotatef(180.f, 0.f, 0.f, 1.f);
|
||||
glColor3f(0.0f, 0.8f, 0.0f);
|
||||
glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
|
||||
glRotatef(180.0f, 0.0f, 0.0f, 1.0f);
|
||||
glScalef(_scale * CHAT_MESSAGE_SCALE, _scale * CHAT_MESSAGE_SCALE, 1.0f);
|
||||
|
||||
glDisable(GL_LIGHTING);
|
||||
|
@ -298,7 +305,7 @@ void Avatar::render(const glm::vec3& cameraPosition, RenderMode renderMode) {
|
|||
_chatMessage[lastIndex] = '\0';
|
||||
textRenderer(CHAT)->draw(-width / 2.0f, 0, _chatMessage.c_str());
|
||||
_chatMessage[lastIndex] = lastChar;
|
||||
glColor3f(0.f, 1.f, 0.f);
|
||||
glColor3f(0.0f, 1.0f, 0.0f);
|
||||
textRenderer(CHAT)->draw(width / 2.0f - lastWidth, 0, _chatMessage.c_str() + lastIndex);
|
||||
}
|
||||
glEnable(GL_LIGHTING);
|
||||
|
@ -522,6 +529,11 @@ bool Avatar::findSphereCollisions(const glm::vec3& penetratorCenter, float penet
|
|||
//return getHead()->getFaceModel().findSphereCollisions(penetratorCenter, penetratorRadius, collisions);
|
||||
}
|
||||
|
||||
bool Avatar::findPlaneCollisions(const glm::vec4& plane, CollisionList& collisions) {
|
||||
return _skeletonModel.findPlaneCollisions(plane, collisions) ||
|
||||
getHead()->getFaceModel().findPlaneCollisions(plane, collisions);
|
||||
}
|
||||
|
||||
void Avatar::updateShapePositions() {
|
||||
_skeletonModel.updateShapePositions();
|
||||
Model& headModel = getHead()->getFaceModel();
|
||||
|
@ -550,7 +562,7 @@ bool Avatar::findParticleCollisions(const glm::vec3& particleCenter, float parti
|
|||
const PalmData* palm = handData->getPalm(i);
|
||||
if (palm && palm->hasPaddle()) {
|
||||
// create a disk collision proxy where the hand is
|
||||
glm::vec3 fingerAxis(0.f);
|
||||
glm::vec3 fingerAxis(0.0f);
|
||||
for (size_t f = 0; f < palm->getNumFingers(); ++f) {
|
||||
const FingerData& finger = (palm->getFingers())[f];
|
||||
if (finger.isActive()) {
|
||||
|
@ -692,8 +704,8 @@ void Avatar::renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2,
|
|||
glm::vec3 perpCos = glm::normalize(glm::cross(axis, perpSin));
|
||||
perpSin = glm::cross(perpCos, axis);
|
||||
|
||||
float anglea = 0.f;
|
||||
float angleb = 0.f;
|
||||
float anglea = 0.0f;
|
||||
float angleb = 0.0f;
|
||||
|
||||
for (int i = 0; i < NUM_BODY_CONE_SIDES; i ++) {
|
||||
|
||||
|
@ -743,8 +755,8 @@ void Avatar::updateCollisionFlags() {
|
|||
void Avatar::setScale(float scale) {
|
||||
_scale = scale;
|
||||
|
||||
if (_targetScale * (1.f - RESCALING_TOLERANCE) < _scale &&
|
||||
_scale < _targetScale * (1.f + RESCALING_TOLERANCE)) {
|
||||
if (_targetScale * (1.0f - RESCALING_TOLERANCE) < _scale &&
|
||||
_scale < _targetScale * (1.0f + RESCALING_TOLERANCE)) {
|
||||
_scale = _targetScale;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -64,7 +64,7 @@ enum ScreenTintLayer {
|
|||
// Where one's own Avatar begins in the world (will be overwritten if avatar data file is found)
|
||||
// this is basically in the center of the ground plane. Slightly adjusted. This was asked for by
|
||||
// Grayson as he's building a street around here for demo dinner 2
|
||||
const glm::vec3 START_LOCATION(0.485f * TREE_SCALE, 0.f, 0.5f * TREE_SCALE);
|
||||
const glm::vec3 START_LOCATION(0.485f * TREE_SCALE, 0.0f, 0.5f * TREE_SCALE);
|
||||
|
||||
class Texture;
|
||||
|
||||
|
@ -119,6 +119,12 @@ public:
|
|||
bool findSphereCollisions(const glm::vec3& penetratorCenter, float penetratorRadius,
|
||||
CollisionList& collisions, int skeletonSkipIndex = -1);
|
||||
|
||||
/// Checks for penetration between the described plane and the avatar.
|
||||
/// \param plane the penetration plane
|
||||
/// \param collisions[out] a list to which collisions get appended
|
||||
/// \return whether or not the plane penetrated
|
||||
bool findPlaneCollisions(const glm::vec4& plane, CollisionList& collisions);
|
||||
|
||||
/// Checks for collision between the a spherical particle and the avatar (including paddle hands)
|
||||
/// \param collisionCenter the center of particle's bounding sphere
|
||||
/// \param collisionRadius the radius of particle's bounding sphere
|
||||
|
@ -143,8 +149,6 @@ public:
|
|||
|
||||
static void renderJointConnectingCone(glm::vec3 position1, glm::vec3 position2, float radius1, float radius2);
|
||||
|
||||
|
||||
|
||||
/// \return true if we expect the avatar would move as a result of the collision
|
||||
bool collisionWouldMoveAvatar(CollisionInfo& collision) const;
|
||||
|
||||
|
@ -157,6 +161,9 @@ public:
|
|||
public slots:
|
||||
void updateCollisionFlags();
|
||||
|
||||
signals:
|
||||
void collisionWithAvatar(const QUuid& myUUID, const QUuid& theirUUID, const CollisionInfo& collision);
|
||||
|
||||
protected:
|
||||
SkeletonModel _skeletonModel;
|
||||
float _bodyYawDelta;
|
||||
|
|
|
@ -163,6 +163,11 @@ void Hand::collideAgainstAvatar(Avatar* avatar, bool isMyHand) {
|
|||
// TODO: submit collision info to MyAvatar which should lean accordingly
|
||||
averageContactPoint /= (float)handCollisions.size();
|
||||
avatar->applyCollision(averageContactPoint, totalPenetration);
|
||||
|
||||
CollisionInfo collision;
|
||||
collision._penetration = totalPenetration;
|
||||
collision._contactPoint = averageContactPoint;
|
||||
emit avatar->collisionWithAvatar(avatar->getSessionUUID(), _owningAvatar->getSessionUUID(), collision);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -647,7 +647,7 @@ void MyAvatar::renderBody(RenderMode renderMode) {
|
|||
_skeletonModel.render(1.0f, modelRenderMode);
|
||||
|
||||
// Render head so long as the camera isn't inside it
|
||||
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.40f;
|
||||
const float RENDER_HEAD_CUTOFF_DISTANCE = 0.50f;
|
||||
Camera* myCamera = Application::getInstance()->getCamera();
|
||||
if (renderMode != NORMAL_RENDER_MODE || (glm::length(myCamera->getPosition() - getHead()->calculateAverageEyePosition()) >
|
||||
RENDER_HEAD_CUTOFF_DISTANCE * _scale)) {
|
||||
|
@ -896,8 +896,7 @@ bool findAvatarAvatarPenetration(const glm::vec3 positionA, float radiusA, float
|
|||
return false;
|
||||
}
|
||||
|
||||
static CollisionList bodyCollisions(16);
|
||||
const float BODY_COLLISION_RESOLVE_TIMESCALE = 0.5f; // seconds
|
||||
const float BODY_COLLISION_RESOLUTION_TIMESCALE = 0.5f; // seconds
|
||||
|
||||
void MyAvatar::updateCollisionWithAvatars(float deltaTime) {
|
||||
// Reset detector for nearest avatar
|
||||
|
@ -910,7 +909,7 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) {
|
|||
updateShapePositions();
|
||||
float myBoundingRadius = getBoundingRadius();
|
||||
|
||||
const float BODY_COLLISION_RESOLVE_FACTOR = deltaTime / BODY_COLLISION_RESOLVE_TIMESCALE;
|
||||
const float BODY_COLLISION_RESOLUTION_FACTOR = deltaTime / BODY_COLLISION_RESOLUTION_TIMESCALE;
|
||||
|
||||
foreach (const AvatarSharedPointer& avatarPointer, avatars) {
|
||||
Avatar* avatar = static_cast<Avatar*>(avatarPointer.data());
|
||||
|
@ -930,26 +929,19 @@ void MyAvatar::updateCollisionWithAvatars(float deltaTime) {
|
|||
_skeletonModel.getBodyShapes(myShapes);
|
||||
QVector<const Shape*> theirShapes;
|
||||
avatar->getSkeletonModel().getBodyShapes(theirShapes);
|
||||
bodyCollisions.clear();
|
||||
// TODO: add method to ShapeCollider for colliding lists of shapes
|
||||
foreach (const Shape* myShape, myShapes) {
|
||||
foreach (const Shape* theirShape, theirShapes) {
|
||||
ShapeCollider::shapeShape(myShape, theirShape, bodyCollisions);
|
||||
|
||||
CollisionInfo collision;
|
||||
if (ShapeCollider::collideShapesCoarse(myShapes, theirShapes, collision)) {
|
||||
if (glm::length2(collision._penetration) > EPSILON) {
|
||||
setPosition(getPosition() - BODY_COLLISION_RESOLUTION_FACTOR * collision._penetration);
|
||||
_lastBodyPenetration += collision._penetration;
|
||||
emit collisionWithAvatar(getSessionUUID(), avatar->getSessionUUID(), collision);
|
||||
}
|
||||
}
|
||||
glm::vec3 totalPenetration(0.0f);
|
||||
for (int j = 0; j < bodyCollisions.size(); ++j) {
|
||||
CollisionInfo* collision = bodyCollisions.getCollision(j);
|
||||
totalPenetration = addPenetrations(totalPenetration, collision->_penetration);
|
||||
}
|
||||
if (glm::length2(totalPenetration) > EPSILON) {
|
||||
setPosition(getPosition() - BODY_COLLISION_RESOLVE_FACTOR * totalPenetration);
|
||||
}
|
||||
_lastBodyPenetration += totalPenetration;
|
||||
|
||||
// collide our hands against them
|
||||
// TODO: make this work when we can figure out when the other avatar won't yeild
|
||||
// (for example, we're colling against their chest or leg)
|
||||
// (for example, we're colliding against their chest or leg)
|
||||
//getHand()->collideAgainstAvatar(avatar, true);
|
||||
|
||||
// collide their hands against us
|
||||
|
|
|
@ -595,7 +595,7 @@ bool Model::findCollisions(const QVector<const Shape*> shapes, CollisionList& co
|
|||
const Shape* theirShape = shapes[i];
|
||||
for (int j = 0; j < _jointShapes.size(); ++j) {
|
||||
const Shape* ourShape = _jointShapes[j];
|
||||
if (ShapeCollider::shapeShape(theirShape, ourShape, collisions)) {
|
||||
if (ShapeCollider::collideShapes(theirShape, ourShape, collisions)) {
|
||||
collided = true;
|
||||
}
|
||||
}
|
||||
|
@ -622,7 +622,7 @@ bool Model::findSphereCollisions(const glm::vec3& sphereCenter, float sphereRadi
|
|||
} while (ancestorIndex != -1);
|
||||
}
|
||||
}
|
||||
if (ShapeCollider::shapeShape(&sphere, _jointShapes[i], collisions)) {
|
||||
if (ShapeCollider::collideShapes(&sphere, _jointShapes[i], collisions)) {
|
||||
CollisionInfo* collision = collisions.getLastCollision();
|
||||
collision->_type = MODEL_COLLISION;
|
||||
collision->_data = (void*)(this);
|
||||
|
@ -634,6 +634,21 @@ bool Model::findSphereCollisions(const glm::vec3& sphereCenter, float sphereRadi
|
|||
return collided;
|
||||
}
|
||||
|
||||
bool Model::findPlaneCollisions(const glm::vec4& plane, CollisionList& collisions) {
|
||||
bool collided = false;
|
||||
PlaneShape planeShape(plane);
|
||||
for (int i = 0; i < _jointShapes.size(); i++) {
|
||||
if (ShapeCollider::collideShapes(&planeShape, _jointShapes[i], collisions)) {
|
||||
CollisionInfo* collision = collisions.getLastCollision();
|
||||
collision->_type = MODEL_COLLISION;
|
||||
collision->_data = (void*)(this);
|
||||
collision->_flags = i;
|
||||
collided = true;
|
||||
}
|
||||
}
|
||||
return collided;
|
||||
}
|
||||
|
||||
class Blender : public QRunnable {
|
||||
public:
|
||||
|
||||
|
|
|
@ -176,6 +176,8 @@ public:
|
|||
|
||||
bool findSphereCollisions(const glm::vec3& penetratorCenter, float penetratorRadius,
|
||||
CollisionList& collisions, int skipIndex = -1);
|
||||
|
||||
bool findPlaneCollisions(const glm::vec4& plane, CollisionList& collisions);
|
||||
|
||||
/// \param collision details about the collisions
|
||||
/// \return true if the collision is against a moveable joint
|
||||
|
|
|
@ -12,10 +12,12 @@
|
|||
#include <QGridLayout>
|
||||
#include <QFrame>
|
||||
#include <QLayoutItem>
|
||||
#include <QMainWindow>
|
||||
#include <QPalette>
|
||||
#include <QScrollBar>
|
||||
#include <QSizePolicy>
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
#include "Application.h"
|
||||
#include "FlowLayout.h"
|
||||
|
@ -35,7 +37,9 @@ ChatWindow::ChatWindow() :
|
|||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
// remove the title bar (see the Qt docs on setTitleBarWidget)
|
||||
// remove the title bar (see the Qt docs on setTitleBarWidget), but we keep it for undocking
|
||||
//
|
||||
titleBar = titleBarWidget();
|
||||
setTitleBarWidget(new QWidget());
|
||||
|
||||
FlowLayout* flowLayout = new FlowLayout(0, 4, 4);
|
||||
|
@ -260,3 +264,16 @@ void ChatWindow::messageReceived(const QXmppMessage& message) {
|
|||
}
|
||||
|
||||
#endif
|
||||
|
||||
void ChatWindow::togglePinned() {
|
||||
QMainWindow* mainWindow = Application::getInstance()->getWindow();
|
||||
mainWindow->removeDockWidget(this);
|
||||
if (ui->togglePinnedButton->isChecked()) {
|
||||
mainWindow->addDockWidget(ui->togglePinnedButton->isChecked() ? Qt::RightDockWidgetArea : Qt::NoDockWidgetArea, this);
|
||||
}
|
||||
if (!this->toggleViewAction()->isChecked()) {
|
||||
this->toggleViewAction()->trigger();
|
||||
}
|
||||
this->setFloating(!ui->togglePinnedButton->isChecked());
|
||||
setTitleBarWidget(ui->togglePinnedButton->isChecked()?new QWidget():titleBar);
|
||||
}
|
|
@ -50,12 +50,14 @@ private:
|
|||
void addTimeStamp();
|
||||
|
||||
Ui::ChatWindow* ui;
|
||||
QWidget* titleBar;
|
||||
int numMessagesAfterLastTimeStamp;
|
||||
QDateTime lastMessageStamp;
|
||||
|
||||
private slots:
|
||||
void connected();
|
||||
void timeout();
|
||||
void togglePinned();
|
||||
#ifdef HAVE_QXMPP
|
||||
void error(QXmppClient::Error error);
|
||||
void participantsChanged();
|
||||
|
|
100
interface/src/ui/FramelessDialog.cpp
Normal file
|
@ -0,0 +1,100 @@
|
|||
//
|
||||
// FramelessDialog.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Stojce Slavkovski on 2/20/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "Application.h"
|
||||
#include "FramelessDialog.h"
|
||||
|
||||
const int RESIZE_HANDLE_WIDTH = 7;
|
||||
|
||||
FramelessDialog::FramelessDialog(QWidget *parent, Qt::WindowFlags flags) :
|
||||
QDialog(parent, flags | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint) {
|
||||
setAttribute(Qt::WA_DeleteOnClose);
|
||||
|
||||
// handle rezize and move events
|
||||
parentWidget()->installEventFilter(this);
|
||||
|
||||
// handle minimize, restore and focus events
|
||||
Application::getInstance()->installEventFilter(this);
|
||||
}
|
||||
|
||||
bool FramelessDialog::eventFilter(QObject* sender, QEvent* event) {
|
||||
switch (event->type()) {
|
||||
case QEvent::Move:
|
||||
if (sender == parentWidget()) {
|
||||
// move to upper left corner on app move
|
||||
move(parentWidget()->geometry().topLeft());
|
||||
}
|
||||
break;
|
||||
case QEvent::Resize:
|
||||
if (sender == parentWidget()) {
|
||||
// keep full app height on resizing the app
|
||||
setFixedHeight(parentWidget()->size().height());
|
||||
}
|
||||
break;
|
||||
case QEvent::WindowStateChange:
|
||||
if (parentWidget()->isMinimized()) {
|
||||
setHidden(true);
|
||||
} else {
|
||||
setHidden(false);
|
||||
}
|
||||
break;
|
||||
case QEvent::ApplicationDeactivate:
|
||||
// hide on minimize and focus lost
|
||||
setHidden(true);
|
||||
break;
|
||||
case QEvent::ApplicationActivate:
|
||||
setHidden(false);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FramelessDialog::setStyleSheetFile(const QString& fileName) {
|
||||
QFile globalStyleSheet(Application::resourcesPath() + "styles/global.qss");
|
||||
QFile styleSheet(Application::resourcesPath() + fileName);
|
||||
if (styleSheet.open(QIODevice::ReadOnly) && globalStyleSheet.open(QIODevice::ReadOnly) ) {
|
||||
QDir::setCurrent(Application::resourcesPath());
|
||||
setStyleSheet(globalStyleSheet.readAll() + styleSheet.readAll());
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessDialog::showEvent(QShowEvent* event) {
|
||||
// move to upper left corner
|
||||
move(parentWidget()->geometry().topLeft());
|
||||
|
||||
// keep full app height
|
||||
setFixedHeight(parentWidget()->size().height());
|
||||
|
||||
// resize parrent if width is smaller than this dialog
|
||||
if (parentWidget()->size().width() < size().width()) {
|
||||
parentWidget()->resize(size().width(), parentWidget()->size().height());
|
||||
}
|
||||
}
|
||||
void FramelessDialog::mousePressEvent(QMouseEvent* mouseEvent) {
|
||||
if (abs(mouseEvent->pos().x() - size().width()) < RESIZE_HANDLE_WIDTH && mouseEvent->button() == Qt::LeftButton) {
|
||||
_isResizing = true;
|
||||
QApplication::setOverrideCursor(Qt::SizeHorCursor);
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessDialog::mouseReleaseEvent(QMouseEvent* mouseEvent) {
|
||||
QApplication::restoreOverrideCursor();
|
||||
_isResizing = false;
|
||||
}
|
||||
|
||||
void FramelessDialog::mouseMoveEvent(QMouseEvent* mouseEvent) {
|
||||
if (_isResizing) {
|
||||
resize(mouseEvent->pos().x(), size().height());
|
||||
}
|
||||
}
|
38
interface/src/ui/FramelessDialog.h
Normal file
|
@ -0,0 +1,38 @@
|
|||
//
|
||||
// FramelessDialog.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Stojce Slavkovski on 2/20/14.
|
||||
// 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
|
||||
//
|
||||
|
||||
|
||||
#ifndef hifi_FramelessDialog_h
|
||||
#define hifi_FramelessDialog_h
|
||||
|
||||
#include <QDialog>
|
||||
|
||||
class FramelessDialog : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FramelessDialog(QWidget* parent = 0, Qt::WindowFlags flags = 0);
|
||||
void setStyleSheetFile(const QString& fileName);
|
||||
|
||||
protected:
|
||||
virtual void mouseMoveEvent(QMouseEvent* mouseEvent);
|
||||
virtual void mousePressEvent(QMouseEvent* mouseEvent);
|
||||
virtual void mouseReleaseEvent(QMouseEvent* mouseEvent);
|
||||
virtual void showEvent(QShowEvent* event);
|
||||
|
||||
bool eventFilter(QObject* sender, QEvent* event);
|
||||
|
||||
private:
|
||||
bool _isResizing;
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_FramelessDialog_h
|
|
@ -65,7 +65,7 @@ static const QString propertiesIds[MODEL_METADATA_COUNT] = {
|
|||
};
|
||||
|
||||
ModelsBrowser::ModelsBrowser(ModelType modelsType, QWidget* parent) :
|
||||
QWidget(parent),
|
||||
QWidget(parent, Qt::WindowStaysOnTopHint),
|
||||
_handler(new ModelHandler(modelsType))
|
||||
{
|
||||
connect(_handler, SIGNAL(doneDownloading()), SLOT(resizeView()));
|
||||
|
|
164
interface/src/ui/PreferencesDialog.cpp
Normal file
|
@ -0,0 +1,164 @@
|
|||
//
|
||||
// PreferencesDialog.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Stojce Slavkovski on 2/20/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
#include "Application.h"
|
||||
#include "Menu.h"
|
||||
#include "PreferencesDialog.h"
|
||||
#include "ModelsBrowser.h"
|
||||
|
||||
const int SCROLL_PANEL_BOTTOM_MARGIN = 30;
|
||||
const int OK_BUTTON_RIGHT_MARGIN = 30;
|
||||
const int BUTTONS_TOP_MARGIN = 24;
|
||||
|
||||
PreferencesDialog::PreferencesDialog(QWidget* parent, Qt::WindowFlags flags) : FramelessDialog(parent, flags) {
|
||||
|
||||
ui.setupUi(this);
|
||||
setStyleSheetFile("styles/preferences.qss");
|
||||
loadPreferences();
|
||||
connect(ui.closeButton, &QPushButton::clicked, this, &QDialog::close);
|
||||
|
||||
connect(ui.buttonBrowseHead, &QPushButton::clicked, this, &PreferencesDialog::openHeadModelBrowser);
|
||||
connect(ui.buttonBrowseBody, &QPushButton::clicked, this, &PreferencesDialog::openBodyModelBrowser);
|
||||
}
|
||||
|
||||
void PreferencesDialog::accept() {
|
||||
savePreferences();
|
||||
close();
|
||||
}
|
||||
|
||||
void PreferencesDialog::setHeadUrl(QString modelUrl) {
|
||||
ui.faceURLEdit->setText(modelUrl);
|
||||
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
|
||||
}
|
||||
|
||||
void PreferencesDialog::setSkeletonUrl(QString modelUrl) {
|
||||
ui.skeletonURLEdit->setText(modelUrl);
|
||||
setWindowFlags(windowFlags() | Qt::WindowStaysOnTopHint);
|
||||
}
|
||||
|
||||
void PreferencesDialog::openHeadModelBrowser() {
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
|
||||
ModelsBrowser modelBrowser(Head);
|
||||
connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setHeadUrl);
|
||||
modelBrowser.browse();
|
||||
}
|
||||
|
||||
void PreferencesDialog::openBodyModelBrowser() {
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowStaysOnTopHint);
|
||||
ModelsBrowser modelBrowser(Skeleton);
|
||||
connect(&modelBrowser, &ModelsBrowser::selected, this, &PreferencesDialog::setSkeletonUrl);
|
||||
modelBrowser.browse();
|
||||
}
|
||||
|
||||
void PreferencesDialog::resizeEvent(QResizeEvent *resizeEvent) {
|
||||
|
||||
// keep buttons panel at the bottom
|
||||
ui.buttonsPanel->setGeometry(0, size().height() - ui.buttonsPanel->height(), size().width(), ui.buttonsPanel->height());
|
||||
|
||||
// set width and height of srcollarea to match bottom panel and width
|
||||
ui.scrollArea->setGeometry(ui.scrollArea->geometry().x(), ui.scrollArea->geometry().y(),
|
||||
size().width(),
|
||||
size().height() - ui.buttonsPanel->height() -
|
||||
SCROLL_PANEL_BOTTOM_MARGIN - ui.scrollArea->geometry().y());
|
||||
|
||||
// move Save button to left position
|
||||
ui.defaultButton->move(size().width() - OK_BUTTON_RIGHT_MARGIN - ui.defaultButton->size().width(), BUTTONS_TOP_MARGIN);
|
||||
|
||||
// move Save button to left position
|
||||
ui.cancelButton->move(ui.defaultButton->pos().x() - ui.cancelButton->size().width(), BUTTONS_TOP_MARGIN);
|
||||
|
||||
// move close button
|
||||
ui.closeButton->move(size().width() - OK_BUTTON_RIGHT_MARGIN - ui.closeButton->size().width(), ui.closeButton->pos().y());
|
||||
}
|
||||
|
||||
void PreferencesDialog::loadPreferences() {
|
||||
|
||||
MyAvatar* myAvatar = Application::getInstance()->getAvatar();
|
||||
Menu* menuInstance = Menu::getInstance();
|
||||
|
||||
_displayNameString = myAvatar->getDisplayName();
|
||||
ui.displayNameEdit->setText(_displayNameString);
|
||||
|
||||
_faceURLString = myAvatar->getHead()->getFaceModel().getURL().toString();
|
||||
ui.faceURLEdit->setText(_faceURLString);
|
||||
|
||||
_skeletonURLString = myAvatar->getSkeletonModel().getURL().toString();
|
||||
ui.skeletonURLEdit->setText(_skeletonURLString);
|
||||
|
||||
ui.pupilDilationSlider->setValue(myAvatar->getHead()->getPupilDilation() *
|
||||
ui.pupilDilationSlider->maximum());
|
||||
|
||||
ui.faceshiftEyeDeflectionSider->setValue(menuInstance->getFaceshiftEyeDeflection() *
|
||||
ui.faceshiftEyeDeflectionSider->maximum());
|
||||
|
||||
ui.audioJitterSpin->setValue(menuInstance->getAudioJitterBufferSamples());
|
||||
|
||||
ui.fieldOfViewSpin->setValue(menuInstance->getFieldOfView());
|
||||
|
||||
ui.leanScaleSpin->setValue(myAvatar->getLeanScale());
|
||||
|
||||
ui.avatarScaleSpin->setValue(myAvatar->getScale());
|
||||
|
||||
ui.maxVoxelsSpin->setValue(menuInstance->getMaxVoxels());
|
||||
|
||||
ui.maxVoxelsPPSSpin->setValue(menuInstance->getMaxVoxelPacketsPerSecond());
|
||||
}
|
||||
|
||||
void PreferencesDialog::savePreferences() {
|
||||
|
||||
MyAvatar* myAvatar = Application::getInstance()->getAvatar();
|
||||
bool shouldDispatchIdentityPacket = false;
|
||||
|
||||
QString displayNameStr(ui.displayNameEdit->text());
|
||||
if (displayNameStr != _displayNameString) {
|
||||
myAvatar->setDisplayName(displayNameStr);
|
||||
shouldDispatchIdentityPacket = true;
|
||||
}
|
||||
|
||||
QUrl faceModelURL(ui.faceURLEdit->text());
|
||||
if (faceModelURL.toString() != _faceURLString) {
|
||||
// change the faceModelURL in the profile, it will also update this user's BlendFace
|
||||
myAvatar->setFaceModelURL(faceModelURL);
|
||||
shouldDispatchIdentityPacket = true;
|
||||
}
|
||||
|
||||
QUrl skeletonModelURL(ui.skeletonURLEdit->text());
|
||||
if (skeletonModelURL.toString() != _skeletonURLString) {
|
||||
// change the skeletonModelURL in the profile, it will also update this user's Body
|
||||
myAvatar->setSkeletonModelURL(skeletonModelURL);
|
||||
shouldDispatchIdentityPacket = true;
|
||||
}
|
||||
|
||||
if (shouldDispatchIdentityPacket) {
|
||||
myAvatar->sendIdentityPacket();
|
||||
Application::getInstance()->bumpSettings();
|
||||
}
|
||||
|
||||
myAvatar->getHead()->setPupilDilation(ui.pupilDilationSlider->value() / (float)ui.pupilDilationSlider->maximum());
|
||||
myAvatar->setLeanScale(ui.leanScaleSpin->value());
|
||||
myAvatar->setClampedTargetScale(ui.avatarScaleSpin->value());
|
||||
|
||||
Application::getInstance()->getVoxels()->setMaxVoxels(ui.maxVoxelsSpin->value());
|
||||
Application::getInstance()->resizeGL(Application::getInstance()->getGLWidget()->width(),
|
||||
Application::getInstance()->getGLWidget()->height());
|
||||
|
||||
Menu::getInstance()->setFieldOfView(ui.fieldOfViewSpin->value());
|
||||
|
||||
Menu::getInstance()->setFaceshiftEyeDeflection(ui.faceshiftEyeDeflectionSider->value() /
|
||||
(float)ui.faceshiftEyeDeflectionSider->maximum());
|
||||
Menu::getInstance()->setMaxVoxelPacketsPerSecond(ui.maxVoxelsPPSSpin->value());
|
||||
|
||||
Menu::getInstance()->setAudioJitterBufferSamples(ui.audioJitterSpin->value());
|
||||
|
||||
Application::getInstance()->resizeGL(Application::getInstance()->getGLWidget()->width(),
|
||||
Application::getInstance()->getGLWidget()->height());
|
||||
}
|
47
interface/src/ui/PreferencesDialog.h
Normal file
|
@ -0,0 +1,47 @@
|
|||
//
|
||||
// PreferencesDialog.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Stojce Slavkovski on 2/20/14.
|
||||
// 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
|
||||
//
|
||||
|
||||
#ifndef hifi_PreferencesDialog_h
|
||||
#define hifi_PreferencesDialog_h
|
||||
|
||||
#include "FramelessDialog.h"
|
||||
#include "ui_preferencesDialog.h"
|
||||
|
||||
#include <QString>
|
||||
|
||||
class PreferencesDialog : public FramelessDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
PreferencesDialog(QWidget* parent = 0, Qt::WindowFlags flags = 0);
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent* resizeEvent);
|
||||
|
||||
private:
|
||||
void loadPreferences();
|
||||
void savePreferences();
|
||||
void openHeadModelBrowser();
|
||||
void openBodyModelBrowser();
|
||||
|
||||
Ui_PreferencesDialog ui;
|
||||
QString _faceURLString;
|
||||
QString _skeletonURLString;
|
||||
QString _displayNameString;
|
||||
|
||||
private slots:
|
||||
void accept();
|
||||
void setHeadUrl(QString modelUrl);
|
||||
void setSkeletonUrl(QString modelUrl);
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_PreferencesDialog_h
|
|
@ -20,7 +20,7 @@
|
|||
<string notr="true">font-family: Helvetica, Arial, sans-serif;</string>
|
||||
</property>
|
||||
<property name="features">
|
||||
<set>QDockWidget::NoDockWidgetFeatures</set>
|
||||
<set>QDockWidget::DockWidgetFloatable|QDockWidget::DockWidgetMovable</set>
|
||||
</property>
|
||||
<property name="allowedAreas">
|
||||
<set>Qt::NoDockWidgetArea</set>
|
||||
|
@ -79,6 +79,45 @@
|
|||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="togglePinnedButton">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>16</width>
|
||||
<height>16</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="focusPolicy">
|
||||
<enum>Qt::NoFocus</enum>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset resource="../resources/resources.qrc">
|
||||
<normaloff>:/images/pin.svg</normaloff>
|
||||
<normalon>:/images/pinned.svg</normalon>:/images/pin.svg</iconset>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="default">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="closeButton">
|
||||
<property name="sizePolicy">
|
||||
|
@ -204,6 +243,22 @@
|
|||
<include location="../resources/resources.qrc"/>
|
||||
</resources>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>togglePinnedButton</sender>
|
||||
<signal>clicked()</signal>
|
||||
<receiver>ChatWindow</receiver>
|
||||
<slot>togglePinned()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>390</x>
|
||||
<y>42</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>550</x>
|
||||
<y>42</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>closeButton</sender>
|
||||
<signal>clicked()</signal>
|
||||
|
|
1375
interface/ui/preferencesDialog.ui
Normal file
|
@ -95,8 +95,9 @@ ScriptEngine::ScriptEngine(const QUrl& scriptURL,
|
|||
|
||||
QUrl url(scriptURL);
|
||||
|
||||
// if the scheme is empty, maybe they typed in a file, let's try
|
||||
if (url.scheme().isEmpty()) {
|
||||
// if the scheme length is one or lower, maybe they typed in a file, let's try
|
||||
const int WINDOWS_DRIVE_LETTER_SIZE = 1;
|
||||
if (url.scheme().size() <= WINDOWS_DRIVE_LETTER_SIZE) {
|
||||
url = QUrl::fromLocalFile(scriptURLString);
|
||||
}
|
||||
|
||||
|
|
|
@ -116,7 +116,6 @@ private:
|
|||
|
||||
static VoxelsScriptingInterface _voxelsScriptingInterface;
|
||||
static ParticlesScriptingInterface _particlesScriptingInterface;
|
||||
static int _scriptNumber;
|
||||
|
||||
AbstractControllerScriptingInterface* _controllerScriptingInterface;
|
||||
AudioScriptingInterface _audioScriptingInterface;
|
||||
|
|
36
libraries/shared/src/PlaneShape.cpp
Normal file
|
@ -0,0 +1,36 @@
|
|||
//
|
||||
// PlaneShape.cpp
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrzej Kapolka on 4/10/2014.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "PlaneShape.h"
|
||||
#include "SharedUtil.h"
|
||||
|
||||
const glm::vec3 UNROTATED_NORMAL(0.0f, 1.0f, 0.0f);
|
||||
|
||||
PlaneShape::PlaneShape(const glm::vec4& coefficients) :
|
||||
Shape(Shape::PLANE_SHAPE) {
|
||||
|
||||
glm::vec3 normal = glm::vec3(coefficients);
|
||||
_position = -normal * coefficients.w;
|
||||
|
||||
float angle = acosf(glm::dot(normal, UNROTATED_NORMAL));
|
||||
if (angle > EPSILON) {
|
||||
if (angle > PI - EPSILON) {
|
||||
_rotation = glm::angleAxis(PI, glm::vec3(1.0f, 0.0f, 0.0f));
|
||||
} else {
|
||||
_rotation = glm::angleAxis(angle, glm::normalize(glm::cross(UNROTATED_NORMAL, normal)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glm::vec4 PlaneShape::getCoefficients() const {
|
||||
glm::vec3 normal = _rotation * UNROTATED_NORMAL;
|
||||
return glm::vec4(normal.x, normal.y, normal.z, -glm::dot(normal, _position));
|
||||
}
|
24
libraries/shared/src/PlaneShape.h
Normal file
|
@ -0,0 +1,24 @@
|
|||
//
|
||||
// PlaneShape.h
|
||||
// libraries/shared/src
|
||||
//
|
||||
// Created by Andrzej Kapolka on 4/9/2014.
|
||||
// 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
|
||||
//
|
||||
|
||||
#ifndef hifi_PlaneShape_h
|
||||
#define hifi_PlaneShape_h
|
||||
|
||||
#include "Shape.h"
|
||||
|
||||
class PlaneShape : public Shape {
|
||||
public:
|
||||
PlaneShape(const glm::vec4& coefficients = glm::vec4(0.0f, 1.0f, 0.0f, 0.0f));
|
||||
|
||||
glm::vec4 getCoefficients() const;
|
||||
};
|
||||
|
||||
#endif // hifi_PlaneShape_h
|
|
@ -22,6 +22,7 @@ public:
|
|||
UNKNOWN_SHAPE = 0,
|
||||
SPHERE_SHAPE,
|
||||
CAPSULE_SHAPE,
|
||||
PLANE_SHAPE,
|
||||
BOX_SHAPE,
|
||||
LIST_SHAPE
|
||||
};
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <glm/gtx/norm.hpp>
|
||||
|
||||
#include "GeometryUtil.h"
|
||||
#include "ShapeCollider.h"
|
||||
|
||||
// NOTE:
|
||||
|
@ -22,7 +23,7 @@
|
|||
|
||||
namespace ShapeCollider {
|
||||
|
||||
bool shapeShape(const Shape* shapeA, const Shape* shapeB, CollisionList& collisions) {
|
||||
bool collideShapes(const Shape* shapeA, const Shape* shapeB, CollisionList& collisions) {
|
||||
// ATM we only have two shape types so we just check every case.
|
||||
// TODO: make a fast lookup for correct method
|
||||
int typeA = shapeA->getType();
|
||||
|
@ -33,6 +34,8 @@ bool shapeShape(const Shape* shapeA, const Shape* shapeB, CollisionList& collisi
|
|||
return sphereSphere(sphereA, static_cast<const SphereShape*>(shapeB), collisions);
|
||||
} else if (typeB == Shape::CAPSULE_SHAPE) {
|
||||
return sphereCapsule(sphereA, static_cast<const CapsuleShape*>(shapeB), collisions);
|
||||
} else if (typeB == Shape::PLANE_SHAPE) {
|
||||
return spherePlane(sphereA, static_cast<const PlaneShape*>(shapeB), collisions);
|
||||
}
|
||||
} else if (typeA == Shape::CAPSULE_SHAPE) {
|
||||
const CapsuleShape* capsuleA = static_cast<const CapsuleShape*>(shapeA);
|
||||
|
@ -40,6 +43,17 @@ bool shapeShape(const Shape* shapeA, const Shape* shapeB, CollisionList& collisi
|
|||
return capsuleSphere(capsuleA, static_cast<const SphereShape*>(shapeB), collisions);
|
||||
} else if (typeB == Shape::CAPSULE_SHAPE) {
|
||||
return capsuleCapsule(capsuleA, static_cast<const CapsuleShape*>(shapeB), collisions);
|
||||
} else if (typeB == Shape::PLANE_SHAPE) {
|
||||
return capsulePlane(capsuleA, static_cast<const PlaneShape*>(shapeB), collisions);
|
||||
}
|
||||
} else if (typeA == Shape::PLANE_SHAPE) {
|
||||
const PlaneShape* planeA = static_cast<const PlaneShape*>(shapeA);
|
||||
if (typeB == Shape::SPHERE_SHAPE) {
|
||||
return planeSphere(planeA, static_cast<const SphereShape*>(shapeB), collisions);
|
||||
} else if (typeB == Shape::CAPSULE_SHAPE) {
|
||||
return planeCapsule(planeA, static_cast<const CapsuleShape*>(shapeB), collisions);
|
||||
} else if (typeB == Shape::PLANE_SHAPE) {
|
||||
return planePlane(planeA, static_cast<const PlaneShape*>(shapeB), collisions);
|
||||
}
|
||||
} else if (typeA == Shape::LIST_SHAPE) {
|
||||
const ListShape* listA = static_cast<const ListShape*>(shapeA);
|
||||
|
@ -47,11 +61,37 @@ bool shapeShape(const Shape* shapeA, const Shape* shapeB, CollisionList& collisi
|
|||
return listSphere(listA, static_cast<const SphereShape*>(shapeB), collisions);
|
||||
} else if (typeB == Shape::CAPSULE_SHAPE) {
|
||||
return listCapsule(listA, static_cast<const CapsuleShape*>(shapeB), collisions);
|
||||
} else if (typeB == Shape::PLANE_SHAPE) {
|
||||
return listPlane(listA, static_cast<const PlaneShape*>(shapeB), collisions);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static CollisionList tempCollisions(32);
|
||||
|
||||
bool collideShapesCoarse(const QVector<const Shape*>& shapesA, const QVector<const Shape*>& shapesB, CollisionInfo& collision) {
|
||||
tempCollisions.clear();
|
||||
foreach (const Shape* shapeA, shapesA) {
|
||||
foreach (const Shape* shapeB, shapesB) {
|
||||
ShapeCollider::collideShapes(shapeA, shapeB, tempCollisions);
|
||||
}
|
||||
}
|
||||
if (tempCollisions.size() > 0) {
|
||||
glm::vec3 totalPenetration(0.0f);
|
||||
glm::vec3 averageContactPoint(0.0f);
|
||||
for (int j = 0; j < tempCollisions.size(); ++j) {
|
||||
CollisionInfo* c = tempCollisions.getCollision(j);
|
||||
totalPenetration = addPenetrations(totalPenetration, c->_penetration);
|
||||
averageContactPoint += c->_contactPoint;
|
||||
}
|
||||
collision._penetration = totalPenetration;
|
||||
collision._contactPoint = averageContactPoint / (float)(tempCollisions.size());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sphereSphere(const SphereShape* sphereA, const SphereShape* sphereB, CollisionList& collisions) {
|
||||
glm::vec3 BA = sphereB->getPosition() - sphereA->getPosition();
|
||||
float distanceSquared = glm::dot(BA, BA);
|
||||
|
@ -61,7 +101,7 @@ bool sphereSphere(const SphereShape* sphereA, const SphereShape* sphereB, Collis
|
|||
float distance = sqrtf(distanceSquared);
|
||||
if (distance < EPSILON) {
|
||||
// the spheres are on top of each other, so we pick an arbitrary penetration direction
|
||||
BA = glm::vec3(0.f, 1.f, 0.f);
|
||||
BA = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||
distance = totalRadius;
|
||||
} else {
|
||||
BA /= distance;
|
||||
|
@ -96,7 +136,7 @@ bool sphereCapsule(const SphereShape* sphereA, const CapsuleShape* capsuleB, Col
|
|||
}
|
||||
if (absAxialDistance > capsuleB->getHalfHeight()) {
|
||||
// sphere hits capsule on a cap --> recompute radialAxis to point from spherA to cap center
|
||||
float sign = (axialDistance > 0.f) ? 1.f : -1.f;
|
||||
float sign = (axialDistance > 0.0f) ? 1.0f : -1.0f;
|
||||
radialAxis = BA + (sign * capsuleB->getHalfHeight()) * capsuleAxis;
|
||||
radialDistance2 = glm::length2(radialAxis);
|
||||
if (radialDistance2 > totalRadius2) {
|
||||
|
@ -128,12 +168,12 @@ bool sphereCapsule(const SphereShape* sphereA, const CapsuleShape* capsuleB, Col
|
|||
return false;
|
||||
}
|
||||
// ... but still defined for the cap case
|
||||
if (axialDistance < 0.f) {
|
||||
if (axialDistance < 0.0f) {
|
||||
// we're hitting the start cap, so we negate the capsuleAxis
|
||||
capsuleAxis *= -1;
|
||||
}
|
||||
// penetration points from A into B
|
||||
float sign = (axialDistance > 0.f) ? -1.f : 1.f;
|
||||
float sign = (axialDistance > 0.0f) ? -1.0f : 1.0f;
|
||||
collision->_penetration = (sign * (totalRadius + capsuleB->getHalfHeight() - absAxialDistance)) * capsuleAxis;
|
||||
// contactPoint is on surface of sphereA
|
||||
collision->_contactPoint = sphereA->getPosition() + (sign * sphereA->getRadius()) * capsuleAxis;
|
||||
|
@ -143,6 +183,20 @@ bool sphereCapsule(const SphereShape* sphereA, const CapsuleShape* capsuleB, Col
|
|||
return false;
|
||||
}
|
||||
|
||||
bool spherePlane(const SphereShape* sphereA, const PlaneShape* planeB, CollisionList& collisions) {
|
||||
glm::vec3 penetration;
|
||||
if (findSpherePlanePenetration(sphereA->getPosition(), sphereA->getRadius(), planeB->getCoefficients(), penetration)) {
|
||||
CollisionInfo* collision = collisions.getNewCollision();
|
||||
if (!collision) {
|
||||
return false; // collision list is full
|
||||
}
|
||||
collision->_penetration = penetration;
|
||||
collision->_contactPoint = sphereA->getPosition() + sphereA->getRadius() * glm::normalize(penetration);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool capsuleSphere(const CapsuleShape* capsuleA, const SphereShape* sphereB, CollisionList& collisions) {
|
||||
// find sphereB's closest approach to axis of capsuleA
|
||||
glm::vec3 AB = capsuleA->getPosition() - sphereB->getPosition();
|
||||
|
@ -166,7 +220,7 @@ bool capsuleSphere(const CapsuleShape* capsuleA, const SphereShape* sphereB, Col
|
|||
if (absAxialDistance > capsuleA->getHalfHeight()) {
|
||||
// sphere hits capsule on a cap
|
||||
// --> recompute radialAxis and closestApproach
|
||||
float sign = (axialDistance > 0.f) ? 1.f : -1.f;
|
||||
float sign = (axialDistance > 0.0f) ? 1.0f : -1.0f;
|
||||
closestApproach = capsuleA->getPosition() + (sign * capsuleA->getHalfHeight()) * capsuleAxis;
|
||||
radialAxis = closestApproach - sphereB->getPosition();
|
||||
radialDistance2 = glm::length2(radialAxis);
|
||||
|
@ -199,11 +253,11 @@ bool capsuleSphere(const CapsuleShape* capsuleA, const SphereShape* sphereB, Col
|
|||
return false;
|
||||
}
|
||||
// ... but still defined for the cap case
|
||||
if (axialDistance < 0.f) {
|
||||
if (axialDistance < 0.0f) {
|
||||
// we're hitting the start cap, so we negate the capsuleAxis
|
||||
capsuleAxis *= -1;
|
||||
}
|
||||
float sign = (axialDistance > 0.f) ? 1.f : -1.f;
|
||||
float sign = (axialDistance > 0.0f) ? 1.0f : -1.0f;
|
||||
collision->_penetration = (sign * (totalRadius + capsuleA->getHalfHeight() - absAxialDistance)) * capsuleAxis;
|
||||
// contactPoint is on surface of sphereA
|
||||
collision->_contactPoint = closestApproach + (sign * capsuleA->getRadius()) * capsuleAxis;
|
||||
|
@ -226,7 +280,7 @@ bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB,
|
|||
// d = [(B - A) . (a - (a.b)b)] / (1 - (a.b)^2)
|
||||
|
||||
float aDotB = glm::dot(axisA, axisB);
|
||||
float denominator = 1.f - aDotB * aDotB;
|
||||
float denominator = 1.0f - aDotB * aDotB;
|
||||
float totalRadius = capsuleA->getRadius() + capsuleB->getRadius();
|
||||
if (denominator > EPSILON) {
|
||||
// distances to points of closest approach
|
||||
|
@ -236,12 +290,12 @@ bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB,
|
|||
// clamp the distances to the ends of the capsule line segments
|
||||
float absDistanceA = fabs(distanceA);
|
||||
if (absDistanceA > capsuleA->getHalfHeight() + capsuleA->getRadius()) {
|
||||
float signA = distanceA < 0.f ? -1.f : 1.f;
|
||||
float signA = distanceA < 0.0f ? -1.0f : 1.0f;
|
||||
distanceA = signA * capsuleA->getHalfHeight();
|
||||
}
|
||||
float absDistanceB = fabs(distanceB);
|
||||
if (absDistanceB > capsuleB->getHalfHeight() + capsuleB->getRadius()) {
|
||||
float signB = distanceB < 0.f ? -1.f : 1.f;
|
||||
float signB = distanceB < 0.0f ? -1.0f : 1.0f;
|
||||
distanceB = signB * capsuleB->getHalfHeight();
|
||||
}
|
||||
|
||||
|
@ -268,7 +322,7 @@ bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB,
|
|||
{
|
||||
// the capsule centers are on top of each other!
|
||||
// give up on a valid penetration direction and just use the yAxis
|
||||
BA = glm::vec3(0.f, 1.f, 0.f);
|
||||
BA = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||
distance = glm::max(capsuleB->getRadius(), capsuleA->getRadius());
|
||||
}
|
||||
} else {
|
||||
|
@ -300,7 +354,7 @@ bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB,
|
|||
float distance = sqrtf(distanceSquared);
|
||||
if (distance < EPSILON) {
|
||||
// the spheres are on top of each other, so we pick an arbitrary penetration direction
|
||||
BA = glm::vec3(0.f, 1.f, 0.f);
|
||||
BA = glm::vec3(0.0f, 1.0f, 0.0f);
|
||||
} else {
|
||||
BA /= distance;
|
||||
}
|
||||
|
@ -349,6 +403,63 @@ bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB,
|
|||
return false;
|
||||
}
|
||||
|
||||
bool capsulePlane(const CapsuleShape* capsuleA, const PlaneShape* planeB, CollisionList& collisions) {
|
||||
glm::vec3 start, end, penetration;
|
||||
capsuleA->getStartPoint(start);
|
||||
capsuleA->getEndPoint(end);
|
||||
glm::vec4 plane = planeB->getCoefficients();
|
||||
if (findCapsulePlanePenetration(start, end, capsuleA->getRadius(), plane, penetration)) {
|
||||
CollisionInfo* collision = collisions.getNewCollision();
|
||||
if (!collision) {
|
||||
return false; // collision list is full
|
||||
}
|
||||
collision->_penetration = penetration;
|
||||
glm::vec3 deepestEnd = (glm::dot(start, glm::vec3(plane)) < glm::dot(end, glm::vec3(plane))) ? start : end;
|
||||
collision->_contactPoint = deepestEnd + capsuleA->getRadius() * glm::normalize(penetration);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool planeSphere(const PlaneShape* planeA, const SphereShape* sphereB, CollisionList& collisions) {
|
||||
glm::vec3 penetration;
|
||||
if (findSpherePlanePenetration(sphereB->getPosition(), sphereB->getRadius(), planeA->getCoefficients(), penetration)) {
|
||||
CollisionInfo* collision = collisions.getNewCollision();
|
||||
if (!collision) {
|
||||
return false; // collision list is full
|
||||
}
|
||||
collision->_penetration = -penetration;
|
||||
collision->_contactPoint = sphereB->getPosition() +
|
||||
(sphereB->getRadius() / glm::length(penetration) - 1.0f) * penetration;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool planeCapsule(const PlaneShape* planeA, const CapsuleShape* capsuleB, CollisionList& collisions) {
|
||||
glm::vec3 start, end, penetration;
|
||||
capsuleB->getStartPoint(start);
|
||||
capsuleB->getEndPoint(end);
|
||||
glm::vec4 plane = planeA->getCoefficients();
|
||||
if (findCapsulePlanePenetration(start, end, capsuleB->getRadius(), plane, penetration)) {
|
||||
CollisionInfo* collision = collisions.getNewCollision();
|
||||
if (!collision) {
|
||||
return false; // collision list is full
|
||||
}
|
||||
collision->_penetration = -penetration;
|
||||
glm::vec3 deepestEnd = (glm::dot(start, glm::vec3(plane)) < glm::dot(end, glm::vec3(plane))) ? start : end;
|
||||
collision->_contactPoint = deepestEnd + (capsuleB->getRadius() / glm::length(penetration) - 1.0f) * penetration;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool planePlane(const PlaneShape* planeA, const PlaneShape* planeB, CollisionList& collisions) {
|
||||
// technically, planes always collide unless they're parallel and not coincident; however, that's
|
||||
// not going to give us any useful information
|
||||
return false;
|
||||
}
|
||||
|
||||
bool sphereList(const SphereShape* sphereA, const ListShape* listB, CollisionList& collisions) {
|
||||
bool touching = false;
|
||||
for (int i = 0; i < listB->size() && !collisions.isFull(); ++i) {
|
||||
|
@ -358,6 +469,8 @@ bool sphereList(const SphereShape* sphereA, const ListShape* listB, CollisionLis
|
|||
touching = sphereSphere(sphereA, static_cast<const SphereShape*>(subShape), collisions) || touching;
|
||||
} else if (subType == Shape::CAPSULE_SHAPE) {
|
||||
touching = sphereCapsule(sphereA, static_cast<const CapsuleShape*>(subShape), collisions) || touching;
|
||||
} else if (subType == Shape::PLANE_SHAPE) {
|
||||
touching = spherePlane(sphereA, static_cast<const PlaneShape*>(subShape), collisions) || touching;
|
||||
}
|
||||
}
|
||||
return touching;
|
||||
|
@ -372,6 +485,24 @@ bool capsuleList(const CapsuleShape* capsuleA, const ListShape* listB, Collision
|
|||
touching = capsuleSphere(capsuleA, static_cast<const SphereShape*>(subShape), collisions) || touching;
|
||||
} else if (subType == Shape::CAPSULE_SHAPE) {
|
||||
touching = capsuleCapsule(capsuleA, static_cast<const CapsuleShape*>(subShape), collisions) || touching;
|
||||
} else if (subType == Shape::PLANE_SHAPE) {
|
||||
touching = capsulePlane(capsuleA, static_cast<const PlaneShape*>(subShape), collisions) || touching;
|
||||
}
|
||||
}
|
||||
return touching;
|
||||
}
|
||||
|
||||
bool planeList(const PlaneShape* planeA, const ListShape* listB, CollisionList& collisions) {
|
||||
bool touching = false;
|
||||
for (int i = 0; i < listB->size() && !collisions.isFull(); ++i) {
|
||||
const Shape* subShape = listB->getSubShape(i);
|
||||
int subType = subShape->getType();
|
||||
if (subType == Shape::SPHERE_SHAPE) {
|
||||
touching = planeSphere(planeA, static_cast<const SphereShape*>(subShape), collisions) || touching;
|
||||
} else if (subType == Shape::CAPSULE_SHAPE) {
|
||||
touching = planeCapsule(planeA, static_cast<const CapsuleShape*>(subShape), collisions) || touching;
|
||||
} else if (subType == Shape::PLANE_SHAPE) {
|
||||
touching = planePlane(planeA, static_cast<const PlaneShape*>(subShape), collisions) || touching;
|
||||
}
|
||||
}
|
||||
return touching;
|
||||
|
@ -386,6 +517,8 @@ bool listSphere(const ListShape* listA, const SphereShape* sphereB, CollisionLis
|
|||
touching = sphereSphere(static_cast<const SphereShape*>(subShape), sphereB, collisions) || touching;
|
||||
} else if (subType == Shape::CAPSULE_SHAPE) {
|
||||
touching = capsuleSphere(static_cast<const CapsuleShape*>(subShape), sphereB, collisions) || touching;
|
||||
} else if (subType == Shape::PLANE_SHAPE) {
|
||||
touching = planeSphere(static_cast<const PlaneShape*>(subShape), sphereB, collisions) || touching;
|
||||
}
|
||||
}
|
||||
return touching;
|
||||
|
@ -400,6 +533,24 @@ bool listCapsule(const ListShape* listA, const CapsuleShape* capsuleB, Collision
|
|||
touching = sphereCapsule(static_cast<const SphereShape*>(subShape), capsuleB, collisions) || touching;
|
||||
} else if (subType == Shape::CAPSULE_SHAPE) {
|
||||
touching = capsuleCapsule(static_cast<const CapsuleShape*>(subShape), capsuleB, collisions) || touching;
|
||||
} else if (subType == Shape::PLANE_SHAPE) {
|
||||
touching = planeCapsule(static_cast<const PlaneShape*>(subShape), capsuleB, collisions) || touching;
|
||||
}
|
||||
}
|
||||
return touching;
|
||||
}
|
||||
|
||||
bool listPlane(const ListShape* listA, const PlaneShape* planeB, CollisionList& collisions) {
|
||||
bool touching = false;
|
||||
for (int i = 0; i < listA->size() && !collisions.isFull(); ++i) {
|
||||
const Shape* subShape = listA->getSubShape(i);
|
||||
int subType = subShape->getType();
|
||||
if (subType == Shape::SPHERE_SHAPE) {
|
||||
touching = spherePlane(static_cast<const SphereShape*>(subShape), planeB, collisions) || touching;
|
||||
} else if (subType == Shape::CAPSULE_SHAPE) {
|
||||
touching = capsulePlane(static_cast<const CapsuleShape*>(subShape), planeB, collisions) || touching;
|
||||
} else if (subType == Shape::PLANE_SHAPE) {
|
||||
touching = planePlane(static_cast<const PlaneShape*>(subShape), planeB, collisions) || touching;
|
||||
}
|
||||
}
|
||||
return touching;
|
||||
|
@ -410,7 +561,7 @@ bool listList(const ListShape* listA, const ListShape* listB, CollisionList& col
|
|||
for (int i = 0; i < listA->size() && !collisions.isFull(); ++i) {
|
||||
const Shape* subShape = listA->getSubShape(i);
|
||||
for (int j = 0; j < listB->size() && !collisions.isFull(); ++j) {
|
||||
touching = shapeShape(subShape, listB->getSubShape(j), collisions) || touching;
|
||||
touching = collideShapes(subShape, listB->getSubShape(j), collisions) || touching;
|
||||
}
|
||||
}
|
||||
return touching;
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "CapsuleShape.h"
|
||||
#include "CollisionInfo.h"
|
||||
#include "ListShape.h"
|
||||
#include "PlaneShape.h"
|
||||
#include "SharedUtil.h"
|
||||
#include "SphereShape.h"
|
||||
|
||||
|
@ -22,9 +23,15 @@ namespace ShapeCollider {
|
|||
|
||||
/// \param shapeA pointer to first shape
|
||||
/// \param shapeB pointer to second shape
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \param collisions[out] collision details
|
||||
/// \return true if shapes collide
|
||||
bool shapeShape(const Shape* shapeA, const Shape* shapeB, CollisionList& collisions);
|
||||
bool collideShapes(const Shape* shapeA, const Shape* shapeB, CollisionList& collisions);
|
||||
|
||||
/// \param shapesA list of shapes
|
||||
/// \param shapeB list of shapes
|
||||
/// \param collisions[out] average collision details
|
||||
/// \return true if any shapes collide
|
||||
bool collideShapesCoarse(const QVector<const Shape*>& shapesA, const QVector<const Shape*>& shapesB, CollisionInfo& collision);
|
||||
|
||||
/// \param sphereA pointer to first shape
|
||||
/// \param sphereB pointer to second shape
|
||||
|
@ -38,6 +45,12 @@ namespace ShapeCollider {
|
|||
/// \return true if shapes collide
|
||||
bool sphereCapsule(const SphereShape* sphereA, const CapsuleShape* capsuleB, CollisionList& collisions);
|
||||
|
||||
/// \param sphereA pointer to first shape
|
||||
/// \param planeB pointer to second shape
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if shapes collide
|
||||
bool spherePlane(const SphereShape* sphereA, const PlaneShape* planeB, CollisionList& collisions);
|
||||
|
||||
/// \param capsuleA pointer to first shape
|
||||
/// \param sphereB pointer to second shape
|
||||
/// \param[out] collisions where to append collision details
|
||||
|
@ -50,6 +63,30 @@ namespace ShapeCollider {
|
|||
/// \return true if shapes collide
|
||||
bool capsuleCapsule(const CapsuleShape* capsuleA, const CapsuleShape* capsuleB, CollisionList& collisions);
|
||||
|
||||
/// \param capsuleA pointer to first shape
|
||||
/// \param planeB pointer to second shape
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if shapes collide
|
||||
bool capsulePlane(const CapsuleShape* capsuleA, const PlaneShape* planeB, CollisionList& collisions);
|
||||
|
||||
/// \param planeA pointer to first shape
|
||||
/// \param sphereB pointer to second shape
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if shapes collide
|
||||
bool planeSphere(const PlaneShape* planeA, const SphereShape* sphereB, CollisionList& collisions);
|
||||
|
||||
/// \param planeA pointer to first shape
|
||||
/// \param capsuleB pointer to second shape
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if shapes collide
|
||||
bool planeCapsule(const PlaneShape* planeA, const CapsuleShape* capsuleB, CollisionList& collisions);
|
||||
|
||||
/// \param planeA pointer to first shape
|
||||
/// \param planeB pointer to second shape
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if shapes collide
|
||||
bool planePlane(const PlaneShape* planeA, const PlaneShape* planeB, CollisionList& collisions);
|
||||
|
||||
/// \param sphereA pointer to first shape
|
||||
/// \param listB pointer to second shape
|
||||
/// \param[out] collisions where to append collision details
|
||||
|
@ -62,6 +99,12 @@ namespace ShapeCollider {
|
|||
/// \return true if shapes collide
|
||||
bool capsuleList(const CapsuleShape* capsuleA, const ListShape* listB, CollisionList& collisions);
|
||||
|
||||
/// \param planeA pointer to first shape
|
||||
/// \param listB pointer to second shape
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if shapes collide
|
||||
bool planeList(const PlaneShape* planeA, const ListShape* listB, CollisionList& collisions);
|
||||
|
||||
/// \param listA pointer to first shape
|
||||
/// \param sphereB pointer to second shape
|
||||
/// \param[out] collisions where to append collision details
|
||||
|
@ -74,6 +117,12 @@ namespace ShapeCollider {
|
|||
/// \return true if shapes collide
|
||||
bool listCapsule(const ListShape* listA, const CapsuleShape* capsuleB, CollisionList& collisions);
|
||||
|
||||
/// \param listA pointer to first shape
|
||||
/// \param planeB pointer to second shape
|
||||
/// \param[out] collisions where to append collision details
|
||||
/// \return true if shapes collide
|
||||
bool listPlane(const ListShape* listA, const PlaneShape* planeB, CollisionList& collisions);
|
||||
|
||||
/// \param listA pointer to first shape
|
||||
/// \param capsuleB pointer to second shape
|
||||
/// \param[out] collisions where to append collision details
|
||||
|
|
|
@ -43,7 +43,7 @@ void ShapeColliderTests::sphereMissesSphere() {
|
|||
|
||||
// collide A to B...
|
||||
{
|
||||
bool touching = ShapeCollider::shapeShape(&sphereA, &sphereB, collisions);
|
||||
bool touching = ShapeCollider::collideShapes(&sphereA, &sphereB, collisions);
|
||||
if (touching) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphereA and sphereB should NOT touch" << std::endl;
|
||||
|
@ -52,7 +52,7 @@ void ShapeColliderTests::sphereMissesSphere() {
|
|||
|
||||
// collide B to A...
|
||||
{
|
||||
bool touching = ShapeCollider::shapeShape(&sphereB, &sphereA, collisions);
|
||||
bool touching = ShapeCollider::collideShapes(&sphereB, &sphereA, collisions);
|
||||
if (touching) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphereA and sphereB should NOT touch" << std::endl;
|
||||
|
@ -61,7 +61,7 @@ void ShapeColliderTests::sphereMissesSphere() {
|
|||
|
||||
// also test shapeShape
|
||||
{
|
||||
bool touching = ShapeCollider::shapeShape(&sphereB, &sphereA, collisions);
|
||||
bool touching = ShapeCollider::collideShapes(&sphereB, &sphereA, collisions);
|
||||
if (touching) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphereA and sphereB should NOT touch" << std::endl;
|
||||
|
@ -93,7 +93,7 @@ void ShapeColliderTests::sphereTouchesSphere() {
|
|||
|
||||
// collide A to B...
|
||||
{
|
||||
bool touching = ShapeCollider::shapeShape(&sphereA, &sphereB, collisions);
|
||||
bool touching = ShapeCollider::collideShapes(&sphereA, &sphereB, collisions);
|
||||
if (!touching) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphereA and sphereB should touch" << std::endl;
|
||||
|
@ -136,7 +136,7 @@ void ShapeColliderTests::sphereTouchesSphere() {
|
|||
|
||||
// collide B to A...
|
||||
{
|
||||
bool touching = ShapeCollider::shapeShape(&sphereB, &sphereA, collisions);
|
||||
bool touching = ShapeCollider::collideShapes(&sphereB, &sphereA, collisions);
|
||||
if (!touching) {
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphereA and sphereB should touch" << std::endl;
|
||||
|
@ -199,7 +199,7 @@ void ShapeColliderTests::sphereMissesCapsule() {
|
|||
sphereA.setPosition(rotation * localPosition + translation);
|
||||
|
||||
// sphereA agains capsuleB
|
||||
if (ShapeCollider::shapeShape(&sphereA, &capsuleB, collisions))
|
||||
if (ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphere and capsule should NOT touch"
|
||||
|
@ -207,7 +207,7 @@ void ShapeColliderTests::sphereMissesCapsule() {
|
|||
}
|
||||
|
||||
// capsuleB against sphereA
|
||||
if (ShapeCollider::shapeShape(&capsuleB, &sphereA, collisions))
|
||||
if (ShapeCollider::collideShapes(&capsuleB, &sphereA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphere and capsule should NOT touch"
|
||||
|
@ -241,7 +241,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
|||
{ // sphereA collides with capsuleB's cylindrical wall
|
||||
sphereA.setPosition(radialOffset * xAxis);
|
||||
|
||||
if (!ShapeCollider::shapeShape(&sphereA, &capsuleB, collisions))
|
||||
if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphere and capsule should touch"
|
||||
|
@ -272,7 +272,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
|||
}
|
||||
|
||||
// capsuleB collides with sphereA
|
||||
if (!ShapeCollider::shapeShape(&capsuleB, &sphereA, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleB, &sphereA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and sphere should touch"
|
||||
|
@ -308,7 +308,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
|||
glm::vec3 axialOffset = (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis;
|
||||
sphereA.setPosition(axialOffset * yAxis);
|
||||
|
||||
if (!ShapeCollider::shapeShape(&sphereA, &capsuleB, collisions))
|
||||
if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphere and capsule should touch"
|
||||
|
@ -339,7 +339,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
|||
}
|
||||
|
||||
// capsuleB collides with sphereA
|
||||
if (!ShapeCollider::shapeShape(&capsuleB, &sphereA, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleB, &sphereA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and sphere should touch"
|
||||
|
@ -375,7 +375,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
|||
glm::vec3 axialOffset = - (halfHeightB + alpha * radiusA + beta * radiusB) * yAxis;
|
||||
sphereA.setPosition(axialOffset * yAxis);
|
||||
|
||||
if (!ShapeCollider::shapeShape(&sphereA, &capsuleB, collisions))
|
||||
if (!ShapeCollider::collideShapes(&sphereA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: sphere and capsule should touch"
|
||||
|
@ -406,7 +406,7 @@ void ShapeColliderTests::sphereTouchesCapsule() {
|
|||
}
|
||||
|
||||
// capsuleB collides with sphereA
|
||||
if (!ShapeCollider::shapeShape(&capsuleB, &sphereA, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleB, &sphereA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and sphere should touch"
|
||||
|
@ -462,13 +462,13 @@ void ShapeColliderTests::capsuleMissesCapsule() {
|
|||
|
||||
// side by side
|
||||
capsuleB.setPosition((1.01f * totalRadius) * xAxis);
|
||||
if (ShapeCollider::shapeShape(&capsuleA, &capsuleB, collisions))
|
||||
if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should NOT touch"
|
||||
<< std::endl;
|
||||
}
|
||||
if (ShapeCollider::shapeShape(&capsuleB, &capsuleA, collisions))
|
||||
if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should NOT touch"
|
||||
|
@ -477,13 +477,13 @@ void ShapeColliderTests::capsuleMissesCapsule() {
|
|||
|
||||
// end to end
|
||||
capsuleB.setPosition((1.01f * totalHalfLength) * xAxis);
|
||||
if (ShapeCollider::shapeShape(&capsuleA, &capsuleB, collisions))
|
||||
if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should NOT touch"
|
||||
<< std::endl;
|
||||
}
|
||||
if (ShapeCollider::shapeShape(&capsuleB, &capsuleA, collisions))
|
||||
if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should NOT touch"
|
||||
|
@ -494,13 +494,13 @@ void ShapeColliderTests::capsuleMissesCapsule() {
|
|||
glm::quat rotation = glm::angleAxis(PI_OVER_TWO, zAxis);
|
||||
capsuleB.setRotation(rotation);
|
||||
capsuleB.setPosition((1.01f * (totalRadius + capsuleB.getHalfHeight())) * xAxis);
|
||||
if (ShapeCollider::shapeShape(&capsuleA, &capsuleB, collisions))
|
||||
if (ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should NOT touch"
|
||||
<< std::endl;
|
||||
}
|
||||
if (ShapeCollider::shapeShape(&capsuleB, &capsuleA, collisions))
|
||||
if (ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should NOT touch"
|
||||
|
@ -532,7 +532,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
|||
|
||||
{ // side by side
|
||||
capsuleB.setPosition((0.99f * totalRadius) * xAxis);
|
||||
if (!ShapeCollider::shapeShape(&capsuleA, &capsuleB, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should touch"
|
||||
|
@ -540,7 +540,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
|||
} else {
|
||||
++numCollisions;
|
||||
}
|
||||
if (!ShapeCollider::shapeShape(&capsuleB, &capsuleA, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should touch"
|
||||
|
@ -553,7 +553,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
|||
{ // end to end
|
||||
capsuleB.setPosition((0.99f * totalHalfLength) * yAxis);
|
||||
|
||||
if (!ShapeCollider::shapeShape(&capsuleA, &capsuleB, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should touch"
|
||||
|
@ -561,7 +561,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
|||
} else {
|
||||
++numCollisions;
|
||||
}
|
||||
if (!ShapeCollider::shapeShape(&capsuleB, &capsuleA, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should touch"
|
||||
|
@ -576,7 +576,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
|||
capsuleB.setRotation(rotation);
|
||||
capsuleB.setPosition((0.99f * (totalRadius + capsuleB.getHalfHeight())) * xAxis);
|
||||
|
||||
if (!ShapeCollider::shapeShape(&capsuleA, &capsuleB, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should touch"
|
||||
|
@ -584,7 +584,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
|||
} else {
|
||||
++numCollisions;
|
||||
}
|
||||
if (!ShapeCollider::shapeShape(&capsuleB, &capsuleA, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should touch"
|
||||
|
@ -602,7 +602,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
|||
capsuleB.setPosition(positionB);
|
||||
|
||||
// capsuleA vs capsuleB
|
||||
if (!ShapeCollider::shapeShape(&capsuleA, &capsuleB, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should touch"
|
||||
|
@ -631,7 +631,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
|||
}
|
||||
|
||||
// capsuleB vs capsuleA
|
||||
if (!ShapeCollider::shapeShape(&capsuleB, &capsuleA, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleB, &capsuleA, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should touch"
|
||||
|
@ -669,7 +669,7 @@ void ShapeColliderTests::capsuleTouchesCapsule() {
|
|||
capsuleB.setPosition(positionB);
|
||||
|
||||
// capsuleA vs capsuleB
|
||||
if (!ShapeCollider::shapeShape(&capsuleA, &capsuleB, collisions))
|
||||
if (!ShapeCollider::collideShapes(&capsuleA, &capsuleB, collisions))
|
||||
{
|
||||
std::cout << __FILE__ << ":" << __LINE__
|
||||
<< " ERROR: capsule and capsule should touch"
|
||||
|
|