mirror of
https://github.com/overte-org/overte.git
synced 2025-07-22 20:23:26 +02:00
Merge branch 'master' of github.com:highfidelity/hifi into detect-ballistic
This commit is contained in:
commit
bc65616bb3
91 changed files with 3866 additions and 885 deletions
|
@ -92,8 +92,17 @@ else ()
|
|||
if (NOT QT_CMAKE_PREFIX_PATH)
|
||||
set(QT_CMAKE_PREFIX_PATH $ENV{QT_CMAKE_PREFIX_PATH})
|
||||
endif ()
|
||||
if (NOT QT_CMAKE_PREFIX_PATH)
|
||||
get_filename_component(QT_CMAKE_PREFIX_PATH "${Qt5_DIR}/.." REALPATH)
|
||||
endif ()
|
||||
endif ()
|
||||
|
||||
if (WIN32)
|
||||
if (NOT EXISTS ${QT_CMAKE_PREFIX_PATH})
|
||||
message(FATAL_ERROR "Could not determine QT_CMAKE_PREFIX_PATH.")
|
||||
endif ()
|
||||
endif()
|
||||
|
||||
# figure out where the qt dir is
|
||||
get_filename_component(QT_DIR "${QT_CMAKE_PREFIX_PATH}/../../" ABSOLUTE)
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ Script.include([
|
|||
"libraries/gridTool.js",
|
||||
"libraries/entityList.js",
|
||||
"libraries/lightOverlayManager.js",
|
||||
"libraries/zoneOverlayManager.js",
|
||||
]);
|
||||
|
||||
var selectionDisplay = SelectionDisplay;
|
||||
|
@ -35,6 +36,7 @@ var selectionManager = SelectionManager;
|
|||
var entityPropertyDialogBox = EntityPropertyDialogBox;
|
||||
|
||||
var lightOverlayManager = new LightOverlayManager();
|
||||
var zoneOverlayManager = new ZoneOverlayManager();
|
||||
|
||||
var cameraManager = new CameraManager();
|
||||
|
||||
|
@ -47,6 +49,7 @@ var entityListTool = EntityListTool();
|
|||
selectionManager.addEventListener(function() {
|
||||
selectionDisplay.updateHandles();
|
||||
lightOverlayManager.updatePositions();
|
||||
zoneOverlayManager.updatePositions();
|
||||
});
|
||||
|
||||
var windowDimensions = Controller.getViewportDimensions();
|
||||
|
@ -77,11 +80,13 @@ var DEFAULT_LIGHT_DIMENSIONS = Vec3.multiply(20, DEFAULT_DIMENSIONS);
|
|||
var MENU_AUTO_FOCUS_ON_SELECT = "Auto Focus on Select";
|
||||
var MENU_EASE_ON_FOCUS = "Ease Orientation on Focus";
|
||||
var MENU_SHOW_LIGHTS_IN_EDIT_MODE = "Show Lights in Edit Mode";
|
||||
var MENU_SHOW_ZONES_IN_EDIT_MODE = "Show Zones in Edit Mode";
|
||||
|
||||
var SETTING_INSPECT_TOOL_ENABLED = "inspectToolEnabled";
|
||||
var SETTING_AUTO_FOCUS_ON_SELECT = "autoFocusOnSelect";
|
||||
var SETTING_EASE_ON_FOCUS = "cameraEaseOnFocus";
|
||||
var SETTING_SHOW_LIGHTS_IN_EDIT_MODE = "showLightsInEditMode";
|
||||
var SETTING_SHOW_ZONES_IN_EDIT_MODE = "showZonesInEditMode";
|
||||
|
||||
var INSUFFICIENT_PERMISSIONS_ERROR_MSG = "You do not have the necessary permissions to edit on this domain."
|
||||
var INSUFFICIENT_PERMISSIONS_IMPORT_ERROR_MSG = "You do not have the necessary permissions to place items on this domain."
|
||||
|
@ -135,6 +140,7 @@ var toolBar = (function () {
|
|||
newSphereButton,
|
||||
newLightButton,
|
||||
newTextButton,
|
||||
newZoneButton,
|
||||
browseMarketplaceButton;
|
||||
|
||||
function initialize() {
|
||||
|
@ -201,6 +207,14 @@ var toolBar = (function () {
|
|||
alpha: 0.9,
|
||||
visible: false
|
||||
});
|
||||
newZoneButton = toolBar.addTool({
|
||||
imageURL: toolIconUrl + "zonecube3.svg",
|
||||
subImage: { x: 0, y: Tool.IMAGE_WIDTH + 208, width: 256, height: 256 },
|
||||
width: toolWidth,
|
||||
height: toolHeight,
|
||||
alpha: 0.9,
|
||||
visible: false
|
||||
});
|
||||
|
||||
that.setActive(false);
|
||||
}
|
||||
|
@ -232,6 +246,7 @@ var toolBar = (function () {
|
|||
}
|
||||
toolBar.selectTool(activeButton, isActive);
|
||||
lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE));
|
||||
zoneOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE));
|
||||
};
|
||||
|
||||
// Sets visibility of tool buttons, excluding the power button
|
||||
|
@ -241,6 +256,7 @@ var toolBar = (function () {
|
|||
toolBar.showTool(newSphereButton, doShow);
|
||||
toolBar.showTool(newLightButton, doShow);
|
||||
toolBar.showTool(newTextButton, doShow);
|
||||
toolBar.showTool(newZoneButton, doShow);
|
||||
};
|
||||
|
||||
var RESIZE_INTERVAL = 50;
|
||||
|
@ -412,6 +428,21 @@ var toolBar = (function () {
|
|||
return true;
|
||||
}
|
||||
|
||||
if (newZoneButton === toolBar.clicked(clickedOverlay)) {
|
||||
var position = getPositionToCreateEntity();
|
||||
|
||||
if (position.x > 0 && position.y > 0 && position.z > 0) {
|
||||
placingEntityID = Entities.addEntity({
|
||||
type: "Zone",
|
||||
position: grid.snapToSurface(grid.snapToGrid(position, false, DEFAULT_DIMENSIONS), DEFAULT_DIMENSIONS),
|
||||
dimensions: { x: 10, y: 10, z: 10 },
|
||||
});
|
||||
} else {
|
||||
print("Can't create box: Text would be out of bounds.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
};
|
||||
|
||||
|
@ -486,12 +517,22 @@ function rayPlaneIntersection(pickRay, point, normal) {
|
|||
}
|
||||
|
||||
function findClickedEntity(event) {
|
||||
var pickZones = event.isControl;
|
||||
|
||||
if (pickZones) {
|
||||
Entities.setZonesArePickable(true);
|
||||
}
|
||||
|
||||
var pickRay = Camera.computePickRay(event.x, event.y);
|
||||
|
||||
var entityResult = Entities.findRayIntersection(pickRay, true); // want precision picking
|
||||
var lightResult = lightOverlayManager.findRayIntersection(pickRay);
|
||||
lightResult.accurate = true;
|
||||
|
||||
if (pickZones) {
|
||||
Entities.setZonesArePickable(false);
|
||||
}
|
||||
|
||||
var result;
|
||||
|
||||
if (!entityResult.intersects && !lightResult.intersects) {
|
||||
|
@ -776,6 +817,8 @@ function setupModelMenus() {
|
|||
isCheckable: true, isChecked: Settings.getValue(SETTING_EASE_ON_FOCUS) == "true" });
|
||||
Menu.addMenuItem({ menuName: "View", menuItemName: MENU_SHOW_LIGHTS_IN_EDIT_MODE, afterItem: MENU_EASE_ON_FOCUS,
|
||||
isCheckable: true, isChecked: Settings.getValue(SETTING_SHOW_LIGHTS_IN_EDIT_MODE) == "true" });
|
||||
Menu.addMenuItem({ menuName: "View", menuItemName: MENU_SHOW_ZONES_IN_EDIT_MODE, afterItem: MENU_SHOW_LIGHTS_IN_EDIT_MODE,
|
||||
isCheckable: true, isChecked: Settings.getValue(SETTING_SHOW_ZONES_IN_EDIT_MODE) == "true" });
|
||||
|
||||
Entities.setLightsArePickable(false);
|
||||
}
|
||||
|
@ -804,12 +847,14 @@ function cleanupModelMenus() {
|
|||
Menu.removeMenuItem("View", MENU_AUTO_FOCUS_ON_SELECT);
|
||||
Menu.removeMenuItem("View", MENU_EASE_ON_FOCUS);
|
||||
Menu.removeMenuItem("View", MENU_SHOW_LIGHTS_IN_EDIT_MODE);
|
||||
Menu.removeMenuItem("View", MENU_SHOW_ZONES_IN_EDIT_MODE);
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(function() {
|
||||
Settings.setValue(SETTING_AUTO_FOCUS_ON_SELECT, Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT));
|
||||
Settings.setValue(SETTING_EASE_ON_FOCUS, Menu.isOptionChecked(MENU_EASE_ON_FOCUS));
|
||||
Settings.setValue(SETTING_SHOW_LIGHTS_IN_EDIT_MODE, Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE));
|
||||
Settings.setValue(SETTING_SHOW_ZONES_IN_EDIT_MODE, Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE));
|
||||
|
||||
progressDialog.cleanup();
|
||||
toolBar.cleanup();
|
||||
|
@ -942,6 +987,8 @@ function handeMenuEvent(menuItem) {
|
|||
selectAllEtitiesInCurrentSelectionBox(true);
|
||||
} else if (menuItem == MENU_SHOW_LIGHTS_IN_EDIT_MODE) {
|
||||
lightOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_LIGHTS_IN_EDIT_MODE));
|
||||
} else if (menuItem == MENU_SHOW_ZONES_IN_EDIT_MODE) {
|
||||
zoneOverlayManager.setVisible(isActive && Menu.isOptionChecked(MENU_SHOW_ZONES_IN_EDIT_MODE));
|
||||
}
|
||||
tooltip.show(false);
|
||||
}
|
||||
|
|
72
examples/example/entities/zoneEntityExample.js
Normal file
72
examples/example/entities/zoneEntityExample.js
Normal file
|
@ -0,0 +1,72 @@
|
|||
//
|
||||
// zoneEntityExample.js
|
||||
// examples
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 4/16/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// This is an example script that demonstrates creating and editing a entity
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
HIFI_PUBLIC_BUCKET = "http://s3.amazonaws.com/hifi-public/";
|
||||
|
||||
var count = 0;
|
||||
var stopAfter = 1000;
|
||||
|
||||
var zoneEntityA = Entities.addEntity({
|
||||
type: "Zone",
|
||||
position: { x: 5, y: 5, z: 5 },
|
||||
dimensions: { x: 10, y: 10, z: 10 },
|
||||
keyLightColor: { red: 255, green: 0, blue: 0 },
|
||||
stageSunModelEnabled: false,
|
||||
keyLightDirection: { x: 0, y: -1.0, z: 0 },
|
||||
shapeType: "sphere"
|
||||
});
|
||||
|
||||
print("zoneEntityA:" + zoneEntityA);
|
||||
|
||||
var zoneEntityB = Entities.addEntity({
|
||||
type: "Zone",
|
||||
position: { x: 5, y: 5, z: 5 },
|
||||
dimensions: { x: 2, y: 2, z: 2 },
|
||||
keyLightColor: { red: 0, green: 255, blue: 0 },
|
||||
keyLightIntensity: 0.9,
|
||||
stageLatitude: 37.777,
|
||||
stageLongitude: 122.407,
|
||||
stageAltitude: 0.03,
|
||||
stageDay: 60,
|
||||
stageHour: 12,
|
||||
stageSunModelEnabled: true
|
||||
});
|
||||
|
||||
print("zoneEntityB:" + zoneEntityB);
|
||||
|
||||
|
||||
var zoneEntityC = Entities.addEntity({
|
||||
type: "Zone",
|
||||
position: { x: 5, y: 10, z: 5 },
|
||||
dimensions: { x: 10, y: 10, z: 10 },
|
||||
keyLightColor: { red: 0, green: 0, blue: 255 },
|
||||
keyLightIntensity: 0.75,
|
||||
keyLightDirection: { x: 0, y: 0, z: -1 },
|
||||
stageSunModelEnabled: false,
|
||||
shapeType: "compound",
|
||||
compoundShapeURL: "http://headache.hungry.com/~seth/hifi/cube.fbx"
|
||||
});
|
||||
|
||||
print("zoneEntityC:" + zoneEntityC);
|
||||
|
||||
|
||||
// register the call back so it fires before each data send
|
||||
Script.update.connect(function(deltaTime) {
|
||||
// stop it...
|
||||
if (count >= stopAfter) {
|
||||
print("calling Script.stop()");
|
||||
Script.stop();
|
||||
}
|
||||
count++;
|
||||
});
|
||||
|
|
@ -162,7 +162,7 @@
|
|||
|
||||
var elModelSections = document.querySelectorAll(".model-section");
|
||||
var elModelURL = document.getElementById("property-model-url");
|
||||
var elCollisionModelURL = document.getElementById("property-collision-model-url");
|
||||
var elCompoundShapeURL = document.getElementById("property-compound-shape-url");
|
||||
var elModelAnimationURL = document.getElementById("property-model-animation-url");
|
||||
var elModelAnimationPlaying = document.getElementById("property-model-animation-playing");
|
||||
var elModelAnimationFPS = document.getElementById("property-model-animation-fps");
|
||||
|
@ -182,6 +182,23 @@
|
|||
var elTextBackgroundColorGreen = document.getElementById("property-text-background-color-green");
|
||||
var elTextBackgroundColorBlue = document.getElementById("property-text-background-color-blue");
|
||||
|
||||
var elZoneSections = document.querySelectorAll(".zone-section");
|
||||
var elZoneStageSunModelEnabled = document.getElementById("property-zone-stage-sun-model-enabled");
|
||||
var elZoneKeyLightColorRed = document.getElementById("property-zone-key-light-color-red");
|
||||
var elZoneKeyLightColorGreen = document.getElementById("property-zone-key-light-color-green");
|
||||
var elZoneKeyLightColorBlue = document.getElementById("property-zone-key-light-color-blue");
|
||||
var elZoneKeyLightIntensity = document.getElementById("property-zone-key-intensity");
|
||||
var elZoneKeyLightAmbientIntensity = document.getElementById("property-zone-key-ambient-intensity");
|
||||
var elZoneKeyLightDirectionX = document.getElementById("property-zone-key-light-direction-x");
|
||||
var elZoneKeyLightDirectionY = document.getElementById("property-zone-key-light-direction-y");
|
||||
var elZoneKeyLightDirectionZ = document.getElementById("property-zone-key-light-direction-z");
|
||||
|
||||
var elZoneStageLatitude = document.getElementById("property-zone-stage-latitude");
|
||||
var elZoneStageLongitude = document.getElementById("property-zone-stage-longitude");
|
||||
var elZoneStageAltitude = document.getElementById("property-zone-stage-altitude");
|
||||
var elZoneStageDay = document.getElementById("property-zone-stage-day");
|
||||
var elZoneStageHour = document.getElementById("property-zone-stage-hour");
|
||||
|
||||
if (window.EventBridge !== undefined) {
|
||||
EventBridge.scriptEventReceived.connect(function(data) {
|
||||
data = JSON.parse(data);
|
||||
|
@ -306,7 +323,7 @@
|
|||
}
|
||||
|
||||
elModelURL.value = properties.modelURL;
|
||||
elCollisionModelURL.value = properties.collisionModelURL;
|
||||
elCompoundShapeURL.value = properties.compoundShapeURL;
|
||||
elModelAnimationURL.value = properties.animationURL;
|
||||
elModelAnimationPlaying.checked = properties.animationIsPlaying;
|
||||
elModelAnimationFPS.value = properties.animationFPS;
|
||||
|
@ -356,6 +373,32 @@
|
|||
elLightCutoff.value = properties.cutoff;
|
||||
}
|
||||
|
||||
if (properties.type != "Zone") {
|
||||
for (var i = 0; i < elZoneSections.length; i++) {
|
||||
elZoneSections[i].style.display = 'none';
|
||||
}
|
||||
} else {
|
||||
for (var i = 0; i < elZoneSections.length; i++) {
|
||||
elZoneSections[i].style.display = 'block';
|
||||
}
|
||||
|
||||
elZoneStageSunModelEnabled.checked = properties.stageSunModelEnabled;
|
||||
elZoneKeyLightColorRed.value = properties.keyLightColor.red;
|
||||
elZoneKeyLightColorGreen.value = properties.keyLightColor.green;
|
||||
elZoneKeyLightColorBlue.value = properties.keyLightColor.blue;
|
||||
elZoneKeyLightIntensity.value = properties.keyLightIntensity.toFixed(2);
|
||||
elZoneKeyLightAmbientIntensity.value = properties.keyLightAmbientIntensity.toFixed(2);
|
||||
elZoneKeyLightDirectionX.value = properties.keyLightDirection.x.toFixed(2);
|
||||
elZoneKeyLightDirectionY.value = properties.keyLightDirection.y.toFixed(2);
|
||||
elZoneKeyLightDirectionZ.value = properties.keyLightDirection.z.toFixed(2);
|
||||
|
||||
elZoneStageLatitude.value = properties.stageLatitude.toFixed(2);
|
||||
elZoneStageLongitude.value = properties.stageLongitude.toFixed(2);
|
||||
elZoneStageAltitude.value = properties.stageAltitude.toFixed(2);
|
||||
elZoneStageDay.value = properties.stageDay;
|
||||
elZoneStageHour.value = properties.stageHour;
|
||||
}
|
||||
|
||||
if (selected) {
|
||||
activeElement.focus();
|
||||
activeElement.select();
|
||||
|
@ -444,7 +487,7 @@
|
|||
elLightCutoff.addEventListener('change', createEmitNumberPropertyUpdateFunction('cutoff'));
|
||||
|
||||
elModelURL.addEventListener('change', createEmitTextPropertyUpdateFunction('modelURL'));
|
||||
elCollisionModelURL.addEventListener('change', createEmitTextPropertyUpdateFunction('collisionModelURL'));
|
||||
elCompoundShapeURL.addEventListener('change', createEmitTextPropertyUpdateFunction('compoundShapeURL'));
|
||||
elModelAnimationURL.addEventListener('change', createEmitTextPropertyUpdateFunction('animationURL'));
|
||||
elModelAnimationPlaying.addEventListener('change', createEmitCheckedPropertyUpdateFunction('animationIsPlaying'));
|
||||
elModelAnimationFPS.addEventListener('change', createEmitNumberPropertyUpdateFunction('animationFPS'));
|
||||
|
@ -468,6 +511,26 @@
|
|||
elTextBackgroundColorGreen.addEventListener('change', textBackgroundColorChangeFunction);
|
||||
elTextBackgroundColorBlue.addEventListener('change', textBackgroundColorChangeFunction);
|
||||
|
||||
elZoneStageSunModelEnabled.addEventListener('change', createEmitCheckedPropertyUpdateFunction('stageSunModelEnabled'));
|
||||
var zoneKeyLightColorChangeFunction = createEmitColorPropertyUpdateFunction(
|
||||
'keyLightColor', elZoneKeyLightColorRed, elZoneKeyLightColorGreen, elZoneKeyLightColorBlue);
|
||||
elZoneKeyLightColorRed.addEventListener('change', zoneKeyLightColorChangeFunction);
|
||||
elZoneKeyLightColorGreen.addEventListener('change', zoneKeyLightColorChangeFunction);
|
||||
elZoneKeyLightColorBlue.addEventListener('change', zoneKeyLightColorChangeFunction);
|
||||
elZoneKeyLightIntensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('keyLightIntensity'));
|
||||
elZoneKeyLightAmbientIntensity.addEventListener('change', createEmitNumberPropertyUpdateFunction('keyLightAmbientIntensity'));
|
||||
var zoneKeyLightDirectionChangeFunction = createEmitVec3PropertyUpdateFunction(
|
||||
'keyLightDirection', elZoneKeyLightDirectionX, elZoneKeyLightDirectionY, elZoneKeyLightDirectionZ);
|
||||
elZoneKeyLightDirectionX.addEventListener('change', zoneKeyLightDirectionChangeFunction);
|
||||
elZoneKeyLightDirectionY.addEventListener('change', zoneKeyLightDirectionChangeFunction);
|
||||
elZoneKeyLightDirectionZ.addEventListener('change', zoneKeyLightDirectionChangeFunction);
|
||||
|
||||
elZoneStageLatitude.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageLatitude'));
|
||||
elZoneStageLongitude.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageLongitude'));
|
||||
elZoneStageAltitude.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageAltitude'));
|
||||
elZoneStageDay.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageDay'));
|
||||
elZoneStageHour.addEventListener('change', createEmitNumberPropertyUpdateFunction('stageHour'));
|
||||
|
||||
elMoveSelectionToGrid.addEventListener("click", function() {
|
||||
EventBridge.emitWebEvent(JSON.stringify({
|
||||
type: "action",
|
||||
|
@ -712,9 +775,9 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="model-section property">
|
||||
<div class="label">Collision Model URL</div>
|
||||
<div class="label">Compound Shape URL</div>
|
||||
<div class="value">
|
||||
<input type="text" id="property-collision-model-url" class="url"></input>
|
||||
<input type="text" id="property-compound-shape-url" class="url"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="model-section property">
|
||||
|
@ -833,6 +896,73 @@
|
|||
<input class="coord" type='number' id="property-light-cutoff"></input>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="zone-section property">
|
||||
<span class="label">Stage Sun Model Enabled</span>
|
||||
<span class="value">
|
||||
<input type='checkbox' id="property-zone-stage-sun-model-enabled">
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<div class="zone-section property">
|
||||
<div class="label">Key Light Color</div>
|
||||
<div class="value">
|
||||
<div class="input-area">R <input class="coord" type='number' id="property-zone-key-light-color-red" min="0" max="255" step="1"></input></div>
|
||||
<div class="input-area">G <input class="coord" type='number' id="property-zone-key-light-color-green" min="0" max="255" step="1"></input></div>
|
||||
<div class="input-area">B <input class="coord" type='number' id="property-zone-key-light-color-blue" min="0" max="255" step="1"></input></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section property">
|
||||
<div class="label">Key Light Intensity</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-key-intensity" min="0" max="10" step="0.1"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section property">
|
||||
<div class="label">Key Light Ambient Intensity</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-key-ambient-intensity" min="0" max="10" step="0.1"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section property">
|
||||
<div class="label">Key Light Direction</div>
|
||||
<div class="value">
|
||||
<div class="input-area">Pitch <input class="coord" type='number' id="property-zone-key-light-direction-x"></input></div>
|
||||
<div class="input-area">Yaw <input class="coord" type='number' id="property-zone-key-light-direction-y"></input></div>
|
||||
<div class="input-area">Roll <input class="coord" type='number' id="property-zone-key-light-direction-z"></input></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="zone-section property">
|
||||
<div class="label">Stage Latitude</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-latitude" min="-90" max="90" step="1"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section property">
|
||||
<div class="label">Stage Longitude</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-longitude" min="-180" max="180" step="1"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section property">
|
||||
<div class="label">Stage Altitude</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-altitude" step="1"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section property">
|
||||
<div class="label">Stage Day</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-day" min="0" max="365" step="1"></input>
|
||||
</div>
|
||||
</div>
|
||||
<div class="zone-section property">
|
||||
<div class="label">Stage Hour</div>
|
||||
<div class="value">
|
||||
<input class="coord" type='number' id="property-zone-stage-hour" min="0" max="24" step="0.5"></input>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
|
|
|
@ -53,7 +53,7 @@ function Tooltip() {
|
|||
text += "ID: " + properties.id + "\n"
|
||||
if (properties.type == "Model") {
|
||||
text += "Model URL: " + properties.modelURL + "\n"
|
||||
text += "Collision Model URL: " + properties.collisionModelURL + "\n"
|
||||
text += "Compound Shape URL: " + properties.compoundShapeURL + "\n"
|
||||
text += "Animation URL: " + properties.animationURL + "\n"
|
||||
text += "Animation is playing: " + properties.animationIsPlaying + "\n"
|
||||
if (properties.sittingPoints && properties.sittingPoints.length > 0) {
|
||||
|
|
|
@ -52,7 +52,7 @@ EntityPropertyDialogBox = (function () {
|
|||
if (properties.type == "Model") {
|
||||
array.push({ label: "Model URL:", value: properties.modelURL });
|
||||
index++;
|
||||
array.push({ label: "Collision Model URL:", value: properties.collisionModelURL });
|
||||
array.push({ label: "Compound Shape URL:", value: properties.compoundShapeURL });
|
||||
index++;
|
||||
array.push({ label: "Animation URL:", value: properties.animationURL });
|
||||
index++;
|
||||
|
@ -284,7 +284,7 @@ EntityPropertyDialogBox = (function () {
|
|||
properties.locked = array[index++].value;
|
||||
if (properties.type == "Model") {
|
||||
properties.modelURL = array[index++].value;
|
||||
properties.collisionModelURL = array[index++].value;
|
||||
properties.compoundShapeURL = array[index++].value;
|
||||
properties.animationURL = array[index++].value;
|
||||
|
||||
var newAnimationIsPlaying = array[index++].value;
|
||||
|
|
|
@ -122,7 +122,7 @@ LightOverlayManager = function() {
|
|||
Entities.clearingEntities.connect(clearEntities);
|
||||
|
||||
// Add existing entities
|
||||
var ids = Entities.findEntities(MyAvatar.position, 100);
|
||||
var ids = Entities.findEntities(MyAvatar.position, 64000);
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
addEntity(ids[i]);
|
||||
}
|
||||
|
|
145
examples/libraries/zoneOverlayManager.js
Normal file
145
examples/libraries/zoneOverlayManager.js
Normal file
|
@ -0,0 +1,145 @@
|
|||
ZoneOverlayManager = function(isEntityFunc, entityAddedFunc, entityRemovedFunc, entityMovedFunc) {
|
||||
var self = this;
|
||||
|
||||
var visible = false;
|
||||
|
||||
// List of all created overlays
|
||||
var allOverlays = [];
|
||||
|
||||
// List of overlays not currently being used
|
||||
var unusedOverlays = [];
|
||||
|
||||
// Map from EntityItemID.id to overlay id
|
||||
var entityOverlays = {};
|
||||
|
||||
// Map from EntityItemID.id to EntityItemID object
|
||||
var entityIDs = {};
|
||||
|
||||
this.updatePositions = function(ids) {
|
||||
for (var id in entityIDs) {
|
||||
var entityID = entityIDs[id];
|
||||
var properties = Entities.getEntityProperties(entityID);
|
||||
Overlays.editOverlay(entityOverlays[entityID.id].solid, {
|
||||
position: properties.position,
|
||||
rotation: properties.rotation,
|
||||
dimensions: properties.dimensions,
|
||||
});
|
||||
Overlays.editOverlay(entityOverlays[entityID.id].outline, {
|
||||
position: properties.position,
|
||||
rotation: properties.rotation,
|
||||
dimensions: properties.dimensions,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
this.setVisible = function(isVisible) {
|
||||
if (visible != isVisible) {
|
||||
visible = isVisible;
|
||||
for (var id in entityOverlays) {
|
||||
Overlays.editOverlay(entityOverlays[id].solid, { visible: visible });
|
||||
Overlays.editOverlay(entityOverlays[id].outline, { visible: visible });
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Allocate or get an unused overlay
|
||||
function getOverlay() {
|
||||
if (unusedOverlays.length == 0) {
|
||||
var overlay = Overlays.addOverlay("cube", {
|
||||
});
|
||||
allOverlays.push(overlay);
|
||||
} else {
|
||||
var overlay = unusedOverlays.pop();
|
||||
};
|
||||
return overlay;
|
||||
}
|
||||
|
||||
function releaseOverlay(overlay) {
|
||||
unusedOverlays.push(overlay);
|
||||
Overlays.editOverlay(overlay, { visible: false });
|
||||
}
|
||||
|
||||
function addEntity(entityID) {
|
||||
var properties = Entities.getEntityProperties(entityID);
|
||||
if (properties.type == "Zone" && !(entityID.id in entityOverlays)) {
|
||||
var overlaySolid = getOverlay();
|
||||
var overlayOutline = getOverlay();
|
||||
|
||||
entityOverlays[entityID.id] = {
|
||||
solid: overlaySolid,
|
||||
outline: overlayOutline,
|
||||
}
|
||||
entityIDs[entityID.id] = entityID;
|
||||
|
||||
var color = {
|
||||
red: Math.round(Math.random() * 255),
|
||||
green: Math.round(Math.random() * 255),
|
||||
blue: Math.round(Math.random() * 255)
|
||||
};
|
||||
Overlays.editOverlay(overlaySolid, {
|
||||
position: properties.position,
|
||||
rotation: properties.rotation,
|
||||
dimensions: properties.dimensions,
|
||||
visible: visible,
|
||||
solid: true,
|
||||
alpha: 0.1,
|
||||
color: color,
|
||||
ignoreRayIntersection: true,
|
||||
});
|
||||
Overlays.editOverlay(overlayOutline, {
|
||||
position: properties.position,
|
||||
rotation: properties.rotation,
|
||||
dimensions: properties.dimensions,
|
||||
visible: visible,
|
||||
solid: false,
|
||||
dashed: false,
|
||||
lineWidth: 2.0,
|
||||
alpha: 1.0,
|
||||
color: color,
|
||||
ignoreRayIntersection: true,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function deleteEntity(entityID) {
|
||||
if (entityID.id in entityOverlays) {
|
||||
releaseOverlay(entityOverlays[entityID.id].outline);
|
||||
releaseOverlay(entityOverlays[entityID.id].solid);
|
||||
delete entityOverlays[entityID.id];
|
||||
}
|
||||
}
|
||||
|
||||
function changeEntityID(oldEntityID, newEntityID) {
|
||||
entityOverlays[newEntityID.id] = entityOverlays[oldEntityID.id];
|
||||
entityIDs[newEntityID.id] = newEntityID;
|
||||
|
||||
delete entityOverlays[oldEntityID.id];
|
||||
delete entityIDs[oldEntityID.id];
|
||||
}
|
||||
|
||||
function clearEntities() {
|
||||
for (var id in entityOverlays) {
|
||||
releaseOverlay(entityOverlays[id].outline);
|
||||
releaseOverlay(entityOverlays[id].solid);
|
||||
}
|
||||
entityOverlays = {};
|
||||
entityIDs = {};
|
||||
}
|
||||
|
||||
Entities.addingEntity.connect(addEntity);
|
||||
Entities.changingEntityID.connect(changeEntityID);
|
||||
Entities.deletingEntity.connect(deleteEntity);
|
||||
Entities.clearingEntities.connect(clearEntities);
|
||||
|
||||
// Add existing entities
|
||||
var ids = Entities.findEntities(MyAvatar.position, 64000);
|
||||
for (var i = 0; i < ids.length; i++) {
|
||||
addEntity(ids[i]);
|
||||
}
|
||||
|
||||
Script.scriptEnding.connect(function() {
|
||||
for (var i = 0; i < allOverlays.length; i++) {
|
||||
Overlays.deleteOverlay(allOverlays[i]);
|
||||
}
|
||||
});
|
||||
};
|
|
@ -54,7 +54,7 @@ else ()
|
|||
list(REMOVE_ITEM INTERFACE_SRCS ${SPEECHRECOGNIZER_CPP})
|
||||
endif ()
|
||||
|
||||
find_package(Qt5 COMPONENTS Gui Multimedia Network OpenGL Script Svg WebKitWidgets)
|
||||
find_package(Qt5 COMPONENTS Gui Multimedia Network OpenGL Qml Quick Script Svg WebKitWidgets)
|
||||
|
||||
# grab the ui files in resources/ui
|
||||
file (GLOB_RECURSE QT_UI_FILES ui/*.ui)
|
||||
|
|
76
interface/resources/qml/AddressBarDialog.qml
Normal file
76
interface/resources/qml/AddressBarDialog.qml
Normal file
|
@ -0,0 +1,76 @@
|
|||
import Hifi 1.0
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
|
||||
CustomDialog {
|
||||
title: "Go to..."
|
||||
objectName: "AddressBarDialog"
|
||||
height: 128
|
||||
width: 512
|
||||
destroyOnCloseButton: false
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
reset();
|
||||
}
|
||||
}
|
||||
|
||||
onEnabledChanged: {
|
||||
if (enabled) {
|
||||
addressLine.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
function reset() {
|
||||
addressLine.text = ""
|
||||
goButton.source = "../images/address-bar-submit.svg"
|
||||
}
|
||||
|
||||
AddressBarDialog {
|
||||
id: addressBarDialog
|
||||
|
||||
// The client area
|
||||
anchors.fill: parent
|
||||
anchors.margins: parent.margins
|
||||
anchors.topMargin: parent.topMargin
|
||||
|
||||
CustomBorder {
|
||||
height: 64
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
anchors.right: goButton.left
|
||||
anchors.rightMargin: 8
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
CustomTextInput {
|
||||
id: addressLine
|
||||
anchors.fill: parent
|
||||
helperText: "domain, location, @user, /x,y,z"
|
||||
anchors.margins: 8
|
||||
onAccepted: {
|
||||
addressBarDialog.loadAddress(addressLine.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Image {
|
||||
id: goButton
|
||||
width: 32
|
||||
height: 32
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 8
|
||||
source: "../images/address-bar-submit.svg"
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
parent.source = "../images/address-bar-submit-active.svg"
|
||||
addressBarDialog.loadAddress(addressLine.text)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
45
interface/resources/qml/Browser.qml
Normal file
45
interface/resources/qml/Browser.qml
Normal file
|
@ -0,0 +1,45 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Dialogs 1.2
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
import QtWebKit 3.0
|
||||
|
||||
CustomDialog {
|
||||
title: "Test Dlg"
|
||||
id: testDialog
|
||||
objectName: "Browser"
|
||||
width: 1280
|
||||
height: 720
|
||||
|
||||
Item {
|
||||
id: clientArea
|
||||
// The client area
|
||||
anchors.fill: parent
|
||||
anchors.margins: parent.margins
|
||||
anchors.topMargin: parent.topMargin
|
||||
|
||||
|
||||
ScrollView {
|
||||
anchors.fill: parent
|
||||
WebView {
|
||||
id: webview
|
||||
url: "http://slashdot.org"
|
||||
anchors.fill: parent
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
// This is the behavior, and it applies a NumberAnimation to any attempt to set the x property
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
}
|
||||
*/
|
12
interface/resources/qml/CustomBorder.qml
Normal file
12
interface/resources/qml/CustomBorder.qml
Normal file
|
@ -0,0 +1,12 @@
|
|||
import QtQuick 2.3
|
||||
|
||||
|
||||
Rectangle {
|
||||
SystemPalette { id: myPalette; colorGroup: SystemPalette.Active }
|
||||
property int margin: 5
|
||||
color: myPalette.window
|
||||
border.color: myPalette.dark
|
||||
border.width: 5
|
||||
radius: border.width * 2
|
||||
}
|
||||
|
23
interface/resources/qml/CustomButton.qml
Normal file
23
interface/resources/qml/CustomButton.qml
Normal file
|
@ -0,0 +1,23 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.3
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
|
||||
Button {
|
||||
SystemPalette { id: myPalette; colorGroup: SystemPalette.Active }
|
||||
text: "Text"
|
||||
width: 128
|
||||
height: 64
|
||||
style: ButtonStyle {
|
||||
background: CustomBorder {
|
||||
anchors.fill: parent
|
||||
}
|
||||
label: CustomText {
|
||||
renderType: Text.NativeRendering
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: control.text
|
||||
color: control.enabled ? myPalette.text : myPalette.dark
|
||||
}
|
||||
}
|
||||
}
|
162
interface/resources/qml/CustomDialog.qml
Normal file
162
interface/resources/qml/CustomDialog.qml
Normal file
|
@ -0,0 +1,162 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Dialogs 1.2
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
import "hifiConstants.js" as HifiConstants
|
||||
|
||||
Item {
|
||||
SystemPalette { id: myPalette; colorGroup: SystemPalette.Active }
|
||||
id: dialog
|
||||
width: 256
|
||||
height: 256
|
||||
scale: 0.0
|
||||
enabled: false
|
||||
property int animationDuration: 400
|
||||
property bool destroyOnInvisible: false
|
||||
property bool destroyOnCloseButton: true
|
||||
property bool resizable: false
|
||||
property int minX: 256
|
||||
property int minY: 256
|
||||
clip: true
|
||||
|
||||
onEnabledChanged: {
|
||||
scale = enabled ? 1.0 : 0.0
|
||||
}
|
||||
|
||||
onScaleChanged: {
|
||||
visible = (scale != 0.0);
|
||||
}
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible && destroyOnInvisible) {
|
||||
console.log("Destroying closed component");
|
||||
destroy();
|
||||
}
|
||||
}
|
||||
|
||||
function close() {
|
||||
if (destroyOnCloseButton) {
|
||||
destroyOnInvisible = true
|
||||
}
|
||||
enabled = false;
|
||||
}
|
||||
|
||||
function deltaSize(dx, dy) {
|
||||
width = Math.max(width + dx, minX)
|
||||
height = Math.max(height + dy, minY)
|
||||
}
|
||||
|
||||
Behavior on scale {
|
||||
NumberAnimation {
|
||||
//This specifies how long the animation takes
|
||||
duration: dialog.animationDuration
|
||||
//This selects an easing curve to interpolate with, the default is Easing.Linear
|
||||
easing.type: Easing.InOutBounce
|
||||
}
|
||||
}
|
||||
|
||||
property int topMargin: dialog.height - clientBorder.height + 8
|
||||
property int margins: 8
|
||||
property string title
|
||||
property int titleSize: titleBorder.height + 12
|
||||
property string frameColor: HifiConstants.color
|
||||
property string backgroundColor: myPalette.window
|
||||
property string headerBackgroundColor: myPalette.dark
|
||||
|
||||
CustomBorder {
|
||||
id: windowBorder
|
||||
anchors.fill: parent
|
||||
border.color: dialog.frameColor
|
||||
color: dialog.backgroundColor
|
||||
|
||||
CustomBorder {
|
||||
id: titleBorder
|
||||
height: 48
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
border.color: dialog.frameColor
|
||||
color: dialog.headerBackgroundColor
|
||||
|
||||
CustomText {
|
||||
id: titleText
|
||||
color: "white"
|
||||
text: dialog.title
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
anchors.fill: parent
|
||||
}
|
||||
|
||||
MouseArea {
|
||||
id: titleDrag
|
||||
anchors.right: closeButton.left
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
anchors.rightMargin: 4
|
||||
drag {
|
||||
target: dialog
|
||||
minimumX: 0
|
||||
minimumY: 0
|
||||
maximumX: dialog.parent ? dialog.parent.width - dialog.width : 0
|
||||
maximumY: dialog.parent ? dialog.parent.height - dialog.height : 0
|
||||
}
|
||||
}
|
||||
Image {
|
||||
id: closeButton
|
||||
x: 360
|
||||
height: 16
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
width: 16
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 12
|
||||
source: "../styles/close.svg"
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
dialog.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
} // header border
|
||||
|
||||
CustomBorder {
|
||||
id: clientBorder
|
||||
border.color: dialog.frameColor
|
||||
color: "#00000000"
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
anchors.top: titleBorder.bottom
|
||||
anchors.topMargin: -titleBorder.border.width
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 0
|
||||
clip: true
|
||||
} // client border
|
||||
} // window border
|
||||
|
||||
MouseArea {
|
||||
id: sizeDrag
|
||||
property int startX
|
||||
property int startY
|
||||
anchors.right: parent.right
|
||||
anchors.bottom: parent.bottom
|
||||
width: 16
|
||||
height: 16
|
||||
hoverEnabled: true
|
||||
onPressed: {
|
||||
startX = mouseX
|
||||
startY = mouseY
|
||||
}
|
||||
onPositionChanged: {
|
||||
if (pressed && dialog.resizable) {
|
||||
dialog.deltaSize((mouseX - startX), (mouseY - startY))
|
||||
startX = mouseX
|
||||
startY = mouseY
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
7
interface/resources/qml/CustomText.qml
Normal file
7
interface/resources/qml/CustomText.qml
Normal file
|
@ -0,0 +1,7 @@
|
|||
import QtQuick 2.3
|
||||
|
||||
Text {
|
||||
font.family: "Helvetica"
|
||||
font.pointSize: 18
|
||||
}
|
||||
|
10
interface/resources/qml/CustomTextArea.qml
Normal file
10
interface/resources/qml/CustomTextArea.qml
Normal file
|
@ -0,0 +1,10 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
|
||||
TextArea {
|
||||
font.family: "Helvetica"
|
||||
font.pointSize: 18
|
||||
backgroundVisible: false
|
||||
readOnly: true
|
||||
}
|
||||
|
7
interface/resources/qml/CustomTextEdit.qml
Normal file
7
interface/resources/qml/CustomTextEdit.qml
Normal file
|
@ -0,0 +1,7 @@
|
|||
import QtQuick 2.3
|
||||
|
||||
TextEdit {
|
||||
font.family: "Helvetica"
|
||||
font.pointSize: 18
|
||||
}
|
||||
|
34
interface/resources/qml/CustomTextInput.qml
Normal file
34
interface/resources/qml/CustomTextInput.qml
Normal file
|
@ -0,0 +1,34 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
|
||||
TextInput {
|
||||
SystemPalette { id: myPalette; colorGroup: SystemPalette.Active }
|
||||
property string helperText: ""
|
||||
font.family: "Helvetica"
|
||||
font.pointSize: 18
|
||||
width: 256
|
||||
height: 64
|
||||
color: myPalette.text
|
||||
clip: true
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
|
||||
onTextChanged: {
|
||||
if (text == "") {
|
||||
helperText.visible = true;
|
||||
} else {
|
||||
helperText.visible = false;
|
||||
}
|
||||
}
|
||||
|
||||
Text {
|
||||
id: helperText
|
||||
anchors.fill: parent
|
||||
font.pointSize: parent.font.pointSize
|
||||
font.family: "Helvetica"
|
||||
verticalAlignment: TextInput.AlignVCenter
|
||||
text: parent.helperText
|
||||
color: myPalette.dark
|
||||
clip: true
|
||||
}
|
||||
}
|
||||
|
8
interface/resources/qml/Icon.qml
Normal file
8
interface/resources/qml/Icon.qml
Normal file
|
@ -0,0 +1,8 @@
|
|||
import QtQuick 1.0
|
||||
|
||||
Image {
|
||||
id: icon
|
||||
width: 64
|
||||
height: 64
|
||||
source: "file.svg"
|
||||
}
|
24
interface/resources/qml/IconControl.qml
Normal file
24
interface/resources/qml/IconControl.qml
Normal file
|
@ -0,0 +1,24 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.3
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
|
||||
Button {
|
||||
text: "Text"
|
||||
style: ButtonStyle {
|
||||
background: Item { anchors.fill: parent }
|
||||
label: Text {
|
||||
id: icon
|
||||
width: height
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
renderType: Text.NativeRendering
|
||||
font.family: iconFont.name
|
||||
font.pointSize: 18
|
||||
property alias unicode: icon.text
|
||||
FontLoader { id: iconFont; source: "/fonts/fontawesome-webfont.ttf"; }
|
||||
text: control.text
|
||||
color: control.enabled ? "white" : "dimgray"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
191
interface/resources/qml/LoginDialog.qml
Normal file
191
interface/resources/qml/LoginDialog.qml
Normal file
|
@ -0,0 +1,191 @@
|
|||
import Hifi 1.0
|
||||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
import "hifiConstants.js" as HifiConstants
|
||||
|
||||
CustomDialog {
|
||||
title: "Login"
|
||||
SystemPalette { id: myPalette; colorGroup: SystemPalette.Active }
|
||||
objectName: "LoginDialog"
|
||||
height: 512
|
||||
width: 384
|
||||
|
||||
onVisibleChanged: {
|
||||
if (!visible) {
|
||||
reset()
|
||||
}
|
||||
}
|
||||
|
||||
onEnabledChanged: {
|
||||
if (enabled) {
|
||||
username.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
function reset() {
|
||||
username.text = ""
|
||||
password.text = ""
|
||||
loginDialog.statusText = ""
|
||||
}
|
||||
|
||||
LoginDialog {
|
||||
id: loginDialog
|
||||
anchors.fill: parent
|
||||
anchors.margins: parent.margins
|
||||
anchors.topMargin: parent.topMargin
|
||||
Column {
|
||||
anchors.topMargin: 8
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.top: parent.top
|
||||
spacing: 8
|
||||
|
||||
Image {
|
||||
height: 64
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
width: 64
|
||||
source: "../images/hifi-logo.svg"
|
||||
}
|
||||
|
||||
CustomBorder {
|
||||
width: 304
|
||||
height: 64
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
CustomTextInput {
|
||||
id: username
|
||||
anchors.fill: parent
|
||||
helperText: "Username or Email"
|
||||
anchors.margins: 8
|
||||
KeyNavigation.tab: password
|
||||
KeyNavigation.backtab: password
|
||||
onAccepted: {
|
||||
password.forceActiveFocus()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomBorder {
|
||||
width: 304
|
||||
height: 64
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
CustomTextInput {
|
||||
id: password
|
||||
anchors.fill: parent
|
||||
echoMode: TextInput.Password
|
||||
helperText: "Password"
|
||||
anchors.margins: 8
|
||||
KeyNavigation.tab: username
|
||||
KeyNavigation.backtab: username
|
||||
onAccepted: {
|
||||
if (username.text == "") {
|
||||
username.forceActiveFocus()
|
||||
} else {
|
||||
loginDialog.login(username.text, password.text)
|
||||
}
|
||||
}
|
||||
onFocusChanged: {
|
||||
if (password.focus) {
|
||||
password.selectAll()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
textFormat: Text.StyledText
|
||||
width: parent.width
|
||||
height: 96
|
||||
wrapMode: Text.WordWrap
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
text: loginDialog.statusText
|
||||
}
|
||||
}
|
||||
|
||||
Column {
|
||||
anchors.bottomMargin: 5
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 0
|
||||
anchors.left: parent.left
|
||||
anchors.bottom: parent.bottom
|
||||
|
||||
Rectangle {
|
||||
width: 192
|
||||
height: 64
|
||||
anchors.horizontalCenter: parent.horizontalCenter
|
||||
color: HifiConstants.color
|
||||
border.width: 0
|
||||
radius: 10
|
||||
|
||||
MouseArea {
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 0
|
||||
anchors.top: parent.top
|
||||
anchors.right: parent.right
|
||||
anchors.left: parent.left
|
||||
onClicked: {
|
||||
loginDialog.login(username.text, password.text)
|
||||
}
|
||||
}
|
||||
|
||||
Row {
|
||||
anchors.centerIn: parent
|
||||
anchors.verticalCenter: parent.verticalCenter
|
||||
spacing: 8
|
||||
Image {
|
||||
id: loginIcon
|
||||
height: 32
|
||||
width: 32
|
||||
source: "../images/login.svg"
|
||||
}
|
||||
CustomText {
|
||||
text: "Login"
|
||||
color: "white"
|
||||
width: 64
|
||||
height: parent.height
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CustomText {
|
||||
width: parent.width
|
||||
height: 24
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
text:"Create Account"
|
||||
font.pointSize: 12
|
||||
font.bold: true
|
||||
color: HifiConstants.color
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
loginDialog.openUrl(loginDialog.rootUrl + "/signup")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomText {
|
||||
width: parent.width
|
||||
height: 24
|
||||
horizontalAlignment: Text.AlignHCenter
|
||||
verticalAlignment: Text.AlignVCenter
|
||||
font.pointSize: 12
|
||||
text: "Recover Password"
|
||||
color: HifiConstants.color
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
onClicked: {
|
||||
loginDialog.openUrl(loginDialog.rootUrl + "/users/password/new")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
236
interface/resources/qml/Palettes.qml
Normal file
236
interface/resources/qml/Palettes.qml
Normal file
|
@ -0,0 +1,236 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Dialogs 1.2
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
|
||||
Rectangle {
|
||||
color: "teal"
|
||||
height: 512
|
||||
width: 192
|
||||
SystemPalette { id: sp; colorGroup: SystemPalette.Active }
|
||||
SystemPalette { id: spi; colorGroup: SystemPalette.Inactive }
|
||||
SystemPalette { id: spd; colorGroup: SystemPalette.Disabled }
|
||||
|
||||
Column {
|
||||
anchors.margins: 8
|
||||
anchors.fill: parent
|
||||
spacing: 8
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 16
|
||||
Text { height: parent.height; width: 128; text: "base" }
|
||||
Rectangle { height: parent.height; width: 16; color: sp.base }
|
||||
Rectangle { height: parent.height; width: 16; color: spi.base }
|
||||
Rectangle { height: parent.height; width: 16; color: spd.base }
|
||||
}
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 16
|
||||
Text { height: parent.height; width: 128; text: "alternateBase" }
|
||||
Rectangle { height: parent.height; width: 16; color: sp.alternateBase }
|
||||
Rectangle { height: parent.height; width: 16; color: spi.alternateBase }
|
||||
Rectangle { height: parent.height; width: 16; color: spd.alternateBase }
|
||||
}
|
||||
Item {
|
||||
height: 16
|
||||
width:parent.width
|
||||
}
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 16
|
||||
Text { height: parent.height; width: 128; text: "dark" }
|
||||
Rectangle { height: parent.height; width: 16; color: sp.dark }
|
||||
Rectangle { height: parent.height; width: 16; color: spi.dark }
|
||||
Rectangle { height: parent.height; width: 16; color: spd.dark }
|
||||
}
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 16
|
||||
Text { height: parent.height; width: 128; text: "mid" }
|
||||
Rectangle { height: parent.height; width: 16; color: sp.mid }
|
||||
Rectangle { height: parent.height; width: 16; color: spi.mid }
|
||||
Rectangle { height: parent.height; width: 16; color: spd.mid }
|
||||
}
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 16
|
||||
Text { height: parent.height; width: 128; text: "mid light" }
|
||||
Rectangle { height: parent.height; width: 16; color: sp.midlight }
|
||||
Rectangle { height: parent.height; width: 16; color: spi.midlight }
|
||||
Rectangle { height: parent.height; width: 16; color: spd.midlight }
|
||||
}
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 16
|
||||
Text { height: parent.height; width: 128; text: "light" }
|
||||
Rectangle { height: parent.height; width: 16; color: sp.light}
|
||||
Rectangle { height: parent.height; width: 16; color: spi.light}
|
||||
Rectangle { height: parent.height; width: 16; color: spd.light}
|
||||
}
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 16
|
||||
Text { height: parent.height; width: 128; text: "shadow" }
|
||||
Rectangle { height: parent.height; width: 16; color: sp.shadow}
|
||||
Rectangle { height: parent.height; width: 16; color: spi.shadow}
|
||||
Rectangle { height: parent.height; width: 16; color: spd.shadow}
|
||||
}
|
||||
Item {
|
||||
height: 16
|
||||
width:parent.width
|
||||
}
|
||||
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 16
|
||||
Text { height: parent.height; width: 128; text: "text" }
|
||||
Rectangle { height: parent.height; width: 16; color: sp.text }
|
||||
Rectangle { height: parent.height; width: 16; color: spi.text }
|
||||
Rectangle { height: parent.height; width: 16; color: spd.text }
|
||||
}
|
||||
Item {
|
||||
height: 16
|
||||
width:parent.width
|
||||
}
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 16
|
||||
Text { height: parent.height; width: 128; text: "window" }
|
||||
Rectangle { height: parent.height; width: 16; color: sp.window }
|
||||
Rectangle { height: parent.height; width: 16; color: spi.window }
|
||||
Rectangle { height: parent.height; width: 16; color: spd.window }
|
||||
}
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 16
|
||||
Text { height: parent.height; width: 128; text: "window text" }
|
||||
Rectangle { height: parent.height; width: 16; color: sp.windowText }
|
||||
Rectangle { height: parent.height; width: 16; color: spi.windowText }
|
||||
Rectangle { height: parent.height; width: 16; color: spd.windowText }
|
||||
}
|
||||
Item {
|
||||
height: 16
|
||||
width:parent.width
|
||||
}
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 16
|
||||
Text { height: parent.height; width: 128; text: "button" }
|
||||
Rectangle { height: parent.height; width: 16; color: sp.button }
|
||||
Rectangle { height: parent.height; width: 16; color: spi.button }
|
||||
Rectangle { height: parent.height; width: 16; color: spd.button }
|
||||
}
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 16
|
||||
Text { height: parent.height; width: 128; text: "buttonText" }
|
||||
Rectangle { height: parent.height; width: 16; color: sp.buttonText }
|
||||
Rectangle { height: parent.height; width: 16; color: spi.buttonText }
|
||||
Rectangle { height: parent.height; width: 16; color: spd.buttonText }
|
||||
}
|
||||
Item {
|
||||
height: 16
|
||||
width:parent.width
|
||||
}
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 16
|
||||
Text { height: parent.height; width: 128; text: "highlight" }
|
||||
Rectangle { height: parent.height; width: 16; color: sp.highlight }
|
||||
Rectangle { height: parent.height; width: 16; color: spi.highlight }
|
||||
Rectangle { height: parent.height; width: 16; color: spd.highlight }
|
||||
}
|
||||
Row {
|
||||
width: parent.width
|
||||
height: 16
|
||||
Text { height: parent.height; width: 128; text: "highlighted text" }
|
||||
Rectangle { height: parent.height; width: 16; color: sp.highlightedText}
|
||||
Rectangle { height: parent.height; width: 16; color: spi.highlightedText}
|
||||
Rectangle { height: parent.height; width: 16; color: spd.highlightedText}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
CustomDialog {
|
||||
title: "Test Dlg"
|
||||
anchors.fill: parent
|
||||
|
||||
Rectangle {
|
||||
property int d: 100
|
||||
id: square
|
||||
objectName: "testRect"
|
||||
width: d
|
||||
height: d
|
||||
anchors.centerIn: parent
|
||||
color: "red"
|
||||
NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; }
|
||||
}
|
||||
|
||||
|
||||
CustomTextEdit {
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 12
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 12
|
||||
clip: true
|
||||
text: "test edit"
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: parent.titleSize + 12
|
||||
}
|
||||
|
||||
CustomButton {
|
||||
x: 128
|
||||
y: 192
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 12
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 12
|
||||
onClicked: {
|
||||
console.log("Click");
|
||||
if (square.visible) {
|
||||
square.visible = false
|
||||
} else {
|
||||
square.visible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomButton {
|
||||
id: customButton2
|
||||
y: 192
|
||||
text: "Close"
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 12
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 12
|
||||
onClicked: {
|
||||
onClicked: testDialog.x == 0 ? testDialog.x = 200 : testDialog.x = 0
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
console.log("Key " + event.key);
|
||||
switch (event.key) {
|
||||
case Qt.Key_Q:
|
||||
if (Qt.ControlModifier == event.modifiers) {
|
||||
event.accepted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
// This is the behavior, and it applies a NumberAnimation to any attempt to set the x property
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
}
|
||||
*/
|
9
interface/resources/qml/Root.qml
Normal file
9
interface/resources/qml/Root.qml
Normal file
|
@ -0,0 +1,9 @@
|
|||
import Hifi 1.0
|
||||
import QtQuick 2.3
|
||||
|
||||
Root {
|
||||
id: root
|
||||
width: 1280
|
||||
height: 720
|
||||
}
|
||||
|
106
interface/resources/qml/TestDialog.qml
Normal file
106
interface/resources/qml/TestDialog.qml
Normal file
|
@ -0,0 +1,106 @@
|
|||
import QtQuick 2.3
|
||||
import QtQuick.Controls 1.2
|
||||
import QtQuick.Window 2.2
|
||||
import QtQuick.Dialogs 1.2
|
||||
import QtQuick.Controls.Styles 1.3
|
||||
|
||||
CustomDialog {
|
||||
title: "Test Dialog"
|
||||
id: testDialog
|
||||
objectName: "TestDialog"
|
||||
width: 512
|
||||
height: 512
|
||||
animationDuration: 200
|
||||
|
||||
onEnabledChanged: {
|
||||
if (enabled) {
|
||||
edit.forceActiveFocus();
|
||||
}
|
||||
}
|
||||
|
||||
Item {
|
||||
id: clientArea
|
||||
// The client area
|
||||
anchors.fill: parent
|
||||
anchors.margins: parent.margins
|
||||
anchors.topMargin: parent.topMargin
|
||||
|
||||
Rectangle {
|
||||
property int d: 100
|
||||
id: square
|
||||
objectName: "testRect"
|
||||
width: d
|
||||
height: d
|
||||
anchors.centerIn: parent
|
||||
color: "red"
|
||||
NumberAnimation on rotation { from: 0; to: 360; duration: 2000; loops: Animation.Infinite; }
|
||||
}
|
||||
|
||||
|
||||
CustomTextEdit {
|
||||
id: edit
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 12
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 12
|
||||
clip: true
|
||||
text: "test edit"
|
||||
anchors.top: parent.top
|
||||
anchors.topMargin: 12
|
||||
}
|
||||
|
||||
CustomButton {
|
||||
x: 128
|
||||
y: 192
|
||||
text: "Test"
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 12
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 12
|
||||
onClicked: {
|
||||
console.log("Click");
|
||||
|
||||
if (square.visible) {
|
||||
square.visible = false
|
||||
} else {
|
||||
square.visible = true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
CustomButton {
|
||||
id: customButton2
|
||||
y: 192
|
||||
text: "Move"
|
||||
anchors.left: parent.left
|
||||
anchors.leftMargin: 12
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 12
|
||||
onClicked: {
|
||||
onClicked: testDialog.x == 0 ? testDialog.x = 200 : testDialog.x = 0
|
||||
}
|
||||
}
|
||||
|
||||
Keys.onPressed: {
|
||||
console.log("Key " + event.key);
|
||||
switch (event.key) {
|
||||
case Qt.Key_Q:
|
||||
if (Qt.ControlModifier == event.modifiers) {
|
||||
event.accepted = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
|
||||
// This is the behavior, and it applies a NumberAnimation to any attempt to set the x property
|
||||
|
||||
MouseArea {
|
||||
anchors.fill: parent
|
||||
}
|
||||
*/
|
35
interface/resources/qml/TestRoot.qml
Normal file
35
interface/resources/qml/TestRoot.qml
Normal file
|
@ -0,0 +1,35 @@
|
|||
import Hifi 1.0
|
||||
import QtQuick 2.3
|
||||
|
||||
Root {
|
||||
id: root
|
||||
width: 1280
|
||||
height: 720
|
||||
|
||||
CustomButton {
|
||||
id: messageBox
|
||||
anchors.right: createDialog.left
|
||||
anchors.rightMargin: 24
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 24
|
||||
text: "Message"
|
||||
onClicked: {
|
||||
console.log("Foo")
|
||||
root.information("a")
|
||||
console.log("Bar")
|
||||
}
|
||||
}
|
||||
|
||||
CustomButton {
|
||||
id: createDialog
|
||||
anchors.right: parent.right
|
||||
anchors.rightMargin: 24
|
||||
anchors.bottom: parent.bottom
|
||||
anchors.bottomMargin: 24
|
||||
text: "Create"
|
||||
onClicked: {
|
||||
root.loadChild("TestDialog.qml");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
29
interface/resources/qml/componentCreation.js
Normal file
29
interface/resources/qml/componentCreation.js
Normal file
|
@ -0,0 +1,29 @@
|
|||
var component;
|
||||
var instance;
|
||||
var parent;
|
||||
|
||||
function createObject(parentObject, url) {
|
||||
parent = parentObject;
|
||||
component = Qt.createComponent(url);
|
||||
if (component.status == Component.Ready)
|
||||
finishCreation();
|
||||
else
|
||||
component.statusChanged.connect(finishCreation);
|
||||
}
|
||||
|
||||
function finishCreation() {
|
||||
if (component.status == Component.Ready) {
|
||||
instance = component.createObject(parent, {"x": 100, "y": 100});
|
||||
if (instance == null) {
|
||||
// Error Handling
|
||||
console.log("Error creating object");
|
||||
} else {
|
||||
instance.enabled = true
|
||||
}
|
||||
} else if (component.status == Component.Error) {
|
||||
// Error Handling
|
||||
console.log("Error loading component:", component.errorString());
|
||||
} else {
|
||||
console.log("Unknown component status: " + component.status);
|
||||
}
|
||||
}
|
4
interface/resources/qml/hifiConstants.js
Normal file
4
interface/resources/qml/hifiConstants.js
Normal file
|
@ -0,0 +1,4 @@
|
|||
var color = "#0e7077"
|
||||
var Colors = {
|
||||
hifiBlue: "#0e7077"
|
||||
}
|
|
@ -135,6 +135,7 @@
|
|||
#include "ui/Snapshot.h"
|
||||
#include "ui/StandAloneJSConsole.h"
|
||||
#include "ui/Stats.h"
|
||||
#include "ui/AddressBarDialog.h"
|
||||
|
||||
// ON WIndows PC, NVidia Optimus laptop, we want to enable NVIDIA GPU
|
||||
#if defined(Q_OS_WIN)
|
||||
|
@ -207,8 +208,12 @@ public:
|
|||
|
||||
void messageHandler(QtMsgType type, const QMessageLogContext& context, const QString& message) {
|
||||
QString logMessage = LogHandler::getInstance().printMessage((LogMsgType) type, context, message);
|
||||
|
||||
|
||||
if (!logMessage.isEmpty()) {
|
||||
#ifdef Q_OS_WIN
|
||||
OutputDebugStringA(logMessage.toLocal8Bit().constData());
|
||||
OutputDebugStringA("\n");
|
||||
#endif
|
||||
Application::getInstance()->getLogger()->addMessage(qPrintable(logMessage + "\n"));
|
||||
}
|
||||
}
|
||||
|
@ -257,6 +262,7 @@ bool setupEssentials(int& argc, char** argv) {
|
|||
#endif
|
||||
auto discoverabilityManager = DependencyManager::set<DiscoverabilityManager>();
|
||||
auto sceneScriptingInterface = DependencyManager::set<SceneScriptingInterface>();
|
||||
auto offscreenUi = DependencyManager::set<OffscreenUi>();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -313,8 +319,10 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
#ifdef Q_OS_WIN
|
||||
installNativeEventFilter(&MyNativeEventFilter::getInstance());
|
||||
#endif
|
||||
|
||||
|
||||
_logger = new FileLogger(this); // After setting organization name in order to get correct directory
|
||||
|
||||
qInstallMessageHandler(messageHandler);
|
||||
|
||||
QFontDatabase::addApplicationFont(PathUtils::resourcesPath() + "styles/Inconsolata.otf");
|
||||
|
@ -559,8 +567,12 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
|
|||
#endif
|
||||
|
||||
this->installEventFilter(this);
|
||||
// The offscreen UI needs to intercept the mouse and keyboard
|
||||
// events coming from the onscreen window
|
||||
_glWidget->installEventFilter(DependencyManager::get<OffscreenUi>().data());
|
||||
}
|
||||
|
||||
|
||||
void Application::aboutToQuit() {
|
||||
emit beforeAboutToQuit();
|
||||
|
||||
|
@ -634,6 +646,7 @@ Application::~Application() {
|
|||
// stop the glWidget frame timer so it doesn't call paintGL
|
||||
_glWidget->stopFrameTimer();
|
||||
|
||||
DependencyManager::destroy<OffscreenUi>();
|
||||
DependencyManager::destroy<AvatarManager>();
|
||||
DependencyManager::destroy<AnimationCache>();
|
||||
DependencyManager::destroy<TextureCache>();
|
||||
|
@ -721,10 +734,45 @@ void Application::initializeGL() {
|
|||
|
||||
// update before the first render
|
||||
update(1.0f / _fps);
|
||||
|
||||
// The UI can't be created until the primary OpenGL
|
||||
// context is created, because it needs to share
|
||||
// texture resources
|
||||
initializeUi();
|
||||
|
||||
InfoView::showFirstTime(INFO_HELP_PATH);
|
||||
}
|
||||
|
||||
void Application::initializeUi() {
|
||||
AddressBarDialog::registerType();
|
||||
LoginDialog::registerType();
|
||||
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
offscreenUi->create(_glWidget->context()->contextHandle());
|
||||
offscreenUi->resize(_glWidget->size());
|
||||
offscreenUi->setProxyWindow(_window->windowHandle());
|
||||
offscreenUi->setBaseUrl(QUrl::fromLocalFile(PathUtils::resourcesPath() + "/qml/"));
|
||||
offscreenUi->load("Root.qml");
|
||||
offscreenUi->setMouseTranslator([this](const QPointF& p){
|
||||
if (OculusManager::isConnected()) {
|
||||
glm::vec2 pos = _applicationOverlay.screenToOverlay(toGlm(p));
|
||||
return QPointF(pos.x, pos.y);
|
||||
}
|
||||
return QPointF(p);
|
||||
});
|
||||
offscreenUi->resume();
|
||||
connect(_window, &MainWindow::windowGeometryChanged, [this](const QRect & r){
|
||||
static qreal oldDevicePixelRatio = 0;
|
||||
qreal devicePixelRatio = _glWidget->devicePixelRatio();
|
||||
if (devicePixelRatio != oldDevicePixelRatio) {
|
||||
oldDevicePixelRatio = devicePixelRatio;
|
||||
qDebug() << "Device pixel ratio changed, triggering GL resize";
|
||||
resizeGL(_glWidget->width(),
|
||||
_glWidget->height());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void Application::paintGL() {
|
||||
PROFILE_RANGE(__FUNCTION__);
|
||||
PerformanceTimer perfTimer("paintGL");
|
||||
|
@ -819,7 +867,7 @@ void Application::paintGL() {
|
|||
|
||||
{
|
||||
PerformanceTimer perfTimer("renderOverlay");
|
||||
_applicationOverlay.renderOverlay(true);
|
||||
_applicationOverlay.renderOverlay();
|
||||
_applicationOverlay.displayOverlayTexture();
|
||||
}
|
||||
}
|
||||
|
@ -864,6 +912,9 @@ void Application::resizeGL(int width, int height) {
|
|||
updateProjectionMatrix();
|
||||
glLoadIdentity();
|
||||
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
offscreenUi->resize(_glWidget->size());
|
||||
|
||||
// update Stats width
|
||||
// let's set horizontal offset to give stats some margin to mirror
|
||||
int horizontalOffset = MIRROR_VIEW_WIDTH + MIRROR_VIEW_LEFT_PADDING * 2;
|
||||
|
@ -912,6 +963,44 @@ bool Application::importSVOFromURL(const QString& urlString) {
|
|||
}
|
||||
|
||||
bool Application::event(QEvent* event) {
|
||||
switch (event->type()) {
|
||||
case QEvent::MouseMove:
|
||||
mouseMoveEvent((QMouseEvent*)event);
|
||||
return true;
|
||||
case QEvent::MouseButtonPress:
|
||||
mousePressEvent((QMouseEvent*)event);
|
||||
return true;
|
||||
case QEvent::MouseButtonRelease:
|
||||
mouseReleaseEvent((QMouseEvent*)event);
|
||||
return true;
|
||||
case QEvent::KeyPress:
|
||||
keyPressEvent((QKeyEvent*)event);
|
||||
return true;
|
||||
case QEvent::KeyRelease:
|
||||
keyReleaseEvent((QKeyEvent*)event);
|
||||
return true;
|
||||
case QEvent::FocusOut:
|
||||
focusOutEvent((QFocusEvent*)event);
|
||||
return true;
|
||||
case QEvent::TouchBegin:
|
||||
touchBeginEvent(static_cast<QTouchEvent*>(event));
|
||||
event->accept();
|
||||
return true;
|
||||
case QEvent::TouchEnd:
|
||||
touchEndEvent(static_cast<QTouchEvent*>(event));
|
||||
return true;
|
||||
case QEvent::TouchUpdate:
|
||||
touchUpdateEvent(static_cast<QTouchEvent*>(event));
|
||||
return true;
|
||||
case QEvent::Wheel:
|
||||
wheelEvent(static_cast<QWheelEvent*>(event));
|
||||
return true;
|
||||
case QEvent::Drop:
|
||||
dropEvent(static_cast<QDropEvent*>(event));
|
||||
return true;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// handle custom URL
|
||||
if (event->type() == QEvent::FileOpen) {
|
||||
|
@ -932,7 +1021,7 @@ bool Application::event(QEvent* event) {
|
|||
if (HFActionEvent::types().contains(event->type())) {
|
||||
_controllerScriptingInterface.handleMetaEvent(static_cast<HFMetaEvent*>(event));
|
||||
}
|
||||
|
||||
|
||||
return QApplication::event(event);
|
||||
}
|
||||
|
||||
|
@ -964,14 +1053,17 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
bool isShifted = event->modifiers().testFlag(Qt::ShiftModifier);
|
||||
bool isMeta = event->modifiers().testFlag(Qt::ControlModifier);
|
||||
bool isOption = event->modifiers().testFlag(Qt::AltModifier);
|
||||
bool isKeypad = event->modifiers().testFlag(Qt::KeypadModifier);
|
||||
switch (event->key()) {
|
||||
break;
|
||||
case Qt::Key_L:
|
||||
if (isShifted) {
|
||||
Menu::getInstance()->triggerOption(MenuOption::LodTools);
|
||||
} else if (isMeta) {
|
||||
if (isShifted && isMeta) {
|
||||
Menu::getInstance()->triggerOption(MenuOption::Log);
|
||||
}
|
||||
} else if (isMeta) {
|
||||
Menu::getInstance()->triggerOption(MenuOption::AddressBar);
|
||||
} else if (isShifted) {
|
||||
Menu::getInstance()->triggerOption(MenuOption::LodTools);
|
||||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_E:
|
||||
|
@ -1031,11 +1123,6 @@ void Application::keyPressEvent(QKeyEvent* event) {
|
|||
}
|
||||
break;
|
||||
|
||||
case Qt::Key_Return:
|
||||
case Qt::Key_Enter:
|
||||
Menu::getInstance()->triggerOption(MenuOption::AddressBar);
|
||||
break;
|
||||
|
||||
case Qt::Key_Backslash:
|
||||
Menu::getInstance()->triggerOption(MenuOption::Chat);
|
||||
break;
|
||||
|
@ -1495,6 +1582,17 @@ void Application::dropEvent(QDropEvent *event) {
|
|||
}
|
||||
}
|
||||
|
||||
void Application::dragEnterEvent(QDragEnterEvent* event) {
|
||||
const QMimeData* mimeData = event->mimeData();
|
||||
foreach(QUrl url, mimeData->urls()) {
|
||||
auto urlString = url.toString();
|
||||
if (canAcceptURL(urlString)) {
|
||||
event->acceptProposedAction();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Application::acceptSnapshot(const QString& urlString) {
|
||||
QUrl url(urlString);
|
||||
QString snapshotPath = url.toLocalFile();
|
||||
|
@ -1744,10 +1842,9 @@ void Application::setActiveFaceTracker() {
|
|||
DependencyManager::get<Faceshift>()->setTCPEnabled(Menu::getInstance()->isOptionChecked(MenuOption::Faceshift));
|
||||
#endif
|
||||
#ifdef HAVE_DDE
|
||||
bool isUsingDDE = Menu::getInstance()->isOptionChecked(MenuOption::DDEFaceRegression);
|
||||
bool isUsingDDE = Menu::getInstance()->isOptionChecked(MenuOption::UseCamera);
|
||||
Menu::getInstance()->getActionForOption(MenuOption::UseAudioForMouth)->setVisible(isUsingDDE);
|
||||
Menu::getInstance()->getActionForOption(MenuOption::DDEFiltering)->setVisible(isUsingDDE);
|
||||
Menu::getInstance()->getActionForOption(MenuOption::ResetDDETracking)->setVisible(isUsingDDE);
|
||||
Menu::getInstance()->getActionForOption(MenuOption::VelocityFilter)->setVisible(isUsingDDE);
|
||||
DependencyManager::get<DdeFaceTracker>()->setEnabled(isUsingDDE);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -30,6 +30,7 @@
|
|||
#include <NetworkPacket.h>
|
||||
#include <NodeList.h>
|
||||
#include <OctreeQuery.h>
|
||||
#include <OffscreenUi.h>
|
||||
#include <PacketHeaders.h>
|
||||
#include <PhysicsEngine.h>
|
||||
#include <ScriptEngine.h>
|
||||
|
@ -151,6 +152,7 @@ public:
|
|||
void setPreviousScriptLocation(const QString& previousScriptLocation);
|
||||
void clearScriptsBeforeRunning();
|
||||
void initializeGL();
|
||||
void initializeUi();
|
||||
void paintGL();
|
||||
void resizeGL(int width, int height);
|
||||
|
||||
|
@ -169,7 +171,8 @@ public:
|
|||
void touchUpdateEvent(QTouchEvent* event);
|
||||
|
||||
void wheelEvent(QWheelEvent* event);
|
||||
void dropEvent(QDropEvent *event);
|
||||
void dropEvent(QDropEvent* event);
|
||||
void dragEnterEvent(QDragEnterEvent* event);
|
||||
|
||||
bool event(QEvent* event);
|
||||
bool eventFilter(QObject* object, QEvent* event);
|
||||
|
|
|
@ -82,30 +82,6 @@ void GLCanvas::resizeGL(int width, int height) {
|
|||
Application::getInstance()->resizeGL(width, height);
|
||||
}
|
||||
|
||||
void GLCanvas::keyPressEvent(QKeyEvent* event) {
|
||||
Application::getInstance()->keyPressEvent(event);
|
||||
}
|
||||
|
||||
void GLCanvas::keyReleaseEvent(QKeyEvent* event) {
|
||||
Application::getInstance()->keyReleaseEvent(event);
|
||||
}
|
||||
|
||||
void GLCanvas::focusOutEvent(QFocusEvent* event) {
|
||||
Application::getInstance()->focusOutEvent(event);
|
||||
}
|
||||
|
||||
void GLCanvas::mouseMoveEvent(QMouseEvent* event) {
|
||||
Application::getInstance()->mouseMoveEvent(event);
|
||||
}
|
||||
|
||||
void GLCanvas::mousePressEvent(QMouseEvent* event) {
|
||||
Application::getInstance()->mousePressEvent(event);
|
||||
}
|
||||
|
||||
void GLCanvas::mouseReleaseEvent(QMouseEvent* event) {
|
||||
Application::getInstance()->mouseReleaseEvent(event);
|
||||
}
|
||||
|
||||
void GLCanvas::activeChanged(Qt::ApplicationState state) {
|
||||
switch (state) {
|
||||
case Qt::ApplicationActive:
|
||||
|
@ -139,6 +115,7 @@ void GLCanvas::throttleRender() {
|
|||
OculusManager::beginFrameTiming();
|
||||
}
|
||||
|
||||
makeCurrent();
|
||||
Application::getInstance()->paintGL();
|
||||
swapBuffers();
|
||||
|
||||
|
@ -151,40 +128,37 @@ void GLCanvas::throttleRender() {
|
|||
int updateTime = 0;
|
||||
bool GLCanvas::event(QEvent* event) {
|
||||
switch (event->type()) {
|
||||
case QEvent::MouseMove:
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::KeyPress:
|
||||
case QEvent::KeyRelease:
|
||||
case QEvent::FocusIn:
|
||||
case QEvent::FocusOut:
|
||||
case QEvent::Resize:
|
||||
case QEvent::TouchBegin:
|
||||
Application::getInstance()->touchBeginEvent(static_cast<QTouchEvent*>(event));
|
||||
event->accept();
|
||||
return true;
|
||||
case QEvent::TouchEnd:
|
||||
Application::getInstance()->touchEndEvent(static_cast<QTouchEvent*>(event));
|
||||
return true;
|
||||
case QEvent::TouchUpdate:
|
||||
Application::getInstance()->touchUpdateEvent(static_cast<QTouchEvent*>(event));
|
||||
return true;
|
||||
case QEvent::Wheel:
|
||||
case QEvent::DragEnter:
|
||||
case QEvent::Drop:
|
||||
if (QCoreApplication::sendEvent(QCoreApplication::instance(), event)) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
case QEvent::Paint:
|
||||
// Ignore paint events that occur after we've decided to quit
|
||||
if (Application::getInstance()->isAboutToQuit()) {
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QGLWidget::event(event);
|
||||
}
|
||||
|
||||
void GLCanvas::wheelEvent(QWheelEvent* event) {
|
||||
Application::getInstance()->wheelEvent(event);
|
||||
}
|
||||
|
||||
void GLCanvas::dragEnterEvent(QDragEnterEvent* event) {
|
||||
const QMimeData* mimeData = event->mimeData();
|
||||
foreach (QUrl url, mimeData->urls()) {
|
||||
auto urlString = url.toString();
|
||||
if (Application::getInstance()->canAcceptURL(urlString)) {
|
||||
event->acceptProposedAction();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GLCanvas::dropEvent(QDropEvent* event) {
|
||||
Application::getInstance()->dropEvent(event);
|
||||
}
|
||||
|
||||
// Pressing Alt (and Meta) key alone activates the menubar because its style inherits the
|
||||
// SHMenuBarAltKeyNavigation from QWindowsStyle. This makes it impossible for a scripts to
|
||||
|
|
|
@ -40,23 +40,8 @@ protected:
|
|||
virtual void initializeGL();
|
||||
virtual void paintGL();
|
||||
virtual void resizeGL(int width, int height);
|
||||
|
||||
virtual void keyPressEvent(QKeyEvent* event);
|
||||
virtual void keyReleaseEvent(QKeyEvent* event);
|
||||
|
||||
virtual void focusOutEvent(QFocusEvent* event);
|
||||
|
||||
virtual void mouseMoveEvent(QMouseEvent* event);
|
||||
virtual void mousePressEvent(QMouseEvent* event);
|
||||
virtual void mouseReleaseEvent(QMouseEvent* event);
|
||||
|
||||
virtual bool event(QEvent* event);
|
||||
|
||||
virtual void wheelEvent(QWheelEvent* event);
|
||||
|
||||
virtual void dragEnterEvent(QDragEnterEvent *event);
|
||||
virtual void dropEvent(QDropEvent* event);
|
||||
|
||||
private slots:
|
||||
void activeChanged(Qt::ApplicationState state);
|
||||
void throttleRender();
|
||||
|
|
|
@ -96,7 +96,7 @@ Menu::Menu() {
|
|||
|
||||
addActionToQMenuAndActionHash(fileMenu,
|
||||
MenuOption::AddressBar,
|
||||
Qt::Key_Enter,
|
||||
Qt::CTRL | Qt::Key_L,
|
||||
dialogsManager.data(),
|
||||
SLOT(toggleAddressBar()));
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
|
@ -150,7 +150,8 @@ Menu::Menu() {
|
|||
connect(speechRecognizer.data(), SIGNAL(enabledUpdated(bool)), speechRecognizerAction, SLOT(setChecked(bool)));
|
||||
#endif
|
||||
|
||||
addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat, Qt::Key_Backslash,
|
||||
addActionToQMenuAndActionHash(toolsMenu, MenuOption::Chat,
|
||||
0, // QML Qt::Key_Backslash,
|
||||
dialogsManager.data(), SLOT(showIRCLink()));
|
||||
addActionToQMenuAndActionHash(toolsMenu, MenuOption::AddRemoveFriends, 0,
|
||||
qApp, SLOT(showFriendsWindow()));
|
||||
|
@ -193,7 +194,7 @@ Menu::Menu() {
|
|||
|
||||
addActionToQMenuAndActionHash(toolsMenu,
|
||||
MenuOption::ResetSensors,
|
||||
Qt::Key_Apostrophe,
|
||||
0, // QML Qt::Key_Apostrophe,
|
||||
qApp,
|
||||
SLOT(resetSensors()));
|
||||
|
||||
|
@ -206,17 +207,17 @@ Menu::Menu() {
|
|||
QMenu* avatarSizeMenu = avatarMenu->addMenu("Size");
|
||||
addActionToQMenuAndActionHash(avatarSizeMenu,
|
||||
MenuOption::IncreaseAvatarSize,
|
||||
Qt::Key_Plus,
|
||||
0, // QML Qt::Key_Plus,
|
||||
avatar,
|
||||
SLOT(increaseSize()));
|
||||
addActionToQMenuAndActionHash(avatarSizeMenu,
|
||||
MenuOption::DecreaseAvatarSize,
|
||||
Qt::Key_Minus,
|
||||
0, // QML Qt::Key_Minus,
|
||||
avatar,
|
||||
SLOT(decreaseSize()));
|
||||
addActionToQMenuAndActionHash(avatarSizeMenu,
|
||||
MenuOption::ResetAvatarSize,
|
||||
Qt::Key_Equal,
|
||||
0, // QML Qt::Key_Equal,
|
||||
avatar,
|
||||
SLOT(resetSize()));
|
||||
|
||||
|
@ -245,11 +246,15 @@ Menu::Menu() {
|
|||
qApp,
|
||||
SLOT(setFullscreen(bool)));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson, Qt::Key_P, true,
|
||||
qApp,SLOT(cameraMenuChanged()));
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror, Qt::SHIFT | Qt::Key_H, true);
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror, Qt::Key_H, false,
|
||||
qApp, SLOT(cameraMenuChanged()));
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FirstPerson,
|
||||
0, // QML Qt::Key_P,
|
||||
true, qApp, SLOT(cameraMenuChanged()));
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Mirror,
|
||||
0, //QML Qt::SHIFT | Qt::Key_H,
|
||||
true);
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::FullscreenMirror,
|
||||
0, // QML Qt::Key_H,
|
||||
false, qApp, SLOT(cameraMenuChanged()));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::HMDTools,
|
||||
#ifdef Q_OS_MAC
|
||||
|
@ -282,8 +287,12 @@ Menu::Menu() {
|
|||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::TurnWithHead, 0, false);
|
||||
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats, Qt::Key_Slash);
|
||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::Log, Qt::CTRL | Qt::Key_L, qApp, SLOT(toggleLogDialog()));
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats,
|
||||
0); // QML Qt::Key_Slash);
|
||||
addCheckableActionToQMenuAndActionHash(viewMenu, MenuOption::Stats);
|
||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::Log,
|
||||
Qt::CTRL | Qt::SHIFT | Qt::Key_L,
|
||||
qApp, SLOT(toggleLogDialog()));
|
||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::BandwidthDetails, 0,
|
||||
dialogsManager.data(), SLOT(bandwidthDetails()));
|
||||
addActionToQMenuAndActionHash(viewMenu, MenuOption::OctreeStats, 0,
|
||||
|
@ -293,7 +302,9 @@ Menu::Menu() {
|
|||
QMenu* developerMenu = addMenu("Developer");
|
||||
|
||||
QMenu* renderOptionsMenu = developerMenu->addMenu("Render");
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere, Qt::SHIFT | Qt::Key_A, true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Atmosphere,
|
||||
0, // QML Qt::SHIFT | Qt::Key_A,
|
||||
true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::AmbientOcclusion);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::DontFadeOnOctreeServerChanges);
|
||||
|
||||
|
@ -345,13 +356,16 @@ Menu::Menu() {
|
|||
resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionThird, 0, false));
|
||||
resolutionGroup->addAction(addCheckableActionToQMenuAndActionHash(resolutionMenu, MenuOption::RenderResolutionQuarter, 0, false));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars, Qt::Key_Asterisk, true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Stars,
|
||||
0, // QML Qt::Key_Asterisk,
|
||||
true);
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::EnableGlowEffect, 0, true,
|
||||
DependencyManager::get<GlowEffect>().data(), SLOT(toggleGlowEffect(bool)));
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::Wireframe, Qt::ALT | Qt::Key_W, false);
|
||||
addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools, Qt::SHIFT | Qt::Key_L,
|
||||
dialogsManager.data(), SLOT(lodTools()));
|
||||
addActionToQMenuAndActionHash(renderOptionsMenu, MenuOption::LodTools,
|
||||
0, // QML Qt::SHIFT | Qt::Key_L,
|
||||
dialogsManager.data(), SLOT(lodTools()));
|
||||
|
||||
QMenu* avatarDebugMenu = developerMenu->addMenu("Avatar");
|
||||
|
||||
|
@ -371,7 +385,7 @@ Menu::Menu() {
|
|||
faceTrackerGroup->addAction(faceshiftFaceTracker);
|
||||
#endif
|
||||
#ifdef HAVE_DDE
|
||||
QAction* ddeFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::DDEFaceRegression,
|
||||
QAction* ddeFaceTracker = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::UseCamera,
|
||||
0, false,
|
||||
qApp, SLOT(setActiveFaceTracker()));
|
||||
faceTrackerGroup->addAction(ddeFaceTracker);
|
||||
|
@ -381,13 +395,8 @@ Menu::Menu() {
|
|||
faceTrackingMenu->addSeparator();
|
||||
QAction* useAudioForMouth = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::UseAudioForMouth, 0, true);
|
||||
useAudioForMouth->setVisible(false);
|
||||
QAction* ddeFiltering = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::DDEFiltering, 0, true);
|
||||
QAction* ddeFiltering = addCheckableActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::VelocityFilter, 0, true);
|
||||
ddeFiltering->setVisible(false);
|
||||
QAction* ddeFaceTrackerReset = addActionToQMenuAndActionHash(faceTrackingMenu, MenuOption::ResetDDETracking,
|
||||
Qt::CTRL | Qt::Key_Apostrophe,
|
||||
DependencyManager::get<DdeFaceTracker>().data(), SLOT(resetTracking()));
|
||||
ddeFaceTrackerReset->setVisible(false);
|
||||
faceTrackingMenu->addAction(ddeFaceTrackerReset);
|
||||
#endif
|
||||
|
||||
addCheckableActionToQMenuAndActionHash(avatarDebugMenu, MenuOption::RenderSkeletonCollisionShapes);
|
||||
|
|
|
@ -130,8 +130,6 @@ namespace MenuOption {
|
|||
const QString ControlWithSpeech = "Control With Speech";
|
||||
const QString CopyAddress = "Copy Address to Clipboard";
|
||||
const QString CopyPath = "Copy Path to Clipboard";
|
||||
const QString DDEFaceRegression = "DDE Face Regression";
|
||||
const QString DDEFiltering = "DDE Filtering";
|
||||
const QString DecreaseAvatarSize = "Decrease Avatar Size";
|
||||
const QString DeleteBookmark = "Delete Bookmark...";
|
||||
const QString DisableActivityLogger = "Disable Activity Logger";
|
||||
|
@ -224,7 +222,6 @@ namespace MenuOption {
|
|||
const QString RenderAmbientLight8 = "CAMPUS_SUNSET";
|
||||
const QString RenderAmbientLight9 = "FUNSTON_BEACH_SUNSET";
|
||||
const QString ResetAvatarSize = "Reset Avatar Size";
|
||||
const QString ResetDDETracking = "Reset DDE Tracking";
|
||||
const QString ResetSensors = "Reset Sensors";
|
||||
const QString RunningScripts = "Running Scripts";
|
||||
const QString RunTimingTests = "Run Timing Tests";
|
||||
|
@ -247,6 +244,8 @@ namespace MenuOption {
|
|||
const QString TransmitterDrive = "Transmitter Drive";
|
||||
const QString TurnWithHead = "Turn using Head";
|
||||
const QString UseAudioForMouth = "Use Audio for Mouth";
|
||||
const QString UseCamera = "Use Camera";
|
||||
const QString VelocityFilter = "Velocity Filter";
|
||||
const QString VisibleToEveryone = "Everyone";
|
||||
const QString VisibleToFriends = "Friends";
|
||||
const QString VisibleToNoOne = "No one";
|
||||
|
|
|
@ -200,7 +200,7 @@ void DdeFaceTracker::setEnabled(bool enabled) {
|
|||
qDebug() << "[Info] DDE Face Tracker Starting";
|
||||
_ddeProcess = new QProcess(qApp);
|
||||
connect(_ddeProcess, SIGNAL(finished(int, QProcess::ExitStatus)), SLOT(processFinished(int, QProcess::ExitStatus)));
|
||||
_ddeProcess->start(QCoreApplication::applicationDirPath() + DDE_PROGRAM_PATH, DDE_ARGUMENTS);
|
||||
_ddeProcess->start(QCoreApplication::applicationDirPath() + DDE_PROGRAM_PATH, DDE_ARGUMENTS, QIODevice::ReadOnly);
|
||||
}
|
||||
|
||||
if (!enabled && _ddeProcess) {
|
||||
|
@ -222,10 +222,14 @@ void DdeFaceTracker::processFinished(int exitCode, QProcess::ExitStatus exitStat
|
|||
}
|
||||
}
|
||||
|
||||
void DdeFaceTracker::resetTracking() {
|
||||
void DdeFaceTracker::reset() {
|
||||
_reset = true;
|
||||
|
||||
qDebug() << "[Info] Reset DDE Tracking";
|
||||
const char* DDE_RESET_COMMAND = "reset";
|
||||
_udpSocket.writeDatagram(DDE_RESET_COMMAND, DDE_SERVER_ADDR, _controlPort);
|
||||
|
||||
_reset = true;
|
||||
}
|
||||
|
||||
bool DdeFaceTracker::isActive() const {
|
||||
|
@ -281,7 +285,7 @@ float DdeFaceTracker::getBlendshapeCoefficient(int index) const {
|
|||
|
||||
void DdeFaceTracker::decodePacket(const QByteArray& buffer) {
|
||||
if(buffer.size() > MIN_PACKET_SIZE) {
|
||||
bool isFiltering = Menu::getInstance()->isOptionChecked(MenuOption::DDEFiltering);
|
||||
bool isFiltering = Menu::getInstance()->isOptionChecked(MenuOption::VelocityFilter);
|
||||
|
||||
Packet packet;
|
||||
int bytesToCopy = glm::min((int)sizeof(packet), buffer.size());
|
||||
|
|
|
@ -28,7 +28,7 @@ class DdeFaceTracker : public FaceTracker, public Dependency {
|
|||
SINGLETON_DEPENDENCY
|
||||
|
||||
public:
|
||||
virtual void reset() { _reset = true; }
|
||||
virtual void reset();
|
||||
|
||||
virtual bool isActive() const;
|
||||
virtual bool isTracking() const { return isActive(); }
|
||||
|
@ -50,7 +50,6 @@ public:
|
|||
|
||||
public slots:
|
||||
void setEnabled(bool enabled);
|
||||
void resetTracking();
|
||||
|
||||
private slots:
|
||||
void processFinished(int exitCode, QProcess::ExitStatus exitStatus);
|
||||
|
|
|
@ -525,7 +525,7 @@ void OculusManager::display(const glm::quat &bodyOrientation, const glm::vec3 &p
|
|||
|
||||
// We only need to render the overlays to a texture once, then we just render the texture on the hemisphere
|
||||
// PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay()
|
||||
applicationOverlay.renderOverlay(true);
|
||||
applicationOverlay.renderOverlay();
|
||||
|
||||
//Bind our framebuffer object. If we are rendering the glow effect, we let the glow effect shader take care of it
|
||||
if (Menu::getInstance()->isOptionChecked(MenuOption::EnableGlowEffect)) {
|
||||
|
|
|
@ -101,7 +101,7 @@ void TV3DManager::display(Camera& whichCamera) {
|
|||
|
||||
// We only need to render the overlays to a texture once, then we just render the texture as a quad
|
||||
// PrioVR will only work if renderOverlay is called, calibration is connected to Application::renderingOverlay()
|
||||
applicationOverlay.renderOverlay(true);
|
||||
applicationOverlay.renderOverlay();
|
||||
|
||||
DependencyManager::get<GlowEffect>()->prepare();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
|
|
@ -1,148 +1,47 @@
|
|||
//
|
||||
// AddressBarDialog.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Stojce Slavkovski on 9/22/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
// Created by Bradley Austin Davis on 2015/04/14
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "AddressBarDialog.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include "AddressBarDialog.h"
|
||||
#include "DependencyManager.h"
|
||||
#include "AddressManager.h"
|
||||
#include "Application.h"
|
||||
#include "MainWindow.h"
|
||||
|
||||
const QString ADDRESSBAR_GO_BUTTON_ICON = "images/address-bar-submit.svg";
|
||||
const QString ADDRESSBAR_GO_BUTTON_ACTIVE_ICON = "images/address-bar-submit-active.svg";
|
||||
QML_DIALOG_DEF(AddressBarDialog)
|
||||
|
||||
AddressBarDialog::AddressBarDialog(QWidget* parent) :
|
||||
FramelessDialog(parent, 0, FramelessDialog::POSITION_TOP)
|
||||
{
|
||||
setAttribute(Qt::WA_DeleteOnClose, false);
|
||||
setupUI();
|
||||
|
||||
AddressBarDialog::AddressBarDialog(QQuickItem* parent) : OffscreenQmlDialog(parent) {
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
|
||||
connect(addressManager.data(), &AddressManager::lookupResultIsOffline, this, &AddressBarDialog::displayAddressOfflineMessage);
|
||||
connect(addressManager.data(), &AddressManager::lookupResultIsNotFound, this, &AddressBarDialog::displayAddressNotFoundMessage);
|
||||
connect(addressManager.data(), &AddressManager::lookupResultsFinished, this, &AddressBarDialog::hide);
|
||||
}
|
||||
|
||||
void AddressBarDialog::setupUI() {
|
||||
|
||||
const QString DIALOG_STYLESHEET = "font-family: Helvetica, Arial, sans-serif;";
|
||||
const QString ADDRESSBAR_PLACEHOLDER = "Go to: domain, location, @user, /x,y,z";
|
||||
const QString ADDRESSBAR_STYLESHEET = "padding: 5px 10px; font-size: 20px;";
|
||||
|
||||
const int ADDRESSBAR_MIN_WIDTH = 200;
|
||||
const int ADDRESSBAR_MAX_WIDTH = 615;
|
||||
const int ADDRESSBAR_HEIGHT = 42;
|
||||
const int ADDRESSBAR_STRETCH = 60;
|
||||
|
||||
const int BUTTON_SPACER_SIZE = 5;
|
||||
const int DEFAULT_SPACER_SIZE = 20;
|
||||
const int ADDRESS_LAYOUT_RIGHT_MARGIN = 10;
|
||||
|
||||
const int GO_BUTTON_SIZE = 42;
|
||||
const int CLOSE_BUTTON_SIZE = 16;
|
||||
const QString CLOSE_BUTTON_ICON = "styles/close.svg";
|
||||
|
||||
const int DIALOG_HEIGHT = 62;
|
||||
const int DIALOG_INITIAL_WIDTH = 560;
|
||||
|
||||
QSizePolicy sizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
|
||||
setSizePolicy(sizePolicy);
|
||||
setMinimumSize(QSize(DIALOG_INITIAL_WIDTH, DIALOG_HEIGHT));
|
||||
setMaximumHeight(DIALOG_HEIGHT);
|
||||
setStyleSheet(DIALOG_STYLESHEET);
|
||||
|
||||
_verticalLayout = new QVBoxLayout(this);
|
||||
_verticalLayout->setContentsMargins(0, 0, 0, 0);
|
||||
|
||||
_addressLayout = new QHBoxLayout();
|
||||
_addressLayout->setContentsMargins(0, 0, ADDRESS_LAYOUT_RIGHT_MARGIN, 0);
|
||||
|
||||
_leftSpacer = new QSpacerItem(DEFAULT_SPACER_SIZE,
|
||||
DEFAULT_SPACER_SIZE,
|
||||
QSizePolicy::MinimumExpanding,
|
||||
QSizePolicy::Minimum);
|
||||
|
||||
_addressLayout->addItem(_leftSpacer);
|
||||
|
||||
_addressLineEdit = new QLineEdit(this);
|
||||
_addressLineEdit->setAttribute(Qt::WA_MacShowFocusRect, 0);
|
||||
_addressLineEdit->setPlaceholderText(ADDRESSBAR_PLACEHOLDER);
|
||||
QSizePolicy sizePolicyLineEdit(QSizePolicy::Preferred, QSizePolicy::Fixed);
|
||||
sizePolicyLineEdit.setHorizontalStretch(ADDRESSBAR_STRETCH);
|
||||
_addressLineEdit->setSizePolicy(sizePolicyLineEdit);
|
||||
_addressLineEdit->setMinimumSize(QSize(ADDRESSBAR_MIN_WIDTH, ADDRESSBAR_HEIGHT));
|
||||
_addressLineEdit->setMaximumSize(QSize(ADDRESSBAR_MAX_WIDTH, ADDRESSBAR_HEIGHT));
|
||||
_addressLineEdit->setStyleSheet(ADDRESSBAR_STYLESHEET);
|
||||
_addressLayout->addWidget(_addressLineEdit);
|
||||
|
||||
_buttonSpacer = new QSpacerItem(BUTTON_SPACER_SIZE, BUTTON_SPACER_SIZE, QSizePolicy::Fixed, QSizePolicy::Minimum);
|
||||
_addressLayout->addItem(_buttonSpacer);
|
||||
|
||||
_goButton = new QPushButton(this);
|
||||
_goButton->setSizePolicy(sizePolicy);
|
||||
_goButton->setMinimumSize(QSize(GO_BUTTON_SIZE, GO_BUTTON_SIZE));
|
||||
_goButton->setMaximumSize(QSize(GO_BUTTON_SIZE, GO_BUTTON_SIZE));
|
||||
_goButton->setIcon(QIcon(PathUtils::resourcesPath() + ADDRESSBAR_GO_BUTTON_ICON));
|
||||
_goButton->setIconSize(QSize(GO_BUTTON_SIZE, GO_BUTTON_SIZE));
|
||||
_goButton->setDefault(true);
|
||||
_goButton->setFlat(true);
|
||||
_addressLayout->addWidget(_goButton);
|
||||
|
||||
_rightSpacer = new QSpacerItem(DEFAULT_SPACER_SIZE,
|
||||
DEFAULT_SPACER_SIZE,
|
||||
QSizePolicy::MinimumExpanding,
|
||||
QSizePolicy::Minimum);
|
||||
|
||||
_addressLayout->addItem(_rightSpacer);
|
||||
|
||||
_closeButton = new QPushButton(this);
|
||||
_closeButton->setSizePolicy(sizePolicy);
|
||||
_closeButton->setMinimumSize(QSize(CLOSE_BUTTON_SIZE, CLOSE_BUTTON_SIZE));
|
||||
_closeButton->setMaximumSize(QSize(CLOSE_BUTTON_SIZE, CLOSE_BUTTON_SIZE));
|
||||
QIcon icon(PathUtils::resourcesPath() + CLOSE_BUTTON_ICON);
|
||||
_closeButton->setIcon(icon);
|
||||
_closeButton->setIconSize(QSize(CLOSE_BUTTON_SIZE, CLOSE_BUTTON_SIZE));
|
||||
_closeButton->setFlat(true);
|
||||
_addressLayout->addWidget(_closeButton, 0, Qt::AlignRight);
|
||||
|
||||
_verticalLayout->addLayout(_addressLayout);
|
||||
|
||||
connect(_goButton, &QPushButton::clicked, this, &AddressBarDialog::accept);
|
||||
connect(_closeButton, &QPushButton::clicked, this, &QDialog::close);
|
||||
void AddressBarDialog::hide() {
|
||||
((QQuickItem*)parent())->setEnabled(false);
|
||||
}
|
||||
|
||||
void AddressBarDialog::showEvent(QShowEvent* event) {
|
||||
_goButton->setIcon(QIcon(PathUtils::resourcesPath() + ADDRESSBAR_GO_BUTTON_ICON));
|
||||
_addressLineEdit->setText(QString());
|
||||
_addressLineEdit->setFocus();
|
||||
FramelessDialog::showEvent(event);
|
||||
}
|
||||
|
||||
void AddressBarDialog::accept() {
|
||||
if (!_addressLineEdit->text().isEmpty()) {
|
||||
_goButton->setIcon(QIcon(PathUtils::resourcesPath() + ADDRESSBAR_GO_BUTTON_ACTIVE_ICON));
|
||||
auto addressManager = DependencyManager::get<AddressManager>();
|
||||
connect(addressManager.data(), &AddressManager::lookupResultsFinished, this, &QDialog::hide);
|
||||
addressManager->handleLookupString(_addressLineEdit->text());
|
||||
void AddressBarDialog::loadAddress(const QString& address) {
|
||||
qDebug() << "Called LoadAddress with address " << address;
|
||||
if (!address.isEmpty()) {
|
||||
DependencyManager::get<AddressManager>()->handleLookupString(address);
|
||||
}
|
||||
}
|
||||
|
||||
void AddressBarDialog::displayAddressOfflineMessage() {
|
||||
QMessageBox::information(Application::getInstance()->getWindow(), "Address offline",
|
||||
"That user or place is currently offline.");
|
||||
OffscreenUi::information("Address offline",
|
||||
"That user or place is currently offline.");
|
||||
}
|
||||
|
||||
void AddressBarDialog::displayAddressNotFoundMessage() {
|
||||
QMessageBox::information(Application::getInstance()->getWindow(), "Address not found",
|
||||
"There is no address information for that user or place.");
|
||||
}
|
||||
OffscreenUi::information("Address not found",
|
||||
"There is no address information for that user or place.");
|
||||
}
|
||||
|
||||
|
|
|
@ -1,47 +1,33 @@
|
|||
//
|
||||
// AddressBarDialog.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Stojce Slavkovski on 9/22/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
// Created by Bradley Austin Davis on 2015/04/14
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_AddressBarDialog_h
|
||||
#define hifi_AddressBarDialog_h
|
||||
|
||||
#include "FramelessDialog.h"
|
||||
#include <OffscreenQmlDialog.h>
|
||||
|
||||
#include <QLineEdit>
|
||||
#include <QHBoxLayout>
|
||||
#include <QSpacerItem>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
class AddressBarDialog : public FramelessDialog {
|
||||
class AddressBarDialog : public OffscreenQmlDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_DIALOG_DECL
|
||||
|
||||
public:
|
||||
AddressBarDialog(QWidget* parent);
|
||||
|
||||
private:
|
||||
void setupUI();
|
||||
void showEvent(QShowEvent* event);
|
||||
|
||||
QVBoxLayout *_verticalLayout;
|
||||
QHBoxLayout *_addressLayout;
|
||||
QSpacerItem *_leftSpacer;
|
||||
QSpacerItem *_rightSpacer;
|
||||
QSpacerItem *_buttonSpacer;
|
||||
QPushButton *_goButton;
|
||||
QPushButton *_closeButton;
|
||||
QLineEdit *_addressLineEdit;
|
||||
|
||||
private slots:
|
||||
void accept();
|
||||
AddressBarDialog(QQuickItem* parent = nullptr);
|
||||
|
||||
protected:
|
||||
void displayAddressOfflineMessage();
|
||||
void displayAddressNotFoundMessage();
|
||||
void hide();
|
||||
|
||||
Q_INVOKABLE void loadAddress(const QString& address);
|
||||
};
|
||||
|
||||
#endif // hifi_AddressBarDialog_h
|
||||
#endif
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#include <GLMHelpers.h>
|
||||
#include <PathUtils.h>
|
||||
#include <PerfStat.h>
|
||||
#include <OffscreenUi.h>
|
||||
|
||||
#include "AudioClient.h"
|
||||
#include "audio/AudioIOStatsRenderer.h"
|
||||
|
@ -161,13 +162,27 @@ ApplicationOverlay::ApplicationOverlay() :
|
|||
_domainStatusBorder = geometryCache->allocateID();
|
||||
_magnifierBorder = geometryCache->allocateID();
|
||||
|
||||
// Once we move UI rendering and screen rendering to different
|
||||
// threads, we need to use a sync object to deteremine when
|
||||
// the current UI texture is no longer being read from, and only
|
||||
// then release it back to the UI for re-use
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [&](GLuint textureId) {
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
offscreenUi->lockTexture(textureId);
|
||||
assert(!glGetError());
|
||||
std::swap(_newUiTexture, textureId);
|
||||
if (textureId) {
|
||||
offscreenUi->releaseTexture(textureId);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
ApplicationOverlay::~ApplicationOverlay() {
|
||||
}
|
||||
|
||||
// Renders the overlays either to a texture or to the screen
|
||||
void ApplicationOverlay::renderOverlay(bool renderToTexture) {
|
||||
void ApplicationOverlay::renderOverlay() {
|
||||
PerformanceWarning warn(Menu::getInstance()->isOptionChecked(MenuOption::PipelineWarnings), "ApplicationOverlay::displayOverlay()");
|
||||
Overlays& overlays = qApp->getOverlays();
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
|
@ -183,11 +198,9 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) {
|
|||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
if (renderToTexture) {
|
||||
_overlays.buildFramebufferObject();
|
||||
_overlays.bind();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
}
|
||||
_overlays.buildFramebufferObject();
|
||||
_overlays.bind();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
glPushMatrix(); {
|
||||
const float NEAR_CLIP = -10000;
|
||||
|
@ -218,9 +231,25 @@ void ApplicationOverlay::renderOverlay(bool renderToTexture) {
|
|||
glEnable(GL_LIGHTING);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||
|
||||
if (renderToTexture) {
|
||||
_overlays.release();
|
||||
_overlays.release();
|
||||
}
|
||||
|
||||
// A quick and dirty solution for compositing the old overlay
|
||||
// texture with the new one
|
||||
template <typename F>
|
||||
void with_each_texture(GLuint firstPassTexture, GLuint secondPassTexture, F f) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
if (firstPassTexture) {
|
||||
glBindTexture(GL_TEXTURE_2D, firstPassTexture);
|
||||
f();
|
||||
}
|
||||
if (secondPassTexture) {
|
||||
glBindTexture(GL_TEXTURE_2D, secondPassTexture);
|
||||
f();
|
||||
}
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
// Draws the FBO texture for the screen
|
||||
|
@ -229,30 +258,24 @@ void ApplicationOverlay::displayOverlayTexture() {
|
|||
return;
|
||||
}
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
_overlays.bindTexture();
|
||||
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glPushMatrix(); {
|
||||
glLoadIdentity();
|
||||
glOrtho(0, glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight(), 0, -1.0, 1.0);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_BLEND);
|
||||
|
||||
glm::vec2 topLeft(0.0f, 0.0f);
|
||||
glm::vec2 bottomRight(glCanvas->getDeviceWidth(), glCanvas->getDeviceHeight());
|
||||
glm::vec2 texCoordTopLeft(0.0f, 1.0f);
|
||||
glm::vec2 texCoordBottomRight(1.0f, 0.0f);
|
||||
if (_alpha < 1.0) {
|
||||
glEnable(GL_BLEND);
|
||||
}
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
||||
glm::vec4(1.0f, 1.0f, 1.0f, _alpha));
|
||||
|
||||
with_each_texture(_overlays.getTexture(), _newUiTexture, [&] {
|
||||
static const glm::vec2 topLeft(-1, 1);
|
||||
static const glm::vec2 bottomRight(1, -1);
|
||||
static const glm::vec2 texCoordTopLeft(0.0f, 1.0f);
|
||||
static const glm::vec2 texCoordBottomRight(1.0f, 0.0f);
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, texCoordTopLeft, texCoordBottomRight,
|
||||
glm::vec4(1.0f, 1.0f, 1.0f, _alpha));
|
||||
});
|
||||
} glPopMatrix();
|
||||
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
}
|
||||
|
||||
// Draws the FBO texture for Oculus rift.
|
||||
|
@ -260,10 +283,7 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
|
|||
if (_alpha == 0.0f) {
|
||||
return;
|
||||
}
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
_overlays.bindTexture();
|
||||
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
|
@ -271,8 +291,8 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
|
|||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_ALPHA_TEST);
|
||||
glAlphaFunc(GL_GREATER, 0.01f);
|
||||
|
||||
|
||||
|
||||
|
||||
//Update and draw the magnifiers
|
||||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
const glm::quat& orientation = myAvatar->getOrientation();
|
||||
|
@ -303,8 +323,9 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
|
|||
//Render magnifier, but dont show border for mouse magnifier
|
||||
glm::vec2 projection = screenToOverlay(glm::vec2(_reticlePosition[MOUSE].x(),
|
||||
_reticlePosition[MOUSE].y()));
|
||||
|
||||
renderMagnifier(projection, _magSizeMult[i], i != MOUSE);
|
||||
with_each_texture(_overlays.getTexture(), _newUiTexture, [&] {
|
||||
renderMagnifier(projection, _magSizeMult[i], i != MOUSE);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -319,12 +340,15 @@ void ApplicationOverlay::displayOverlayTextureOculus(Camera& whichCamera) {
|
|||
|
||||
_overlays.buildVBO(_textureFov, _textureAspectRatio, 80, 80);
|
||||
}
|
||||
_overlays.render();
|
||||
|
||||
with_each_texture(_overlays.getTexture(), _newUiTexture, [&] {
|
||||
_overlays.render();
|
||||
});
|
||||
|
||||
if (!Application::getInstance()->isMouseHidden()) {
|
||||
renderPointersOculus(myAvatar->getDefaultEyePosition());
|
||||
}
|
||||
glDepthMask(GL_TRUE);
|
||||
_overlays.releaseTexture();
|
||||
glDisable(GL_TEXTURE_2D);
|
||||
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||
|
@ -341,14 +365,10 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as
|
|||
MyAvatar* myAvatar = DependencyManager::get<AvatarManager>()->getMyAvatar();
|
||||
const glm::vec3& viewMatrixTranslation = qApp->getViewMatrixTranslation();
|
||||
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFuncSeparate(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA, GL_CONSTANT_ALPHA, GL_ONE);
|
||||
_overlays.bindTexture();
|
||||
glEnable(GL_DEPTH_TEST);
|
||||
glDisable(GL_LIGHTING);
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
|
||||
|
@ -382,13 +402,15 @@ void ApplicationOverlay::displayOverlayTexture3DTV(Camera& whichCamera, float as
|
|||
GLfloat y = -halfQuadHeight;
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(glm::vec3(x, y + quadHeight, -distance),
|
||||
with_each_texture(_overlays.getTexture(), _newUiTexture, [&] {
|
||||
DependencyManager::get<GeometryCache>()->renderQuad(glm::vec3(x, y + quadHeight, -distance),
|
||||
glm::vec3(x + quadWidth, y + quadHeight, -distance),
|
||||
glm::vec3(x + quadWidth, y, -distance),
|
||||
glm::vec3(x, y, -distance),
|
||||
glm::vec2(0.0f, 1.0f), glm::vec2(1.0f, 1.0f),
|
||||
glm::vec2(1.0f, 0.0f), glm::vec2(0.0f, 0.0f),
|
||||
overlayColor);
|
||||
});
|
||||
|
||||
auto glCanvas = Application::getInstance()->getGLWidget();
|
||||
if (_crosshairTexture == 0) {
|
||||
|
@ -993,14 +1015,6 @@ void ApplicationOverlay::TexturedHemisphere::release() {
|
|||
_framebufferObject->release();
|
||||
}
|
||||
|
||||
void ApplicationOverlay::TexturedHemisphere::bindTexture() {
|
||||
glBindTexture(GL_TEXTURE_2D, _framebufferObject->texture());
|
||||
}
|
||||
|
||||
void ApplicationOverlay::TexturedHemisphere::releaseTexture() {
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
void ApplicationOverlay::TexturedHemisphere::buildVBO(const float fov,
|
||||
const float aspectRatio,
|
||||
const int slices,
|
||||
|
@ -1099,14 +1113,14 @@ void ApplicationOverlay::TexturedHemisphere::buildFramebufferObject() {
|
|||
}
|
||||
|
||||
_framebufferObject = new QOpenGLFramebufferObject(size, QOpenGLFramebufferObject::Depth);
|
||||
bindTexture();
|
||||
glBindTexture(GL_TEXTURE_2D, getTexture());
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
|
||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
|
||||
GLfloat borderColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
|
||||
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor);
|
||||
releaseTexture();
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
}
|
||||
|
||||
//Renders a hemisphere with texture coordinates.
|
||||
|
@ -1137,6 +1151,10 @@ void ApplicationOverlay::TexturedHemisphere::render() {
|
|||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
|
||||
}
|
||||
|
||||
GLuint ApplicationOverlay::TexturedHemisphere::getTexture() {
|
||||
return _framebufferObject->texture();
|
||||
}
|
||||
|
||||
glm::vec2 ApplicationOverlay::directionToSpherical(glm::vec3 direction) const {
|
||||
glm::vec2 result;
|
||||
// Compute yaw
|
||||
|
|
|
@ -23,12 +23,13 @@ const float MAGNIFY_MULT = 2.0f;
|
|||
const float DEFAULT_OCULUS_UI_ANGULAR_SIZE = 72.0f;
|
||||
|
||||
// Handles the drawing of the overlays to the screen
|
||||
class ApplicationOverlay {
|
||||
class ApplicationOverlay : public QObject {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ApplicationOverlay();
|
||||
~ApplicationOverlay();
|
||||
|
||||
void renderOverlay(bool renderToTexture = false);
|
||||
void renderOverlay();
|
||||
void displayOverlayTexture();
|
||||
void displayOverlayTextureOculus(Camera& whichCamera);
|
||||
void displayOverlayTexture3DTV(Camera& whichCamera, float aspectRatio, float fov);
|
||||
|
@ -75,8 +76,7 @@ private:
|
|||
|
||||
void bind();
|
||||
void release();
|
||||
void bindTexture();
|
||||
void releaseTexture();
|
||||
GLuint getTexture();
|
||||
|
||||
void buildFramebufferObject();
|
||||
void buildVBO(const float fov, const float aspectRatio, const int slices, const int stacks);
|
||||
|
@ -122,6 +122,9 @@ private:
|
|||
float _trailingAudioLoudness;
|
||||
|
||||
GLuint _crosshairTexture;
|
||||
// TODO, move divide up the rendering, displaying and input handling
|
||||
// facilities of this class
|
||||
GLuint _newUiTexture{ 0 };
|
||||
|
||||
int _reticleQuad;
|
||||
int _magnifierQuad;
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "DialogsManager.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <AccountManager.h>
|
||||
|
@ -29,14 +31,9 @@
|
|||
#include "PreferencesDialog.h"
|
||||
#include "ScriptEditorWindow.h"
|
||||
|
||||
#include "DialogsManager.h"
|
||||
|
||||
void DialogsManager::toggleAddressBar() {
|
||||
maybeCreateDialog(_addressBarDialog);
|
||||
|
||||
if (!_addressBarDialog->isVisible()) {
|
||||
_addressBarDialog->show();
|
||||
}
|
||||
AddressBarDialog::toggle();
|
||||
}
|
||||
|
||||
void DialogsManager::toggleDiskCacheEditor() {
|
||||
|
@ -45,13 +42,11 @@ void DialogsManager::toggleDiskCacheEditor() {
|
|||
}
|
||||
|
||||
void DialogsManager::toggleLoginDialog() {
|
||||
maybeCreateDialog(_loginDialog);
|
||||
_loginDialog->toggleQAction();
|
||||
LoginDialog::toggleAction();
|
||||
}
|
||||
|
||||
void DialogsManager::showLoginDialog() {
|
||||
maybeCreateDialog(_loginDialog);
|
||||
_loginDialog->showLoginForCurrentDomain();
|
||||
LoginDialog::show();
|
||||
}
|
||||
|
||||
void DialogsManager::octreeStatsDetails() {
|
||||
|
@ -180,3 +175,4 @@ void DialogsManager::showIRCLink() {
|
|||
|
||||
_ircInfoBox->raise();
|
||||
}
|
||||
|
||||
|
|
|
@ -1,166 +0,0 @@
|
|||
//
|
||||
// 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 <QScreen>
|
||||
#include <QWindow>
|
||||
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "FramelessDialog.h"
|
||||
#include "Menu.h"
|
||||
|
||||
const int RESIZE_HANDLE_WIDTH = 7;
|
||||
|
||||
FramelessDialog::FramelessDialog(QWidget *parent, Qt::WindowFlags flags, Position position) :
|
||||
QDialog(parent, flags | Qt::FramelessWindowHint | Qt::WindowStaysOnTopHint),
|
||||
_allowResize(true),
|
||||
_isResizing(false),
|
||||
_resizeInitialWidth(0),
|
||||
_selfHidden(false),
|
||||
_position(position),
|
||||
_hideOnBlur(true) {
|
||||
|
||||
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()) {
|
||||
resizeAndPosition(false);
|
||||
}
|
||||
break;
|
||||
case QEvent::Resize:
|
||||
if (sender == parentWidget()) {
|
||||
resizeAndPosition(false);
|
||||
}
|
||||
break;
|
||||
case QEvent::WindowStateChange:
|
||||
if (_hideOnBlur && parentWidget()->isMinimized()) {
|
||||
if (isVisible()) {
|
||||
_selfHidden = true;
|
||||
setHidden(true);
|
||||
}
|
||||
} else if (_selfHidden) {
|
||||
_selfHidden = false;
|
||||
setHidden(false);
|
||||
}
|
||||
break;
|
||||
case QEvent::ApplicationDeactivate:
|
||||
// hide on minimize and focus lost
|
||||
if (_hideOnBlur && isVisible()) {
|
||||
_selfHidden = true;
|
||||
setHidden(true);
|
||||
}
|
||||
break;
|
||||
case QEvent::ApplicationActivate:
|
||||
if (_selfHidden) {
|
||||
_selfHidden = false;
|
||||
setHidden(false);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void FramelessDialog::setStyleSheetFile(const QString& fileName) {
|
||||
QFile globalStyleSheet(PathUtils::resourcesPath() + "styles/global.qss");
|
||||
QFile styleSheet(PathUtils::resourcesPath() + fileName);
|
||||
if (styleSheet.open(QIODevice::ReadOnly) && globalStyleSheet.open(QIODevice::ReadOnly) ) {
|
||||
QDir::setCurrent(PathUtils::resourcesPath());
|
||||
setStyleSheet(globalStyleSheet.readAll() + styleSheet.readAll());
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessDialog::showEvent(QShowEvent* event) {
|
||||
resizeAndPosition();
|
||||
QDialog::showEvent(event);
|
||||
}
|
||||
|
||||
void FramelessDialog::resizeAndPosition(bool resizeParent) {
|
||||
QRect parentGeometry = Application::getInstance()->getDesirableApplicationGeometry();
|
||||
QSize parentSize = parentGeometry.size();
|
||||
|
||||
// keep full app height or width depending on position
|
||||
if (_position == POSITION_LEFT || _position == POSITION_RIGHT) {
|
||||
setFixedHeight(parentSize.height());
|
||||
} else {
|
||||
setFixedWidth(parentSize.width());
|
||||
}
|
||||
|
||||
// resize parrent if width is smaller than this dialog
|
||||
if (resizeParent && parentSize.width() < size().width()) {
|
||||
parentWidget()->resize(size().width(), parentSize.height());
|
||||
}
|
||||
|
||||
if (_position == POSITION_LEFT || _position == POSITION_TOP) {
|
||||
// move to upper left corner
|
||||
move(parentGeometry.topLeft());
|
||||
} else if (_position == POSITION_RIGHT) {
|
||||
// move to upper right corner
|
||||
QPoint pos = parentGeometry.topRight();
|
||||
pos.setX(pos.x() - size().width());
|
||||
move(pos);
|
||||
}
|
||||
repaint();
|
||||
}
|
||||
|
||||
void FramelessDialog::mousePressEvent(QMouseEvent* mouseEvent) {
|
||||
if (_allowResize && mouseEvent->button() == Qt::LeftButton) {
|
||||
if (_position == POSITION_LEFT || _position == POSITION_RIGHT) {
|
||||
bool hitLeft = (_position == POSITION_LEFT) && (abs(mouseEvent->pos().x() - size().width()) < RESIZE_HANDLE_WIDTH);
|
||||
bool hitRight = (_position == POSITION_RIGHT) && (mouseEvent->pos().x() < RESIZE_HANDLE_WIDTH);
|
||||
if (hitLeft || hitRight) {
|
||||
_isResizing = true;
|
||||
_resizeInitialWidth = size().width();
|
||||
setCursor(Qt::SizeHorCursor);
|
||||
}
|
||||
} else {
|
||||
bool hitTop = (_position == POSITION_TOP) && (abs(mouseEvent->pos().y() - size().height()) < RESIZE_HANDLE_WIDTH);
|
||||
if (hitTop) {
|
||||
_isResizing = true;
|
||||
_resizeInitialWidth = size().height();
|
||||
setCursor(Qt::SizeHorCursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void FramelessDialog::mouseReleaseEvent(QMouseEvent* mouseEvent) {
|
||||
unsetCursor();
|
||||
_isResizing = false;
|
||||
}
|
||||
|
||||
void FramelessDialog::mouseMoveEvent(QMouseEvent* mouseEvent) {
|
||||
if (_isResizing) {
|
||||
if (_position == POSITION_LEFT) {
|
||||
resize(mouseEvent->pos().x(), size().height());
|
||||
} else if (_position == POSITION_RIGHT) {
|
||||
setUpdatesEnabled(false);
|
||||
resize(_resizeInitialWidth - mouseEvent->pos().x(), size().height());
|
||||
resizeAndPosition();
|
||||
_resizeInitialWidth = size().width();
|
||||
setUpdatesEnabled(true);
|
||||
} else if (_position == POSITION_TOP) {
|
||||
resize(size().width(), mouseEvent->pos().y());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
//
|
||||
// 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:
|
||||
enum Position { POSITION_LEFT, POSITION_RIGHT, POSITION_TOP };
|
||||
|
||||
FramelessDialog(QWidget* parent, Qt::WindowFlags flags = 0, Position position = POSITION_LEFT);
|
||||
void setStyleSheetFile(const QString& fileName);
|
||||
void setAllowResize(bool allowResize) { _allowResize = allowResize; }
|
||||
bool getAllowResize() { return _allowResize; }
|
||||
void setHideOnBlur(bool hideOnBlur) { _hideOnBlur = hideOnBlur; }
|
||||
bool getHideOnBlur() { return _hideOnBlur; }
|
||||
void resizeAndPosition(bool resizeParent = true);
|
||||
|
||||
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 _allowResize;
|
||||
bool _isResizing;
|
||||
int _resizeInitialWidth;
|
||||
bool _selfHidden; ///< true when the dialog itself because of a window event (deactivation or minimization)
|
||||
Position _position;
|
||||
bool _hideOnBlur;
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_FramelessDialog_h
|
|
@ -1,120 +1,35 @@
|
|||
//
|
||||
//
|
||||
// LoginDialog.cpp
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Ryan Huffman on 4/23/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
// Created by Bradley Austin Davis on 2015/04/14
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
#include <QWidget>
|
||||
#include <QPushButton>
|
||||
#include <QPixmap>
|
||||
|
||||
#include <NetworkingConstants.h>
|
||||
#include <PathUtils.h>
|
||||
|
||||
#include "Application.h"
|
||||
#include "Menu.h"
|
||||
#include "AccountManager.h"
|
||||
#include "ui_loginDialog.h"
|
||||
#include "LoginDialog.h"
|
||||
#include "UIUtil.h"
|
||||
|
||||
const QString CREATE_ACCOUNT_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/signup";
|
||||
const QString FORGOT_PASSWORD_URL = NetworkingConstants::METAVERSE_SERVER_URL.toString() + "/users/password/new";
|
||||
#include "DependencyManager.h"
|
||||
#include "AccountManager.h"
|
||||
#include "Menu.h"
|
||||
#include <NetworkingConstants.h>
|
||||
|
||||
LoginDialog::LoginDialog(QWidget* parent) :
|
||||
FramelessDialog(parent, 0, FramelessDialog::POSITION_TOP),
|
||||
_ui(new Ui::LoginDialog) {
|
||||
|
||||
_ui->setupUi(this);
|
||||
reset();
|
||||
|
||||
setAttribute(Qt::WA_DeleteOnClose, false);
|
||||
QML_DIALOG_DEF(LoginDialog)
|
||||
|
||||
LoginDialog::LoginDialog(QQuickItem *parent) : OffscreenQmlDialog(parent), _rootUrl(NetworkingConstants::METAVERSE_SERVER_URL.toString()) {
|
||||
connect(&AccountManager::getInstance(), &AccountManager::loginComplete,
|
||||
this, &LoginDialog::handleLoginCompleted);
|
||||
this, &LoginDialog::handleLoginCompleted);
|
||||
connect(&AccountManager::getInstance(), &AccountManager::loginFailed,
|
||||
this, &LoginDialog::handleLoginFailed);
|
||||
connect(_ui->loginButton, &QPushButton::clicked,
|
||||
this, &LoginDialog::handleLoginClicked);
|
||||
connect(_ui->closeButton, &QPushButton::clicked,
|
||||
this, &LoginDialog::close);
|
||||
|
||||
UIUtil::scaleWidgetFontSizes(this);
|
||||
_ui->accountLabel->setText(_ui->accountLabel->text().arg(CREATE_ACCOUNT_URL, FORGOT_PASSWORD_URL));
|
||||
|
||||
// Initialize toggle connection
|
||||
toggleQAction();
|
||||
};
|
||||
|
||||
LoginDialog::~LoginDialog() {
|
||||
delete _ui;
|
||||
};
|
||||
|
||||
void LoginDialog::reset() {
|
||||
_ui->errorLabel->hide();
|
||||
_ui->emailLineEdit->setFocus();
|
||||
_ui->logoLabel->setPixmap(QPixmap(PathUtils::resourcesPath() + "images/hifi-logo.svg"));
|
||||
_ui->loginButton->setIcon(QIcon(PathUtils::resourcesPath() + "images/login.svg"));
|
||||
_ui->closeButton->setIcon(QIcon(PathUtils::resourcesPath() + "images/close.svg"));
|
||||
_ui->infoLabel->setVisible(false);
|
||||
_ui->errorLabel->setVisible(false);
|
||||
|
||||
_ui->emailLineEdit->setText("");
|
||||
_ui->passwordLineEdit->setText("");
|
||||
_ui->loginArea->setDisabled(false);
|
||||
this, &LoginDialog::handleLoginFailed);
|
||||
}
|
||||
|
||||
void LoginDialog::handleLoginCompleted(const QUrl& authURL) {
|
||||
reset();
|
||||
close();
|
||||
};
|
||||
|
||||
void LoginDialog::handleLoginFailed() {
|
||||
_ui->infoLabel->setVisible(false);
|
||||
_ui->errorLabel->setVisible(true);
|
||||
|
||||
_ui->errorLabel->show();
|
||||
_ui->loginArea->setDisabled(false);
|
||||
|
||||
// Move focus to password and select the entire line
|
||||
_ui->passwordLineEdit->setFocus();
|
||||
_ui->passwordLineEdit->setSelection(0, _ui->emailLineEdit->maxLength());
|
||||
};
|
||||
|
||||
void LoginDialog::handleLoginClicked() {
|
||||
// If the email or password inputs are empty, move focus to them, otherwise attempt to login.
|
||||
if (_ui->emailLineEdit->text().isEmpty()) {
|
||||
_ui->emailLineEdit->setFocus();
|
||||
} else if (_ui->passwordLineEdit->text().isEmpty()) {
|
||||
_ui->passwordLineEdit->setFocus();
|
||||
} else {
|
||||
_ui->infoLabel->setVisible(true);
|
||||
_ui->errorLabel->setVisible(false);
|
||||
|
||||
_ui->loginArea->setDisabled(true);
|
||||
AccountManager::getInstance().requestAccessToken(_ui->emailLineEdit->text(), _ui->passwordLineEdit->text());
|
||||
}
|
||||
};
|
||||
|
||||
void LoginDialog::moveEvent(QMoveEvent* event) {
|
||||
// Modal dialogs seemed to get repositioned automatically. Combat this by moving the window if needed.
|
||||
resizeAndPosition();
|
||||
};
|
||||
|
||||
|
||||
void LoginDialog::toggleQAction() {
|
||||
void LoginDialog::toggleAction() {
|
||||
AccountManager& accountManager = AccountManager::getInstance();
|
||||
QAction* loginAction = Menu::getInstance()->getActionForOption(MenuOption::Login);
|
||||
Q_CHECK_PTR(loginAction);
|
||||
|
||||
disconnect(loginAction, 0, 0, 0);
|
||||
|
||||
|
||||
if (accountManager.isLoggedIn()) {
|
||||
// change the menu item to logout
|
||||
loginAction->setText("Logout " + accountManager.getAccountInfo().getUsername());
|
||||
|
@ -122,11 +37,39 @@ void LoginDialog::toggleQAction() {
|
|||
} else {
|
||||
// change the menu item to login
|
||||
loginAction->setText("Login");
|
||||
connect(loginAction, &QAction::triggered, this, &LoginDialog::showLoginForCurrentDomain);
|
||||
connect(loginAction, &QAction::triggered, &LoginDialog::show);
|
||||
}
|
||||
}
|
||||
|
||||
void LoginDialog::showLoginForCurrentDomain() {
|
||||
show();
|
||||
resizeAndPosition(false);
|
||||
void LoginDialog::handleLoginCompleted(const QUrl&) {
|
||||
hide();
|
||||
}
|
||||
|
||||
void LoginDialog::handleLoginFailed() {
|
||||
setStatusText("<font color = \"#267077\">Invalid username or password.< / font>");
|
||||
}
|
||||
|
||||
void LoginDialog::setStatusText(const QString& statusText) {
|
||||
if (statusText != _statusText) {
|
||||
_statusText = statusText;
|
||||
emit statusTextChanged();
|
||||
}
|
||||
}
|
||||
|
||||
QString LoginDialog::statusText() const {
|
||||
return _statusText;
|
||||
}
|
||||
|
||||
QString LoginDialog::rootUrl() const {
|
||||
return _rootUrl;
|
||||
}
|
||||
|
||||
void LoginDialog::login(const QString& username, const QString& password) {
|
||||
qDebug() << "Attempting to login " << username;
|
||||
setStatusText("Authenticating...");
|
||||
AccountManager::getInstance().requestAccessToken(username, password);
|
||||
}
|
||||
|
||||
void LoginDialog::openUrl(const QString& url) {
|
||||
qDebug() << url;
|
||||
}
|
||||
|
|
|
@ -1,46 +1,49 @@
|
|||
//
|
||||
// LoginDialog.h
|
||||
// interface/src/ui
|
||||
//
|
||||
// Created by Ryan Huffman on 4/23/14.
|
||||
// Copyright 2014 High Fidelity, Inc.
|
||||
// Created by Bradley Austin Davis on 2015/04/14
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_LoginDialog_h
|
||||
#define hifi_LoginDialog_h
|
||||
|
||||
#include <QObject>
|
||||
#include "FramelessDialog.h"
|
||||
#include <OffscreenQmlDialog.h>
|
||||
|
||||
namespace Ui {
|
||||
class LoginDialog;
|
||||
}
|
||||
|
||||
class LoginDialog : public FramelessDialog {
|
||||
class LoginDialog : public OffscreenQmlDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
QML_DIALOG_DECL
|
||||
|
||||
Q_PROPERTY(QString statusText READ statusText WRITE setStatusText NOTIFY statusTextChanged)
|
||||
Q_PROPERTY(QString rootUrl READ rootUrl)
|
||||
|
||||
public:
|
||||
LoginDialog(QWidget* parent);
|
||||
~LoginDialog();
|
||||
static void toggleAction();
|
||||
|
||||
public slots:
|
||||
void toggleQAction();
|
||||
void showLoginForCurrentDomain();
|
||||
|
||||
protected slots:
|
||||
void reset();
|
||||
void handleLoginClicked();
|
||||
LoginDialog(QQuickItem* parent = nullptr);
|
||||
|
||||
void setStatusText(const QString& statusText);
|
||||
QString statusText() const;
|
||||
|
||||
QString rootUrl() const;
|
||||
|
||||
signals:
|
||||
void statusTextChanged();
|
||||
|
||||
protected:
|
||||
void handleLoginCompleted(const QUrl& authURL);
|
||||
void handleLoginFailed();
|
||||
|
||||
protected:
|
||||
void moveEvent(QMoveEvent* event);
|
||||
|
||||
Q_INVOKABLE void login(const QString& username, const QString& password);
|
||||
Q_INVOKABLE void openUrl(const QString& url);
|
||||
private:
|
||||
Ui::LoginDialog* _ui = nullptr;
|
||||
QString _statusText;
|
||||
const QString _rootUrl;
|
||||
};
|
||||
|
||||
#endif // hifi_LoginDialog_h
|
||||
|
|
|
@ -77,7 +77,7 @@ void Cube3DOverlay::render(RenderArgs* args) {
|
|||
if (_drawOnHUD) {
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha));
|
||||
} else {
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha));
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, glm::vec4(1.0f, 1.0f, 1.0f, alpha));
|
||||
}
|
||||
|
||||
glPopMatrix();
|
||||
|
@ -89,7 +89,7 @@ void Cube3DOverlay::render(RenderArgs* args) {
|
|||
if (_drawOnHUD) {
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, cubeColor);
|
||||
} else {
|
||||
DependencyManager::get<DeferredLightingEffect>()->renderSolidCube(1.0f, cubeColor);
|
||||
DependencyManager::get<GeometryCache>()->renderSolidCube(1.0f, cubeColor);
|
||||
}
|
||||
glPopMatrix();
|
||||
} else {
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
#include <Model.h>
|
||||
#include <NetworkAccessManager.h>
|
||||
#include <PerfStat.h>
|
||||
#include <SceneScriptingInterface.h>
|
||||
#include <ScriptEngine.h>
|
||||
|
||||
#include "EntityTreeRenderer.h"
|
||||
|
@ -30,12 +31,12 @@
|
|||
#include "RenderableBoxEntityItem.h"
|
||||
#include "RenderableLightEntityItem.h"
|
||||
#include "RenderableModelEntityItem.h"
|
||||
#include "RenderableParticleEffectEntityItem.h"
|
||||
#include "RenderableSphereEntityItem.h"
|
||||
#include "RenderableTextEntityItem.h"
|
||||
#include "RenderableParticleEffectEntityItem.h"
|
||||
#include "RenderableZoneEntityItem.h"
|
||||
#include "EntitiesRendererLogging.h"
|
||||
|
||||
|
||||
EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterface* viewState,
|
||||
AbstractScriptingServicesInterface* scriptingServices) :
|
||||
OctreeRenderer(),
|
||||
|
@ -56,6 +57,7 @@ EntityTreeRenderer::EntityTreeRenderer(bool wantScripts, AbstractViewStateInterf
|
|||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Light, RenderableLightEntityItem::factory)
|
||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Text, RenderableTextEntityItem::factory)
|
||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(ParticleEffect, RenderableParticleEffectEntityItem::factory)
|
||||
REGISTER_ENTITY_TYPE_WITH_FACTORY(Zone, RenderableZoneEntityItem::factory)
|
||||
|
||||
_currentHoverOverEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID
|
||||
_currentClickingOnEntityID = EntityItemID::createInvalidEntityID(); // makes it the unknown ID
|
||||
|
@ -393,10 +395,51 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode, RenderArgs::R
|
|||
|
||||
|
||||
_tree->lockForRead();
|
||||
|
||||
// Whenever you're in an intersection between zones, we will always choose the smallest zone.
|
||||
_bestZone = NULL;
|
||||
_bestZoneVolume = std::numeric_limits<float>::max();
|
||||
_tree->recurseTreeWithOperation(renderOperation, &args);
|
||||
|
||||
// Model::RenderMode modelRenderMode = renderMode == RenderArgs::SHADOW_RENDER_MODE
|
||||
// ? RenderArgs::SHADOW_RENDER_MODE : RenderArgs::DEFAULT_RENDER_MODE;
|
||||
QSharedPointer<SceneScriptingInterface> scene = DependencyManager::get<SceneScriptingInterface>();
|
||||
|
||||
if (_bestZone) {
|
||||
if (!_hasPreviousZone) {
|
||||
_previousKeyLightColor = scene->getKeyLightColor();
|
||||
_previousKeyLightIntensity = scene->getKeyLightIntensity();
|
||||
_previousKeyLightAmbientIntensity = scene->getKeyLightAmbientIntensity();
|
||||
_previousKeyLightDirection = scene->getKeyLightDirection();
|
||||
_previousStageSunModelEnabled = scene->isStageSunModelEnabled();
|
||||
_previousStageLongitude = scene->getStageLocationLongitude();
|
||||
_previousStageLatitude = scene->getStageLocationLatitude();
|
||||
_previousStageAltitude = scene->getStageLocationAltitude();
|
||||
_previousStageHour = scene->getStageDayTime();
|
||||
_previousStageDay = scene->getStageYearTime();
|
||||
_hasPreviousZone = true;
|
||||
}
|
||||
scene->setKeyLightColor(_bestZone->getKeyLightColorVec3());
|
||||
scene->setKeyLightIntensity(_bestZone->getKeyLightIntensity());
|
||||
scene->setKeyLightAmbientIntensity(_bestZone->getKeyLightAmbientIntensity());
|
||||
scene->setKeyLightDirection(_bestZone->getKeyLightDirection());
|
||||
scene->setStageSunModelEnable(_bestZone->getStageSunModelEnabled());
|
||||
scene->setStageLocation(_bestZone->getStageLongitude(), _bestZone->getStageLatitude(),
|
||||
_bestZone->getStageAltitude());
|
||||
scene->setStageDayTime(_bestZone->getStageHour());
|
||||
scene->setStageYearTime(_bestZone->getStageDay());
|
||||
} else {
|
||||
if (_hasPreviousZone) {
|
||||
scene->setKeyLightColor(_previousKeyLightColor);
|
||||
scene->setKeyLightIntensity(_previousKeyLightIntensity);
|
||||
scene->setKeyLightAmbientIntensity(_previousKeyLightAmbientIntensity);
|
||||
scene->setKeyLightDirection(_previousKeyLightDirection);
|
||||
scene->setStageSunModelEnable(_previousStageSunModelEnabled);
|
||||
scene->setStageLocation(_previousStageLongitude, _previousStageLatitude,
|
||||
_previousStageAltitude);
|
||||
scene->setStageDayTime(_previousStageHour);
|
||||
scene->setStageYearTime(_previousStageDay);
|
||||
_hasPreviousZone = false;
|
||||
}
|
||||
}
|
||||
|
||||
// we must call endScene while we still have the tree locked so that no one deletes a model
|
||||
// on us while rendering the scene
|
||||
|
@ -454,7 +497,7 @@ const FBXGeometry* EntityTreeRenderer::getCollisionGeometryForEntity(const Entit
|
|||
|
||||
if (entityItem->getType() == EntityTypes::Model) {
|
||||
const RenderableModelEntityItem* constModelEntityItem = dynamic_cast<const RenderableModelEntityItem*>(entityItem);
|
||||
if (constModelEntityItem->hasCollisionModel()) {
|
||||
if (constModelEntityItem->hasCompoundShapeURL()) {
|
||||
RenderableModelEntityItem* modelEntityItem = const_cast<RenderableModelEntityItem*>(constModelEntityItem);
|
||||
Model* model = modelEntityItem->getModel(this);
|
||||
if (model) {
|
||||
|
@ -596,34 +639,59 @@ void EntityTreeRenderer::renderElement(OctreeElement* element, RenderArgs* args)
|
|||
EntityItem* entityItem = entityItems[i];
|
||||
|
||||
if (entityItem->isVisible()) {
|
||||
// render entityItem
|
||||
AABox entityBox = entityItem->getAABox();
|
||||
|
||||
// TODO: some entity types (like lights) might want to be rendered even
|
||||
// when they are outside of the view frustum...
|
||||
float distance = args->_viewFrustum->distanceToCamera(entityBox.calcCenter());
|
||||
|
||||
bool outOfView = args->_viewFrustum->boxInFrustum(entityBox) == ViewFrustum::OUTSIDE;
|
||||
if (!outOfView) {
|
||||
bool bigEnoughToRender = _viewState->shouldRenderMesh(entityBox.getLargestDimension(), distance);
|
||||
|
||||
if (bigEnoughToRender) {
|
||||
renderProxies(entityItem, args);
|
||||
|
||||
Glower* glower = NULL;
|
||||
if (entityItem->getGlowLevel() > 0.0f) {
|
||||
glower = new Glower(entityItem->getGlowLevel());
|
||||
// NOTE: Zone Entities are a special case we handle here... Zones don't render
|
||||
// like other entity types. So we will skip the normal rendering tests
|
||||
if (entityItem->getType() == EntityTypes::Zone) {
|
||||
if (entityItem->contains(args->_viewFrustum->getPosition())) {
|
||||
float entityVolumeEstimate = entityItem->getVolumeEstimate();
|
||||
if (entityVolumeEstimate < _bestZoneVolume) {
|
||||
_bestZoneVolume = entityVolumeEstimate;
|
||||
_bestZone = dynamic_cast<const ZoneEntityItem*>(entityItem);
|
||||
} else if (entityVolumeEstimate == _bestZoneVolume) {
|
||||
if (!_bestZone) {
|
||||
_bestZoneVolume = entityVolumeEstimate;
|
||||
_bestZone = dynamic_cast<const ZoneEntityItem*>(entityItem);
|
||||
} else {
|
||||
// in the case of the volume being equal, we will use the
|
||||
// EntityItemID to deterministically pick one entity over the other
|
||||
if (entityItem->getEntityItemID() < _bestZone->getEntityItemID()) {
|
||||
_bestZoneVolume = entityVolumeEstimate;
|
||||
_bestZone = dynamic_cast<const ZoneEntityItem*>(entityItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
entityItem->render(args);
|
||||
args->_itemsRendered++;
|
||||
if (glower) {
|
||||
delete glower;
|
||||
}
|
||||
} else {
|
||||
args->_itemsTooSmall++;
|
||||
}
|
||||
} else {
|
||||
args->_itemsOutOfView++;
|
||||
// render entityItem
|
||||
AABox entityBox = entityItem->getAABox();
|
||||
|
||||
// TODO: some entity types (like lights) might want to be rendered even
|
||||
// when they are outside of the view frustum...
|
||||
float distance = args->_viewFrustum->distanceToCamera(entityBox.calcCenter());
|
||||
|
||||
bool outOfView = args->_viewFrustum->boxInFrustum(entityBox) == ViewFrustum::OUTSIDE;
|
||||
if (!outOfView) {
|
||||
bool bigEnoughToRender = _viewState->shouldRenderMesh(entityBox.getLargestDimension(), distance);
|
||||
|
||||
if (bigEnoughToRender) {
|
||||
renderProxies(entityItem, args);
|
||||
|
||||
Glower* glower = NULL;
|
||||
if (entityItem->getGlowLevel() > 0.0f) {
|
||||
glower = new Glower(entityItem->getGlowLevel());
|
||||
}
|
||||
entityItem->render(args);
|
||||
args->_itemsRendered++;
|
||||
if (glower) {
|
||||
delete glower;
|
||||
}
|
||||
} else {
|
||||
args->_itemsTooSmall++;
|
||||
}
|
||||
} else {
|
||||
args->_itemsOutOfView++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,18 +12,20 @@
|
|||
#ifndef hifi_EntityTreeRenderer_h
|
||||
#define hifi_EntityTreeRenderer_h
|
||||
|
||||
#include <QSet>
|
||||
#include <QStack>
|
||||
|
||||
#include <EntityTree.h>
|
||||
#include <EntityScriptingInterface.h> // for RayToEntityIntersectionResult
|
||||
#include <MouseEvent.h>
|
||||
#include <OctreeRenderer.h>
|
||||
#include <ScriptCache.h>
|
||||
|
||||
class AbstractScriptingServicesInterface;
|
||||
class AbstractViewStateInterface;
|
||||
class Model;
|
||||
class ScriptEngine;
|
||||
class AbstractViewStateInterface;
|
||||
class AbstractScriptingServicesInterface;
|
||||
|
||||
class ScriptEngine;
|
||||
class ZoneEntityItem;
|
||||
|
||||
class EntityScriptDetails {
|
||||
public:
|
||||
|
@ -164,6 +166,21 @@ private:
|
|||
bool _shuttingDown = false;
|
||||
|
||||
QMultiMap<QUrl, EntityItemID> _waitingOnPreload;
|
||||
|
||||
bool _hasPreviousZone = false;
|
||||
const ZoneEntityItem* _bestZone;
|
||||
float _bestZoneVolume;
|
||||
|
||||
glm::vec3 _previousKeyLightColor;
|
||||
float _previousKeyLightIntensity;
|
||||
float _previousKeyLightAmbientIntensity;
|
||||
glm::vec3 _previousKeyLightDirection;
|
||||
bool _previousStageSunModelEnabled;
|
||||
float _previousStageLongitude;
|
||||
float _previousStageLatitude;
|
||||
float _previousStageAltitude;
|
||||
float _previousStageHour;
|
||||
int _previousStageDay;
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -224,10 +224,10 @@ Model* RenderableModelEntityItem::getModel(EntityTreeRenderer* renderer) {
|
|||
// if we have a previously allocated model, but its URL doesn't match
|
||||
// then we need to let our renderer update our model for us.
|
||||
if (_model && QUrl(getModelURL()) != _model->getURL()) {
|
||||
result = _model = _myRenderer->updateModel(_model, getModelURL(), getCollisionModelURL());
|
||||
result = _model = _myRenderer->updateModel(_model, getModelURL(), getCompoundShapeURL());
|
||||
_needsInitialSimulation = true;
|
||||
} else if (!_model) { // if we don't yet have a model, then we want our renderer to allocate one
|
||||
result = _model = _myRenderer->allocateModel(getModelURL(), getCollisionModelURL());
|
||||
result = _model = _myRenderer->allocateModel(getModelURL(), getCompoundShapeURL());
|
||||
_needsInitialSimulation = true;
|
||||
} else { // we already have the model we want...
|
||||
result = _model;
|
||||
|
@ -267,8 +267,8 @@ bool RenderableModelEntityItem::findDetailedRayIntersection(const glm::vec3& ori
|
|||
return _model->findRayIntersectionAgainstSubMeshes(origin, direction, distance, face, extraInfo, precisionPicking);
|
||||
}
|
||||
|
||||
void RenderableModelEntityItem::setCollisionModelURL(const QString& url) {
|
||||
ModelEntityItem::setCollisionModelURL(url);
|
||||
void RenderableModelEntityItem::setCompoundShapeURL(const QString& url) {
|
||||
ModelEntityItem::setCompoundShapeURL(url);
|
||||
if (_model) {
|
||||
_model->setCollisionModelURL(QUrl(url));
|
||||
}
|
||||
|
@ -410,8 +410,17 @@ void RenderableModelEntityItem::computeShapeInfo(ShapeInfo& info) {
|
|||
}
|
||||
|
||||
glm::vec3 collisionModelDimensions = box.getDimensions();
|
||||
info.setParams(type, collisionModelDimensions, _collisionModelURL);
|
||||
info.setParams(type, collisionModelDimensions, _compoundShapeURL);
|
||||
info.setConvexHulls(_points);
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderableModelEntityItem::contains(const glm::vec3& point) const {
|
||||
if (EntityItem::contains(point) && _model && _model->getCollisionGeometry()) {
|
||||
const QSharedPointer<NetworkGeometry> collisionNetworkGeometry = _model->getCollisionGeometry();
|
||||
const FBXGeometry& collisionGeometry = collisionNetworkGeometry->getFBXGeometry();
|
||||
return collisionGeometry.convexHullContains(worldToEntity(point));
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
@ -52,10 +52,12 @@ public:
|
|||
|
||||
bool needsToCallUpdate() const;
|
||||
|
||||
virtual void setCollisionModelURL(const QString& url);
|
||||
virtual void setCompoundShapeURL(const QString& url);
|
||||
|
||||
bool isReadyToComputeShape();
|
||||
void computeShapeInfo(ShapeInfo& info);
|
||||
|
||||
virtual bool contains(const glm::vec3& point) const;
|
||||
|
||||
private:
|
||||
void remapTextures();
|
||||
|
|
57
libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
Normal file
57
libraries/entities-renderer/src/RenderableZoneEntityItem.cpp
Normal file
|
@ -0,0 +1,57 @@
|
|||
//
|
||||
// RenderableZoneEntityItem.cpp
|
||||
//
|
||||
//
|
||||
// Created by Clement on 4/22/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "RenderableZoneEntityItem.h"
|
||||
|
||||
#include <DependencyManager.h>
|
||||
#include <GeometryCache.h>
|
||||
|
||||
EntityItem* RenderableZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
return new RenderableZoneEntityItem(entityID, properties);
|
||||
}
|
||||
|
||||
bool RenderableZoneEntityItem::setProperties(const EntityItemProperties& properties) {
|
||||
QString oldShapeURL = getCompoundShapeURL();
|
||||
bool somethingChanged = ZoneEntityItem::setProperties(properties);
|
||||
if (somethingChanged && oldShapeURL != getCompoundShapeURL()) {
|
||||
_compoundShapeModel = DependencyManager::get<GeometryCache>()->getGeometry(getCompoundShapeURL(), QUrl(), true);
|
||||
}
|
||||
return somethingChanged;
|
||||
}
|
||||
|
||||
int RenderableZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||
ReadBitstreamToTreeParams& args,
|
||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
|
||||
QString oldShapeURL = getCompoundShapeURL();
|
||||
int bytesRead = ZoneEntityItem::readEntitySubclassDataFromBuffer(data, bytesLeftToRead,
|
||||
args, propertyFlags, overwriteLocalData);
|
||||
if (oldShapeURL != getCompoundShapeURL()) {
|
||||
_compoundShapeModel = DependencyManager::get<GeometryCache>()->getGeometry(getCompoundShapeURL(), QUrl(), true);
|
||||
}
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
bool RenderableZoneEntityItem::contains(const glm::vec3& point) const {
|
||||
if (getShapeType() != SHAPE_TYPE_COMPOUND) {
|
||||
return EntityItem::contains(point);
|
||||
}
|
||||
if (!_compoundShapeModel && hasCompoundShapeURL()) {
|
||||
const_cast<RenderableZoneEntityItem*>(this)->_compoundShapeModel = DependencyManager::get<GeometryCache>()->getGeometry(getCompoundShapeURL(), QUrl(), true);
|
||||
}
|
||||
|
||||
if (EntityItem::contains(point) && _compoundShapeModel && _compoundShapeModel->isLoaded()) {
|
||||
const FBXGeometry& geometry = _compoundShapeModel->getFBXGeometry();
|
||||
glm::vec3 meshDimensions = geometry.getUnscaledMeshExtents().maximum - geometry.getUnscaledMeshExtents().minimum;
|
||||
return geometry.convexHullContains(worldToEntity(point) * meshDimensions);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
39
libraries/entities-renderer/src/RenderableZoneEntityItem.h
Normal file
39
libraries/entities-renderer/src/RenderableZoneEntityItem.h
Normal file
|
@ -0,0 +1,39 @@
|
|||
//
|
||||
// RenderableZoneEntityItem.h
|
||||
//
|
||||
//
|
||||
// Created by Clement on 4/22/15.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_RenderableZoneEntityItem_h
|
||||
#define hifi_RenderableZoneEntityItem_h
|
||||
|
||||
#include <ZoneEntityItem.h>
|
||||
|
||||
class NetworkGeometry;
|
||||
|
||||
class RenderableZoneEntityItem : public ZoneEntityItem {
|
||||
public:
|
||||
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
||||
RenderableZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
||||
ZoneEntityItem(entityItemID, properties)
|
||||
{ }
|
||||
|
||||
virtual bool setProperties(const EntityItemProperties& properties);
|
||||
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||
ReadBitstreamToTreeParams& args,
|
||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
|
||||
|
||||
virtual bool contains(const glm::vec3& point) const;
|
||||
|
||||
private:
|
||||
|
||||
QSharedPointer<NetworkGeometry> _compoundShapeModel;
|
||||
};
|
||||
|
||||
#endif // hifi_RenderableZoneEntityItem_h
|
|
@ -11,6 +11,8 @@
|
|||
|
||||
#include <QtCore/QObject>
|
||||
|
||||
#include <glm/gtx/transform.hpp>
|
||||
|
||||
#include <ByteCountCoding.h>
|
||||
#include <GLMHelpers.h>
|
||||
#include <Octree.h>
|
||||
|
@ -599,7 +601,7 @@ int EntityItem::readEntityDataFromBuffer(const unsigned char* data, int bytesLef
|
|||
|
||||
auto nodeList = DependencyManager::get<NodeList>();
|
||||
const QUuid& myNodeID = nodeList->getSessionUUID();
|
||||
if (_simulatorID == myNodeID) {
|
||||
if (_simulatorID == myNodeID && !_simulatorID.isNull()) {
|
||||
// the packet that produced this bitstream originally came from physics simulations performed by
|
||||
// this node, so our version has to be newer than what the packet contained.
|
||||
_position = savePosition;
|
||||
|
@ -821,7 +823,27 @@ bool EntityItem::isMoving() const {
|
|||
return hasVelocity() || hasAngularVelocity();
|
||||
}
|
||||
|
||||
bool EntityItem::lifetimeHasExpired() const {
|
||||
glm::mat4 EntityItem::getEntityToWorldMatrix() const {
|
||||
glm::mat4 translation = glm::translate(getPosition());
|
||||
glm::mat4 rotation = glm::mat4_cast(getRotation());
|
||||
glm::mat4 scale = glm::scale(getDimensions());
|
||||
glm::mat4 registration = glm::translate(ENTITY_ITEM_DEFAULT_REGISTRATION_POINT - getRegistrationPoint());
|
||||
return translation * rotation * scale * registration;
|
||||
}
|
||||
|
||||
glm::mat4 EntityItem::getWorldToEntityMatrix() const {
|
||||
return glm::inverse(getEntityToWorldMatrix());
|
||||
}
|
||||
|
||||
glm::vec3 EntityItem::entityToWorld(const glm::vec3 point) const {
|
||||
return glm::vec3(getEntityToWorldMatrix() * glm::vec4(point, 1.0f));
|
||||
}
|
||||
|
||||
glm::vec3 EntityItem::worldToEntity(const glm::vec3 point) const {
|
||||
return glm::vec3(getWorldToEntityMatrix() * glm::vec4(point, 1.0f));
|
||||
}
|
||||
|
||||
bool EntityItem::lifetimeHasExpired() const {
|
||||
return isMortal() && (getAge() > getLifetime());
|
||||
}
|
||||
|
||||
|
@ -1011,12 +1033,6 @@ AABox EntityItem::getAABox() const {
|
|||
return AABox(rotatedExtentsRelativeToRegistrationPoint);
|
||||
}
|
||||
|
||||
AABox EntityItem::getAABoxInDomainUnits() const {
|
||||
AABox box = getAABox();
|
||||
box.scale(1.0f / (float)TREE_SCALE);
|
||||
return box;
|
||||
}
|
||||
|
||||
// NOTE: This should only be used in cases of old bitstreams which only contain radius data
|
||||
// 0,0,0 --> maxDimension,maxDimension,maxDimension
|
||||
// ... has a corner to corner distance of glm::length(maxDimension,maxDimension,maxDimension)
|
||||
|
@ -1044,6 +1060,16 @@ float EntityItem::getRadius() const {
|
|||
return 0.5f * glm::length(_dimensions);
|
||||
}
|
||||
|
||||
bool EntityItem::contains(const glm::vec3& point) const {
|
||||
if (getShapeType() == SHAPE_TYPE_COMPOUND) {
|
||||
return getAABox().contains(point);
|
||||
} else {
|
||||
ShapeInfo info;
|
||||
info.setParams(getShapeType(), glm::vec3(0.5f));
|
||||
return info.contains(worldToEntity(point));
|
||||
}
|
||||
}
|
||||
|
||||
void EntityItem::computeShapeInfo(ShapeInfo& info) {
|
||||
info.setParams(getShapeType(), 0.5f * getDimensions());
|
||||
}
|
||||
|
|
|
@ -145,25 +145,16 @@ public:
|
|||
|
||||
// attributes applicable to all entity types
|
||||
EntityTypes::EntityType getType() const { return _type; }
|
||||
glm::vec3 getPositionInDomainUnits() const { return _position / (float)TREE_SCALE; } /// get position in domain scale units (0.0 - 1.0)
|
||||
const glm::vec3& getPosition() const { return _position; } /// get position in meters
|
||||
|
||||
/// set position in domain scale units (0.0 - 1.0)
|
||||
void setPositionInDomainUnits(const glm::vec3& value)
|
||||
{ setPosition(glm::clamp(value, 0.0f, 1.0f) * (float)TREE_SCALE); }
|
||||
void setPosition(const glm::vec3& value) {
|
||||
_position = value;
|
||||
}
|
||||
|
||||
glm::vec3 getCenterInDomainUnits() const { return getCenter() / (float) TREE_SCALE; }
|
||||
glm::vec3 getCenter() const;
|
||||
|
||||
glm::vec3 getDimensionsInDomainUnits() const { return _dimensions / (float)TREE_SCALE; } /// get dimensions in domain scale units (0.0 - 1.0)
|
||||
const glm::vec3& getDimensions() const { return _dimensions; } /// get dimensions in meters
|
||||
|
||||
/// set dimensions in domain scale units (0.0 - 1.0)
|
||||
virtual void setDimensionsInDomainUnits(const glm::vec3& value) { _dimensions = glm::abs(value) * (float)TREE_SCALE; }
|
||||
|
||||
/// set dimensions in meter units (0.0 - TREE_SCALE)
|
||||
virtual void setDimensions(const glm::vec3& value) { _dimensions = glm::abs(value); }
|
||||
|
||||
|
@ -182,15 +173,11 @@ public:
|
|||
|
||||
float getDensity() const { return _density; }
|
||||
|
||||
glm::vec3 getVelocityInDomainUnits() const { return _velocity / (float)TREE_SCALE; } /// velocity in domain scale units (0.0-1.0) per second
|
||||
const glm::vec3 getVelocity() const { return _velocity; } /// get velocity in meters
|
||||
void setVelocityInDomainUnits(const glm::vec3& value) { _velocity = value * (float)TREE_SCALE; } /// velocity in domain scale units (0.0-1.0) per second
|
||||
void setVelocity(const glm::vec3& value) { _velocity = value; } /// velocity in meters
|
||||
bool hasVelocity() const { return _velocity != ENTITY_ITEM_ZERO_VEC3; }
|
||||
|
||||
glm::vec3 getGravityInDomainUnits() const { return _gravity / (float)TREE_SCALE; } /// gravity in domain scale units (0.0-1.0) per second squared
|
||||
const glm::vec3& getGravity() const { return _gravity; } /// get gravity in meters
|
||||
void setGravityInDomainUnits(const glm::vec3& value) { _gravity = value * (float)TREE_SCALE; } /// gravity in domain scale units (0.0-1.0) per second squared
|
||||
void setGravity(const glm::vec3& value) { _gravity = value; } /// gravity in meters
|
||||
bool hasGravity() const { return _gravity != ENTITY_ITEM_ZERO_VEC3; }
|
||||
|
||||
|
@ -220,7 +207,6 @@ public:
|
|||
AACube getMaximumAACube() const;
|
||||
AACube getMinimumAACube() const;
|
||||
AABox getAABox() const; /// axis aligned bounding box in world-frame (meters)
|
||||
AABox getAABoxInDomainUnits() const; /// axis aligned bounding box in domain scale units (0.0 - 1.0)
|
||||
|
||||
const QString& getScript() const { return _script; }
|
||||
void setScript(const QString& value) { _script = value; }
|
||||
|
@ -265,11 +251,11 @@ public:
|
|||
// TODO: get rid of users of getRadius()...
|
||||
float getRadius() const;
|
||||
|
||||
virtual bool contains(const glm::vec3& point) const { return getAABox().contains(point); }
|
||||
virtual bool containsInDomainUnits(const glm::vec3& point) const { return getAABoxInDomainUnits().contains(point); }
|
||||
virtual bool contains(const glm::vec3& point) const;
|
||||
|
||||
virtual bool isReadyToComputeShape() { return true; }
|
||||
virtual void computeShapeInfo(ShapeInfo& info);
|
||||
virtual float getVolumeEstimate() const { return _dimensions.x * _dimensions.y * _dimensions.z; }
|
||||
|
||||
/// return preferred shape type (actual physical shape may differ)
|
||||
virtual ShapeType getShapeType() const { return SHAPE_TYPE_NONE; }
|
||||
|
@ -309,6 +295,11 @@ public:
|
|||
static void setSendPhysicsUpdates(bool value) { _sendPhysicsUpdates = value; }
|
||||
static bool getSendPhysicsUpdates() { return _sendPhysicsUpdates; }
|
||||
|
||||
glm::mat4 getEntityToWorldMatrix() const;
|
||||
glm::mat4 getWorldToEntityMatrix() const;
|
||||
glm::vec3 worldToEntity(const glm::vec3 point) const;
|
||||
glm::vec3 entityToWorld(const glm::vec3 point) const;
|
||||
|
||||
protected:
|
||||
|
||||
static bool _sendPhysicsUpdates;
|
||||
|
|
|
@ -18,14 +18,14 @@
|
|||
#include <GLMHelpers.h>
|
||||
#include <RegisteredMetaTypes.h>
|
||||
|
||||
#include "EntitiesLogging.h"
|
||||
#include "EntityItem.h"
|
||||
#include "EntityItemProperties.h"
|
||||
#include "EntityItemPropertiesDefaults.h"
|
||||
#include "ModelEntityItem.h"
|
||||
#include "TextEntityItem.h"
|
||||
#include "EntitiesLogging.h"
|
||||
#include "ParticleEffectEntityItem.h"
|
||||
|
||||
#include "TextEntityItem.h"
|
||||
#include "ZoneEntityItem.h"
|
||||
|
||||
EntityPropertyList PROP_LAST_ITEM = (EntityPropertyList)(PROP_AFTER_LAST_ITEM - 1);
|
||||
|
||||
|
@ -44,7 +44,7 @@ EntityItemProperties::EntityItemProperties() :
|
|||
CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT),
|
||||
CONSTRUCT_PROPERTY(color, ),
|
||||
CONSTRUCT_PROPERTY(modelURL, ""),
|
||||
CONSTRUCT_PROPERTY(collisionModelURL, ""),
|
||||
CONSTRUCT_PROPERTY(compoundShapeURL, ""),
|
||||
CONSTRUCT_PROPERTY(animationURL, ""),
|
||||
CONSTRUCT_PROPERTY(animationFPS, ModelEntityItem::DEFAULT_ANIMATION_FPS),
|
||||
CONSTRUCT_PROPERTY(animationFrameIndex, ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX),
|
||||
|
@ -76,6 +76,16 @@ EntityItemProperties::EntityItemProperties() :
|
|||
CONSTRUCT_PROPERTY(localGravity, ParticleEffectEntityItem::DEFAULT_LOCAL_GRAVITY),
|
||||
CONSTRUCT_PROPERTY(particleRadius, ParticleEffectEntityItem::DEFAULT_PARTICLE_RADIUS),
|
||||
CONSTRUCT_PROPERTY(marketplaceID, ENTITY_ITEM_DEFAULT_MARKETPLACE_ID),
|
||||
CONSTRUCT_PROPERTY(keyLightColor, ZoneEntityItem::DEFAULT_KEYLIGHT_COLOR),
|
||||
CONSTRUCT_PROPERTY(keyLightIntensity, ZoneEntityItem::DEFAULT_KEYLIGHT_INTENSITY),
|
||||
CONSTRUCT_PROPERTY(keyLightAmbientIntensity, ZoneEntityItem::DEFAULT_KEYLIGHT_AMBIENT_INTENSITY),
|
||||
CONSTRUCT_PROPERTY(keyLightDirection, ZoneEntityItem::DEFAULT_KEYLIGHT_DIRECTION),
|
||||
CONSTRUCT_PROPERTY(stageSunModelEnabled, ZoneEntityItem::DEFAULT_STAGE_SUN_MODEL_ENABLED),
|
||||
CONSTRUCT_PROPERTY(stageLatitude, ZoneEntityItem::DEFAULT_STAGE_LATITUDE),
|
||||
CONSTRUCT_PROPERTY(stageLongitude, ZoneEntityItem::DEFAULT_STAGE_LONGITUDE),
|
||||
CONSTRUCT_PROPERTY(stageAltitude, ZoneEntityItem::DEFAULT_STAGE_ALTITUDE),
|
||||
CONSTRUCT_PROPERTY(stageDay, ZoneEntityItem::DEFAULT_STAGE_DAY),
|
||||
CONSTRUCT_PROPERTY(stageHour, ZoneEntityItem::DEFAULT_STAGE_HOUR),
|
||||
|
||||
_id(UNKNOWN_ENTITY_ID),
|
||||
_idSet(false),
|
||||
|
@ -165,7 +175,7 @@ void EntityItemProperties::debugDump() const {
|
|||
qCDebug(entities) << " _position=" << _position.x << "," << _position.y << "," << _position.z;
|
||||
qCDebug(entities) << " _dimensions=" << getDimensions();
|
||||
qCDebug(entities) << " _modelURL=" << _modelURL;
|
||||
qCDebug(entities) << " _collisionModelURL=" << _collisionModelURL;
|
||||
qCDebug(entities) << " _compoundShapeURL=" << _compoundShapeURL;
|
||||
qCDebug(entities) << " changed properties...";
|
||||
EntityPropertyFlags props = getChangedProperties();
|
||||
props.debugDumpBits();
|
||||
|
@ -235,7 +245,7 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_SCRIPT, script);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COLOR, color);
|
||||
CHECK_PROPERTY_CHANGE(PROP_MODEL_URL, modelURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COLLISION_MODEL_URL, collisionModelURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_COMPOUND_SHAPE_URL, compoundShapeURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_URL, animationURL);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_PLAYING, animationIsPlaying);
|
||||
CHECK_PROPERTY_CHANGE(PROP_ANIMATION_FRAME_INDEX, animationFrameIndex);
|
||||
|
@ -268,6 +278,16 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
|
|||
CHECK_PROPERTY_CHANGE(PROP_LOCAL_GRAVITY, localGravity);
|
||||
CHECK_PROPERTY_CHANGE(PROP_PARTICLE_RADIUS, particleRadius);
|
||||
CHECK_PROPERTY_CHANGE(PROP_MARKETPLACE_ID, marketplaceID);
|
||||
CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_COLOR, keyLightColor);
|
||||
CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_INTENSITY, keyLightIntensity);
|
||||
CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_AMBIENT_INTENSITY, keyLightAmbientIntensity);
|
||||
CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_DIRECTION, keyLightDirection);
|
||||
CHECK_PROPERTY_CHANGE(PROP_STAGE_SUN_MODEL_ENABLED, stageSunModelEnabled);
|
||||
CHECK_PROPERTY_CHANGE(PROP_STAGE_LATITUDE, stageLatitude);
|
||||
CHECK_PROPERTY_CHANGE(PROP_STAGE_LONGITUDE, stageLongitude);
|
||||
CHECK_PROPERTY_CHANGE(PROP_STAGE_ALTITUDE, stageAltitude);
|
||||
CHECK_PROPERTY_CHANGE(PROP_STAGE_DAY, stageDay);
|
||||
CHECK_PROPERTY_CHANGE(PROP_STAGE_HOUR, stageHour);
|
||||
|
||||
return changedProperties;
|
||||
}
|
||||
|
@ -302,7 +322,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE(visible);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR(color);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(modelURL);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(collisionModelURL);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(compoundShapeURL);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(animationURL);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(animationIsPlaying);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(animationFPS);
|
||||
|
@ -334,6 +354,17 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine) cons
|
|||
COPY_PROPERTY_TO_QSCRIPTVALUE(particleRadius);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(marketplaceID);
|
||||
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_COLOR(keyLightColor);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightIntensity);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightAmbientIntensity);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE_VEC3(keyLightDirection);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(stageSunModelEnabled);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(stageLatitude);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(stageLongitude);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(stageAltitude);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(stageDay);
|
||||
COPY_PROPERTY_TO_QSCRIPTVALUE(stageHour);
|
||||
|
||||
// Sitting properties support
|
||||
QScriptValue sittingPoints = engine->newObject();
|
||||
for (int i = 0; i < _sittingPoints.size(); ++i) {
|
||||
|
@ -386,7 +417,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(visible, setVisible);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(color, setColor);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(modelURL, setModelURL);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(collisionModelURL, setCollisionModelURL);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(compoundShapeURL, setCompoundShapeURL);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(animationURL, setAnimationURL);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(animationIsPlaying, setAnimationIsPlaying);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(animationFPS, setAnimationFPS);
|
||||
|
@ -418,6 +449,17 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
|
|||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(particleRadius, setParticleRadius);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_STRING(marketplaceID, setMarketplaceID);
|
||||
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_COLOR(keyLightColor, setKeyLightColor);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(keyLightIntensity, setKeyLightIntensity);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(keyLightAmbientIntensity, setKeyLightAmbientIntensity);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_VEC3(keyLightDirection, setKeyLightDirection);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(stageSunModelEnabled, setStageSunModelEnabled);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(stageLatitude, setStageLatitude);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(stageLongitude, setStageLongitude);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(stageAltitude, setStageAltitude);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_INT(stageDay, setStageDay);
|
||||
COPY_PROPERTY_FROM_QSCRIPTVALUE_FLOAT(stageHour, setStageHour);
|
||||
|
||||
_lastEdited = usecTimestampNow();
|
||||
}
|
||||
|
||||
|
@ -576,7 +618,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
|
|||
|
||||
if (properties.getType() == EntityTypes::Model) {
|
||||
APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, properties.getModelURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLLISION_MODEL_URL, appendValue, properties.getCollisionModelURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, properties.getCompoundShapeURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, properties.getAnimationURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, properties.getAnimationFPS());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, properties.getAnimationFrameIndex());
|
||||
|
@ -603,6 +645,22 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
|
|||
APPEND_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, appendValue, properties.getLocalGravity());
|
||||
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, appendValue, properties.getParticleRadius());
|
||||
}
|
||||
|
||||
if (properties.getType() == EntityTypes::Zone) {
|
||||
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, appendColor, properties.getKeyLightColor());
|
||||
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, appendValue, properties.getKeyLightIntensity());
|
||||
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, appendValue, properties.getKeyLightAmbientIntensity());
|
||||
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, appendValue, properties.getKeyLightDirection());
|
||||
APPEND_ENTITY_PROPERTY(PROP_STAGE_SUN_MODEL_ENABLED, appendValue, properties.getStageSunModelEnabled());
|
||||
APPEND_ENTITY_PROPERTY(PROP_STAGE_LATITUDE, appendValue, properties.getStageLatitude());
|
||||
APPEND_ENTITY_PROPERTY(PROP_STAGE_LONGITUDE, appendValue, properties.getStageLongitude());
|
||||
APPEND_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, appendValue, properties.getStageAltitude());
|
||||
APPEND_ENTITY_PROPERTY(PROP_STAGE_DAY, appendValue, properties.getStageDay());
|
||||
APPEND_ENTITY_PROPERTY(PROP_STAGE_HOUR, appendValue, properties.getStageHour());
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, appendValue, (uint32_t)properties.getShapeType());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, properties.getCompoundShapeURL());
|
||||
}
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_MARKETPLACE_ID, appendValue, properties.getMarketplaceID());
|
||||
}
|
||||
|
@ -809,7 +867,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
|
||||
if (properties.getType() == EntityTypes::Model) {
|
||||
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MODEL_URL, setModelURL);
|
||||
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_COLLISION_MODEL_URL, setCollisionModelURL);
|
||||
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL);
|
||||
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_ANIMATION_URL, setAnimationURL);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FPS, float, setAnimationFPS);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex);
|
||||
|
@ -836,6 +894,21 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
|
|||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCAL_GRAVITY, float, setLocalGravity);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_PARTICLE_RADIUS, float, setParticleRadius);
|
||||
}
|
||||
|
||||
if (properties.getType() == EntityTypes::Zone) {
|
||||
READ_ENTITY_PROPERTY_COLOR_TO_PROPERTIES(PROP_KEYLIGHT_COLOR, setKeyLightColor);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEYLIGHT_INTENSITY, float, setKeyLightIntensity);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEYLIGHT_AMBIENT_INTENSITY, float, setKeyLightAmbientIntensity);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_KEYLIGHT_DIRECTION, glm::vec3, setKeyLightDirection);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_SUN_MODEL_ENABLED, bool, setStageSunModelEnabled);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_LATITUDE, float, setStageLatitude);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_LONGITUDE, float, setStageLongitude);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_ALTITUDE, float, setStageAltitude);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_DAY, quint16, setStageDay);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_STAGE_HOUR, float, setStageHour);
|
||||
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType);
|
||||
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL);
|
||||
}
|
||||
|
||||
READ_ENTITY_PROPERTY_STRING_TO_PROPERTIES(PROP_MARKETPLACE_ID, setMarketplaceID);
|
||||
|
||||
|
@ -890,7 +963,7 @@ void EntityItemProperties::markAllChanged() {
|
|||
_visibleChanged = true;
|
||||
_colorChanged = true;
|
||||
_modelURLChanged = true;
|
||||
_collisionModelURLChanged = true;
|
||||
_compoundShapeURLChanged = true;
|
||||
_animationURLChanged = true;
|
||||
_animationIsPlayingChanged = true;
|
||||
_animationFrameIndexChanged = true;
|
||||
|
@ -923,6 +996,17 @@ void EntityItemProperties::markAllChanged() {
|
|||
_particleRadiusChanged = true;
|
||||
|
||||
_marketplaceIDChanged = true;
|
||||
|
||||
_keyLightColorChanged = true;
|
||||
_keyLightIntensityChanged = true;
|
||||
_keyLightAmbientIntensityChanged = true;
|
||||
_keyLightDirectionChanged = true;
|
||||
_stageSunModelEnabledChanged = true;
|
||||
_stageLatitudeChanged = true;
|
||||
_stageLongitudeChanged = true;
|
||||
_stageAltitudeChanged = true;
|
||||
_stageDayChanged = true;
|
||||
_stageHourChanged = true;
|
||||
}
|
||||
|
||||
/// The maximum bounding cube for the entity, independent of it's rotation.
|
||||
|
|
|
@ -93,17 +93,16 @@ enum EntityPropertyList {
|
|||
PROP_LOCAL_GRAVITY,
|
||||
PROP_PARTICLE_RADIUS,
|
||||
|
||||
PROP_COLLISION_MODEL_URL,
|
||||
PROP_COMPOUND_SHAPE_URL,
|
||||
PROP_MARKETPLACE_ID,
|
||||
PROP_ACCELERATION,
|
||||
PROP_SIMULATOR_ID,
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// ATTENTION: add new properties ABOVE this line
|
||||
PROP_AFTER_LAST_ITEM,
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// WARNING! Do not add props here unless you intentionally mean to reuse PROP_ indexes
|
||||
//
|
||||
|
@ -113,7 +112,22 @@ enum EntityPropertyList {
|
|||
PROP_TEXT = PROP_MODEL_URL,
|
||||
PROP_LINE_HEIGHT = PROP_ANIMATION_URL,
|
||||
PROP_BACKGROUND_COLOR = PROP_ANIMATION_FPS,
|
||||
PROP_COLLISION_MODEL_URL_OLD_VERSION = PROP_ANIMATION_FPS + 1
|
||||
PROP_COLLISION_MODEL_URL_OLD_VERSION = PROP_ANIMATION_FPS + 1,
|
||||
|
||||
// Aliases/Piggyback properties for Zones. These properties intentionally reuse the enum values for
|
||||
// other properties which will never overlap with each other. We do this so that we don't have to expand
|
||||
// the size of the properties bitflags mask
|
||||
PROP_KEYLIGHT_COLOR = PROP_COLOR,
|
||||
PROP_KEYLIGHT_INTENSITY = PROP_INTENSITY,
|
||||
PROP_KEYLIGHT_AMBIENT_INTENSITY = PROP_CUTOFF,
|
||||
PROP_KEYLIGHT_DIRECTION = PROP_EXPONENT,
|
||||
PROP_STAGE_SUN_MODEL_ENABLED = PROP_IS_SPOTLIGHT,
|
||||
PROP_STAGE_LATITUDE = PROP_DIFFUSE_COLOR_UNUSED,
|
||||
PROP_STAGE_LONGITUDE = PROP_AMBIENT_COLOR_UNUSED,
|
||||
PROP_STAGE_ALTITUDE = PROP_SPECULAR_COLOR_UNUSED,
|
||||
PROP_STAGE_DAY = PROP_LINEAR_ATTENUATION_UNUSED,
|
||||
PROP_STAGE_HOUR = PROP_QUADRATIC_ATTENUATION_UNUSED,
|
||||
|
||||
// WARNING!!! DO NOT ADD PROPS_xxx here unless you really really meant to.... Add them UP above
|
||||
};
|
||||
|
||||
|
@ -137,6 +151,7 @@ class EntityItemProperties {
|
|||
friend class LightEntityItem; // TODO: consider removing this friend relationship and use public methods
|
||||
friend class TextEntityItem; // TODO: consider removing this friend relationship and use public methods
|
||||
friend class ParticleEffectEntityItem; // TODO: consider removing this friend relationship and use public methods
|
||||
friend class ZoneEntityItem; // TODO: consider removing this friend relationship and use public methods
|
||||
public:
|
||||
EntityItemProperties();
|
||||
virtual ~EntityItemProperties();
|
||||
|
@ -182,7 +197,7 @@ public:
|
|||
DEFINE_PROPERTY_REF(PROP_SCRIPT, Script, script, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_COLOR, Color, color, xColor);
|
||||
DEFINE_PROPERTY_REF(PROP_MODEL_URL, ModelURL, modelURL, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_COLLISION_MODEL_URL, CollisionModelURL, collisionModelURL, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_COMPOUND_SHAPE_URL, CompoundShapeURL, compoundShapeURL, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_ANIMATION_URL, AnimationURL, animationURL, QString);
|
||||
DEFINE_PROPERTY(PROP_ANIMATION_FPS, AnimationFPS, animationFPS, float);
|
||||
DEFINE_PROPERTY(PROP_ANIMATION_FRAME_INDEX, AnimationFrameIndex, animationFrameIndex, float);
|
||||
|
@ -214,6 +229,17 @@ public:
|
|||
DEFINE_PROPERTY(PROP_LOCAL_GRAVITY, LocalGravity, localGravity, float);
|
||||
DEFINE_PROPERTY(PROP_PARTICLE_RADIUS, ParticleRadius, particleRadius, float);
|
||||
DEFINE_PROPERTY_REF(PROP_MARKETPLACE_ID, MarketplaceID, marketplaceID, QString);
|
||||
DEFINE_PROPERTY_REF(PROP_KEYLIGHT_COLOR, KeyLightColor, keyLightColor, xColor);
|
||||
DEFINE_PROPERTY(PROP_KEYLIGHT_INTENSITY, KeyLightIntensity, keyLightIntensity, float);
|
||||
DEFINE_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, KeyLightAmbientIntensity, keyLightAmbientIntensity, float);
|
||||
DEFINE_PROPERTY_REF(PROP_KEYLIGHT_DIRECTION, KeyLightDirection, keyLightDirection, glm::vec3);
|
||||
DEFINE_PROPERTY(PROP_STAGE_SUN_MODEL_ENABLED, StageSunModelEnabled, stageSunModelEnabled, bool);
|
||||
DEFINE_PROPERTY(PROP_STAGE_LATITUDE, StageLatitude, stageLatitude, float);
|
||||
DEFINE_PROPERTY(PROP_STAGE_LONGITUDE, StageLongitude, stageLongitude, float);
|
||||
DEFINE_PROPERTY(PROP_STAGE_ALTITUDE, StageAltitude, stageAltitude, float);
|
||||
DEFINE_PROPERTY(PROP_STAGE_DAY, StageDay, stageDay, quint16);
|
||||
DEFINE_PROPERTY(PROP_STAGE_HOUR, StageHour, stageHour, float);
|
||||
|
||||
|
||||
public:
|
||||
float getMaxDimension() const { return glm::max(_dimensions.x, _dimensions.y, _dimensions.z); }
|
||||
|
@ -314,7 +340,7 @@ inline QDebug operator<<(QDebug debug, const EntityItemProperties& properties) {
|
|||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Script, script, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, Color, color, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, ModelURL, modelURL, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CollisionModelURL, collisionModelURL, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, CompoundShapeURL, compoundShapeURL, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationURL, animationURL, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationFPS, animationFPS, "");
|
||||
DEBUG_PROPERTY_IF_CHANGED(debug, properties, AnimationFrameIndex, animationFrameIndex, "");
|
||||
|
|
|
@ -228,6 +228,15 @@
|
|||
} \
|
||||
}
|
||||
|
||||
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_INT(P, S) \
|
||||
QScriptValue P = object.property(#P); \
|
||||
if (P.isValid()) { \
|
||||
int newValue = P.toVariant().toInt(); \
|
||||
if (_defaultSettings || newValue != _##P) { \
|
||||
S(newValue); \
|
||||
} \
|
||||
}
|
||||
|
||||
#define COPY_PROPERTY_FROM_QSCRIPTVALUE_BOOL(P, S) \
|
||||
QScriptValue P = object.property(#P); \
|
||||
if (P.isValid()) { \
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
#include "EntityTree.h"
|
||||
#include "LightEntityItem.h"
|
||||
#include "ModelEntityItem.h"
|
||||
#include "ZoneEntityItem.h"
|
||||
|
||||
|
||||
EntityScriptingInterface::EntityScriptingInterface() :
|
||||
|
@ -306,6 +307,14 @@ bool EntityScriptingInterface::getLightsArePickable() const {
|
|||
return LightEntityItem::getLightsArePickable();
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::setZonesArePickable(bool value) {
|
||||
ZoneEntityItem::setZonesArePickable(value);
|
||||
}
|
||||
|
||||
bool EntityScriptingInterface::getZonesArePickable() const {
|
||||
return ZoneEntityItem::getZonesArePickable();
|
||||
}
|
||||
|
||||
void EntityScriptingInterface::setSendPhysicsUpdates(bool value) {
|
||||
EntityItem::setSendPhysicsUpdates(value);
|
||||
}
|
||||
|
|
|
@ -111,6 +111,9 @@ public slots:
|
|||
Q_INVOKABLE void setLightsArePickable(bool value);
|
||||
Q_INVOKABLE bool getLightsArePickable() const;
|
||||
|
||||
Q_INVOKABLE void setZonesArePickable(bool value);
|
||||
Q_INVOKABLE bool getZonesArePickable() const;
|
||||
|
||||
Q_INVOKABLE void setSendPhysicsUpdates(bool value);
|
||||
Q_INVOKABLE bool getSendPhysicsUpdates() const;
|
||||
|
||||
|
|
|
@ -21,9 +21,10 @@
|
|||
#include "BoxEntityItem.h"
|
||||
#include "LightEntityItem.h"
|
||||
#include "ModelEntityItem.h"
|
||||
#include "ParticleEffectEntityItem.h"
|
||||
#include "SphereEntityItem.h"
|
||||
#include "TextEntityItem.h"
|
||||
#include "ParticleEffectEntityItem.h"
|
||||
#include "ZoneEntityItem.h"
|
||||
|
||||
QMap<EntityTypes::EntityType, QString> EntityTypes::_typeToNameMap;
|
||||
QMap<QString, EntityTypes::EntityType> EntityTypes::_nameToTypeMap;
|
||||
|
@ -39,7 +40,7 @@ REGISTER_ENTITY_TYPE(Sphere)
|
|||
REGISTER_ENTITY_TYPE(Light)
|
||||
REGISTER_ENTITY_TYPE(Text)
|
||||
REGISTER_ENTITY_TYPE(ParticleEffect)
|
||||
|
||||
REGISTER_ENTITY_TYPE(Zone)
|
||||
|
||||
const QString& EntityTypes::getEntityTypeName(EntityType entityType) {
|
||||
QMap<EntityType, QString>::iterator matchedTypeName = _typeToNameMap.find(entityType);
|
||||
|
|
|
@ -36,7 +36,8 @@ public:
|
|||
Light,
|
||||
Text,
|
||||
ParticleEffect,
|
||||
LAST = ParticleEffect
|
||||
Zone,
|
||||
LAST = Zone
|
||||
} EntityType;
|
||||
|
||||
static const QString& getEntityTypeName(EntityType entityType);
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
#include "ModelEntityItem.h"
|
||||
|
||||
const QString ModelEntityItem::DEFAULT_MODEL_URL = QString("");
|
||||
const QString ModelEntityItem::DEFAULT_COLLISION_MODEL_URL = QString("");
|
||||
const QString ModelEntityItem::DEFAULT_COMPOUND_SHAPE_URL = QString("");
|
||||
const QString ModelEntityItem::DEFAULT_ANIMATION_URL = QString("");
|
||||
const float ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX = 0.0f;
|
||||
const bool ModelEntityItem::DEFAULT_ANIMATION_IS_PLAYING = false;
|
||||
|
@ -47,7 +47,7 @@ EntityItemProperties ModelEntityItem::getProperties() const {
|
|||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(color, getXColor);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(modelURL, getModelURL);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(collisionModelURL, getCollisionModelURL);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationURL, getAnimationURL);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationIsPlaying, getAnimationIsPlaying);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(animationFrameIndex, getAnimationFrameIndex);
|
||||
|
@ -65,7 +65,7 @@ bool ModelEntityItem::setProperties(const EntityItemProperties& properties) {
|
|||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(color, setColor);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(modelURL, setModelURL);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionModelURL, setCollisionModelURL);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationURL, setAnimationURL);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationIsPlaying, setAnimationIsPlaying);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(animationFrameIndex, setAnimationFrameIndex);
|
||||
|
@ -98,11 +98,11 @@ int ModelEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data,
|
|||
READ_ENTITY_PROPERTY_COLOR(PROP_COLOR, _color);
|
||||
READ_ENTITY_PROPERTY_STRING(PROP_MODEL_URL, setModelURL);
|
||||
if (args.bitstreamVersion < VERSION_ENTITIES_HAS_COLLISION_MODEL) {
|
||||
setCollisionModelURL("");
|
||||
setCompoundShapeURL("");
|
||||
} else if (args.bitstreamVersion == VERSION_ENTITIES_HAS_COLLISION_MODEL) {
|
||||
READ_ENTITY_PROPERTY_STRING(PROP_COLLISION_MODEL_URL_OLD_VERSION, setCollisionModelURL);
|
||||
READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL);
|
||||
} else {
|
||||
READ_ENTITY_PROPERTY_STRING(PROP_COLLISION_MODEL_URL, setCollisionModelURL);
|
||||
READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL);
|
||||
}
|
||||
READ_ENTITY_PROPERTY_STRING(PROP_ANIMATION_URL, setAnimationURL);
|
||||
|
||||
|
@ -140,7 +140,7 @@ EntityPropertyFlags ModelEntityItem::getEntityProperties(EncodeBitstreamParams&
|
|||
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
|
||||
|
||||
requestedProperties += PROP_MODEL_URL;
|
||||
requestedProperties += PROP_COLLISION_MODEL_URL;
|
||||
requestedProperties += PROP_COMPOUND_SHAPE_URL;
|
||||
requestedProperties += PROP_ANIMATION_URL;
|
||||
requestedProperties += PROP_ANIMATION_FPS;
|
||||
requestedProperties += PROP_ANIMATION_FRAME_INDEX;
|
||||
|
@ -164,7 +164,7 @@ void ModelEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBit
|
|||
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLOR, appendColor, getColor());
|
||||
APPEND_ENTITY_PROPERTY(PROP_MODEL_URL, appendValue, getModelURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COLLISION_MODEL_URL, appendValue, getCollisionModelURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, getCompoundShapeURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_URL, appendValue, getAnimationURL());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, appendValue, getAnimationFPS());
|
||||
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, appendValue, getAnimationFrameIndex());
|
||||
|
@ -272,7 +272,7 @@ void ModelEntityItem::debugDump() const {
|
|||
qCDebug(entities) << " position:" << getPosition();
|
||||
qCDebug(entities) << " dimensions:" << getDimensions();
|
||||
qCDebug(entities) << " model URL:" << getModelURL();
|
||||
qCDebug(entities) << " collision model URL:" << getCollisionModelURL();
|
||||
qCDebug(entities) << " compound shape URL:" << getCompoundShapeURL();
|
||||
}
|
||||
|
||||
void ModelEntityItem::updateShapeType(ShapeType type) {
|
||||
|
@ -280,8 +280,8 @@ void ModelEntityItem::updateShapeType(ShapeType type) {
|
|||
// we have allowed inconsistent ShapeType's to be stored in SVO files in the past (this was a bug)
|
||||
// but we are now enforcing the entity properties to be consistent. To make the possible we're
|
||||
// introducing a temporary workaround: we will ignore ShapeType updates that conflict with the
|
||||
// _collisionModelURL.
|
||||
if (hasCollisionModel()) {
|
||||
// _compoundShapeURL.
|
||||
if (hasCompoundShapeURL()) {
|
||||
type = SHAPE_TYPE_COMPOUND;
|
||||
}
|
||||
// END_TEMPORARY_WORKAROUND
|
||||
|
@ -295,17 +295,17 @@ void ModelEntityItem::updateShapeType(ShapeType type) {
|
|||
// virtual
|
||||
ShapeType ModelEntityItem::getShapeType() const {
|
||||
if (_shapeType == SHAPE_TYPE_COMPOUND) {
|
||||
return hasCollisionModel() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE;
|
||||
return hasCompoundShapeURL() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE;
|
||||
} else {
|
||||
return _shapeType;
|
||||
}
|
||||
}
|
||||
|
||||
void ModelEntityItem::setCollisionModelURL(const QString& url) {
|
||||
if (_collisionModelURL != url) {
|
||||
_collisionModelURL = url;
|
||||
void ModelEntityItem::setCompoundShapeURL(const QString& url) {
|
||||
if (_compoundShapeURL != url) {
|
||||
_compoundShapeURL = url;
|
||||
_dirtyFlags |= EntityItem::DIRTY_SHAPE | EntityItem::DIRTY_MASS;
|
||||
_shapeType = _collisionModelURL.isEmpty() ? SHAPE_TYPE_NONE : SHAPE_TYPE_COMPOUND;
|
||||
_shapeType = _compoundShapeURL.isEmpty() ? SHAPE_TYPE_NONE : SHAPE_TYPE_COMPOUND;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -57,13 +57,13 @@ public:
|
|||
const rgbColor& getColor() const { return _color; }
|
||||
xColor getXColor() const { xColor color = { _color[RED_INDEX], _color[GREEN_INDEX], _color[BLUE_INDEX] }; return color; }
|
||||
bool hasModel() const { return !_modelURL.isEmpty(); }
|
||||
virtual bool hasCollisionModel() const { return !_collisionModelURL.isEmpty(); }
|
||||
virtual bool hasCompoundShapeURL() const { return !_compoundShapeURL.isEmpty(); }
|
||||
|
||||
static const QString DEFAULT_MODEL_URL;
|
||||
const QString& getModelURL() const { return _modelURL; }
|
||||
|
||||
static const QString DEFAULT_COLLISION_MODEL_URL;
|
||||
const QString& getCollisionModelURL() const { return _collisionModelURL; }
|
||||
static const QString DEFAULT_COMPOUND_SHAPE_URL;
|
||||
const QString& getCompoundShapeURL() const { return _compoundShapeURL; }
|
||||
|
||||
bool hasAnimation() const { return !_animationURL.isEmpty(); }
|
||||
static const QString DEFAULT_ANIMATION_URL;
|
||||
|
@ -78,7 +78,7 @@ public:
|
|||
|
||||
// model related properties
|
||||
void setModelURL(const QString& url) { _modelURL = url; }
|
||||
virtual void setCollisionModelURL(const QString& url);
|
||||
virtual void setCompoundShapeURL(const QString& url);
|
||||
void setAnimationURL(const QString& url);
|
||||
static const float DEFAULT_ANIMATION_FRAME_INDEX;
|
||||
void setAnimationFrameIndex(float value);
|
||||
|
@ -126,7 +126,7 @@ protected:
|
|||
|
||||
rgbColor _color;
|
||||
QString _modelURL;
|
||||
QString _collisionModelURL;
|
||||
QString _compoundShapeURL;
|
||||
|
||||
quint64 _lastAnimated;
|
||||
QString _animationURL;
|
||||
|
|
|
@ -96,11 +96,7 @@ bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, cons
|
|||
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking) const {
|
||||
// determine the ray in the frame of the entity transformed from a unit sphere
|
||||
glm::mat4 translation = glm::translate(getPosition());
|
||||
glm::mat4 rotation = glm::mat4_cast(getRotation());
|
||||
glm::mat4 scale = glm::scale(getDimensions());
|
||||
glm::mat4 registration = glm::translate(glm::vec3(0.5f, 0.5f, 0.5f) - getRegistrationPoint());
|
||||
glm::mat4 entityToWorldMatrix = translation * rotation * scale * registration;
|
||||
glm::mat4 entityToWorldMatrix = getEntityToWorldMatrix();
|
||||
glm::mat4 worldToEntityMatrix = glm::inverse(entityToWorldMatrix);
|
||||
glm::vec3 entityFrameOrigin = glm::vec3(worldToEntityMatrix * glm::vec4(origin, 1.0f));
|
||||
glm::vec3 entityFrameDirection = glm::normalize(glm::vec3(worldToEntityMatrix * glm::vec4(direction, 0.0f)));
|
||||
|
@ -112,7 +108,7 @@ bool SphereEntityItem::findDetailedRayIntersection(const glm::vec3& origin, cons
|
|||
glm::vec3 entityFrameHitAt = entityFrameOrigin + (entityFrameDirection * localDistance);
|
||||
// then translate back to work coordinates
|
||||
glm::vec3 hitAt = glm::vec3(entityToWorldMatrix * glm::vec4(entityFrameHitAt, 1.0f));
|
||||
distance = glm::distance(origin,hitAt);
|
||||
distance = glm::distance(origin, hitAt);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
|
|
|
@ -50,9 +50,6 @@ public:
|
|||
_color[BLUE_INDEX] = value.blue;
|
||||
}
|
||||
|
||||
// TODO: implement proper contains for 3D ellipsoid
|
||||
//virtual bool contains(const glm::vec3& point) const;
|
||||
|
||||
virtual ShapeType getShapeType() const { return SHAPE_TYPE_SPHERE; }
|
||||
|
||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||
|
|
|
@ -48,11 +48,6 @@ void TextEntityItem::setDimensions(const glm::vec3& value) {
|
|||
_dimensions = glm::vec3(value.x, value.y, TEXT_ENTITY_ITEM_FIXED_DEPTH);
|
||||
}
|
||||
|
||||
void TextEntityItem::setDimensionsInDomainUnits(const glm::vec3& value) {
|
||||
// NOTE: Text Entities always have a "depth" of 1cm.
|
||||
_dimensions = glm::vec3(value.x * (float)TREE_SCALE, value.y * (float)TREE_SCALE, TEXT_ENTITY_ITEM_FIXED_DEPTH);
|
||||
}
|
||||
|
||||
EntityItemProperties TextEntityItem::getProperties() const {
|
||||
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
|
||||
|
||||
|
|
|
@ -24,7 +24,6 @@ public:
|
|||
|
||||
/// set dimensions in domain scale units (0.0 - 1.0) this will also reset radius appropriately
|
||||
virtual void setDimensions(const glm::vec3& value);
|
||||
virtual void setDimensionsInDomainUnits(const glm::vec3& value);
|
||||
virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; }
|
||||
|
||||
// methods for getting/setting all properties of an entity
|
||||
|
|
224
libraries/entities/src/ZoneEntityItem.cpp
Normal file
224
libraries/entities/src/ZoneEntityItem.cpp
Normal file
|
@ -0,0 +1,224 @@
|
|||
//
|
||||
// ZoneEntityItem.cpp
|
||||
// libraries/entities/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/4/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <ByteCountCoding.h>
|
||||
|
||||
#include "ZoneEntityItem.h"
|
||||
#include "EntityTree.h"
|
||||
#include "EntitiesLogging.h"
|
||||
#include "EntityTreeElement.h"
|
||||
|
||||
bool ZoneEntityItem::_zonesArePickable = false;
|
||||
|
||||
const xColor ZoneEntityItem::DEFAULT_KEYLIGHT_COLOR = { 255, 255, 255 };
|
||||
const float ZoneEntityItem::DEFAULT_KEYLIGHT_INTENSITY = 1.0f;
|
||||
const float ZoneEntityItem::DEFAULT_KEYLIGHT_AMBIENT_INTENSITY = 0.5f;
|
||||
const glm::vec3 ZoneEntityItem::DEFAULT_KEYLIGHT_DIRECTION = { 0.0f, -1.0f, 0.0f };
|
||||
const bool ZoneEntityItem::DEFAULT_STAGE_SUN_MODEL_ENABLED = false;
|
||||
const float ZoneEntityItem::DEFAULT_STAGE_LATITUDE = 37.777f;
|
||||
const float ZoneEntityItem::DEFAULT_STAGE_LONGITUDE = 122.407f;
|
||||
const float ZoneEntityItem::DEFAULT_STAGE_ALTITUDE = 0.03f;
|
||||
const quint16 ZoneEntityItem::DEFAULT_STAGE_DAY = 60;
|
||||
const float ZoneEntityItem::DEFAULT_STAGE_HOUR = 12.0f;
|
||||
const ShapeType ZoneEntityItem::DEFAULT_SHAPE_TYPE = SHAPE_TYPE_BOX;
|
||||
const QString ZoneEntityItem::DEFAULT_COMPOUND_SHAPE_URL = "";
|
||||
|
||||
EntityItem* ZoneEntityItem::factory(const EntityItemID& entityID, const EntityItemProperties& properties) {
|
||||
EntityItem* result = new ZoneEntityItem(entityID, properties);
|
||||
return result;
|
||||
}
|
||||
|
||||
ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) :
|
||||
EntityItem(entityItemID)
|
||||
{
|
||||
_type = EntityTypes::Zone;
|
||||
_created = properties.getCreated();
|
||||
|
||||
_keyLightColor[RED_INDEX] = DEFAULT_KEYLIGHT_COLOR.red;
|
||||
_keyLightColor[GREEN_INDEX] = DEFAULT_KEYLIGHT_COLOR.green;
|
||||
_keyLightColor[BLUE_INDEX] = DEFAULT_KEYLIGHT_COLOR.blue;
|
||||
|
||||
_keyLightIntensity = DEFAULT_KEYLIGHT_INTENSITY;
|
||||
_keyLightAmbientIntensity = DEFAULT_KEYLIGHT_AMBIENT_INTENSITY;
|
||||
_keyLightDirection = DEFAULT_KEYLIGHT_DIRECTION;
|
||||
_stageSunModelEnabled = DEFAULT_STAGE_SUN_MODEL_ENABLED;
|
||||
_stageLatitude = DEFAULT_STAGE_LATITUDE;
|
||||
_stageLongitude = DEFAULT_STAGE_LONGITUDE;
|
||||
_stageAltitude = DEFAULT_STAGE_ALTITUDE;
|
||||
_stageDay = DEFAULT_STAGE_DAY;
|
||||
_stageHour = DEFAULT_STAGE_HOUR;
|
||||
_shapeType = DEFAULT_SHAPE_TYPE;
|
||||
_compoundShapeURL = DEFAULT_COMPOUND_SHAPE_URL;
|
||||
|
||||
setProperties(properties);
|
||||
}
|
||||
|
||||
EntityItemProperties ZoneEntityItem::getProperties() const {
|
||||
EntityItemProperties properties = EntityItem::getProperties(); // get the properties from our base class
|
||||
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightColor, getKeyLightColor);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightIntensity, getKeyLightIntensity);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightAmbientIntensity, getKeyLightAmbientIntensity);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(keyLightDirection, getKeyLightDirection);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageSunModelEnabled, getStageSunModelEnabled);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageLatitude, getStageLatitude);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageLongitude, getStageLongitude);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageAltitude, getStageAltitude);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageDay, getStageDay);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(stageHour, getStageHour);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(shapeType, getShapeType);
|
||||
COPY_ENTITY_PROPERTY_TO_PROPERTIES(compoundShapeURL, getCompoundShapeURL);
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
bool ZoneEntityItem::setProperties(const EntityItemProperties& properties) {
|
||||
bool somethingChanged = false;
|
||||
somethingChanged = EntityItem::setProperties(properties); // set the properties in our base class
|
||||
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(keyLightColor, setKeyLightColor);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(keyLightIntensity, setKeyLightIntensity);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(keyLightAmbientIntensity, setKeyLightAmbientIntensity);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(keyLightDirection, setKeyLightDirection);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageSunModelEnabled, setStageSunModelEnabled);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageLatitude, setStageLatitude);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageLongitude, setStageLongitude);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageAltitude, setStageAltitude);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageDay, setStageDay);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(stageHour, setStageHour);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(shapeType, updateShapeType);
|
||||
SET_ENTITY_PROPERTY_FROM_PROPERTIES(compoundShapeURL, setCompoundShapeURL);
|
||||
|
||||
if (somethingChanged) {
|
||||
bool wantDebug = false;
|
||||
if (wantDebug) {
|
||||
uint64_t now = usecTimestampNow();
|
||||
int elapsed = now - getLastEdited();
|
||||
qCDebug(entities) << "ZoneEntityItem::setProperties() AFTER update... edited AGO=" << elapsed <<
|
||||
"now=" << now << " getLastEdited()=" << getLastEdited();
|
||||
}
|
||||
setLastEdited(properties._lastEdited);
|
||||
}
|
||||
return somethingChanged;
|
||||
}
|
||||
|
||||
int ZoneEntityItem::readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||
ReadBitstreamToTreeParams& args,
|
||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData) {
|
||||
|
||||
int bytesRead = 0;
|
||||
const unsigned char* dataAt = data;
|
||||
|
||||
READ_ENTITY_PROPERTY_COLOR(PROP_KEYLIGHT_COLOR, _keyLightColor);
|
||||
READ_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, float, _keyLightIntensity);
|
||||
READ_ENTITY_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, float, _keyLightAmbientIntensity);
|
||||
READ_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, glm::vec3, _keyLightDirection);
|
||||
READ_ENTITY_PROPERTY(PROP_STAGE_SUN_MODEL_ENABLED, bool, _stageSunModelEnabled);
|
||||
READ_ENTITY_PROPERTY(PROP_STAGE_LATITUDE, float, _stageLatitude);
|
||||
READ_ENTITY_PROPERTY(PROP_STAGE_LONGITUDE, float, _stageLongitude);
|
||||
READ_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, float, _stageAltitude);
|
||||
READ_ENTITY_PROPERTY(PROP_STAGE_DAY, quint16, _stageDay);
|
||||
READ_ENTITY_PROPERTY(PROP_STAGE_HOUR, float, _stageHour);
|
||||
READ_ENTITY_PROPERTY_SETTER(PROP_SHAPE_TYPE, ShapeType, updateShapeType);
|
||||
READ_ENTITY_PROPERTY_STRING(PROP_COMPOUND_SHAPE_URL, setCompoundShapeURL);
|
||||
|
||||
return bytesRead;
|
||||
}
|
||||
|
||||
|
||||
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time
|
||||
EntityPropertyFlags ZoneEntityItem::getEntityProperties(EncodeBitstreamParams& params) const {
|
||||
EntityPropertyFlags requestedProperties = EntityItem::getEntityProperties(params);
|
||||
|
||||
requestedProperties += PROP_KEYLIGHT_COLOR;
|
||||
requestedProperties += PROP_KEYLIGHT_INTENSITY;
|
||||
requestedProperties += PROP_KEYLIGHT_AMBIENT_INTENSITY;
|
||||
requestedProperties += PROP_KEYLIGHT_DIRECTION;
|
||||
requestedProperties += PROP_STAGE_SUN_MODEL_ENABLED;
|
||||
requestedProperties += PROP_STAGE_LATITUDE;
|
||||
requestedProperties += PROP_STAGE_LONGITUDE;
|
||||
requestedProperties += PROP_STAGE_ALTITUDE;
|
||||
requestedProperties += PROP_STAGE_DAY;
|
||||
requestedProperties += PROP_STAGE_HOUR;
|
||||
requestedProperties += PROP_SHAPE_TYPE;
|
||||
requestedProperties += PROP_COMPOUND_SHAPE_URL;
|
||||
|
||||
return requestedProperties;
|
||||
}
|
||||
|
||||
void ZoneEntityItem::appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
|
||||
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
|
||||
EntityPropertyFlags& requestedProperties,
|
||||
EntityPropertyFlags& propertyFlags,
|
||||
EntityPropertyFlags& propertiesDidntFit,
|
||||
int& propertyCount,
|
||||
OctreeElement::AppendState& appendState) const {
|
||||
|
||||
bool successPropertyFits = true;
|
||||
|
||||
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, appendColor, _keyLightColor);
|
||||
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, appendValue, getKeyLightIntensity());
|
||||
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, appendValue, getKeyLightAmbientIntensity());
|
||||
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, appendValue, getKeyLightDirection());
|
||||
APPEND_ENTITY_PROPERTY(PROP_STAGE_SUN_MODEL_ENABLED, appendValue, getStageSunModelEnabled());
|
||||
APPEND_ENTITY_PROPERTY(PROP_STAGE_LATITUDE, appendValue, getStageLatitude());
|
||||
APPEND_ENTITY_PROPERTY(PROP_STAGE_LONGITUDE, appendValue, getStageLongitude());
|
||||
APPEND_ENTITY_PROPERTY(PROP_STAGE_ALTITUDE, appendValue, getStageAltitude());
|
||||
APPEND_ENTITY_PROPERTY(PROP_STAGE_DAY, appendValue, getStageDay());
|
||||
APPEND_ENTITY_PROPERTY(PROP_STAGE_HOUR, appendValue, getStageHour());
|
||||
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, appendValue, (uint32_t)getShapeType());
|
||||
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, appendValue, getCompoundShapeURL());
|
||||
}
|
||||
|
||||
void ZoneEntityItem::debugDump() const {
|
||||
quint64 now = usecTimestampNow();
|
||||
qCDebug(entities) << " ZoneEntityItem id:" << getEntityItemID() << "---------------------------------------------";
|
||||
qCDebug(entities) << " keyLightColor:" << _keyLightColor[0] << "," << _keyLightColor[1] << "," << _keyLightColor[2];
|
||||
qCDebug(entities) << " position:" << debugTreeVector(_position);
|
||||
qCDebug(entities) << " dimensions:" << debugTreeVector(_dimensions);
|
||||
qCDebug(entities) << " getLastEdited:" << debugTime(getLastEdited(), now);
|
||||
qCDebug(entities) << " _keyLightIntensity:" << _keyLightIntensity;
|
||||
qCDebug(entities) << " _keyLightAmbientIntensity:" << _keyLightAmbientIntensity;
|
||||
qCDebug(entities) << " _keyLightDirection:" << _keyLightDirection;
|
||||
qCDebug(entities) << " _stageSunModelEnabled:" << _stageSunModelEnabled;
|
||||
qCDebug(entities) << " _stageLatitude:" << _stageLatitude;
|
||||
qCDebug(entities) << " _stageLongitude:" << _stageLongitude;
|
||||
qCDebug(entities) << " _stageAltitude:" << _stageAltitude;
|
||||
qCDebug(entities) << " _stageDay:" << _stageDay;
|
||||
qCDebug(entities) << " _stageHour:" << _stageHour;
|
||||
}
|
||||
|
||||
ShapeType ZoneEntityItem::getShapeType() const {
|
||||
if (_shapeType == SHAPE_TYPE_COMPOUND) {
|
||||
return hasCompoundShapeURL() ? SHAPE_TYPE_COMPOUND : SHAPE_TYPE_NONE;
|
||||
} else {
|
||||
return _shapeType;
|
||||
}
|
||||
}
|
||||
|
||||
void ZoneEntityItem::setCompoundShapeURL(const QString& url) {
|
||||
_compoundShapeURL = url;
|
||||
if (!_compoundShapeURL.isEmpty()) {
|
||||
updateShapeType(SHAPE_TYPE_COMPOUND);
|
||||
} else if (_shapeType == SHAPE_TYPE_COMPOUND) {
|
||||
_shapeType = DEFAULT_SHAPE_TYPE;
|
||||
}
|
||||
}
|
||||
|
||||
bool ZoneEntityItem::findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking) const {
|
||||
|
||||
return _zonesArePickable;
|
||||
}
|
142
libraries/entities/src/ZoneEntityItem.h
Normal file
142
libraries/entities/src/ZoneEntityItem.h
Normal file
|
@ -0,0 +1,142 @@
|
|||
//
|
||||
// ZoneEntityItem.h
|
||||
// libraries/entities/src
|
||||
//
|
||||
// Created by Brad Hefta-Gaub on 12/4/13.
|
||||
// Copyright 2013 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#ifndef hifi_ZoneEntityItem_h
|
||||
#define hifi_ZoneEntityItem_h
|
||||
|
||||
#include "EntityItem.h"
|
||||
|
||||
class ZoneEntityItem : public EntityItem {
|
||||
public:
|
||||
static EntityItem* factory(const EntityItemID& entityID, const EntityItemProperties& properties);
|
||||
|
||||
ZoneEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties);
|
||||
|
||||
ALLOW_INSTANTIATION // This class can be instantiated
|
||||
|
||||
// methods for getting/setting all properties of an entity
|
||||
virtual EntityItemProperties getProperties() const;
|
||||
virtual bool setProperties(const EntityItemProperties& properties);
|
||||
|
||||
// TODO: eventually only include properties changed since the params.lastViewFrustumSent time
|
||||
virtual EntityPropertyFlags getEntityProperties(EncodeBitstreamParams& params) const;
|
||||
|
||||
virtual void appendSubclassData(OctreePacketData* packetData, EncodeBitstreamParams& params,
|
||||
EntityTreeElementExtraEncodeData* modelTreeElementExtraEncodeData,
|
||||
EntityPropertyFlags& requestedProperties,
|
||||
EntityPropertyFlags& propertyFlags,
|
||||
EntityPropertyFlags& propertiesDidntFit,
|
||||
int& propertyCount,
|
||||
OctreeElement::AppendState& appendState) const;
|
||||
|
||||
virtual int readEntitySubclassDataFromBuffer(const unsigned char* data, int bytesLeftToRead,
|
||||
ReadBitstreamToTreeParams& args,
|
||||
EntityPropertyFlags& propertyFlags, bool overwriteLocalData);
|
||||
|
||||
// NOTE: Apparently if you begin to return a shape type, then the physics system will prevent an avatar
|
||||
// from penetrating the walls of the entity. This fact will likely be important to Clement as he works
|
||||
// on better defining the shape/volume of a zone.
|
||||
//virtual ShapeType getShapeType() const { return SHAPE_TYPE_BOX; }
|
||||
|
||||
xColor getKeyLightColor() const { xColor color = { _keyLightColor[RED_INDEX], _keyLightColor[GREEN_INDEX], _keyLightColor[BLUE_INDEX] }; return color; }
|
||||
void setKeyLightColor(const xColor& value) {
|
||||
_keyLightColor[RED_INDEX] = value.red;
|
||||
_keyLightColor[GREEN_INDEX] = value.green;
|
||||
_keyLightColor[BLUE_INDEX] = value.blue;
|
||||
}
|
||||
|
||||
glm::vec3 getKeyLightColorVec3() const {
|
||||
const quint8 MAX_COLOR = 255;
|
||||
glm::vec3 color = { _keyLightColor[RED_INDEX] / MAX_COLOR,
|
||||
_keyLightColor[GREEN_INDEX] / MAX_COLOR,
|
||||
_keyLightColor[BLUE_INDEX] / MAX_COLOR };
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
float getKeyLightIntensity() const { return _keyLightIntensity; }
|
||||
void setKeyLightIntensity(float value) { _keyLightIntensity = value; }
|
||||
|
||||
float getKeyLightAmbientIntensity() const { return _keyLightAmbientIntensity; }
|
||||
void setKeyLightAmbientIntensity(float value) { _keyLightAmbientIntensity = value; }
|
||||
|
||||
const glm::vec3& getKeyLightDirection() const { return _keyLightDirection; }
|
||||
void setKeyLightDirection(const glm::vec3& value) { _keyLightDirection = value; }
|
||||
|
||||
bool getStageSunModelEnabled() const { return _stageSunModelEnabled; }
|
||||
void setStageSunModelEnabled(bool value) { _stageSunModelEnabled = value; }
|
||||
|
||||
float getStageLatitude() const { return _stageLatitude; }
|
||||
void setStageLatitude(float value) { _stageLatitude = value; }
|
||||
|
||||
float getStageLongitude() const { return _stageLongitude; }
|
||||
void setStageLongitude(float value) { _stageLongitude = value; }
|
||||
|
||||
float getStageAltitude() const { return _stageAltitude; }
|
||||
void setStageAltitude(float value) { _stageAltitude = value; }
|
||||
|
||||
uint16_t getStageDay() const { return _stageDay; }
|
||||
void setStageDay(uint16_t value) { _stageDay = value; }
|
||||
|
||||
float getStageHour() const { return _stageHour; }
|
||||
void setStageHour(float value) { _stageHour = value; }
|
||||
|
||||
static bool getZonesArePickable() { return _zonesArePickable; }
|
||||
static void setZonesArePickable(bool value) { _zonesArePickable = value; }
|
||||
|
||||
virtual bool isReadyToComputeShape() { return false; }
|
||||
void updateShapeType(ShapeType type) { _shapeType = type; }
|
||||
virtual ShapeType getShapeType() const;
|
||||
|
||||
virtual bool hasCompoundShapeURL() const { return !_compoundShapeURL.isEmpty(); }
|
||||
const QString getCompoundShapeURL() const { return _compoundShapeURL; }
|
||||
virtual void setCompoundShapeURL(const QString& url);
|
||||
|
||||
virtual bool supportsDetailedRayIntersection() const { return true; }
|
||||
virtual bool findDetailedRayIntersection(const glm::vec3& origin, const glm::vec3& direction,
|
||||
bool& keepSearching, OctreeElement*& element, float& distance, BoxFace& face,
|
||||
void** intersectedObject, bool precisionPicking) const;
|
||||
|
||||
virtual void debugDump() const;
|
||||
|
||||
static const xColor DEFAULT_KEYLIGHT_COLOR;
|
||||
static const float DEFAULT_KEYLIGHT_INTENSITY;
|
||||
static const float DEFAULT_KEYLIGHT_AMBIENT_INTENSITY;
|
||||
static const glm::vec3 DEFAULT_KEYLIGHT_DIRECTION;
|
||||
static const bool DEFAULT_STAGE_SUN_MODEL_ENABLED;
|
||||
static const float DEFAULT_STAGE_LATITUDE;
|
||||
static const float DEFAULT_STAGE_LONGITUDE;
|
||||
static const float DEFAULT_STAGE_ALTITUDE;
|
||||
static const quint16 DEFAULT_STAGE_DAY;
|
||||
static const float DEFAULT_STAGE_HOUR;
|
||||
static const ShapeType DEFAULT_SHAPE_TYPE;
|
||||
static const QString DEFAULT_COMPOUND_SHAPE_URL;
|
||||
|
||||
protected:
|
||||
// properties of the "sun" in the zone
|
||||
rgbColor _keyLightColor;
|
||||
float _keyLightIntensity;
|
||||
float _keyLightAmbientIntensity;
|
||||
glm::vec3 _keyLightDirection;
|
||||
bool _stageSunModelEnabled;
|
||||
float _stageLatitude;
|
||||
float _stageLongitude;
|
||||
float _stageAltitude;
|
||||
uint16_t _stageDay;
|
||||
float _stageHour;
|
||||
|
||||
ShapeType _shapeType = SHAPE_TYPE_NONE;
|
||||
QString _compoundShapeURL;
|
||||
|
||||
static bool _zonesArePickable;
|
||||
};
|
||||
|
||||
#endif // hifi_ZoneEntityItem_h
|
|
@ -125,6 +125,51 @@ Extents FBXGeometry::getUnscaledMeshExtents() const {
|
|||
return scaledExtents;
|
||||
}
|
||||
|
||||
// TODO: Move to model::Mesh when Sam's ready
|
||||
bool FBXGeometry::convexHullContains(const glm::vec3& point) const {
|
||||
if (!getUnscaledMeshExtents().containsPoint(point)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
auto checkEachPrimitive = [=](FBXMesh& mesh, QVector<int> indices, int primitiveSize) -> bool {
|
||||
// Check whether the point is "behind" all the primitives.
|
||||
for (unsigned int j = 0; j < indices.size(); j += primitiveSize) {
|
||||
if (!isPointBehindTrianglesPlane(point,
|
||||
mesh.vertices[indices[j]],
|
||||
mesh.vertices[indices[j + 1]],
|
||||
mesh.vertices[indices[j + 2]])) {
|
||||
// it's not behind at least one so we bail
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
// Check that the point is contained in at least one convex mesh.
|
||||
for (auto mesh : meshes) {
|
||||
bool insideMesh = true;
|
||||
|
||||
// To be considered inside a convex mesh,
|
||||
// the point needs to be "behind" all the primitives respective planes.
|
||||
for (auto part : mesh.parts) {
|
||||
// run through all the triangles and quads
|
||||
if (!checkEachPrimitive(mesh, part.triangleIndices, 3) ||
|
||||
!checkEachPrimitive(mesh, part.quadIndices, 4)) {
|
||||
// If not, the point is outside, bail for this mesh
|
||||
insideMesh = false;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (insideMesh) {
|
||||
// It's inside this mesh, return true.
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// It wasn't in any mesh, return false.
|
||||
return false;
|
||||
}
|
||||
|
||||
QString FBXGeometry::getModelNameOfMesh(int meshIndex) const {
|
||||
if (meshIndicesToModelNames.contains(meshIndex)) {
|
||||
return meshIndicesToModelNames.value(meshIndex);
|
||||
|
@ -132,8 +177,6 @@ QString FBXGeometry::getModelNameOfMesh(int meshIndex) const {
|
|||
return QString();
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int fbxGeometryMetaTypeId = qRegisterMetaType<FBXGeometry>();
|
||||
static int fbxAnimationFrameMetaTypeId = qRegisterMetaType<FBXAnimationFrame>();
|
||||
static int fbxAnimationFrameVectorMetaTypeId = qRegisterMetaType<QVector<FBXAnimationFrame> >();
|
||||
|
|
|
@ -252,6 +252,7 @@ public:
|
|||
/// Returns the unscaled extents of the model's mesh
|
||||
Extents getUnscaledMeshExtents() const;
|
||||
|
||||
bool convexHullContains(const glm::vec3& point) const;
|
||||
|
||||
QHash<int, QString> meshIndicesToModelNames;
|
||||
|
||||
|
|
|
@ -74,7 +74,7 @@ PacketVersion versionForPacketType(PacketType type) {
|
|||
return 1;
|
||||
case PacketTypeEntityAddOrEdit:
|
||||
case PacketTypeEntityData:
|
||||
return VERSION_ENTITIES_HAVE_UUIDS;
|
||||
return VERSION_ENTITIES_ZONE_ENTITIES_HAVE_DYNAMIC_SHAPE;
|
||||
case PacketTypeEntityErase:
|
||||
return 2;
|
||||
case PacketTypeAudioStreamStats:
|
||||
|
|
|
@ -119,6 +119,7 @@ PacketType packetTypeForPacket(const char* packet);
|
|||
int arithmeticCodingValueFromBuffer(const char* checkValue);
|
||||
int numBytesArithmeticCodingFromBuffer(const char* checkValue);
|
||||
|
||||
const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1;
|
||||
const PacketVersion VERSION_ENTITIES_HAVE_ANIMATION = 1;
|
||||
const PacketVersion VERSION_ROOT_ELEMENT_HAS_DATA = 2;
|
||||
const PacketVersion VERSION_ENTITIES_SUPPORT_SPLIT_MTU = 3;
|
||||
|
@ -136,6 +137,7 @@ const PacketVersion VERSION_ENTITIES_HAS_MARKETPLACE_ID_DAMAGED = 13;
|
|||
const PacketVersion VERSION_ENTITIES_HAS_MARKETPLACE_ID = 14;
|
||||
const PacketVersion VERSION_ENTITIES_HAVE_ACCELERATION = 15;
|
||||
const PacketVersion VERSION_ENTITIES_HAVE_UUIDS = 16;
|
||||
const PacketVersion VERSION_OCTREE_HAS_FILE_BREAKS = 1;
|
||||
const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_EXIST = 17;
|
||||
const PacketVersion VERSION_ENTITIES_ZONE_ENTITIES_HAVE_DYNAMIC_SHAPE = 18;
|
||||
|
||||
#endif // hifi_PacketHeaders_h
|
||||
|
|
|
@ -6,7 +6,7 @@ AUTOSCRIBE_SHADER_LIB(gpu model)
|
|||
qt5_add_resources(QT_RESOURCES_FILE "${CMAKE_CURRENT_SOURCE_DIR}/res/fonts/fonts.qrc")
|
||||
|
||||
# use setup_hifi_library macro to setup our project and link appropriate Qt modules
|
||||
setup_hifi_library(Widgets OpenGL Network Script)
|
||||
setup_hifi_library(Widgets OpenGL Network Qml Quick Script)
|
||||
|
||||
add_dependency_external_projects(glm)
|
||||
find_package(GLM REQUIRED)
|
||||
|
|
98
libraries/render-utils/src/FboCache.cpp
Normal file
98
libraries/render-utils/src/FboCache.cpp
Normal file
|
@ -0,0 +1,98 @@
|
|||
//
|
||||
// OffscreenGlCanvas.cpp
|
||||
// interface/src/renderer
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2014/04/09.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
#include "FboCache.h"
|
||||
|
||||
#include <QOpenGLFramebufferObject>
|
||||
#include <QDebug>
|
||||
#include "ThreadHelpers.h"
|
||||
|
||||
FboCache::FboCache() {
|
||||
// Why do we even HAVE that lever?
|
||||
}
|
||||
|
||||
void FboCache::lockTexture(int texture) {
|
||||
withLock(_lock, [&] {
|
||||
Q_ASSERT(_fboMap.count(texture));
|
||||
if (!_fboLocks.count(texture)) {
|
||||
Q_ASSERT(_readyFboQueue.front()->texture() == texture);
|
||||
_readyFboQueue.pop_front();
|
||||
_fboLocks[texture] = 1;
|
||||
} else {
|
||||
_fboLocks[texture]++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void FboCache::releaseTexture(int texture) {
|
||||
withLock(_lock, [&] {
|
||||
Q_ASSERT(_fboMap.count(texture));
|
||||
Q_ASSERT(_fboLocks.count(texture));
|
||||
int newLockCount = --_fboLocks[texture];
|
||||
if (!newLockCount) {
|
||||
auto fbo = _fboMap[texture].data();
|
||||
if (fbo->size() != _size) {
|
||||
// Move the old FBO to the destruction queue.
|
||||
// We can't destroy the FBO here because we might
|
||||
// not be on the right thread or have the context active
|
||||
_destroyFboQueue.push_back(_fboMap[texture]);
|
||||
_fboMap.remove(texture);
|
||||
} else {
|
||||
_readyFboQueue.push_back(fbo);
|
||||
}
|
||||
_fboLocks.remove(texture);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
QOpenGLFramebufferObject* FboCache::getReadyFbo() {
|
||||
QOpenGLFramebufferObject* result = nullptr;
|
||||
withLock(_lock, [&] {
|
||||
// Delete any FBOs queued for deletion
|
||||
_destroyFboQueue.clear();
|
||||
|
||||
if (_readyFboQueue.empty()) {
|
||||
qDebug() << "Building new offscreen FBO number " << _fboMap.size() + 1;
|
||||
result = new QOpenGLFramebufferObject(_size, QOpenGLFramebufferObject::CombinedDepthStencil);
|
||||
_fboMap[result->texture()] = QSharedPointer<QOpenGLFramebufferObject>(result);
|
||||
_readyFboQueue.push_back(result);
|
||||
} else {
|
||||
result = _readyFboQueue.front();
|
||||
}
|
||||
});
|
||||
return result;
|
||||
}
|
||||
|
||||
void FboCache::setSize(const QSize& newSize) {
|
||||
if (_size == newSize) {
|
||||
return;
|
||||
}
|
||||
_size = newSize;
|
||||
withLock(_lock, [&] {
|
||||
// Clear out any fbos with the old id
|
||||
_readyFboQueue.clear();
|
||||
|
||||
QSet<int> outdatedFbos;
|
||||
// FBOs that are locked will be removed as they are unlocked
|
||||
foreach(int texture, _fboMap.keys()) {
|
||||
if (!_fboLocks.count(texture)) {
|
||||
outdatedFbos.insert(texture);
|
||||
}
|
||||
}
|
||||
// Implicitly deletes the FBO via the shared pointer destruction mechanism
|
||||
foreach(int texture, outdatedFbos) {
|
||||
_fboMap.remove(texture);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
51
libraries/render-utils/src/FboCache.h
Normal file
51
libraries/render-utils/src/FboCache.h
Normal file
|
@ -0,0 +1,51 @@
|
|||
//
|
||||
// OffscreenGlCanvas.h
|
||||
// interface/src/renderer
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2014/04/09.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#pragma once
|
||||
#ifndef hifi_FboCache_h
|
||||
#define hifi_FboCache_h
|
||||
|
||||
#include <QOpenGLContext>
|
||||
#include <QOffscreenSurface>
|
||||
#include <QQueue>
|
||||
#include <QMap>
|
||||
#include <QSharedPointer>
|
||||
#include <QMutex>
|
||||
|
||||
class QOpenGLFramebufferObject;
|
||||
|
||||
class FboCache : public QObject {
|
||||
public:
|
||||
FboCache();
|
||||
|
||||
// setSize() and getReadyFbo() must consitently be called from only a single
|
||||
// thread. Additionally, it is the caller's responsibility to ensure that
|
||||
// the appropriate OpenGL context is active when doing so.
|
||||
|
||||
// Important.... textures are sharable resources, but FBOs ARE NOT.
|
||||
void setSize(const QSize& newSize);
|
||||
QOpenGLFramebufferObject* getReadyFbo();
|
||||
|
||||
// These operations are thread safe and require no OpenGL context. They manipulate the
|
||||
// internal locks and pointers but execute no OpenGL opreations.
|
||||
void lockTexture(int texture);
|
||||
void releaseTexture(int texture);
|
||||
|
||||
protected:
|
||||
QMap<int, QSharedPointer<QOpenGLFramebufferObject>> _fboMap;
|
||||
QMap<int, int> _fboLocks;
|
||||
QQueue<QOpenGLFramebufferObject*> _readyFboQueue;
|
||||
QQueue<QSharedPointer<QOpenGLFramebufferObject>> _destroyFboQueue;
|
||||
QMutex _lock;
|
||||
QSize _size;
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_FboCache_h
|
45
libraries/render-utils/src/OffscreenGlCanvas.cpp
Normal file
45
libraries/render-utils/src/OffscreenGlCanvas.cpp
Normal file
|
@ -0,0 +1,45 @@
|
|||
//
|
||||
// OffscreenGlCanvas.cpp
|
||||
// interface/src/renderer
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2014/04/09.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
|
||||
#include "OffscreenGlCanvas.h"
|
||||
|
||||
OffscreenGlCanvas::OffscreenGlCanvas() {
|
||||
}
|
||||
|
||||
void OffscreenGlCanvas::create(QOpenGLContext* sharedContext) {
|
||||
if (nullptr != sharedContext) {
|
||||
sharedContext->doneCurrent();
|
||||
_context.setFormat(sharedContext->format());
|
||||
_context.setShareContext(sharedContext);
|
||||
} else {
|
||||
QSurfaceFormat format;
|
||||
format.setDepthBufferSize(16);
|
||||
format.setStencilBufferSize(8);
|
||||
format.setMajorVersion(4);
|
||||
format.setMinorVersion(1);
|
||||
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile);
|
||||
_context.setFormat(format);
|
||||
}
|
||||
_context.create();
|
||||
|
||||
_offscreenSurface.setFormat(_context.format());
|
||||
_offscreenSurface.create();
|
||||
}
|
||||
|
||||
bool OffscreenGlCanvas::makeCurrent() {
|
||||
return _context.makeCurrent(&_offscreenSurface);
|
||||
}
|
||||
|
||||
void OffscreenGlCanvas::doneCurrent() {
|
||||
_context.doneCurrent();
|
||||
}
|
||||
|
31
libraries/render-utils/src/OffscreenGlCanvas.h
Normal file
31
libraries/render-utils/src/OffscreenGlCanvas.h
Normal file
|
@ -0,0 +1,31 @@
|
|||
//
|
||||
// OffscreenGlCanvas.h
|
||||
// interface/src/renderer
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2014/04/09.
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#pragma once
|
||||
#ifndef hifi_OffscreenGlCanvas_h
|
||||
#define hifi_OffscreenGlCanvas_h
|
||||
|
||||
#include <QOpenGLContext>
|
||||
#include <QOffscreenSurface>
|
||||
|
||||
class OffscreenGlCanvas : public QObject {
|
||||
public:
|
||||
OffscreenGlCanvas();
|
||||
void create(QOpenGLContext* sharedContext = nullptr);
|
||||
bool makeCurrent();
|
||||
void doneCurrent();
|
||||
|
||||
protected:
|
||||
QOpenGLContext _context;
|
||||
QOffscreenSurface _offscreenSurface;
|
||||
|
||||
};
|
||||
|
||||
#endif // hifi_OffscreenGlCanvas_h
|
18
libraries/render-utils/src/OffscreenQmlDialog.cpp
Normal file
18
libraries/render-utils/src/OffscreenQmlDialog.cpp
Normal file
|
@ -0,0 +1,18 @@
|
|||
//
|
||||
// OffscreenQmlDialog.cpp
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2015/04/14
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "OffscreenQmlDialog.h"
|
||||
|
||||
OffscreenQmlDialog::OffscreenQmlDialog(QQuickItem* parent)
|
||||
: QQuickItem(parent) { }
|
||||
|
||||
void OffscreenQmlDialog::hide() {
|
||||
static_cast<QQuickItem*>(parent())->setEnabled(false);
|
||||
}
|
56
libraries/render-utils/src/OffscreenQmlDialog.h
Normal file
56
libraries/render-utils/src/OffscreenQmlDialog.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
//
|
||||
// OffscreenQmlDialog.h
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2015/04/14
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#pragma once
|
||||
#ifndef hifi_OffscreenQmlDialog_h
|
||||
#define hifi_OffscreenQmlDialog_h
|
||||
|
||||
#include <QQuickItem>
|
||||
#include "OffscreenUi.h"
|
||||
|
||||
#define QML_DIALOG_DECL \
|
||||
private: \
|
||||
static const QString NAME; \
|
||||
static const QUrl QML; \
|
||||
public: \
|
||||
static void registerType(); \
|
||||
static void show(); \
|
||||
static void toggle(); \
|
||||
private:
|
||||
|
||||
#define QML_DIALOG_DEF(x) \
|
||||
const QUrl x::QML = QUrl(#x ".qml"); \
|
||||
const QString x::NAME = #x; \
|
||||
\
|
||||
void x::registerType() { \
|
||||
qmlRegisterType<x>("Hifi", 1, 0, NAME.toLocal8Bit().constData()); \
|
||||
} \
|
||||
\
|
||||
void x::show() { \
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>(); \
|
||||
offscreenUi->show(QML, NAME); \
|
||||
} \
|
||||
\
|
||||
void x::toggle() { \
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>(); \
|
||||
offscreenUi->toggle(QML, NAME); \
|
||||
}
|
||||
|
||||
class OffscreenQmlDialog : public QQuickItem
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
OffscreenQmlDialog(QQuickItem* parent = nullptr);
|
||||
|
||||
protected:
|
||||
void hide();
|
||||
};
|
||||
|
||||
#endif
|
412
libraries/render-utils/src/OffscreenUi.cpp
Normal file
412
libraries/render-utils/src/OffscreenUi.cpp
Normal file
|
@ -0,0 +1,412 @@
|
|||
//
|
||||
// OffscreenUi.cpp
|
||||
// interface/src/render-utils
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2015-04-04
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#include "OffscreenUi.h"
|
||||
#include <QOpenGLFramebufferObject>
|
||||
#include <QOpenGLDebugLogger>
|
||||
#include <QGLWidget>
|
||||
#include <QtQml>
|
||||
|
||||
// Time between receiving a request to render the offscreen UI actually triggering
|
||||
// the render. Could possibly be increased depending on the framerate we expect to
|
||||
// achieve.
|
||||
static const int SMALL_INTERVAL = 5;
|
||||
|
||||
class OffscreenUiRoot : public QQuickItem {
|
||||
Q_OBJECT
|
||||
public:
|
||||
|
||||
OffscreenUiRoot(QQuickItem* parent = 0);
|
||||
Q_INVOKABLE void information(const QString& title, const QString& text);
|
||||
Q_INVOKABLE void loadChild(const QUrl& url) {
|
||||
DependencyManager::get<OffscreenUi>()->load(url);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
OffscreenUiRoot::OffscreenUiRoot(QQuickItem* parent) : QQuickItem(parent) {
|
||||
}
|
||||
|
||||
void OffscreenUiRoot::information(const QString& title, const QString& text) {
|
||||
OffscreenUi::information(title, text);
|
||||
}
|
||||
|
||||
OffscreenUi::OffscreenUi() {
|
||||
::qmlRegisterType<OffscreenUiRoot>("Hifi", 1, 0, "Root");
|
||||
}
|
||||
|
||||
OffscreenUi::~OffscreenUi() {
|
||||
// Make sure the context is current while doing cleanup. Note that we use the
|
||||
// offscreen surface here because passing 'this' at this point is not safe: the
|
||||
// underlying platform window may already be destroyed. To avoid all the trouble, use
|
||||
// another surface that is valid for sure.
|
||||
makeCurrent();
|
||||
|
||||
// Delete the render control first since it will free the scenegraph resources.
|
||||
// Destroy the QQuickWindow only afterwards.
|
||||
delete _renderControl;
|
||||
|
||||
delete _qmlComponent;
|
||||
delete _quickWindow;
|
||||
delete _qmlEngine;
|
||||
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
void OffscreenUi::create(QOpenGLContext* shareContext) {
|
||||
OffscreenGlCanvas::create(shareContext);
|
||||
|
||||
makeCurrent();
|
||||
|
||||
// Create a QQuickWindow that is associated with out render control. Note that this
|
||||
// window never gets created or shown, meaning that it will never get an underlying
|
||||
// native (platform) window.
|
||||
QQuickWindow::setDefaultAlphaBuffer(true);
|
||||
_quickWindow = new QQuickWindow(_renderControl);
|
||||
_quickWindow->setColor(QColor(255, 255, 255, 0));
|
||||
_quickWindow->setFlags(_quickWindow->flags() | static_cast<Qt::WindowFlags>(Qt::WA_TranslucentBackground));
|
||||
// Create a QML engine.
|
||||
_qmlEngine = new QQmlEngine;
|
||||
if (!_qmlEngine->incubationController()) {
|
||||
_qmlEngine->setIncubationController(_quickWindow->incubationController());
|
||||
}
|
||||
|
||||
// When Quick says there is a need to render, we will not render immediately. Instead,
|
||||
// a timer with a small interval is used to get better performance.
|
||||
_updateTimer.setSingleShot(true);
|
||||
_updateTimer.setInterval(SMALL_INTERVAL);
|
||||
connect(&_updateTimer, &QTimer::timeout, this, &OffscreenUi::updateQuick);
|
||||
|
||||
// Now hook up the signals. For simplicy we don't differentiate between
|
||||
// renderRequested (only render is needed, no sync) and sceneChanged (polish and sync
|
||||
// is needed too).
|
||||
connect(_renderControl, &QQuickRenderControl::renderRequested, this, &OffscreenUi::requestRender);
|
||||
connect(_renderControl, &QQuickRenderControl::sceneChanged, this, &OffscreenUi::requestUpdate);
|
||||
_quickWindow->focusObject();
|
||||
|
||||
_qmlComponent = new QQmlComponent(_qmlEngine);
|
||||
// Initialize the render control and our OpenGL resources.
|
||||
makeCurrent();
|
||||
_renderControl->initialize(&_context);
|
||||
}
|
||||
|
||||
void OffscreenUi::addImportPath(const QString& path) {
|
||||
_qmlEngine->addImportPath(path);
|
||||
}
|
||||
|
||||
void OffscreenUi::resize(const QSize& newSize) {
|
||||
makeCurrent();
|
||||
|
||||
// Clear out any fbos with the old size
|
||||
qreal pixelRatio = _renderControl->_renderWindow ? _renderControl->_renderWindow->devicePixelRatio() : 1.0;
|
||||
qDebug() << "Offscreen UI resizing to " << newSize.width() << "x" << newSize.height() << " with pixel ratio " << pixelRatio;
|
||||
_fboCache.setSize(newSize * pixelRatio);
|
||||
|
||||
// Update our members
|
||||
if (_rootItem) {
|
||||
_rootItem->setSize(newSize);
|
||||
}
|
||||
|
||||
if (_quickWindow) {
|
||||
_quickWindow->setGeometry(QRect(QPoint(), newSize));
|
||||
}
|
||||
|
||||
doneCurrent();
|
||||
}
|
||||
|
||||
QQmlContext* OffscreenUi::qmlContext() {
|
||||
if (nullptr == _rootItem) {
|
||||
return _qmlComponent->creationContext();
|
||||
}
|
||||
return QQmlEngine::contextForObject(_rootItem);
|
||||
}
|
||||
|
||||
void OffscreenUi::setBaseUrl(const QUrl& baseUrl) {
|
||||
_qmlEngine->setBaseUrl(baseUrl);
|
||||
}
|
||||
|
||||
void OffscreenUi::load(const QUrl& qmlSource, std::function<void(QQmlContext*)> f) {
|
||||
qDebug() << "Loading QML from URL " << qmlSource;
|
||||
_qmlComponent->loadUrl(qmlSource);
|
||||
if (_qmlComponent->isLoading()) {
|
||||
connect(_qmlComponent, &QQmlComponent::statusChanged, this, []{});
|
||||
} else {
|
||||
finishQmlLoad();
|
||||
}
|
||||
}
|
||||
|
||||
void OffscreenUi::requestUpdate() {
|
||||
_polish = true;
|
||||
if (!_updateTimer.isActive()) {
|
||||
_updateTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
void OffscreenUi::requestRender() {
|
||||
if (!_updateTimer.isActive()) {
|
||||
_updateTimer.start();
|
||||
}
|
||||
}
|
||||
|
||||
void OffscreenUi::finishQmlLoad() {
|
||||
disconnect(_qmlComponent, &QQmlComponent::statusChanged, this, &OffscreenUi::finishQmlLoad);
|
||||
if (_qmlComponent->isError()) {
|
||||
QList<QQmlError> errorList = _qmlComponent->errors();
|
||||
foreach(const QQmlError &error, errorList) {
|
||||
qWarning() << error.url() << error.line() << error;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
QObject* newObject = _qmlComponent->create();
|
||||
if (_qmlComponent->isError()) {
|
||||
QList<QQmlError> errorList = _qmlComponent->errors();
|
||||
foreach(const QQmlError &error, errorList)
|
||||
qWarning() << error.url() << error.line() << error;
|
||||
if (!_rootItem) {
|
||||
qFatal("Unable to finish loading QML root");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
QQuickItem* newItem = qobject_cast<QQuickItem*>(newObject);
|
||||
if (!newItem) {
|
||||
qWarning("run: Not a QQuickItem");
|
||||
delete newObject;
|
||||
if (!_rootItem) {
|
||||
qFatal("Unable to find root QQuickItem");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
// Make sure we make items focusable (critical for
|
||||
// supporting keyboard shortcuts)
|
||||
newItem->setFlag(QQuickItem::ItemIsFocusScope, true);
|
||||
|
||||
if (!_rootItem) {
|
||||
// The root item is ready. Associate it with the window.
|
||||
_rootItem = newItem;
|
||||
_rootItem->setParentItem(_quickWindow->contentItem());
|
||||
_rootItem->setSize(_quickWindow->renderTargetSize());
|
||||
} else {
|
||||
// Allow child windows to be destroyed from JS
|
||||
QQmlEngine::setObjectOwnership(newItem, QQmlEngine::JavaScriptOwnership);
|
||||
newItem->setParent(_rootItem);
|
||||
newItem->setParentItem(_rootItem);
|
||||
newItem->setEnabled(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void OffscreenUi::updateQuick() {
|
||||
if (_paused) {
|
||||
return;
|
||||
}
|
||||
if (!makeCurrent()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Polish, synchronize and render the next frame (into our fbo). In this example
|
||||
// everything happens on the same thread and therefore all three steps are performed
|
||||
// in succession from here. In a threaded setup the render() call would happen on a
|
||||
// separate thread.
|
||||
if (_polish) {
|
||||
_renderControl->polishItems();
|
||||
_renderControl->sync();
|
||||
_polish = false;
|
||||
}
|
||||
|
||||
QOpenGLFramebufferObject* fbo = _fboCache.getReadyFbo();
|
||||
|
||||
_quickWindow->setRenderTarget(fbo);
|
||||
fbo->bind();
|
||||
|
||||
glClearColor(0, 0, 0, 1);
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
_renderControl->render();
|
||||
|
||||
Q_ASSERT(!glGetError());
|
||||
|
||||
_quickWindow->resetOpenGLState();
|
||||
|
||||
QOpenGLFramebufferObject::bindDefault();
|
||||
// Force completion of all the operations before we emit the texture as being ready for use
|
||||
glFinish();
|
||||
|
||||
emit textureUpdated(fbo->texture());
|
||||
}
|
||||
|
||||
QPointF OffscreenUi::mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject) {
|
||||
vec2 sourceSize;
|
||||
if (dynamic_cast<QWidget*>(sourceObject)) {
|
||||
sourceSize = toGlm(((QWidget*)sourceObject)->size());
|
||||
} else if (dynamic_cast<QWindow*>(sourceObject)) {
|
||||
sourceSize = toGlm(((QWindow*)sourceObject)->size());
|
||||
}
|
||||
vec2 offscreenPosition = toGlm(sourcePosition);
|
||||
offscreenPosition /= sourceSize;
|
||||
offscreenPosition *= vec2(toGlm(_quickWindow->size()));
|
||||
return QPointF(offscreenPosition.x, offscreenPosition.y);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////
|
||||
//
|
||||
// Event handling customization
|
||||
//
|
||||
|
||||
bool OffscreenUi::eventFilter(QObject* originalDestination, QEvent* event) {
|
||||
// Only intercept events while we're in an active state
|
||||
if (_paused) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Don't intercept our own events, or we enter an infinite recursion
|
||||
if (originalDestination == _quickWindow) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (event->type()) {
|
||||
case QEvent::Resize: {
|
||||
QResizeEvent* resizeEvent = static_cast<QResizeEvent*>(event);
|
||||
QGLWidget* widget = dynamic_cast<QGLWidget*>(originalDestination);
|
||||
if (widget) {
|
||||
this->resize(resizeEvent->size());
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
case QEvent::KeyPress:
|
||||
case QEvent::KeyRelease: {
|
||||
event->ignore();
|
||||
if (QCoreApplication::sendEvent(_quickWindow, event)) {
|
||||
return event->isAccepted();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case QEvent::Wheel: {
|
||||
QWheelEvent* wheelEvent = static_cast<QWheelEvent*>(event);
|
||||
QWheelEvent mappedEvent(
|
||||
mapWindowToUi(wheelEvent->pos(), originalDestination),
|
||||
wheelEvent->delta(), wheelEvent->buttons(),
|
||||
wheelEvent->modifiers(), wheelEvent->orientation());
|
||||
mappedEvent.ignore();
|
||||
if (QCoreApplication::sendEvent(_quickWindow, &mappedEvent)) {
|
||||
return mappedEvent.isAccepted();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Fall through
|
||||
case QEvent::MouseButtonDblClick:
|
||||
case QEvent::MouseButtonPress:
|
||||
case QEvent::MouseButtonRelease:
|
||||
case QEvent::MouseMove: {
|
||||
QMouseEvent* mouseEvent = static_cast<QMouseEvent*>(event);
|
||||
QPointF originalPos = mouseEvent->localPos();
|
||||
QPointF transformedPos = _mouseTranslator(originalPos);
|
||||
QMouseEvent mappedEvent(mouseEvent->type(),
|
||||
mapWindowToUi(transformedPos, originalDestination),
|
||||
mouseEvent->screenPos(), mouseEvent->button(),
|
||||
mouseEvent->buttons(), mouseEvent->modifiers());
|
||||
mappedEvent.ignore();
|
||||
if (QCoreApplication::sendEvent(_quickWindow, &mappedEvent)) {
|
||||
return mappedEvent.isAccepted();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void OffscreenUi::lockTexture(int texture) {
|
||||
_fboCache.lockTexture(texture);
|
||||
}
|
||||
|
||||
void OffscreenUi::releaseTexture(int texture) {
|
||||
_fboCache.releaseTexture(texture);
|
||||
}
|
||||
|
||||
void OffscreenUi::pause() {
|
||||
_paused = true;
|
||||
}
|
||||
|
||||
void OffscreenUi::resume() {
|
||||
_paused = false;
|
||||
requestRender();
|
||||
}
|
||||
|
||||
bool OffscreenUi::isPaused() const {
|
||||
return _paused;
|
||||
}
|
||||
|
||||
void OffscreenUi::setProxyWindow(QWindow* window) {
|
||||
_renderControl->_renderWindow = window;
|
||||
}
|
||||
|
||||
void OffscreenUi::show(const QUrl& url, const QString& name) {
|
||||
QQuickItem* item = _rootItem->findChild<QQuickItem*>(name);
|
||||
// First load?
|
||||
if (!item) {
|
||||
load(url);
|
||||
return;
|
||||
}
|
||||
item->setEnabled(true);
|
||||
}
|
||||
|
||||
void OffscreenUi::toggle(const QUrl& url, const QString& name) {
|
||||
QQuickItem* item = _rootItem->findChild<QQuickItem*>(name);
|
||||
// First load?
|
||||
if (!item) {
|
||||
load(url);
|
||||
return;
|
||||
}
|
||||
item->setEnabled(!item->isEnabled());
|
||||
}
|
||||
|
||||
void OffscreenUi::messageBox(const QString& title, const QString& text,
|
||||
QMessageBox::Icon icon,
|
||||
QMessageBox::StandardButtons buttons,
|
||||
ButtonCallback f) {
|
||||
}
|
||||
|
||||
void OffscreenUi::information(const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons,
|
||||
ButtonCallback callback) {
|
||||
callback(QMessageBox::information(nullptr, title, text, buttons));
|
||||
}
|
||||
|
||||
void OffscreenUi::question(const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons,
|
||||
ButtonCallback callback) {
|
||||
callback(QMessageBox::question(nullptr, title, text, buttons));
|
||||
}
|
||||
|
||||
void OffscreenUi::warning(const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons,
|
||||
ButtonCallback callback) {
|
||||
callback(QMessageBox::warning(nullptr, title, text, buttons));
|
||||
}
|
||||
|
||||
void OffscreenUi::critical(const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons,
|
||||
ButtonCallback callback) {
|
||||
callback(QMessageBox::critical(nullptr, title, text, buttons));
|
||||
}
|
||||
|
||||
|
||||
OffscreenUi::ButtonCallback OffscreenUi::NO_OP_CALLBACK = [](QMessageBox::StandardButton) {};
|
||||
|
||||
#include "OffscreenUi.moc"
|
136
libraries/render-utils/src/OffscreenUi.h
Normal file
136
libraries/render-utils/src/OffscreenUi.h
Normal file
|
@ -0,0 +1,136 @@
|
|||
//
|
||||
// OffscreenUi.h
|
||||
// interface/src/entities
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2015-04-04
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#pragma once
|
||||
#ifndef hifi_OffscreenUi_h
|
||||
#define hifi_OffscreenUi_h
|
||||
|
||||
#include <QQmlEngine>
|
||||
#include <QQmlComponent>
|
||||
#include <QQuickItem>
|
||||
#include <QQuickWindow>
|
||||
#include <QQuickRenderControl>
|
||||
#include <QQuickImageProvider>
|
||||
#include <QTimer>
|
||||
#include <QMessageBox>
|
||||
|
||||
#include <atomic>
|
||||
#include <functional>
|
||||
|
||||
#include <GLMHelpers.h>
|
||||
#include <ThreadHelpers.h>
|
||||
#include <DependencyManager.h>
|
||||
|
||||
#include "OffscreenGlCanvas.h"
|
||||
#include "FboCache.h"
|
||||
#include <QQuickItem>
|
||||
|
||||
|
||||
class OffscreenUi : public OffscreenGlCanvas, public Dependency {
|
||||
Q_OBJECT
|
||||
|
||||
class QMyQuickRenderControl : public QQuickRenderControl {
|
||||
protected:
|
||||
QWindow* renderWindow(QPoint* offset) Q_DECL_OVERRIDE{
|
||||
if (nullptr == _renderWindow) {
|
||||
return QQuickRenderControl::renderWindow(offset);
|
||||
}
|
||||
if (nullptr != offset) {
|
||||
offset->rx() = offset->ry() = 0;
|
||||
}
|
||||
return _renderWindow;
|
||||
}
|
||||
|
||||
private:
|
||||
QWindow* _renderWindow{ nullptr };
|
||||
friend class OffscreenUi;
|
||||
};
|
||||
|
||||
public:
|
||||
using MouseTranslator = std::function<QPointF(const QPointF&)>;
|
||||
OffscreenUi();
|
||||
virtual ~OffscreenUi();
|
||||
void create(QOpenGLContext* context);
|
||||
void resize(const QSize& size);
|
||||
void load(const QUrl& qmlSource, std::function<void(QQmlContext*)> f = [](QQmlContext*) {});
|
||||
void load(const QString& qmlSourceFile, std::function<void(QQmlContext*)> f = [](QQmlContext*) {}) {
|
||||
load(QUrl(qmlSourceFile), f);
|
||||
}
|
||||
void show(const QUrl& url, const QString& name);
|
||||
void toggle(const QUrl& url, const QString& name);
|
||||
void setBaseUrl(const QUrl& baseUrl);
|
||||
void addImportPath(const QString& path);
|
||||
QQmlContext* qmlContext();
|
||||
|
||||
void pause();
|
||||
void resume();
|
||||
bool isPaused() const;
|
||||
void setProxyWindow(QWindow* window);
|
||||
QPointF mapWindowToUi(const QPointF& sourcePosition, QObject* sourceObject);
|
||||
virtual bool eventFilter(QObject* originalDestination, QEvent* event);
|
||||
void setMouseTranslator(MouseTranslator mouseTranslator) {
|
||||
_mouseTranslator = mouseTranslator;
|
||||
}
|
||||
|
||||
|
||||
// Messagebox replacement functions
|
||||
using ButtonCallback = std::function<void(QMessageBox::StandardButton)>;
|
||||
static ButtonCallback NO_OP_CALLBACK;
|
||||
|
||||
static void messageBox(const QString& title, const QString& text,
|
||||
QMessageBox::Icon icon,
|
||||
QMessageBox::StandardButtons buttons,
|
||||
ButtonCallback f);
|
||||
|
||||
static void information(const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
ButtonCallback callback = NO_OP_CALLBACK);
|
||||
|
||||
static void question(const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::StandardButtons(QMessageBox::Yes | QMessageBox::No),
|
||||
ButtonCallback callback = [](QMessageBox::StandardButton) {});
|
||||
|
||||
static void warning(const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
ButtonCallback callback = [](QMessageBox::StandardButton) {});
|
||||
|
||||
static void critical(const QString& title, const QString& text,
|
||||
QMessageBox::StandardButtons buttons = QMessageBox::Ok,
|
||||
ButtonCallback callback = [](QMessageBox::StandardButton) {});
|
||||
|
||||
protected:
|
||||
|
||||
private slots:
|
||||
void updateQuick();
|
||||
void finishQmlLoad();
|
||||
|
||||
public slots:
|
||||
void requestUpdate();
|
||||
void requestRender();
|
||||
void lockTexture(int texture);
|
||||
void releaseTexture(int texture);
|
||||
|
||||
signals:
|
||||
void textureUpdated(GLuint texture);
|
||||
|
||||
private:
|
||||
QMyQuickRenderControl* _renderControl{ new QMyQuickRenderControl };
|
||||
QQuickWindow* _quickWindow{ nullptr };
|
||||
QQmlEngine* _qmlEngine{ nullptr };
|
||||
QQmlComponent* _qmlComponent{ nullptr };
|
||||
QQuickItem* _rootItem{ nullptr };
|
||||
QTimer _updateTimer;
|
||||
FboCache _fboCache;
|
||||
bool _polish{ true };
|
||||
bool _paused{ true };
|
||||
MouseTranslator _mouseTranslator{ [](const QPointF& p) { return p; } };
|
||||
};
|
||||
|
||||
#endif
|
|
@ -15,4 +15,54 @@
|
|||
/// Renders a quad from (-1, -1, 0) to (1, 1, 0) with texture coordinates from (sMin, tMin) to (sMax, tMax).
|
||||
void renderFullscreenQuad(float sMin = 0.0f, float sMax = 1.0f, float tMin = 0.0f, float tMax = 1.0f);
|
||||
|
||||
template <typename F, GLenum matrix>
|
||||
void withMatrixPush(F f) {
|
||||
glMatrixMode(matrix);
|
||||
glPushMatrix();
|
||||
f();
|
||||
glPopMatrix();
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void withProjectionPush(F f) {
|
||||
withMatrixPush<GL_PROJECTION>(f);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void withProjectionIdentity(F f) {
|
||||
withProjectionPush([&] {
|
||||
glLoadIdentity();
|
||||
f();
|
||||
});
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void withProjectionMatrix(GLfloat* matrix, F f) {
|
||||
withProjectionPush([&] {
|
||||
glLoadMatrixf(matrix);
|
||||
f();
|
||||
});
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void withModelviewPush(F f) {
|
||||
withMatrixPush<GL_MODELVIEW>(f);
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void withModelviewIdentity(F f) {
|
||||
withModelviewPush([&] {
|
||||
glLoadIdentity();
|
||||
f();
|
||||
});
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void withModelviewMatrix(GLfloat* matrix, F f) {
|
||||
withModelviewPush([&] {
|
||||
glLoadMatrixf(matrix);
|
||||
f();
|
||||
});
|
||||
}
|
||||
|
||||
#endif // hifi_RenderUtil_h
|
||||
|
|
|
@ -203,6 +203,13 @@ glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2) {
|
|||
return glm::angleAxis(angle, axis);
|
||||
}
|
||||
|
||||
bool isPointBehindTrianglesPlane(glm::vec3 point, glm::vec3 p0, glm::vec3 p1, glm::vec3 p2) {
|
||||
glm::vec3 v1 = p0 - p1, v2 = p2 - p1; // Non-collinear vectors contained in the plane
|
||||
glm::vec3 n = glm::cross(v1, v2); // Plane's normal vector, pointing out of the triangle
|
||||
float d = -glm::dot(n, p0); // Compute plane's equation constant
|
||||
return (glm::dot(n, point) + d) >= 0;
|
||||
}
|
||||
|
||||
glm::vec3 extractTranslation(const glm::mat4& matrix) {
|
||||
return glm::vec3(matrix[3][0], matrix[3][1], matrix[3][2]);
|
||||
}
|
||||
|
|
|
@ -17,6 +17,17 @@
|
|||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
|
||||
// Bring the most commonly used GLM types into the default namespace
|
||||
using glm::ivec3;
|
||||
using glm::ivec2;
|
||||
using glm::uvec2;
|
||||
using glm::mat3;
|
||||
using glm::mat4;
|
||||
using glm::vec2;
|
||||
using glm::vec3;
|
||||
using glm::vec4;
|
||||
using glm::quat;
|
||||
|
||||
#include <QtCore/QByteArray>
|
||||
#include <QtGui/QMatrix4x4>
|
||||
#include <QtGui/QColor>
|
||||
|
@ -71,6 +82,8 @@ float angleBetween(const glm::vec3& v1, const glm::vec3& v2);
|
|||
|
||||
glm::quat rotationBetween(const glm::vec3& v1, const glm::vec3& v2);
|
||||
|
||||
bool isPointBehindTrianglesPlane(glm::vec3 point, glm::vec3 p0, glm::vec3 p1, glm::vec3 p2);
|
||||
|
||||
glm::vec3 extractTranslation(const glm::mat4& matrix);
|
||||
|
||||
void setTranslation(glm::mat4& matrix, const glm::vec3& translation);
|
||||
|
|
|
@ -114,7 +114,7 @@ float ShapeInfo::computeVolume() const {
|
|||
}
|
||||
case SHAPE_TYPE_CAPSULE_Y: {
|
||||
float radius = _halfExtents.x;
|
||||
volume = PI * radius * radius * (2.0f * _halfExtents.y + 4.0f * radius / 3.0f);
|
||||
volume = PI * radius * radius * (2.0f * (_halfExtents.y - _halfExtents.x) + 4.0f * radius / 3.0f);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
|
@ -124,6 +124,54 @@ float ShapeInfo::computeVolume() const {
|
|||
return volume;
|
||||
}
|
||||
|
||||
bool ShapeInfo::contains(const glm::vec3& point) const {
|
||||
switch(_type) {
|
||||
case SHAPE_TYPE_SPHERE:
|
||||
return glm::length(point) <= _halfExtents.x;
|
||||
case SHAPE_TYPE_ELLIPSOID: {
|
||||
glm::vec3 scaledPoint = glm::abs(point) / _halfExtents;
|
||||
return glm::length(scaledPoint) <= 1.0f;
|
||||
}
|
||||
case SHAPE_TYPE_CYLINDER_X:
|
||||
return glm::length(glm::vec2(point.y, point.z)) <= _halfExtents.z;
|
||||
case SHAPE_TYPE_CYLINDER_Y:
|
||||
return glm::length(glm::vec2(point.x, point.z)) <= _halfExtents.x;
|
||||
case SHAPE_TYPE_CYLINDER_Z:
|
||||
return glm::length(glm::vec2(point.x, point.y)) <= _halfExtents.y;
|
||||
case SHAPE_TYPE_CAPSULE_X: {
|
||||
if (glm::abs(point.x) <= _halfExtents.x) {
|
||||
return glm::length(glm::vec2(point.y, point.z)) <= _halfExtents.z;
|
||||
} else {
|
||||
glm::vec3 absPoint = glm::abs(point) - _halfExtents.x;
|
||||
return glm::length(absPoint) <= _halfExtents.z;
|
||||
}
|
||||
}
|
||||
case SHAPE_TYPE_CAPSULE_Y: {
|
||||
if (glm::abs(point.y) <= _halfExtents.y) {
|
||||
return glm::length(glm::vec2(point.x, point.z)) <= _halfExtents.x;
|
||||
} else {
|
||||
glm::vec3 absPoint = glm::abs(point) - _halfExtents.y;
|
||||
return glm::length(absPoint) <= _halfExtents.x;
|
||||
}
|
||||
}
|
||||
case SHAPE_TYPE_CAPSULE_Z: {
|
||||
if (glm::abs(point.z) <= _halfExtents.z) {
|
||||
return glm::length(glm::vec2(point.x, point.y)) <= _halfExtents.y;
|
||||
} else {
|
||||
glm::vec3 absPoint = glm::abs(point) - _halfExtents.z;
|
||||
return glm::length(absPoint) <= _halfExtents.y;
|
||||
}
|
||||
}
|
||||
case SHAPE_TYPE_BOX:
|
||||
default: {
|
||||
glm::vec3 absPoint = glm::abs(point);
|
||||
return absPoint.x <= _halfExtents.x
|
||||
&& absPoint.y <= _halfExtents.y
|
||||
&& absPoint.z <= _halfExtents.z;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const DoubleHashKey& ShapeInfo::getHash() const {
|
||||
// NOTE: we cache the key so we only ever need to compute it once for any valid ShapeInfo instance.
|
||||
if (_doubleHashKey.isNull() && _type != SHAPE_TYPE_NONE) {
|
||||
|
|
|
@ -57,6 +57,10 @@ public:
|
|||
void appendToPoints (const QVector<glm::vec3>& newPoints) { _points << newPoints; }
|
||||
|
||||
float computeVolume() const;
|
||||
|
||||
/// Returns whether point is inside the shape
|
||||
/// For compound shapes it will only return whether it is inside the bounding box
|
||||
bool contains(const glm::vec3& point) const;
|
||||
|
||||
const DoubleHashKey& getHash() const;
|
||||
|
||||
|
|
29
libraries/shared/src/ThreadHelpers.h
Normal file
29
libraries/shared/src/ThreadHelpers.h
Normal file
|
@ -0,0 +1,29 @@
|
|||
//
|
||||
// ThreadHelpers.h
|
||||
//
|
||||
// Created by Bradley Austin Davis on 2015-04-04
|
||||
// Copyright 2015 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
#pragma once
|
||||
#ifndef hifi_ThreadHelpers_h
|
||||
#define hifi_ThreadHelpers_h
|
||||
|
||||
#include <exception>
|
||||
#include <QMutex>
|
||||
#include <QMutexLocker>
|
||||
|
||||
template <typename L, typename F>
|
||||
void withLock(L lock, F function) {
|
||||
throw std::exception();
|
||||
}
|
||||
|
||||
template <typename F>
|
||||
void withLock(QMutex& lock, F function) {
|
||||
QMutexLocker locker(&lock);
|
||||
function();
|
||||
}
|
||||
|
||||
#endif
|
|
@ -74,7 +74,7 @@ void OctreeTests::propertyFlagsTests(bool verbose) {
|
|||
props.setHasProperty(PROP_POSITION);
|
||||
props.setHasProperty(PROP_RADIUS);
|
||||
props.setHasProperty(PROP_MODEL_URL);
|
||||
props.setHasProperty(PROP_COLLISION_MODEL_URL);
|
||||
props.setHasProperty(PROP_COMPOUND_SHAPE_URL);
|
||||
props.setHasProperty(PROP_ROTATION);
|
||||
|
||||
QByteArray encoded = props.encode();
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
|
||||
#include "TextRenderer.h"
|
||||
#include "MatrixStack.h"
|
||||
#include "OffscreenUi.h"
|
||||
|
||||
#include <QWindow>
|
||||
#include <QFile>
|
||||
|
@ -21,13 +22,16 @@
|
|||
#include <QOpenGLBuffer>
|
||||
#include <QOpenGLShaderProgram>
|
||||
#include <QResizeEvent>
|
||||
#include <QLoggingCategory>
|
||||
#include <QOpenGLTexture>
|
||||
#include <QOpenGLVertexArrayObject>
|
||||
#include <QApplication>
|
||||
#include <QOpenGLDebugLogger>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <glm/glm.hpp>
|
||||
#include <PathUtils.h>
|
||||
#include <QDir>
|
||||
|
||||
class RateCounter {
|
||||
std::vector<float> times;
|
||||
|
@ -65,115 +69,191 @@ public:
|
|||
}
|
||||
};
|
||||
|
||||
|
||||
const QString& getQmlDir() {
|
||||
static QString dir;
|
||||
if (dir.isEmpty()) {
|
||||
QDir path(__FILE__);
|
||||
path.cdUp();
|
||||
dir = path.cleanPath(path.absoluteFilePath("../../../interface/resources/qml/")) + "/";
|
||||
qDebug() << "Qml Path: " << dir;
|
||||
}
|
||||
return dir;
|
||||
}
|
||||
// Create a simple OpenGL window that renders text in various ways
|
||||
class QTestWindow: public QWindow {
|
||||
class QTestWindow : public QWindow {
|
||||
Q_OBJECT
|
||||
QOpenGLContext * _context;
|
||||
|
||||
QOpenGLContext* _context{ nullptr };
|
||||
QSize _size;
|
||||
TextRenderer* _textRenderer[4];
|
||||
RateCounter fps;
|
||||
int testQmlTexture{ 0 };
|
||||
//ProgramPtr _planeProgam;
|
||||
//ShapeWrapperPtr _planeShape;
|
||||
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent * ev) override {
|
||||
QWindow::resizeEvent(ev);
|
||||
_size = ev->size();
|
||||
resizeGl();
|
||||
}
|
||||
|
||||
void resizeGl() {
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, _size.width(), _size.height(), 0, 1, -1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glViewport(0, 0, _size.width(), _size.height());
|
||||
void renderText();
|
||||
void renderQml();
|
||||
|
||||
private:
|
||||
void resizeWindow(const QSize& size) {
|
||||
_size = size;
|
||||
DependencyManager::get<OffscreenUi>()->resize(_size);
|
||||
}
|
||||
|
||||
public:
|
||||
QTestWindow();
|
||||
virtual ~QTestWindow() {
|
||||
QTestWindow() {
|
||||
DependencyManager::set<OffscreenUi>();
|
||||
setSurfaceType(QSurface::OpenGLSurface);
|
||||
|
||||
QSurfaceFormat format;
|
||||
// Qt Quick may need a depth and stencil buffer. Always make sure these are available.
|
||||
format.setDepthBufferSize(16);
|
||||
format.setStencilBufferSize(8);
|
||||
format.setVersion(4, 5);
|
||||
format.setProfile(QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile);
|
||||
format.setOption(QSurfaceFormat::DebugContext);
|
||||
|
||||
setFormat(format);
|
||||
|
||||
_context = new QOpenGLContext;
|
||||
_context->setFormat(format);
|
||||
_context->create();
|
||||
|
||||
show();
|
||||
makeCurrent();
|
||||
|
||||
{
|
||||
QOpenGLDebugLogger* logger = new QOpenGLDebugLogger(this);
|
||||
logger->initialize(); // initializes in the current context, i.e. ctx
|
||||
logger->enableMessages();
|
||||
connect(logger, &QOpenGLDebugLogger::messageLogged, this, [&](const QOpenGLDebugMessage & debugMessage) {
|
||||
qDebug() << debugMessage;
|
||||
});
|
||||
// logger->startLogging(QOpenGLDebugLogger::SynchronousLogging);
|
||||
}
|
||||
qDebug() << (const char*)glGetString(GL_VERSION);
|
||||
|
||||
#ifdef WIN32
|
||||
glewExperimental = true;
|
||||
GLenum err = glewInit();
|
||||
if (GLEW_OK != err) {
|
||||
/* Problem: glewInit failed, something is seriously wrong. */
|
||||
const GLubyte * errStr = glewGetErrorString(err);
|
||||
qDebug("Error: %s\n", errStr);
|
||||
}
|
||||
qDebug("Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
|
||||
|
||||
if (wglewGetExtension("WGL_EXT_swap_control")) {
|
||||
int swapInterval = wglGetSwapIntervalEXT();
|
||||
qDebug("V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF"));
|
||||
}
|
||||
glGetError();
|
||||
#endif
|
||||
|
||||
_textRenderer[0] = TextRenderer::getInstance(SANS_FONT_FAMILY, 12, false);
|
||||
_textRenderer[1] = TextRenderer::getInstance(SERIF_FONT_FAMILY, 12, false,
|
||||
TextRenderer::SHADOW_EFFECT);
|
||||
_textRenderer[2] = TextRenderer::getInstance(MONO_FONT_FAMILY, 48, -1,
|
||||
false, TextRenderer::OUTLINE_EFFECT);
|
||||
_textRenderer[3] = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, 24);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glClearColor(0.2f, 0.2f, 0.2f, 1);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
|
||||
auto offscreenUi = DependencyManager::get<OffscreenUi>();
|
||||
offscreenUi->create(_context);
|
||||
// FIXME, need to switch to a QWindow for mouse and keyboard input to work
|
||||
offscreenUi->setProxyWindow(this);
|
||||
// "#0e7077"
|
||||
setFramePosition(QPoint(-1000, 0));
|
||||
resize(QSize(800, 600));
|
||||
|
||||
offscreenUi->setBaseUrl(QUrl::fromLocalFile(getQmlDir()));
|
||||
offscreenUi->load(QUrl("TestRoot.qml"));
|
||||
offscreenUi->addImportPath(getQmlDir());
|
||||
offscreenUi->addImportPath(".");
|
||||
|
||||
connect(offscreenUi.data(), &OffscreenUi::textureUpdated, this, [this, offscreenUi](int textureId) {
|
||||
offscreenUi->lockTexture(textureId);
|
||||
assert(!glGetError());
|
||||
GLuint oldTexture = testQmlTexture;
|
||||
testQmlTexture = textureId;
|
||||
if (oldTexture) {
|
||||
offscreenUi->releaseTexture(oldTexture);
|
||||
}
|
||||
});
|
||||
installEventFilter(offscreenUi.data());
|
||||
offscreenUi->resume();
|
||||
}
|
||||
|
||||
virtual ~QTestWindow() {
|
||||
}
|
||||
|
||||
void draw();
|
||||
void makeCurrent() {
|
||||
_context->makeCurrent(this);
|
||||
}
|
||||
|
||||
void draw();
|
||||
protected:
|
||||
|
||||
void resizeEvent(QResizeEvent* ev) override {
|
||||
resizeWindow(ev->size());
|
||||
}
|
||||
|
||||
|
||||
void keyPressEvent(QKeyEvent* event) {
|
||||
switch (event->key()) {
|
||||
case Qt::Key_L:
|
||||
if (event->modifiers() & Qt::CTRL) {
|
||||
DependencyManager::get<OffscreenUi>()->toggle(QString("TestDialog.qml"), "TestDialog");
|
||||
}
|
||||
break;
|
||||
}
|
||||
QWindow::keyPressEvent(event);
|
||||
}
|
||||
|
||||
void moveEvent(QMoveEvent* event) {
|
||||
static qreal oldPixelRatio = 0.0;
|
||||
if (devicePixelRatio() != oldPixelRatio) {
|
||||
oldPixelRatio = devicePixelRatio();
|
||||
resizeWindow(size());
|
||||
}
|
||||
|
||||
QWindow::moveEvent(event);
|
||||
}
|
||||
};
|
||||
|
||||
#ifndef SERIF_FONT_FAMILY
|
||||
#define SERIF_FONT_FAMILY "Times New Roman"
|
||||
#endif
|
||||
|
||||
QTestWindow::QTestWindow() {
|
||||
setSurfaceType(QSurface::OpenGLSurface);
|
||||
|
||||
QSurfaceFormat format;
|
||||
// Qt Quick may need a depth and stencil buffer. Always make sure these are available.
|
||||
format.setDepthBufferSize(16);
|
||||
format.setStencilBufferSize(8);
|
||||
format.setVersion(3, 2);
|
||||
format.setProfile(
|
||||
QSurfaceFormat::OpenGLContextProfile::CompatibilityProfile);
|
||||
setFormat(format);
|
||||
|
||||
_context = new QOpenGLContext;
|
||||
_context->setFormat(format);
|
||||
_context->create();
|
||||
|
||||
show();
|
||||
makeCurrent();
|
||||
qDebug() << (const char*) glGetString(GL_VERSION);
|
||||
|
||||
#ifdef WIN32
|
||||
glewExperimental = true;
|
||||
GLenum err = glewInit();
|
||||
if (GLEW_OK != err) {
|
||||
/* Problem: glewInit failed, something is seriously wrong. */
|
||||
const GLubyte * errStr = glewGetErrorString(err);
|
||||
qDebug("Error: %s\n", errStr);
|
||||
}
|
||||
qDebug("Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
|
||||
|
||||
if (wglewGetExtension("WGL_EXT_swap_control")) {
|
||||
int swapInterval = wglGetSwapIntervalEXT();
|
||||
qDebug("V-Sync is %s\n", (swapInterval > 0 ? "ON" : "OFF"));
|
||||
}
|
||||
glGetError();
|
||||
#endif
|
||||
|
||||
setFramePosition(QPoint(100, -900));
|
||||
resize(QSize(800, 600));
|
||||
_size = QSize(800, 600);
|
||||
|
||||
_textRenderer[0] = TextRenderer::getInstance(SANS_FONT_FAMILY, 12, false);
|
||||
_textRenderer[1] = TextRenderer::getInstance(SERIF_FONT_FAMILY, 12, false,
|
||||
TextRenderer::SHADOW_EFFECT);
|
||||
_textRenderer[2] = TextRenderer::getInstance(MONO_FONT_FAMILY, 48, -1,
|
||||
false, TextRenderer::OUTLINE_EFFECT);
|
||||
_textRenderer[3] = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, 24);
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
glClearColor(0.2f, 0.2f, 0.2f, 1);
|
||||
glDisable(GL_DEPTH_TEST);
|
||||
resizeGl();
|
||||
}
|
||||
|
||||
static const wchar_t * EXAMPLE_TEXT = L"Hello";
|
||||
//static const wchar_t * EXAMPLE_TEXT = L"\xC1y Hello 1.0\ny\xC1 line 2\n\xC1y";
|
||||
static const wchar_t* EXAMPLE_TEXT = L"Hello";
|
||||
//static const wchar_t* EXAMPLE_TEXT = L"\xC1y Hello 1.0\ny\xC1 line 2\n\xC1y";
|
||||
static const glm::uvec2 QUAD_OFFSET(10, 10);
|
||||
|
||||
static const glm::vec3 COLORS[4] = { { 1.0, 1.0, 1.0 }, { 0.5, 1.0, 0.5 }, {
|
||||
1.0, 0.5, 0.5 }, { 0.5, 0.5, 1.0 } };
|
||||
|
||||
void QTestWindow::draw() {
|
||||
makeCurrent();
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
void QTestWindow::renderText() {
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glOrtho(0, _size.width(), _size.height(), 0, 1, -1);
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
|
||||
const glm::uvec2 size = glm::uvec2(_size.width() / 2, _size.height() / 2);
|
||||
const glm::uvec2 offsets[4] = { { QUAD_OFFSET.x, QUAD_OFFSET.y }, { size.x
|
||||
+ QUAD_OFFSET.x, QUAD_OFFSET.y }, { size.x + QUAD_OFFSET.x, size.y
|
||||
+ QUAD_OFFSET.y }, { QUAD_OFFSET.x, size.y + QUAD_OFFSET.y }, };
|
||||
|
||||
const glm::uvec2 offsets[4] = {
|
||||
{ QUAD_OFFSET.x, QUAD_OFFSET.y },
|
||||
{ size.x + QUAD_OFFSET.x, QUAD_OFFSET.y },
|
||||
{ size.x + QUAD_OFFSET.x, size.y + QUAD_OFFSET.y },
|
||||
{ QUAD_OFFSET.x, size.y + QUAD_OFFSET.y },
|
||||
};
|
||||
|
||||
QString str = QString::fromWCharArray(EXAMPLE_TEXT);
|
||||
for (int i = 0; i < 4; ++i) {
|
||||
|
@ -200,8 +280,45 @@ void QTestWindow::draw() {
|
|||
glm::vec4(COLORS[i], 1.0f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void QTestWindow::renderQml() {
|
||||
glMatrixMode(GL_PROJECTION);
|
||||
glLoadIdentity();
|
||||
glMatrixMode(GL_MODELVIEW);
|
||||
glLoadIdentity();
|
||||
if (testQmlTexture > 0) {
|
||||
glEnable(GL_TEXTURE_2D);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, testQmlTexture);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
}
|
||||
glBegin(GL_QUADS);
|
||||
{
|
||||
glTexCoord2f(0, 0);
|
||||
glVertex2f(-1, -1);
|
||||
glTexCoord2f(0, 1);
|
||||
glVertex2f(-1, 1);
|
||||
glTexCoord2f(1, 1);
|
||||
glVertex2f(1, 1);
|
||||
glTexCoord2f(1, 0);
|
||||
glVertex2f(1, -1);
|
||||
}
|
||||
glEnd();
|
||||
}
|
||||
|
||||
void QTestWindow::draw() {
|
||||
makeCurrent();
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
glViewport(0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio());
|
||||
|
||||
//renderText();
|
||||
renderQml();
|
||||
|
||||
_context->swapBuffers(this);
|
||||
glFinish();
|
||||
|
||||
fps.increment();
|
||||
if (fps.elapsed() >= 2.0f) {
|
||||
qDebug() << "FPS: " << fps.rate();
|
||||
|
@ -211,7 +328,9 @@ void QTestWindow::draw() {
|
|||
|
||||
int main(int argc, char** argv) {
|
||||
QApplication app(argc, argv);
|
||||
//QLoggingCategory::setFilterRules("qt.quick.mouse.debug = true");
|
||||
QTestWindow window;
|
||||
|
||||
QTimer timer;
|
||||
timer.setInterval(1);
|
||||
app.connect(&timer, &QTimer::timeout, &app, [&] {
|
||||
|
|
Loading…
Reference in a new issue