Merge branch 'master' of https://github.com/highfidelity/hifi into brown

This commit is contained in:
samcake 2017-05-26 16:47:49 -07:00
commit 882df7391b
33 changed files with 1395 additions and 504 deletions

View file

@ -1379,6 +1379,8 @@ function addTableRow(row) {
var setting_name = table.attr("name");
row.addClass(Settings.DATA_ROW_CLASS + " " + Settings.NEW_ROW_CLASS);
var focusChanged = false;
_.each(row.children(), function(element) {
if ($(element).hasClass("numbered")) {
// Index row
@ -1429,6 +1431,11 @@ function addTableRow(row) {
});
}
if (!focusChanged) {
input.focus();
focusChanged = true;
}
if (isCheckbox) {
$(input).find("input").attr("data-changed", "true");
} else {

View file

@ -114,6 +114,24 @@
"weightVar": "headWeight",
"weight": 4.0,
"flexCoefficients": [1, 0.05, 0.25, 0.25, 0.25]
},
{
"jointName": "LeftArm",
"positionVar": "leftArmPosition",
"rotationVar": "leftArmRotation",
"typeVar": "leftArmType",
"weightVar": "leftArmWeight",
"weight": 0.75,
"flexCoefficients": [1.0, 0.35, 0.2, 0.1, 0.05, 0.0, 0.0, 0.0]
},
{
"jointName": "RightArm",
"positionVar": "rightArmPosition",
"rotationVar": "rightArmRotation",
"typeVar": "rightArmType",
"weightVar": "rightArmWeight",
"weight": 0.75,
"flexCoefficients": [1.0, 0.35, 0.2, 0.1, 0.05, 0.0, 0.0, 0.0]
}
]
},

View file

@ -66,6 +66,8 @@
{ "from": "Standard.Hips", "to": "Actions.Hips" },
{ "from": "Standard.Spine2", "to": "Actions.Spine2" },
{ "from": "Standard.Head", "to": "Actions.Head" }
{ "from": "Standard.Head", "to": "Actions.Head" },
{ "from": "Standard.LeftArm", "to": "Actions.LeftArm" },
{ "from": "Standard.RightArm", "to": "Actions.RightArm" }
]
}

View file

@ -3,7 +3,7 @@
"channels": [
{ "from": "Vive.LY", "when": "Vive.LSY", "filters": ["invert"], "to": "Standard.LY" },
{ "from": "Vive.LX", "when": "Vive.LSX", "to": "Standard.LX" },
{
{
"from": "Vive.LT", "to": "Standard.LT",
"filters": [
{ "type": "deadZone", "min": 0.05 }
@ -17,7 +17,7 @@
{ "from": "Vive.RY", "when": "Vive.RSY", "filters": ["invert"], "to": "Standard.RY" },
{ "from": "Vive.RX", "when": "Vive.RSX", "to": "Standard.RX" },
{
{
"from": "Vive.RT", "to": "Standard.RT",
"filters": [
{ "type": "deadZone", "min": 0.05 }
@ -36,31 +36,34 @@
{ "from": "Vive.LeftHand", "to": "Standard.LeftHand", "when": [ "Application.InHMD" ] },
{ "from": "Vive.RightHand", "to": "Standard.RightHand", "when": [ "Application.InHMD" ] },
{
"from": "Vive.LeftFoot", "to" : "Standard.LeftFoot",
"filters" : [{"type" : "lowVelocity", "rotation" : 1.0, "translation": 1.0}],
"when": [ "Application.InHMD"]
},
{
"from": "Vive.RightFoot", "to" : "Standard.RightFoot",
"filters" : [{"type" : "lowVelocity", "rotation" : 1.0, "translation": 1.0}],
"when": [ "Application.InHMD"]
},
{
"from": "Vive.Hips", "to" : "Standard.Hips",
"filters" : [{"type" : "lowVelocity", "rotation" : 0.01, "translation": 0.01}],
"when": [ "Application.InHMD"]
},
{
"from": "Vive.Spine2", "to" : "Standard.Spine2",
"filters" : [{"type" : "lowVelocity", "rotation" : 0.01, "translation": 0.01}],
"when": [ "Application.InHMD"]
},
{ "from": "Vive.Head", "to" : "Standard.Head", "when" : [ "Application.InHMD"] }
{ "from": "Vive.Head", "to" : "Standard.Head", "when" : [ "Application.InHMD"] },
{ "from": "Vive.RightArm", "to" : "Standard.RightArm", "when" : [ "Application.InHMD"] },
{ "from": "Vive.LeftArm", "to" : "Standard.LeftArm", "when" : [ "Application.InHMD"] }
]
}

View file

@ -1622,7 +1622,6 @@ void Application::cleanupBeforeQuit() {
// Clear any queued processing (I/O, FBX/OBJ/Texture parsing)
QThreadPool::globalInstance()->clear();
DependencyManager::get<ScriptEngines>()->saveScripts();
DependencyManager::get<ScriptEngines>()->shutdownScripting(); // stop all currently running global scripts
DependencyManager::destroy<ScriptEngines>();
@ -4364,7 +4363,11 @@ void Application::update(float deltaTime) {
myAvatar->getSpine2CalibrationMat(),
myAvatar->getHipsCalibrationMat(),
myAvatar->getLeftFootCalibrationMat(),
myAvatar->getRightFootCalibrationMat()
myAvatar->getRightFootCalibrationMat(),
myAvatar->getRightArmCalibrationMat(),
myAvatar->getLeftArmCalibrationMat(),
myAvatar->getRightHandCalibrationMat(),
myAvatar->getLeftHandCalibrationMat()
};
InputPluginPointer keyboardMousePlugin;
@ -4420,6 +4423,10 @@ void Application::update(float deltaTime) {
controller::Pose headPose = userInputMapper->getPoseState(controller::Action::HEAD);
myAvatar->setHeadControllerPoseInSensorFrame(headPose.transform(avatarToSensorMatrix));
controller::Pose leftArmPose = userInputMapper->getPoseState(controller::Action::LEFT_ARM);
controller::Pose rightArmPose = userInputMapper->getPoseState(controller::Action::RIGHT_ARM);
myAvatar->setArmControllerPosesInSensorFrame(leftArmPose.transform(avatarToSensorMatrix), rightArmPose.transform(avatarToSensorMatrix));
updateThreads(deltaTime); // If running non-threaded, then give the threads some time to process...
updateDialogs(deltaTime); // update various stats dialogs if present

View file

@ -90,6 +90,14 @@ const float MyAvatar::ZOOM_DEFAULT = 1.5f;
// static const glm::quat DEFAULT_AVATAR_MIDDLE_EYE_ROT { Quaternions::Y_180 };
static const glm::vec3 DEFAULT_AVATAR_MIDDLE_EYE_POS { 0.0f, 0.6f, 0.0f };
static const glm::vec3 DEFAULT_AVATAR_HEAD_POS { 0.0f, 0.53f, 0.0f };
static const glm::vec3 DEFAULT_AVATAR_RIGHTARM_POS { -0.134824f, 0.396348f, -0.0515777f };
static const glm::quat DEFAULT_AVATAR_RIGHTARM_ROT { -0.536241f, 0.536241f, -0.460918f, -0.460918f };
static const glm::vec3 DEFAULT_AVATAR_LEFTARM_POS { 0.134795f, 0.396349f, -0.0515881f };
static const glm::quat DEFAULT_AVATAR_LEFTARM_ROT { 0.536257f, 0.536258f, -0.460899f, 0.4609f };
static const glm::vec3 DEFAULT_AVATAR_RIGHTHAND_POS { -0.72768f, 0.396349f, -0.0515779f };
static const glm::quat DEFAULT_AVATAR_RIGHTHAND_ROT { 0.479184f, -0.520013f, 0.522537f, 0.476365f};
static const glm::vec3 DEFAULT_AVATAR_LEFTHAND_POS { 0.727588f, 0.39635f, -0.0515878f };
static const glm::quat DEFAULT_AVATAR_LEFTHAND_ROT { -0.479181f, -0.52001f, 0.52254f, -0.476369f };
static const glm::vec3 DEFAULT_AVATAR_NECK_POS { 0.0f, 0.445f, 0.025f };
static const glm::vec3 DEFAULT_AVATAR_SPINE2_POS { 0.0f, 0.32f, 0.02f };
static const glm::vec3 DEFAULT_AVATAR_HIPS_POS { 0.0f, 0.0f, 0.0f };
@ -1434,6 +1442,37 @@ controller::Pose MyAvatar::getHeadControllerPoseInAvatarFrame() const {
return getHeadControllerPoseInWorldFrame().transform(invAvatarMatrix);
}
void MyAvatar::setArmControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right) {
_leftArmControllerPoseInSensorFrameCache.set(left);
_rightArmControllerPoseInSensorFrameCache.set(right);
}
controller::Pose MyAvatar::getLeftArmControllerPoseInSensorFrame() const {
return _leftArmControllerPoseInSensorFrameCache.get();
}
controller::Pose MyAvatar::getRightArmControllerPoseInSensorFrame() const {
return _rightArmControllerPoseInSensorFrameCache.get();
}
controller::Pose MyAvatar::getLeftArmControllerPoseInWorldFrame() const {
return getLeftArmControllerPoseInSensorFrame().transform(getSensorToWorldMatrix());
}
controller::Pose MyAvatar::getRightArmControllerPoseInWorldFrame() const {
return getRightArmControllerPoseInSensorFrame().transform(getSensorToWorldMatrix());
}
controller::Pose MyAvatar::getLeftArmControllerPoseInAvatarFrame() const {
glm::mat4 worldToAvatarMat = glm::inverse(createMatFromQuatAndPos(getOrientation(), getPosition()));
return getLeftArmControllerPoseInWorldFrame().transform(worldToAvatarMat);
}
controller::Pose MyAvatar::getRightArmControllerPoseInAvatarFrame() const {
glm::mat4 worldToAvatarMat = glm::inverse(createMatFromQuatAndPos(getOrientation(), getPosition()));
return getRightArmControllerPoseInWorldFrame().transform(worldToAvatarMat);
}
void MyAvatar::updateMotors() {
_characterController.clearMotors();
glm::quat motorRotation;
@ -2747,6 +2786,51 @@ glm::mat4 MyAvatar::getRightFootCalibrationMat() const {
}
}
glm::mat4 MyAvatar::getRightArmCalibrationMat() const {
int rightArmIndex = _skeletonModel->getRig().indexOfJoint("RightArm");
if (rightArmIndex >= 0) {
auto rightArmPos = getAbsoluteDefaultJointTranslationInObjectFrame(rightArmIndex);
auto rightArmRot = getAbsoluteDefaultJointRotationInObjectFrame(rightArmIndex);
return createMatFromQuatAndPos(rightArmRot, rightArmPos);
} else {
return createMatFromQuatAndPos(DEFAULT_AVATAR_RIGHTARM_ROT, DEFAULT_AVATAR_RIGHTARM_POS);
}
}
glm::mat4 MyAvatar::getLeftArmCalibrationMat() const {
int leftArmIndex = _skeletonModel->getRig().indexOfJoint("LeftArm");
if (leftArmIndex >= 0) {
auto leftArmPos = getAbsoluteDefaultJointTranslationInObjectFrame(leftArmIndex);
auto leftArmRot = getAbsoluteDefaultJointRotationInObjectFrame(leftArmIndex);
return createMatFromQuatAndPos(leftArmRot, leftArmPos);
} else {
return createMatFromQuatAndPos(DEFAULT_AVATAR_LEFTARM_ROT, DEFAULT_AVATAR_RIGHTARM_POS);
}
}
glm::mat4 MyAvatar::getRightHandCalibrationMat() const {
int rightHandIndex = _skeletonModel->getRig().indexOfJoint("RightHand");
if (rightHandIndex >= 0) {
auto rightHandPos = getAbsoluteDefaultJointTranslationInObjectFrame(rightHandIndex);
auto rightHandRot = getAbsoluteDefaultJointRotationInObjectFrame(rightHandIndex);
return createMatFromQuatAndPos(rightHandRot, rightHandPos);
} else {
return createMatFromQuatAndPos(DEFAULT_AVATAR_RIGHTHAND_ROT, DEFAULT_AVATAR_RIGHTHAND_POS);
}
}
glm::mat4 MyAvatar::getLeftHandCalibrationMat() const {
int leftHandIndex = _skeletonModel->getRig().indexOfJoint("LeftHand");
if (leftHandIndex >= 0) {
auto leftHandPos = getAbsoluteDefaultJointTranslationInObjectFrame(leftHandIndex);
auto leftHandRot = getAbsoluteDefaultJointRotationInObjectFrame(leftHandIndex);
return createMatFromQuatAndPos(leftHandRot, leftHandPos);
} else {
return createMatFromQuatAndPos(DEFAULT_AVATAR_LEFTHAND_ROT, DEFAULT_AVATAR_LEFTHAND_POS);
}
}
bool MyAvatar::pinJoint(int index, const glm::vec3& position, const glm::quat& orientation) {
auto hipsIndex = getJointIndex("Hips");
if (index != hipsIndex) {

View file

@ -471,6 +471,14 @@ public:
controller::Pose getHeadControllerPoseInWorldFrame() const;
controller::Pose getHeadControllerPoseInAvatarFrame() const;
void setArmControllerPosesInSensorFrame(const controller::Pose& left, const controller::Pose& right);
controller::Pose getLeftArmControllerPoseInSensorFrame() const;
controller::Pose getRightArmControllerPoseInSensorFrame() const;
controller::Pose getLeftArmControllerPoseInWorldFrame() const;
controller::Pose getRightArmControllerPoseInWorldFrame() const;
controller::Pose getLeftArmControllerPoseInAvatarFrame() const;
controller::Pose getRightArmControllerPoseInAvatarFrame() const;
bool hasDriveInput() const;
Q_INVOKABLE void setCollisionsEnabled(bool enabled);
@ -488,6 +496,10 @@ public:
glm::mat4 getHipsCalibrationMat() const;
glm::mat4 getLeftFootCalibrationMat() const;
glm::mat4 getRightFootCalibrationMat() const;
glm::mat4 getRightArmCalibrationMat() const;
glm::mat4 getLeftArmCalibrationMat() const;
glm::mat4 getLeftHandCalibrationMat() const;
glm::mat4 getRightHandCalibrationMat() const;
void addHoldAction(AvatarActionHold* holdAction); // thread-safe
void removeHoldAction(AvatarActionHold* holdAction); // thread-safe
@ -737,6 +749,8 @@ private:
ThreadSafeValueCache<controller::Pose> _hipsControllerPoseInSensorFrameCache{ controller::Pose() };
ThreadSafeValueCache<controller::Pose> _spine2ControllerPoseInSensorFrameCache{ controller::Pose() };
ThreadSafeValueCache<controller::Pose> _headControllerPoseInSensorFrameCache{ controller::Pose() };
ThreadSafeValueCache<controller::Pose> _leftArmControllerPoseInSensorFrameCache{ controller::Pose() };
ThreadSafeValueCache<controller::Pose> _rightArmControllerPoseInSensorFrameCache{ controller::Pose() };
bool _hmdLeanRecenterEnabled = true;

View file

@ -92,6 +92,26 @@ void MySkeletonModel::updateRig(float deltaTime, glm::mat4 parentTransform) {
headParams.spine2Enabled = false;
}
auto avatarRightArmPose = myAvatar->getRightArmControllerPoseInAvatarFrame();
if (avatarRightArmPose.isValid()) {
glm::mat4 rightArmMat = Matrices::Y_180 * createMatFromQuatAndPos(avatarRightArmPose.getRotation(), avatarRightArmPose.getTranslation());
headParams.rightArmPosition = extractTranslation(rightArmMat);
headParams.rightArmRotation = glmExtractRotation(rightArmMat);
headParams.rightArmEnabled = true;
} else {
headParams.rightArmEnabled = false;
}
auto avatarLeftArmPose = myAvatar->getLeftArmControllerPoseInAvatarFrame();
if (avatarLeftArmPose.isValid()) {
glm::mat4 leftArmMat = Matrices::Y_180 * createMatFromQuatAndPos(avatarLeftArmPose.getRotation(), avatarLeftArmPose.getTranslation());
headParams.leftArmPosition = extractTranslation(leftArmMat);
headParams.leftArmRotation = glmExtractRotation(leftArmMat);
headParams.leftArmEnabled = true;
} else {
headParams.leftArmEnabled = false;
}
headParams.isTalking = head->getTimeWithoutTalking() <= 1.5f;
_rig.updateFromHeadParameters(headParams, deltaTime);

View file

@ -1047,6 +1047,22 @@ void Rig::updateFromHeadParameters(const HeadParameters& params, float dt) {
} else {
_animVars.set("spine2Type", (int)IKTarget::Type::Unknown);
}
if (params.leftArmEnabled) {
_animVars.set("leftArmType", (int)IKTarget::Type::RotationAndPosition);
_animVars.set("leftArmPosition", params.leftArmPosition);
_animVars.set("leftArmRotation", params.leftArmRotation);
} else {
_animVars.set("leftArmType", (int)IKTarget::Type::Unknown);
}
if (params.rightArmEnabled) {
_animVars.set("rightArmType", (int)IKTarget::Type::RotationAndPosition);
_animVars.set("rightArmPosition", params.rightArmPosition);
_animVars.set("rightArmRotation", params.rightArmRotation);
} else {
_animVars.set("rightArmType", (int)IKTarget::Type::Unknown);
}
}
void Rig::updateFromEyeParameters(const EyeParameters& params) {

View file

@ -46,9 +46,15 @@ public:
glm::mat4 spine2Matrix = glm::mat4(); // rig space
glm::quat rigHeadOrientation = glm::quat(); // rig space (-z forward)
glm::vec3 rigHeadPosition = glm::vec3(); // rig space
glm::vec3 rightArmPosition = glm::vec3(); // rig space
glm::quat rightArmRotation = glm::quat(); // rig space
glm::vec3 leftArmPosition = glm::vec3(); // rig space
glm::quat leftArmRotation = glm::quat(); // rig space
bool hipsEnabled = false;
bool headEnabled = false;
bool spine2Enabled = false;
bool leftArmEnabled = false;
bool rightArmEnabled = false;
bool isTalking = false;
};

View file

@ -51,6 +51,8 @@ namespace controller {
makePosePair(Action::LEFT_HAND, "LeftHand"),
makePosePair(Action::RIGHT_HAND, "RightHand"),
makePosePair(Action::RIGHT_ARM, "RightArm"),
makePosePair(Action::LEFT_ARM, "LeftArm"),
makePosePair(Action::LEFT_FOOT, "LeftFoot"),
makePosePair(Action::RIGHT_FOOT, "RightFoot"),
makePosePair(Action::HIPS, "Hips"),

View file

@ -42,6 +42,8 @@ enum class Action {
LEFT_HAND = NUM_COMBINED_AXES,
RIGHT_HAND,
LEFT_ARM,
RIGHT_ARM,
LEFT_FOOT,
RIGHT_FOOT,
HIPS,

View file

@ -24,7 +24,11 @@ struct InputCalibrationData {
glm::mat4 defaultSpine2; // default pose for spine2 joint in avatar space
glm::mat4 defaultHips; // default pose for hips joint in avatar space
glm::mat4 defaultLeftFoot; // default pose for leftFoot joint in avatar space
glm::mat4 defaultRightFoot; // default pose for leftFoot joint in avatar space
glm::mat4 defaultRightFoot; // default pose for rightFoot joint in avatar space
glm::mat4 defaultRightArm; // default pose for rightArm joint in avatar space
glm::mat4 defaultLeftArm; // default pose for leftArm joint in avatar space
glm::mat4 defaultRightHand; // default pose for rightHand joint in avatar space
glm::mat4 defaultLeftHand; // default pose for leftHand joint in avatar space
};
enum class ChannelType {

View file

@ -104,6 +104,8 @@ Input::NamedVector StandardController::getAvailableInputs() const {
makePair(RIGHT_HAND, "RightHand"),
makePair(LEFT_FOOT, "LeftFoot"),
makePair(RIGHT_FOOT, "RightFoot"),
makePair(RIGHT_ARM, "RightArm"),
makePair(LEFT_ARM, "LeftArm"),
makePair(HIPS, "Hips"),
makePair(SPINE2, "Spine2"),
makePair(HEAD, "Head"),

View file

@ -911,22 +911,40 @@ void EntityTreeRenderer::entityCollisionWithEntity(const EntityItemID& idA, cons
// trigger scripted collision sounds and events for locally owned objects
EntityItemPointer entityA = entityTree->findEntityByEntityItemID(idA);
if ((bool)entityA && myNodeID == entityA->getSimulatorID()) {
playEntityCollisionSound(entityA, collision);
emit collisionWithEntity(idA, idB, collision);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(idA, "collisionWithEntity", idB, collision);
}
}
EntityItemPointer entityB = entityTree->findEntityByEntityItemID(idB);
if ((bool)entityB && myNodeID == entityB->getSimulatorID()) {
playEntityCollisionSound(entityB, collision);
// since we're swapping A and B we need to send the inverted collision
Collision invertedCollision(collision);
invertedCollision.invert();
emit collisionWithEntity(idB, idA, invertedCollision);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(idB, "collisionWithEntity", idA, invertedCollision);
if ((bool)entityA && (bool)entityB) {
QUuid entityASimulatorID = entityA->getSimulatorID();
QUuid entityBSimulatorID = entityB->getSimulatorID();
bool entityAIsDynamic = entityA->getDynamic();
bool entityBIsDynamic = entityB->getDynamic();
#ifdef WANT_DEBUG
bool bothEntitiesStatic = !entityAIsDynamic && !entityBIsDynamic;
if (bothEntitiesStatic) {
qCDebug(entities) << "A collision has occurred between two static entities!";
qCDebug(entities) << "Entity A ID:" << entityA->getID();
qCDebug(entities) << "Entity B ID:" << entityB->getID();
}
assert(!bothEntitiesStatic);
#endif
if ((myNodeID == entityASimulatorID && entityAIsDynamic) || (myNodeID == entityBSimulatorID && (!entityAIsDynamic || entityASimulatorID.isNull()))) {
playEntityCollisionSound(entityA, collision);
emit collisionWithEntity(idA, idB, collision);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(idA, "collisionWithEntity", idB, collision);
}
}
if ((myNodeID == entityBSimulatorID && entityBIsDynamic) || (myNodeID == entityASimulatorID && (!entityBIsDynamic || entityBSimulatorID.isNull()))) {
playEntityCollisionSound(entityB, collision);
// since we're swapping A and B we need to send the inverted collision
Collision invertedCollision(collision);
invertedCollision.invert();
emit collisionWithEntity(idB, idA, invertedCollision);
if (_entitiesScriptEngine) {
_entitiesScriptEngine->callEntityScriptMethod(idB, "collisionWithEntity", idA, invertedCollision);
}
}
}
}

View file

@ -210,9 +210,12 @@ public:
};
glm::mat4 getGlobalTransform(const QMultiMap<QString, QString>& _connectionParentMap,
const QHash<QString, FBXModel>& models, QString nodeID, bool mixamoHack) {
const QHash<QString, FBXModel>& models, QString nodeID, bool mixamoHack, const QString& url) {
glm::mat4 globalTransform;
QVector<QString> visitedNodes; // Used to prevent following a cycle
while (!nodeID.isNull()) {
visitedNodes.append(nodeID); // Append each node we visit
const FBXModel& model = models.value(nodeID);
globalTransform = glm::translate(model.translation) * model.preTransform * glm::mat4_cast(model.preRotation *
model.rotation * model.postRotation) * model.postTransform * globalTransform;
@ -223,6 +226,11 @@ glm::mat4 getGlobalTransform(const QMultiMap<QString, QString>& _connectionParen
QList<QString> parentIDs = _connectionParentMap.values(nodeID);
nodeID = QString();
foreach (const QString& parentID, parentIDs) {
if (visitedNodes.contains(parentID)) {
qCWarning(modelformat) << "Ignoring loop detected in FBX connection map for" << url;
continue;
}
if (models.contains(parentID)) {
nodeID = parentID;
break;
@ -347,10 +355,18 @@ void addBlendshapes(const ExtractedBlendshape& extracted, const QList<WeightedIn
}
QString getTopModelID(const QMultiMap<QString, QString>& connectionParentMap,
const QHash<QString, FBXModel>& models, const QString& modelID) {
const QHash<QString, FBXModel>& models, const QString& modelID, const QString& url) {
QString topID = modelID;
QVector<QString> visitedNodes; // Used to prevent following a cycle
forever {
visitedNodes.append(topID); // Append each node we visit
foreach (const QString& parentID, connectionParentMap.values(topID)) {
if (visitedNodes.contains(parentID)) {
qCWarning(modelformat) << "Ignoring loop detected in FBX connection map for" << url;
continue;
}
if (models.contains(parentID)) {
topID = parentID;
goto outerContinue;
@ -1307,7 +1323,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
if (!clusters.contains(clusterID)) {
continue;
}
QString topID = getTopModelID(_connectionParentMap, models, _connectionChildMap.value(clusterID));
QString topID = getTopModelID(_connectionParentMap, models, _connectionChildMap.value(clusterID), url);
_connectionChildMap.remove(_connectionParentMap.take(model.key()), model.key());
_connectionParentMap.insert(model.key(), topID);
goto outerBreak;
@ -1329,7 +1345,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
first = id;
}
}
QString topID = getTopModelID(_connectionParentMap, models, first);
QString topID = getTopModelID(_connectionParentMap, models, first, url);
appendModelIDs(_connectionParentMap.value(topID), _connectionChildMap, models, remainingModels, modelIDs);
}
@ -1511,7 +1527,7 @@ FBXGeometry* FBXReader::extractFBXGeometry(const QVariantHash& mapping, const QS
// accumulate local transforms
QString modelID = models.contains(it.key()) ? it.key() : _connectionParentMap.value(it.key());
glm::mat4 modelTransform = getGlobalTransform(_connectionParentMap, models, modelID, geometry.applicationName == "mixamo.com");
glm::mat4 modelTransform = getGlobalTransform(_connectionParentMap, models, modelID, geometry.applicationName == "mixamo.com", url);
// compute the mesh extents from the transformed vertices
foreach (const glm::vec3& vertex, extracted.mesh.vertices) {

View file

@ -510,29 +510,29 @@ TexturePointer Texture::unserialize(const std::string& ktxfile, const ktx::KTXDe
bool Texture::evalKTXFormat(const Element& mipFormat, const Element& texelFormat, ktx::Header& header) {
if (texelFormat == Format::COLOR_RGBA_32 && mipFormat == Format::COLOR_BGRA_32) {
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::BGRA, ktx::GLInternalFormat_Uncompressed::RGBA8, ktx::GLBaseInternalFormat::RGBA);
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::BGRA, ktx::GLInternalFormat::RGBA8, ktx::GLBaseInternalFormat::RGBA);
} else if (texelFormat == Format::COLOR_RGBA_32 && mipFormat == Format::COLOR_RGBA_32) {
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::RGBA, ktx::GLInternalFormat_Uncompressed::RGBA8, ktx::GLBaseInternalFormat::RGBA);
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::RGBA, ktx::GLInternalFormat::RGBA8, ktx::GLBaseInternalFormat::RGBA);
} else if (texelFormat == Format::COLOR_SRGBA_32 && mipFormat == Format::COLOR_SBGRA_32) {
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::BGRA, ktx::GLInternalFormat_Uncompressed::SRGB8_ALPHA8, ktx::GLBaseInternalFormat::RGBA);
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::BGRA, ktx::GLInternalFormat::SRGB8_ALPHA8, ktx::GLBaseInternalFormat::RGBA);
} else if (texelFormat == Format::COLOR_SRGBA_32 && mipFormat == Format::COLOR_SRGBA_32) {
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::RGBA, ktx::GLInternalFormat_Uncompressed::SRGB8_ALPHA8, ktx::GLBaseInternalFormat::RGBA);
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::RGBA, ktx::GLInternalFormat::SRGB8_ALPHA8, ktx::GLBaseInternalFormat::RGBA);
} else if (texelFormat == Format::COLOR_R_8 && mipFormat == Format::COLOR_R_8) {
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::RED, ktx::GLInternalFormat_Uncompressed::R8, ktx::GLBaseInternalFormat::RED);
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::RED, ktx::GLInternalFormat::R8, ktx::GLBaseInternalFormat::RED);
} else if (texelFormat == Format::VEC2NU8_XY && mipFormat == Format::VEC2NU8_XY) {
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::RG, ktx::GLInternalFormat_Uncompressed::RG8, ktx::GLBaseInternalFormat::RG);
header.setUncompressed(ktx::GLType::UNSIGNED_BYTE, 1, ktx::GLFormat::RG, ktx::GLInternalFormat::RG8, ktx::GLBaseInternalFormat::RG);
} else if (texelFormat == Format::COLOR_COMPRESSED_SRGB && mipFormat == Format::COLOR_COMPRESSED_SRGB) {
header.setCompressed(ktx::GLInternalFormat_Compressed::COMPRESSED_SRGB_S3TC_DXT1_EXT, ktx::GLBaseInternalFormat::RGB);
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT, ktx::GLBaseInternalFormat::RGB);
} else if (texelFormat == Format::COLOR_COMPRESSED_SRGBA_MASK && mipFormat == Format::COLOR_COMPRESSED_SRGBA_MASK) {
header.setCompressed(ktx::GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, ktx::GLBaseInternalFormat::RGBA);
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT, ktx::GLBaseInternalFormat::RGBA);
} else if (texelFormat == Format::COLOR_COMPRESSED_SRGBA && mipFormat == Format::COLOR_COMPRESSED_SRGBA) {
header.setCompressed(ktx::GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, ktx::GLBaseInternalFormat::RGBA);
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, ktx::GLBaseInternalFormat::RGBA);
} else if (texelFormat == Format::COLOR_COMPRESSED_RED && mipFormat == Format::COLOR_COMPRESSED_RED) {
header.setCompressed(ktx::GLInternalFormat_Compressed::COMPRESSED_RED_RGTC1, ktx::GLBaseInternalFormat::RED);
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_RED_RGTC1, ktx::GLBaseInternalFormat::RED);
} else if (texelFormat == Format::COLOR_COMPRESSED_XY && mipFormat == Format::COLOR_COMPRESSED_XY) {
header.setCompressed(ktx::GLInternalFormat_Compressed::COMPRESSED_RG_RGTC2, ktx::GLBaseInternalFormat::RG);
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_RG_RGTC2, ktx::GLBaseInternalFormat::RG);
} else if (texelFormat == Format::COLOR_COMPRESSED_SRGBA_HIGH && mipFormat == Format::COLOR_COMPRESSED_SRGBA_HIGH) {
header.setCompressed(ktx::GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_BPTC_UNORM, ktx::GLBaseInternalFormat::RGBA);
header.setCompressed(ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM, ktx::GLBaseInternalFormat::RGBA);
} else {
return false;
}
@ -542,20 +542,20 @@ bool Texture::evalKTXFormat(const Element& mipFormat, const Element& texelFormat
bool Texture::evalTextureFormat(const ktx::Header& header, Element& mipFormat, Element& texelFormat) {
if (header.getGLFormat() == ktx::GLFormat::BGRA && header.getGLType() == ktx::GLType::UNSIGNED_BYTE && header.getTypeSize() == 1) {
if (header.getGLInternaFormat_Uncompressed() == ktx::GLInternalFormat_Uncompressed::RGBA8) {
if (header.getGLInternaFormat() == ktx::GLInternalFormat::RGBA8) {
mipFormat = Format::COLOR_BGRA_32;
texelFormat = Format::COLOR_RGBA_32;
} else if (header.getGLInternaFormat_Uncompressed() == ktx::GLInternalFormat_Uncompressed::SRGB8_ALPHA8) {
} else if (header.getGLInternaFormat() == ktx::GLInternalFormat::SRGB8_ALPHA8) {
mipFormat = Format::COLOR_SBGRA_32;
texelFormat = Format::COLOR_SRGBA_32;
} else {
return false;
}
} else if (header.getGLFormat() == ktx::GLFormat::RGBA && header.getGLType() == ktx::GLType::UNSIGNED_BYTE && header.getTypeSize() == 1) {
if (header.getGLInternaFormat_Uncompressed() == ktx::GLInternalFormat_Uncompressed::RGBA8) {
if (header.getGLInternaFormat() == ktx::GLInternalFormat::RGBA8) {
mipFormat = Format::COLOR_RGBA_32;
texelFormat = Format::COLOR_RGBA_32;
} else if (header.getGLInternaFormat_Uncompressed() == ktx::GLInternalFormat_Uncompressed::SRGB8_ALPHA8) {
} else if (header.getGLInternaFormat() == ktx::GLInternalFormat::SRGB8_ALPHA8) {
mipFormat = Format::COLOR_SRGBA_32;
texelFormat = Format::COLOR_SRGBA_32;
} else {
@ -563,35 +563,35 @@ bool Texture::evalTextureFormat(const ktx::Header& header, Element& mipFormat, E
}
} else if (header.getGLFormat() == ktx::GLFormat::RED && header.getGLType() == ktx::GLType::UNSIGNED_BYTE && header.getTypeSize() == 1) {
mipFormat = Format::COLOR_R_8;
if (header.getGLInternaFormat_Uncompressed() == ktx::GLInternalFormat_Uncompressed::R8) {
if (header.getGLInternaFormat() == ktx::GLInternalFormat::R8) {
texelFormat = Format::COLOR_R_8;
} else {
return false;
}
} else if (header.getGLFormat() == ktx::GLFormat::RG && header.getGLType() == ktx::GLType::UNSIGNED_BYTE && header.getTypeSize() == 1) {
mipFormat = Format::VEC2NU8_XY;
if (header.getGLInternaFormat_Uncompressed() == ktx::GLInternalFormat_Uncompressed::RG8) {
if (header.getGLInternaFormat() == ktx::GLInternalFormat::RG8) {
texelFormat = Format::VEC2NU8_XY;
} else {
return false;
}
} else if (header.getGLFormat() == ktx::GLFormat::COMPRESSED_FORMAT && header.getGLType() == ktx::GLType::COMPRESSED_TYPE) {
if (header.getGLInternaFormat_Compressed() == ktx::GLInternalFormat_Compressed::COMPRESSED_SRGB_S3TC_DXT1_EXT) {
} else if (header.isCompressed()) {
if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT) {
mipFormat = Format::COLOR_COMPRESSED_SRGB;
texelFormat = Format::COLOR_COMPRESSED_SRGB;
} else if (header.getGLInternaFormat_Compressed() == ktx::GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) {
} else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) {
mipFormat = Format::COLOR_COMPRESSED_SRGBA_MASK;
texelFormat = Format::COLOR_COMPRESSED_SRGBA_MASK;
} else if (header.getGLInternaFormat_Compressed() == ktx::GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT) {
} else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT) {
mipFormat = Format::COLOR_COMPRESSED_SRGBA;
texelFormat = Format::COLOR_COMPRESSED_SRGBA;
} else if (header.getGLInternaFormat_Compressed() == ktx::GLInternalFormat_Compressed::COMPRESSED_RED_RGTC1) {
} else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RED_RGTC1) {
mipFormat = Format::COLOR_COMPRESSED_RED;
texelFormat = Format::COLOR_COMPRESSED_RED;
} else if (header.getGLInternaFormat_Compressed() == ktx::GLInternalFormat_Compressed::COMPRESSED_RG_RGTC2) {
} else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_RG_RGTC2) {
mipFormat = Format::COLOR_COMPRESSED_XY;
texelFormat = Format::COLOR_COMPRESSED_XY;
} else if (header.getGLInternaFormat_Compressed() == ktx::GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_BPTC_UNORM) {
} else if (header.getGLInternaFormat() == ktx::GLInternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM) {
mipFormat = Format::COLOR_COMPRESSED_SRGBA_HIGH;
texelFormat = Format::COLOR_COMPRESSED_SRGBA_HIGH;
} else {

View file

@ -493,10 +493,6 @@ gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(const QImage& s
if (validAlpha) {
processTextureAlpha(image, validAlpha, alphaAsMask);
// NOTE: This disables BC1a compression because it was producing odd artifacts on text textures
// for the tutorial. Instead we use BC3 (which is larger) but doesn't produce the same artifacts).
alphaAsMask = false;
}
gpu::TexturePointer theTexture = nullptr;
@ -506,7 +502,9 @@ gpu::TexturePointer TextureUsage::process2DTextureColorFromImage(const QImage& s
gpu::Element formatGPU;
if (isColorTexturesCompressionEnabled()) {
if (validAlpha) {
formatGPU = alphaAsMask ? gpu::Element::COLOR_COMPRESSED_SRGBA_MASK : gpu::Element::COLOR_COMPRESSED_SRGBA;
// NOTE: This disables BC1a compression because it was producing odd artifacts on text textures
// for the tutorial. Instead we use BC3 (which is larger) but doesn't produce the same artifacts).
formatGPU = gpu::Element::COLOR_COMPRESSED_SRGBA;
} else {
formatGPU = gpu::Element::COLOR_COMPRESSED_SRGB;
}

View file

@ -0,0 +1,304 @@
//
// Created by Bradley Austin Davis on 2017/05/13
// Copyright 2017 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 khronos_khr_hpp
#define khronos_khr_hpp
namespace khronos {
namespace gl {
enum class Type : uint32_t {
// GL 4.4 Table 8.2
UNSIGNED_BYTE = 0x1401,
BYTE = 0x1400,
UNSIGNED_SHORT = 0x1403,
SHORT = 0x1402,
UNSIGNED_INT = 0x1405,
INT = 0x1404,
HALF_FLOAT = 0x140B,
FLOAT = 0x1406,
UNSIGNED_BYTE_3_3_2 = 0x8032,
UNSIGNED_BYTE_2_3_3_REV = 0x8362,
UNSIGNED_SHORT_5_6_5 = 0x8363,
UNSIGNED_SHORT_5_6_5_REV = 0x8364,
UNSIGNED_SHORT_4_4_4_4 = 0x8033,
UNSIGNED_SHORT_4_4_4_4_REV = 0x8365,
UNSIGNED_SHORT_5_5_5_1 = 0x8034,
UNSIGNED_SHORT_1_5_5_5_REV = 0x8366,
UNSIGNED_INT_8_8_8_8 = 0x8035,
UNSIGNED_INT_8_8_8_8_REV = 0x8367,
UNSIGNED_INT_10_10_10_2 = 0x8036,
UNSIGNED_INT_2_10_10_10_REV = 0x8368,
UNSIGNED_INT_24_8 = 0x84FA,
UNSIGNED_INT_10F_11F_11F_REV = 0x8C3B,
UNSIGNED_INT_5_9_9_9_REV = 0x8C3E,
FLOAT_32_UNSIGNED_INT_24_8_REV = 0x8DAD,
};
namespace texture {
enum class Format : uint32_t {
COMPRESSED_FORMAT = 0,
// GL 4.4 Table 8.3
STENCIL_INDEX = 0x1901,
DEPTH_COMPONENT = 0x1902,
DEPTH_STENCIL = 0x84F9,
RED = 0x1903,
GREEN = 0x1904,
BLUE = 0x1905,
RG = 0x8227,
RGB = 0x1907,
RGBA = 0x1908,
BGR = 0x80E0,
BGRA = 0x80E1,
RG_INTEGER = 0x8228,
RED_INTEGER = 0x8D94,
GREEN_INTEGER = 0x8D95,
BLUE_INTEGER = 0x8D96,
RGB_INTEGER = 0x8D98,
RGBA_INTEGER = 0x8D99,
BGR_INTEGER = 0x8D9A,
BGRA_INTEGER = 0x8D9B,
};
enum class InternalFormat : uint32_t {
// GL 4.4 Table 8.12
R8 = 0x8229,
R8_SNORM = 0x8F94,
R16 = 0x822A,
R16_SNORM = 0x8F98,
RG8 = 0x822B,
RG8_SNORM = 0x8F95,
RG16 = 0x822C,
RG16_SNORM = 0x8F99,
R3_G3_B2 = 0x2A10,
RGB4 = 0x804F,
RGB5 = 0x8050,
RGB565 = 0x8D62,
RGB8 = 0x8051,
RGB8_SNORM = 0x8F96,
RGB10 = 0x8052,
RGB12 = 0x8053,
RGB16 = 0x8054,
RGB16_SNORM = 0x8F9A,
RGBA2 = 0x8055,
RGBA4 = 0x8056,
RGB5_A1 = 0x8057,
RGBA8 = 0x8058,
RGBA8_SNORM = 0x8F97,
RGB10_A2 = 0x8059,
RGB10_A2UI = 0x906F,
RGBA12 = 0x805A,
RGBA16 = 0x805B,
RGBA16_SNORM = 0x8F9B,
SRGB8 = 0x8C41,
SRGB8_ALPHA8 = 0x8C43,
R16F = 0x822D,
RG16F = 0x822F,
RGB16F = 0x881B,
RGBA16F = 0x881A,
R32F = 0x822E,
RG32F = 0x8230,
RGB32F = 0x8815,
RGBA32F = 0x8814,
R11F_G11F_B10F = 0x8C3A,
RGB9_E5 = 0x8C3D,
R8I = 0x8231,
R8UI = 0x8232,
R16I = 0x8233,
R16UI = 0x8234,
R32I = 0x8235,
R32UI = 0x8236,
RG8I = 0x8237,
RG8UI = 0x8238,
RG16I = 0x8239,
RG16UI = 0x823A,
RG32I = 0x823B,
RG32UI = 0x823C,
RGB8I = 0x8D8F,
RGB8UI = 0x8D7D,
RGB16I = 0x8D89,
RGB16UI = 0x8D77,
RGB32I = 0x8D83,
RGB32UI = 0x8D71,
RGBA8I = 0x8D8E,
RGBA8UI = 0x8D7C,
RGBA16I = 0x8D88,
RGBA16UI = 0x8D76,
RGBA32I = 0x8D82,
RGBA32UI = 0x8D70,
// GL 4.4 Table 8.13
DEPTH_COMPONENT16 = 0x81A5,
DEPTH_COMPONENT24 = 0x81A6,
DEPTH_COMPONENT32 = 0x81A7,
DEPTH_COMPONENT32F = 0x8CAC,
DEPTH24_STENCIL8 = 0x88F0,
DEPTH32F_STENCIL8 = 0x8CAD,
STENCIL_INDEX1 = 0x8D46,
STENCIL_INDEX4 = 0x8D47,
STENCIL_INDEX8 = 0x8D48,
STENCIL_INDEX16 = 0x8D49,
// GL 4.4 Table 8.14
COMPRESSED_RED = 0x8225,
COMPRESSED_RG = 0x8226,
COMPRESSED_RGB = 0x84ED,
COMPRESSED_RGBA = 0x84EE,
COMPRESSED_SRGB = 0x8C48,
COMPRESSED_SRGB_ALPHA = 0x8C49,
COMPRESSED_ETC1_RGB8_OES = 0x8D64,
COMPRESSED_SRGB_S3TC_DXT1_EXT = 0x8C4C,
COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT = 0x8C4D,
COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT = 0x8C4E,
COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT = 0x8C4F,
COMPRESSED_RED_RGTC1 = 0x8DBB,
COMPRESSED_SIGNED_RED_RGTC1 = 0x8DBC,
COMPRESSED_RG_RGTC2 = 0x8DBD,
COMPRESSED_SIGNED_RG_RGTC2 = 0x8DBE,
COMPRESSED_RGBA_BPTC_UNORM = 0x8E8C,
COMPRESSED_SRGB_ALPHA_BPTC_UNORM = 0x8E8D,
COMPRESSED_RGB_BPTC_SIGNED_FLOAT = 0x8E8E,
COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT = 0x8E8F,
COMPRESSED_RGB8_ETC2 = 0x9274,
COMPRESSED_SRGB8_ETC2 = 0x9275,
COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9276,
COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277,
COMPRESSED_RGBA8_ETC2_EAC = 0x9278,
COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 0x9279,
COMPRESSED_R11_EAC = 0x9270,
COMPRESSED_SIGNED_R11_EAC = 0x9271,
COMPRESSED_RG11_EAC = 0x9272,
COMPRESSED_SIGNED_RG11_EAC = 0x9273,
};
template <uint32_t ALIGNMENT>
inline uint32_t evalAlignedCompressedBlockCount(uint32_t value) {
// FIXME add static assert that ALIGNMENT is a power of 2
static uint32_t ALIGNMENT_REMAINDER = ALIGNMENT - 1;
return (value + ALIGNMENT_REMAINDER) / ALIGNMENT;
}
inline uint32_t evalCompressedBlockCount(InternalFormat format, uint32_t value) {
switch (format) {
case InternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT: // BC1
case InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: // BC1A
case InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: // BC3
case InternalFormat::COMPRESSED_RED_RGTC1: // BC4
case InternalFormat::COMPRESSED_RG_RGTC2: // BC5
case InternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM: // BC7
return evalAlignedCompressedBlockCount<4>(value);
default:
throw std::runtime_error("Unknown format");
}
}
inline uint8_t evalCompressedBlockSize(InternalFormat format) {
switch (format) {
case InternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT:
case InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT:
case InternalFormat::COMPRESSED_RED_RGTC1:
return 8;
case InternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
case InternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
case InternalFormat::COMPRESSED_RG_RGTC2:
return 16;
default:
return 0;
}
}
enum class BaseInternalFormat : uint32_t {
// GL 4.4 Table 8.11
DEPTH_COMPONENT = 0x1902,
DEPTH_STENCIL = 0x84F9,
RED = 0x1903,
RG = 0x8227,
RGB = 0x1907,
RGBA = 0x1908,
STENCIL_INDEX = 0x1901,
};
inline uint8_t evalComponentCount(BaseInternalFormat format) {
switch (format) {
case BaseInternalFormat::DEPTH_COMPONENT:
case BaseInternalFormat::STENCIL_INDEX:
case BaseInternalFormat::RED:
return 1;
case BaseInternalFormat::DEPTH_STENCIL:
case BaseInternalFormat::RG:
return 2;
case BaseInternalFormat::RGB:
return 3;
case BaseInternalFormat::RGBA:
return 4;
default:
break;
}
return 0;
}
namespace cubemap {
enum Constants {
NUM_CUBEMAPFACES = 6,
};
enum class Face {
POSITIVE_X = 0x8515,
NEGATIVE_X = 0x8516,
POSITIVE_Y = 0x8517,
NEGATIVE_Y = 0x8518,
POSITIVE_Z = 0x8519,
NEGATIVE_Z = 0x851A,
};
}
}
}
}
#endif // khronos_khr_hpp

View file

@ -16,16 +16,6 @@
using namespace ktx;
uint32_t Header::evalPadding(size_t byteSize) {
//auto padding = byteSize % PACKING_SIZE;
// return (uint32_t) (padding ? PACKING_SIZE - padding : 0);
return (uint32_t) (3 - (byteSize + 3) % PACKING_SIZE);// padding ? PACKING_SIZE - padding : 0);
}
bool Header::checkAlignment(size_t byteSize) {
return ((byteSize & 0x3) == 0);
}
const Header::Identifier ktx::Header::IDENTIFIER {{
0xAB, 0x4B, 0x54, 0x58, 0x20, 0x31, 0x31, 0xBB, 0x0D, 0x0A, 0x1A, 0x0A
}};
@ -38,68 +28,45 @@ uint32_t Header::evalMaxDimension() const {
return std::max(getPixelWidth(), std::max(getPixelHeight(), getPixelDepth()));
}
uint32_t Header::evalPixelOrBlockDimension(uint32_t pixelDimension) const {
if (isCompressed()) {
return khronos::gl::texture::evalCompressedBlockCount(getGLInternaFormat(), pixelDimension);
}
return pixelDimension;
}
uint32_t Header::evalMipPixelOrBlockDimension(uint32_t mipLevel, uint32_t pixelDimension) const {
uint32_t mipPixelDimension = evalMipDimension(mipLevel, pixelDimension);
return evalPixelOrBlockDimension(mipPixelDimension);
}
uint32_t Header::evalPixelOrBlockWidth(uint32_t level) const {
auto pixelWidth = std::max(getPixelWidth() >> level, 1U);
if (getGLType() == GLType::COMPRESSED_TYPE) {
return (pixelWidth + 3) / 4;
} else {
return pixelWidth;
}
return evalMipPixelOrBlockDimension(level, getPixelWidth());
}
uint32_t Header::evalPixelOrBlockHeight(uint32_t level) const {
auto pixelWidth = std::max(getPixelHeight() >> level, 1U);
if (getGLType() == GLType::COMPRESSED_TYPE) {
auto format = getGLInternaFormat_Compressed();
switch (format) {
case GLInternalFormat_Compressed::COMPRESSED_SRGB_S3TC_DXT1_EXT: // BC1
case GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT: // BC1A
case GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT: // BC3
case GLInternalFormat_Compressed::COMPRESSED_RED_RGTC1: // BC4
case GLInternalFormat_Compressed::COMPRESSED_RG_RGTC2: // BC5
case GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_BPTC_UNORM: // BC7
return (pixelWidth + 3) / 4;
default:
throw std::runtime_error("Unknown format");
}
} else {
return pixelWidth;
}
return evalMipPixelOrBlockDimension(level, getPixelHeight());
}
uint32_t Header::evalPixelOrBlockDepth(uint32_t level) const {
return std::max(getPixelDepth() >> level, 1U);
return evalMipDimension(level, getPixelDepth());
}
size_t Header::evalPixelOrBlockSize() const {
if (getGLType() == GLType::COMPRESSED_TYPE) {
auto format = getGLInternaFormat_Compressed();
if (format == GLInternalFormat_Compressed::COMPRESSED_SRGB_S3TC_DXT1_EXT) {
return 8;
} else if (format == GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT) {
return 8;
} else if (format == GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT) {
return 16;
} else if (format == GLInternalFormat_Compressed::COMPRESSED_RED_RGTC1) {
return 8;
} else if (format == GLInternalFormat_Compressed::COMPRESSED_RG_RGTC2) {
return 16;
} else if (format == GLInternalFormat_Compressed::COMPRESSED_SRGB_ALPHA_BPTC_UNORM) {
return 16;
}
size_t result = 0;
if (isCompressed()) {
auto format = getGLInternaFormat();
result = khronos::gl::texture::evalCompressedBlockSize(format);
} else {
// FIXME should really be using the internal format, not the base internal format
auto baseFormat = getGLBaseInternalFormat();
if (baseFormat == GLBaseInternalFormat::RED) {
return 1;
} else if (baseFormat == GLBaseInternalFormat::RG) {
return 2;
} else if (baseFormat == GLBaseInternalFormat::RGB) {
return 3;
} else if (baseFormat == GLBaseInternalFormat::RGBA) {
return 4;
}
result = khronos::gl::texture::evalComponentCount(baseFormat);
}
qWarning() << "Unknown ktx format: " << glFormat << " " << glBaseInternalFormat << " " << glInternalFormat;
return 0;
if (0 == result) {
qWarning() << "Unknown ktx format: " << glFormat << " " << glBaseInternalFormat << " " << glInternalFormat;
}
return result;
}
size_t Header::evalRowSize(uint32_t level) const {
@ -108,16 +75,16 @@ size_t Header::evalRowSize(uint32_t level) const {
if (pixSize == 0) {
return 0;
}
auto netSize = pixWidth * pixSize;
auto padding = evalPadding(netSize);
return netSize + padding;
return evalPaddedSize(pixWidth * pixSize);
}
size_t Header::evalFaceSize(uint32_t level) const {
auto pixHeight = evalPixelOrBlockHeight(level);
auto pixDepth = evalPixelOrBlockDepth(level);
auto rowSize = evalRowSize(level);
return pixDepth * pixHeight * rowSize;
}
size_t Header::evalImageSize(uint32_t level) const {
auto faceSize = evalFaceSize(level);
if (!checkAlignment(faceSize)) {
@ -192,7 +159,7 @@ KeyValue::KeyValue(const std::string& key, const std::string& value) :
}
uint32_t KeyValue::serializedByteSize() const {
return (uint32_t) (sizeof(uint32_t) + _byteSize + Header::evalPadding(_byteSize));
return (uint32_t)sizeof(uint32_t) + evalPaddedSize(_byteSize);
}
uint32_t KeyValue::serializedKeyValuesByteSize(const KeyValues& keyValues) {
@ -200,14 +167,8 @@ uint32_t KeyValue::serializedKeyValuesByteSize(const KeyValues& keyValues) {
for (auto& keyval : keyValues) {
keyValuesSize += keyval.serializedByteSize();
}
return (keyValuesSize + Header::evalPadding(keyValuesSize));
}
KTX::KTX() {
}
KTX::~KTX() {
Q_ASSERT(keyValuesSize % 4 == 0);
return keyValuesSize;
}
void KTX::resetStorage(const StoragePointer& storage) {
@ -230,7 +191,7 @@ size_t KTX::getTexelsDataSize() const {
if (!_storage) {
return 0;
}
return (_storage->data() + _storage->size()) - getTexelsData();
return _storage->size() - sizeof(Header) - getKeyValueDataSize();
}
const Byte* KTX::getKeyValueData() const {

View file

@ -22,7 +22,14 @@
#include <shared/Storage.h>
/* KTX Spec:
#include "../khronos/KHR.h"
/*
KTX Specification: https://www.khronos.org/opengles/sdk/tools/KTX/file_format_spec/
**** A KTX header is 64 bytes layed out as follows
Byte[12] identifier
UInt32 endianness
@ -38,6 +45,8 @@ UInt32 numberOfArrayElements
UInt32 numberOfFaces
UInt32 numberOfMipmapLevels
UInt32 bytesOfKeyValueData
**** Each KTX key value pair block is 4 byte aligned
for each keyValuePair that fits in bytesOfKeyValueData
UInt32 keyAndValueByteSize
@ -45,6 +54,8 @@ for each keyValuePair that fits in bytesOfKeyValueData
Byte valuePadding[3 - ((keyAndValueByteSize + 3) % 4)]
end
**** Each mip and cube face is 4 byte aligned
for each mipmap_level in numberOfMipmapLevels*
UInt32 imageSize;
for each array_element in numberOfArrayElements*
@ -67,229 +78,22 @@ end
** Uncompressed texture data matches a GL_UNPACK_ALIGNMENT of 4.
*/
namespace ktx {
const uint32_t PACKING_SIZE { sizeof(uint32_t) };
const std::string HIFI_MIN_POPULATED_MIP_KEY{ "hifi.minMip" };
// Alignment constants
static const uint32_t ALIGNMENT { sizeof(uint32_t) };
static const uint32_t ALIGNMENT_REMAINDER { ALIGNMENT - 1 };
static const uint32_t NUM_CUBEMAPFACES = khronos::gl::texture::cubemap::NUM_CUBEMAPFACES;
// FIXME move out of this header, not specific to ktx
const std::string HIFI_MIN_POPULATED_MIP_KEY { "hifi.minMip" };
using Byte = uint8_t;
enum class GLType : uint32_t {
COMPRESSED_TYPE = 0,
// GL 4.4 Table 8.2
UNSIGNED_BYTE = 0x1401,
BYTE = 0x1400,
UNSIGNED_SHORT = 0x1403,
SHORT = 0x1402,
UNSIGNED_INT = 0x1405,
INT = 0x1404,
HALF_FLOAT = 0x140B,
FLOAT = 0x1406,
UNSIGNED_BYTE_3_3_2 = 0x8032,
UNSIGNED_BYTE_2_3_3_REV = 0x8362,
UNSIGNED_SHORT_5_6_5 = 0x8363,
UNSIGNED_SHORT_5_6_5_REV = 0x8364,
UNSIGNED_SHORT_4_4_4_4 = 0x8033,
UNSIGNED_SHORT_4_4_4_4_REV = 0x8365,
UNSIGNED_SHORT_5_5_5_1 = 0x8034,
UNSIGNED_SHORT_1_5_5_5_REV = 0x8366,
UNSIGNED_INT_8_8_8_8 = 0x8035,
UNSIGNED_INT_8_8_8_8_REV = 0x8367,
UNSIGNED_INT_10_10_10_2 = 0x8036,
UNSIGNED_INT_2_10_10_10_REV = 0x8368,
UNSIGNED_INT_24_8 = 0x84FA,
UNSIGNED_INT_10F_11F_11F_REV = 0x8C3B,
UNSIGNED_INT_5_9_9_9_REV = 0x8C3E,
FLOAT_32_UNSIGNED_INT_24_8_REV = 0x8DAD,
};
enum class GLFormat : uint32_t {
COMPRESSED_FORMAT = 0,
// GL 4.4 Table 8.3
STENCIL_INDEX = 0x1901,
DEPTH_COMPONENT = 0x1902,
DEPTH_STENCIL = 0x84F9,
RED = 0x1903,
GREEN = 0x1904,
BLUE = 0x1905,
RG = 0x8227,
RGB = 0x1907,
RGBA = 0x1908,
BGR = 0x80E0,
BGRA = 0x80E1,
RG_INTEGER = 0x8228,
RED_INTEGER = 0x8D94,
GREEN_INTEGER = 0x8D95,
BLUE_INTEGER = 0x8D96,
RGB_INTEGER = 0x8D98,
RGBA_INTEGER = 0x8D99,
BGR_INTEGER = 0x8D9A,
BGRA_INTEGER = 0x8D9B,
};
enum class GLInternalFormat_Uncompressed : uint32_t {
// GL 4.4 Table 8.12
R8 = 0x8229,
R8_SNORM = 0x8F94,
R16 = 0x822A,
R16_SNORM = 0x8F98,
RG8 = 0x822B,
RG8_SNORM = 0x8F95,
RG16 = 0x822C,
RG16_SNORM = 0x8F99,
R3_G3_B2 = 0x2A10,
RGB4 = 0x804F,
RGB5 = 0x8050,
RGB565 = 0x8D62,
RGB8 = 0x8051,
RGB8_SNORM = 0x8F96,
RGB10 = 0x8052,
RGB12 = 0x8053,
RGB16 = 0x8054,
RGB16_SNORM = 0x8F9A,
RGBA2 = 0x8055,
RGBA4 = 0x8056,
RGB5_A1 = 0x8057,
RGBA8 = 0x8058,
RGBA8_SNORM = 0x8F97,
RGB10_A2 = 0x8059,
RGB10_A2UI = 0x906F,
RGBA12 = 0x805A,
RGBA16 = 0x805B,
RGBA16_SNORM = 0x8F9B,
SRGB8 = 0x8C41,
SRGB8_ALPHA8 = 0x8C43,
R16F = 0x822D,
RG16F = 0x822F,
RGB16F = 0x881B,
RGBA16F = 0x881A,
R32F = 0x822E,
RG32F = 0x8230,
RGB32F = 0x8815,
RGBA32F = 0x8814,
R11F_G11F_B10F = 0x8C3A,
RGB9_E5 = 0x8C3D,
R8I = 0x8231,
R8UI = 0x8232,
R16I = 0x8233,
R16UI = 0x8234,
R32I = 0x8235,
R32UI = 0x8236,
RG8I = 0x8237,
RG8UI = 0x8238,
RG16I = 0x8239,
RG16UI = 0x823A,
RG32I = 0x823B,
RG32UI = 0x823C,
RGB8I = 0x8D8F,
RGB8UI = 0x8D7D,
RGB16I = 0x8D89,
RGB16UI = 0x8D77,
RGB32I = 0x8D83,
RGB32UI = 0x8D71,
RGBA8I = 0x8D8E,
RGBA8UI = 0x8D7C,
RGBA16I = 0x8D88,
RGBA16UI = 0x8D76,
RGBA32I = 0x8D82,
RGBA32UI = 0x8D70,
// GL 4.4 Table 8.13
DEPTH_COMPONENT16 = 0x81A5,
DEPTH_COMPONENT24 = 0x81A6,
DEPTH_COMPONENT32 = 0x81A7,
DEPTH_COMPONENT32F = 0x8CAC,
DEPTH24_STENCIL8 = 0x88F0,
DEPTH32F_STENCIL8 = 0x8CAD,
STENCIL_INDEX1 = 0x8D46,
STENCIL_INDEX4 = 0x8D47,
STENCIL_INDEX8 = 0x8D48,
STENCIL_INDEX16 = 0x8D49,
};
enum class GLInternalFormat_Compressed : uint32_t {
// GL 4.4 Table 8.14
COMPRESSED_RED = 0x8225,
COMPRESSED_RG = 0x8226,
COMPRESSED_RGB = 0x84ED,
COMPRESSED_RGBA = 0x84EE,
COMPRESSED_SRGB = 0x8C48,
COMPRESSED_SRGB_ALPHA = 0x8C49,
COMPRESSED_SRGB_S3TC_DXT1_EXT = 0x8C4C,
COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT = 0x8C4D,
COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT = 0x8C4E,
COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT = 0x8C4F,
COMPRESSED_RED_RGTC1 = 0x8DBB,
COMPRESSED_SIGNED_RED_RGTC1 = 0x8DBC,
COMPRESSED_RG_RGTC2 = 0x8DBD,
COMPRESSED_SIGNED_RG_RGTC2 = 0x8DBE,
COMPRESSED_RGBA_BPTC_UNORM = 0x8E8C,
COMPRESSED_SRGB_ALPHA_BPTC_UNORM = 0x8E8D,
COMPRESSED_RGB_BPTC_SIGNED_FLOAT = 0x8E8E,
COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT = 0x8E8F,
COMPRESSED_RGB8_ETC2 = 0x9274,
COMPRESSED_SRGB8_ETC2 = 0x9275,
COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9276,
COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277,
COMPRESSED_RGBA8_ETC2_EAC = 0x9278,
COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 0x9279,
COMPRESSED_R11_EAC = 0x9270,
COMPRESSED_SIGNED_R11_EAC = 0x9271,
COMPRESSED_RG11_EAC = 0x9272,
COMPRESSED_SIGNED_RG11_EAC = 0x9273,
};
enum class GLBaseInternalFormat : uint32_t {
// GL 4.4 Table 8.11
DEPTH_COMPONENT = 0x1902,
DEPTH_STENCIL = 0x84F9,
RED = 0x1903,
RG = 0x8227,
RGB = 0x1907,
RGBA = 0x1908,
STENCIL_INDEX = 0x1901,
};
enum CubeMapFace {
POS_X = 0,
NEG_X = 1,
POS_Y = 2,
NEG_Y = 3,
POS_Z = 4,
NEG_Z = 5,
NUM_CUBEMAPFACES = 6,
};
using GLType = khronos::gl::Type;
using GLFormat = khronos::gl::texture::Format;
using GLInternalFormat = khronos::gl::texture::InternalFormat;
using GLBaseInternalFormat = khronos::gl::texture::BaseInternalFormat;
using Storage = storage::Storage;
using StoragePointer = std::shared_ptr<Storage>;
@ -299,31 +103,54 @@ namespace ktx {
bool checkIdentifier(const Byte* identifier);
// Returns the number of bytes required be added to the passed value to make it 4 byte aligned
template <typename T>
inline uint8_t evalPadding(T value) {
return ALIGNMENT_REMAINDER - ((value + ALIGNMENT_REMAINDER) % ALIGNMENT);
}
// Returns the passed value rounded up to the next 4 byte aligned value, if it's not already 4 byte aligned
template <typename T>
inline T evalPaddedSize(T value) {
return (value + ALIGNMENT_REMAINDER) & ~(T)ALIGNMENT_REMAINDER;
}
template <typename T>
inline T evalAlignedCount(T value) {
return (value + ALIGNMENT_REMAINDER) / ALIGNMENT;
}
template <typename T>
inline bool checkAlignment(T value) {
return ((value & ALIGNMENT_REMAINDER) == 0);
}
// Header
struct Header {
static const size_t IDENTIFIER_LENGTH = 12;
static const uint32_t COMPRESSED_FORMAT { 0 };
static const uint32_t COMPRESSED_TYPE { 0 };
static const uint32_t COMPRESSED_TYPE_SIZE { 1 };
static const size_t IDENTIFIER_LENGTH { 12 };
using Identifier = std::array<uint8_t, IDENTIFIER_LENGTH>;
static const Identifier IDENTIFIER;
static const uint32_t ENDIAN_TEST = 0x04030201;
static const uint32_t REVERSE_ENDIAN_TEST = 0x01020304;
static uint32_t evalPadding(size_t byteSize);
static bool checkAlignment(size_t byteSize);
Header();
Byte identifier[IDENTIFIER_LENGTH];
uint32_t endianness { ENDIAN_TEST };
uint32_t glType;
uint32_t glType { static_cast<uint32_t>(GLType::UNSIGNED_BYTE) };
uint32_t glTypeSize { 0 };
uint32_t glFormat;
uint32_t glInternalFormat;
uint32_t glBaseInternalFormat;
uint32_t glFormat { static_cast<uint32_t>(GLFormat::RGBA) };
uint32_t glInternalFormat { static_cast<uint32_t>(GLInternalFormat::RGBA8) };
uint32_t glBaseInternalFormat { static_cast<uint32_t>(GLBaseInternalFormat::RGBA) };
uint32_t pixelWidth { 1 };
uint32_t pixelHeight { 0 };
uint32_t pixelHeight { 1 };
uint32_t pixelDepth { 0 };
uint32_t numberOfArrayElements { 0 };
uint32_t numberOfFaces { 1 };
@ -336,6 +163,7 @@ namespace ktx {
uint32_t getPixelDepth() const { return (pixelDepth ? pixelDepth : 1); }
uint32_t getNumberOfSlices() const { return (numberOfArrayElements ? numberOfArrayElements : 1); }
uint32_t getNumberOfLevels() const { return (numberOfMipmapLevels ? numberOfMipmapLevels : 1); }
bool isCompressed() const { return glFormat == COMPRESSED_FORMAT; }
uint32_t evalMaxDimension() const;
uint32_t evalPixelOrBlockWidth(uint32_t level) const;
@ -347,17 +175,21 @@ namespace ktx {
size_t evalFaceSize(uint32_t level) const;
size_t evalImageSize(uint32_t level) const;
void setUncompressed(GLType type, uint32_t typeSize, GLFormat format, GLInternalFormat_Uncompressed internalFormat, GLBaseInternalFormat baseInternalFormat) {
// FIXME base internal format should automatically be determined by internal format
// FIXME type size should automatically be determined by type
void setUncompressed(GLType type, uint32_t typeSize, GLFormat format, GLInternalFormat internalFormat, GLBaseInternalFormat baseInternalFormat) {
glType = (uint32_t) type;
glTypeSize = typeSize;
glFormat = (uint32_t) format;
glInternalFormat = (uint32_t) internalFormat;
glBaseInternalFormat = (uint32_t) baseInternalFormat;
}
void setCompressed(GLInternalFormat_Compressed internalFormat, GLBaseInternalFormat baseInternalFormat) {
glType = (uint32_t) GLType::COMPRESSED_TYPE;
glTypeSize = 1;
glFormat = (uint32_t) GLFormat::COMPRESSED_FORMAT;
// FIXME base internal format should automatically be determined by internal format
void setCompressed(GLInternalFormat internalFormat, GLBaseInternalFormat baseInternalFormat) {
glType = COMPRESSED_TYPE;
glFormat = COMPRESSED_FORMAT;
glTypeSize = COMPRESSED_TYPE_SIZE;
glInternalFormat = (uint32_t) internalFormat;
glBaseInternalFormat = (uint32_t) baseInternalFormat;
}
@ -365,18 +197,9 @@ namespace ktx {
GLType getGLType() const { return (GLType)glType; }
uint32_t getTypeSize() const { return glTypeSize; }
GLFormat getGLFormat() const { return (GLFormat)glFormat; }
GLInternalFormat_Uncompressed getGLInternaFormat_Uncompressed() const { return (GLInternalFormat_Uncompressed)glInternalFormat; }
GLInternalFormat_Compressed getGLInternaFormat_Compressed() const { return (GLInternalFormat_Compressed)glInternalFormat; }
GLInternalFormat getGLInternaFormat() const { return (GLInternalFormat)glInternalFormat; }
GLBaseInternalFormat getGLBaseInternalFormat() const { return (GLBaseInternalFormat)glBaseInternalFormat; }
void setDimensions(uint32_t width, uint32_t height = 0, uint32_t depth = 0, uint32_t numSlices = 0, uint32_t numFaces = 1) {
pixelWidth = (width > 0 ? width : 1);
pixelHeight = height;
pixelDepth = depth;
numberOfArrayElements = numSlices;
numberOfFaces = ((numFaces == 1) || (numFaces == NUM_CUBEMAPFACES) ? numFaces : 1);
}
void set1D(uint32_t width) { setDimensions(width); }
void set1DArray(uint32_t width, uint32_t numSlices) { setDimensions(width, 0, 0, (numSlices > 0 ? numSlices : 1)); }
void set2D(uint32_t width, uint32_t height) { setDimensions(width, height); }
@ -386,12 +209,33 @@ namespace ktx {
void setCube(uint32_t width, uint32_t height) { setDimensions(width, height, 0, 0, NUM_CUBEMAPFACES); }
void setCubeArray(uint32_t width, uint32_t height, uint32_t numSlices) { setDimensions(width, height, 0, (numSlices > 0 ? numSlices : 1), NUM_CUBEMAPFACES); }
bool isValid() const;
// Generate a set of image descriptors based on the assumption that the full mip pyramid is populated
ImageDescriptors generateImageDescriptors() const;
private:
uint32_t evalPixelOrBlockDimension(uint32_t pixelDimension) const;
uint32_t evalMipPixelOrBlockDimension(uint32_t level, uint32_t pixelDimension) const;
static inline uint32_t evalMipDimension(uint32_t mipLevel, uint32_t pixelDimension) {
return std::max(pixelDimension >> mipLevel, 1U);
}
void setDimensions(uint32_t width, uint32_t height = 0, uint32_t depth = 0, uint32_t numSlices = 0, uint32_t numFaces = 1) {
pixelWidth = (width > 0 ? width : 1);
pixelHeight = height;
pixelDepth = depth;
numberOfArrayElements = numSlices;
numberOfFaces = numFaces;
}
};
static const size_t KTX_HEADER_SIZE = 64;
// Size as specified by the KTX specification
static const size_t KTX_HEADER_SIZE { 64 };
static_assert(sizeof(Header) == KTX_HEADER_SIZE, "KTX Header size is static and should not change from the spec");
static const size_t KV_SIZE_WIDTH = 4; // Number of bytes for keyAndValueByteSize
static const size_t IMAGE_SIZE_WIDTH = 4; // Number of bytes for imageSize
static const size_t KV_SIZE_WIDTH { ALIGNMENT }; // Number of bytes for keyAndValueByteSize
static const size_t IMAGE_SIZE_WIDTH { ALIGNMENT }; // Number of bytes for imageSize
// Key Values
struct KeyValue {
@ -426,6 +270,7 @@ namespace ktx {
const uint32_t _imageSize;
const uint32_t _faceSize;
const uint32_t _padding;
ImageHeader(bool cube, size_t imageOffset, uint32_t imageSize, uint32_t padding) :
_numFaces(cube ? NUM_CUBEMAPFACES : 1),
_imageOffset(imageOffset),
@ -481,11 +326,11 @@ namespace ktx {
class KTX {
void resetStorage(const StoragePointer& src);
KTX();
KTX() {}
KTX(const StoragePointer& storage, const Header& header, const KeyValues& keyValues, const Images& images);
public:
~KTX();
static bool validate(const StoragePointer& src);
// Define a KTX object manually to write it somewhere (in a file on disk?)
// This path allocate the Storage where to store header, keyvalues and copy mips
// Then COPY all the data
@ -530,6 +375,7 @@ namespace ktx {
KTXDescriptor toDescriptor() const;
size_t getKeyValueDataSize() const;
size_t getTexelsDataSize() const;
bool isValid() const;
Header _header;
StoragePointer _storage;

View file

@ -151,7 +151,7 @@ namespace ktx {
auto expectedImageSize = header.evalImageSize((uint32_t) images.size());
if (imageSize != expectedImageSize) {
break;
} else if (!Header::checkAlignment(imageSize)) {
} else if (!checkAlignment(imageSize)) {
break;
}
@ -163,7 +163,7 @@ namespace ktx {
// If enough data ahead then capture the pointer
if ((currentPtr - srcBytes) + imageSize <= (srcSize)) {
auto padding = Header::evalPadding(imageSize);
auto padding = evalPadding(imageSize);
if (numFaces == NUM_CUBEMAPFACES) {
Image::FaceBytes faces(NUM_CUBEMAPFACES);

View file

@ -0,0 +1,428 @@
//
// Created by Bradley Austin Davis on 2017/05/13
// Copyright 2017 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 "KTX.h"
#include <unordered_set>
#include <QDebug>
using namespace ktx;
static const std::unordered_set<uint32_t> VALID_GL_TYPES {
(uint32_t)GLType::UNSIGNED_BYTE,
(uint32_t)GLType::BYTE,
(uint32_t)GLType::UNSIGNED_SHORT,
(uint32_t)GLType::SHORT,
(uint32_t)GLType::UNSIGNED_INT,
(uint32_t)GLType::INT,
(uint32_t)GLType::HALF_FLOAT,
(uint32_t)GLType::FLOAT,
(uint32_t)GLType::UNSIGNED_BYTE_3_3_2,
(uint32_t)GLType::UNSIGNED_BYTE_2_3_3_REV,
(uint32_t)GLType::UNSIGNED_SHORT_5_6_5,
(uint32_t)GLType::UNSIGNED_SHORT_5_6_5_REV,
(uint32_t)GLType::UNSIGNED_SHORT_4_4_4_4,
(uint32_t)GLType::UNSIGNED_SHORT_4_4_4_4_REV,
(uint32_t)GLType::UNSIGNED_SHORT_5_5_5_1,
(uint32_t)GLType::UNSIGNED_SHORT_1_5_5_5_REV,
(uint32_t)GLType::UNSIGNED_INT_8_8_8_8,
(uint32_t)GLType::UNSIGNED_INT_8_8_8_8_REV,
(uint32_t)GLType::UNSIGNED_INT_10_10_10_2,
(uint32_t)GLType::UNSIGNED_INT_2_10_10_10_REV,
(uint32_t)GLType::UNSIGNED_INT_24_8,
(uint32_t)GLType::UNSIGNED_INT_10F_11F_11F_REV,
(uint32_t)GLType::UNSIGNED_INT_5_9_9_9_REV,
(uint32_t)GLType::FLOAT_32_UNSIGNED_INT_24_8_REV,
};
static const std::unordered_set<uint32_t> VALID_GL_FORMATS {
(uint32_t)GLFormat::STENCIL_INDEX,
(uint32_t)GLFormat::DEPTH_COMPONENT,
(uint32_t)GLFormat::DEPTH_STENCIL,
(uint32_t)GLFormat::RED,
(uint32_t)GLFormat::GREEN,
(uint32_t)GLFormat::BLUE,
(uint32_t)GLFormat::RG,
(uint32_t)GLFormat::RGB,
(uint32_t)GLFormat::RGBA,
(uint32_t)GLFormat::BGR,
(uint32_t)GLFormat::BGRA,
(uint32_t)GLFormat::RG_INTEGER,
(uint32_t)GLFormat::RED_INTEGER,
(uint32_t)GLFormat::GREEN_INTEGER,
(uint32_t)GLFormat::BLUE_INTEGER,
(uint32_t)GLFormat::RGB_INTEGER,
(uint32_t)GLFormat::RGBA_INTEGER,
(uint32_t)GLFormat::BGR_INTEGER,
(uint32_t)GLFormat::BGRA_INTEGER,
};
static const std::unordered_set<uint32_t> VALID_GL_INTERNAL_FORMATS {
(uint32_t)GLInternalFormat::R8,
(uint32_t)GLInternalFormat::R8_SNORM,
(uint32_t)GLInternalFormat::R16,
(uint32_t)GLInternalFormat::R16_SNORM,
(uint32_t)GLInternalFormat::RG8,
(uint32_t)GLInternalFormat::RG8_SNORM,
(uint32_t)GLInternalFormat::RG16,
(uint32_t)GLInternalFormat::RG16_SNORM,
(uint32_t)GLInternalFormat::R3_G3_B2,
(uint32_t)GLInternalFormat::RGB4,
(uint32_t)GLInternalFormat::RGB5,
(uint32_t)GLInternalFormat::RGB565,
(uint32_t)GLInternalFormat::RGB8,
(uint32_t)GLInternalFormat::RGB8_SNORM,
(uint32_t)GLInternalFormat::RGB10,
(uint32_t)GLInternalFormat::RGB12,
(uint32_t)GLInternalFormat::RGB16,
(uint32_t)GLInternalFormat::RGB16_SNORM,
(uint32_t)GLInternalFormat::RGBA2,
(uint32_t)GLInternalFormat::RGBA4,
(uint32_t)GLInternalFormat::RGB5_A1,
(uint32_t)GLInternalFormat::RGBA8,
(uint32_t)GLInternalFormat::RGBA8_SNORM,
(uint32_t)GLInternalFormat::RGB10_A2,
(uint32_t)GLInternalFormat::RGB10_A2UI,
(uint32_t)GLInternalFormat::RGBA12,
(uint32_t)GLInternalFormat::RGBA16,
(uint32_t)GLInternalFormat::RGBA16_SNORM,
(uint32_t)GLInternalFormat::SRGB8,
(uint32_t)GLInternalFormat::SRGB8_ALPHA8,
(uint32_t)GLInternalFormat::R16F,
(uint32_t)GLInternalFormat::RG16F,
(uint32_t)GLInternalFormat::RGB16F,
(uint32_t)GLInternalFormat::RGBA16F,
(uint32_t)GLInternalFormat::R32F,
(uint32_t)GLInternalFormat::RG32F,
(uint32_t)GLInternalFormat::RGBA32F,
(uint32_t)GLInternalFormat::R11F_G11F_B10F,
(uint32_t)GLInternalFormat::RGB9_E5,
(uint32_t)GLInternalFormat::R8I,
(uint32_t)GLInternalFormat::R8UI,
(uint32_t)GLInternalFormat::R16I,
(uint32_t)GLInternalFormat::R16UI,
(uint32_t)GLInternalFormat::R32I,
(uint32_t)GLInternalFormat::R32UI,
(uint32_t)GLInternalFormat::RG8I,
(uint32_t)GLInternalFormat::RG8UI,
(uint32_t)GLInternalFormat::RG16I,
(uint32_t)GLInternalFormat::RG16UI,
(uint32_t)GLInternalFormat::RG32I,
(uint32_t)GLInternalFormat::RG32UI,
(uint32_t)GLInternalFormat::RGB8I,
(uint32_t)GLInternalFormat::RGB8UI,
(uint32_t)GLInternalFormat::RGB16I,
(uint32_t)GLInternalFormat::RGB16UI,
(uint32_t)GLInternalFormat::RGB32I,
(uint32_t)GLInternalFormat::RGB32UI,
(uint32_t)GLInternalFormat::RGBA8I,
(uint32_t)GLInternalFormat::RGBA8UI,
(uint32_t)GLInternalFormat::RGBA16I,
(uint32_t)GLInternalFormat::RGBA16UI,
(uint32_t)GLInternalFormat::RGBA32I,
(uint32_t)GLInternalFormat::RGBA32UI,
(uint32_t)GLInternalFormat::DEPTH_COMPONENT16,
(uint32_t)GLInternalFormat::DEPTH_COMPONENT24,
(uint32_t)GLInternalFormat::DEPTH_COMPONENT32,
(uint32_t)GLInternalFormat::DEPTH_COMPONENT32F,
(uint32_t)GLInternalFormat::DEPTH24_STENCIL8,
(uint32_t)GLInternalFormat::DEPTH32F_STENCIL8,
(uint32_t)GLInternalFormat::STENCIL_INDEX1,
(uint32_t)GLInternalFormat::STENCIL_INDEX4,
(uint32_t)GLInternalFormat::STENCIL_INDEX8,
(uint32_t)GLInternalFormat::STENCIL_INDEX16,
};
static const std::unordered_set<uint32_t> VALID_GL_INTERNAL_COMPRESSED_FORMATS {
(uint32_t)GLInternalFormat::COMPRESSED_RED,
(uint32_t)GLInternalFormat::COMPRESSED_RG,
(uint32_t)GLInternalFormat::COMPRESSED_RGB,
(uint32_t)GLInternalFormat::COMPRESSED_RGBA,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB_ALPHA,
(uint32_t)GLInternalFormat::COMPRESSED_ETC1_RGB8_OES,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB_S3TC_DXT1_EXT,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT1_EXT,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT,
(uint32_t)GLInternalFormat::COMPRESSED_RED_RGTC1,
(uint32_t)GLInternalFormat::COMPRESSED_SIGNED_RED_RGTC1,
(uint32_t)GLInternalFormat::COMPRESSED_RG_RGTC2,
(uint32_t)GLInternalFormat::COMPRESSED_SIGNED_RG_RGTC2,
(uint32_t)GLInternalFormat::COMPRESSED_RGBA_BPTC_UNORM,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB_ALPHA_BPTC_UNORM,
(uint32_t)GLInternalFormat::COMPRESSED_RGB_BPTC_SIGNED_FLOAT,
(uint32_t)GLInternalFormat::COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT,
(uint32_t)GLInternalFormat::COMPRESSED_RGB8_ETC2,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB8_ETC2,
(uint32_t)GLInternalFormat::COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2,
(uint32_t)GLInternalFormat::COMPRESSED_RGBA8_ETC2_EAC,
(uint32_t)GLInternalFormat::COMPRESSED_SRGB8_ALPHA8_ETC2_EAC,
(uint32_t)GLInternalFormat::COMPRESSED_R11_EAC,
(uint32_t)GLInternalFormat::COMPRESSED_SIGNED_R11_EAC,
(uint32_t)GLInternalFormat::COMPRESSED_RG11_EAC,
(uint32_t)GLInternalFormat::COMPRESSED_SIGNED_RG11_EAC,
};
static const std::unordered_set<uint32_t> VALID_GL_BASE_INTERNAL_FORMATS {
(uint32_t)GLBaseInternalFormat::DEPTH_COMPONENT,
(uint32_t)GLBaseInternalFormat::DEPTH_STENCIL,
(uint32_t)GLBaseInternalFormat::RED,
(uint32_t)GLBaseInternalFormat::RG,
(uint32_t)GLBaseInternalFormat::RGB,
(uint32_t)GLBaseInternalFormat::RGBA,
(uint32_t)GLBaseInternalFormat::STENCIL_INDEX,
};
bool Header::isValid() const {
if (0 != memcmp(identifier, IDENTIFIER.data(), IDENTIFIER_LENGTH)) {
qDebug() << "Invalid header identifier";
return false;
}
if (endianness != ENDIAN_TEST && endianness != REVERSE_ENDIAN_TEST) {
qDebug("Invalid endian marker 0x%x", endianness);
return false;
}
//
// GL enum validity
//
if (VALID_GL_BASE_INTERNAL_FORMATS.count(glBaseInternalFormat) != 1) {
qDebug("Invalid base internal format 0x%x", glBaseInternalFormat);
return false;
}
if (isCompressed()) {
if (glType != COMPRESSED_TYPE) {
qDebug("Invalid type for compressed texture 0x%x", glType);
return false;
}
if (glTypeSize != COMPRESSED_TYPE_SIZE) {
qDebug("Invalid type size for compressed texture %d", glTypeSize);
return false;
}
if (VALID_GL_INTERNAL_COMPRESSED_FORMATS.count(glInternalFormat) != 1) {
qDebug("Invalid compressed internal format 0x%x", glInternalFormat);
return false;
}
} else {
if (VALID_GL_TYPES.count(glType) != 1) {
qDebug("Invalid type 0x%x", glType);
return false;
}
if (VALID_GL_FORMATS.count(glFormat) != 1) {
qDebug("Invalid format 0x%x", glFormat);
return false;
}
if (VALID_GL_INTERNAL_FORMATS.count(glInternalFormat) != 1) {
qDebug("Invalid internal format 0x%x", glInternalFormat);
return false;
}
}
//
// Dimensions validity
//
// Textures must at least have a width
// If they have a depth, they must have a height
if ((pixelWidth == 0) || (pixelDepth != 0 && pixelHeight == 0)) {
qDebug() << "Invalid dimensions " << pixelWidth << "x" << pixelHeight << "x" << pixelDepth;
return false;
}
if (numberOfFaces != 1 && numberOfFaces != NUM_CUBEMAPFACES) {
qDebug() << "Invalid number of faces " << numberOfFaces;
return false;
}
// FIXME validate numberOfMipmapLevels based on the dimensions?
if ((bytesOfKeyValueData % 4) != 0) {
qDebug() << "Invalid keyvalue data size " << bytesOfKeyValueData;
return false;
}
return true;
}
struct AlignedStreamBuffer {
AlignedStreamBuffer(size_t size, const uint8_t* data)
: _size(size), _data(data) { }
AlignedStreamBuffer(const StoragePointer& storage)
: AlignedStreamBuffer(storage->size(), storage->data()) { }
template<typename T>
bool read(T& t) {
// Ensure we don't read more than we have
if (sizeof(T) > _size) {
return false;
}
// Grab the data
memcpy(&t, _data, sizeof(T));
// Advance the pointer
return skip(sizeof(T));
}
bool skip(size_t skipSize) {
skipSize = ktx::evalPaddedSize(skipSize);
if (skipSize > _size) {
return false;
}
_data += skipSize;
_size -= skipSize;
return true;
}
AlignedStreamBuffer front(size_t size) const {
return AlignedStreamBuffer { std::min(size, _size), _data };
}
bool empty() const {
return _size == 0;
}
private:
size_t _size;
const uint8_t* _data;
};
bool validateKeyValueData(AlignedStreamBuffer kvbuffer) {
while (!kvbuffer.empty()) {
uint32_t keyValueSize;
// Try to fetch the size of the next key value block
if (!kvbuffer.read(keyValueSize)) {
qDebug() << "Unable to read past key value size";
return false;
}
if (!kvbuffer.skip(keyValueSize)) {
qDebug() << "Unable to skip past key value data";
return false;
}
}
return true;
}
bool KTX::validate(const StoragePointer& src) {
if (!checkAlignment(src->size())) {
// All KTX data is 4-byte aligned
qDebug() << "Invalid size, not 4 byte aligned";
return false;
}
Header header;
AlignedStreamBuffer buffer { src };
if (!buffer.read(header)) {
qDebug() << "Unable to read header";
return false;
}
// Basic header validation, are the enums and size valid?
if (!header.isValid()) {
qDebug() << "Invalid header";
return false;
}
// Validate the key value pairs
if (!validateKeyValueData(buffer.front(header.bytesOfKeyValueData))) {
qDebug() << "Invalid key value data";
return false;
}
// now skip the KV data
if (!buffer.skip(header.bytesOfKeyValueData)) {
qDebug() << "Unable to read past key value data";
return false;
}
// Validate the images
for (uint32_t mip = 0; mip < header.numberOfMipmapLevels; ++mip) {
uint32_t imageSize;
if (!buffer.read(imageSize)) {
qDebug() << "Unable to read image size";
return false;
}
uint32_t arrayElements = header.numberOfArrayElements == 0 ? 1 : header.numberOfArrayElements;
for (uint32_t arrayElement = 0; arrayElement < arrayElements; ++arrayElement) {
for (uint8_t face = 0; face < header.numberOfFaces; ++face) {
if (!buffer.skip(imageSize)) {
qDebug() << "Unable to skip past image data";
return false;
}
}
}
}
// The buffer should be empty afer we've skipped all of the KTX data
if (!buffer.empty()) {
return false;
}
return true;
}
bool KTX::isValid() const {
if (!_header.isValid()) {
return false;
}
if (_images.size() != _header.numberOfMipmapLevels) {
return false;
}
const auto start = _storage->data();
const auto end = start + _storage->size();
// FIXME, do key value checks?
for (const auto& image : _images) {
if (image._numFaces != _header.numberOfFaces) {
return false;
}
for (const auto& facePointer : image._faceBytes) {
if (facePointer + image._faceSize > end) {
return false;
}
}
}
for (uint8_t mip = 0; mip < _header.numberOfMipmapLevels; ++mip) {
for (uint8_t face = 0; face < _header.numberOfFaces; ++face) {
auto faceStorage = getMipFaceTexelsData(mip, face);
// The face start offset must be 4 byte aligned
if (!checkAlignment(faceStorage->data() - start)) {
return false;
}
// The face size must be 4 byte aligned
if (!checkAlignment(faceStorage->size())) {
return false;
}
}
}
return true;
}

View file

@ -70,8 +70,7 @@ namespace ktx {
for (uint32_t l = 0; l < numMips; l++) {
if (images.size() > l) {
storageSize += sizeof(uint32_t);
storageSize += images[l]._imageSize;
storageSize += Header::evalPadding(images[l]._imageSize);
storageSize += evalPaddedSize(images[l]._imageSize);
}
}
return storageSize;
@ -89,8 +88,7 @@ namespace ktx {
for (uint32_t l = 0; l < numMips; l++) {
if (imageDescriptors.size() > l) {
storageSize += sizeof(uint32_t);
storageSize += imageDescriptors[l]._imageSize;
storageSize += Header::evalPadding(imageDescriptors[l]._imageSize);
storageSize += evalPaddedSize(imageDescriptors[l]._imageSize);
}
}
return storageSize;
@ -221,7 +219,7 @@ namespace ktx {
// If enough data ahead then capture the copy source pointer
if (currentDataSize + imageSize <= (allocatedImagesDataSize)) {
auto padding = Header::evalPadding(imageSize);
auto padding = evalPadding(imageSize);
// Single face vs cubes
if (srcImages[l]._numFaces == 1) {

View file

@ -114,7 +114,8 @@ public:
EntityServerScriptLog,
AdjustAvatarSorting,
OctreeFileReplacement,
LAST_PACKET_TYPE = OctreeFileReplacement
CollisionEventChanges,
LAST_PACKET_TYPE = CollisionEventChanges
};
};

View file

@ -26,8 +26,12 @@
#define __LOC__ __FILE__ "(" __STR1__(__LINE__) ") : Warning Msg: "
static const QString DESKTOP_LOCATION = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
static const bool HIFI_SCRIPT_DEBUGGABLES { true };
static const QString SETTINGS_KEY { "RunningScripts" };
static const QUrl DEFAULT_SCRIPTS_LOCATION { "file:///~//defaultScripts.js" };
// Using a QVariantList so this is human-readable in the settings file
static Setting::Handle<QVariantList> runningScriptsHandle(SETTINGS_KEY, { QVariant(DEFAULT_SCRIPTS_LOCATION) });
ScriptsModel& getScriptsModel() {
static ScriptsModel scriptsModel;
@ -61,19 +65,6 @@ ScriptEngines::ScriptEngines(ScriptEngine::Context context)
_scriptsModelFilter.setSourceModel(&_scriptsModel);
_scriptsModelFilter.sort(0, Qt::AscendingOrder);
_scriptsModelFilter.setDynamicSortFilter(true);
static const int SCRIPT_SAVE_COUNTDOWN_INTERVAL_MS = 5000;
QTimer* scriptSaveTimer = new QTimer(this);
scriptSaveTimer->setSingleShot(true);
QMetaObject::Connection timerConnection = connect(scriptSaveTimer, &QTimer::timeout, [] {
DependencyManager::get<ScriptEngines>()->saveScripts();
});
connect(qApp, &QCoreApplication::aboutToQuit, [=] {
disconnect(timerConnection);
});
connect(this, &ScriptEngines::scriptCountChanged, this, [scriptSaveTimer] {
scriptSaveTimer->start(SCRIPT_SAVE_COUNTDOWN_INTERVAL_MS);
}, Qt::QueuedConnection);
}
QUrl normalizeScriptURL(const QUrl& rawScriptURL) {
@ -280,13 +271,8 @@ QVariantList ScriptEngines::getRunning() {
return result;
}
static const QString SETTINGS_KEY = "RunningScripts";
void ScriptEngines::loadDefaultScripts() {
QUrl defaultScriptsLoc = defaultScriptsLocation();
defaultScriptsLoc.setPath(defaultScriptsLoc.path() + "/defaultScripts.js");
loadScript(defaultScriptsLoc.toString());
loadScript(DEFAULT_SCRIPTS_LOCATION);
}
void ScriptEngines::loadOneScript(const QString& scriptFilename) {
@ -294,17 +280,11 @@ void ScriptEngines::loadOneScript(const QString& scriptFilename) {
}
void ScriptEngines::loadScripts() {
// check first run...
Setting::Handle<bool> firstRun { Settings::firstRun, true };
if (firstRun.get()) {
qCDebug(scriptengine) << "This is a first run...";
// clear the scripts, and set out script to our default scripts
clearScripts();
loadDefaultScripts();
return;
}
// loads all saved scripts
// START BACKWARD COMPATIBILITY CODE
// The following code makes sure people don't lose all their scripts
// This should be removed after a reasonable ammount of time went by
// Load old setting format if present
bool foundDeprecatedSetting = false;
Settings settings;
int size = settings.beginReadArray(SETTINGS_KEY);
for (int i = 0; i < size; ++i) {
@ -312,35 +292,51 @@ void ScriptEngines::loadScripts() {
QString string = settings.value("script").toString();
if (!string.isEmpty()) {
loadScript(string);
foundDeprecatedSetting = true;
}
}
settings.endArray();
}
if (foundDeprecatedSetting) {
// Remove old settings found and return
settings.beginWriteArray(SETTINGS_KEY);
settings.remove("");
settings.endArray();
settings.remove(SETTINGS_KEY + "/size");
return;
}
// END BACKWARD COMPATIBILITY CODE
void ScriptEngines::clearScripts() {
// clears all scripts from the settingsSettings settings;
Settings settings;
settings.beginWriteArray(SETTINGS_KEY);
settings.remove("");
settings.endArray();
// loads all saved scripts
auto runningScripts = runningScriptsHandle.get();
for (auto script : runningScripts) {
auto string = script.toString();
if (!string.isEmpty()) {
loadScript(string);
}
}
}
void ScriptEngines::saveScripts() {
// Saves all currently running user-loaded scripts
Settings settings;
settings.beginWriteArray(SETTINGS_KEY);
settings.remove("");
// Do not save anything if we are in the process of shutting down
if (qApp->closingDown()) {
qWarning() << "Trying to save scripts during shutdown.";
return;
}
QStringList runningScripts = getRunningScripts();
int i = 0;
for (auto it = runningScripts.begin(); it != runningScripts.end(); ++it) {
if (getScriptEngine(*it)->isUserLoaded()) {
settings.setArrayIndex(i);
settings.setValue("script", normalizeScriptURL(*it).toString());
++i;
// Saves all currently running user-loaded scripts
QVariantList list;
{
QReadLocker lock(&_scriptEnginesHashLock);
for (auto it = _scriptEnginesHash.begin(); it != _scriptEnginesHash.end(); ++it) {
if (it.value() && it.value()->isUserLoaded()) {
auto normalizedUrl = normalizeScriptURL(it.key());
list.append(normalizedUrl.toString());
}
}
}
settings.endArray();
runningScriptsHandle.set(list);
}
QStringList ScriptEngines::getRunningScripts() {
@ -513,6 +509,9 @@ void ScriptEngines::onScriptEngineLoaded(const QString& rawScriptURL) {
QUrl normalized = normalizeScriptURL(url);
_scriptEnginesHash.insertMulti(normalized, scriptEngine);
}
// Update settings with new script
saveScripts();
emit scriptCountChanged();
}
@ -553,6 +552,8 @@ void ScriptEngines::onScriptFinished(const QString& rawScriptURL, ScriptEngine*
}
if (removed) {
// Update settings with removed script
saveScripts();
emit scriptCountChanged();
}
}

View file

@ -40,7 +40,6 @@ public:
void loadScripts();
void saveScripts();
void clearScripts();
QString getScriptsLocation() const;
void loadDefaultScripts();

View file

@ -33,6 +33,7 @@
#include <controllers/StandardControls.h>
extern PoseData _nextSimPoseData;
vr::IVRSystem* acquireOpenVrSystem();
@ -49,6 +50,7 @@ static const char* RENDER_CONTROLLERS = "Render Hand Controllers";
static const int MIN_PUCK_COUNT = 2;
static const int MIN_FEET_AND_HIPS = 3;
static const int MIN_FEET_HIPS_CHEST = 4;
static const int MIN_FEET_HIPS_SHOULDERS = 5;
static const int FIRST_FOOT = 0;
static const int SECOND_FOOT = 1;
static const int HIP = 2;
@ -70,10 +72,14 @@ static glm::mat4 computeOffset(glm::mat4 defaultToReferenceMat, glm::mat4 defaul
return glm::inverse(poseMat) * referenceJointMat;
}
static bool sortPucksYPosition(std::pair<uint32_t, controller::Pose> firstPuck, std::pair<uint32_t, controller::Pose> secondPuck) {
static bool sortPucksYPosition(PuckPosePair firstPuck, PuckPosePair secondPuck) {
return (firstPuck.second.translation.y < secondPuck.second.translation.y);
}
static bool sortPucksXPosition(PuckPosePair firstPuck, PuckPosePair secondPuck) {
return (firstPuck.second.translation.x < secondPuck.second.translation.x);
}
static QString deviceTrackingResultToString(vr::ETrackingResult trackingResult) {
QString result;
auto iterator = TRACKING_RESULT_TO_STRING.find(trackingResult);
@ -168,6 +174,7 @@ ViveControllerManager::InputDevice::InputDevice(vr::IVRSystem*& system) : contro
_configStringMap[Config::Feet] = QString("Feet");
_configStringMap[Config::FeetAndHips] = QString("FeetAndHips");
_configStringMap[Config::FeetHipsAndChest] = QString("FeetHipsAndChest");
_configStringMap[Config::FeetHipsAndShoulders] = QString("FeetHipsAndShoulders");
if (openVrSupported()) {
createPreferences();
@ -333,34 +340,21 @@ void ViveControllerManager::InputDevice::calibrate(const controller::InputCalibr
std::sort(_validTrackedObjects.begin(), _validTrackedObjects.end(), sortPucksYPosition);
auto& firstFoot = _validTrackedObjects[FIRST_FOOT];
auto& secondFoot = _validTrackedObjects[SECOND_FOOT];
controller::Pose& firstFootPose = firstFoot.second;
controller::Pose& secondFootPose = secondFoot.second;
if (firstFootPose.translation.x < secondFootPose.translation.x) {
_jointToPuckMap[controller::LEFT_FOOT] = firstFoot.first;
_pucksOffset[firstFoot.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultLeftFoot, firstFootPose);
_jointToPuckMap[controller::RIGHT_FOOT] = secondFoot.first;
_pucksOffset[secondFoot.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultRightFoot, secondFootPose);
} else {
_jointToPuckMap[controller::LEFT_FOOT] = secondFoot.first;
_pucksOffset[secondFoot.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultLeftFoot, secondFootPose);
_jointToPuckMap[controller::RIGHT_FOOT] = firstFoot.first;
_pucksOffset[firstFoot.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultRightFoot, firstFootPose);
}
if (_config == Config::Feet) {
// done
calibrateFeet(defaultToReferenceMat, inputCalibration);
} else if (_config == Config::FeetAndHips && puckCount >= MIN_FEET_AND_HIPS) {
_jointToPuckMap[controller::HIPS] = _validTrackedObjects[HIP].first;
_pucksOffset[_validTrackedObjects[HIP].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultHips, _validTrackedObjects[HIP].second);
calibrateFeet(defaultToReferenceMat, inputCalibration);
calibrateHips(defaultToReferenceMat, inputCalibration);
} else if (_config == Config::FeetHipsAndChest && puckCount >= MIN_FEET_HIPS_CHEST) {
_jointToPuckMap[controller::HIPS] = _validTrackedObjects[HIP].first;
_pucksOffset[_validTrackedObjects[HIP].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultHips, _validTrackedObjects[HIP].second);
_jointToPuckMap[controller::SPINE2] = _validTrackedObjects[CHEST].first;
_pucksOffset[_validTrackedObjects[CHEST].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultSpine2, _validTrackedObjects[CHEST].second);
calibrateFeet(defaultToReferenceMat, inputCalibration);
calibrateHips(defaultToReferenceMat, inputCalibration);
calibrateChest(defaultToReferenceMat, inputCalibration);
} else if (_config == Config::FeetHipsAndShoulders && puckCount >= MIN_FEET_HIPS_SHOULDERS) {
calibrateFeet(defaultToReferenceMat, inputCalibration);
calibrateHips(defaultToReferenceMat, inputCalibration);
int firstShoulderIndex = 3;
int secondShoulderIndex = 4;
calibrateShoulders(defaultToReferenceMat, inputCalibration, firstShoulderIndex, secondShoulderIndex);
} else {
qDebug() << "Puck Calibration: " << configToString(_config) << " Config Failed: Could not meet the minimal # of pucks";
uncalibrate();
@ -382,6 +376,8 @@ void ViveControllerManager::InputDevice::updateCalibratedLimbs() {
_poseStateMap[controller::RIGHT_FOOT] = addOffsetToPuckPose(controller::RIGHT_FOOT);
_poseStateMap[controller::HIPS] = addOffsetToPuckPose(controller::HIPS);
_poseStateMap[controller::SPINE2] = addOffsetToPuckPose(controller::SPINE2);
_poseStateMap[controller::RIGHT_ARM] = addOffsetToPuckPose(controller::RIGHT_ARM);
_poseStateMap[controller::LEFT_ARM] = addOffsetToPuckPose(controller::LEFT_ARM);
}
controller::Pose ViveControllerManager::InputDevice::addOffsetToPuckPose(int joint) const {
@ -615,6 +611,56 @@ void ViveControllerManager::InputDevice::hapticsHelper(float deltaTime, bool lef
}
}
void ViveControllerManager::InputDevice::calibrateFeet(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
auto& firstFoot = _validTrackedObjects[FIRST_FOOT];
auto& secondFoot = _validTrackedObjects[SECOND_FOOT];
controller::Pose& firstFootPose = firstFoot.second;
controller::Pose& secondFootPose = secondFoot.second;
if (firstFootPose.translation.x < secondFootPose.translation.x) {
_jointToPuckMap[controller::LEFT_FOOT] = firstFoot.first;
_pucksOffset[firstFoot.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultLeftFoot, firstFootPose);
_jointToPuckMap[controller::RIGHT_FOOT] = secondFoot.first;
_pucksOffset[secondFoot.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultRightFoot, secondFootPose);
} else {
_jointToPuckMap[controller::LEFT_FOOT] = secondFoot.first;
_pucksOffset[secondFoot.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultLeftFoot, secondFootPose);
_jointToPuckMap[controller::RIGHT_FOOT] = firstFoot.first;
_pucksOffset[firstFoot.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultRightFoot, firstFootPose);
}
}
void ViveControllerManager::InputDevice::calibrateHips(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
_jointToPuckMap[controller::HIPS] = _validTrackedObjects[HIP].first;
_pucksOffset[_validTrackedObjects[HIP].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultHips, _validTrackedObjects[HIP].second);
}
void ViveControllerManager::InputDevice::calibrateChest(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration) {
_jointToPuckMap[controller::SPINE2] = _validTrackedObjects[CHEST].first;
_pucksOffset[_validTrackedObjects[CHEST].first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultSpine2, _validTrackedObjects[CHEST].second);
}
void ViveControllerManager::InputDevice::calibrateShoulders(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration,
int firstShoulderIndex, int secondShoulderIndex) {
const PuckPosePair& firstShoulder = _validTrackedObjects[firstShoulderIndex];
const PuckPosePair& secondShoulder = _validTrackedObjects[secondShoulderIndex];
const controller::Pose& firstShoulderPose = firstShoulder.second;
const controller::Pose& secondShoulderPose = secondShoulder.second;
if (firstShoulderPose.translation.x < secondShoulderPose.translation.x) {
_jointToPuckMap[controller::LEFT_ARM] = firstShoulder.first;
_pucksOffset[firstShoulder.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultLeftArm, firstShoulder.second);
_jointToPuckMap[controller::RIGHT_ARM] = secondShoulder.first;
_pucksOffset[secondShoulder.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultRightArm, secondShoulder.second);
} else {
_jointToPuckMap[controller::LEFT_ARM] = secondShoulder.first;
_pucksOffset[secondShoulder.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultLeftArm, secondShoulder.second);
_jointToPuckMap[controller::RIGHT_ARM] = firstShoulder.first;
_pucksOffset[firstShoulder.first] = computeOffset(defaultToReferenceMat, inputCalibration.defaultRightArm, firstShoulder.second);
}
}
void ViveControllerManager::InputDevice::loadSettings() {
Settings settings;
settings.beginGroup("PUCK_CONFIG");
@ -646,6 +692,8 @@ void ViveControllerManager::InputDevice::setConfigFromString(const QString& valu
_preferedConfig = Config::FeetAndHips;
} else if (value == "FeetHipsAndChest") {
_preferedConfig = Config::FeetHipsAndChest;
} else if (value == "FeetHipsAndShoulders") {
_preferedConfig = Config::FeetHipsAndShoulders;
}
}
@ -658,7 +706,7 @@ void ViveControllerManager::InputDevice::createPreferences() {
auto getter = [this]()->QString { return _configStringMap[_preferedConfig]; };
auto setter = [this](const QString& value) { setConfigFromString(value); saveSettings(); };
auto preference = new ComboBoxPreference(VIVE_PUCKS_CONFIG, "Configuration", getter, setter);
QStringList list = (QStringList() << "Auto" << "Feet" << "FeetAndHips" << "FeetHipsAndChest");
QStringList list = {"Auto", "Feet", "FeetAndHips", "FeetHipsAndChest", "FeetHipsAndShoulders"};
preference->setItems(list);
preferences->addPreference(preference);
@ -710,6 +758,8 @@ controller::Input::NamedVector ViveControllerManager::InputDevice::getAvailableI
makePair(HIPS, "Hips"),
makePair(SPINE2, "Spine2"),
makePair(HEAD, "Head"),
makePair(LEFT_ARM, "LeftArm"),
makePair(RIGHT_ARM, "RightArm"),
// 16 tracked poses
makePair(TRACKED_OBJECT_00, "TrackedObject00"),

View file

@ -27,6 +27,8 @@
#include <render/Scene.h>
#include "OpenVrHelpers.h"
using PuckPosePair = std::pair<uint32_t, controller::Pose>;
namespace vr {
class IVRSystem;
}
@ -78,6 +80,15 @@ private:
const vec3& angularVelocity);
void partitionTouchpad(int sButton, int xAxis, int yAxis, int centerPsuedoButton, int xPseudoButton, int yPseudoButton);
void printDeviceTrackingResultChange(uint32_t deviceIndex);
void setConfigFromString(const QString& value);
void loadSettings();
void saveSettings() const;
void calibrateFeet(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
void calibrateHips(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
void calibrateChest(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration);
void calibrateShoulders(glm::mat4& defaultToReferenceMat, const controller::InputCalibrationData& inputCalibration,
int firstShoulderIndex, int secondShoulderIndex);
class FilteredStick {
public:
@ -102,13 +113,19 @@ private:
float _timer { 0.0f };
glm::vec2 _stick { 0.0f, 0.0f };
};
enum class Config { Feet, FeetAndHips, FeetHipsAndChest, Auto };
enum class Config {
Auto,
Feet,
FeetAndHips,
FeetHipsAndChest,
FeetHipsAndShoulders,
};
Config _config { Config::Auto };
Config _preferedConfig { Config::Auto };
FilteredStick _filteredLeftStick;
FilteredStick _filteredRightStick;
std::vector<std::pair<uint32_t, controller::Pose>> _validTrackedObjects;
std::vector<PuckPosePair> _validTrackedObjects;
std::map<uint32_t, glm::mat4> _pucksOffset;
std::map<int, uint32_t> _jointToPuckMap;
std::map<Config, QString> _configStringMap;
@ -131,9 +148,6 @@ private:
mutable std::recursive_mutex _lock;
QString configToString(Config config);
void setConfigFromString(const QString& value);
void loadSettings();
void saveSettings() const;
friend class ViveControllerManager;
};

View file

@ -20,9 +20,9 @@ Item {
id: stats
spacing: 8
anchors.fill:parent
property var config: Render.getConfig("Stats")
function evalEvenHeight() {
// Why do we have to do that manually ? cannot seem to find a qml / anchor / layout mode that does that ?
return (height - spacing * (children.length - 1)) / children.length
@ -81,7 +81,7 @@ Item {
color: "#1AC567"
},
{
prop: "textureGPUTransferCount",
prop: "texturePendingGPUTransferCount",
label: "Transfer",
color: "#9495FF"
}
@ -158,7 +158,7 @@ Item {
}
]
}
PlotPerf {
title: "State Changes"
height: parent.evalEvenHeight()
@ -180,7 +180,7 @@ Item {
color: "#1AC567"
}
]
}
}
property var drawOpaqueConfig: Render.getConfig("DrawOpaqueDeferred")
property var drawTransparentConfig: Render.getConfig("DrawTransparentDeferred")
@ -211,7 +211,7 @@ Item {
color: "#FED959"
}
]
}
}
PlotPerf {
title: "Timing"
@ -250,4 +250,3 @@ Item {
}
}

View file

@ -1036,8 +1036,8 @@ function getControllerJointIndex(hand) {
"_CONTROLLER_RIGHTHAND" :
"_CONTROLLER_LEFTHAND");
}
return MyAvatar.getJointIndex("Head");
return MyAvatar.getJointIndex("Head");
}
// global EquipHotspotBuddy instance
@ -1331,7 +1331,7 @@ function MyController(hand) {
if (this.stylus) {
return;
}
var stylusProperties = {
name: "stylus",
url: Script.resourcesPath() + "meshes/tablet-stylus-fat.fbx",
@ -2134,7 +2134,7 @@ function MyController(hand) {
return null;
}
};
this.chooseNearEquipHotspotsForFarToNearEquip = function(candidateEntities, distance) {
var equippableHotspots = flatten(candidateEntities.map(function(entityID) {
return _this.collectEquipHotspots(entityID);
@ -2291,7 +2291,7 @@ function MyController(hand) {
return;
}
}
if (isInEditMode()) {
this.searchIndicatorOn(rayPickInfo.searchRay);
if (this.triggerSmoothedGrab()) {
@ -2347,10 +2347,11 @@ function MyController(hand) {
var avatar = AvatarList.getAvatar(this.otherGrabbingUUID);
var IN_FRONT_OF_AVATAR = { x: 0, y: 0.2, z: 0.4 }; // Up from hips and in front of avatar.
var startPosition = Vec3.sum(avatar.position, Vec3.multiplyQbyV(avatar.rotation, IN_FRONT_OF_AVATAR));
var finishPisition = Vec3.sum(rayPickInfo.properties.position, // Entity's centroid.
Vec3.multiplyQbyV(rayPickInfo.properties.rotation ,
Vec3.multiplyVbyV(rayPickInfo.properties.dimensions,
Vec3.subtract(DEFAULT_REGISTRATION_POINT, rayPickInfo.properties.registrationPoint))));
var rayHitProps = entityPropertiesCache.getProps(rayPickInfo.entityID);
var finishPisition = Vec3.sum(rayHitProps.position, // Entity's centroid.
Vec3.multiplyQbyV(rayHitProps.rotation,
Vec3.multiplyVbyV(rayHitProps.dimensions,
Vec3.subtract(DEFAULT_REGISTRATION_POINT, rayHitProps.registrationPoint))));
this.otherGrabbingLineOn(startPosition, finishPisition, COLORS_GRAB_DISTANCE_HOLD);
} else {
this.otherGrabbingLineOff();
@ -3442,14 +3443,14 @@ function MyController(hand) {
};
this.offEnter = function() {
// Reuse the existing search distance if lasers were active since
// Reuse the existing search distance if lasers were active since
// they will be shown in OFF state while in edit mode.
var existingSearchDistance = this.searchSphereDistance;
this.release();
if (isInEditMode()) {
this.searchSphereDistance = existingSearchDistance;
}
}
};
this.entityLaserTouchingEnter = function() {
@ -4154,7 +4155,7 @@ var updateWrapper = function () {
}
Script.setTimeout(updateWrapper, UPDATE_SLEEP_MS);
}
};
Script.setTimeout(updateWrapper, UPDATE_SLEEP_MS);
function cleanup() {

View file

@ -261,7 +261,7 @@
}
}
gpuTextures = Render.getConfig("Stats").textureGPUTransferCount;
gpuTextures = Render.getConfig("Stats").texturePendingGPUTransferCount;
// Update state
if (!visible) { // Not visible because no recent downloads
@ -290,7 +290,7 @@
}, FADE_OUT_WAIT);
}
} else {
if (displayProgress < 100 || gpuTextures > 0) { // Was finished and waiting to fade out but have resumed so
if (displayProgress < 100 || gpuTextures > 0) { // Was finished and waiting to fade out but have resumed so
// don't fade out
Script.clearInterval(fadeWaitTimer);
fadeWaitTimer = null;

View file

@ -21,6 +21,7 @@
#include <QtCore/QTimer>
#include <QtCore/QThread>
#include <QtCore/QThreadPool>
#include <QtCore/QSaveFile>
#include <QtGui/QGuiApplication>
#include <QtGui/QResizeEvent>
@ -38,14 +39,12 @@
#include <StatTracker.h>
#include <LogHandler.h>
#include <gpu/Texture.h>
#include <gl/Config.h>
#include <model/TextureMap.h>
#include <ktx/KTX.h>
#include <image/Image.h>
QSharedPointer<FileLogger> logger;
gpu::Texture* cacheTexture(const std::string& name, gpu::Texture* srcTexture, bool write = true, bool read = true);
@ -59,7 +58,9 @@ void messageHandler(QtMsgType type, const QMessageLogContext& context, const QSt
OutputDebugStringA(logMessage.toLocal8Bit().constData());
OutputDebugStringA("\n");
#endif
logger->addMessage(qPrintable(logMessage + "\n"));
if (logger) {
logger->addMessage(qPrintable(logMessage + "\n"));
}
}
}
@ -88,6 +89,20 @@ int main(int argc, char** argv) {
QCoreApplication::setOrganizationDomain("highfidelity.com");
logger.reset(new FileLogger());
Q_ASSERT(ktx::evalPadding(0) == 0);
Q_ASSERT(ktx::evalPadding(1) == 3);
Q_ASSERT(ktx::evalPadding(2) == 2);
Q_ASSERT(ktx::evalPadding(3) == 1);
Q_ASSERT(ktx::evalPadding(4) == 0);
Q_ASSERT(ktx::evalPadding(1024) == 0);
Q_ASSERT(ktx::evalPadding(1025) == 3);
Q_ASSERT(ktx::evalPaddedSize(0) == 0);
Q_ASSERT(ktx::evalPaddedSize(1) == 4);
Q_ASSERT(ktx::evalPaddedSize(2) == 4);
Q_ASSERT(ktx::evalPaddedSize(3) == 4);
Q_ASSERT(ktx::evalPaddedSize(4) == 4);
Q_ASSERT(ktx::evalPaddedSize(1024) == 1024);
Q_ASSERT(ktx::evalPaddedSize(1025) == 1028);
Q_ASSERT(sizeof(ktx::Header) == 12 + (sizeof(uint32_t) * 13));
DependencyManager::set<tracing::Tracer>();
@ -100,8 +115,10 @@ int main(int argc, char** argv) {
auto ktxMemory = gpu::Texture::serialize(*testTexture);
{
const auto& ktxStorage = ktxMemory->getStorage();
QFile outFile(TEST_IMAGE_KTX);
if (!outFile.open(QFile::Truncate | QFile::ReadWrite)) {
Q_ASSERT_X(ktx::KTX::validate(ktxStorage), __FUNCTION__, "KTX storage validation failed");
Q_ASSERT_X(ktxMemory->isValid(), __FUNCTION__, "KTX self-validation failed");
QSaveFile outFile(TEST_IMAGE_KTX);
if (!outFile.open(QFile::WriteOnly)) {
throw std::runtime_error("Unable to open file");
}
auto ktxSize = ktxStorage->size();
@ -109,7 +126,7 @@ int main(int argc, char** argv) {
auto dest = outFile.map(0, ktxSize);
memcpy(dest, ktxStorage->data(), ktxSize);
outFile.unmap(dest);
outFile.close();
outFile.commit();
}
{
@ -149,5 +166,58 @@ int main(int argc, char** argv) {
return 0;
}
#if 0
static const QString TEST_FOLDER { "H:/ktx_cacheold" };
//static const QString TEST_FOLDER { "C:/Users/bdavis/Git/KTX/testimages" };
//static const QString EXTENSIONS { "4bbdf8f786470e4ab3e672d44b8e8df2.ktx" };
static const QString EXTENSIONS { "*.ktx" };
int mainTemp(int, char**) {
qInstallMessageHandler(messageHandler);
auto fileInfoList = QDir { TEST_FOLDER }.entryInfoList(QStringList { EXTENSIONS });
for (auto fileInfo : fileInfoList) {
qDebug() << fileInfo.filePath();
std::shared_ptr<storage::Storage> storage { new storage::FileStorage { fileInfo.filePath() } };
if (!ktx::KTX::validate(storage)) {
qDebug() << "KTX invalid";
}
auto ktxFile = ktx::KTX::create(storage);
ktx::KTXDescriptor ktxDescriptor = ktxFile->toDescriptor();
qDebug() << "Contains " << ktxDescriptor.keyValues.size() << " key value pairs";
for (const auto& kv : ktxDescriptor.keyValues) {
qDebug() << "\t" << kv._key.c_str();
}
auto offsetToMinMipKV = ktxDescriptor.getValueOffsetForKey(ktx::HIFI_MIN_POPULATED_MIP_KEY);
if (offsetToMinMipKV) {
auto data = storage->data() + ktx::KTX_HEADER_SIZE + offsetToMinMipKV;
auto minMipLevelAvailable = *data;
qDebug() << "\tMin mip available " << minMipLevelAvailable;
assert(minMipLevelAvailable < ktxDescriptor.header.numberOfMipmapLevels);
}
auto storageSize = storage->size();
for (const auto& faceImageDesc : ktxDescriptor.images) {
//assert(0 == (faceImageDesc._faceSize % 4));
for (const auto& faceOffset : faceImageDesc._faceOffsets) {
assert(0 == (faceOffset % 4));
auto faceEndOffset = faceOffset + faceImageDesc._faceSize;
assert(faceEndOffset <= storageSize);
}
}
for (const auto& faceImage : ktxFile->_images) {
for (const ktx::Byte* faceBytes : faceImage._faceBytes) {
assert(0 == (reinterpret_cast<size_t>(faceBytes) % 4));
}
}
}
return 0;
}
#endif
#include "main.moc"