summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--indra/llimage/llimage.cpp53
-rw-r--r--indra/llimage/llimage.h6
-rw-r--r--indra/newview/llfetchedgltfmaterial.cpp5
-rw-r--r--indra/newview/llfetchedgltfmaterial.h9
-rw-r--r--indra/newview/llgltfmateriallist.cpp4
-rw-r--r--indra/newview/llsurfacepatch.cpp2
-rw-r--r--indra/newview/llvlcomposition.cpp125
-rw-r--r--indra/newview/llvlcomposition.h2
8 files changed, 179 insertions, 27 deletions
diff --git a/indra/llimage/llimage.cpp b/indra/llimage/llimage.cpp
index a96b6601bd..acfc254b65 100644
--- a/indra/llimage/llimage.cpp
+++ b/indra/llimage/llimage.cpp
@@ -31,6 +31,7 @@
#include "llmath.h"
#include "v4coloru.h"
+#include "v3color.h"
#include "llimagebmp.h"
#include "llimagetga.h"
@@ -1026,6 +1027,34 @@ bool LLImageRaw::optimizeAwayAlpha()
return false;
}
+bool LLImageRaw::makeAlpha()
+{
+ if (getComponents() == 3)
+ {
+ U8* data = getData();
+ U32 pixels = getWidth() * getHeight();
+
+ // alpha channel doesn't exist, make a new copy of data with alpha channel
+ U8* new_data = (U8*) ll_aligned_malloc_16(getWidth() * getHeight() * 4);
+
+ for (U32 i = 0; i < pixels; ++i)
+ {
+ U32 di = i * 4;
+ U32 si = i * 3;
+ for (U32 j = 0; j < 3; ++j)
+ {
+ new_data[di+j] = data[si+j];
+ }
+ }
+
+ setDataAndSize(new_data, getWidth(), getHeight(), 3);
+
+ return true;
+ }
+
+ return false;
+}
+
void LLImageRaw::expandToPowerOfTwo(S32 max_dim, bool scale_image)
{
// Find new sizes
@@ -1268,6 +1297,30 @@ void LLImageRaw::fill( const LLColor4U& color )
}
}
+void LLImageRaw::tint( const LLColor3& color )
+{
+ llassert( (3 == getComponents()) || (4 == getComponents()) );
+ if (isBufferInvalid())
+ {
+ LL_WARNS() << "Invalid image buffer" << LL_ENDL;
+ return;
+ }
+
+ S32 pixels = getWidth() * getHeight();
+ const S32 components = getComponents();
+ U8* data = getData();
+ for( S32 i = 0; i < pixels; i++ )
+ {
+ const float c0 = data[0] * color.mV[0];
+ const float c1 = data[1] * color.mV[1];
+ const float c2 = data[2] * color.mV[2];
+ data[0] = llclamp((U8)c0, 0, 255);
+ data[1] = llclamp((U8)c1, 0, 255);
+ data[2] = llclamp((U8)c2, 0, 255);
+ data += components;
+ }
+}
+
LLPointer<LLImageRaw> LLImageRaw::duplicate()
{
if(getNumRefs() < 2)
diff --git a/indra/llimage/llimage.h b/indra/llimage/llimage.h
index 8f9e1b3c54..77b5f0b7bc 100644
--- a/indra/llimage/llimage.h
+++ b/indra/llimage/llimage.h
@@ -71,6 +71,7 @@ const S32 HTTP_PACKET_SIZE = 1496;
class LLImageFormatted;
class LLImageRaw;
class LLColor4U;
+class LLColor3;
typedef enum e_image_codec
{
@@ -212,6 +213,8 @@ public:
// if the alpha channel is all 100% opaque, delete it
// returns true if alpha channel was deleted
bool optimizeAwayAlpha();
+ // Create an alpha channel if this image doesn't have one
+ bool makeAlpha();
static S32 biasedDimToPowerOfTwo(S32 curr_dim, S32 max_dim = MAX_IMAGE_SIZE);
static S32 expandDimToPowerOfTwo(S32 curr_dim, S32 max_dim = MAX_IMAGE_SIZE);
@@ -225,6 +228,9 @@ public:
// Fill the buffer with a constant color
void fill( const LLColor4U& color );
+ // Multiply this raw image by the given color
+ void tint( const LLColor3& color );
+
// Copy operations
//duplicate this raw image if refCount > 1.
diff --git a/indra/newview/llfetchedgltfmaterial.cpp b/indra/newview/llfetchedgltfmaterial.cpp
index 1fb3577dd7..c870d4778c 100644
--- a/indra/newview/llfetchedgltfmaterial.cpp
+++ b/indra/newview/llfetchedgltfmaterial.cpp
@@ -35,8 +35,6 @@
LLFetchedGLTFMaterial::LLFetchedGLTFMaterial()
: LLGLTFMaterial()
, mExpectedFlusTime(0.f)
- , mActive(true)
- , mFetching(false)
{
}
@@ -163,10 +161,11 @@ void LLFetchedGLTFMaterial::onMaterialComplete(std::function<void()> material_co
materialCompleteCallbacks.push_back(material_complete);
}
-void LLFetchedGLTFMaterial::materialComplete()
+void LLFetchedGLTFMaterial::materialComplete(bool success)
{
llassert(mFetching);
mFetching = false;
+ mFetchSuccess = success;
for (std::function<void()> material_complete : materialCompleteCallbacks)
{
diff --git a/indra/newview/llfetchedgltfmaterial.h b/indra/newview/llfetchedgltfmaterial.h
index ce4d33a213..c5f6f6ca94 100644
--- a/indra/newview/llfetchedgltfmaterial.h
+++ b/indra/newview/llfetchedgltfmaterial.h
@@ -49,7 +49,7 @@ public:
void bind(LLViewerTexture* media_tex = nullptr);
bool isFetching() const { return mFetching; }
- bool isLoaded() const { return !mFetching; }
+ bool isLoaded() const { return !mFetching && mFetchSuccess; }
// Textures used for fetching/rendering
LLPointer<LLViewerFetchedTexture> mBaseColorTexture;
@@ -61,11 +61,12 @@ protected:
// Lifetime management
void materialBegin();
- void materialComplete();
+ void materialComplete(bool success);
F64 mExpectedFlusTime; // since epoch in seconds
- bool mActive;
- bool mFetching;
+ bool mActive = true;
+ bool mFetching = false;
+ bool mFetchSuccess = false;
std::vector<std::function<void()>> materialCompleteCallbacks;
};
diff --git a/indra/newview/llgltfmateriallist.cpp b/indra/newview/llgltfmateriallist.cpp
index 99a052f719..7994515b61 100644
--- a/indra/newview/llgltfmateriallist.cpp
+++ b/indra/newview/llgltfmateriallist.cpp
@@ -549,7 +549,7 @@ void LLGLTFMaterialList::onAssetLoadComplete(const LLUUID& id, LLAssetType::ETyp
if (status != LL_ERR_NOERR)
{
LL_WARNS("GLTF") << "Error getting material asset data: " << LLAssetStorage::getErrorString(status) << " (" << status << ")" << LL_ENDL;
- asset_data->mMaterial->materialComplete();
+ asset_data->mMaterial->materialComplete(false);
delete asset_data;
}
else
@@ -634,7 +634,7 @@ void LLGLTFMaterialList::onAssetLoadComplete(const LLUUID& id, LLAssetType::ETyp
LL_DEBUGS("GLTF") << "Failed to get material " << id << LL_ENDL;
}
- asset_data->mMaterial->materialComplete();
+ asset_data->mMaterial->materialComplete(true);
delete asset_data;
});
diff --git a/indra/newview/llsurfacepatch.cpp b/indra/newview/llsurfacepatch.cpp
index b4daf71ce2..a6370e9ec2 100644
--- a/indra/newview/llsurfacepatch.cpp
+++ b/indra/newview/llsurfacepatch.cpp
@@ -741,7 +741,7 @@ void LLSurfacePatch::updateGL()
updateCompositionStats();
F32 tex_patch_size = meters_per_grid*grids_per_patch_edge;
- if (comp->generateTexture((F32)origin_region[VX], (F32)origin_region[VY],
+ if (comp->generateMinimapTileLand((F32)origin_region[VX], (F32)origin_region[VY],
tex_patch_size, tex_patch_size))
{
mSTexUpdate = FALSE;
diff --git a/indra/newview/llvlcomposition.cpp b/indra/newview/llvlcomposition.cpp
index fa19bcae87..f645023217 100644
--- a/indra/newview/llvlcomposition.cpp
+++ b/indra/newview/llvlcomposition.cpp
@@ -129,26 +129,28 @@ LLTerrainMaterials::Type LLTerrainMaterials::getMaterialType()
BOOL LLTerrainMaterials::texturesReady(BOOL boost)
{
+ BOOL ready = TRUE;
for (S32 i = 0; i < ASSET_COUNT; i++)
{
if (!textureReady(mDetailTextures[i], boost))
{
- return FALSE;
+ ready = FALSE;
}
}
- return TRUE;
+ return ready;
}
BOOL LLTerrainMaterials::materialsReady(BOOL boost)
{
+ BOOL ready = TRUE;
for (S32 i = 0; i < ASSET_COUNT; i++)
{
if (!materialReady(mDetailMaterials[i], mMaterialTexturesSet[i], boost))
{
- return FALSE;
+ ready = FALSE;
}
}
- return TRUE;
+ return ready;
}
// Boost the texture loading priority
@@ -188,6 +190,10 @@ BOOL LLTerrainMaterials::textureReady(LLPointer<LLViewerFetchedTexture>& tex, BO
}
return FALSE;
}
+ if (tex->getComponents() == 0)
+ {
+ return FALSE;
+ }
return TRUE;
}
@@ -381,8 +387,7 @@ BOOL LLVLComposition::generateComposition()
return LLTerrainMaterials::generateMaterials();
}
-// *TODO: Re-evaluate usefulness of this function in the PBR case. There is currently a hack here to treat the material base color like a legacy terrain texture, but I'm not sure if that's useful.
-BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
+BOOL LLVLComposition::generateMinimapTileLand(const F32 x, const F32 y,
const F32 width, const F32 height)
{
LL_PROFILE_ZONE_SCOPED
@@ -390,8 +395,6 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
llassert(x >= 0.f);
llassert(y >= 0.f);
- LLTimer gen_timer;
-
///////////////////////////
//
// Generate raw data arrays for surface textures
@@ -403,6 +406,17 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
S32 st_data_size[ASSET_COUNT]; // for debugging
const bool use_textures = getMaterialType() != LLTerrainMaterials::Type::PBR;
+ // *TODO: Remove this as it is reduandant computation (first and foremost
+ // because getMaterialType() does something similar, but also... shouldn't
+ // the textures/materials already be loaded by now?)
+ if (use_textures)
+ {
+ if (!texturesReady()) { return FALSE; }
+ }
+ else
+ {
+ if (!materialsReady()) { return FALSE; }
+ }
for (S32 i = 0; i < ASSET_COUNT; i++)
{
@@ -410,16 +424,37 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
{
// Read back a raw image for this discard level, if it exists
LLViewerFetchedTexture* tex;
+ LLViewerFetchedTexture* tex_emissive; // Can be null
+ bool has_base_color_factor;
+ bool has_emissive_factor;
+ LLColor3 base_color_factor;
+ LLColor3 emissive_factor;
if (use_textures)
{
tex = mDetailTextures[i];
+ tex_emissive = nullptr;
+ has_base_color_factor = false;
+ has_emissive_factor = false;
+ llassert(tex);
}
else
{
tex = mDetailMaterials[i]->mBaseColorTexture;
+ tex_emissive = mDetailMaterials[i]->mEmissiveTexture;
+ base_color_factor = LLColor3(mDetailMaterials[i]->mBaseColor);
+ // *HACK: Treat alpha as black
+ base_color_factor *= (mDetailMaterials[i]->mBaseColor.mV[VW]);
+ emissive_factor = mDetailMaterials[i]->mEmissiveColor;
+ has_base_color_factor = (base_color_factor.mV[VX] != 1.f ||
+ base_color_factor.mV[VY] != 1.f ||
+ base_color_factor.mV[VZ] != 1.f);
+ has_emissive_factor = (emissive_factor.mV[VX] != 1.f ||
+ emissive_factor.mV[VY] != 1.f ||
+ emissive_factor.mV[VZ] != 1.f);
}
- // *TODO: Why are terrain textures (not terrain materials) not loading? (that is why there is a getComponents() check here)
- if (!tex || tex->getComponents() == 0) { tex = LLViewerFetchedTexture::sWhiteImagep; }
+
+ if (!tex) { tex = LLViewerFetchedTexture::sWhiteImagep; }
+ // tex_emissive can be null, and then will be ignored
S32 min_dim = llmin(tex->getFullWidth(), tex->getFullHeight());
S32 ddiscard = 0;
@@ -430,8 +465,9 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
}
BOOL delete_raw = (tex->reloadRawImage(ddiscard) != NULL) ;
- if(tex->getRawImageLevel() != ddiscard)//raw iamge is not ready, will enter here again later.
+ if(tex->getRawImageLevel() != ddiscard)
{
+ // Raw image is not ready, will enter here again later.
if (tex->getFetchPriority() <= 0.0f && !tex->hasSavedRawImage())
{
tex->setBoostLevel(LLGLTexture::BOOST_MAP);
@@ -442,21 +478,78 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
{
tex->destroyRawImage() ;
}
- LL_DEBUGS("Terrain") << "cached raw data for terrain detail texture is not ready yet: " << tex->getID() << " Discard: " << ddiscard << LL_ENDL;
return FALSE;
}
+ if (tex_emissive)
+ {
+ if(tex_emissive->getRawImageLevel() != ddiscard)
+ {
+ // Raw image is not ready, will enter here again later.
+ if (tex_emissive->getFetchPriority() <= 0.0f && !tex_emissive->hasSavedRawImage())
+ {
+ tex_emissive->setBoostLevel(LLGLTexture::BOOST_MAP);
+ tex_emissive->forceToRefetchTexture(ddiscard);
+ }
+
+ if(delete_raw)
+ {
+ tex_emissive->destroyRawImage() ;
+ }
+ return FALSE;
+ }
+ }
mRawImages[i] = tex->getRawImage() ;
if(delete_raw)
{
tex->destroyRawImage() ;
}
- if (tex->getWidth(ddiscard) != BASE_SIZE ||
+
+ // *TODO: This isn't quite right for PBR:
+ // 1) It does not convert the color images from SRGB to linear
+ // before mixing (which will always require copying the image).
+ // 2) It mixes emissive and base color before mixing terrain
+ // materials, but it should be the other way around
+ // 3) The composite function used to put emissive into base color
+ // is not an alpha blend.
+ // Long-term, we should consider a method that is more
+ // maintainable. Shaders, perhaps? Bake shaders to textures?
+ LLPointer<LLImageRaw> raw_emissive;
+ if (tex_emissive)
+ {
+ raw_emissive = tex_emissive->getRawImage();
+ if (has_emissive_factor ||
+ tex_emissive->getWidth(ddiscard) != BASE_SIZE ||
+ tex_emissive->getHeight(ddiscard) != BASE_SIZE ||
+ tex_emissive->getComponents() != 4)
+ {
+ LLPointer<LLImageRaw> newraw_emissive = new LLImageRaw(BASE_SIZE, BASE_SIZE, 4);
+ // Copy RGB, leave alpha alone (set to opaque by default)
+ newraw_emissive->copy(mRawImages[i]);
+ if (has_emissive_factor)
+ {
+ newraw_emissive->tint(emissive_factor);
+ }
+ raw_emissive = newraw_emissive; // deletes old
+ }
+ }
+ if (has_base_color_factor ||
+ raw_emissive ||
+ tex->getWidth(ddiscard) != BASE_SIZE ||
tex->getHeight(ddiscard) != BASE_SIZE ||
tex->getComponents() != 3)
{
LLPointer<LLImageRaw> newraw = new LLImageRaw(BASE_SIZE, BASE_SIZE, 3);
newraw->composite(mRawImages[i]);
+ if (has_base_color_factor)
+ {
+ newraw->tint(base_color_factor);
+ }
+ // Apply emissive texture
+ if (raw_emissive)
+ {
+ newraw->composite(raw_emissive);
+ }
mRawImages[i] = newraw; // deletes old
}
}
@@ -478,12 +571,12 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
if (x_end > mWidth)
{
- LL_WARNS("Terrain") << "x end > width" << LL_ENDL;
+ llassert(false);
x_end = mWidth;
}
if (y_end > mWidth)
{
- LL_WARNS("Terrain") << "y end > width" << LL_ENDL;
+ llassert(false);
y_end = mWidth;
}
@@ -513,7 +606,7 @@ BOOL LLVLComposition::generateTexture(const F32 x, const F32 y,
if (tex_comps != st_comps)
{
- LL_WARNS("Terrain") << "Base texture comps != input texture comps" << LL_ENDL;
+ llassert(false);
return FALSE;
}
diff --git a/indra/newview/llvlcomposition.h b/indra/newview/llvlcomposition.h
index 882c3d89b2..d59c0f95bb 100644
--- a/indra/newview/llvlcomposition.h
+++ b/indra/newview/llvlcomposition.h
@@ -87,7 +87,7 @@ public:
BOOL generateHeights(const F32 x, const F32 y, const F32 width, const F32 height);
BOOL generateComposition();
// Generate texture from composition values.
- BOOL generateTexture(const F32 x, const F32 y, const F32 width, const F32 height);
+ BOOL generateMinimapTileLand(const F32 x, const F32 y, const F32 width, const F32 height);
// Heights map into textures (or materials) as 0-1 = first, 1-2 = second, etc.
// So we need to compress heights into this range.