Merge branch 'team-teaching' of https://github.com/highfidelity/hifi into team-teaching-scene-api

This commit is contained in:
ZappoMan 2015-05-22 14:54:47 -07:00
commit d9ed1e061c
23 changed files with 720 additions and 612 deletions

View file

@ -254,12 +254,15 @@ $(document).ready(function(){
});
$('#' + Settings.FORM_ID).on('click', '#' + Settings.DISCONNECT_ACCOUNT_BTN_ID, function(e){
$(this).blur();
disonnectHighFidelityAccount();
e.preventDefault();
});
$('#' + Settings.FORM_ID).on('click', '#' + Settings.CONNECT_ACCOUNT_BTN_ID, function(e){
$(this).blur();
prepareAccessTokenPrompt();
e.preventDefault();
});
var panelsSource = $('#panels-template').html()
@ -345,7 +348,7 @@ function disonnectHighFidelityAccount() {
+ "</br></br>This could cause your domain to appear offline and no longer be reachable via any place names.",
type: "warning",
html: true,
showCancelButton: true,
showCancelButton: true
}, function(){
// we need to post to settings to clear the access-token
$(Settings.ACCESS_TOKEN_SELECTOR).val('').change();

View file

@ -18,3 +18,4 @@ Script.load("notifications.js");
Script.load("look.js");
Script.load("users.js");
Script.load("grab.js");
Script.load("pointer.js");

View file

@ -762,7 +762,7 @@ function mouseClickEvent(event) {
selectionManager.addEntity(foundEntity, true);
}
print("Model selected: " + foundEntity.id);
print("Model selected: " + foundEntity);
selectionDisplay.select(selectedEntityID, event);
if (Menu.isOptionChecked(MENU_AUTO_FOCUS_ON_SELECT)) {
@ -1201,7 +1201,7 @@ PropertiesTool = function(opts) {
var selections = [];
for (var i = 0; i < selectionManager.selections.length; i++) {
var entity = {};
entity.id = selectionManager.selections[i].id;
entity.id = selectionManager.selections[i];
entity.properties = Entities.getEntityProperties(selectionManager.selections[i]);
entity.properties.rotation = Quat.safeEulerAngles(entity.properties.rotation);
selections.push(entity);
@ -1251,7 +1251,7 @@ PropertiesTool = function(opts) {
var dY = grid.getOrigin().y - (selectionManager.worldPosition.y - selectionManager.worldDimensions.y / 2),
var diff = { x: 0, y: dY, z: 0 };
for (var i = 0; i < selectionManager.selections.length; i++) {
var properties = selectionManager.savedProperties[selectionManager.selections[i].id];
var properties = selectionManager.savedProperties[selectionManager.selections[i]];
var newPosition = Vec3.sum(properties.position, diff);
Entities.editEntity(selectionManager.selections[i], {
position: newPosition,
@ -1264,7 +1264,7 @@ PropertiesTool = function(opts) {
if (selectionManager.hasSelection()) {
selectionManager.saveProperties();
for (var i = 0; i < selectionManager.selections.length; i++) {
var properties = selectionManager.savedProperties[selectionManager.selections[i].id];
var properties = selectionManager.savedProperties[selectionManager.selections[i]];
var bottomY = properties.boundingBox.center.y - properties.boundingBox.dimensions.y / 2;
var dY = grid.getOrigin().y - bottomY;
var diff = { x: 0, y: dY, z: 0 };
@ -1280,7 +1280,7 @@ PropertiesTool = function(opts) {
if (selectionManager.hasSelection()) {
selectionManager.saveProperties();
for (var i = 0; i < selectionManager.selections.length; i++) {
var properties = selectionManager.savedProperties[selectionManager.selections[i].id];
var properties = selectionManager.savedProperties[selectionManager.selections[i]];
var naturalDimensions = properties.naturalDimensions;
// If any of the natural dimensions are not 0, resize
@ -1302,7 +1302,7 @@ PropertiesTool = function(opts) {
if (selectionManager.hasSelection()) {
selectionManager.saveProperties();
for (var i = 0; i < selectionManager.selections.length; i++) {
var properties = selectionManager.savedProperties[selectionManager.selections[i].id];
var properties = selectionManager.savedProperties[selectionManager.selections[i]];
Entities.editEntity(selectionManager.selections[i], {
dimensions: Vec3.multiply(multiplier, properties.dimensions),
});
@ -1314,7 +1314,7 @@ PropertiesTool = function(opts) {
if (selectionManager.hasSelection()) {
selectionManager.saveProperties();
for (var i = 0; i < selectionManager.selections.length; i++) {
var properties = selectionManager.savedProperties[selectionManager.selections[i].id];
var properties = selectionManager.savedProperties[selectionManager.selections[i]];
if (properties.type == "Zone") {
var centerOfZone = properties.boundingBox.center;
var atmosphereCenter = { x: centerOfZone.x,

View file

@ -25,8 +25,18 @@ var ALTITUDE_RATE = 200.0;
var RADIUS_RATE = 1.0 / 100.0;
var PAN_RATE = 50.0;
var Y_AXIS = { x: 0, y: 1, z: 0 };
var X_AXIS = { x: 1, y: 0, z: 0 };
var Y_AXIS = {
x: 0,
y: 1,
z: 0
};
var X_AXIS = {
x: 1,
y: 0,
z: 0
};
var LOOK_AT_TIME = 500;
var alt = false;
var shift = false;
@ -34,6 +44,7 @@ var control = false;
var isActive = false;
var oldMode = Camera.mode;
var noMode = 0;
var orbitMode = 1;
var radialMode = 2;
@ -46,9 +57,21 @@ var mouseLastX = 0;
var mouseLastY = 0;
var center = { x: 0, y: 0, z: 0 };
var position = { x: 0, y: 0, z: 0 };
var vector = { x: 0, y: 0, z: 0 };
var center = {
x: 0,
y: 0,
z: 0
};
var position = {
x: 0,
y: 0,
z: 0
};
var vector = {
x: 0,
y: 0,
z: 0
};
var radius = 0.0;
var azimuth = 0.0;
var altitude = 0.0;
@ -56,244 +79,262 @@ var altitude = 0.0;
var avatarPosition;
var avatarOrientation;
var rotatingTowardsTarget = false;
var targetCamOrientation;
var oldPosition, oldOrientation;
function orientationOf(vector) {
var direction,
yaw,
pitch;
var direction,
yaw,
pitch;
direction = Vec3.normalize(vector);
yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * RAD_TO_DEG, Y_AXIS);
pitch = Quat.angleAxis(Math.asin(-direction.y) * RAD_TO_DEG, X_AXIS);
return Quat.multiply(yaw, pitch);
direction = Vec3.normalize(vector);
yaw = Quat.angleAxis(Math.atan2(direction.x, direction.z) * RAD_TO_DEG, Y_AXIS);
pitch = Quat.angleAxis(Math.asin(-direction.y) * RAD_TO_DEG, X_AXIS);
return Quat.multiply(yaw, pitch);
}
function handleRadialMode(dx, dy) {
azimuth += dx / AZIMUTH_RATE;
radius += radius * dy * RADIUS_RATE;
if (radius < 1) {
radius = 1;
}
vector = { x: (Math.cos(altitude) * Math.cos(azimuth)) * radius,
y: Math.sin(altitude) * radius,
z: (Math.cos(altitude) * Math.sin(azimuth)) * radius };
position = Vec3.sum(center, vector);
Camera.setPosition(position);
Camera.setOrientation(orientationOf(vector));
azimuth += dx / AZIMUTH_RATE;
radius += radius * dy * RADIUS_RATE;
if (radius < 1) {
radius = 1;
}
vector = {
x: (Math.cos(altitude) * Math.cos(azimuth)) * radius,
y: Math.sin(altitude) * radius,
z: (Math.cos(altitude) * Math.sin(azimuth)) * radius
};
position = Vec3.sum(center, vector);
Camera.setPosition(position);
Camera.setOrientation(orientationOf(vector));
}
function handleOrbitMode(dx, dy) {
azimuth += dx / AZIMUTH_RATE;
altitude += dy / ALTITUDE_RATE;
if (altitude > PI / 2.0) {
altitude = PI / 2.0;
}
if (altitude < -PI / 2.0) {
altitude = -PI / 2.0;
}
vector = { x:(Math.cos(altitude) * Math.cos(azimuth)) * radius,
y:Math.sin(altitude) * radius,
z:(Math.cos(altitude) * Math.sin(azimuth)) * radius };
position = Vec3.sum(center, vector);
Camera.setPosition(position);
Camera.setOrientation(orientationOf(vector));
azimuth += dx / AZIMUTH_RATE;
altitude += dy / ALTITUDE_RATE;
if (altitude > PI / 2.0) {
altitude = PI / 2.0;
}
if (altitude < -PI / 2.0) {
altitude = -PI / 2.0;
}
vector = {
x: (Math.cos(altitude) * Math.cos(azimuth)) * radius,
y: Math.sin(altitude) * radius,
z: (Math.cos(altitude) * Math.sin(azimuth)) * radius
};
position = Vec3.sum(center, vector);
Camera.setPosition(position);
Camera.setOrientation(orientationOf(vector));
}
function handlePanMode(dx, dy) {
var up = Quat.getUp(Camera.getOrientation());
var right = Quat.getRight(Camera.getOrientation());
var distance = Vec3.length(vector);
var dv = Vec3.sum(Vec3.multiply(up, - distance * dy / PAN_RATE), Vec3.multiply(right, distance * dx / PAN_RATE));
center = Vec3.sum(center, dv);
position = Vec3.sum(position, dv);
Camera.setPosition(position);
Camera.setOrientation(orientationOf(vector));
var up = Quat.getUp(Camera.getOrientation());
var right = Quat.getRight(Camera.getOrientation());
var distance = Vec3.length(vector);
var dv = Vec3.sum(Vec3.multiply(up, -distance * dy / PAN_RATE), Vec3.multiply(right, distance * dx / PAN_RATE));
center = Vec3.sum(center, dv);
position = Vec3.sum(position, dv);
Camera.setPosition(position);
Camera.setOrientation(orientationOf(vector));
}
function saveCameraState() {
oldMode = Camera.mode;
var oldPosition = Camera.getPosition();
Camera.mode = "independent";
Camera.setPosition(oldPosition);
oldMode = Camera.mode;
oldPosition = Camera.getPosition();
oldOrientation = Camera.getOrientation();
Camera.mode = "independent";
Camera.setPosition(oldPosition);
}
function restoreCameraState() {
Camera.mode = oldMode;
Camera.mode = oldMode;
Camera.setPosition(oldPosition);
Camera.setOrientation(oldOrientation);
}
function handleModes() {
var newMode = (mode == noMode) ? noMode : detachedMode;
if (alt) {
if (control) {
if (shift) {
newMode = panningMode;
} else {
newMode = orbitMode;
}
} else {
newMode = radialMode;
}
}
// if entering detachMode
if (newMode == detachedMode && mode != detachedMode) {
avatarPosition = MyAvatar.position;
avatarOrientation = MyAvatar.orientation;
}
// if leaving detachMode
if (mode == detachedMode && newMode == detachedMode &&
(avatarPosition.x != MyAvatar.position.x ||
avatarPosition.y != MyAvatar.position.y ||
avatarPosition.z != MyAvatar.position.z ||
avatarOrientation.x != MyAvatar.orientation.x ||
avatarOrientation.y != MyAvatar.orientation.y ||
avatarOrientation.z != MyAvatar.orientation.z ||
avatarOrientation.w != MyAvatar.orientation.w)) {
newMode = noMode;
var newMode = (mode == noMode) ? noMode : detachedMode;
if (alt) {
if (control) {
if (shift) {
newMode = panningMode;
} else {
newMode = orbitMode;
}
} else {
newMode = radialMode;
}
}
if (mode == noMode && newMode != noMode && Camera.mode == "independent") {
newMode = noMode;
}
// if entering detachMode
if (newMode == detachedMode && mode != detachedMode) {
avatarPosition = MyAvatar.position;
avatarOrientation = MyAvatar.orientation;
}
// if leaving detachMode
if (mode == detachedMode && newMode == detachedMode &&
(avatarPosition.x != MyAvatar.position.x ||
avatarPosition.y != MyAvatar.position.y ||
avatarPosition.z != MyAvatar.position.z ||
avatarOrientation.x != MyAvatar.orientation.x ||
avatarOrientation.y != MyAvatar.orientation.y ||
avatarOrientation.z != MyAvatar.orientation.z ||
avatarOrientation.w != MyAvatar.orientation.w)) {
newMode = noMode;
}
// if leaving noMode
if (mode == noMode && newMode != noMode) {
saveCameraState();
}
// if entering noMode
if (newMode == noMode && mode != noMode) {
restoreCameraState();
}
mode = newMode;
if (mode == noMode && newMode != noMode && Camera.mode == "independent") {
newMode = noMode;
}
// if leaving noMode
if (mode == noMode && newMode != noMode) {
saveCameraState();
}
// if entering noMode
if (newMode == noMode && mode != noMode) {
restoreCameraState();
}
mode = newMode;
}
function keyPressEvent(event) {
var changed = false;
if (event.text == "ALT") {
alt = true;
changed = true;
}
if (event.text == "CONTROL") {
control = true;
changed = true;
}
if (event.text == "SHIFT") {
shift = true;
changed = true;
}
if (changed) {
handleModes();
}
var changed = false;
if (event.text == "ALT") {
alt = true;
changed = true;
}
if (event.text == "CONTROL") {
control = true;
changed = true;
}
if (event.text == "SHIFT") {
shift = true;
changed = true;
}
if (changed) {
handleModes();
}
}
function keyReleaseEvent(event) {
var changed = false;
if (event.text == "ALT") {
alt = false;
changed = true;
}
if (event.text == "CONTROL") {
control = false;
changed = true;
}
if (event.text == "SHIFT") {
shift = false;
changed = true;
}
if (changed) {
handleModes();
}
var changed = false;
if (event.text == "ALT") {
alt = false;
changed = true;
mode = noMode;
restoreCameraState();
}
if (event.text == "CONTROL") {
control = false;
changed = true;
}
if (event.text == "SHIFT") {
shift = false;
changed = true;
}
if (changed) {
handleModes();
}
}
function mousePressEvent(event) {
if (alt && !isActive) {
mouseLastX = event.x;
mouseLastY = event.y;
// Compute trajectories related values
var pickRay = Camera.computePickRay(mouseLastX, mouseLastY);
var modelIntersection = Entities.findRayIntersection(pickRay);
position = Camera.getPosition();
var avatarTarget = MyAvatar.getTargetAvatarPosition();
var distance = -1;
var string;
if (modelIntersection.intersects && modelIntersection.accurate) {
distance = modelIntersection.distance;
center = modelIntersection.properties.position;
string = "Inspecting model";
}
if ((distance == -1 || Vec3.length(Vec3.subtract(avatarTarget, position)) < distance) &&
(avatarTarget.x != 0 || avatarTarget.y != 0 || avatarTarget.z != 0)) {
distance = Vec3.length(Vec3.subtract(avatarTarget, position));
center = avatarTarget;
string = "Inspecting avatar";
}
if (distance == -1) {
return;
}
vector = Vec3.subtract(position, center);
radius = Vec3.length(vector);
azimuth = Math.atan2(vector.z, vector.x);
altitude = Math.asin(vector.y / Vec3.length(vector));
print(string);
isActive = true;
if (alt && !isActive) {
mouseLastX = event.x;
mouseLastY = event.y;
// Compute trajectories related values
var pickRay = Camera.computePickRay(mouseLastX, mouseLastY);
var modelIntersection = Entities.findRayIntersection(pickRay, true);
position = Camera.getPosition();
var avatarTarget = MyAvatar.getTargetAvatarPosition();
var distance = -1;
var string;
if (modelIntersection.intersects && modelIntersection.accurate) {
distance = modelIntersection.distance;
center = modelIntersection.intersection;
string = "Inspecting model";
//We've selected our target, now orbit towards it automatically
rotatingTowardsTarget = true;
//calculate our target cam rotation
Script.setTimeout(function() {
rotatingTowardsTarget = false;
}, LOOK_AT_TIME);
vector = Vec3.subtract(position, center);
targetCamOrientation = orientationOf(vector);
radius = Vec3.length(vector);
azimuth = Math.atan2(vector.z, vector.x);
altitude = Math.asin(vector.y / Vec3.length(vector));
isActive = true;
}
}
}
function mouseReleaseEvent(event) {
if (isActive) {
isActive = false;
}
if (isActive) {
isActive = false;
}
}
function mouseMoveEvent(event) {
if (isActive && mode != noMode) {
if (mode == radialMode) {
handleRadialMode(event.x - mouseLastX, event.y - mouseLastY);
}
if (mode == orbitMode) {
handleOrbitMode(event.x - mouseLastX, event.y - mouseLastY);
}
if (mode == panningMode) {
handlePanMode(event.x - mouseLastX, event.y - mouseLastY);
}
mouseLastX = event.x;
mouseLastY = event.y;
if (isActive && mode != noMode && !rotatingTowardsTarget) {
if (mode == radialMode) {
handleRadialMode(event.x - mouseLastX, event.y - mouseLastY);
}
if (mode == orbitMode) {
handleOrbitMode(event.x - mouseLastX, event.y - mouseLastY);
}
if (mode == panningMode) {
handlePanMode(event.x - mouseLastX, event.y - mouseLastY);
}
}
mouseLastX = event.x;
mouseLastY = event.y;
}
function update() {
handleModes();
handleModes();
if (rotatingTowardsTarget) {
rotateTowardsTarget();
}
}
function rotateTowardsTarget() {
var newOrientation = Quat.mix(Camera.getOrientation(), targetCamOrientation, .1);
Camera.setOrientation(newOrientation);
}
function scriptEnding() {
if (mode != noMode) {
restoreCameraState();
}
if (mode != noMode) {
restoreCameraState();
}
}
Controller.keyPressEvent.connect(keyPressEvent);

View file

@ -1,77 +1,99 @@
var lineEntityID = null;
var lineIsRezzed = false;
var altHeld = false;
var lineCreated = false;
function nearLinePoint(targetPosition) {
var handPosition = MyAvatar.getRightPalmPosition();
var along = Vec3.subtract(targetPosition, handPosition);
along = Vec3.normalize(along);
along = Vec3.multiply(along, 0.4);
return Vec3.sum(handPosition, along);
var handPosition = MyAvatar.getRightPalmPosition();
var along = Vec3.subtract(targetPosition, handPosition);
along = Vec3.normalize(along);
along = Vec3.multiply(along, 0.4);
return Vec3.sum(handPosition, along);
}
function removeLine() {
if (lineIsRezzed) {
Entities.deleteEntity(lineEntityID);
lineEntityID = null;
lineIsRezzed = false;
}
if (lineIsRezzed) {
Entities.deleteEntity(lineEntityID);
lineEntityID = null;
lineIsRezzed = false;
}
}
function createOrUpdateLine(event) {
var pickRay = Camera.computePickRay(event.x, event.y);
var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking
var props = Entities.getEntityProperties(intersection.entityID);
var pickRay = Camera.computePickRay(event.x, event.y);
var intersection = Entities.findRayIntersection(pickRay, true); // accurate picking
var props = Entities.getEntityProperties(intersection.entityID);
if (intersection.intersects) {
var dim = Vec3.subtract(intersection.intersection, nearLinePoint(intersection.intersection));
if (lineIsRezzed) {
Entities.editEntity(lineEntityID, {
position: nearLinePoint(intersection.intersection),
dimensions: dim,
lifetime: 15 + props.lifespan // renew lifetime
});
} else {
lineIsRezzed = true;
lineEntityID = Entities.addEntity({
type: "Line",
position: nearLinePoint(intersection.intersection),
dimensions: dim,
color: { red: 255, green: 255, blue: 255 },
lifetime: 15 // if someone crashes while pointing, don't leave the line there forever.
});
}
if (intersection.intersects) {
var dim = Vec3.subtract(intersection.intersection, nearLinePoint(intersection.intersection));
if (lineIsRezzed) {
Entities.editEntity(lineEntityID, {
position: nearLinePoint(intersection.intersection),
dimensions: dim,
lifetime: 15 + props.lifespan // renew lifetime
});
} else {
removeLine();
lineIsRezzed = true;
lineEntityID = Entities.addEntity({
type: "Line",
position: nearLinePoint(intersection.intersection),
dimensions: dim,
color: {
red: 255,
green: 255,
blue: 255
},
lifetime: 15 // if someone crashes while pointing, don't leave the line there forever.
});
}
} else {
removeLine();
}
}
function mousePressEvent(event) {
if (!event.isLeftButton) {
return;
}
Controller.mouseMoveEvent.connect(mouseMoveEvent);
createOrUpdateLine(event);
}
if (!event.isLeftButton || altHeld) {
return;
}
Controller.mouseMoveEvent.connect(mouseMoveEvent);
createOrUpdateLine(event);
lineCreated = true;
}
function mouseMoveEvent(event) {
createOrUpdateLine(event);
createOrUpdateLine(event);
}
function mouseReleaseEvent(event) {
if (!event.isLeftButton) {
return;
}
Controller.mouseMoveEvent.disconnect(mouseMoveEvent);
removeLine();
if (!lineCreated) {
return;
}
Controller.mouseMoveEvent.disconnect(mouseMoveEvent);
removeLine();
lineCreated = false;
}
function keyPressEvent(event) {
if (event.text == "ALT") {
altHeld = true;
}
}
function keyReleaseEvent(event) {
if (event.text == "ALT") {
altHeld = false;
}
}
Controller.mousePressEvent.connect(mousePressEvent);
Controller.mouseReleaseEvent.connect(mouseReleaseEvent);
Controller.keyPressEvent.connect(keyPressEvent);
Controller.keyReleaseEvent.connect(keyReleaseEvent);

View file

@ -391,7 +391,7 @@ Application::Application(int& argc, char** argv, QElapsedTimer &startup_time) :
// emit checkBackgroundDownloads to cause the GeometryCache to check it's queue for requested background
// downloads.
QSharedPointer<GeometryCache> geometryCacheP = DependencyManager::get<GeometryCache>();
ResourceCache *geometryCache = geometryCacheP.data();
ResourceCache* geometryCache = geometryCacheP.data();
connect(this, &Application::checkBackgroundDownloads, geometryCache, &ResourceCache::checkAsynchronousGets);
// connect the DataProcessor processDatagrams slot to the QUDPSocket readyRead() signal
@ -3291,7 +3291,7 @@ void Application::displaySide(Camera& theCamera, bool selfAvatarOnly, RenderArgs
gpu::Batch batch;
model::Skybox::render(batch, _viewFrustum, *skybox);
gpu::GLBackend::renderBatch(batch);
gpu::GLBackend::renderBatch(batch, true);
glUseProgram(0);
}
}

View file

@ -38,6 +38,7 @@ static const QString DDE_PROGRAM_PATH = "/dde.app/Contents/MacOS/dde";
static const QStringList DDE_ARGUMENTS = QStringList()
<< "--udp=" + DDE_SERVER_ADDR.toString() + ":" + QString::number(DDE_SERVER_PORT)
<< "--receiver=" + QString::number(DDE_CONTROL_PORT)
<< "--facedet_interval=500" // ms
<< "--headless";
static const int NUM_EXPRESSIONS = 46;

View file

@ -126,8 +126,7 @@ void Cube3DOverlay::render(RenderArgs* args) {
} else {
glScalef(dimensions.x, dimensions.y, dimensions.z);
// FIXME Remove non Batch version of renderWireCube once we use the render pipeline
DependencyManager::get<DeferredLightingEffect>()->renderWireCube(1.0f, cubeColor);
DependencyManager::get<GeometryCache>()->renderWireCube(1.0f, cubeColor);
}
}
glPopMatrix();

View file

@ -510,7 +510,7 @@ void EntityTreeRenderer::render(RenderArgs::RenderMode renderMode,
_tree->unlock();
glPushMatrix();
gpu::GLBackend::renderBatch(batch);
gpu::GLBackend::renderBatch(batch, true);
glPopMatrix();
// stats...

View file

@ -51,9 +51,9 @@ void RenderableTextEntityItem::render(RenderArgs* args) {
// TODO: Determine if we want these entities to have the deferred lighting effect? I think we do, so that the color
// used for a sphere, or box have the same look as those used on a text entity.
DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram();
//DependencyManager::get<DeferredLightingEffect>()->bindSimpleProgram();
DependencyManager::get<GeometryCache>()->renderQuad(topLeft, bottomRight, glm::vec4(toGlm(getBackgroundColorX()), alpha));
DependencyManager::get<DeferredLightingEffect>()->releaseSimpleProgram();
//DependencyManager::get<DeferredLightingEffect>()->releaseSimpleProgram();
glTranslatef(-(halfDimensions.x - leftMargin), halfDimensions.y - topMargin, 0.0f);
glm::vec4 textColor(toGlm(getTextColorX()), alpha);

View file

@ -35,80 +35,80 @@ EntityPropertyList PROP_LAST_ITEM = (EntityPropertyList)(PROP_AFTER_LAST_ITEM -
EntityItemProperties::EntityItemProperties() :
CONSTRUCT_PROPERTY(visible, ENTITY_ITEM_DEFAULT_VISIBLE),
CONSTRUCT_PROPERTY(position, 0),
CONSTRUCT_PROPERTY(dimensions, ENTITY_ITEM_DEFAULT_DIMENSIONS),
CONSTRUCT_PROPERTY(rotation, ENTITY_ITEM_DEFAULT_ROTATION),
CONSTRUCT_PROPERTY(density, ENTITY_ITEM_DEFAULT_DENSITY),
CONSTRUCT_PROPERTY(velocity, ENTITY_ITEM_DEFAULT_VELOCITY),
CONSTRUCT_PROPERTY(gravity, ENTITY_ITEM_DEFAULT_GRAVITY),
CONSTRUCT_PROPERTY(acceleration, ENTITY_ITEM_DEFAULT_ACCELERATION),
CONSTRUCT_PROPERTY(damping, ENTITY_ITEM_DEFAULT_DAMPING),
CONSTRUCT_PROPERTY(restitution, ENTITY_ITEM_DEFAULT_RESTITUTION),
CONSTRUCT_PROPERTY(friction, ENTITY_ITEM_DEFAULT_FRICTION),
CONSTRUCT_PROPERTY(lifetime, ENTITY_ITEM_DEFAULT_LIFETIME),
CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT),
CONSTRUCT_PROPERTY(collisionSoundURL, ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL),
CONSTRUCT_PROPERTY(color, ),
CONSTRUCT_PROPERTY(modelURL, ""),
CONSTRUCT_PROPERTY(compoundShapeURL, ""),
CONSTRUCT_PROPERTY(animationURL, ""),
CONSTRUCT_PROPERTY(animationFPS, ModelEntityItem::DEFAULT_ANIMATION_FPS),
CONSTRUCT_PROPERTY(animationFrameIndex, ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX),
CONSTRUCT_PROPERTY(animationIsPlaying, ModelEntityItem::DEFAULT_ANIMATION_IS_PLAYING),
CONSTRUCT_PROPERTY(registrationPoint, ENTITY_ITEM_DEFAULT_REGISTRATION_POINT),
CONSTRUCT_PROPERTY(angularVelocity, ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY),
CONSTRUCT_PROPERTY(angularDamping, ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING),
CONSTRUCT_PROPERTY(ignoreForCollisions, ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS),
CONSTRUCT_PROPERTY(collisionsWillMove, ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE),
CONSTRUCT_PROPERTY(isSpotlight, false),
CONSTRUCT_PROPERTY(intensity, 1.0f),
CONSTRUCT_PROPERTY(exponent, 0.0f),
CONSTRUCT_PROPERTY(cutoff, ENTITY_ITEM_DEFAULT_CUTOFF),
CONSTRUCT_PROPERTY(locked, ENTITY_ITEM_DEFAULT_LOCKED),
CONSTRUCT_PROPERTY(textures, ""),
CONSTRUCT_PROPERTY(animationSettings, ""),
CONSTRUCT_PROPERTY(userData, ENTITY_ITEM_DEFAULT_USER_DATA),
CONSTRUCT_PROPERTY(simulatorID, ENTITY_ITEM_DEFAULT_SIMULATOR_ID),
CONSTRUCT_PROPERTY(text, TextEntityItem::DEFAULT_TEXT),
CONSTRUCT_PROPERTY(lineHeight, TextEntityItem::DEFAULT_LINE_HEIGHT),
CONSTRUCT_PROPERTY(textColor, TextEntityItem::DEFAULT_TEXT_COLOR),
CONSTRUCT_PROPERTY(backgroundColor, TextEntityItem::DEFAULT_BACKGROUND_COLOR),
CONSTRUCT_PROPERTY(shapeType, SHAPE_TYPE_NONE),
CONSTRUCT_PROPERTY(maxParticles, ParticleEffectEntityItem::DEFAULT_MAX_PARTICLES),
CONSTRUCT_PROPERTY(lifespan, ParticleEffectEntityItem::DEFAULT_LIFESPAN),
CONSTRUCT_PROPERTY(emitRate, ParticleEffectEntityItem::DEFAULT_EMIT_RATE),
CONSTRUCT_PROPERTY(emitDirection, ParticleEffectEntityItem::DEFAULT_EMIT_DIRECTION),
CONSTRUCT_PROPERTY(emitStrength, ParticleEffectEntityItem::DEFAULT_EMIT_STRENGTH),
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(name, ENTITY_ITEM_DEFAULT_NAME),
CONSTRUCT_PROPERTY(backgroundMode, BACKGROUND_MODE_INHERIT),
CONSTRUCT_PROPERTY(sourceUrl, ""),
CONSTRUCT_PROPERTY(visible, ENTITY_ITEM_DEFAULT_VISIBLE),
CONSTRUCT_PROPERTY(position, 0),
CONSTRUCT_PROPERTY(dimensions, ENTITY_ITEM_DEFAULT_DIMENSIONS),
CONSTRUCT_PROPERTY(rotation, ENTITY_ITEM_DEFAULT_ROTATION),
CONSTRUCT_PROPERTY(density, ENTITY_ITEM_DEFAULT_DENSITY),
CONSTRUCT_PROPERTY(velocity, ENTITY_ITEM_DEFAULT_VELOCITY),
CONSTRUCT_PROPERTY(gravity, ENTITY_ITEM_DEFAULT_GRAVITY),
CONSTRUCT_PROPERTY(acceleration, ENTITY_ITEM_DEFAULT_ACCELERATION),
CONSTRUCT_PROPERTY(damping, ENTITY_ITEM_DEFAULT_DAMPING),
CONSTRUCT_PROPERTY(restitution, ENTITY_ITEM_DEFAULT_RESTITUTION),
CONSTRUCT_PROPERTY(friction, ENTITY_ITEM_DEFAULT_FRICTION),
CONSTRUCT_PROPERTY(lifetime, ENTITY_ITEM_DEFAULT_LIFETIME),
CONSTRUCT_PROPERTY(script, ENTITY_ITEM_DEFAULT_SCRIPT),
CONSTRUCT_PROPERTY(collisionSoundURL, ENTITY_ITEM_DEFAULT_COLLISION_SOUND_URL),
CONSTRUCT_PROPERTY(color, ),
CONSTRUCT_PROPERTY(modelURL, ""),
CONSTRUCT_PROPERTY(compoundShapeURL, ""),
CONSTRUCT_PROPERTY(animationURL, ""),
CONSTRUCT_PROPERTY(animationFPS, ModelEntityItem::DEFAULT_ANIMATION_FPS),
CONSTRUCT_PROPERTY(animationFrameIndex, ModelEntityItem::DEFAULT_ANIMATION_FRAME_INDEX),
CONSTRUCT_PROPERTY(animationIsPlaying, ModelEntityItem::DEFAULT_ANIMATION_IS_PLAYING),
CONSTRUCT_PROPERTY(registrationPoint, ENTITY_ITEM_DEFAULT_REGISTRATION_POINT),
CONSTRUCT_PROPERTY(angularVelocity, ENTITY_ITEM_DEFAULT_ANGULAR_VELOCITY),
CONSTRUCT_PROPERTY(angularDamping, ENTITY_ITEM_DEFAULT_ANGULAR_DAMPING),
CONSTRUCT_PROPERTY(ignoreForCollisions, ENTITY_ITEM_DEFAULT_IGNORE_FOR_COLLISIONS),
CONSTRUCT_PROPERTY(collisionsWillMove, ENTITY_ITEM_DEFAULT_COLLISIONS_WILL_MOVE),
CONSTRUCT_PROPERTY(isSpotlight, false),
CONSTRUCT_PROPERTY(intensity, 1.0f),
CONSTRUCT_PROPERTY(exponent, 0.0f),
CONSTRUCT_PROPERTY(cutoff, ENTITY_ITEM_DEFAULT_CUTOFF),
CONSTRUCT_PROPERTY(locked, ENTITY_ITEM_DEFAULT_LOCKED),
CONSTRUCT_PROPERTY(textures, ""),
CONSTRUCT_PROPERTY(animationSettings, ""),
CONSTRUCT_PROPERTY(userData, ENTITY_ITEM_DEFAULT_USER_DATA),
CONSTRUCT_PROPERTY(simulatorID, ENTITY_ITEM_DEFAULT_SIMULATOR_ID),
CONSTRUCT_PROPERTY(text, TextEntityItem::DEFAULT_TEXT),
CONSTRUCT_PROPERTY(lineHeight, TextEntityItem::DEFAULT_LINE_HEIGHT),
CONSTRUCT_PROPERTY(textColor, TextEntityItem::DEFAULT_TEXT_COLOR),
CONSTRUCT_PROPERTY(backgroundColor, TextEntityItem::DEFAULT_BACKGROUND_COLOR),
CONSTRUCT_PROPERTY(shapeType, SHAPE_TYPE_NONE),
CONSTRUCT_PROPERTY(maxParticles, ParticleEffectEntityItem::DEFAULT_MAX_PARTICLES),
CONSTRUCT_PROPERTY(lifespan, ParticleEffectEntityItem::DEFAULT_LIFESPAN),
CONSTRUCT_PROPERTY(emitRate, ParticleEffectEntityItem::DEFAULT_EMIT_RATE),
CONSTRUCT_PROPERTY(emitDirection, ParticleEffectEntityItem::DEFAULT_EMIT_DIRECTION),
CONSTRUCT_PROPERTY(emitStrength, ParticleEffectEntityItem::DEFAULT_EMIT_STRENGTH),
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(name, ENTITY_ITEM_DEFAULT_NAME),
CONSTRUCT_PROPERTY(backgroundMode, BACKGROUND_MODE_INHERIT),
CONSTRUCT_PROPERTY(sourceUrl, ""),
_id(UNKNOWN_ENTITY_ID),
_idSet(false),
_lastEdited(0),
_created(UNKNOWN_CREATED_TIME),
_type(EntityTypes::Unknown),
_id(UNKNOWN_ENTITY_ID),
_idSet(false),
_lastEdited(0),
_created(UNKNOWN_CREATED_TIME),
_type(EntityTypes::Unknown),
_glowLevel(0.0f),
_localRenderAlpha(1.0f),
_glowLevel(0.0f),
_localRenderAlpha(1.0f),
_glowLevelChanged(false),
_localRenderAlphaChanged(false),
_glowLevelChanged(false),
_localRenderAlphaChanged(false),
_defaultSettings(true),
_naturalDimensions(1.0f, 1.0f, 1.0f)
_defaultSettings(true),
_naturalDimensions(1.0f, 1.0f, 1.0f)
{
}
EntityItemProperties::~EntityItemProperties() {
EntityItemProperties::~EntityItemProperties() {
}
void EntityItemProperties::setSittingPoints(const QVector<SittingPoint>& sittingPoints) {
@ -118,11 +118,11 @@ void EntityItemProperties::setSittingPoints(const QVector<SittingPoint>& sitting
}
}
void EntityItemProperties::setAnimationSettings(const QString& value) {
void EntityItemProperties::setAnimationSettings(const QString& value) {
// the animations setting is a JSON string that may contain various animation settings.
// if it includes fps, frameIndex, or running, those values will be parsed out and
// will over ride the regular animation settings
QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8());
QJsonObject settingsAsJsonObject = settingsAsJson.object();
QVariantMap settingsMap = settingsAsJsonObject.toVariantMap();
@ -130,37 +130,37 @@ void EntityItemProperties::setAnimationSettings(const QString& value) {
float fps = settingsMap["fps"].toFloat();
setAnimationFPS(fps);
}
if (settingsMap.contains("frameIndex")) {
float frameIndex = settingsMap["frameIndex"].toFloat();
setAnimationFrameIndex(frameIndex);
}
if (settingsMap.contains("running")) {
bool running = settingsMap["running"].toBool();
setAnimationIsPlaying(running);
}
_animationSettings = value;
_animationSettingsChanged = true;
_animationSettings = value;
_animationSettingsChanged = true;
}
QString EntityItemProperties::getAnimationSettings() const {
QString EntityItemProperties::getAnimationSettings() const {
// the animations setting is a JSON string that may contain various animation settings.
// if it includes fps, frameIndex, or running, those values will be parsed out and
// will over ride the regular animation settings
QString value = _animationSettings;
QJsonDocument settingsAsJson = QJsonDocument::fromJson(value.toUtf8());
QJsonObject settingsAsJsonObject = settingsAsJson.object();
QVariantMap settingsMap = settingsAsJsonObject.toVariantMap();
QVariant fpsValue(getAnimationFPS());
settingsMap["fps"] = fpsValue;
QVariant frameIndexValue(getAnimationFrameIndex());
settingsMap["frameIndex"] = frameIndexValue;
QVariant runningValue(getAnimationIsPlaying());
settingsMap["running"] = runningValue;
@ -180,28 +180,28 @@ void EntityItemProperties::debugDump() const {
qCDebug(entities) << " _dimensions=" << getDimensions();
qCDebug(entities) << " _modelURL=" << _modelURL;
qCDebug(entities) << " _compoundShapeURL=" << _compoundShapeURL;
getAtmosphere().debugDump();
getSkybox().debugDump();
qCDebug(entities) << " changed properties...";
EntityPropertyFlags props = getChangedProperties();
props.debugDumpBits();
}
void EntityItemProperties::setCreated(quint64 usecTime) {
_created = usecTime;
void EntityItemProperties::setCreated(quint64 usecTime) {
_created = usecTime;
if (_lastEdited < _created) {
_lastEdited = _created;
}
}
void EntityItemProperties::setLastEdited(quint64 usecTime) {
_lastEdited = usecTime > _created ? usecTime : _created;
void EntityItemProperties::setLastEdited(quint64 usecTime) {
_lastEdited = usecTime > _created ? usecTime : _created;
}
const char* shapeTypeNames[] = {"none", "box", "sphere", "ellipsoid", "plane", "compound", "capsule-x",
"capsule-y", "capsule-z", "cylinder-x", "cylinder-y", "cylinder-z"};
"capsule-y", "capsule-z", "cylinder-x", "cylinder-y", "cylinder-z"};
QHash<QString, ShapeType> stringToShapeTypeLookup;
@ -336,22 +336,22 @@ EntityPropertyFlags EntityItemProperties::getChangedProperties() const {
CHECK_PROPERTY_CHANGE(PROP_KEYLIGHT_DIRECTION, keyLightDirection);
CHECK_PROPERTY_CHANGE(PROP_BACKGROUND_MODE, backgroundMode);
CHECK_PROPERTY_CHANGE(PROP_SOURCE_URL, sourceUrl);
changedProperties += _stage.getChangedProperties();
changedProperties += _atmosphere.getChangedProperties();
changedProperties += _skybox.getChangedProperties();
return changedProperties;
}
QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool skipDefaults) const {
QScriptValue properties = engine->newObject();
EntityItemProperties defaultEntityProperties;
if (_idSet) {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(id, _id.toString());
}
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(type, EntityTypes::getEntityTypeName(_type));
COPY_PROPERTY_TO_QSCRIPTVALUE(position);
COPY_PROPERTY_TO_QSCRIPTVALUE(dimensions);
@ -411,14 +411,14 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
COPY_PROPERTY_TO_QSCRIPTVALUE(marketplaceID);
COPY_PROPERTY_TO_QSCRIPTVALUE(name);
COPY_PROPERTY_TO_QSCRIPTVALUE(collisionSoundURL);
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightColor);
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightIntensity);
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightAmbientIntensity);
COPY_PROPERTY_TO_QSCRIPTVALUE(keyLightDirection);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(backgroundMode, getBackgroundModeAsString());
COPY_PROPERTY_TO_QSCRIPTVALUE(sourceUrl);
// Sitting properties support
if (!skipDefaults) {
QScriptValue sittingPoints = engine->newObject();
@ -432,7 +432,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
sittingPoints.setProperty("length", _sittingPoints.size());
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER(sittingPoints, sittingPoints); // gettable, but not settable
}
if (!skipDefaults) {
AABox aaBox = getAABox();
QScriptValue boundingBox = engine->newObject();
@ -446,7 +446,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
boundingBox.setProperty("dimensions", boundingBoxDimensions);
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(boundingBox, boundingBox); // gettable, but not settable
}
QString textureNamesList = _textureNames.join(",\n");
if (!skipDefaults) {
COPY_PROPERTY_TO_QSCRIPTVALUE_GETTER_NO_SKIP(originalTextures, textureNamesList); // gettable, but not settable
@ -455,7 +455,7 @@ QScriptValue EntityItemProperties::copyToScriptValue(QScriptEngine* engine, bool
_stage.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties);
_atmosphere.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties);
_skybox.copyToScriptValue(properties, engine, skipDefaults, defaultEntityProperties);
return properties;
}
@ -464,7 +464,7 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
if (typeScriptValue.isValid()) {
setType(typeScriptValue.toVariant().toString());
}
COPY_PROPERTY_FROM_QSCRIPTVALUE(position, glmVec3, setPosition);
COPY_PROPERTY_FROM_QSCRIPTVALUE(dimensions, glmVec3, setDimensions);
COPY_PROPERTY_FROM_QSCRIPTVALUE(rotation, glmQuat, setRotation);
@ -516,14 +516,14 @@ void EntityItemProperties::copyFromScriptValue(const QScriptValue& object) {
COPY_PROPERTY_FROM_QSCRIPTVALUE(marketplaceID, QString, setMarketplaceID);
COPY_PROPERTY_FROM_QSCRIPTVALUE(name, QString, setName);
COPY_PROPERTY_FROM_QSCRIPTVALUE(collisionSoundURL, QString, setCollisionSoundURL);
COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightColor, xColor, setKeyLightColor);
COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightIntensity, float, setKeyLightIntensity);
COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightAmbientIntensity, float, setKeyLightAmbientIntensity);
COPY_PROPERTY_FROM_QSCRIPTVALUE(keyLightDirection, glmVec3, setKeyLightDirection);
COPY_PROPERTY_FROM_QSCRITPTVALUE_ENUM(backgroundMode, BackgroundMode);
COPY_PROPERTY_FROM_QSCRIPTVALUE(sourceUrl, QString, setSourceUrl);
_stage.copyFromScriptValue(object, _defaultSettings);
_atmosphere.copyFromScriptValue(object, _defaultSettings);
_skybox.copyFromScriptValue(object, _defaultSettings);
@ -542,8 +542,8 @@ void EntityItemPropertiesFromScriptValue(const QScriptValue &object, EntityItemP
properties.copyFromScriptValue(object);
}
// TODO: Implement support for edit packets that can span an MTU sized buffer. We need to implement a mechanism for the
// encodeEntityEditPacket() method to communicate the the caller which properties couldn't fit in the buffer. Similar
// TODO: Implement support for edit packets that can span an MTU sized buffer. We need to implement a mechanism for the
// encodeEntityEditPacket() method to communicate the the caller which properties couldn't fit in the buffer. Similar
// to how we handle this in the Octree streaming case.
//
// TODO: Right now, all possible properties for all subclasses are handled here. Ideally we'd prefer
@ -561,11 +561,11 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
unsigned char* bufferOut, int sizeIn, int& sizeOut) {
OctreePacketData ourDataPacket(false, sizeIn); // create a packetData object to add out packet details too.
OctreePacketData* packetData = &ourDataPacket; // we want a pointer to this so we can use our APPEND_ENTITY_PROPERTY macro
bool success = true; // assume the best
OctreeElement::AppendState appendState = OctreeElement::COMPLETED; // assume the best
sizeOut = 0;
// TODO: We need to review how jurisdictions should be handled for entities. (The old Models and Particles code
// didn't do anything special for jurisdictions, so we're keeping that same behavior here.)
//
@ -575,35 +575,35 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
glm::vec3 rootPosition(0);
float rootScale = 0.5f;
unsigned char* octcode = pointToOctalCode(rootPosition.x, rootPosition.y, rootPosition.z, rootScale);
success = packetData->startSubTree(octcode);
delete[] octcode;
// assuming we have rome to fit our octalCode, proceed...
if (success) {
// Now add our edit content details...
// id
// encode our ID as a byte count coded byte stream
QByteArray encodedID = id.toRfc4122(); // NUM_BYTES_RFC4122_UUID
// encode our ID as a byte count coded byte stream
ByteCountCoded<quint32> tokenCoder;
QByteArray encodedToken;
// encode our type as a byte count coded byte stream
ByteCountCoded<quint32> typeCoder = (quint32)properties.getType();
QByteArray encodedType = typeCoder;
quint64 updateDelta = 0; // this is an edit so by definition, it's update is in sync
ByteCountCoded<quint64> updateDeltaCoder = updateDelta;
QByteArray encodedUpdateDelta = updateDeltaCoder;
EntityPropertyFlags propertyFlags(PROP_LAST_ITEM);
EntityPropertyFlags requestedProperties = properties.getChangedProperties();
EntityPropertyFlags propertiesDidntFit = requestedProperties;
// TODO: we need to handle the multi-pass form of this, similar to how we handle entity data
//
// If we are being called for a subsequent pass at appendEntityData() that failed to completely encode this item,
@ -611,46 +611,46 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
//if (modelTreeElementExtraEncodeData && modelTreeElementExtraEncodeData->includedItems.contains(getEntityItemID())) {
// requestedProperties = modelTreeElementExtraEncodeData->includedItems.value(getEntityItemID());
//}
LevelDetails entityLevel = packetData->startLevel();
// Last Edited quint64 always first, before any other details, which allows us easy access to adjusting this
// timestamp for clock skew
quint64 lastEdited = properties.getLastEdited();
bool successLastEditedFits = packetData->appendValue(lastEdited);
bool successIDFits = packetData->appendValue(encodedID);
if (successIDFits) {
successIDFits = packetData->appendValue(encodedToken);
}
bool successTypeFits = packetData->appendValue(encodedType);
// NOTE: We intentionally do not send "created" times in edit messages. This is because:
// 1) if the edit is to an existing entity, the created time can not be changed
// 2) if the edit is to a new entity, the created time is the last edited time
// TODO: Should we get rid of this in this in edit packets, since this has to always be 0?
bool successLastUpdatedFits = packetData->appendValue(encodedUpdateDelta);
int propertyFlagsOffset = packetData->getUncompressedByteOffset();
QByteArray encodedPropertyFlags = propertyFlags;
int oldPropertyFlagsLength = encodedPropertyFlags.length();
bool successPropertyFlagsFits = packetData->appendValue(encodedPropertyFlags);
int propertyCount = 0;
bool headerFits = successIDFits && successTypeFits && successLastEditedFits
&& successLastUpdatedFits && successPropertyFlagsFits;
&& successLastUpdatedFits && successPropertyFlagsFits;
int startOfEntityItemData = packetData->getUncompressedByteOffset();
if (headerFits) {
bool successPropertyFits;
propertyFlags -= PROP_LAST_ITEM; // clear the last item for now, we may or may not set it as the actual item
// These items would go here once supported....
// PROP_PAGED_PROPERTY,
// PROP_CUSTOM_PROPERTIES_INCLUDED,
APPEND_ENTITY_PROPERTY(PROP_POSITION, properties.getPosition());
APPEND_ENTITY_PROPERTY(PROP_DIMENSIONS, properties.getDimensions()); // NOTE: PROP_RADIUS obsolete
APPEND_ENTITY_PROPERTY(PROP_ROTATION, properties.getRotation());
@ -677,7 +677,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
if (properties.getType() == EntityTypes::Web) {
APPEND_ENTITY_PROPERTY(PROP_SOURCE_URL, properties.getSourceUrl());
}
if (properties.getType() == EntityTypes::Text) {
APPEND_ENTITY_PROPERTY(PROP_TEXT, properties.getText());
APPEND_ENTITY_PROPERTY(PROP_LINE_HEIGHT, properties.getLineHeight());
@ -696,7 +696,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, properties.getAnimationSettings());
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)(properties.getShapeType()));
}
if (properties.getType() == EntityTypes::Light) {
APPEND_ENTITY_PROPERTY(PROP_IS_SPOTLIGHT, properties.getIsSpotlight());
APPEND_ENTITY_PROPERTY(PROP_COLOR, properties.getColor());
@ -704,8 +704,13 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
APPEND_ENTITY_PROPERTY(PROP_EXPONENT, properties.getExponent());
APPEND_ENTITY_PROPERTY(PROP_CUTOFF, properties.getCutoff());
}
if (properties.getType() == EntityTypes::ParticleEffect) {
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FPS, properties.getAnimationFPS());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_FRAME_INDEX, properties.getAnimationFrameIndex());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_PLAYING, properties.getAnimationIsPlaying());
APPEND_ENTITY_PROPERTY(PROP_ANIMATION_SETTINGS, properties.getAnimationSettings());
APPEND_ENTITY_PROPERTY(PROP_TEXTURES, properties.getTextures());
APPEND_ENTITY_PROPERTY(PROP_MAX_PARTICLES, properties.getMaxParticles());
APPEND_ENTITY_PROPERTY(PROP_LIFESPAN, properties.getLifespan());
APPEND_ENTITY_PROPERTY(PROP_EMIT_RATE, properties.getEmitRate());
@ -714,24 +719,24 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
APPEND_ENTITY_PROPERTY(PROP_LOCAL_GRAVITY, properties.getLocalGravity());
APPEND_ENTITY_PROPERTY(PROP_PARTICLE_RADIUS, properties.getParticleRadius());
}
if (properties.getType() == EntityTypes::Zone) {
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_COLOR, properties.getKeyLightColor());
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_INTENSITY, properties.getKeyLightIntensity());
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_AMBIENT_INTENSITY, properties.getKeyLightAmbientIntensity());
APPEND_ENTITY_PROPERTY(PROP_KEYLIGHT_DIRECTION, properties.getKeyLightDirection());
_staticStage.setProperties(properties);
_staticStage.appentToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState );
APPEND_ENTITY_PROPERTY(PROP_SHAPE_TYPE, (uint32_t)properties.getShapeType());
APPEND_ENTITY_PROPERTY(PROP_COMPOUND_SHAPE_URL, properties.getCompoundShapeURL());
APPEND_ENTITY_PROPERTY(PROP_BACKGROUND_MODE, (uint32_t)properties.getBackgroundMode());
_staticAtmosphere.setProperties(properties);
_staticAtmosphere.appentToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState );
_staticSkybox.setProperties(properties);
_staticSkybox.appentToEditPacket(packetData, requestedProperties, propertyFlags, propertiesDidntFit, propertyCount, appendState );
}
@ -742,41 +747,41 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
}
if (propertyCount > 0) {
int endOfEntityItemData = packetData->getUncompressedByteOffset();
encodedPropertyFlags = propertyFlags;
int newPropertyFlagsLength = encodedPropertyFlags.length();
packetData->updatePriorBytes(propertyFlagsOffset,
(const unsigned char*)encodedPropertyFlags.constData(), encodedPropertyFlags.length());
packetData->updatePriorBytes(propertyFlagsOffset,
(const unsigned char*)encodedPropertyFlags.constData(), encodedPropertyFlags.length());
// if the size of the PropertyFlags shrunk, we need to shift everything down to front of packet.
if (newPropertyFlagsLength < oldPropertyFlagsLength) {
int oldSize = packetData->getUncompressedSize();
const unsigned char* modelItemData = packetData->getUncompressedData(propertyFlagsOffset + oldPropertyFlagsLength);
int modelItemDataLength = endOfEntityItemData - startOfEntityItemData;
int newEntityItemDataStart = propertyFlagsOffset + newPropertyFlagsLength;
packetData->updatePriorBytes(newEntityItemDataStart, modelItemData, modelItemDataLength);
int newSize = oldSize - (oldPropertyFlagsLength - newPropertyFlagsLength);
packetData->setUncompressedSize(newSize);
} else {
assert(newPropertyFlagsLength == oldPropertyFlagsLength); // should not have grown
}
packetData->endLevel(entityLevel);
} else {
packetData->discardLevel(entityLevel);
appendState = OctreeElement::NONE; // if we got here, then we didn't include the item
}
// If any part of the model items didn't fit, then the element is considered partial
if (appendState != OctreeElement::COMPLETED) {
// TODO: handle mechanism for handling partial fitting data!
// add this item into our list for the next appendElementData() pass
//modelTreeElementExtraEncodeData->includedItems.insert(getEntityItemID(), propertiesDidntFit);
// for now, if it's not complete, it's not successful
success = false;
}
@ -801,7 +806,7 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
return success;
}
// TODO:
// TODO:
// how to handle lastEdited?
// how to handle lastUpdated?
// consider handling case where no properties are included... we should just ignore this packet...
@ -820,15 +825,15 @@ bool EntityItemProperties::encodeEntityEditPacket(PacketType command, EntityItem
bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int bytesToRead, int& processedBytes,
EntityItemID& entityID, EntityItemProperties& properties) {
bool valid = false;
const unsigned char* dataAt = data;
processedBytes = 0;
// the first part of the data is an octcode, this is a required element of the edit packet format, but we don't
// actually use it, we do need to skip it and read to the actual data we care about.
int octets = numberOfThreeBitSectionsInCode(data);
int bytesToReadOfOctcode = bytesRequiredForCodeLength(octets);
// we don't actually do anything with this octcode...
dataAt += bytesToReadOfOctcode;
processedBytes += bytesToReadOfOctcode;
@ -841,20 +846,20 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
dataAt += sizeof(lastEdited);
processedBytes += sizeof(lastEdited);
properties.setLastEdited(lastEdited);
// NOTE: We intentionally do not send "created" times in edit messages. This is because:
// 1) if the edit is to an existing entity, the created time can not be changed
// 2) if the edit is to a new entity, the created time is the last edited time
// encoded id
QByteArray encodedID((const char*)dataAt, NUM_BYTES_RFC4122_UUID); // maximum possible size
QUuid editID = QUuid::fromRfc4122(encodedID);
dataAt += encodedID.size();
processedBytes += encodedID.size();
entityID = editID;
valid = true;
// Entity Type...
QByteArray encodedType((const char*)dataAt, (bytesToRead - processedBytes));
ByteCountCoded<quint32> typeCoder = encodedType;
@ -863,18 +868,18 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
encodedType = typeCoder; // determine true bytesToRead
dataAt += encodedType.size();
processedBytes += encodedType.size();
// Update Delta - when was this item updated relative to last edit... this really should be 0
// TODO: Should we get rid of this in this in edit packets, since this has to always be 0?
// TODO: do properties need to handle lastupdated???
// last updated is stored as ByteCountCoded delta from lastEdited
QByteArray encodedUpdateDelta((const char*)dataAt, (bytesToRead - processedBytes));
ByteCountCoded<quint64> updateDeltaCoder = encodedUpdateDelta;
encodedUpdateDelta = updateDeltaCoder; // determine true bytesToRead
dataAt += encodedUpdateDelta.size();
processedBytes += encodedUpdateDelta.size();
// TODO: Do we need this lastUpdated?? We don't seem to use it.
//quint64 updateDelta = updateDeltaCoder;
//quint64 lastUpdated = lastEdited + updateDelta; // don't adjust for clock skew since we already did that for lastEdited
@ -884,7 +889,7 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
EntityPropertyFlags propertyFlags = encodedPropertyFlags;
dataAt += propertyFlags.getEncodedLength();
processedBytes += propertyFlags.getEncodedLength();
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_POSITION, glm::vec3, setPosition);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_DIMENSIONS, glm::vec3, setDimensions); // NOTE: PROP_RADIUS obsolete
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ROTATION, glm::quat, setRotation);
@ -907,11 +912,11 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LOCKED, bool, setLocked);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_USER_DATA, QString, setUserData);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SIMULATOR_ID, QUuid, setSimulatorID);
if (properties.getType() == EntityTypes::Web) {
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SOURCE_URL, QString, setSourceUrl);
}
if (properties.getType() == EntityTypes::Text) {
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXT, QString, setText);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LINE_HEIGHT, float, setLineHeight);
@ -938,8 +943,14 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EXPONENT, float, setExponent);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_CUTOFF, float, setCutoff);
}
if (properties.getType() == EntityTypes::ParticleEffect) {
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FPS, float, setAnimationFPS);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_FRAME_INDEX, float, setAnimationFrameIndex);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_PLAYING, bool, setAnimationIsPlaying);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_ANIMATION_SETTINGS, QString, setAnimationSettings);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_TEXTURES, QString, setTextures);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MAX_PARTICLES, float, setMaxParticles);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_LIFESPAN, float, setLifespan);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_EMIT_RATE, float, setEmitRate);
@ -948,15 +959,15 @@ 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_TO_PROPERTIES(PROP_KEYLIGHT_COLOR, xColor, 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);
properties.getStage().decodeFromEditPacket(propertyFlags, dataAt , processedBytes);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_SHAPE_TYPE, ShapeType, setShapeType);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COMPOUND_SHAPE_URL, QString, setCompoundShapeURL);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_BACKGROUND_MODE, BackgroundMode, setBackgroundMode);
@ -967,20 +978,20 @@ bool EntityItemProperties::decodeEntityEditPacket(const unsigned char* data, int
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_MARKETPLACE_ID, QString, setMarketplaceID);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_NAME, QString, setName);
READ_ENTITY_PROPERTY_TO_PROPERTIES(PROP_COLLISION_SOUND_URL, QString, setCollisionSoundURL);
return valid;
}
// NOTE: This version will only encode the portion of the edit message immediately following the
// header it does not include the send times and sequence number because that is handled by the
// header it does not include the send times and sequence number because that is handled by the
// edit packet sender...
bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityItemID,
bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityItemID,
unsigned char* outputBuffer, size_t maxLength, size_t& outputLength) {
unsigned char* copyAt = outputBuffer;
uint16_t numberOfIds = 1; // only one entity ID in this message
if (maxLength < sizeof(numberOfIds) + NUM_BYTES_RFC4122_UUID) {
qCDebug(entities) << "ERROR - encodeEraseEntityMessage() called with buffer that is too small!";
outputLength = 0;
@ -989,14 +1000,14 @@ bool EntityItemProperties::encodeEraseEntityMessage(const EntityItemID& entityIt
memcpy(copyAt, &numberOfIds, sizeof(numberOfIds));
copyAt += sizeof(numberOfIds);
outputLength = sizeof(numberOfIds);
QUuid entityID = entityItemID;
QByteArray encodedEntityID = entityID.toRfc4122();
memcpy(copyAt, encodedEntityID.constData(), NUM_BYTES_RFC4122_UUID);
copyAt += NUM_BYTES_RFC4122_UUID;
outputLength += NUM_BYTES_RFC4122_UUID;
return true;
}
@ -1034,7 +1045,7 @@ void EntityItemProperties::markAllChanged() {
_isSpotlightChanged = true;
_ignoreForCollisionsChanged = true;
_collisionsWillMoveChanged = true;
_intensityChanged = true;
_exponentChanged = true;
_cutoffChanged = true;
@ -1046,7 +1057,7 @@ void EntityItemProperties::markAllChanged() {
_textColorChanged = true;
_backgroundColorChanged = true;
_shapeTypeChanged = true;
_maxParticlesChanged = true;
_lifespanChanged = true;
_emitRateChanged = true;
@ -1056,7 +1067,7 @@ void EntityItemProperties::markAllChanged() {
_particleRadiusChanged = true;
_marketplaceIDChanged = true;
_keyLightColorChanged = true;
_keyLightIntensityChanged = true;
_keyLightAmbientIntensityChanged = true;
@ -1066,39 +1077,39 @@ void EntityItemProperties::markAllChanged() {
_stage.markAllChanged();
_atmosphere.markAllChanged();
_skybox.markAllChanged();
_sourceUrlChanged = true;
}
/// The maximum bounding cube for the entity, independent of it's rotation.
/// This accounts for the registration point (upon which rotation occurs around).
///
AACube EntityItemProperties::getMaximumAACube() const {
///
AACube EntityItemProperties::getMaximumAACube() const {
// * we know that the position is the center of rotation
glm::vec3 centerOfRotation = _position; // also where _registration point is
// * we know that the registration point is the center of rotation
// * we can calculate the length of the furthest extent from the registration point
// as the dimensions * max (registrationPoint, (1.0,1.0,1.0) - registrationPoint)
glm::vec3 registrationPoint = (_dimensions * _registrationPoint);
glm::vec3 registrationRemainder = (_dimensions * (glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint));
glm::vec3 furthestExtentFromRegistration = glm::max(registrationPoint, registrationRemainder);
// * we know that if you rotate in any direction you would create a sphere
// that has a radius of the length of furthest extent from registration point
float radius = glm::length(furthestExtentFromRegistration);
// * we know that the minimum bounding cube of this maximum possible sphere is
// (center - radius) to (center + radius)
glm::vec3 minimumCorner = centerOfRotation - glm::vec3(radius, radius, radius);
float diameter = radius * 2.0f;
return AACube(minimumCorner, diameter);
}
// The minimum bounding box for the entity.
AABox EntityItemProperties::getAABox() const {
AABox EntityItemProperties::getAABox() const {
// _position represents the position of the registration point.
glm::vec3 registrationRemainder = glm::vec3(1.0f, 1.0f, 1.0f) - _registrationPoint;

View file

@ -76,12 +76,10 @@ GLBackend::GLBackend() :
_output()
{
initTransform();
initInput();
}
GLBackend::~GLBackend() {
killTransform();
killInput();
}
void GLBackend::render(Batch& batch) {
@ -98,8 +96,11 @@ void GLBackend::render(Batch& batch) {
}
}
void GLBackend::renderBatch(Batch& batch) {
void GLBackend::renderBatch(Batch& batch, bool syncCache) {
GLBackend backend;
if (syncCache) {
backend.syncCache();
}
backend.render(batch);
}
@ -136,6 +137,13 @@ bool GLBackend::checkGLError(const char* name) {
}
}
void GLBackend::syncCache() {
syncTransformStateCache();
syncPipelineStateCache();
syncInputStateCache();
}
void GLBackend::do_draw(Batch& batch, uint32 paramOffset) {
updateInput();
updateTransform();
@ -549,4 +557,3 @@ void GLBackend::fetchMatrix(GLenum target, glm::mat4 & m) {
}

View file

@ -24,12 +24,20 @@ namespace gpu {
class GLBackend : public Backend {
public:
explicit GLBackend(bool syncCache);
GLBackend();
~GLBackend();
void render(Batch& batch);
static void renderBatch(Batch& batch);
// Render Batch create a local Context and execute the batch with it
// WARNING:
// if syncCache is true, then the gpu::GLBackend will synchornize
// its cache with the current gl state and it's BAD
// If you know you don't rely on any state changed by naked gl calls then
// leave to false where it belongs
// if true, the needed resync IS EXPENSIVE
static void renderBatch(Batch& batch, bool syncCache = false);
static bool checkGLError(const char* name = nullptr);
@ -79,6 +87,7 @@ public:
static GLShader* syncGPUObject(const Shader& shader);
static GLuint getShaderID(const ShaderPointer& shader);
// FIXME: Please remove these 2 calls once the text renderer doesn't use naked gl calls anymore
static void loadMatrix(GLenum target, const glm::mat4 & m);
static void fetchMatrix(GLenum target, glm::mat4 & m);
@ -186,6 +195,12 @@ public:
void do_setStateColorWriteMask(uint32 mask);
// This call synchronize the Full Backend cache with the current GLState
// THis is only intended to be used when mixing raw gl calls with the gpu api usage in order to sync
// the gpu::Backend state with the true gl state which has probably been messed up by these ugly naked gl calls
// Let's try to avoid to do that as much as possible!
void syncCache();
protected:
// Draw Stage
@ -201,8 +216,8 @@ protected:
void do_setInputBuffer(Batch& batch, uint32 paramOffset);
void do_setIndexBuffer(Batch& batch, uint32 paramOffset);
void initInput();
void killInput();
// Synchronize the state cache of this Backend with the actual real state of the GL Context
void syncInputStateCache();
void updateInput();
struct InputStageState {
bool _invalidFormat;
@ -243,6 +258,8 @@ protected:
void initTransform();
void killTransform();
// Synchronize the state cache of this Backend with the actual real state of the GL Context
void syncTransformStateCache();
void updateTransform();
struct TransformStageState {
TransformObject _transformObject;
@ -299,7 +316,6 @@ protected:
GLState* _state;
bool _invalidState = false;
bool _needStateSync = true;
PipelineStageState() :
_pipeline(),
@ -308,8 +324,7 @@ protected:
_stateCache(State::DEFAULT),
_stateSignatureCache(0),
_state(nullptr),
_invalidState(false),
_needStateSync(true)
_invalidState(false)
{}
} _pipeline;

View file

@ -46,24 +46,12 @@ static const GLenum attributeSlotToClassicAttribName[NUM_CLASSIC_ATTRIBS] = {
};
#endif
void GLBackend::initInput() {
glPushClientAttrib(GL_VERTEX_ARRAY);
glPushClientAttrib(GL_NORMAL_ARRAY);
glPushClientAttrib(GL_COLOR_ARRAY);
glPushClientAttrib(GL_TEXTURE_COORD_ARRAY);
void GLBackend::syncInputStateCache() {
for (int i = 0; i < NUM_CLASSIC_ATTRIBS; i++) {
_input._attributeActivation[i] = glIsEnabled(attributeSlotToClassicAttribName[i]);
}
}
void GLBackend::killInput() {
glPopClientAttrib(); // GL_VERTEX_ARRAY
glPopClientAttrib(); // GL_NORMAL_ARRAY
glPopClientAttrib(); // GL_COLOR_ARRAY
glPopClientAttrib(); // GL_TEXTURE_COORD_ARRAY
}
void GLBackend::updateInput() {
if (_input._invalidFormat || _input._buffersState.any()) {
@ -164,9 +152,6 @@ void GLBackend::updateInput() {
}
}
}
} else {
glBindBuffer(GL_ARRAY_BUFFER, 0);
(void) CHECK_GL_ERROR();
}
// everything format related should be in sync now
_input._invalidFormat = false;

View file

@ -63,11 +63,6 @@ void GLBackend::do_setPipeline(Batch& batch, uint32 paramOffset) {
if (_pipeline._pipeline == pipeline) {
return;
}
if (_pipeline._needStateSync) {
syncPipelineStateCache();
_pipeline._needStateSync = false;
}
// null pipeline == reset
if (!pipeline) {
@ -108,17 +103,7 @@ void GLBackend::do_setPipeline(Batch& batch, uint32 paramOffset) {
}
}
#define DEBUG_GLSTATE
void GLBackend::updatePipeline() {
#ifdef DEBUG_GLSTATE
if (_pipeline._needStateSync) {
State::Data state;
getCurrentGLState(state);
State::Signature signature = State::evalSignature(state);
(void) signature; // quiet compiler
}
#endif
if (_pipeline._invalidProgram) {
// doing it here is aproblem for calls to glUniform.... so will do it on assing...
glUseProgram(_pipeline._program);

View file

@ -55,6 +55,25 @@ void GLBackend::killTransform() {
#else
#endif
}
void GLBackend::syncTransformStateCache() {
_transform._invalidProj = true;
_transform._invalidView = true;
_transform._invalidModel = true;
GLint currentMode;
glGetIntegerv(GL_MATRIX_MODE, &currentMode);
_transform._lastMode = currentMode;
glGetFloatv(GL_PROJECTION_MATRIX, (float*) &_transform._projection);
Mat4 modelView;
glGetFloatv(GL_MODELVIEW_MATRIX, (float*) &modelView);
auto modelViewInv = glm::inverse(modelView);
_transform._view.evalFromRawMatrix(modelViewInv);
_transform._model.setIdentity();
}
void GLBackend::updateTransform() {
// Check all the dirty flags and update the state accordingly
if (_transform._invalidProj) {

View file

@ -87,49 +87,50 @@ PacketVersion versionForPacketType(PacketType packetType) {
QString nameForPacketType(PacketType packetType) {
switch (packetType) {
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnknown);
PACKET_TYPE_NAME_LOOKUP(PacketTypeStunResponse);
PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainList);
PACKET_TYPE_NAME_LOOKUP(PacketTypePing);
PACKET_TYPE_NAME_LOOKUP(PacketTypePingReply);
PACKET_TYPE_NAME_LOOKUP(PacketTypeKillAvatar);
PACKET_TYPE_NAME_LOOKUP(PacketTypeAvatarData);
PACKET_TYPE_NAME_LOOKUP(PacketTypeInjectAudio);
PACKET_TYPE_NAME_LOOKUP(PacketTypeMixedAudio);
PACKET_TYPE_NAME_LOOKUP(PacketTypeMicrophoneAudioNoEcho);
PACKET_TYPE_NAME_LOOKUP(PacketTypeMicrophoneAudioWithEcho);
PACKET_TYPE_NAME_LOOKUP(PacketTypeBulkAvatarData);
PACKET_TYPE_NAME_LOOKUP(PacketTypeSilentAudioFrame);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEnvironmentData);
PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainListRequest);
PACKET_TYPE_NAME_LOOKUP(PacketTypeRequestAssignment);
PACKET_TYPE_NAME_LOOKUP(PacketTypeCreateAssignment);
PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainConnectionDenied);
PACKET_TYPE_NAME_LOOKUP(PacketTypeMuteEnvironment);
PACKET_TYPE_NAME_LOOKUP(PacketTypeAudioStreamStats);
PACKET_TYPE_NAME_LOOKUP(PacketTypeDataServerConfirm);
PACKET_TYPE_NAME_LOOKUP(PacketTypeOctreeStats);
PACKET_TYPE_NAME_LOOKUP(PacketTypeJurisdiction);
PACKET_TYPE_NAME_LOOKUP(PacketTypeJurisdictionRequest);
PACKET_TYPE_NAME_LOOKUP(PacketTypeAvatarIdentity);
PACKET_TYPE_NAME_LOOKUP(PacketTypeAvatarBillboard);
PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainConnectRequest);
PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainServerRequireDTLS);
PACKET_TYPE_NAME_LOOKUP(PacketTypeNodeJsonStats);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityQuery);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityData);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityErase);
PACKET_TYPE_NAME_LOOKUP(PacketTypeOctreeDataNack);
PACKET_TYPE_NAME_LOOKUP(PacketTypeStopNode);
PACKET_TYPE_NAME_LOOKUP(PacketTypeAudioEnvironment);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityEditNack);
PACKET_TYPE_NAME_LOOKUP(PacketTypeSignedTransactionPayment);
PACKET_TYPE_NAME_LOOKUP(PacketTypeIceServerHeartbeat);
PACKET_TYPE_NAME_LOOKUP(PacketTypeIceServerHeartbeatResponse);
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPing);
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPingReply);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAdd);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityEdit);
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnknown);
PACKET_TYPE_NAME_LOOKUP(PacketTypeStunResponse);
PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainList);
PACKET_TYPE_NAME_LOOKUP(PacketTypePing);
PACKET_TYPE_NAME_LOOKUP(PacketTypePingReply);
PACKET_TYPE_NAME_LOOKUP(PacketTypeKillAvatar);
PACKET_TYPE_NAME_LOOKUP(PacketTypeAvatarData);
PACKET_TYPE_NAME_LOOKUP(PacketTypeInjectAudio);
PACKET_TYPE_NAME_LOOKUP(PacketTypeMixedAudio);
PACKET_TYPE_NAME_LOOKUP(PacketTypeMicrophoneAudioNoEcho);
PACKET_TYPE_NAME_LOOKUP(PacketTypeMicrophoneAudioWithEcho);
PACKET_TYPE_NAME_LOOKUP(PacketTypeBulkAvatarData);
PACKET_TYPE_NAME_LOOKUP(PacketTypeSilentAudioFrame);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEnvironmentData);
PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainListRequest);
PACKET_TYPE_NAME_LOOKUP(PacketTypeRequestAssignment);
PACKET_TYPE_NAME_LOOKUP(PacketTypeCreateAssignment);
PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainConnectionDenied);
PACKET_TYPE_NAME_LOOKUP(PacketTypeMuteEnvironment);
PACKET_TYPE_NAME_LOOKUP(PacketTypeAudioStreamStats);
PACKET_TYPE_NAME_LOOKUP(PacketTypeDataServerConfirm);
PACKET_TYPE_NAME_LOOKUP(PacketTypeOctreeStats);
PACKET_TYPE_NAME_LOOKUP(PacketTypeJurisdiction);
PACKET_TYPE_NAME_LOOKUP(PacketTypeJurisdictionRequest);
PACKET_TYPE_NAME_LOOKUP(PacketTypeAvatarIdentity);
PACKET_TYPE_NAME_LOOKUP(PacketTypeAvatarBillboard);
PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainConnectRequest);
PACKET_TYPE_NAME_LOOKUP(PacketTypeDomainServerRequireDTLS);
PACKET_TYPE_NAME_LOOKUP(PacketTypeNodeJsonStats);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityQuery);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityData);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityErase);
PACKET_TYPE_NAME_LOOKUP(PacketTypeOctreeDataNack);
PACKET_TYPE_NAME_LOOKUP(PacketTypeStopNode);
PACKET_TYPE_NAME_LOOKUP(PacketTypeAudioEnvironment);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityEditNack);
PACKET_TYPE_NAME_LOOKUP(PacketTypeSignedTransactionPayment);
PACKET_TYPE_NAME_LOOKUP(PacketTypeIceServerHeartbeat);
PACKET_TYPE_NAME_LOOKUP(PacketTypeIceServerHeartbeatResponse);
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPing);
PACKET_TYPE_NAME_LOOKUP(PacketTypeUnverifiedPingReply);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityAdd);
PACKET_TYPE_NAME_LOOKUP(PacketTypeEntityEdit);
PACKET_TYPE_NAME_LOOKUP(PacketTypeParticleEntitiesFix);
default:
return QString("Type: ") + QString::number((int)packetType);
}
@ -167,14 +168,14 @@ int populatePacketHeaderWithUUID(char* packet, PacketType packetType, const QUui
memset(position, 0, NUM_BYTES_MD5_HASH);
position += NUM_BYTES_MD5_HASH;
}
if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) {
// Pack zeros for the number of bytes that the sequence number requires.
// The LimitedNodeList will handle packing in the sequence number when sending out the packet.
memset(position, 0, sizeof(PacketSequenceNumber));
position += sizeof(PacketSequenceNumber);
// Pack zeros for the number of bytes that the sequence number requires.
// The LimitedNodeList will handle packing in the sequence number when sending out the packet.
memset(position, 0, sizeof(PacketSequenceNumber));
position += sizeof(PacketSequenceNumber);
}
// return the number of bytes written for pointer pushing
return position - packet;
}
@ -194,7 +195,7 @@ int numBytesForArithmeticCodedPacketType(PacketType packetType) {
}
int numBytesForPacketHeaderGivenPacketType(PacketType packetType) {
return numBytesForArithmeticCodedPacketType(packetType)
return numBytesForArithmeticCodedPacketType(packetType)
+ numHashBytesForType(packetType)
+ numSequenceNumberBytesForType(packetType)
+ NUM_STATIC_HEADER_BYTES;
@ -214,7 +215,7 @@ QUuid uuidFromPacketHeader(const QByteArray& packet) {
}
int hashOffsetForPacketType(PacketType packetType) {
return numBytesForArithmeticCodedPacketType(packetType) + NUM_STATIC_HEADER_BYTES;
return numBytesForArithmeticCodedPacketType(packetType) + NUM_STATIC_HEADER_BYTES;
}
int sequenceNumberOffsetForPacketType(PacketType packetType) {
@ -234,13 +235,13 @@ PacketSequenceNumber sequenceNumberFromHeader(const QByteArray& packet, PacketTy
if (packetType == PacketTypeUnknown) {
packetType = packetTypeForPacket(packet);
}
PacketSequenceNumber result = DEFAULT_SEQUENCE_NUMBER;
if (SEQUENCE_NUMBERED_PACKETS.contains(packetType)) {
memcpy(&result, packet.data() + sequenceNumberOffsetForPacketType(packetType), sizeof(PacketSequenceNumber));
}
}
return result;
}
@ -249,7 +250,7 @@ void replaceHashInPacket(QByteArray& packet, const QUuid& connectionUUID, Packet
packetType = packetTypeForPacket(packet);
}
packet.replace(hashOffsetForPacketType(packetType), NUM_BYTES_MD5_HASH,
packet.replace(hashOffsetForPacketType(packetType), NUM_BYTES_MD5_HASH,
hashForPacketAndConnectionUUID(packet, connectionUUID));
}
@ -257,17 +258,17 @@ void replaceSequenceNumberInPacket(QByteArray& packet, PacketSequenceNumber sequ
if (packetType == PacketTypeUnknown) {
packetType = packetTypeForPacket(packet);
}
packet.replace(sequenceNumberOffsetForPacketType(packetType),
packet.replace(sequenceNumberOffsetForPacketType(packetType),
sizeof(PacketSequenceNumber), reinterpret_cast<char*>(&sequenceNumber), sizeof(PacketSequenceNumber));
}
}
void replaceHashAndSequenceNumberInPacket(QByteArray& packet, const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber,
void replaceHashAndSequenceNumberInPacket(QByteArray& packet, const QUuid& connectionUUID, PacketSequenceNumber sequenceNumber,
PacketType packetType) {
if (packetType == PacketTypeUnknown) {
packetType = packetTypeForPacket(packet);
}
replaceHashInPacket(packet, connectionUUID, packetType);
replaceSequenceNumberInPacket(packet, sequenceNumber, packetType);
}

View file

@ -79,7 +79,8 @@ enum PacketType {
PacketTypeIceServerHeartbeat, // 50
PacketTypeIceServerHeartbeatResponse,
PacketTypeUnverifiedPing,
PacketTypeUnverifiedPingReply
PacketTypeUnverifiedPingReply,
PacketTypeParticleEntitiesFix
};
typedef char PacketVersion;
@ -90,17 +91,17 @@ const PacketSequenceNumber DEFAULT_SEQUENCE_NUMBER = 0;
typedef std::map<PacketType, PacketSequenceNumber> PacketTypeSequenceMap;
const QSet<PacketType> NON_VERIFIED_PACKETS = QSet<PacketType>()
<< PacketTypeDomainServerRequireDTLS << PacketTypeDomainConnectRequest
<< PacketTypeDomainList << PacketTypeDomainListRequest << PacketTypeDomainConnectionDenied
<< PacketTypeCreateAssignment << PacketTypeRequestAssignment << PacketTypeStunResponse
<< PacketTypeNodeJsonStats << PacketTypeEntityQuery
<< PacketTypeOctreeDataNack << PacketTypeEntityEditNack
<< PacketTypeIceServerHeartbeat << PacketTypeIceServerHeartbeatResponse
<< PacketTypeUnverifiedPing << PacketTypeUnverifiedPingReply << PacketTypeStopNode
<< PacketTypeDomainServerPathQuery << PacketTypeDomainServerPathResponse;
<< PacketTypeDomainServerRequireDTLS << PacketTypeDomainConnectRequest
<< PacketTypeDomainList << PacketTypeDomainListRequest << PacketTypeDomainConnectionDenied
<< PacketTypeCreateAssignment << PacketTypeRequestAssignment << PacketTypeStunResponse
<< PacketTypeNodeJsonStats << PacketTypeEntityQuery
<< PacketTypeOctreeDataNack << PacketTypeEntityEditNack
<< PacketTypeIceServerHeartbeat << PacketTypeIceServerHeartbeatResponse
<< PacketTypeUnverifiedPing << PacketTypeUnverifiedPingReply << PacketTypeStopNode
<< PacketTypeDomainServerPathQuery << PacketTypeDomainServerPathResponse;
const QSet<PacketType> SEQUENCE_NUMBERED_PACKETS = QSet<PacketType>()
<< PacketTypeAvatarData;
<< PacketTypeAvatarData;
const int NUM_BYTES_MD5_HASH = 16;
const int NUM_STATIC_HEADER_BYTES = sizeof(PacketVersion) + NUM_BYTES_RFC4122_UUID;
@ -179,5 +180,6 @@ const PacketVersion VERSION_ENTITIES_HAVE_LINE_TYPE = 24;
const PacketVersion VERSION_ENTITIES_HAVE_COLLISION_SOUND_URL = 25;
const PacketVersion VERSION_ENTITIES_HAVE_FRICTION = 26;
const PacketVersion VERSION_NO_ENTITY_ID_SWAP = 27;
const PacketVersion VERSION_ENTITIES_PARTICLE_FIX = 28;
#endif // hifi_PacketHeaders_h

View file

@ -12,7 +12,6 @@
// include this before QOpenGLFramebufferObject, which includes an earlier version of OpenGL
#include <gpu/GPUConfig.h>
#include <GLMHelpers.h>
#include <PathUtils.h>
#include <ViewFrustum.h>
@ -48,16 +47,26 @@
#include "point_light_frag.h"
#include "spot_light_frag.h"
static const std::string glowIntensityShaderHandle = "glowIntensity";
void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
auto vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(simple_vert)));
auto pixelShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(simple_frag)));
gpu::Shader::BindingSet slotBindings;
slotBindings.insert(gpu::Shader::Binding(glowIntensityShaderHandle, 0));
gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader));
gpu::Shader::makeProgram(*program, slotBindings);
gpu::StatePointer state = gpu::StatePointer(new gpu::State());
state->setCullMode(gpu::State::CULL_BACK);
state->setDepthTest(true, true, gpu::LESS_EQUAL);
state->setBlendFunction(false,
gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA,
gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE);
_simpleProgram = gpu::PipelinePointer(gpu::Pipeline::create(program, state));
_viewState = viewState;
_simpleProgram.addShaderFromSourceCode(QGLShader::Vertex, simple_vert);
_simpleProgram.addShaderFromSourceCode(QGLShader::Fragment, simple_frag);
_simpleProgram.link();
_simpleProgram.bind();
_glowIntensityLocation = _simpleProgram.uniformLocation("glowIntensity");
_simpleProgram.release();
loadLightProgram(directional_light_frag, false, _directionalLight, _directionalLightLocations);
loadLightProgram(directional_light_shadow_map_frag, false, _directionalLightShadowMap,
_directionalLightShadowMapLocations);
@ -92,29 +101,12 @@ void DeferredLightingEffect::init(AbstractViewStateInterface* viewState) {
lp->setAmbientSpherePreset(gpu::SphericalHarmonics::Preset(_ambientLightMode % gpu::SphericalHarmonics::NUM_PRESET));
}
void DeferredLightingEffect::bindSimpleProgram() {
DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(true, true, true);
_simpleProgram.bind();
_simpleProgram.setUniformValue(_glowIntensityLocation, DependencyManager::get<GlowEffect>()->getIntensity());
glDisable(GL_BLEND);
}
void DeferredLightingEffect::bindSimpleProgram(gpu::Batch& batch) {
DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(batch, true, true, true);
batch._glUseProgram(_simpleProgram.programId());
batch._glUniform1f(_glowIntensityLocation, DependencyManager::get<GlowEffect>()->getIntensity());
batch._glDisable(GL_BLEND);
}
void DeferredLightingEffect::releaseSimpleProgram() {
glEnable(GL_BLEND);
_simpleProgram.release();
DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(true, false, false);
batch.setPipeline(_simpleProgram);
}
void DeferredLightingEffect::releaseSimpleProgram(gpu::Batch& batch) {
batch._glEnable(GL_BLEND);
batch._glUseProgram(0);
DependencyManager::get<TextureCache>()->setPrimaryDrawBuffers(batch, true, false, false);
}
@ -136,12 +128,6 @@ void DeferredLightingEffect::renderSolidCube(gpu::Batch& batch, float size, cons
releaseSimpleProgram(batch);
}
void DeferredLightingEffect::renderWireCube(float size, const glm::vec4& color) {
gpu::Batch batch;
renderWireCube(batch, size, color);
gpu::GLBackend::renderBatch(batch);
}
void DeferredLightingEffect::renderWireCube(gpu::Batch& batch, float size, const glm::vec4& color) {
bindSimpleProgram(batch);
DependencyManager::get<GeometryCache>()->renderWireCube(batch, size, color);

View file

@ -33,15 +33,10 @@ public:
void init(AbstractViewStateInterface* viewState);
/// Returns a reference to a simple program suitable for rendering static untextured geometry
ProgramObject& getSimpleProgram() { return _simpleProgram; }
/// Sets up the state necessary to render static untextured geometry with the simple program.
void bindSimpleProgram();
void bindSimpleProgram(gpu::Batch& batch);
/// Tears down the state necessary to render static untextured geometry with the simple program.
void releaseSimpleProgram();
void releaseSimpleProgram(gpu::Batch& batch);
//// Renders a solid sphere with the simple program.
@ -54,8 +49,6 @@ public:
void renderSolidCube(gpu::Batch& batch, float size, const glm::vec4& color);
//// Renders a wireframe cube with the simple program.
// FIXME Remove non Batch version once Cube3DOverlay uses the render pipeline
void renderWireCube(float size, const glm::vec4& color);
void renderWireCube(gpu::Batch& batch, float size, const glm::vec4& color);
//// Renders a quad with the simple program.
@ -105,10 +98,9 @@ private:
};
static void loadLightProgram(const char* fragSource, bool limited, ProgramObject& program, LightLocations& locations);
ProgramObject _simpleProgram;
int _glowIntensityLocation;
gpu::PipelinePointer _simpleProgram;
ProgramObject _directionalSkyboxLight;
LightLocations _directionalSkyboxLightLocations;
ProgramObject _directionalSkyboxLightShadowMap;

View file

@ -946,8 +946,8 @@ bool Model::renderCore(float alpha, RenderMode mode, RenderArgs* args) {
glPushMatrix();
#endif
::gpu::GLBackend::renderBatch(batch);
::gpu::GLBackend::renderBatch(batch, true); // force sync with gl state here
#if defined(ANDROID)
#else
glPopMatrix();
@ -1859,6 +1859,7 @@ void Model::endScene(RenderMode mode, RenderArgs* args) {
}
gpu::GLBackend backend;
backend.syncCache(); // force sync with gl state here
if (args) {
glm::mat4 proj;

View file

@ -12,16 +12,22 @@
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
//
<@include gpu/Transform.slh@>
<$declareStandardTransform()$>
// the interpolated normal
varying vec4 interpolatedNormal;
void main(void) {
// transform and store the normal for interpolation
interpolatedNormal = normalize(gl_ModelViewMatrix * vec4(gl_Normal, 0.0));
// pass along the diffuse color
gl_FrontColor = gl_Color;
// use standard pipeline transform
gl_Position = ftransform();
}
// standard transform
TransformCamera cam = getTransformCamera();
TransformObject obj = getTransformObject();
<$transformModelToClipPos(cam, obj, gl_Vertex, gl_Position)$>
<$transformModelToEyeDir(cam, obj, gl_Normal, interpolatedNormal.xyz)$>
interpolatedNormal = vec4(normalize(interpolatedNormal.xyz), 0.0);
}

View file

@ -22,6 +22,18 @@
#include <memory>
inline bool isValidScale(glm::vec3 scale) {
bool result = scale.x != 0.0f && scale.y != 0.0f && scale.z != 0.0f;
assert(result);
return result;
}
inline bool isValidScale(float scale) {
bool result = scale != 0.0f;
assert(result);
return result;
}
class Transform {
public:
typedef glm::mat4 Mat4;
@ -32,7 +44,7 @@ public:
typedef glm::quat Quat;
Transform() :
_rotation(1.0f, 0, 0, 0),
_rotation(1.0f, 0.0f, 0.0f, 0.0f),
_scale(1.0f),
_translation(0.0f),
_flags(FLAG_CACHE_INVALID_BITSET) // invalid cache
@ -44,6 +56,9 @@ public:
_translation(translation),
_flags(FLAG_CACHE_INVALID_BITSET) // invalid cache
{
if (!isValidScale(_scale)) {
_scale = Vec3(1.0f);
}
}
Transform(const Transform& transform) :
_rotation(transform._rotation),
@ -166,8 +181,8 @@ protected:
};
inline void Transform::setIdentity() {
_translation = Vec3(0);
_rotation = Quat(1.0f, 0, 0, 0);
_translation = Vec3(0.0f);
_rotation = Quat(1.0f, 0.0f, 0.0f, 0.0f);
_scale = Vec3(1.0f);
_flags = Flags(FLAG_CACHE_INVALID_BITSET);
}
@ -187,19 +202,25 @@ inline void Transform::setTranslation(const Vec3& translation) {
}
inline void Transform::preTranslate(const Vec3& translation) {
if (translation == Vec3() ) return;
if (translation == Vec3()) {
return;
}
invalidCache();
flagTranslation();
_translation += translation;
}
inline void Transform::postTranslate(const Vec3& translation) {
if (translation == Vec3() ) return;
if (translation == Vec3()) {
return;
}
invalidCache();
flagTranslation();
Vec3 scaledT = translation;
if (isScaling()) scaledT *= _scale;
if (isScaling()) {
scaledT *= _scale;
}
if (isRotating()) {
_translation += glm::rotate(_rotation, scaledT);
@ -223,7 +244,9 @@ inline void Transform::setRotation(const Quat& rotation) {
}
inline void Transform::preRotate(const Quat& rotation) {
if (rotation == Quat()) return;
if (rotation == Quat()) {
return;
}
invalidCache();
if (isRotating()) {
_rotation = rotation * _rotation;
@ -236,7 +259,9 @@ inline void Transform::preRotate(const Quat& rotation) {
}
inline void Transform::postRotate(const Quat& rotation) {
if (rotation == Quat()) return;
if (rotation == Quat()) {
return;
}
invalidCache();
if (isNonUniform()) {
@ -269,8 +294,12 @@ inline const Transform::Vec3& Transform::getScale() const {
}
inline void Transform::setScale(float scale) {
if (!isValidScale(scale)) {
return;
}
invalidCache();
flagUniform();
if (scale == 1.0f) {
unflagScaling();
} else {
@ -280,6 +309,9 @@ inline void Transform::setScale(float scale) {
}
inline void Transform::setScale(const Vec3& scale) {
if (!isValidScale(scale)) {
return;
}
if ((scale.x == scale.y) && (scale.x == scale.z)) {
setScale(scale.x);
} else {
@ -291,9 +323,11 @@ inline void Transform::setScale(const Vec3& scale) {
}
inline void Transform::postScale(float scale) {
if (scale == 1.0f) return;
if (isValidScale(scale) || scale == 1.0f) {
return;
}
if (isScaling()) {
// if already scaling, just invalid cache and aply uniform scale
// if already scaling, just invalid cache and apply uniform scale
invalidCache();
_scale *= scale;
} else {
@ -302,6 +336,9 @@ inline void Transform::postScale(float scale) {
}
inline void Transform::postScale(const Vec3& scale) {
if (!isValidScale(scale)) {
return;
}
invalidCache();
if (isScaling()) {
_scale *= scale;
@ -360,7 +397,7 @@ inline Transform::Mat4& Transform::getRotationScaleMatrixInverse(Mat4& result) c
inline void Transform::evalFromRawMatrix(const Mat4& matrix) {
// for now works only in the case of TRS transformation
if ((matrix[0][3] == 0) && (matrix[1][3] == 0) && (matrix[2][3] == 0) && (matrix[3][3] == 1.0f)) {
if ((matrix[0][3] == 0.0f) && (matrix[1][3] == 0.0f) && (matrix[2][3] == 0.0f) && (matrix[3][3] == 1.0f)) {
setTranslation(Vec3(matrix[3]));
evalFromRawMatrix(Mat3(matrix));
}
@ -377,15 +414,10 @@ inline void Transform::evalFromRawMatrix(const Mat3& rotationScaleMatrix) {
inline Transform& Transform::evalInverse(Transform& inverse) const {
inverse.setIdentity();
if (isScaling()) {
// TODO: At some point we will face the case when scale is 0 and so 1/0 will blow up...
// WHat should we do for this one?
assert(_scale.x != 0);
assert(_scale.y != 0);
assert(_scale.z != 0);
if (isNonUniform()) {
inverse.setScale(Vec3(1.0f/_scale.x, 1.0f/_scale.y, 1.0f/_scale.z));
inverse.setScale(Vec3(1.0f) / _scale);
} else {
inverse.setScale(1.0f/_scale.x);
inverse.setScale(1.0f / _scale.x);
}
}
if (isRotating()) {
@ -421,8 +453,7 @@ inline Transform& Transform::inverseMult( Transform& result, const Transform& le
result.setIdentity();
if (left.isScaling()) {
const Vec3& s = left.getScale();
result.setScale(Vec3(1.0f / s.x, 1.0f / s.y, 1.0f / s.z));
result.setScale(Vec3(1.0f) / left.getScale());
}
if (left.isRotating()) {
result.postRotate(glm::conjugate(left.getRotation()));