From 37dd58dca45e27f0feab20193f303a7cfddfa5eb Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Fri, 9 Feb 2024 22:06:11 +0000 Subject: [PATCH 01/29] Update assimpShapeLoader.cpp non destructive fixes for assimp loader -this creates an ambient sequence if 1 does not exist. -adds a bounds node if 1 does not exist. --- Engine/source/ts/assimp/assimpShapeLoader.cpp | 55 +++++++++++++++++-- 1 file changed, 50 insertions(+), 5 deletions(-) diff --git a/Engine/source/ts/assimp/assimpShapeLoader.cpp b/Engine/source/ts/assimp/assimpShapeLoader.cpp index 2a3735243..fd56bb2a1 100644 --- a/Engine/source/ts/assimp/assimpShapeLoader.cpp +++ b/Engine/source/ts/assimp/assimpShapeLoader.cpp @@ -229,6 +229,18 @@ void AssimpShapeLoader::enumerateScene() if (!processNode(node)) delete node; + // add bounds node. + if (!boundsNode) + { + aiNode* req[1]; + req[0] = new aiNode("bounds"); + mScene->mRootNode->addChildren(1, req); + + AssimpAppNode* appBounds = new AssimpAppNode(mScene, req[0]); + if (!processNode(appBounds)) + delete appBounds; + } + // Check for animations and process those. processAnimations(); } @@ -243,13 +255,42 @@ void AssimpShapeLoader::enumerateScene() void AssimpShapeLoader::processAnimations() { + bool ambient = false; for(U32 n = 0; n < mScene->mNumAnimations; ++n) { Con::printf("[ASSIMP] Animation Found: %s", mScene->mAnimations[n]->mName.C_Str()); + if (mScene->mAnimations[n]->mName.C_Str() == "ambient") + ambient = true; + AssimpAppSequence* newAssimpSeq = new AssimpAppSequence(mScene->mAnimations[n]); appSequences.push_back(newAssimpSeq); } + + // dont have ambient, lets just add everything to an ambient sequence. + // we should probably just do this as default. + if (!ambient) + { + aiAnimation* ambientSeq = new aiAnimation(); + ambientSeq->mName = "ambient"; + + Vector ambientChannels; + + for (U32 i = 0; i < mScene->mNumAnimations; ++i) + { + aiAnimation* anim = mScene->mAnimations[i]; + for (U32 j = 0; j < anim->mNumChannels; j++) + { + ambientChannels.push_back(anim->mChannels[j]); + } + } + + ambientSeq->mChannels = ambientChannels.address(); + + AssimpAppSequence* defaultAssimpSeq = new AssimpAppSequence(ambientSeq); + appSequences.push_back(defaultAssimpSeq); + } + } void AssimpShapeLoader::computeBounds(Box3F& bounds) @@ -369,12 +410,16 @@ bool AssimpShapeLoader::fillGuiTreeView(const char* sourceShapePath, GuiTreeView tree->insertItem(matItem, String::ToString("%s", name.c_str()), String::ToString("%s", texName.c_str())); } - for (U32 i = 0; i < shapeScene->mNumAnimations; i++) + if (shapeScene->mNumAnimations == 0) { - String sequenceName = shapeScene->mAnimations[i]->mName.C_Str(); - if (sequenceName.isEmpty()) - sequenceName = "ambient"; - tree->insertItem(animItem, sequenceName.c_str()); + tree->insertItem(animItem, "ambient", "animation", "", 0, 0); + } + else + { + for (U32 i = 0; i < shapeScene->mNumAnimations; i++) + { + tree->insertItem(animItem, shapeScene->mAnimations[i]->mName.C_Str(), "animation", "", 0, 0); + } } U32 numNodes = 0; From 7115d9bcc6ed92edf7bdbb7667f53fb146a8daed Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Fri, 9 Feb 2024 22:12:52 +0000 Subject: [PATCH 02/29] Update assimpShapeLoader.cpp --- Engine/source/ts/assimp/assimpShapeLoader.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Engine/source/ts/assimp/assimpShapeLoader.cpp b/Engine/source/ts/assimp/assimpShapeLoader.cpp index fd56bb2a1..2e8070091 100644 --- a/Engine/source/ts/assimp/assimpShapeLoader.cpp +++ b/Engine/source/ts/assimp/assimpShapeLoader.cpp @@ -284,7 +284,8 @@ void AssimpShapeLoader::processAnimations() ambientChannels.push_back(anim->mChannels[j]); } } - + + ambientSeq->mNumChannels = ambientChannels.size(); ambientSeq->mChannels = ambientChannels.address(); AssimpAppSequence* defaultAssimpSeq = new AssimpAppSequence(ambientSeq); From 144e1bcc60a33f7bb2be4b30c02b80a00a50673b Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sat, 10 Feb 2024 04:25:48 +0000 Subject: [PATCH 03/29] Update assimpShapeLoader.cpp --- Engine/source/ts/assimp/assimpShapeLoader.cpp | 48 +++++++------------ 1 file changed, 16 insertions(+), 32 deletions(-) diff --git a/Engine/source/ts/assimp/assimpShapeLoader.cpp b/Engine/source/ts/assimp/assimpShapeLoader.cpp index 2e8070091..c7cf7d751 100644 --- a/Engine/source/ts/assimp/assimpShapeLoader.cpp +++ b/Engine/source/ts/assimp/assimpShapeLoader.cpp @@ -255,42 +255,26 @@ void AssimpShapeLoader::enumerateScene() void AssimpShapeLoader::processAnimations() { - bool ambient = false; - for(U32 n = 0; n < mScene->mNumAnimations; ++n) + // add all animations into 1 ambient animation. + aiAnimation* ambientSeq = new aiAnimation(); + ambientSeq->mName = "ambient"; + + Vector ambientChannels; + + for (U32 i = 0; i < mScene->mNumAnimations; ++i) { - Con::printf("[ASSIMP] Animation Found: %s", mScene->mAnimations[n]->mName.C_Str()); - - if (mScene->mAnimations[n]->mName.C_Str() == "ambient") - ambient = true; - - AssimpAppSequence* newAssimpSeq = new AssimpAppSequence(mScene->mAnimations[n]); - appSequences.push_back(newAssimpSeq); - } - - // dont have ambient, lets just add everything to an ambient sequence. - // we should probably just do this as default. - if (!ambient) - { - aiAnimation* ambientSeq = new aiAnimation(); - ambientSeq->mName = "ambient"; - - Vector ambientChannels; - - for (U32 i = 0; i < mScene->mNumAnimations; ++i) + aiAnimation* anim = mScene->mAnimations[i]; + for (U32 j = 0; j < anim->mNumChannels; j++) { - aiAnimation* anim = mScene->mAnimations[i]; - for (U32 j = 0; j < anim->mNumChannels; j++) - { - ambientChannels.push_back(anim->mChannels[j]); - } + ambientChannels.push_back(anim->mChannels[j]); } - - ambientSeq->mNumChannels = ambientChannels.size(); - ambientSeq->mChannels = ambientChannels.address(); - - AssimpAppSequence* defaultAssimpSeq = new AssimpAppSequence(ambientSeq); - appSequences.push_back(defaultAssimpSeq); } + + ambientSeq->mNumChannels = ambientChannels.size(); + ambientSeq->mChannels = ambientChannels.address(); + + AssimpAppSequence* defaultAssimpSeq = new AssimpAppSequence(ambientSeq); + appSequences.push_back(defaultAssimpSeq); } From e2550ed5258a30ae2b85eab0c4c90035369e2cdd Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sat, 10 Feb 2024 04:49:57 +0000 Subject: [PATCH 04/29] Update assimpAppSequence.cpp --- Engine/source/ts/assimp/assimpAppSequence.cpp | 49 ++----------------- 1 file changed, 4 insertions(+), 45 deletions(-) diff --git a/Engine/source/ts/assimp/assimpAppSequence.cpp b/Engine/source/ts/assimp/assimpAppSequence.cpp index e0a78175e..88652fa69 100644 --- a/Engine/source/ts/assimp/assimpAppSequence.cpp +++ b/Engine/source/ts/assimp/assimpAppSequence.cpp @@ -34,52 +34,11 @@ AssimpAppSequence::AssimpAppSequence(aiAnimation *a) : maxKeys = getMax(maxKeys, nodeAnim->mNumRotationKeys); maxKeys = getMax(maxKeys, nodeAnim->mNumScalingKeys); - if (nodeAnim->mNumPositionKeys) - maxEndTime = getMax(maxEndTime, (F32) nodeAnim->mPositionKeys[nodeAnim->mNumPositionKeys-1].mTime); - if (nodeAnim->mNumRotationKeys) - maxEndTime = getMax(maxEndTime, (F32) nodeAnim->mRotationKeys[nodeAnim->mNumRotationKeys-1].mTime); - if (nodeAnim->mNumScalingKeys) - maxEndTime = getMax(maxEndTime, (F32) nodeAnim->mScalingKeys[nodeAnim->mNumScalingKeys-1].mTime); - - for (U32 key = 1; key < nodeAnim->mNumPositionKeys; ++key) - { - F32 deltaT = nodeAnim->mPositionKeys[key].mTime - nodeAnim->mPositionKeys[key-1].mTime; - minFrameTime = getMin(minFrameTime, deltaT); - } - for (U32 key = 1; key < nodeAnim->mNumRotationKeys; ++key) - { - F32 deltaT = nodeAnim->mRotationKeys[key].mTime - nodeAnim->mRotationKeys[key-1].mTime; - minFrameTime = getMin(minFrameTime, deltaT); - } - for (U32 key = 1; key < nodeAnim->mNumScalingKeys; ++key) - { - F32 deltaT = nodeAnim->mScalingKeys[key].mTime - nodeAnim->mScalingKeys[key-1].mTime; - minFrameTime = getMin(minFrameTime, deltaT); - } + maxEndTime = getMax(maxEndTime, (F32)maxKeys); } - S32 timeFactor = ColladaUtils::getOptions().animTiming; - S32 fpsRequest = ColladaUtils::getOptions().animFPS; - if (timeFactor == 0) - { // Timing specified in frames - fps = mClamp(fpsRequest, 5 /*TSShapeLoader::MinFrameRate*/, TSShapeLoader::MaxFrameRate); - maxKeys = getMax(maxKeys, (U32)maxEndTime); // Keys won't be assigned for every frame. - seqEnd = maxKeys / fps; - mTimeMultiplier = 1.0f / fps; - } - else - { // Timing specified in seconds or ms depending on format - if (maxEndTime > 1000.0f || mAnim->mDuration > 1000.0f) - timeFactor = 1000.0f; // If it's more than 1000 seconds, assume it's ms. + seqEnd = maxEndTime; - timeFactor = mClamp(timeFactor, 1, 1000); - minFrameTime /= (F32)timeFactor; - maxEndTime /= (F32)timeFactor; - fps = (minFrameTime > 0.0f) ? 1.0f / minFrameTime : fps; - fps = mClamp(fpsRequest, 5 /*TSShapeLoader::MinFrameRate*/, TSShapeLoader::MaxFrameRate); - seqEnd = maxEndTime; - mTimeMultiplier = 1.0f / timeFactor; - } } AssimpAppSequence::~AssimpAppSequence() @@ -102,7 +61,7 @@ void AssimpAppSequence::setActive(bool active) U32 AssimpAppSequence::getFlags() const { - return TSShape::Blend; + return TSShape::Cyclic; } F32 AssimpAppSequence::getPriority() const { @@ -111,4 +70,4 @@ F32 AssimpAppSequence::getPriority() const F32 AssimpAppSequence::getBlendRefTime() const { return -1.0f; -} \ No newline at end of file +} From 05960e4d255f07dfdb2d4e5a56a3a69abc0f8b2b Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sat, 10 Feb 2024 20:01:52 +0000 Subject: [PATCH 05/29] extra fixes Torque sees the seqEnd in appSequence as a time in seconds whereas in Assimp this is in frames. This is then converted to frames in generateSequences. --- Engine/source/ts/assimp/assimpAppNode.cpp | 169 ++++++++++-------- Engine/source/ts/assimp/assimpAppSequence.cpp | 71 ++++++-- Engine/source/ts/assimp/assimpAppSequence.h | 2 +- Engine/source/ts/assimp/assimpShapeLoader.cpp | 23 ++- 4 files changed, 171 insertions(+), 94 deletions(-) diff --git a/Engine/source/ts/assimp/assimpAppNode.cpp b/Engine/source/ts/assimp/assimpAppNode.cpp index 093101521..2b06b58b8 100644 --- a/Engine/source/ts/assimp/assimpAppNode.cpp +++ b/Engine/source/ts/assimp/assimpAppNode.cpp @@ -122,100 +122,115 @@ MatrixF AssimpAppNode::getTransform(F32 time) void AssimpAppNode::getAnimatedTransform(MatrixF& mat, F32 t, aiAnimation* animSeq) { // Find the channel for this node - for (U32 i = 0; i < animSeq->mNumChannels; ++i) + for (U32 k = 0; k < animSeq->mNumChannels; ++k) { - if (strcmp(mName, animSeq->mChannels[i]->mNodeName.C_Str()) == 0) + if (dStrcmp(mName, animSeq->mChannels[k]->mNodeName.C_Str()) == 0) { - aiNodeAnim *nodeAnim = animSeq->mChannels[i]; + aiNodeAnim *nodeAnim = animSeq->mChannels[k]; Point3F trans(Point3F::Zero); Point3F scale(Point3F::One); QuatF rot; rot.identity(); + // T is in seconds, convert to frames. + F32 frame = t * animSeq->mTicksPerSecond; - // Transform - if (nodeAnim->mNumPositionKeys == 1) - trans.set(nodeAnim->mPositionKeys[0].mValue.x, nodeAnim->mPositionKeys[0].mValue.y, nodeAnim->mPositionKeys[0].mValue.z); + // interpolate scaling. + if (nodeAnim->mNumScalingKeys > 1) { + U32 scaleIndex = 0; + + for (U32 i = 0; i < nodeAnim->mNumScalingKeys-1; i++) + { + if (frame < nodeAnim->mScalingKeys[i + 1].mTime) { + scaleIndex = i; + break; + } + } + + const Point3F& scalingStart = Point3F( nodeAnim->mScalingKeys[scaleIndex].mValue.x, + nodeAnim->mScalingKeys[scaleIndex].mValue.y, + nodeAnim->mScalingKeys[scaleIndex].mValue.z); + + const Point3F& scalingEnd = Point3F(nodeAnim->mScalingKeys[scaleIndex + 1].mValue.x, + nodeAnim->mScalingKeys[scaleIndex + 1].mValue.y, + nodeAnim->mScalingKeys[scaleIndex + 1].mValue.z); + + F32 deltaTime = nodeAnim->mScalingKeys[scaleIndex + 1].mTime - nodeAnim->mScalingKeys[scaleIndex].mTime; + F32 factor = (frame - nodeAnim->mScalingKeys[scaleIndex].mTime) / deltaTime; + + scale = scalingStart + factor * (scalingEnd - scalingStart); + } else { - Point3F curPos, lastPos; - F32 lastT = 0.0; - for (U32 key = 0; key < nodeAnim->mNumPositionKeys; ++key) - { - F32 curT = sTimeMultiplier * (F32)nodeAnim->mPositionKeys[key].mTime; - curPos.set(nodeAnim->mPositionKeys[key].mValue.x, nodeAnim->mPositionKeys[key].mValue.y, nodeAnim->mPositionKeys[key].mValue.z); - if ((curT > t) && (key > 0)) - { - F32 factor = (t - lastT) / (curT - lastT); - trans.interpolate(lastPos, curPos, factor); - break; - } - else if ((curT >= t) || (key == nodeAnim->mNumPositionKeys - 1)) - { - trans = curPos; - break; - } - - lastT = curT; - lastPos = curPos; - } + scale.set( nodeAnim->mScalingKeys[0].mValue.x, + nodeAnim->mScalingKeys[0].mValue.y, + nodeAnim->mScalingKeys[0].mValue.z); } - // Rotation - if (nodeAnim->mNumRotationKeys == 1) - rot.set(nodeAnim->mRotationKeys[0].mValue.x, nodeAnim->mRotationKeys[0].mValue.y, - nodeAnim->mRotationKeys[0].mValue.z, nodeAnim->mRotationKeys[0].mValue.w); + // interpolate rotation. + if (nodeAnim->mNumRotationKeys > 1) { + U32 rotationIndex = 0; + + for (U32 i = 0; i < nodeAnim->mNumRotationKeys - 1; i++) + { + if (frame < nodeAnim->mRotationKeys[i + 1].mTime) { + rotationIndex = i; + break; + } + } + + const QuatF& rotStart = QuatF(nodeAnim->mRotationKeys[rotationIndex].mValue.x, + nodeAnim->mRotationKeys[rotationIndex].mValue.y, + nodeAnim->mRotationKeys[rotationIndex].mValue.z, + nodeAnim->mRotationKeys[rotationIndex].mValue.w); + + const QuatF& rotEnd = QuatF(nodeAnim->mRotationKeys[rotationIndex + 1].mValue.x, + nodeAnim->mRotationKeys[rotationIndex + 1].mValue.y, + nodeAnim->mRotationKeys[rotationIndex + 1].mValue.z, + nodeAnim->mRotationKeys[rotationIndex + 1].mValue.w); + + F32 deltaTime = nodeAnim->mRotationKeys[rotationIndex + 1].mTime - nodeAnim->mRotationKeys[rotationIndex].mTime; + F32 factor = (frame - nodeAnim->mRotationKeys[rotationIndex].mTime) / deltaTime; + + rot.interpolate(rotStart, rotEnd, factor); + } else { - QuatF curRot, lastRot; - F32 lastT = 0.0; - for (U32 key = 0; key < nodeAnim->mNumRotationKeys; ++key) - { - F32 curT = sTimeMultiplier * (F32)nodeAnim->mRotationKeys[key].mTime; - curRot.set(nodeAnim->mRotationKeys[key].mValue.x, nodeAnim->mRotationKeys[key].mValue.y, - nodeAnim->mRotationKeys[key].mValue.z, nodeAnim->mRotationKeys[key].mValue.w); - if ((curT > t) && (key > 0)) - { - F32 factor = (t - lastT) / (curT - lastT); - rot.interpolate(lastRot, curRot, factor); - break; - } - else if ((curT >= t) || (key == nodeAnim->mNumRotationKeys - 1)) - { - rot = curRot; - break; - } - - lastT = curT; - lastRot = curRot; - } + rot.set( nodeAnim->mRotationKeys[0].mValue.x, + nodeAnim->mRotationKeys[0].mValue.y, + nodeAnim->mRotationKeys[0].mValue.z, + nodeAnim->mRotationKeys[0].mValue.w); } - // Scale - if (nodeAnim->mNumScalingKeys == 1) - scale.set(nodeAnim->mScalingKeys[0].mValue.x, nodeAnim->mScalingKeys[0].mValue.y, nodeAnim->mScalingKeys[0].mValue.z); + // interpolate position. + if (nodeAnim->mNumPositionKeys > 1) { + U32 posIndex = 0; + + for (U32 i = 0; i < nodeAnim->mNumPositionKeys - 1; i++) + { + if (frame < nodeAnim->mPositionKeys[i + 1].mTime) { + posIndex = i; + break; + } + } + + const Point3F& posStart = Point3F( nodeAnim->mPositionKeys[posIndex].mValue.x, + nodeAnim->mPositionKeys[posIndex].mValue.y, + nodeAnim->mPositionKeys[posIndex].mValue.z); + + const Point3F& posEnd = Point3F(nodeAnim->mPositionKeys[posIndex + 1].mValue.x, + nodeAnim->mPositionKeys[posIndex + 1].mValue.y, + nodeAnim->mPositionKeys[posIndex + 1].mValue.z); + + F32 deltaTime = nodeAnim->mPositionKeys[posIndex + 1].mTime - nodeAnim->mPositionKeys[posIndex].mTime; + F32 factor = (frame - nodeAnim->mPositionKeys[posIndex].mTime) / deltaTime; + + trans = posStart + factor * (posEnd - posStart); + } else { - Point3F curScale, lastScale; - F32 lastT = 0.0; - for (U32 key = 0; key < nodeAnim->mNumScalingKeys; ++key) - { - F32 curT = sTimeMultiplier * (F32)nodeAnim->mScalingKeys[key].mTime; - curScale.set(nodeAnim->mScalingKeys[key].mValue.x, nodeAnim->mScalingKeys[key].mValue.y, nodeAnim->mScalingKeys[key].mValue.z); - if ((curT > t) && (key > 0)) - { - F32 factor = (t - lastT) / (curT - lastT); - scale.interpolate(lastScale, curScale, factor); - break; - } - else if ((curT >= t) || (key == nodeAnim->mNumScalingKeys - 1)) - { - scale = curScale; - break; - } - - lastT = curT; - lastScale = curScale; - } + trans.set( nodeAnim->mPositionKeys[0].mValue.x, + nodeAnim->mPositionKeys[0].mValue.y, + nodeAnim->mPositionKeys[0].mValue.z); } rot.setMatrix(&mat); diff --git a/Engine/source/ts/assimp/assimpAppSequence.cpp b/Engine/source/ts/assimp/assimpAppSequence.cpp index 88652fa69..69587fe85 100644 --- a/Engine/source/ts/assimp/assimpAppSequence.cpp +++ b/Engine/source/ts/assimp/assimpAppSequence.cpp @@ -14,30 +14,75 @@ AssimpAppSequence::AssimpAppSequence(aiAnimation *a) : seqStart(0.0f), - mAnim(a) + seqEnd(0.0f) { + mAnim = new aiAnimation(*a); + + // Deep copy channels + mAnim->mChannels = new aiNodeAnim * [a->mNumChannels]; + for (U32 i = 0; i < a->mNumChannels; ++i) { + mAnim->mChannels[i] = new aiNodeAnim(*a->mChannels[i]); + } + + // Deep copy meshes + mAnim->mMeshChannels = new aiMeshAnim * [a->mNumMeshChannels]; + for (U32 i = 0; i < a->mNumMeshChannels; ++i) { + mAnim->mMeshChannels[i] = new aiMeshAnim(*a->mMeshChannels[i]); + } + + // Deep copy name + mAnim->mName = a->mName; + mSequenceName = mAnim->mName.C_Str(); if (mSequenceName.isEmpty()) mSequenceName = "ambient"; Con::printf("\n[Assimp] Adding %s animation", mSequenceName.c_str()); - fps = (mAnim->mTicksPerSecond > 0) ? mAnim->mTicksPerSecond : 30.0f; + fps = (a->mTicksPerSecond > 0) ? a->mTicksPerSecond : 30.0f; - U32 maxKeys = 0; - F32 maxEndTime = 0; - F32 minFrameTime = 100000.0f; - // Detect the frame rate (minimum time between keyframes) and max sequence time - for (U32 i = 0; i < mAnim->mNumChannels; ++i) + if (a->mDuration > 0) { - aiNodeAnim *nodeAnim = mAnim->mChannels[i]; - maxKeys = getMax(maxKeys, nodeAnim->mNumPositionKeys); - maxKeys = getMax(maxKeys, nodeAnim->mNumRotationKeys); - maxKeys = getMax(maxKeys, nodeAnim->mNumScalingKeys); + // torques seqEnd is in seconds, this then gets generated into frames in generateSequences() + seqEnd = (F32)a->mDuration / fps; + } + else + { + for (U32 i = 0; i < a->mNumChannels; ++i) + { + aiNodeAnim* nodeAnim = a->mChannels[i]; + // Determine the maximum keyframe time for this animation + F32 maxKeyTime = 0.0f; + for (U32 k = 0; k < nodeAnim->mNumPositionKeys; k++) { + maxKeyTime = getMax(maxKeyTime, (F32)nodeAnim->mPositionKeys[k].mTime); + } + for (U32 k = 0; k < nodeAnim->mNumRotationKeys; k++) { + maxKeyTime = getMax(maxKeyTime, (F32)nodeAnim->mRotationKeys[k].mTime); + } + for (U32 k = 0; k < nodeAnim->mNumScalingKeys; k++) { + maxKeyTime = getMax(maxKeyTime, (F32)nodeAnim->mScalingKeys[k].mTime); + } - maxEndTime = getMax(maxEndTime, (F32)maxKeys); + seqEnd = getMax(seqEnd, maxKeyTime); + } } - seqEnd = maxEndTime; + mTimeMultiplier = 1.0f; + + //S32 timeFactor = ColladaUtils::getOptions().animTiming; + //S32 fpsRequest = (S32)a->mTicksPerSecond; + //if (timeFactor == 0) + //{ // Timing specified in frames + // fps = mClamp(fpsRequest, 5 /*TSShapeLoader::MinFrameRate*/, TSShapeLoader::MaxFrameRate); + // mTimeMultiplier = 1.0f / fps; + //} + //else + //{ // Timing specified in seconds or ms depending on format + // if (seqEnd > 1000.0f || a->mDuration > 1000.0f) + // timeFactor = 1000.0f; // If it's more than 1000 seconds, assume it's ms. + + // timeFactor = mClamp(timeFactor, 1, 1000); + // mTimeMultiplier = 1.0f / timeFactor; + //} } diff --git a/Engine/source/ts/assimp/assimpAppSequence.h b/Engine/source/ts/assimp/assimpAppSequence.h index be5c11025..467aeb4a2 100644 --- a/Engine/source/ts/assimp/assimpAppSequence.h +++ b/Engine/source/ts/assimp/assimpAppSequence.h @@ -48,4 +48,4 @@ public: virtual U32 getFlags() const; virtual F32 getPriority() const; virtual F32 getBlendRefTime() const; -}; \ No newline at end of file +}; diff --git a/Engine/source/ts/assimp/assimpShapeLoader.cpp b/Engine/source/ts/assimp/assimpShapeLoader.cpp index c7cf7d751..908e186f2 100644 --- a/Engine/source/ts/assimp/assimpShapeLoader.cpp +++ b/Engine/source/ts/assimp/assimpShapeLoader.cpp @@ -260,22 +260,39 @@ void AssimpShapeLoader::processAnimations() ambientSeq->mName = "ambient"; Vector ambientChannels; + F32 duration = 0.0f; for (U32 i = 0; i < mScene->mNumAnimations; ++i) { aiAnimation* anim = mScene->mAnimations[i]; for (U32 j = 0; j < anim->mNumChannels; j++) { - ambientChannels.push_back(anim->mChannels[j]); + aiNodeAnim* nodeAnim = anim->mChannels[j]; + // Determine the maximum keyframe time for this animation + F32 maxKeyTime = 0.0f; + for (U32 k = 0; k < nodeAnim->mNumPositionKeys; k++) { + maxKeyTime = getMax(maxKeyTime, (F32)nodeAnim->mPositionKeys[k].mTime); + } + for (U32 k = 0; k < nodeAnim->mNumRotationKeys; k++) { + maxKeyTime = getMax(maxKeyTime, (F32)nodeAnim->mRotationKeys[k].mTime); + } + for (U32 k = 0; k < nodeAnim->mNumScalingKeys; k++) { + maxKeyTime = getMax(maxKeyTime, (F32)nodeAnim->mScalingKeys[k].mTime); + } + + ambientChannels.push_back(nodeAnim); + + duration = getMax(duration, maxKeyTime); } } - + ambientSeq->mNumChannels = ambientChannels.size(); ambientSeq->mChannels = ambientChannels.address(); + ambientSeq->mDuration = duration; + ambientSeq->mTicksPerSecond = 24.0; AssimpAppSequence* defaultAssimpSeq = new AssimpAppSequence(ambientSeq); appSequences.push_back(defaultAssimpSeq); - } void AssimpShapeLoader::computeBounds(Box3F& bounds) From 58bcea770c735b1956631596a5b28d0e90a7e960 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Sat, 10 Feb 2024 21:57:08 +0000 Subject: [PATCH 06/29] Node interp Fix node interpolation to remove the jittered (reverted back to previous get node transform) --- Engine/source/ts/assimp/assimpAppNode.cpp | 161 ++++++++---------- Engine/source/ts/assimp/assimpAppSequence.cpp | 31 ++-- 2 files changed, 89 insertions(+), 103 deletions(-) diff --git a/Engine/source/ts/assimp/assimpAppNode.cpp b/Engine/source/ts/assimp/assimpAppNode.cpp index 2b06b58b8..024186255 100644 --- a/Engine/source/ts/assimp/assimpAppNode.cpp +++ b/Engine/source/ts/assimp/assimpAppNode.cpp @@ -132,105 +132,92 @@ void AssimpAppNode::getAnimatedTransform(MatrixF& mat, F32 t, aiAnimation* animS QuatF rot; rot.identity(); // T is in seconds, convert to frames. - F32 frame = t * animSeq->mTicksPerSecond; + F32 frame = (t * animSeq->mTicksPerSecond + 0.5f) + 1.0f; - // interpolate scaling. - if (nodeAnim->mNumScalingKeys > 1) { - U32 scaleIndex = 0; - - for (U32 i = 0; i < nodeAnim->mNumScalingKeys-1; i++) - { - if (frame < nodeAnim->mScalingKeys[i + 1].mTime) { - scaleIndex = i; - break; - } - } - - const Point3F& scalingStart = Point3F( nodeAnim->mScalingKeys[scaleIndex].mValue.x, - nodeAnim->mScalingKeys[scaleIndex].mValue.y, - nodeAnim->mScalingKeys[scaleIndex].mValue.z); - - const Point3F& scalingEnd = Point3F(nodeAnim->mScalingKeys[scaleIndex + 1].mValue.x, - nodeAnim->mScalingKeys[scaleIndex + 1].mValue.y, - nodeAnim->mScalingKeys[scaleIndex + 1].mValue.z); - - F32 deltaTime = nodeAnim->mScalingKeys[scaleIndex + 1].mTime - nodeAnim->mScalingKeys[scaleIndex].mTime; - F32 factor = (frame - nodeAnim->mScalingKeys[scaleIndex].mTime) / deltaTime; - - scale = scalingStart + factor * (scalingEnd - scalingStart); - } + // Transform + if (nodeAnim->mNumPositionKeys == 1) + trans.set(nodeAnim->mPositionKeys[0].mValue.x, nodeAnim->mPositionKeys[0].mValue.y, nodeAnim->mPositionKeys[0].mValue.z); else { - scale.set( nodeAnim->mScalingKeys[0].mValue.x, - nodeAnim->mScalingKeys[0].mValue.y, - nodeAnim->mScalingKeys[0].mValue.z); - } - - // interpolate rotation. - if (nodeAnim->mNumRotationKeys > 1) { - U32 rotationIndex = 0; - - for (U32 i = 0; i < nodeAnim->mNumRotationKeys - 1; i++) + Point3F curPos, lastPos; + F32 lastT = 0.0; + for (U32 key = 0; key < nodeAnim->mNumPositionKeys; ++key) { - if (frame < nodeAnim->mRotationKeys[i + 1].mTime) { - rotationIndex = i; + F32 curT = sTimeMultiplier * (F32)nodeAnim->mPositionKeys[key].mTime; + curPos.set(nodeAnim->mPositionKeys[key].mValue.x, nodeAnim->mPositionKeys[key].mValue.y, nodeAnim->mPositionKeys[key].mValue.z); + if ((curT > frame) && (key > 0)) + { + F32 factor = (frame - lastT) / (curT - lastT); + trans.interpolate(lastPos, curPos, factor); break; } - } - - const QuatF& rotStart = QuatF(nodeAnim->mRotationKeys[rotationIndex].mValue.x, - nodeAnim->mRotationKeys[rotationIndex].mValue.y, - nodeAnim->mRotationKeys[rotationIndex].mValue.z, - nodeAnim->mRotationKeys[rotationIndex].mValue.w); - - const QuatF& rotEnd = QuatF(nodeAnim->mRotationKeys[rotationIndex + 1].mValue.x, - nodeAnim->mRotationKeys[rotationIndex + 1].mValue.y, - nodeAnim->mRotationKeys[rotationIndex + 1].mValue.z, - nodeAnim->mRotationKeys[rotationIndex + 1].mValue.w); - - F32 deltaTime = nodeAnim->mRotationKeys[rotationIndex + 1].mTime - nodeAnim->mRotationKeys[rotationIndex].mTime; - F32 factor = (frame - nodeAnim->mRotationKeys[rotationIndex].mTime) / deltaTime; - - rot.interpolate(rotStart, rotEnd, factor); - } - else - { - rot.set( nodeAnim->mRotationKeys[0].mValue.x, - nodeAnim->mRotationKeys[0].mValue.y, - nodeAnim->mRotationKeys[0].mValue.z, - nodeAnim->mRotationKeys[0].mValue.w); - } - - // interpolate position. - if (nodeAnim->mNumPositionKeys > 1) { - U32 posIndex = 0; - - for (U32 i = 0; i < nodeAnim->mNumPositionKeys - 1; i++) - { - if (frame < nodeAnim->mPositionKeys[i + 1].mTime) { - posIndex = i; + else if ((curT >= frame) || (key == nodeAnim->mNumPositionKeys - 1)) + { + trans = curPos; break; } + + lastT = curT; + lastPos = curPos; } - - const Point3F& posStart = Point3F( nodeAnim->mPositionKeys[posIndex].mValue.x, - nodeAnim->mPositionKeys[posIndex].mValue.y, - nodeAnim->mPositionKeys[posIndex].mValue.z); - - const Point3F& posEnd = Point3F(nodeAnim->mPositionKeys[posIndex + 1].mValue.x, - nodeAnim->mPositionKeys[posIndex + 1].mValue.y, - nodeAnim->mPositionKeys[posIndex + 1].mValue.z); - - F32 deltaTime = nodeAnim->mPositionKeys[posIndex + 1].mTime - nodeAnim->mPositionKeys[posIndex].mTime; - F32 factor = (frame - nodeAnim->mPositionKeys[posIndex].mTime) / deltaTime; - - trans = posStart + factor * (posEnd - posStart); } + + // Rotation + if (nodeAnim->mNumRotationKeys == 1) + rot.set(nodeAnim->mRotationKeys[0].mValue.x, nodeAnim->mRotationKeys[0].mValue.y, + nodeAnim->mRotationKeys[0].mValue.z, nodeAnim->mRotationKeys[0].mValue.w); else { - trans.set( nodeAnim->mPositionKeys[0].mValue.x, - nodeAnim->mPositionKeys[0].mValue.y, - nodeAnim->mPositionKeys[0].mValue.z); + QuatF curRot, lastRot; + F32 lastT = 0.0; + for (U32 key = 0; key < nodeAnim->mNumRotationKeys; ++key) + { + F32 curT = sTimeMultiplier * (F32)nodeAnim->mRotationKeys[key].mTime; + curRot.set(nodeAnim->mRotationKeys[key].mValue.x, nodeAnim->mRotationKeys[key].mValue.y, + nodeAnim->mRotationKeys[key].mValue.z, nodeAnim->mRotationKeys[key].mValue.w); + if ((curT > frame) && (key > 0)) + { + F32 factor = (frame - lastT) / (curT - lastT); + rot.interpolate(lastRot, curRot, factor); + break; + } + else if ((curT >= frame) || (key == nodeAnim->mNumRotationKeys - 1)) + { + rot = curRot; + break; + } + + lastT = curT; + lastRot = curRot; + } + } + + // Scale + if (nodeAnim->mNumScalingKeys == 1) + scale.set(nodeAnim->mScalingKeys[0].mValue.x, nodeAnim->mScalingKeys[0].mValue.y, nodeAnim->mScalingKeys[0].mValue.z); + else + { + Point3F curScale, lastScale; + F32 lastT = 0.0; + for (U32 key = 0; key < nodeAnim->mNumScalingKeys; ++key) + { + F32 curT = sTimeMultiplier * (F32)nodeAnim->mScalingKeys[key].mTime; + curScale.set(nodeAnim->mScalingKeys[key].mValue.x, nodeAnim->mScalingKeys[key].mValue.y, nodeAnim->mScalingKeys[key].mValue.z); + if ((curT > frame) && (key > 0)) + { + F32 factor = (frame - lastT) / (curT - lastT); + scale.interpolate(lastScale, curScale, factor); + break; + } + else if ((curT >= frame) || (key == nodeAnim->mNumScalingKeys - 1)) + { + scale = curScale; + break; + } + + lastT = curT; + lastScale = curScale; + } } rot.setMatrix(&mat); diff --git a/Engine/source/ts/assimp/assimpAppSequence.cpp b/Engine/source/ts/assimp/assimpAppSequence.cpp index 69587fe85..496d1fb09 100644 --- a/Engine/source/ts/assimp/assimpAppSequence.cpp +++ b/Engine/source/ts/assimp/assimpAppSequence.cpp @@ -17,7 +17,6 @@ AssimpAppSequence::AssimpAppSequence(aiAnimation *a) : seqEnd(0.0f) { mAnim = new aiAnimation(*a); - // Deep copy channels mAnim->mChannels = new aiNodeAnim * [a->mNumChannels]; for (U32 i = 0; i < a->mNumChannels; ++i) { @@ -68,21 +67,21 @@ AssimpAppSequence::AssimpAppSequence(aiAnimation *a) : mTimeMultiplier = 1.0f; - //S32 timeFactor = ColladaUtils::getOptions().animTiming; - //S32 fpsRequest = (S32)a->mTicksPerSecond; - //if (timeFactor == 0) - //{ // Timing specified in frames - // fps = mClamp(fpsRequest, 5 /*TSShapeLoader::MinFrameRate*/, TSShapeLoader::MaxFrameRate); - // mTimeMultiplier = 1.0f / fps; - //} - //else - //{ // Timing specified in seconds or ms depending on format - // if (seqEnd > 1000.0f || a->mDuration > 1000.0f) - // timeFactor = 1000.0f; // If it's more than 1000 seconds, assume it's ms. + S32 timeFactor = ColladaUtils::getOptions().animTiming; + S32 fpsRequest = (S32)a->mTicksPerSecond; + if (timeFactor == 0) + { // Timing specified in frames + fps = mClamp(fpsRequest, 5 /*TSShapeLoader::MinFrameRate*/, TSShapeLoader::MaxFrameRate); + mTimeMultiplier = 1.0f / fps; + } + else + { // Timing specified in seconds or ms depending on format + if (seqEnd > 1000.0f || a->mDuration > 1000.0f) + timeFactor = 1000.0f; // If it's more than 1000 seconds, assume it's ms. - // timeFactor = mClamp(timeFactor, 1, 1000); - // mTimeMultiplier = 1.0f / timeFactor; - //} + timeFactor = mClamp(timeFactor, 1, 1000); + mTimeMultiplier = 1.0f / timeFactor; + } } @@ -114,5 +113,5 @@ F32 AssimpAppSequence::getPriority() const } F32 AssimpAppSequence::getBlendRefTime() const { - return -1.0f; + return 0.0f; } From 60758dd5a2e194b013647f86fa82792ebcb16c6e Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Tue, 20 Feb 2024 14:11:58 -0600 Subject: [PATCH 07/29] temp workaround for material editor crash selection swapping is causing an apcrash notDirtyMaterial.delete(); *should* work, but we know what they say about assumptions. supressing deletion of workspace material kill off and recreation pending proper review --- .../tools/materialEditor/scripts/materialEditor.ed.tscript | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.tscript b/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.tscript index 5f6c92776..ccd93fee2 100644 --- a/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.tscript +++ b/Templates/BaseGame/game/tools/materialEditor/scripts/materialEditor.ed.tscript @@ -745,8 +745,9 @@ function MaterialEditorGui::setActiveMaterial( %this, %material ) MaterialEditorGui.lastMaterial = %material; // we create or recreate a material to hold in a pristine state - if(isObject(notDirtyMaterial)) - notDirtyMaterial.delete(); + // or, this crashes the ap. fix properly - BJR +// if(isObject(notDirtyMaterial)) +// notDirtyMaterial.delete(); singleton Material(notDirtyMaterial) { From a12d91518088c8013367e2564994d4a6100e7225 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 21 Feb 2024 06:22:37 +0000 Subject: [PATCH 08/29] Loads an IES Photometric profile. ADDED: Ability to add IES profile as the cookie texture slot in both point lights and spot lights TODO: Have the IES Profile also drive the settings for the lights. Make it work with Cookie textures. IES profiles are to be another slot in the advanced light section. --- Engine/source/CMakeLists.txt | 2 +- .../source/gfx/bitmap/loaders/bitmapSTB.cpp | 108 +++- .../gfx/bitmap/loaders/ies/ies_loader.cpp | 579 ++++++++++++++++++ .../gfx/bitmap/loaders/ies/ies_loader.h | 116 ++++ .../advanced/advancedLightBinManager.cpp | 1 + .../lighting/advanced/pointLightP.hlsl | 44 +- .../shaders/lighting/advanced/spotLightP.hlsl | 19 +- 7 files changed, 832 insertions(+), 37 deletions(-) create mode 100644 Engine/source/gfx/bitmap/loaders/ies/ies_loader.cpp create mode 100644 Engine/source/gfx/bitmap/loaders/ies/ies_loader.h diff --git a/Engine/source/CMakeLists.txt b/Engine/source/CMakeLists.txt index dea14fe4b..78343a2e6 100644 --- a/Engine/source/CMakeLists.txt +++ b/Engine/source/CMakeLists.txt @@ -79,7 +79,7 @@ if(TORQUE_SFX_OPENAL AND NOT TORQUE_DEDICATED) endif() endif() # Handle GFX -torqueAddSourceDirectories("gfx" "gfx/Null" "gfx/test" "gfx/bitmap" "gfx/bitmap/loaders" +torqueAddSourceDirectories("gfx" "gfx/Null" "gfx/test" "gfx/bitmap" "gfx/bitmap/loaders" "gfx/bitmap/loaders/ies" "gfx/util" "gfx/video" "gfx/sim" ) # add the stb headers diff --git a/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp b/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp index fa65219c5..a5a97917a 100644 --- a/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp +++ b/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp @@ -28,6 +28,7 @@ #include "core/strings/stringFunctions.h" #include "gfx/bitmap/gBitmap.h" #include "gfx/bitmap/imageUtils.h" +#include "gfx/bitmap/loaders/ies/ies_loader.h" #ifdef __clang__ #define STBIWDEF static inline @@ -69,6 +70,7 @@ static struct _privateRegisterSTB reg.extensions.push_back("psd"); reg.extensions.push_back("hdr"); reg.extensions.push_back("tga"); + reg.extensions.push_back("ies"); reg.readFunc = sReadSTB; reg.readStreamFunc = sReadStreamSTB; @@ -93,6 +95,103 @@ bool sReadSTB(const Torque::Path& path, GBitmap* bitmap) U32 prevWaterMark = FrameAllocator::getWaterMark(); + // if this is an ies profile we need to create a texture for it. + if (ext.equal("ies")) + { + String textureName = path.getFullPath(); + textureName.replace(".ies", ".png"); + x = 256; + y = 1; + n = 4; + channels = 4; + GFXFormat format = GFXFormatR8G8B8A8; + + if (Torque::FS::IsFile(textureName.c_str())) + { + // if the txture already exist, load it. + unsigned char* data = stbi_load(textureName.c_str(), &x, &y, &n, channels); + + // actually allocate the bitmap space... + bitmap->allocateBitmap(x, y, + false, // don't extrude miplevels... + format); // use determined format... + + U8* pBase = (U8*)bitmap->getBits(); + + U32 rowBytes = bitmap->getByteSize(); + + dMemcpy(pBase, data, rowBytes); + + stbi_image_free(data); + + FrameAllocator::setWaterMark(prevWaterMark); + + return true; + } + else + { + FileStream* readIes = new FileStream; + + if (!readIes->open(path.getFullPath(), Torque::FS::File::Read)) + { + Con::printf("Failed to open IES profile:%s", path.getFullFileName().c_str()); + return false; + } + + if (readIes->getStatus() != Stream::Ok) + { + Con::printf("Failed to open IES profile:%s", path.getFullFileName().c_str()); + return false; + } + + U32 buffSize = readIes->getStreamSize(); + char* buffer = new char[buffSize]; + readIes->read(buffSize, buffer); + + + IESFileInfo info; + IESLoadHelper IESLoader; + + if (!IESLoader.load(buffer, buffSize, info)) + { + Con::printf("Failed to load IES profile:%s \n LoaderError: %s", path.getFullFileName().c_str(), info.error().c_str()); + return false; + } + + float* data = new float[x*y*channels]; + + if (!IESLoader.saveAs1D(info, data, x, channels)) + { + Con::printf("Failed to create 2d Texture for IES profile:%s", path.getFullFileName().c_str()); + return false; + } + + // use stb function to convert float data to uchar + unsigned char* dataChar = stbi__hdr_to_ldr(data, x, y, channels); + + bitmap->deleteImage(); + // actually allocate the bitmap space... + bitmap->allocateBitmap(x, y, + false, + format); + + U8* pBase = (U8*)bitmap->getBits(); + + U32 rowBytes = x * y * channels; + + dMemcpy(pBase, dataChar, rowBytes); + + stbi_image_free(dataChar); + + FrameAllocator::setWaterMark(prevWaterMark); + + sWriteSTB(textureName, bitmap, 10); + + return true; + } + + } + if (!stbi_info(path.getFullPath().c_str(), &x, &y, &channels)) { FrameAllocator::setWaterMark(prevWaterMark); @@ -142,21 +241,22 @@ bool sReadSTB(const Torque::Path& path, GBitmap* bitmap) if (ext.equal("hdr")) { // force load to 4 channel. - float* data = stbi_loadf(path.getFullPath().c_str(), &x, &y, &n, 4); + float* data = stbi_loadf(path.getFullPath().c_str(), &x, &y, &n, 0); - unsigned char* dataChar = stbi__hdr_to_ldr(data, x, y, 4); + unsigned char* dataChar = stbi__hdr_to_ldr(data, x, y, n); bitmap->deleteImage(); // actually allocate the bitmap space... bitmap->allocateBitmap(x, y, false, - GFXFormatR8G8B8A8); + GFXFormatR8G8B8); U8* pBase = (U8*)bitmap->getBits(); - U32 rowBytes = x * y * 4; + U32 rowBytes = x * y * n; dMemcpy(pBase, dataChar, rowBytes); + //stbi_image_free(data); stbi_image_free(dataChar); FrameAllocator::setWaterMark(prevWaterMark); diff --git a/Engine/source/gfx/bitmap/loaders/ies/ies_loader.cpp b/Engine/source/gfx/bitmap/loaders/ies/ies_loader.cpp new file mode 100644 index 000000000..48602fc9f --- /dev/null +++ b/Engine/source/gfx/bitmap/loaders/ies/ies_loader.cpp @@ -0,0 +1,579 @@ +// +---------------------------------------------------------------------- +// | Project : ray. +// | All rights reserved. +// +---------------------------------------------------------------------- +// | Copyright (c) 2013-2017. +// +---------------------------------------------------------------------- +// | * Redistribution and use of this software in source and binary forms, +// | with or without modification, are permitted provided that the following +// | conditions are met: +// | +// | * Redistributions of source code must retain the above +// | copyright notice, this list of conditions and the +// | following disclaimer. +// | +// | * Redistributions in binary form must reproduce the above +// | copyright notice, this list of conditions and the +// | following disclaimer in the documentation and/or other +// | materials provided with the distribution. +// | +// | * Neither the name of the ray team, nor the names of its +// | contributors may be used to endorse or promote products +// | derived from this software without specific prior +// | written permission of the ray team. +// | +// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +---------------------------------------------------------------------- +#include "ies_loader.h" +#include +#include +#include + +IESFileInfo::IESFileInfo() + : _cachedIntegral(std::numeric_limits::max()) + , _error("No data loaded") +{ +} + +bool +IESFileInfo::valid() const +{ + return _error.empty(); +} + +const std::string& +IESFileInfo::error() const +{ + return _error; +} + +IESLoadHelper::IESLoadHelper() +{ +} + +IESLoadHelper::~IESLoadHelper() +{ +} + +bool +IESLoadHelper::load(const char* data, std::size_t dataLength, IESFileInfo& info) +{ + assert(!info.valid()); + return this->load(std::string(data, dataLength), info); +} + +bool +IESLoadHelper::load(const std::string& data, IESFileInfo& info) +{ + assert(!info.valid()); + + std::string dataPos; + + std::string version; + this->getLineContent(data, dataPos, version, false, false); + + if (version.empty()) + { + info._error = "Unknown IES version"; + return false; + } + else if (version == "IESNA:LM-63-1995") + info._version = "IESNA:LM-63-1995"; + else if (version == "IESNA91") + info._version = "IESNA91"; + else if (version == "IESNA:LM-63-2002") + info._version = "IESNA:LM-63-2002"; + else + info._version = version; + + while (!dataPos.empty()) + { + std::string line; + this->getLineContent(dataPos, dataPos, line, false, false); + + if (line.compare(0, 9, "TILT=NONE", 9) == 0 || + line.compare(0, 10, "TILT= NONE", 10) == 0 || + line.compare(0, 10, "TILT =NONE", 10) == 0 || + line.compare(0, 11, "TILT = NONE", 11) == 0) + { + break; + } + else if (line.compare(0, 5, "TILT=", 5) == 0 || + line.compare(0, 5, "TILT =", 5) == 0) + { + info._error = "Not supported yet."; + return false; + } + } + + this->getFloat(dataPos, dataPos, info.totalLights); + if (info.totalLights < 0 || info.totalLights > std::numeric_limits::max()) + { + info._error = "Light Count is not valid"; + return false; + } + + this->getFloat(dataPos, dataPos, info.totalLumens); + if (info.totalLumens < 0) + { + info._error = "TotalLumens is not positive number"; + return false; + } + + this->getFloat(dataPos, dataPos, info.candalaMult); + if (info.candalaMult < 0) + { + info._error = "CandalaMult is not positive number"; + return false; + } + + this->getInt(dataPos, dataPos, info.anglesNumV); + if (info.anglesNumV < 0 || info.anglesNumV > std::numeric_limits::max()) + { + info._error = "VAnglesNum is not valid"; + return false; + } + + this->getInt(dataPos, dataPos, info.anglesNumH); + if (info.anglesNumH < 0 || info.anglesNumH > std::numeric_limits::max()) + { + info._error = "HAnglesNum is not valid"; + return false; + } + + this->getInt(dataPos, dataPos, info.typeOfPhotometric); + this->getInt(dataPos, dataPos, info.typeOfUnit); + + this->getFloat(dataPos, dataPos, info.width); + this->getFloat(dataPos, dataPos, info.length); + this->getFloat(dataPos, dataPos, info.height); + + this->getFloat(dataPos, dataPos, info.ballastFactor); + this->getFloat(dataPos, dataPos, info.futureUse); + this->getFloat(dataPos, dataPos, info.inputWatts); + + float minSoFarV = std::numeric_limits::lowest(); + float minSoFarH = std::numeric_limits::lowest(); + + info._anglesV.reserve(info.anglesNumV); + info._anglesH.reserve(info.anglesNumH); + + for (std::int32_t y = 0; y < info.anglesNumV; ++y) + { + float value; + this->getFloat(dataPos, dataPos, value, true, true); + + if (value < minSoFarV) + { + info._error = "V Values is not valid"; + return false; + } + + minSoFarV = value; + info._anglesV.push_back(value); + } + + for (std::int32_t x = 0; x < info.anglesNumH; ++x) + { + float value; + this->getFloat(dataPos, dataPos, value, true, true); + + if (value < minSoFarH) + { + info._error = "H Values is not valid"; + return false; + } + + minSoFarH = value; + info._anglesH.push_back(value); + } + + info._candalaValues.reserve(info.anglesNumH * info.anglesNumV); + + for (std::int32_t y = 0; y < info.anglesNumH; ++y) + { + for (std::int32_t x = 0; x < info.anglesNumV; ++x) + { + float value; + this->getFloat(dataPos, dataPos, value, true, true); + info._candalaValues.push_back(value * info.candalaMult); + } + } + + skipSpaceAndLineEnd(dataPos, dataPos); + + if (!dataPos.empty()) + { + std::string line; + this->getLineContent(dataPos, dataPos, line, true, false); + + if (line == "END") + skipSpaceAndLineEnd(dataPos, dataPos); + + if (!dataPos.empty()) + { + info._error = "Unexpected content after END."; + return false; + } + } + + info._error.clear(); + + return true; +} + +bool +IESLoadHelper::saveAs1D(const IESFileInfo& info, float* data, std::uint32_t width, std::uint8_t channel) noexcept +{ + assert(data); + assert(width > 0); + assert(channel == 1 || channel == 3 || channel == 4); + assert(info.valid()); + + float invW = 1.0f / width; + float invMaxValue = this->computeInvMax(info._candalaValues); + + for (std::uint32_t x = 0; x < width; ++x) + { + float fraction = x * invW; + float value = invMaxValue * interpolate1D(info, fraction * 180.0f); + + switch (channel) + { + case 1: + *data++ = value; + break; + case 3: + *data++ = value; + *data++ = value; + *data++ = value; + break; + case 4: + *data++ = value; + *data++ = value; + *data++ = value; + *data++ = 1.0f; + break; + default: + return false; + } + } + + return true; +} + +bool +IESLoadHelper::saveAs2D(const IESFileInfo& info, float* data, std::uint32_t width, std::uint32_t height, std::uint8_t channel) noexcept +{ + assert(data); + assert(width > 0 && height > 0); + assert(channel == 1 || channel == 3 || channel == 4); + assert(info.valid()); + + float invW = 1.0f / width; + float invH = 1.0f / height; + float invMaxValue = this->computeInvMax(info._candalaValues); + + for (std::uint32_t y = 0; y < height; ++y) + { + for (std::uint32_t x = 0; x < width; ++x) + { + float fractionV = x * invW * 180.0f; + float fractionH = y * invH * 180.0f; + float value = invMaxValue * interpolate2D(info, fractionV, fractionH); + + switch (channel) + { + case 1: + *data++ = value; + break; + case 3: + *data++ = value; + *data++ = value; + *data++ = value; + break; + case 4: + *data++ = value; + *data++ = value; + *data++ = value; + *data++ = 1.0; + break; + default: + return false; + } + } + } + + return true; +} + +bool +IESLoadHelper::saveAsPreview(const IESFileInfo& info, std::uint8_t* data, std::uint32_t width, std::uint32_t height, std::uint8_t channel) noexcept +{ + assert(data); + assert(width > 0 && height > 0); + assert(channel == 1 || channel == 3 || channel == 4); + assert(info.valid()); + + std::vector ies(256); + if (!this->saveAs1D(info, ies.data(), ies.size(), 1)) + return false; + + float maxValue = this->computeInvMax(info._candalaValues); + + auto TonemapHable = [](float x) + { + const float A = 0.22f; + const float B = 0.30f; + const float C = 0.10f; + const float D = 0.20f; + const float E = 0.01f; + const float F = 0.30f; + return ((x*(A*x + C*B) + D*E) / (x*(A*x + B) + D*F)) - E / F; + }; + + for (int y = 0; y < height; y++) + { + for (int x = 0; x < width; x++) + { + float u = ((float)x / width) * 2.0f - 1.0f; + float v = 1.0f - ((float)y / height) * 2.0f - 1.0f; + + u *= 2.2f; + v *= 2.4f; + + // float3(0.0f, 0.0f, -0.5f) - ray::float3(u, v, 0.0f) + float lx = +0.0f - u; + float ly = +0.0f - v; + float lz = -0.5f - 0.0f; + + // normalize + float length = std::sqrt(lx * lx + ly * ly + lz * lz); + lx /= length; + ly /= length; + lz /= length; + + float angle = 1.0 - std::acos(lx * 0.0 + ly * -1.0 + lz * 0.0f) / 3.141592654; + + float intensity = ies[angle * 255] * maxValue / length; + + std::uint8_t value = std::min(std::max((int)std::floor(TonemapHable(intensity) / TonemapHable(maxValue) * 255.0f), 0), 255); + + switch (channel) + { + case 1: + *data++ = value; + break; + case 3: + *data++ = value; + *data++ = value; + *data++ = value; + break; + case 4: + *data++ = value; + *data++ = value; + *data++ = value; + *data++ = 1.0; + break; + default: + return false; + } + } + } + + return true; +} + +float +IESLoadHelper::computeInvMax(const std::vector& candalaValues) const +{ + assert(candalaValues.size()); + + float candala = *std::max_element(candalaValues.begin(), candalaValues.end()); + return 1.0f / candala; +} + +float +IESLoadHelper::computeFilterPos(float value, const std::vector& angles) const +{ + assert(angles.size()); + + std::size_t start = 0; + std::size_t end = angles.size() - 1; + + if (value < angles[start]) return 0.0f; + if (value > angles[end]) return (float)end; + + while (start < end) + { + std::size_t index = (start + end + 1) / 2; + + float angle = angles[index]; + if (value >= angle) + { + assert(start != index); + start = index; + } + else + { + assert(end != index - 1); + end = index - 1; + } + } + + float leftValue = angles[start]; + float fraction = 0.0f; + + if (start + 1 < (std::uint32_t)angles.size()) + { + float rightValue = angles[start + 1]; + float deltaValue = rightValue - leftValue; + + if (deltaValue > 0.0001f) + { + fraction = (value - leftValue) / deltaValue; + } + } + + return start + fraction; +} + +float +IESLoadHelper::interpolate1D(const IESFileInfo& info, float angle) const +{ + float angleV = this->computeFilterPos(angle, info._anglesV); + float anglesNum = (float)info._anglesH.size(); + float angleTotal = 0.0f; + + for (float x = 0; x < anglesNum; x++) + angleTotal += this->interpolateBilinear(info, x, angleV); + + return angleTotal / anglesNum; +} + +float +IESLoadHelper::interpolate2D(const IESFileInfo& info, float angleV, float angleH) const +{ + float u = this->computeFilterPos(angleH, info._anglesH); + float v = this->computeFilterPos(angleV, info._anglesV); + return this->interpolateBilinear(info, u, v); +} + +float +IESLoadHelper::interpolatePoint(const IESFileInfo& info, std::uint32_t x, std::uint32_t y) const +{ + assert(x >= 0); + assert(y >= 0); + + std::size_t anglesNumH = info._anglesH.size(); + std::size_t anglesNumV = info._anglesV.size(); + + x %= anglesNumH; + y %= anglesNumV; + + assert(x < anglesNumH); + assert(y < anglesNumV); + + return info._candalaValues[y + anglesNumV * x]; +} + +float +IESLoadHelper::interpolateBilinear(const IESFileInfo& info, float x, float y) const +{ + int ix = (int)std::floor(x); + int iy = (int)std::floor(y); + + float fracX = x - ix; + float fracY = y - iy; + + float p00 = this->interpolatePoint(info, ix + 0, iy + 0); + float p10 = this->interpolatePoint(info, ix + 1, iy + 0); + float p01 = this->interpolatePoint(info, ix + 0, iy + 1); + float p11 = this->interpolatePoint(info, ix + 1, iy + 1); + + auto lerp = [](float t1, float t2, float t3) -> float { return t1 + (t2 - t1) * t3; }; + + float p0 = lerp(p00, p01, fracY); + float p1 = lerp(p10, p11, fracY); + + return lerp(p0, p1, fracX); +} + +void +IESLoadHelper::skipSpaceAndLineEnd(const std::string& data, std::string& out, bool stopOnComma) +{ + std::size_t dataBegin = 0; + std::size_t dataEnd = data.size(); + + while (dataBegin < dataEnd) + { + if (data[dataBegin] != '\r' && data[dataBegin] != '\n' && data[dataBegin] > ' ') + break; + dataBegin++; + } + + if (stopOnComma) + { + while (dataBegin < dataEnd) + { + if (data[dataBegin] != ',') + break; + dataBegin++; + } + } + + out = data.substr(dataBegin, data.size() - dataBegin); +} + +void +IESLoadHelper::getLineContent(const std::string& data, std::string& next, std::string& line, bool stopOnWhiteSpace, bool stopOnComma) +{ + skipSpaceAndLineEnd(data, next); + + auto it = data.begin(); + auto end = data.end(); + + for (; it < end; ++it) + { + if ((*it == '\r') || + (*it == '\n') || + (*it <= ' ' && stopOnWhiteSpace) || + (*it == ',' && stopOnComma)) + { + break; + } + } + + line.assign(data, 0, it - data.begin()); + next.assign(data, it - data.begin(), end - it); + + skipSpaceAndLineEnd(next, next, stopOnComma); +} + +void +IESLoadHelper::getFloat(const std::string& data, std::string& next, float& ret, bool stopOnWhiteSpace, bool stopOnComma) +{ + std::string line; + getLineContent(data, next, line, stopOnWhiteSpace, stopOnComma); + assert(!line.empty()); + ret = (float)std::atof(line.c_str()); +} + +void +IESLoadHelper::getInt(const std::string& data, std::string& next, std::int32_t& ret, bool stopOnWhiteSpace, bool stopOnComma) +{ + std::string line; + getLineContent(data, next, line, stopOnWhiteSpace, stopOnComma); + assert(!line.empty()); + ret = std::atoi(line.c_str()); +} \ No newline at end of file diff --git a/Engine/source/gfx/bitmap/loaders/ies/ies_loader.h b/Engine/source/gfx/bitmap/loaders/ies/ies_loader.h new file mode 100644 index 000000000..532b47d32 --- /dev/null +++ b/Engine/source/gfx/bitmap/loaders/ies/ies_loader.h @@ -0,0 +1,116 @@ +// +---------------------------------------------------------------------- +// | Project : ray. +// | All rights reserved. +// +---------------------------------------------------------------------- +// | Copyright (c) 2013-2017. +// +---------------------------------------------------------------------- +// | * Redistribution and use of this software in source and binary forms, +// | with or without modification, are permitted provided that the following +// | conditions are met: +// | +// | * Redistributions of source code must retain the above +// | copyright notice, this list of conditions and the +// | following disclaimer. +// | +// | * Redistributions in binary form must reproduce the above +// | copyright notice, this list of conditions and the +// | following disclaimer in the documentation and/or other +// | materials provided with the distribution. +// | +// | * Neither the name of the ray team, nor the names of its +// | contributors may be used to endorse or promote products +// | derived from this software without specific prior +// | written permission of the ray team. +// | +// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +---------------------------------------------------------------------- +#ifndef _H_IES_LOADER_H_ +#define _H_IES_LOADER_H_ + +#include +#include + +// https://knowledge.autodesk.com/support/3ds-max/learn-explore/caas/CloudHelp/cloudhelp/2016/ENU/3DSMax/files/GUID-EA0E3DE0-275C-42F7-83EC-429A37B2D501-htm.html +class IESFileInfo +{ +public: + IESFileInfo(); + + bool valid() const; + + const std::string& error() const; + +public: + float totalLights; + float totalLumens; + + float candalaMult; + + std::int32_t typeOfPhotometric; + std::int32_t typeOfUnit; + + std::int32_t anglesNumH; + std::int32_t anglesNumV; + + float width; + float length; + float height; + + float ballastFactor; + float futureUse; + float inputWatts; + +private: + friend class IESLoadHelper; + + float _cachedIntegral; + + std::string _error; + std::string _version; + + std::vector _anglesH; + std::vector _anglesV; + std::vector _candalaValues; +}; + +class IESLoadHelper final +{ +public: + IESLoadHelper(); + ~IESLoadHelper(); + + bool load(const std::string& data, IESFileInfo& info); + bool load(const char* data, std::size_t dataLength, IESFileInfo& info); + + bool saveAs1D(const IESFileInfo& info, float* data, std::uint32_t width = 256, std::uint8_t channel = 3) noexcept; + bool saveAs2D(const IESFileInfo& info, float* data, std::uint32_t width = 256, std::uint32_t height = 256, std::uint8_t channel = 3) noexcept; + bool saveAsPreview(const IESFileInfo& info, std::uint8_t* data, std::uint32_t width = 64, std::uint32_t height = 64, std::uint8_t channel = 3) noexcept; + +private: + float computeInvMax(const std::vector& candalaValues) const; + float computeFilterPos(float value, const std::vector& angle) const; + + float interpolate1D(const IESFileInfo& info, float angle) const; + float interpolate2D(const IESFileInfo& info, float angleV, float angleH) const; + float interpolatePoint(const IESFileInfo& info, std::uint32_t x, std::uint32_t y) const; + float interpolateBilinear(const IESFileInfo& info, float x, float y) const; + +private: + static void skipSpaceAndLineEnd(const std::string& data, std::string& out, bool stopOnComma = false); + + static void getLineContent(const std::string& data, std::string& next, std::string& line, bool stopOnWhiteSpace, bool stopOnComma); + static void getFloat(const std::string& data, std::string& next, float& ret, bool stopOnWhiteSpace = true, bool stopOnComma = false); + static void getInt(const std::string& data, std::string& next, std::int32_t& ret, bool stopOnWhiteSpace = true, bool stopOnComma = false); +}; + +#endif \ No newline at end of file diff --git a/Engine/source/lighting/advanced/advancedLightBinManager.cpp b/Engine/source/lighting/advanced/advancedLightBinManager.cpp index c857933dd..998bc2bcf 100644 --- a/Engine/source/lighting/advanced/advancedLightBinManager.cpp +++ b/Engine/source/lighting/advanced/advancedLightBinManager.cpp @@ -830,6 +830,7 @@ void AdvancedLightBinManager::LightMaterialInfo::setLightParameters( const Light const F32 radius = lightInfo->getRange().x; const F32 invSqrRadius = 1.0f / (radius * radius); matParams->setSafe( lightRange, radius); + matParams->setSafe( lightDirection, -lightInfo->getTransform().getUpVector()); matParams->setSafe( lightInvSqrRange, invSqrRadius); luxTargMultiplier =radius; } diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl index 339bc6619..52931ed15 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl @@ -109,7 +109,7 @@ TORQUE_UNIFORM_SAMPLER2D(colorBuffer, 3); TORQUE_UNIFORM_SAMPLER2D(matInfoBuffer, 4); #ifdef USE_COOKIE_TEX /// The texture for cookie rendering. -TORQUE_UNIFORM_SAMPLERCUBE(cookieMap, 5); +TORQUE_UNIFORM_SAMPLER2D(cookieMap, 5); #endif uniform float4 rtParams0; @@ -117,6 +117,7 @@ uniform float4 lightColor; uniform float lightBrightness; uniform float3 lightPosition; +uniform float3 lightDirection; uniform float4 lightMapParams; uniform float4 vsFarPlane; @@ -163,31 +164,20 @@ float4 main( ConvexConnectP IN ) : SV_TARGET #ifndef NO_SHADOW if (getFlag(surface.matFlag, 0)) //also skip if we don't recieve shadows { - #ifdef SHADOW_CUBE + #ifdef SHADOW_CUBE - // TODO: We need to fix shadow cube to handle soft shadows! - float occ = TORQUE_TEXCUBE( shadowMap, mul( worldToLightProj, -surfaceToLight.L ) ).r; - shadow = saturate( exp( lightParams.y * ( occ - distToLight ) ) ); + // TODO: We need to fix shadow cube to handle soft shadows! + float occ = TORQUE_TEXCUBE( shadowMap, mul( worldToLightProj, -surfaceToLight.L ) ).r; + shadow = saturate( exp( lightParams.y * ( occ - distToLight ) ) ); - #else - float2 shadowCoord = decodeShadowCoord( mul( worldToLightProj, -surfaceToLight.L ) ).xy; - shadow = softShadow_filter(TORQUE_SAMPLER2D_MAKEARG(shadowMap), ssPos.xy, shadowCoord, shadowSoftness, distToLight, surfaceToLight.NdotL, lightParams.y); - #endif + #else + float2 shadowCoord = decodeShadowCoord( mul( worldToLightProj, -surfaceToLight.L ) ).xy; + shadow = softShadow_filter(TORQUE_SAMPLER2D_MAKEARG(shadowMap), ssPos.xy, shadowCoord, shadowSoftness, distToLight, surfaceToLight.NdotL, lightParams.y); + #endif } #endif // !NO_SHADOW float3 lightCol = lightColor.rgb; - #ifdef USE_COOKIE_TEX - // Lookup the cookie sample. - float4 cookie = TORQUE_TEXCUBE(cookieMap, mul(worldToLightProj, -surfaceToLight.L)); - // Multiply the light with the cookie tex. - lightCol *= cookie.rgb; - // Use a maximum channel luminance to attenuate - // the lighting else we get specular in the dark - // regions of the cookie texture. - lightCol *= max(cookie.r, max(cookie.g, cookie.b)); - #endif - #ifdef DIFFUSE_LIGHT_VIZ float attenuation = getDistanceAtt(surfaceToLight.Lu, radius); float3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity * attenuation; @@ -198,7 +188,7 @@ float4 main( ConvexConnectP IN ) : SV_TARGET #endif #ifdef SPECULAR_LIGHT_VIZ - float attenuation = getDistanceAtt(surfaceToLight.Lu, radius); + float attenuation = getDistanceAtt(surfaceToLight.Lu, radius); float3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity * attenuation; float3 diffuse = BRDF_GetDebugSpecular(surface,surfaceToLight) * factor; @@ -219,7 +209,17 @@ float4 main( ConvexConnectP IN ) : SV_TARGET //get punctual light contribution lighting = getPunctualLight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, shadow); + + #ifdef USE_COOKIE_TEX + // Lookup the cookie sample.d + float cosTheta = dot(-surfaceToLight.L, lightDirection); + float angle = acos(cosTheta) * ( M_1OVER_PI_F); + float cookie = TORQUE_TEX2D(cookieMap, float2(angle, 0.0)).r; + // Multiply the light with the cookie tex. + lighting *= cookie; + #endif } - + + return float4(lighting, 0); } diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl index d4ef36a36..22b2275d5 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl @@ -109,16 +109,7 @@ float4 main( ConvexConnectP IN ) : SV_TARGET //distance to light in shadow map space float distToLight = pxlPosLightProj.z / lightRange; shadow = softShadow_filter(TORQUE_SAMPLER2D_MAKEARG(shadowMap), ssPos.xy, shadowCoord, shadowSoftness, distToLight, surfaceToLight.NdotL, lightParams.y); - #ifdef USE_COOKIE_TEX - // Lookup the cookie sample. - float4 cookie = TORQUE_TEX2D(cookieMap, shadowCoord); - // Multiply the light with the cookie tex. - lightCol *= cookie.rgb; - // Use a maximum channel luminance to attenuate - // the lighting else we get specular in the dark - // regions of the cookie texture. - lightCol *= max(cookie.r, max(cookie.g, cookie.b)); - #endif + } #endif @@ -153,6 +144,14 @@ float4 main( ConvexConnectP IN ) : SV_TARGET //get spot light contribution lighting = getSpotlight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, lightDirection, lightSpotParams, shadow); + #ifdef USE_COOKIE_TEX + // Lookup the cookie sample.d + float cosTheta = dot(-surfaceToLight.L, lightDirection); + float angle = acos(cosTheta) * ( M_1OVER_PI_F); + float cookie = TORQUE_TEX2D(cookieMap, float2(angle, 0.0)).r; + // Multiply the light with the cookie tex. + lighting *= cookie; + #endif } return float4(lighting, 0); From 4417462499dffc0956ced889e29f65758207a747 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 21 Feb 2024 07:40:57 +0000 Subject: [PATCH 09/29] Add support for both ies and cookie Both ies and cookies can now exist on a light We are still not using all the capabilities of an IES profile, such as candela and luminance values we are just using them as a mask for the moment Issues compiling on mac and linux, will need to update the ies-loader to use torque methods instead of std:: --- Engine/source/core/util/tDictionary.h | 20 ++++++++++ .../advanced/advancedLightBinManager.cpp | 14 ++++--- .../advanced/advancedLightBinManager.h | 4 +- .../advanced/advancedLightManager.cpp | 15 ++++++++ .../lighting/shadowMap/lightShadowMap.cpp | 37 ++++++++++++++++++- .../lighting/shadowMap/lightShadowMap.h | 7 ++++ Engine/source/materials/materialDefinition.h | 1 + .../materials/processedCustomMaterial.cpp | 8 ++++ .../lighting/advanced/pointLightP.hlsl | 34 ++++++++++++----- .../shaders/lighting/advanced/spotLightP.hlsl | 29 ++++++++++----- 10 files changed, 142 insertions(+), 27 deletions(-) diff --git a/Engine/source/core/util/tDictionary.h b/Engine/source/core/util/tDictionary.h index 901990289..4af0d6037 100644 --- a/Engine/source/core/util/tDictionary.h +++ b/Engine/source/core/util/tDictionary.h @@ -65,6 +65,21 @@ struct CompoundKey3 bool operator==(const CompoundKey3 & compound) const { return key1==compound.key1 && key2==compound.key2 && key3==compound.key3; } }; +template +struct CompoundKey4 +{ + A key1; + B key2; + C key3; + D key4; + + CompoundKey4() {}; + CompoundKey4(const A& a, const B& b, const C& c, const D& d) { key1 = a; key2 = b; key3 = c; key4 = d;}; + + bool operator==(const CompoundKey4& compound) const { return key1 == compound.key1 && key2 == compound.key2 && key3 == compound.key3 && key4 == compound.key4; } +}; + + namespace DictHash { @@ -110,6 +125,11 @@ namespace DictHash return hash(compound.key1) + hash(compound.key2) + hash(compound.key3); } + template + inline U32 hash(const CompoundKey4& compound) + { + return hash(compound.key1) + hash(compound.key2) + hash(compound.key3) + hash(compound.key4); + } U32 nextPrime(U32); }; diff --git a/Engine/source/lighting/advanced/advancedLightBinManager.cpp b/Engine/source/lighting/advanced/advancedLightBinManager.cpp index 998bc2bcf..431ec28ad 100644 --- a/Engine/source/lighting/advanced/advancedLightBinManager.cpp +++ b/Engine/source/lighting/advanced/advancedLightBinManager.cpp @@ -253,7 +253,7 @@ void AdvancedLightBinManager::addLight( LightInfo *light ) LightBinEntry lEntry; lEntry.lightInfo = light; lEntry.shadowMap = lsm; - lEntry.lightMaterial = _getLightMaterial( lightType, shadowType, lsp->hasCookieTex() ); + lEntry.lightMaterial = _getLightMaterial( lightType, shadowType, lsp->hasCookieTex(), lsp->hasIesProfile() ); if( lightType == LightInfo::Spot ) lEntry.vertBuffer = mLightManager->getConeMesh( lEntry.numPrims, lEntry.primBuffer ); @@ -399,9 +399,9 @@ void AdvancedLightBinManager::render( SceneRenderState *state ) sunLight->getCastShadows() && !disableShadows && sunLight->getExtended() ) - vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_PSSM, false ); + vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_PSSM ); else - vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_None, false ); + vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_None ); // Initialize and set the per-frame parameters after getting // the vector light material as we use lazy creation. @@ -513,12 +513,13 @@ void AdvancedLightBinManager::render( SceneRenderState *state ) AdvancedLightBinManager::LightMaterialInfo* AdvancedLightBinManager::_getLightMaterial( LightInfo::Type lightType, ShadowType shadowType, - bool useCookieTex ) + bool useCookieTex, + bool isPhotometric) { PROFILE_SCOPE( AdvancedLightBinManager_GetLightMaterial ); // Build the key. - const LightMatKey key( lightType, shadowType, useCookieTex ); + const LightMatKey key( lightType, shadowType, useCookieTex, isPhotometric ); // See if we've already built this one. LightMatTable::Iterator iter = mLightMaterials.find( key ); @@ -558,6 +559,9 @@ AdvancedLightBinManager::LightMaterialInfo* AdvancedLightBinManager::_getLightMa if ( useCookieTex ) shadowMacros.push_back( GFXShaderMacro( "USE_COOKIE_TEX" ) ); + if(isPhotometric) + shadowMacros.push_back(GFXShaderMacro("UES_PHOTOMETRIC_MASK")); + // Its safe to add the PSSM debug macro to all the materials. if ( smPSSMDebugRender ) shadowMacros.push_back( GFXShaderMacro( "PSSM_DEBUG_RENDER" ) ); diff --git a/Engine/source/lighting/advanced/advancedLightBinManager.h b/Engine/source/lighting/advanced/advancedLightBinManager.h index 4d04f3cfc..71131a1d3 100644 --- a/Engine/source/lighting/advanced/advancedLightBinManager.h +++ b/Engine/source/lighting/advanced/advancedLightBinManager.h @@ -233,14 +233,14 @@ protected: static const GFXVertexFormat* smLightMatVertex[LightInfo::Count]; - typedef CompoundKey3 LightMatKey; + typedef CompoundKey4 LightMatKey; typedef HashTable LightMatTable; /// The fixed table of light material info. LightMatTable mLightMaterials; - LightMaterialInfo* _getLightMaterial( LightInfo::Type lightType, ShadowType shadowType, bool useCookieTex ); + LightMaterialInfo* _getLightMaterial( LightInfo::Type lightType, ShadowType shadowType, bool useCookieTex = false, bool isPhotometric = false ); /// void _onShadowFilterChanged(); diff --git a/Engine/source/lighting/advanced/advancedLightManager.cpp b/Engine/source/lighting/advanced/advancedLightManager.cpp index 47c8d3d36..6d7ea9d7e 100644 --- a/Engine/source/lighting/advanced/advancedLightManager.cpp +++ b/Engine/source/lighting/advanced/advancedLightManager.cpp @@ -277,6 +277,7 @@ void AdvancedLightManager::_initLightFields() DEFINE_LIGHT_FIELD( attenuationRatio, TypePoint3F, NULL ); DEFINE_LIGHT_FIELD( shadowType, TYPEID< ShadowType >(), ConsoleBaseType::getType( TYPEID< ShadowType >() )->getEnumTable() ); DEFINE_LIGHT_FIELD( texSize, TypeS32, NULL ); + DEFINE_LIGHT_FIELD( iesProfile, TypeStringFilename, NULL ); DEFINE_LIGHT_FIELD( cookie, TypeStringFilename, NULL ); DEFINE_LIGHT_FIELD( numSplits, TypeS32, NULL ); DEFINE_LIGHT_FIELD( logWeight, TypeF32, NULL ); @@ -300,6 +301,9 @@ void AdvancedLightManager::_initLightFields() ADD_LIGHT_FIELD( "shadowType", TYPEID< ShadowType >(), shadowType, "The type of shadow to use on this light." ); + ADD_LIGHT_FIELD("iesProfile", TypeStringFilename, iesProfile, + "A photometric profile for the light."); + ADD_LIGHT_FIELD( "cookie", TypeStringFilename, cookie, "A custom pattern texture which is projected from the light." ); @@ -496,6 +500,17 @@ bool AdvancedLightManager::setTextureStage( const SceneData &sgData, return true; } + else if (currTexFlag == Material::PhotometricMask) + { + S32 reg = lsc->mIesProfileSC->getSamplerRegister(); + if (reg != -1 && sgData.lights[0]) + { + ShadowMapParams* p = sgData.lights[0]->getExtended(); + GFX->setTexture(reg, p->getIesProfileTex()); + } + + return true; + } return false; } diff --git a/Engine/source/lighting/shadowMap/lightShadowMap.cpp b/Engine/source/lighting/shadowMap/lightShadowMap.cpp index 9ecde8c97..6f10bf6a1 100644 --- a/Engine/source/lighting/shadowMap/lightShadowMap.cpp +++ b/Engine/source/lighting/shadowMap/lightShadowMap.cpp @@ -269,7 +269,8 @@ bool LightShadowMap::setTextureStage( U32 currTexFlag, LightingShaderConstants* GFX->setTexture( reg, mShadowMapTex); return true; - } else if ( currTexFlag == Material::DynamicLightMask ) + } + else if ( currTexFlag == Material::DynamicLightMask ) { S32 reg = lsc->mCookieMapSC->getSamplerRegister(); if ( reg != -1 ) @@ -284,6 +285,17 @@ bool LightShadowMap::setTextureStage( U32 currTexFlag, LightingShaderConstants* return true; } + else if (currTexFlag == Material::PhotometricMask) + { + S32 reg = lsc->mIesProfileSC->getSamplerRegister(); + if (reg != -1) + { + ShadowMapParams* p = mLight->getExtended(); + GFX->setTexture(reg, p->getIesProfileTex()); + } + + return true; + } return false; } @@ -430,6 +442,7 @@ LightingShaderConstants::LightingShaderConstants() mShadowMapSC(NULL), mShadowMapSizeSC(NULL), mCookieMapSC(NULL), + mIesProfileSC(NULL), mRandomDirsConst(NULL), mShadowSoftnessConst(NULL), mAtlasXOffsetSC(NULL), @@ -490,6 +503,7 @@ void LightingShaderConstants::init(GFXShader* shader) mShadowMapSizeSC = shader->getShaderConstHandle("$shadowMapSize"); mCookieMapSC = shader->getShaderConstHandle("$cookieMap"); + mIesProfileSC = shader->getShaderConstHandle("$iesProfile"); mShadowSoftnessConst = shader->getShaderConstHandle("$shadowSoftness"); mAtlasXOffsetSC = shader->getShaderConstHandle("$atlasXOffset"); @@ -542,7 +556,8 @@ ShadowMapParams::ShadowMapParams( LightInfo *light ) fadeStartDist = 75.0f; lastSplitTerrainOnly = false; mQuery = GFX->createOcclusionQuery(); - cookie = StringTable->EmptyString();; + cookie = StringTable->EmptyString(); + iesProfile = StringTable->EmptyString(); _validate(); } @@ -662,6 +677,22 @@ GFXTextureObject* ShadowMapParams::getCookieTex() return mCookieTex.getPointer(); } +GFXTextureObject* ShadowMapParams::getIesProfileTex() +{ + if (hasIesProfile() && + (mIesTex.isNull() || + iesProfile != StringTable->insert(mIesTex->getPath().c_str()))) + { + mIesTex.set(iesProfile, + &GFXStaticTextureSRGBProfile, + "ShadowMapParams::getIesProfileTex()"); + } + else if (!hasIesProfile()) + mIesTex = NULL; + + return mIesTex.getPointer(); +} + GFXCubemap* ShadowMapParams::getCookieCubeTex() { if ( hasCookieTex() && @@ -695,6 +726,7 @@ void ShadowMapParams::packUpdate( BitStream *stream ) const stream->write( texSize ); stream->writeString( cookie ); + stream->writeString( iesProfile ); stream->write( numSplits ); stream->write( logWeight ); @@ -725,6 +757,7 @@ void ShadowMapParams::unpackUpdate( BitStream *stream ) stream->read( &texSize ); cookie = stream->readSTString(); + iesProfile = stream->readSTString(); stream->read( &numSplits ); stream->read( &logWeight ); diff --git a/Engine/source/lighting/shadowMap/lightShadowMap.h b/Engine/source/lighting/shadowMap/lightShadowMap.h index 57870ac62..a25ff7ec2 100644 --- a/Engine/source/lighting/shadowMap/lightShadowMap.h +++ b/Engine/source/lighting/shadowMap/lightShadowMap.h @@ -99,6 +99,7 @@ struct LightingShaderConstants GFXShaderConstHandle* mShadowMapSizeSC; GFXShaderConstHandle* mCookieMapSC; + GFXShaderConstHandle* mIesProfileSC; GFXShaderConstHandle* mRandomDirsConst; GFXShaderConstHandle* mShadowSoftnessConst; @@ -289,11 +290,14 @@ public: LightShadowMap* getOrCreateShadowMap(); bool hasCookieTex() const { return cookie != StringTable->EmptyString(); } + bool hasIesProfile() const { return iesProfile != StringTable->EmptyString(); } GFXOcclusionQuery* getOcclusionQuery() const { return mQuery; } GFXTextureObject* getCookieTex(); + GFXTextureObject* getIesProfileTex(); + GFXCubemap* getCookieCubeTex(); // Validates the parameters after a field is changed. @@ -313,6 +317,8 @@ protected: GFXCubemapHandle mCookieCubeTex; + GFXTexHandle mIesTex; + public: // We're leaving these public for easy access @@ -326,6 +332,7 @@ public: /// StringTableEntry cookie; + StringTableEntry iesProfile; /// @} diff --git a/Engine/source/materials/materialDefinition.h b/Engine/source/materials/materialDefinition.h index afb68564d..504fecaa6 100644 --- a/Engine/source/materials/materialDefinition.h +++ b/Engine/source/materials/materialDefinition.h @@ -94,6 +94,7 @@ public: Misc, DynamicLight, DynamicLightMask, + PhotometricMask, NormalizeCube, TexTarget, AccuMap, diff --git a/Engine/source/materials/processedCustomMaterial.cpp b/Engine/source/materials/processedCustomMaterial.cpp index e2657b349..15772c078 100644 --- a/Engine/source/materials/processedCustomMaterial.cpp +++ b/Engine/source/materials/processedCustomMaterial.cpp @@ -94,6 +94,14 @@ void ProcessedCustomMaterial::_setStageData() continue; } + if (filename.equal(String("$photometricmask"), String::NoCase)) + { + rpd->mTexType[i] = Material::PhotometricMask; + rpd->mSamplerNames[i] = mCustomMaterial->mSamplerNames[i]; + mMaxTex = i + 1; + continue; + } + if(filename.equal(String("$lightmap"), String::NoCase)) { rpd->mTexType[i] = Material::Lightmap; diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl index 52931ed15..de3d3433f 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl @@ -107,10 +107,13 @@ TORQUE_UNIFORM_SAMPLER2D(shadowMap, 1); #include "softShadow.hlsl" TORQUE_UNIFORM_SAMPLER2D(colorBuffer, 3); TORQUE_UNIFORM_SAMPLER2D(matInfoBuffer, 4); -#ifdef USE_COOKIE_TEX /// The texture for cookie rendering. +#ifdef SHADOW_CUBE +TORQUE_UNIFORM_SAMPLERCUBE(cookieMap, 5); +#else TORQUE_UNIFORM_SAMPLER2D(cookieMap, 5); #endif +TORQUE_UNIFORM_SAMPLER2D(iesProfile, 6); uniform float4 rtParams0; uniform float4 lightColor; @@ -159,8 +162,8 @@ float4 main( ConvexConnectP IN ) : SV_TARGET { float distToLight = dist / lightRange; SurfaceToLight surfaceToLight = createSurfaceToLight(surface, L); - - float shadow = 1.0; + float3 lightCol = lightColor.rgb; + float shadow = 1.0; #ifndef NO_SHADOW if (getFlag(surface.matFlag, 0)) //also skip if we don't recieve shadows { @@ -176,8 +179,21 @@ float4 main( ConvexConnectP IN ) : SV_TARGET #endif } #endif // !NO_SHADOW - - float3 lightCol = lightColor.rgb; + #ifdef USE_COOKIE_TEX + // Lookup the cookie sample. + #ifdef SHADOW_CUBE + float4 cookie = TORQUE_TEXCUBE(cookieMap, mul(worldToLightProj, -surfaceToLight.L)); + #else + float2 cookieCoord = decodeShadowCoord( mul( worldToLightProj, -surfaceToLight.L ) ).xy; + float4 cookie = TORQUE_TEX2D(cookieMap, cookieCoord); + #endif + // Multiply the light with the cookie tex. + lightCol *= cookie.rgb; + // Use a maximum channel luminance to attenuate + // the lighting else we get specular in the dark + // regions of the cookie texture. + lightCol *= max(cookie.r, max(cookie.g, cookie.b)); + #endif #ifdef DIFFUSE_LIGHT_VIZ float attenuation = getDistanceAtt(surfaceToLight.Lu, radius); float3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity * attenuation; @@ -210,13 +226,13 @@ float4 main( ConvexConnectP IN ) : SV_TARGET //get punctual light contribution lighting = getPunctualLight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, shadow); - #ifdef USE_COOKIE_TEX + #ifdef UES_PHOTOMETRIC_MASK // Lookup the cookie sample.d float cosTheta = dot(-surfaceToLight.L, lightDirection); float angle = acos(cosTheta) * ( M_1OVER_PI_F); - float cookie = TORQUE_TEX2D(cookieMap, float2(angle, 0.0)).r; - // Multiply the light with the cookie tex. - lighting *= cookie; + float iesMask = TORQUE_TEX2D(iesProfile, float2(angle, 0.0)).r; + // Multiply the light with the iesMask tex. + lighting *= iesMask; #endif } diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl index 22b2275d5..efd07fa30 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl @@ -42,11 +42,10 @@ TORQUE_UNIFORM_SAMPLER2D(shadowMap, 1); #include "softShadow.hlsl" TORQUE_UNIFORM_SAMPLER2D(colorBuffer, 3); TORQUE_UNIFORM_SAMPLER2D(matInfoBuffer, 4); -#ifdef USE_COOKIE_TEX /// The texture for cookie rendering. TORQUE_UNIFORM_SAMPLER2D(cookieMap, 5); +TORQUE_UNIFORM_SAMPLER2D(iesProfile, 6); -#endif uniform float4 rtParams0; uniform float lightBrightness; @@ -96,8 +95,7 @@ float4 main( ConvexConnectP IN ) : SV_TARGET if(dist < lightRange) { SurfaceToLight surfaceToLight = createSurfaceToLight(surface, L); - float3 lightCol = lightColor.rgb; - + float shadow = 1.0; #ifndef NO_SHADOW if (getFlag(surface.matFlag, 0)) //also skip if we don't recieve shadows @@ -109,10 +107,23 @@ float4 main( ConvexConnectP IN ) : SV_TARGET //distance to light in shadow map space float distToLight = pxlPosLightProj.z / lightRange; shadow = softShadow_filter(TORQUE_SAMPLER2D_MAKEARG(shadowMap), ssPos.xy, shadowCoord, shadowSoftness, distToLight, surfaceToLight.NdotL, lightParams.y); - } #endif + float3 lightCol = lightColor.rgb; + #ifdef USE_COOKIE_TEX + float4 pxlPosLightProj = mul( worldToLightProj, float4( surface.P, 1 ) ); + float2 cookieCoord = ( ( pxlPosLightProj.xy / pxlPosLightProj.w ) * 0.5 ) + float2( 0.5, 0.5 ); + // Lookup the cookie sample. + float4 cookie = TORQUE_TEX2D(cookieMap, cookieCoord); + // Multiply the light with the cookie tex. + lightCol *= cookie.rgb; + // Use a maximum channel luminance to attenuate + // the lighting else we get specular in the dark + // regions of the cookie texture. + lightCol *= max(cookie.r, max(cookie.g, cookie.b)); + #endif + #ifdef DIFFUSE_LIGHT_VIZ float attenuation = getDistanceAtt(surfaceToLight.Lu, radius); float3 factor = lightColor * max(surfaceToLight.NdotL, 0) * shadow * lightIntensity * attenuation; @@ -144,13 +155,13 @@ float4 main( ConvexConnectP IN ) : SV_TARGET //get spot light contribution lighting = getSpotlight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, lightDirection, lightSpotParams, shadow); - #ifdef USE_COOKIE_TEX + #ifdef UES_PHOTOMETRIC_MASK // Lookup the cookie sample.d float cosTheta = dot(-surfaceToLight.L, lightDirection); float angle = acos(cosTheta) * ( M_1OVER_PI_F); - float cookie = TORQUE_TEX2D(cookieMap, float2(angle, 0.0)).r; - // Multiply the light with the cookie tex. - lighting *= cookie; + float iesMask = TORQUE_TEX2D(iesProfile, float2(angle, 0.0)).r; + // Multiply the light with the iesMask tex. + lighting *= iesMask; #endif } From 39ec0305f9d225740beda3326de0b39f2e23c20f Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 21 Feb 2024 08:24:24 +0000 Subject: [PATCH 10/29] GLSL To match Update the glsl side to match hlsl ies profile usage --- .../lighting/advanced/gl/pointLightP.glsl | 20 ++++++++- .../lighting/advanced/gl/spotLightP.glsl | 42 +++++++++++-------- 2 files changed, 44 insertions(+), 18 deletions(-) diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/pointLightP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/pointLightP.glsl index 81a8c7e23..7e6984e21 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/pointLightP.glsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/pointLightP.glsl @@ -108,11 +108,15 @@ uniform sampler2D deferredBuffer; #include "softShadow.glsl" uniform sampler2D colorBuffer; uniform sampler2D matInfoBuffer; -#ifdef USE_COOKIE_TEX +#ifdef SHADOW_CUBE /// The texture for cookie rendering. uniform samplerCube cookieMap; +#else +uniform sampler2D cookieMap; #endif +uniform sampler2D iesProfile; + uniform vec4 rtParams0; uniform vec3 lightPosition; @@ -181,7 +185,12 @@ void main() #ifdef USE_COOKIE_TEX // Lookup the cookie sample. + #ifdef SHADOW_CUBE vec4 cookie = texture(cookieMap, tMul(worldToLightProj, -surfaceToLight.L)); + #else + vec2 cookieCoord = decodeShadowCoord( tMul( worldToLightProj, -surfaceToLight.L ) ).xy; + vec4 cookie = texture(cookieMap, cookieCoord); + #endif // Multiply the light with the cookie tex. lightCol *= cookie.rgb; // Use a maximum channel luminance to attenuate @@ -224,6 +233,15 @@ void main() //get punctual light contribution lighting = getPunctualLight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, shadow); + #ifdef UES_PHOTOMETRIC_MASK + // Lookup the cookie sample.d + float cosTheta = dot(-surfaceToLight.L, lightDirection); + float angle = acos(cosTheta) * ( M_1OVER_PI_F); + float iesMask = texture(iesProfile, vec2(angle, 0.0)).r; + // Multiply the light with the iesMask tex. + lighting *= iesMask; + #endif + } OUT_col = vec4(lighting, 0); diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl index 42654c532..f5983eb0d 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl @@ -38,11 +38,8 @@ uniform sampler2D shadowMap; #include "softShadow.glsl" uniform sampler2D colorBuffer; uniform sampler2D matInfoBuffer; -#ifdef USE_COOKIE_TEX -/// The texture for cookie rendering. uniform sampler2D cookieMap; -#endif - +uniform sampler2D iesProfile; uniform vec4 rtParams0; uniform float lightBrightness; @@ -91,7 +88,7 @@ void main() if(dist < lightRange) { SurfaceToLight surfaceToLight = createSurfaceToLight(surface, L); - vec3 lightCol = lightColor.rgb; + float shadow = 1.0; #ifndef NO_SHADOW @@ -105,19 +102,22 @@ void main() //distance to light in shadow map space float distToLight = pxlPosLightProj.z / lightRange; shadow = softShadow_filter(shadowMap, ssPos.xy/ssPos.w, shadowCoord, shadowSoftness, distToLight, surfaceToLight.NdotL, lightParams.y); - #ifdef USE_COOKIE_TEX - // Lookup the cookie sample. - vec4 cookie = texture(cookieMap, shadowCoord); - // Multiply the light with the cookie tex. - lightCol *= cookie.rgb; - // Use a maximum channel luminance to attenuate - // the lighting else we get specular in the dark - // regions of the cookie texture. - lightCol *= max(cookie.r, max(cookie.g, cookie.b)); - #endif + } - #endif - + #endif + + vec3 lightCol = lightColor.rgb; + #ifdef USE_COOKIE_TEX + // Lookup the cookie sample. + vec4 cookie = texture(cookieMap, shadowCoord); + // Multiply the light with the cookie tex. + lightCol *= cookie.rgb; + // Use a maximum channel luminance to attenuate + // the lighting else we get specular in the dark + // regions of the cookie texture. + lightCol *= max(cookie.r, max(cookie.g, cookie.b)); + #endif + #ifdef DIFFUSE_LIGHT_VIZ float attenuation = getDistanceAtt(surfaceToLight.Lu, radius); @@ -156,6 +156,14 @@ void main() //get spot light contribution lighting = getSpotlight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, lightDirection, lightSpotParams, shadow); + #ifdef UES_PHOTOMETRIC_MASK + // Lookup the cookie sample.d + float cosTheta = dot(-surfaceToLight.L, lightDirection); + float angle = acos(cosTheta) * ( M_1OVER_PI_F); + float iesMask = texture(iesProfile, vec2(angle, 0.0)).r; + // Multiply the light with the iesMask tex. + lighting *= iesMask; + #endif } OUT_col = vec4(lighting, 0); From ad64b4f2df8879b45d1f07838edee4a3decab614 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 21 Feb 2024 09:36:37 +0000 Subject: [PATCH 11/29] IES Loader Updated IES loader to use torque math functions and calls in the problem areas for mac and linux. New F32_MIN_EX which is lower than F32_MIN (required for ies profiles) --- .../gfx/bitmap/loaders/ies/ies_loader.cpp | 26 ++++++++++--------- Engine/source/platform/types.h | 1 + Engine/source/platform/typesLinux.h | 1 + Engine/source/platform/typesWin32.h | 1 + Engine/source/platform/typesX86UNIX.h | 1 + 5 files changed, 18 insertions(+), 12 deletions(-) diff --git a/Engine/source/gfx/bitmap/loaders/ies/ies_loader.cpp b/Engine/source/gfx/bitmap/loaders/ies/ies_loader.cpp index 48602fc9f..3df8c32bd 100644 --- a/Engine/source/gfx/bitmap/loaders/ies/ies_loader.cpp +++ b/Engine/source/gfx/bitmap/loaders/ies/ies_loader.cpp @@ -39,8 +39,10 @@ #include #include +#include "math/mMathFn.h" + IESFileInfo::IESFileInfo() - : _cachedIntegral(std::numeric_limits::max()) + : _cachedIntegral(F32_MAX) , _error("No data loaded") { } @@ -117,7 +119,7 @@ IESLoadHelper::load(const std::string& data, IESFileInfo& info) } this->getFloat(dataPos, dataPos, info.totalLights); - if (info.totalLights < 0 || info.totalLights > std::numeric_limits::max()) + if (info.totalLights < 0 || info.totalLights > F32_MAX) { info._error = "Light Count is not valid"; return false; @@ -138,14 +140,14 @@ IESLoadHelper::load(const std::string& data, IESFileInfo& info) } this->getInt(dataPos, dataPos, info.anglesNumV); - if (info.anglesNumV < 0 || info.anglesNumV > std::numeric_limits::max()) + if (info.anglesNumV < 0 || info.anglesNumV > F32_MAX) { info._error = "VAnglesNum is not valid"; return false; } this->getInt(dataPos, dataPos, info.anglesNumH); - if (info.anglesNumH < 0 || info.anglesNumH > std::numeric_limits::max()) + if (info.anglesNumH < 0 || info.anglesNumH > F32_MAX) { info._error = "HAnglesNum is not valid"; return false; @@ -162,8 +164,8 @@ IESLoadHelper::load(const std::string& data, IESFileInfo& info) this->getFloat(dataPos, dataPos, info.futureUse); this->getFloat(dataPos, dataPos, info.inputWatts); - float minSoFarV = std::numeric_limits::lowest(); - float minSoFarH = std::numeric_limits::lowest(); + float minSoFarV = F32_MIN_EX; + float minSoFarH = F32_MIN_EX; info._anglesV.reserve(info.anglesNumV); info._anglesH.reserve(info.anglesNumH); @@ -358,16 +360,16 @@ IESLoadHelper::saveAsPreview(const IESFileInfo& info, std::uint8_t* data, std::u float lz = -0.5f - 0.0f; // normalize - float length = std::sqrt(lx * lx + ly * ly + lz * lz); + float length = mSqrt(lx * lx + ly * ly + lz * lz); lx /= length; ly /= length; lz /= length; - float angle = 1.0 - std::acos(lx * 0.0 + ly * -1.0 + lz * 0.0f) / 3.141592654; + float angle = 1.0 - mAcos(lx * 0.0 + ly * -1.0 + lz * 0.0f) / 3.141592654; float intensity = ies[angle * 255] * maxValue / length; - std::uint8_t value = std::min(std::max((int)std::floor(TonemapHable(intensity) / TonemapHable(maxValue) * 255.0f), 0), 255); + std::uint8_t value = std::min(std::max((int)mFloor(TonemapHable(intensity) / TonemapHable(maxValue) * 255.0f), 0), 255); switch (channel) { @@ -490,8 +492,8 @@ IESLoadHelper::interpolatePoint(const IESFileInfo& info, std::uint32_t x, std::u float IESLoadHelper::interpolateBilinear(const IESFileInfo& info, float x, float y) const { - int ix = (int)std::floor(x); - int iy = (int)std::floor(y); + int ix = (int)mFloor(x); + int iy = (int)mFloor(y); float fracX = x - ix; float fracY = y - iy; @@ -576,4 +578,4 @@ IESLoadHelper::getInt(const std::string& data, std::string& next, std::int32_t& getLineContent(data, next, line, stopOnWhiteSpace, stopOnComma); assert(!line.empty()); ret = std::atoi(line.c_str()); -} \ No newline at end of file +} diff --git a/Engine/source/platform/types.h b/Engine/source/platform/types.h index 9acdefae0..669659b92 100644 --- a/Engine/source/platform/types.h +++ b/Engine/source/platform/types.h @@ -100,6 +100,7 @@ static const S32 S32_MIN = S32(-2147483647 - 1); ///< Constant static const S32 S32_MAX = S32(2147483647); ///< Constant Max Limit S32 static const U32 U32_MAX = U32(0xffffffff); ///< Constant Max Limit U32 +static const F32 F32_MIN_EX = F32(-3.40282347e+38); ///< Constant Min Limit F32 static const F32 F32_MIN = F32(1.175494351e-38F); ///< Constant Min Limit F32 static const F32 F32_MAX = F32(3.402823466e+38F); ///< Constant Max Limit F32 diff --git a/Engine/source/platform/typesLinux.h b/Engine/source/platform/typesLinux.h index f3b851028..0acb698b9 100644 --- a/Engine/source/platform/typesLinux.h +++ b/Engine/source/platform/typesLinux.h @@ -73,6 +73,7 @@ static const S32 S32_MIN = S32(-2147483647 - 1); static const S32 S32_MAX = S32(2147483647); static const U32 U32_MAX = U32(0xffffffff); +static const F32 F32_MIN_EX = F32(-3.40282347e+38); static const F32 F32_MAX = F32(3.402823466e+38F); static const F32 F32_MIN = F32(1.175494351e-38F); diff --git a/Engine/source/platform/typesWin32.h b/Engine/source/platform/typesWin32.h index 029b1a341..8d96b3bfb 100644 --- a/Engine/source/platform/typesWin32.h +++ b/Engine/source/platform/typesWin32.h @@ -116,6 +116,7 @@ static const S32 S32_MIN = S32(-2147483647 - 1); ///< Constant static const S32 S32_MAX = S32(2147483647); ///< Constant Max Limit S32 static const U32 U32_MAX = U32(0xffffffff); ///< Constant Max Limit U32 +static const F32 F32_MIN_EX = F32(-3.40282347e+38); ///< Constant Min Limit F32 static const F32 F32_MIN = F32(1.175494351e-38F); ///< Constant Min Limit F32 static const F32 F32_MAX = F32(3.402823466e+38F); ///< Constant Max Limit F32 diff --git a/Engine/source/platform/typesX86UNIX.h b/Engine/source/platform/typesX86UNIX.h index 56ba18679..a9b4ab31e 100644 --- a/Engine/source/platform/typesX86UNIX.h +++ b/Engine/source/platform/typesX86UNIX.h @@ -73,6 +73,7 @@ static const S32 S32_MIN = S32(-2147483647 - 1); static const S32 S32_MAX = S32(2147483647); static const U32 U32_MAX = U32(0xffffffff); +static const F32 F32_MIN_EX = F32(-3.40282347e+38); static const F32 F32_MAX = F32(3.402823466e+38F); static const F32 F32_MIN = F32(1.175494351e-38F); From 3b4a15d7aac58ea0e4924f8f3a3e0bcc328136b1 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 21 Feb 2024 10:14:29 +0000 Subject: [PATCH 12/29] Some test ies profiles IES profiles to my knowledge are not only free to download, but also free to distribute. you can get packs with thousands of these, i am uploading 3 test ones for now. --- .../iesprofiles/A23D-Pathway-&-Accent-Light.ies | 14 ++++++++++++++ .../data/Prototyping/iesprofiles/top-post.ies | 16 ++++++++++++++++ .../data/Prototyping/iesprofiles/x-arrow.ies | 13 +++++++++++++ 3 files changed, 43 insertions(+) create mode 100644 Templates/BaseGame/game/data/Prototyping/iesprofiles/A23D-Pathway-&-Accent-Light.ies create mode 100644 Templates/BaseGame/game/data/Prototyping/iesprofiles/top-post.ies create mode 100644 Templates/BaseGame/game/data/Prototyping/iesprofiles/x-arrow.ies diff --git a/Templates/BaseGame/game/data/Prototyping/iesprofiles/A23D-Pathway-&-Accent-Light.ies b/Templates/BaseGame/game/data/Prototyping/iesprofiles/A23D-Pathway-&-Accent-Light.ies new file mode 100644 index 000000000..84f40fa7d --- /dev/null +++ b/Templates/BaseGame/game/data/Prototyping/iesprofiles/A23D-Pathway-&-Accent-Light.ies @@ -0,0 +1,14 @@ +IESNA91 +[MANUFAC] A23D - The largest 3D asset library +[_INFOLINK] www.a23d.co +[COPYRIGHT] A23D, a brand of A2 Virtual Reality. Usage of this file is restricted as per the EULA (www.a23d.co/legal) +TILT=NONE +1 6300 1 29 1 1 1 -0.67 0 0 +1 1 94 +0 5 10 15 20 25 30 35 40 42.5 +45 47.5 50 52.5 55 57.5 60 62.5 65 67.5 +70 72.5 75 77.5 80 82.5 85 87.5 90 +0 +0 3 13 26 56 68 60 175 323 430 +535 622 696 783 884 1000 1104 1218 1262 1243 +1171 981 714 481 288 173 111 79 64 diff --git a/Templates/BaseGame/game/data/Prototyping/iesprofiles/top-post.ies b/Templates/BaseGame/game/data/Prototyping/iesprofiles/top-post.ies new file mode 100644 index 000000000..6d4486ad9 --- /dev/null +++ b/Templates/BaseGame/game/data/Prototyping/iesprofiles/top-post.ies @@ -0,0 +1,16 @@ +IESNA:LM-63-2002 +[TEST]BALLABS TEST NO. 14501.0 +[TESTLAB] BUILDING ACOUSTICS & LIGHTING LABORATORIES, INC +[ISSUEDATE] 04-MAR-2009 +[MANUFAC] LeoMoon Studios +[LUMINAIRE] 1/100W CLEAR ED17PS MH HORIZ LAMP LS SERIES POST LUMINAIRE +[MORE] WHITE TOP REFLECTOR w/FROSTED GLASS CHIMNEY +[MORE] CLEAR ACRYLIC PANELS +[LUMCAT] HLSC15-100PSMH120-BLK +[LAMPCAT] M90 +TILT=NONE +1 9000 1 35 1 1 1 0.885 0.885 0.781 +1 1 100 +0 5 10 15 20 25 30 35 40 45 50 55 60 62.5 65 67.5 70 72.5 75 77.5 80 82.5 85 87.5 90 95 105 115 125 135 145 155 165 175 180 +0 +67.00 113.00 238.00 460.00 973.00 1277.00 1388.00 1425.00 1408.00 1338.00 1199.00 1018.00 700.00 430.00 320.00 335.00 227.00 209.00 154.00 137.00 125.00 109.00 91.00 65.00 46.00 38.00 25.00 18.00 10.00 5.00 3.00 3.00 0.00 0.00 0.00 diff --git a/Templates/BaseGame/game/data/Prototyping/iesprofiles/x-arrow.ies b/Templates/BaseGame/game/data/Prototyping/iesprofiles/x-arrow.ies new file mode 100644 index 000000000..21dadcb8a --- /dev/null +++ b/Templates/BaseGame/game/data/Prototyping/iesprofiles/x-arrow.ies @@ -0,0 +1,13 @@ +IESNA:LM-63-1995 +[TEST] BE1680 +[DATE] 12-FEB-96 +[MANUFAC] LeoMoon Studios +[LUMCAT] 6340 +[LUMINAIRE] SURFACE MOUNTED WALL LUMINAIRE +[LAMP] (1) 100W A-19 INC +TILT=NONE + 1 1750 1.75 73 1 1 2 -.1 0 .05 + 1 1 100 + 0 2.5 5 7.5 10 12.5 15 17.5 20 22.5 25 27.5 30 32.5 35 37.5 40 42.5 45 47.5 50 52.5 55 57.5 60 62.5 65 67.5 70 72.5 75 77.5 80 82.5 85 87.5 90 92.5 95 97.5 100 102.5 105 107.5 110 112.5 115 117.5 120 122.5 125 127.5 130 132.5 135 137.5 140 142.5 145 147.5 150 152.5 155 157.5 160 162.5 165 167.5 170 172.5 175 177.5 180 + 0 + 167.3 168.9 173 179.9 179.2 151.2 119.4 95.63 81.03 71.95 66.46 62.67 60.25 57.67 52.18 46.62 48.91 63.15 83.15 95.41 97.4 87.75 62.6 43.08 39.26 47.36 52.89 45.74 31.45 18.17 10.5 7.888 8.112 7.592 3.665 .6467 .498 .4252 .3735 .3185 .2765 .2279 .2199 .2021 .1746 .1407 .1358 .1277 .1326 .1342 .1406 .1374 .1358 .1375 .1488 .1488 .1536 .1925 .2183 .2328 .2345 .249 .2765 .3023 .3266 .3476 .3557 .3638 .3541 .3573 .3638 .3719 .3816 From 973d2792ed5145c7fd8653e92065a3d48661fd53 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 21 Feb 2024 10:15:44 +0000 Subject: [PATCH 13/29] Delete A23D-Pathway-&-Accent-Light.ies --- .../iesprofiles/A23D-Pathway-&-Accent-Light.ies | 14 -------------- 1 file changed, 14 deletions(-) delete mode 100644 Templates/BaseGame/game/data/Prototyping/iesprofiles/A23D-Pathway-&-Accent-Light.ies diff --git a/Templates/BaseGame/game/data/Prototyping/iesprofiles/A23D-Pathway-&-Accent-Light.ies b/Templates/BaseGame/game/data/Prototyping/iesprofiles/A23D-Pathway-&-Accent-Light.ies deleted file mode 100644 index 84f40fa7d..000000000 --- a/Templates/BaseGame/game/data/Prototyping/iesprofiles/A23D-Pathway-&-Accent-Light.ies +++ /dev/null @@ -1,14 +0,0 @@ -IESNA91 -[MANUFAC] A23D - The largest 3D asset library -[_INFOLINK] www.a23d.co -[COPYRIGHT] A23D, a brand of A2 Virtual Reality. Usage of this file is restricted as per the EULA (www.a23d.co/legal) -TILT=NONE -1 6300 1 29 1 1 1 -0.67 0 0 -1 1 94 -0 5 10 15 20 25 30 35 40 42.5 -45 47.5 50 52.5 55 57.5 60 62.5 65 67.5 -70 72.5 75 77.5 80 82.5 85 87.5 90 -0 -0 3 13 26 56 68 60 175 323 430 -535 622 696 783 884 1000 1104 1218 1262 1243 -1171 981 714 481 288 173 111 79 64 From 7fb14e17b5de0c19e8bee896b5ac1c53851ecc04 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 21 Feb 2024 10:16:07 +0000 Subject: [PATCH 14/29] Create jelly-fish.ies --- .../Prototyping/iesprofiles/jelly-fish.ies | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 Templates/BaseGame/game/data/Prototyping/iesprofiles/jelly-fish.ies diff --git a/Templates/BaseGame/game/data/Prototyping/iesprofiles/jelly-fish.ies b/Templates/BaseGame/game/data/Prototyping/iesprofiles/jelly-fish.ies new file mode 100644 index 000000000..77c4673c7 --- /dev/null +++ b/Templates/BaseGame/game/data/Prototyping/iesprofiles/jelly-fish.ies @@ -0,0 +1,80 @@ +IESNA:LM-63-1995 +[TEST]BALLABS TEST NO. 12788.0 +[MANUFAC] LeoMoon Studios +[LUMINAIRE] 1/100W ICETRON INDUCTION 20x15"DIRECT AREALIGHT LUMINAIRE +[LUMINAIRE] MIRO4 SPEC ALUM TYPE II OPTICS & CLEAR FLAT GLASS LENS +[LUMINAIRE] BLACK PANEL STREET SIDE SYLVANIA # QT 1x150 ICE/UNV-T +[LUMCAT] ICEAL2-150S-TYPE2/CG1-277 +[LAMPCAT] ICE100/QT150 2PIN +TILT=NONE + 1 11000. 1.000000 25 21 1 1 .938 1.266 .000 + 1.0000 1.0000 140.0000 + .0 5.0 10.0 15.0 20.0 25.0 30.0 35.0 40.0 45.0 + 50.0 55.0 60.0 62.5 65.0 67.5 70.0 72.5 75.0 77.5 + 80.0 82.5 85.0 87.5 90.0 + .0 5.0 15.0 25.0 35.0 45.0 55.0 65.0 75.0 85.0 + 90.0 95.0 105.0 115.0 125.0 135.0 145.0 155.0 165.0 175.0 + 180.0 + 1789. 1841. 1911. 1979. 2023. 2025. 1994. 1867. 1718. 1551. + 1374. 1208. 990. 808. 637. 469. 347. 202. 89. 18. + 9. 7. 7. 6. 0. + 1789. 1831. 1908. 1969. 2013. 2018. 1983. 1865. 1701. 1548. + 1353. 1193. 981. 842. 661. 503. 352. 172. 68. 19. + 8. 6. 6. 5. 0. + 1789. 1828. 1891. 1939. 1958. 1939. 1908. 1808. 1668. 1559. + 1428. 1300. 1222. 1161. 999. 778. 580. 318. 129. 39. + 10. 7. 7. 4. 0. + 1789. 1818. 1865. 1891. 1942. 1959. 1927. 1843. 1761. 1714. + 1673. 1599. 1445. 1325. 1165. 948. 668. 400. 186. 75. + 30. 9. 7. 2. 0. + 1789. 1811. 1821. 1891. 1941. 1974. 1980. 1943. 1993. 2082. + 1963. 1808. 1621. 1601. 1424. 1166. 829. 487. 279. 152. + 65. 15. 8. 2. 0. + 1789. 1794. 1804. 1893. 1935. 1995. 2020. 2145. 2342. 2221. + 2063. 2135. 2157. 1694. 948. 340. 101. 8. 0. 185. + 94. 32. 9. 0. 0. + 1789. 1775. 1803. 1868. 1931. 1992. 2076. 2357. 2333. 2285. + 2254. 2608. 2375. 2010. 1722. 1448. 981. 661. 376. 244. + 122. 38. 8. 0. 0. + 1789. 1763. 1798. 1839. 1918. 1961. 2151. 2291. 2310. 2263. + 2575. 2700. 2380. 2075. 1792. 1483. 1102. 702. 430. 298. + 192. 67. 11. 2. 0. + 1789. 1746. 1801. 1827. 1871. 1923. 2176. 2119. 2124. 2062. + 2553. 2596. 2201. 1907. 1678. 1368. 1015. 673. 440. 303. + 178. 63. 10. 1. 0. + 1789. 1738. 1788. 1808. 1830. 1895. 2081. 2024. 1953. 1883. + 2313. 2285. 1854. 1661. 1400. 1139. 833. 577. 404. 267. + 157. 54. 12. 1. 0. + 1789. 1735. 1783. 1797. 1812. 1868. 2046. 1983. 1911. 1805. + 2191. 2151. 1759. 1513. 1288. 1033. 802. 568. 386. 243. + 134. 56. 10. 3. 0. + 1789. 1734. 1778. 1786. 1797. 1838. 2016. 1951. 1871. 1766. + 2128. 2078. 1681. 1474. 1248. 1009. 739. 523. 349. 228. + 144. 52. 13. 2. 0. + 1789. 1733. 1774. 1773. 1771. 1777. 1959. 1895. 1811. 1647. + 2034. 1957. 1595. 1293. 1118. 925. 717. 481. 319. 208. + 125. 51. 7. 1. 0. + 1789. 1738. 1763. 1755. 1744. 1704. 1880. 1794. 1752. 1541. + 1772. 1720. 1427. 1191. 1003. 795. 588. 427. 274. 166. + 98. 39. 8. 3. 0. + 1789. 1734. 1744. 1732. 1708. 1647. 1674. 1703. 1620. 1413. + 1325. 1423. 1205. 983. 808. 642. 464. 312. 192. 107. + 57. 18. 8. 3. 0. + 1789. 1735. 1714. 1725. 1673. 1590. 1481. 1511. 1373. 1230. + 982. 993. 902. 771. 626. 456. 300. 187. 112. 60. + 31. 14. 8. 4. 0. + 1789. 1736. 1681. 1700. 1617. 1511. 1381. 1252. 1210. 1043. + 875. 657. 554. 487. 398. 294. 195. 122. 70. 40. + 19. 11. 8. 3. 0. + 1789. 1737. 1666. 1641. 1577. 1471. 1333. 1172. 1015. 890. + 728. 574. 409. 326. 243. 181. 114. 72. 40. 24. + 14. 9. 7. 4. 0. + 1789. 1740. 1679. 1601. 1493. 1388. 1268. 1114. 956. 769. + 624. 481. 347. 267. 201. 141. 85. 41. 25. 16. + 10. 7. 6. 3. 0. + 1789. 1737. 1693. 1616. 1479. 1340. 1187. 1041. 896. 724. + 572. 431. 303. 233. 167. 117. 62. 29. 18. 12. + 9. 6. 6. 4. 1. + 1789. 1742. 1698. 1623. 1491. 1354. 1196. 1040. 894. 722. + 565. 421. 302. 227. 159. 108. 57. 20. 14. 10. + 8. 6. 6. 5. 0. From 55882139968e65a984f49275ad40463c3926fb30 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 21 Feb 2024 16:28:40 +0000 Subject: [PATCH 15/29] Update LICENSE.md --- LICENSE.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/LICENSE.md b/LICENSE.md index 7eaddb5df..ebad1dc16 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -19,3 +19,6 @@ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + + +IES Profile Generator tool: https://github.com/nickmcdonald/ies-generator From 2335a05fbed5b8c08d2bbced056edc46549bfc28 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Wed, 21 Feb 2024 16:32:29 +0000 Subject: [PATCH 16/29] Update LICENSE.md --- LICENSE.md | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/LICENSE.md b/LICENSE.md index ebad1dc16..15701a3e3 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -22,3 +22,40 @@ SOFTWARE. IES Profile Generator tool: https://github.com/nickmcdonald/ies-generator + +// +---------------------------------------------------------------------- +// | Project : ray. +// | All rights reserved. +// +---------------------------------------------------------------------- +// | Copyright (c) 2013-2017. +// +---------------------------------------------------------------------- +// | * Redistribution and use of this software in source and binary forms, +// | with or without modification, are permitted provided that the following +// | conditions are met: +// | +// | * Redistributions of source code must retain the above +// | copyright notice, this list of conditions and the +// | following disclaimer. +// | +// | * Redistributions in binary form must reproduce the above +// | copyright notice, this list of conditions and the +// | following disclaimer in the documentation and/or other +// | materials provided with the distribution. +// | +// | * Neither the name of the ray team, nor the names of its +// | contributors may be used to endorse or promote products +// | derived from this software without specific prior +// | written permission of the ray team. +// | +// | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +// | "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +// | LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +// | A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +// | OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +// | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +// | LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +// | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +// | THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +// +---------------------------------------------------------------------- From a4da6727edd4f385494bacc2b3867dd4c57ceed5 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Wed, 21 Feb 2024 12:24:38 -0600 Subject: [PATCH 17/29] fix non player class pathshape jitter everything has a consistent getRenderTransform() nowadays --- Engine/source/scene/sceneObject.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/Engine/source/scene/sceneObject.cpp b/Engine/source/scene/sceneObject.cpp index 52ffd545a..435da6a54 100644 --- a/Engine/source/scene/sceneObject.cpp +++ b/Engine/source/scene/sceneObject.cpp @@ -1729,11 +1729,7 @@ void SceneObject::updateRenderChangesByParent(){ //add the "offset" caused by the parents change, and add it to it's own // This is needed by objects that update their own render transform thru interpolate tick // Mostly for stationary objects. - - if (getClassName() == StringTable->insert("Player")) - mat.mul(offset,getRenderTransform()); - else - mat.mul(offset,getTransform()); + mat.mul(offset,getRenderTransform()); setRenderTransform(mat); } } From ad6880ec0dcb009b536f4f9666e51382da02aca3 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Wed, 21 Feb 2024 14:16:38 -0600 Subject: [PATCH 18/29] fizzle fix for gl correct ShaderFeatureGLSL::getInVpos to more closely match directx outcomes so we can keep using the same math across incudes --- .../shaderGen/GLSL/shaderFeatureGLSL.cpp | 76 ++++++++++--------- 1 file changed, 42 insertions(+), 34 deletions(-) diff --git a/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp b/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp index f6503768b..650b3c799 100644 --- a/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp +++ b/Engine/source/shaderGen/GLSL/shaderFeatureGLSL.cpp @@ -438,29 +438,18 @@ Var* ShaderFeatureGLSL::getInColor( const char *name, Var* ShaderFeatureGLSL::addOutVpos( MultiLine *meta, Vector &componentList ) { - /* - // Nothing to do if we're on SM 3.0... we use the real vpos. - if ( GFX->getPixelShaderVersion() >= 3.0f ) - return NULL; - */ - - // For SM 2.x we need to generate the vpos in the vertex shader - // and pass it as a texture coord to the pixel shader. - Var *outVpos = (Var*)LangElement::find( "outVpos" ); if ( !outVpos ) { - ShaderConnector *connectComp = dynamic_cast( componentList[C_CONNECTOR] ); - - outVpos = connectComp->getElement( RT_TEXCOORD ); - outVpos->setName( "outVpos" ); - outVpos->setStructName( "OUT" ); - outVpos->setType( "vec4" ); + ShaderConnector* connectComp = dynamic_cast(componentList[C_CONNECTOR]); + outVpos = connectComp->getElement(RT_TEXCOORD); + outVpos->setName("outVpos"); + outVpos->setStructName("OUT"); + outVpos->setType("vec4"); Var *outPosition = (Var*) LangElement::find( "gl_Position" ); - AssertFatal( outPosition, "ShaderFeatureGLSL::addOutVpos - Didn't find the output position." ); - - meta->addStatement( new GenOp( " @ = @;\r\n", outVpos, outPosition ) ); + AssertFatal( outPosition, "ShaderFeatureGLSL::addOutVpos - gl_Position somehow undefined?." ); + meta->addStatement(new GenOp(" @ = @;\r\n", outVpos, outPosition)); } return outVpos; @@ -469,15 +458,34 @@ Var* ShaderFeatureGLSL::addOutVpos( MultiLine *meta, Var* ShaderFeatureGLSL::getInVpos( MultiLine *meta, Vector &componentList ) { - Var *inVpos = (Var*)LangElement::find( "vpos" ); - if ( inVpos ) + Var* inVpos = (Var*)LangElement::find("inVpos"); + if (inVpos) return inVpos; - ShaderConnector *connectComp = dynamic_cast( componentList[C_CONNECTOR] ); - inVpos = connectComp->getElement( RT_TEXCOORD ); - inVpos->setName( "inVpos" ); - inVpos->setStructName( "IN" ); - inVpos->setType( "vec4" ); + ShaderConnector* connectComp = dynamic_cast(componentList[C_CONNECTOR]); + inVpos = connectComp->getElement(RT_TEXCOORD); + inVpos->setName("inVpos"); + inVpos->setStructName("IN"); + inVpos->setType("vec4"); + + Var* targetSize = (Var*)LangElement::find("targetSize"); + if (!targetSize) + { + targetSize = new Var(); + targetSize->setType("vec2"); + targetSize->setName("targetSize"); + targetSize->uniform = true; + targetSize->constSortPos = cspPotentialPrimitive; + } + + // transform projection space to screen space, needs to be done per-pixel. D3D automatically does this with SV_POSITION semantic types (note GLSL doesn't have semantics, even though Torque still uses the RT_ enums for them for some shaderconnector business) + // optional: OGL provides this data as gl_FragCoord automatically + // Note: for 100% parity with gl_FragCoord (but NOT with vpos in D3D) set .w = 1/.w + meta->addStatement(new GenOp(" @.xyz = @.xyz / @.w;\r\n", inVpos, inVpos, inVpos)); + meta->addStatement(new GenOp(" @.w = @.w;\r\n", inVpos, inVpos)); // for parity w/ gl_FragCoord set: meta->addStatement(new GenOp(" @.w = 1.0 / @.w;\r\n", inVpos, inVpos)); + meta->addStatement(new GenOp(" @.xy = @.xy * 0.5 + vec2(0.5,0.5);\r\n", inVpos, inVpos)); // get the screen coord to 0 to 1 + meta->addStatement(new GenOp(" @.y = 1.0 - @.y;\r\n", inVpos, inVpos)); // flip the y axis + meta->addStatement(new GenOp(" @.xy *= @;\r\n", inVpos, targetSize)); // scale to monitor return inVpos; } @@ -2429,15 +2437,15 @@ void VisibilityFeatGLSL::processPix( Vector &componentList, else { visibility = (Var*)LangElement::find( "visibility" ); - - if ( !visibility ) - { - visibility = new Var(); - visibility->setType( "float" ); - visibility->setName( "visibility" ); - visibility->uniform = true; - visibility->constSortPos = cspPotentialPrimitive; - } + + if (!visibility) + { + visibility = new Var(); + visibility->setType("float"); + visibility->setName("visibility"); + visibility->uniform = true; + visibility->constSortPos = cspPotentialPrimitive; + } } MultiLine* meta = new MultiLine; From 0b7fd2f0b3723293b98a363dc311d3ba869f0d29 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Thu, 22 Feb 2024 16:00:26 -0600 Subject: [PATCH 19/29] ies bugfixes --- .../core/lighting/scripts/advancedLighting_Shaders.tscript | 7 +++++-- .../shaders/lighting/advanced/gl/pointLightP.glsl | 1 + 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/Templates/BaseGame/game/core/lighting/scripts/advancedLighting_Shaders.tscript b/Templates/BaseGame/game/core/lighting/scripts/advancedLighting_Shaders.tscript index 104056efe..964e9e045 100644 --- a/Templates/BaseGame/game/core/lighting/scripts/advancedLighting_Shaders.tscript +++ b/Templates/BaseGame/game/core/lighting/scripts/advancedLighting_Shaders.tscript @@ -118,6 +118,7 @@ singleton GFXStateBlockData( AL_ConvexLightState ) samplerStates[3] = SamplerClampPoint; // colorBuffer samplerStates[4] = SamplerClampPoint; // matInfoBuffer samplerStates[5] = SamplerClampLinear; // Cookie Map + samplerStates[6] = SamplerClampLinear; // Cookie Map cullDefined = true; cullMode = GFXCullCW; @@ -142,6 +143,7 @@ singleton shaderData( AL_PointLightShader ) samplerNames[3] = "$colorBuffer"; samplerNames[4] = "$matInfoBuffer"; samplerNames[5] = "$cookieMap"; + samplerNames[6] = "$iesProfile"; pixVersion = 3.0; }; @@ -156,7 +158,7 @@ singleton CustomMaterial( AL_PointLightMaterial ) sampler["cookieMap"] = "$dynamiclightmask"; sampler["colorBuffer"] = "#color"; sampler["matInfoBuffer"] = "#matinfo"; - + sampler["iesProfile"] = "$photometricmask"; target = "AL_FormatToken"; pixVersion = 3.0; @@ -177,6 +179,7 @@ singleton shaderData( AL_SpotLightShader ) samplerNames[3] = "$colorBuffer"; samplerNames[4] = "$matInfoBuffer"; samplerNames[5] = "$cookieMap"; + samplerNames[6] = "$iesProfile"; pixVersion = 3.0; }; @@ -191,7 +194,7 @@ singleton CustomMaterial( AL_SpotLightMaterial ) sampler["cookieMap"] = "$dynamiclightmask"; sampler["colorBuffer"] = "#color"; sampler["matInfoBuffer"] = "#matinfo"; - + sampler["iesProfile"] = "$photometricmask"; target = "AL_FormatToken"; pixVersion = 3.0; diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/pointLightP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/pointLightP.glsl index 7e6984e21..01a547011 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/pointLightP.glsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/pointLightP.glsl @@ -120,6 +120,7 @@ uniform sampler2D iesProfile; uniform vec4 rtParams0; uniform vec3 lightPosition; +uniform vec3 lightDirection; uniform vec4 lightColor; uniform float lightBrightness; uniform float lightRange; From 14b6822e49f08d01405c6fb08c2f425ed0cd7e46 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Thu, 22 Feb 2024 17:53:53 -0600 Subject: [PATCH 20/29] a) use a 1d texture for this b) if we're going to optionally assign iesProfiles via shadowMacros.push_back, should specify the entries for the samplers too --- .../lighting/advanced/gl/pointLightP.glsl | 16 ++++++++++------ .../lighting/advanced/gl/spotLightP.glsl | 18 +++++++++++++----- .../shaders/lighting/advanced/pointLightP.hlsl | 17 +++++++++++------ .../shaders/lighting/advanced/spotLightP.hlsl | 17 ++++++++++++----- 4 files changed, 46 insertions(+), 22 deletions(-) diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/pointLightP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/pointLightP.glsl index 01a547011..b0b02d226 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/pointLightP.glsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/pointLightP.glsl @@ -108,6 +108,7 @@ uniform sampler2D deferredBuffer; #include "softShadow.glsl" uniform sampler2D colorBuffer; uniform sampler2D matInfoBuffer; + #ifdef SHADOW_CUBE /// The texture for cookie rendering. uniform samplerCube cookieMap; @@ -115,7 +116,9 @@ uniform samplerCube cookieMap; uniform sampler2D cookieMap; #endif -uniform sampler2D iesProfile; +#ifdef UES_PHOTOMETRIC_MASK +uniform sampler1D iesProfile; +#endif uniform vec4 rtParams0; @@ -231,17 +234,18 @@ void main() OUT_col = vec4(final, 0); return #endif - - //get punctual light contribution - lighting = getPunctualLight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, shadow); + #ifdef UES_PHOTOMETRIC_MASK // Lookup the cookie sample.d float cosTheta = dot(-surfaceToLight.L, lightDirection); float angle = acos(cosTheta) * ( M_1OVER_PI_F); - float iesMask = texture(iesProfile, vec2(angle, 0.0)).r; + float iesMask = texture(iesProfile,angle).r; // Multiply the light with the iesMask tex. - lighting *= iesMask; + shadow *= iesMask; #endif + + //get punctual light contribution + lighting = getPunctualLight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, shadow); } diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl index f5983eb0d..f96212c8d 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl @@ -38,8 +38,15 @@ uniform sampler2D shadowMap; #include "softShadow.glsl" uniform sampler2D colorBuffer; uniform sampler2D matInfoBuffer; + +#ifdef USE_COOKIE_TEX uniform sampler2D cookieMap; -uniform sampler2D iesProfile; +#endif + +#ifdef UES_PHOTOMETRIC_MASK +uniform sampler1D iesProfile; +#endif + uniform vec4 rtParams0; uniform float lightBrightness; @@ -154,16 +161,17 @@ void main() return; #endif - //get spot light contribution - lighting = getSpotlight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, lightDirection, lightSpotParams, shadow); #ifdef UES_PHOTOMETRIC_MASK // Lookup the cookie sample.d float cosTheta = dot(-surfaceToLight.L, lightDirection); float angle = acos(cosTheta) * ( M_1OVER_PI_F); - float iesMask = texture(iesProfile, vec2(angle, 0.0)).r; + float iesMask = texture(iesProfile, angle).r; // Multiply the light with the iesMask tex. - lighting *= iesMask; + shadow *= iesMask; #endif + + //get spot light contribution + lighting = getSpotlight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, lightDirection, lightSpotParams, shadow); } OUT_col = vec4(lighting, 0); diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl index de3d3433f..747f168a6 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl @@ -107,13 +107,17 @@ TORQUE_UNIFORM_SAMPLER2D(shadowMap, 1); #include "softShadow.hlsl" TORQUE_UNIFORM_SAMPLER2D(colorBuffer, 3); TORQUE_UNIFORM_SAMPLER2D(matInfoBuffer, 4); + /// The texture for cookie rendering. #ifdef SHADOW_CUBE TORQUE_UNIFORM_SAMPLERCUBE(cookieMap, 5); #else TORQUE_UNIFORM_SAMPLER2D(cookieMap, 5); #endif -TORQUE_UNIFORM_SAMPLER2D(iesProfile, 6); + +#ifdef UES_PHOTOMETRIC_MASK +TORQUE_UNIFORM_SAMPLER1D(iesProfile, 6); +#endif uniform float4 rtParams0; uniform float4 lightColor; @@ -223,17 +227,18 @@ float4 main( ConvexConnectP IN ) : SV_TARGET return final; #endif - //get punctual light contribution - lighting = getPunctualLight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, shadow); - #ifdef UES_PHOTOMETRIC_MASK // Lookup the cookie sample.d float cosTheta = dot(-surfaceToLight.L, lightDirection); float angle = acos(cosTheta) * ( M_1OVER_PI_F); - float iesMask = TORQUE_TEX2D(iesProfile, float2(angle, 0.0)).r; + float iesMask = TORQUE_TEX2D(iesProfile, angle).r; // Multiply the light with the iesMask tex. - lighting *= iesMask; + shadow *= iesMask; #endif + + //get punctual light contribution + lighting = getPunctualLight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, shadow); + } diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl index efd07fa30..dc47ea23d 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl @@ -43,8 +43,14 @@ TORQUE_UNIFORM_SAMPLER2D(shadowMap, 1); TORQUE_UNIFORM_SAMPLER2D(colorBuffer, 3); TORQUE_UNIFORM_SAMPLER2D(matInfoBuffer, 4); /// The texture for cookie rendering. + +#ifdef USE_COOKIE_TEX TORQUE_UNIFORM_SAMPLER2D(cookieMap, 5); -TORQUE_UNIFORM_SAMPLER2D(iesProfile, 6); +#endif + +#ifdef UES_PHOTOMETRIC_MASK +TORQUE_UNIFORM_SAMPLER1D(iesProfile, 6); +#endif uniform float4 rtParams0; @@ -153,16 +159,17 @@ float4 main( ConvexConnectP IN ) : SV_TARGET return final; #endif - //get spot light contribution - lighting = getSpotlight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, lightDirection, lightSpotParams, shadow); #ifdef UES_PHOTOMETRIC_MASK // Lookup the cookie sample.d float cosTheta = dot(-surfaceToLight.L, lightDirection); float angle = acos(cosTheta) * ( M_1OVER_PI_F); - float iesMask = TORQUE_TEX2D(iesProfile, float2(angle, 0.0)).r; + float iesMask = TORQUE_TEX1D(iesProfile, angle).r; // Multiply the light with the iesMask tex. - lighting *= iesMask; + shadow *= iesMask; #endif + + //get spot light contribution + lighting = getSpotlight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, lightDirection, lightSpotParams, shadow); } return float4(lighting, 0); From bbe9bc88711fd7dc4d594f622eb487eaaa8b9d48 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Thu, 22 Feb 2024 23:47:57 -0600 Subject: [PATCH 21/29] missed a 1d convert --- .../core/rendering/shaders/lighting/advanced/pointLightP.hlsl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl index 747f168a6..ab5145849 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/pointLightP.hlsl @@ -231,7 +231,7 @@ float4 main( ConvexConnectP IN ) : SV_TARGET // Lookup the cookie sample.d float cosTheta = dot(-surfaceToLight.L, lightDirection); float angle = acos(cosTheta) * ( M_1OVER_PI_F); - float iesMask = TORQUE_TEX2D(iesProfile, angle).r; + float iesMask = TORQUE_TEX1D(iesProfile, angle).r; // Multiply the light with the iesMask tex. shadow *= iesMask; #endif From c27b9bf48fbb480e9463f02668be7305f34c52dd Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Fri, 23 Feb 2024 01:28:15 -0600 Subject: [PATCH 22/29] allow spotlights specifically to comprress ies based on angle differentials --- .../core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl | 2 +- .../core/rendering/shaders/lighting/advanced/spotLightP.hlsl | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl index f96212c8d..0c423630e 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl @@ -165,7 +165,7 @@ void main() // Lookup the cookie sample.d float cosTheta = dot(-surfaceToLight.L, lightDirection); float angle = acos(cosTheta) * ( M_1OVER_PI_F); - float iesMask = texture(iesProfile, angle).r; + float iesMask = texture(iesProfile, angle/(lightSpotParams.x-lightSpotParams.y)).r; // Multiply the light with the iesMask tex. shadow *= iesMask; #endif diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl index dc47ea23d..c2d8d1e9e 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/spotLightP.hlsl @@ -163,7 +163,7 @@ float4 main( ConvexConnectP IN ) : SV_TARGET // Lookup the cookie sample.d float cosTheta = dot(-surfaceToLight.L, lightDirection); float angle = acos(cosTheta) * ( M_1OVER_PI_F); - float iesMask = TORQUE_TEX1D(iesProfile, angle).r; + float iesMask = TORQUE_TEX1D(iesProfile, angle/(lightSpotParams.x-lightSpotParams.y)).r; // Multiply the light with the iesMask tex. shadow *= iesMask; #endif From 4d1395dd57832ad87e230d6e9a92934ed7b732e4 Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Fri, 23 Feb 2024 11:23:07 -0600 Subject: [PATCH 23/29] from mar: fix the opengl cookie uv lookup --- .../shaders/lighting/advanced/gl/spotLightP.glsl | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl index 0c423630e..3585bfde2 100644 --- a/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl +++ b/Templates/BaseGame/game/core/rendering/shaders/lighting/advanced/gl/spotLightP.glsl @@ -19,7 +19,6 @@ // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS // IN THE SOFTWARE. //----------------------------------------------------------------------------- - #include "../../../gl/hlslCompat.glsl" #include "farFrustumQuad.glsl" #include "../../shadowMap/shadowMapIO_GLSL.h" @@ -116,7 +115,10 @@ void main() vec3 lightCol = lightColor.rgb; #ifdef USE_COOKIE_TEX // Lookup the cookie sample. - vec4 cookie = texture(cookieMap, shadowCoord); + vec4 pxlPosLightProj = tMul( worldToLightProj, vec4( surface.P, 1 ) ); + vec2 cookieCoord = ( ( pxlPosLightProj.xy / pxlPosLightProj.w ) * 0.5 ) + vec2( 0.5, 0.5 ); + cookieCoord.y = 1.0f - cookieCoord.y; + vec4 cookie = texture(cookieMap, cookieCoord); // Multiply the light with the cookie tex. lightCol *= cookie.rgb; // Use a maximum channel luminance to attenuate @@ -169,7 +171,7 @@ void main() // Multiply the light with the iesMask tex. shadow *= iesMask; #endif - + //get spot light contribution lighting = getSpotlight(surface, surfaceToLight, lightCol, lightBrightness, lightInvSqrRange, lightDirection, lightSpotParams, shadow); } From c7cc86b357e0a8602adeff91d12ba761159f1c4f Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Fri, 23 Feb 2024 11:52:43 -0600 Subject: [PATCH 24/29] clamp spot angle to 179, up custommaterial inputs to 16 add Material::PhotometricMask:handling to processedcustommaterial and for paranoias sake go ahead and be explicit about _getLightMaterial (those *should* be unneeded as they optionally default to that, but it's how they were in the beatup fork during testing) --- Engine/source/T3D/spotLight.cpp | 2 +- Engine/source/lighting/advanced/advancedLightBinManager.cpp | 4 ++-- Engine/source/materials/materialDefinition.h | 2 +- Engine/source/materials/processedCustomMaterial.cpp | 1 + 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/Engine/source/T3D/spotLight.cpp b/Engine/source/T3D/spotLight.cpp index 3f43305f7..6653a5365 100644 --- a/Engine/source/T3D/spotLight.cpp +++ b/Engine/source/T3D/spotLight.cpp @@ -132,7 +132,7 @@ void SpotLight::_conformLights() mLight->setDynamicRefreshFreq(mDynamicRefreshFreq); mLight->setPriority( mPriority ); - mOuterConeAngle = getMax( 0.01f, mOuterConeAngle ); + mOuterConeAngle = getMin(getMax( 0.01f, mOuterConeAngle ),179.0f); mInnerConeAngle = getMin( mInnerConeAngle, mOuterConeAngle ); mLight->setInnerConeAngle( mInnerConeAngle ); diff --git a/Engine/source/lighting/advanced/advancedLightBinManager.cpp b/Engine/source/lighting/advanced/advancedLightBinManager.cpp index 431ec28ad..24637de6c 100644 --- a/Engine/source/lighting/advanced/advancedLightBinManager.cpp +++ b/Engine/source/lighting/advanced/advancedLightBinManager.cpp @@ -399,9 +399,9 @@ void AdvancedLightBinManager::render( SceneRenderState *state ) sunLight->getCastShadows() && !disableShadows && sunLight->getExtended() ) - vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_PSSM ); + vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_PSSM,false,false ); else - vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_None ); + vectorMatInfo = _getLightMaterial( LightInfo::Vector, ShadowType_None, false, false); // Initialize and set the per-frame parameters after getting // the vector light material as we use lazy creation. diff --git a/Engine/source/materials/materialDefinition.h b/Engine/source/materials/materialDefinition.h index 504fecaa6..29996cf66 100644 --- a/Engine/source/materials/materialDefinition.h +++ b/Engine/source/materials/materialDefinition.h @@ -71,7 +71,7 @@ public: //----------------------------------------------------------------------- enum Constants { - MAX_TEX_PER_PASS = 8, ///< Number of textures per pass + MAX_TEX_PER_PASS = 16, ///< Number of textures per pass MAX_STAGES = 4, NUM_EFFECT_COLOR_STAGES = 2, ///< Number of effect color definitions for transitioning effects. }; diff --git a/Engine/source/materials/processedCustomMaterial.cpp b/Engine/source/materials/processedCustomMaterial.cpp index 15772c078..1610d7ec9 100644 --- a/Engine/source/materials/processedCustomMaterial.cpp +++ b/Engine/source/materials/processedCustomMaterial.cpp @@ -361,6 +361,7 @@ void ProcessedCustomMaterial::setTextureStages( SceneRenderState *state, const S break; case Material::Mask: + case Material::PhotometricMask: case Material::Standard: case Material::Bump: case Material::Detail: From 3ab716063f17a223ca6287bb5377a653950efade Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Fri, 23 Feb 2024 12:39:26 -0600 Subject: [PATCH 25/29] doc correction --- .../core/lighting/scripts/advancedLighting_Shaders.tscript | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Templates/BaseGame/game/core/lighting/scripts/advancedLighting_Shaders.tscript b/Templates/BaseGame/game/core/lighting/scripts/advancedLighting_Shaders.tscript index 964e9e045..1fcee6079 100644 --- a/Templates/BaseGame/game/core/lighting/scripts/advancedLighting_Shaders.tscript +++ b/Templates/BaseGame/game/core/lighting/scripts/advancedLighting_Shaders.tscript @@ -118,7 +118,7 @@ singleton GFXStateBlockData( AL_ConvexLightState ) samplerStates[3] = SamplerClampPoint; // colorBuffer samplerStates[4] = SamplerClampPoint; // matInfoBuffer samplerStates[5] = SamplerClampLinear; // Cookie Map - samplerStates[6] = SamplerClampLinear; // Cookie Map + samplerStates[6] = SamplerClampLinear; // iesProfile cullDefined = true; cullMode = GFXCullCW; @@ -191,10 +191,10 @@ singleton CustomMaterial( AL_SpotLightMaterial ) sampler["deferredBuffer"] = "#deferred"; sampler["shadowMap"] = "$dynamiclight"; + sampler["iesProfile"] = "$photometricmask"; sampler["cookieMap"] = "$dynamiclightmask"; sampler["colorBuffer"] = "#color"; sampler["matInfoBuffer"] = "#matinfo"; - sampler["iesProfile"] = "$photometricmask"; target = "AL_FormatToken"; pixVersion = 3.0; From 7d1927af99320f2ed0829f9c6382bb104305ba4d Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Wed, 28 Feb 2024 03:53:49 -0600 Subject: [PATCH 26/29] t3d subdirectory review add missing example directory preserve reservations for ecs directories in remmed form --- Engine/source/CMakeLists.txt | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Engine/source/CMakeLists.txt b/Engine/source/CMakeLists.txt index 78343a2e6..f1c243940 100644 --- a/Engine/source/CMakeLists.txt +++ b/Engine/source/CMakeLists.txt @@ -58,10 +58,12 @@ torqueAddSourceDirectories("platform" "platform/threads" "platform/async" torqueAddSourceDirectories("platform/nativeDialogs") # Handle T3D -torqueAddSourceDirectories("T3D/fps" "T3D/fx" "T3D/vehicles" "T3D/physics" - "T3D/decal" "T3D/sfx" "T3D/gameBase" "T3D/turret" - "T3D/lighting" "T3D/gameOBjects" "T3D/components" - "T3D/systems" "T3D/assets" "T3D" "T3D/gameBase/std") +torqueAddSourceDirectories( "T3D" "T3D/assets" "T3D/decal" "T3D/examples" "T3D/fps" "T3D/fx" + "T3D/gameBase" "T3D/gameBase/std" + "T3D/lighting" + "T3D/physics" +# "T3D/components" "T3D/sceneComponent" "T3D/systems" "T3D/gameOBjects" + "T3D/sfx" "T3D/turret" "T3D/vehicles") # Handle TS torqueAddSourceDirectories("ts" "ts/collada" "ts/assimp" "ts/loader" "ts/arch") From cd6656be354de8facfaac015053e800490c555ee Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Fri, 1 Mar 2024 10:06:18 +0000 Subject: [PATCH 27/29] Fix archive Incorrect cmake directory was messing up reading from zips STB was failing to read from zips, it was failing to get the file info, something we were using as an early out, now if that files on the filepath, we use the memory read instead since stream needs to be a success to get to that point. --- Engine/source/CMakeLists.txt | 2 +- Engine/source/gfx/bitmap/gBitmap.cpp | 11 ++++++++--- Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp | 8 +++++++- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Engine/source/CMakeLists.txt b/Engine/source/CMakeLists.txt index f1c243940..342338160 100644 --- a/Engine/source/CMakeLists.txt +++ b/Engine/source/CMakeLists.txt @@ -97,7 +97,7 @@ endif (WIN32 AND TORQUE_D3D11) # Handle core torqueAddSourceDirectories("core" "core/stream" "core/strings" "core/util" - "core/util/journal" "core/util/zip" "core/util/compressors") + "core/util/journal" "core/util/zip" "core/util/zip/compressors") # Handle GUI torqueAddSourceDirectories("gui" "gui/buttons" "gui/containers" "gui/controls" "gui/core" "gui/game" "gui/shiny" "gui/utility" "gui/3d") diff --git a/Engine/source/gfx/bitmap/gBitmap.cpp b/Engine/source/gfx/bitmap/gBitmap.cpp index 8fc0590b6..82c8b2c7f 100644 --- a/Engine/source/gfx/bitmap/gBitmap.cpp +++ b/Engine/source/gfx/bitmap/gBitmap.cpp @@ -1279,9 +1279,14 @@ template<> void *Resource::create(const Torque::Path &path) const String extension = path.getExtension(); if( !bmp->readBitmap( extension, path ) ) { - Con::errorf( "Resource::create - error reading '%s'", path.getFullPath().c_str() ); - delete bmp; - bmp = NULL; + // we can only get here if the stream was successful, so attempt to read the stream. + Con::warnf("Was unable to load as file, going to try the stream instead."); + if (!bmp->readBitmapStream(extension, stream, stream.getStreamSize())) + { + Con::errorf("Resource::create - error reading '%s'", path.getFullPath().c_str()); + delete bmp; + bmp = NULL; + } } return bmp; diff --git a/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp b/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp index a5a97917a..00ef53891 100644 --- a/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp +++ b/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp @@ -195,6 +195,12 @@ bool sReadSTB(const Torque::Path& path, GBitmap* bitmap) if (!stbi_info(path.getFullPath().c_str(), &x, &y, &channels)) { FrameAllocator::setWaterMark(prevWaterMark); + const char* stbErr = stbi_failure_reason(); + + if (!stbErr) + stbErr = "Unknown Error!"; + + Con::errorf("STB failed to get image info: %s", stbErr); return false; } @@ -326,7 +332,7 @@ bool sReadStreamSTB(Stream& stream, GBitmap* bitmap, U32 len) stbErr = "Unknown Error!"; Con::errorf("STB failed to get image info: %s", stbErr); - return false; + Con::warnf("Going to attempt to load stream anyway."); } S32 reqCom = comp; From 6355da5df63b05f780579cbb2ff46ae29d3dea79 Mon Sep 17 00:00:00 2001 From: marauder2k7 Date: Fri, 1 Mar 2024 15:01:47 +0000 Subject: [PATCH 28/29] various fixes STB probably shouldn't fail on failed info, just continue. Assimp only add sequences if there are any. Update kork chan asset. --- .../source/gfx/bitmap/loaders/bitmapSTB.cpp | 6 +-- Engine/source/ts/assimp/assimpShapeLoader.cpp | 54 ++++++++++--------- .../shapes/kork_chanShape.asset.taml | 6 --- .../Prototyping/shapes/kork_chanShape.tscript | 30 ++--------- .../shapes/kork_chanShape_shape.asset.taml | 5 ++ .../shapes/kork_chan_image.asset.taml | 3 +- .../shapes/kork_chan_mat.asset.taml | 7 ++- 7 files changed, 44 insertions(+), 67 deletions(-) delete mode 100644 Templates/BaseGame/game/data/Prototyping/shapes/kork_chanShape.asset.taml create mode 100644 Templates/BaseGame/game/data/Prototyping/shapes/kork_chanShape_shape.asset.taml diff --git a/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp b/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp index 00ef53891..6eb79895c 100644 --- a/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp +++ b/Engine/source/gfx/bitmap/loaders/bitmapSTB.cpp @@ -200,8 +200,7 @@ bool sReadSTB(const Torque::Path& path, GBitmap* bitmap) if (!stbErr) stbErr = "Unknown Error!"; - Con::errorf("STB failed to get image info: %s", stbErr); - return false; + Con::errorf("STB get file info: %s", stbErr); } // do this to map 2 channels to 4, 2 channel not supported by gbitmap yet.. @@ -331,8 +330,7 @@ bool sReadStreamSTB(Stream& stream, GBitmap* bitmap, U32 len) if (!stbErr) stbErr = "Unknown Error!"; - Con::errorf("STB failed to get image info: %s", stbErr); - Con::warnf("Going to attempt to load stream anyway."); + Con::errorf("STB get memory info: %s", stbErr); } S32 reqCom = comp; diff --git a/Engine/source/ts/assimp/assimpShapeLoader.cpp b/Engine/source/ts/assimp/assimpShapeLoader.cpp index 908e186f2..8478e4b78 100644 --- a/Engine/source/ts/assimp/assimpShapeLoader.cpp +++ b/Engine/source/ts/assimp/assimpShapeLoader.cpp @@ -261,38 +261,40 @@ void AssimpShapeLoader::processAnimations() Vector ambientChannels; F32 duration = 0.0f; - - for (U32 i = 0; i < mScene->mNumAnimations; ++i) + if (mScene->mNumAnimations > 0) { - aiAnimation* anim = mScene->mAnimations[i]; - for (U32 j = 0; j < anim->mNumChannels; j++) + for (U32 i = 0; i < mScene->mNumAnimations; ++i) { - aiNodeAnim* nodeAnim = anim->mChannels[j]; - // Determine the maximum keyframe time for this animation - F32 maxKeyTime = 0.0f; - for (U32 k = 0; k < nodeAnim->mNumPositionKeys; k++) { - maxKeyTime = getMax(maxKeyTime, (F32)nodeAnim->mPositionKeys[k].mTime); - } - for (U32 k = 0; k < nodeAnim->mNumRotationKeys; k++) { - maxKeyTime = getMax(maxKeyTime, (F32)nodeAnim->mRotationKeys[k].mTime); - } - for (U32 k = 0; k < nodeAnim->mNumScalingKeys; k++) { - maxKeyTime = getMax(maxKeyTime, (F32)nodeAnim->mScalingKeys[k].mTime); - } + aiAnimation* anim = mScene->mAnimations[i]; + for (U32 j = 0; j < anim->mNumChannels; j++) + { + aiNodeAnim* nodeAnim = anim->mChannels[j]; + // Determine the maximum keyframe time for this animation + F32 maxKeyTime = 0.0f; + for (U32 k = 0; k < nodeAnim->mNumPositionKeys; k++) { + maxKeyTime = getMax(maxKeyTime, (F32)nodeAnim->mPositionKeys[k].mTime); + } + for (U32 k = 0; k < nodeAnim->mNumRotationKeys; k++) { + maxKeyTime = getMax(maxKeyTime, (F32)nodeAnim->mRotationKeys[k].mTime); + } + for (U32 k = 0; k < nodeAnim->mNumScalingKeys; k++) { + maxKeyTime = getMax(maxKeyTime, (F32)nodeAnim->mScalingKeys[k].mTime); + } - ambientChannels.push_back(nodeAnim); + ambientChannels.push_back(nodeAnim); - duration = getMax(duration, maxKeyTime); + duration = getMax(duration, maxKeyTime); + } } + + ambientSeq->mNumChannels = ambientChannels.size(); + ambientSeq->mChannels = ambientChannels.address(); + ambientSeq->mDuration = duration; + ambientSeq->mTicksPerSecond = 24.0; + + AssimpAppSequence* defaultAssimpSeq = new AssimpAppSequence(ambientSeq); + appSequences.push_back(defaultAssimpSeq); } - - ambientSeq->mNumChannels = ambientChannels.size(); - ambientSeq->mChannels = ambientChannels.address(); - ambientSeq->mDuration = duration; - ambientSeq->mTicksPerSecond = 24.0; - - AssimpAppSequence* defaultAssimpSeq = new AssimpAppSequence(ambientSeq); - appSequences.push_back(defaultAssimpSeq); } void AssimpShapeLoader::computeBounds(Box3F& bounds) diff --git a/Templates/BaseGame/game/data/Prototyping/shapes/kork_chanShape.asset.taml b/Templates/BaseGame/game/data/Prototyping/shapes/kork_chanShape.asset.taml deleted file mode 100644 index 475aa7543..000000000 --- a/Templates/BaseGame/game/data/Prototyping/shapes/kork_chanShape.asset.taml +++ /dev/null @@ -1,6 +0,0 @@ - diff --git a/Templates/BaseGame/game/data/Prototyping/shapes/kork_chanShape.tscript b/Templates/BaseGame/game/data/Prototyping/shapes/kork_chanShape.tscript index b53ee1f48..4df275dee 100644 --- a/Templates/BaseGame/game/data/Prototyping/shapes/kork_chanShape.tscript +++ b/Templates/BaseGame/game/data/Prototyping/shapes/kork_chanShape.tscript @@ -1,28 +1,8 @@ -//--- OBJECT WRITE BEGIN --- -new TSShapeConstructor(kork_chanShape_fbx) { - baseShapeAsset = "Prototyping:kork_chanShape"; - upAxis = "DEFAULT"; - unit = "-1"; - LODType = "TrailingNumber"; + +singleton TSShapeConstructor(kork_chanShapefbx) +{ + baseShapeAsset = ":kork_chanShape_shape"; singleDetailSize = "0"; - IgnoreNodeScale = "0"; - AdjustCenter = "0"; - AdjustFloor = "0"; - forceUpdateMaterials = "0"; - convertLeftHanded = "0"; - calcTangentSpace = "0"; - genUVCoords = "0"; - transformUVCoords = "0"; - flipUVCoords = "1"; - findInstances = "0"; - limitBoneWeights = "0"; - JoinIdenticalVerts = "1"; - reverseWindingOrder = "1"; - invertNormals = "0"; - removeRedundantMats = "1"; - animTiming = "Seconds"; + neverImportMat = "DefaultMaterial ColorEffect*"; animFPS = "2"; - canSave = "1"; - canSaveDynamicFields = "1"; }; -//--- OBJECT WRITE END --- diff --git a/Templates/BaseGame/game/data/Prototyping/shapes/kork_chanShape_shape.asset.taml b/Templates/BaseGame/game/data/Prototyping/shapes/kork_chanShape_shape.asset.taml new file mode 100644 index 000000000..ec589dd35 --- /dev/null +++ b/Templates/BaseGame/game/data/Prototyping/shapes/kork_chanShape_shape.asset.taml @@ -0,0 +1,5 @@ + diff --git a/Templates/BaseGame/game/data/Prototyping/shapes/kork_chan_image.asset.taml b/Templates/BaseGame/game/data/Prototyping/shapes/kork_chan_image.asset.taml index db20da923..88c5b7a6f 100644 --- a/Templates/BaseGame/game/data/Prototyping/shapes/kork_chan_image.asset.taml +++ b/Templates/BaseGame/game/data/Prototyping/shapes/kork_chan_image.asset.taml @@ -1,4 +1,3 @@ + imageFile="@assetFile=kork_chan.png"/> diff --git a/Templates/BaseGame/game/data/Prototyping/shapes/kork_chan_mat.asset.taml b/Templates/BaseGame/game/data/Prototyping/shapes/kork_chan_mat.asset.taml index c6b7a02b1..39a276210 100644 --- a/Templates/BaseGame/game/data/Prototyping/shapes/kork_chan_mat.asset.taml +++ b/Templates/BaseGame/game/data/Prototyping/shapes/kork_chan_mat.asset.taml @@ -5,12 +5,11 @@ + doubleSided="true" + originalAssetName="kork_chan_mat"> + DiffuseMapAsset="Prototyping:kork_chan_image"/> From 24562e675885e30bc30dfc6deba54bb0ac1803ff Mon Sep 17 00:00:00 2001 From: AzaezelX Date: Sun, 3 Mar 2024 22:04:09 -0600 Subject: [PATCH 29/29] aug ArrayObject to have a uniquePair command like uniqueket and uniquevalue, removes duplicate entries, but only if *both* match also, use that for the populateAllFonts() cache generator --- Engine/source/console/arrayObject.cpp | 22 +++++++++++++++++++ Engine/source/console/arrayObject.h | 6 ++++- .../utility/scripts/helperFunctions.tscript | 2 +- 3 files changed, 28 insertions(+), 2 deletions(-) diff --git a/Engine/source/console/arrayObject.cpp b/Engine/source/console/arrayObject.cpp index cfd25d6cb..d5eaffe98 100644 --- a/Engine/source/console/arrayObject.cpp +++ b/Engine/source/console/arrayObject.cpp @@ -404,6 +404,22 @@ void ArrayObject::uniqueKey() //----------------------------------------------------------------------------- +void ArrayObject::uniquePair() +{ + for (S32 i = 0; i < mArray.size(); i++) + { + for (S32 j = i + 1; j < mArray.size(); j++) + { + if (isEqual(mArray[i].key, mArray[j].key) && isEqual(mArray[i].value, mArray[j].value)) + { + erase(j); + j--; + } + } + } +} +//----------------------------------------------------------------------------- + void ArrayObject::duplicate(ArrayObject* obj) { empty(); @@ -740,6 +756,12 @@ DefineEngineMethod( ArrayObject, uniqueKey, void, (),, object->uniqueKey(); } +DefineEngineMethod(ArrayObject, uniquePair, void, (), , + "Removes any elements that have duplicated key and value pairs (leaving the first instance)") +{ + object->uniquePair(); +} + DefineEngineMethod( ArrayObject, duplicate, bool, ( ArrayObject* target ),, "Alters array into an exact duplicate of the target array.\n" "@param target ArrayObject to duplicate\n" ) diff --git a/Engine/source/console/arrayObject.h b/Engine/source/console/arrayObject.h index 81531b6c2..cde4f92b6 100644 --- a/Engine/source/console/arrayObject.h +++ b/Engine/source/console/arrayObject.h @@ -158,6 +158,10 @@ public: /// (keeps the first instance only) void uniqueKey(); + /// Removes any duplicate keys from the array + /// (keeps the first instance only) + void uniquePair(); + /// Makes this array an exact duplicate of another array void duplicate( ArrayObject *obj ); @@ -229,4 +233,4 @@ public: static void initPersistFields(); }; -#endif // _ARRAYOBJECT_H_ \ No newline at end of file +#endif // _ARRAYOBJECT_H_ diff --git a/Templates/BaseGame/game/core/utility/scripts/helperFunctions.tscript b/Templates/BaseGame/game/core/utility/scripts/helperFunctions.tscript index 905100648..fc6e0d33c 100644 --- a/Templates/BaseGame/game/core/utility/scripts/helperFunctions.tscript +++ b/Templates/BaseGame/game/core/utility/scripts/helperFunctions.tscript @@ -650,7 +650,7 @@ function populateAllFonts() continue; %fontarray.push_back(%obj.fontType,%obj.fontSize); } - %fontarray.uniqueKey(); + %fontarray.uniquePair(); %fontarrayCount = %fontarray.count();