mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-03-05 13:30:34 +00:00
Merge remote-tracking branch 'upstream/development' into AssimpLoaader-Fix
This commit is contained in:
commit
1ccf4cff85
42 changed files with 1294 additions and 84 deletions
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -33,6 +33,8 @@
|
|||
#include "core/resourceManager.h"
|
||||
#include "scene/sceneManager.h"
|
||||
#include "scene/sceneRenderState.h"
|
||||
#include "renderInstance/renderProbeMgr.h"
|
||||
#include "T3D/lighting/skylight.h"
|
||||
|
||||
// GuiMaterialPreview
|
||||
GuiMaterialPreview::GuiMaterialPreview()
|
||||
|
|
@ -372,6 +374,9 @@ void GuiMaterialPreview::renderWorld(const RectI &updateRect)
|
|||
FogData savedFogData = gClientSceneGraph->getFogData();
|
||||
gClientSceneGraph->setFogData( FogData() ); // no fog in preview window
|
||||
|
||||
if (Skylight::smSkylightProbe.isValid())
|
||||
PROBEMGR->submitProbe(Skylight::smSkylightProbe->getProbeInfo());
|
||||
|
||||
RenderPassManager* renderPass = gClientSceneGraph->getDefaultRenderPass();
|
||||
SceneRenderState state
|
||||
(
|
||||
|
|
|
|||
|
|
@ -31,6 +31,8 @@
|
|||
#include "math/mathTypes.h"
|
||||
#include "gfx/gfxTransformSaver.h"
|
||||
#include "console/engineAPI.h"
|
||||
#include "renderInstance/renderProbeMgr.h"
|
||||
#include "T3D/lighting/skylight.h"
|
||||
|
||||
IMPLEMENT_CONOBJECT( GuiObjectView );
|
||||
|
||||
|
|
@ -541,6 +543,12 @@ void GuiObjectView::renderWorld( const RectI& updateRect )
|
|||
|
||||
// Render primary model.
|
||||
|
||||
if (Skylight::smSkylightProbe.isValid())
|
||||
PROBEMGR->submitProbe(Skylight::smSkylightProbe->getProbeInfo());
|
||||
|
||||
FogData savedFogData = gClientSceneGraph->getFogData();
|
||||
gClientSceneGraph->setFogData(FogData()); // no fog in preview window
|
||||
|
||||
if(mModelInstance)
|
||||
{
|
||||
if( mRunThread )
|
||||
|
|
@ -567,6 +575,7 @@ void GuiObjectView::renderWorld( const RectI& updateRect )
|
|||
|
||||
renderPass->renderPass( &state );
|
||||
|
||||
gClientSceneGraph->setFogData(savedFogData); // restore fog setting
|
||||
// Make sure to remove our fake sun.
|
||||
LIGHTMGR->unregisterAllLights();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -378,6 +378,7 @@ public:
|
|||
/// Invokes a cubemap bake action for this probe
|
||||
/// </summary>
|
||||
void bake();
|
||||
ProbeInfo* getProbeInfo() { return &mProbeInfo; }
|
||||
};
|
||||
|
||||
typedef ReflectionProbe::ProbeInfo::ProbeShapeType ReflectProbeType;
|
||||
|
|
|
|||
|
|
@ -59,6 +59,8 @@ extern bool gEditingMission;
|
|||
extern ColorI gCanvasClearColor;
|
||||
bool Skylight::smRenderSkylights = true;
|
||||
|
||||
SimObjectPtr<Skylight> Skylight::smSkylightProbe = nullptr;
|
||||
|
||||
IMPLEMENT_CO_NETOBJECT_V1(Skylight);
|
||||
|
||||
ConsoleDocClass(Skylight,
|
||||
|
|
@ -117,6 +119,8 @@ bool Skylight::onAdd()
|
|||
if (!Parent::onAdd())
|
||||
return false;
|
||||
|
||||
if (isClientObject())
|
||||
smSkylightProbe = this;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -108,6 +108,7 @@ public:
|
|||
void prepRenderImage(SceneRenderState *state);
|
||||
|
||||
void setPreviewMatParameters(SceneRenderState* renderState, BaseMatInstance* mat);
|
||||
static SimObjectPtr<Skylight> smSkylightProbe;
|
||||
};
|
||||
|
||||
#endif // _Skylight_H_
|
||||
|
|
|
|||
|
|
@ -65,6 +65,21 @@ struct CompoundKey3
|
|||
bool operator==(const CompoundKey3 & compound) const { return key1==compound.key1 && key2==compound.key2 && key3==compound.key3; }
|
||||
};
|
||||
|
||||
template<class A, class B, class C, class D>
|
||||
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<class A, class B, class C, class D>
|
||||
inline U32 hash(const CompoundKey4<A, B, C, D>& compound)
|
||||
{
|
||||
return hash(compound.key1) + hash(compound.key2) + hash(compound.key3) + hash(compound.key4);
|
||||
}
|
||||
U32 nextPrime(U32);
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
581
Engine/source/gfx/bitmap/loaders/ies/ies_loader.cpp
Normal file
581
Engine/source/gfx/bitmap/loaders/ies/ies_loader.cpp
Normal file
|
|
@ -0,0 +1,581 @@
|
|||
// +----------------------------------------------------------------------
|
||||
// | 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 <assert.h>
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
|
||||
#include "math/mMathFn.h"
|
||||
|
||||
IESFileInfo::IESFileInfo()
|
||||
: _cachedIntegral(F32_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 > F32_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 > F32_MAX)
|
||||
{
|
||||
info._error = "VAnglesNum is not valid";
|
||||
return false;
|
||||
}
|
||||
|
||||
this->getInt(dataPos, dataPos, info.anglesNumH);
|
||||
if (info.anglesNumH < 0 || info.anglesNumH > F32_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 = F32_MIN_EX;
|
||||
float minSoFarH = F32_MIN_EX;
|
||||
|
||||
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<float> 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 = mSqrt(lx * lx + ly * ly + lz * lz);
|
||||
lx /= length;
|
||||
ly /= length;
|
||||
lz /= length;
|
||||
|
||||
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)mFloor(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<float>& 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<float>& 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)mFloor(x);
|
||||
int iy = (int)mFloor(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());
|
||||
}
|
||||
116
Engine/source/gfx/bitmap/loaders/ies/ies_loader.h
Normal file
116
Engine/source/gfx/bitmap/loaders/ies/ies_loader.h
Normal file
|
|
@ -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 <vector>
|
||||
#include <string>
|
||||
|
||||
// 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<float> _anglesH;
|
||||
std::vector<float> _anglesV;
|
||||
std::vector<float> _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<float>& candalaValues) const;
|
||||
float computeFilterPos(float value, const std::vector<float>& 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
|
||||
|
|
@ -54,6 +54,7 @@ GuiInspector::GuiInspector()
|
|||
mForcedArrayIndex(-1)
|
||||
{
|
||||
mPadding = 1;
|
||||
mSearchText = StringTable->EmptyString();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -79,7 +80,8 @@ void GuiInspector::initPersistFields()
|
|||
"If false the custom fields Name, Id, and Source Class will not be shown." );
|
||||
|
||||
addField("forcedArrayIndex", TypeS32, Offset(mForcedArrayIndex, GuiInspector));
|
||||
|
||||
|
||||
addField("searchText", TypeString, Offset(mSearchText, GuiInspector), "A string that, if not blank, is used to filter shown fields");
|
||||
endGroup( "Inspector" );
|
||||
|
||||
Parent::initPersistFields();
|
||||
|
|
@ -829,6 +831,12 @@ void GuiInspector::setForcedArrayIndex(S32 arrayIndex)
|
|||
refresh();
|
||||
}
|
||||
|
||||
void GuiInspector::setSearchText(StringTableEntry searchText)
|
||||
{
|
||||
mSearchText = searchText;
|
||||
refresh();
|
||||
}
|
||||
|
||||
//=============================================================================
|
||||
// Console Methods.
|
||||
//=============================================================================
|
||||
|
|
@ -1000,3 +1008,10 @@ DefineEngineMethod(GuiInspector, setForcedArrayIndex, void, (S32 arrayIndex), (-
|
|||
{
|
||||
object->setForcedArrayIndex(arrayIndex);
|
||||
}
|
||||
|
||||
DefineEngineMethod(GuiInspector, setSearchText, void, (const char* searchText), (""),
|
||||
"Sets the searched text used to filter out displayed fields in the inspector."
|
||||
"@param searchText The text to be used as a filter for field names. Leave as blank to clear search")
|
||||
{
|
||||
object->setSearchText(searchText);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -171,6 +171,10 @@ public:
|
|||
|
||||
void setForcedArrayIndex(S32 arrayIndex);
|
||||
|
||||
StringTableEntry getSearchText() { return mSearchText; }
|
||||
|
||||
void setSearchText(StringTableEntry searchText);
|
||||
|
||||
protected:
|
||||
|
||||
typedef Vector< SimObjectPtr< SimObject > > TargetVector;
|
||||
|
|
@ -190,6 +194,8 @@ protected:
|
|||
String mGroupFilters;
|
||||
bool mShowCustomFields;
|
||||
S32 mForcedArrayIndex;
|
||||
|
||||
StringTableEntry mSearchText;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -37,6 +37,8 @@
|
|||
|
||||
#include "T3D/assets/ShapeAsset.h"
|
||||
#include "T3D/assets/ShapeAnimationAsset.h"
|
||||
#include "renderInstance/renderProbeMgr.h"
|
||||
#include "T3D/lighting/skylight.h"
|
||||
|
||||
#ifdef TORQUE_COLLADA
|
||||
#include "collision/optimizedPolyList.h"
|
||||
|
|
@ -1409,6 +1411,8 @@ void GuiShapeEdPreview::renderWorld(const RectI &updateRect)
|
|||
FogData savedFogData = gClientSceneGraph->getFogData();
|
||||
gClientSceneGraph->setFogData( FogData() ); // no fog in preview window
|
||||
|
||||
if (Skylight::smSkylightProbe.isValid())
|
||||
PROBEMGR->submitProbe(Skylight::smSkylightProbe->getProbeInfo());
|
||||
SceneRenderState state
|
||||
(
|
||||
gClientSceneGraph,
|
||||
|
|
|
|||
|
|
@ -175,6 +175,9 @@ GuiControl* GuiInspectorDatablockField::constructEditControl()
|
|||
|
||||
//Add add button
|
||||
mAddButton = new GuiBitmapButtonCtrl();
|
||||
if(mDesiredClass == NULL)
|
||||
return retCtrl;
|
||||
|
||||
dSprintf(szBuffer, sizeof(szBuffer), "DatablockEditorPlugin.createNewDatablockOfType(%s, %d.getText());", mDesiredClass->getClassName(), retCtrl->getId());
|
||||
mAddButton->setField("Command", szBuffer);
|
||||
|
||||
|
|
|
|||
|
|
@ -123,6 +123,12 @@ bool GuiInspectorDynamicGroup::inspectGroup()
|
|||
SimFieldDictionary * fieldDictionary = target->getFieldDictionary();
|
||||
for(SimFieldDictionaryIterator ditr(fieldDictionary); *ditr; ++ditr)
|
||||
{
|
||||
String searchText = mParent->getSearchText();
|
||||
if (searchText != String::EmptyString) {
|
||||
if (String((*ditr)->slotName).find(searchText, 0, String::NoCase | String::Left) == String::NPos)
|
||||
continue;
|
||||
}
|
||||
|
||||
if( i == 0 )
|
||||
{
|
||||
flist.increment();
|
||||
|
|
|
|||
|
|
@ -288,6 +288,12 @@ bool GuiInspectorGroup::inspectGroup()
|
|||
if (field->flag.test(AbstractClassRep::FIELD_HideInInspectors))
|
||||
continue;
|
||||
|
||||
String searchText = mParent->getSearchText();
|
||||
if (searchText != String::EmptyString) {
|
||||
if (String(field->pFieldname).find(searchText, 0, String::NoCase | String::Left) == String::NPos)
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((bGrabItems == true || (bNoGroup == true && bGrabItems == false)) && itr->type != AbstractClassRep::DeprecatedFieldType)
|
||||
{
|
||||
if (bNoGroup == true && bGrabItems == true)
|
||||
|
|
|
|||
|
|
@ -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<ShadowMapParams>() )
|
||||
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" ) );
|
||||
|
|
@ -830,6 +834,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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -233,14 +233,14 @@ protected:
|
|||
|
||||
static const GFXVertexFormat* smLightMatVertex[LightInfo::Count];
|
||||
|
||||
typedef CompoundKey3<LightInfo::Type,ShadowType,bool> LightMatKey;
|
||||
typedef CompoundKey4<LightInfo::Type,ShadowType,bool, bool> LightMatKey;
|
||||
|
||||
typedef HashTable<LightMatKey,LightMaterialInfo*> 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();
|
||||
|
|
|
|||
|
|
@ -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<ShadowMapParams>();
|
||||
GFX->setTexture(reg, p->getIesProfileTex());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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<ShadowMapParams>();
|
||||
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 );
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
||||
/// @}
|
||||
|
||||
|
|
|
|||
|
|
@ -94,6 +94,7 @@ public:
|
|||
Misc,
|
||||
DynamicLight,
|
||||
DynamicLightMask,
|
||||
PhotometricMask,
|
||||
NormalizeCube,
|
||||
TexTarget,
|
||||
AccuMap,
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue