Skip to content

Commit

Permalink
Implemented support for editing and saving Fallout 76 materials
Browse files Browse the repository at this point in the history
  • Loading branch information
fo76utils committed Nov 2, 2024
1 parent c77b895 commit 8f48df7
Show file tree
Hide file tree
Showing 11 changed files with 386 additions and 128 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
== CHANGELOG ==

* Implemented support for editing and saving Fallout 76 materials.

#### NifSkope-2.0.dev9-20241028

* Converting Starfield geometry to external mesh files can now use a custom sub-directory under 'geometries'. This can be configured in the general settings under NIF, and if the name is not empty, exported mesh paths will be in the format 'geometries/SUBDIR/SHA1.mesh', and the full hash (40 characters) will be used as the base name of the file.
Expand Down
2 changes: 2 additions & 0 deletions build/nif.xml
Original file line number Diff line number Diff line change
Expand Up @@ -7238,6 +7238,7 @@
<field name="Terrain Threshold Falloff" type="float" cond="Shader Flags 2 #BITAND# 0x01000000" />
<field name="Terrain Tiling Distance" type="float" cond="Shader Flags 2 #BITAND# 0x01000000" />
<field name="Terrain Rotation Angle" type="float" cond="Shader Flags 2 #BITAND# 0x01000000" />
<field name="Is Modified" type="bool" />
</struct>

<niobject name="BSLightingShaderProperty" inherit="BSShaderProperty" module="BSMain" versions="#SKY_AND_LATER#">
Expand Down Expand Up @@ -7371,6 +7372,7 @@
<field name="Adaptive Emissive Exposure Offset" type="float" />
<field name="Adaptive Emissive Exposure Min" type="float" />
<field name="Adaptive Emissive Exposure Max" type="float" />
<field name="Is Modified" type="bool" />
</struct>

<niobject name="BSEffectShaderProperty" inherit="BSShaderProperty" module="BSMain" versions="#SKY_AND_LATER#">
Expand Down
80 changes: 47 additions & 33 deletions src/gl/glproperty.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -906,12 +906,15 @@ void BSShaderLightingProperty::clear()
{
Property::clear();

setMaterial(nullptr);
if ( material ) {
delete material;
material = nullptr;
}

sf_material = nullptr;
sfMaterialDB_ID = std::uint64_t(-1);
sf_material_valid = false;
sfMaterialPath.clear();
materialPath.clear();
sfMatDataBuf.clear();
}

Expand Down Expand Up @@ -972,22 +975,43 @@ int BSShaderLightingProperty::getSFTexture( int & texunit, FloatVector4 & replUn
return 0;
}

void BSShaderLightingProperty::setMaterial( Material * newMaterial )
void BSShaderLightingProperty::setMaterial( const NifModel * nif, const QModelIndex & index, bool isEffect )
{
if (newMaterial && !newMaterial->isValid()) {
delete newMaterial;
newMaterial = nullptr;
}
if ( material && material != newMaterial ) {
if ( material ) {
delete material;
material = nullptr;
}

bool nameChanged = false;
if ( name != materialPath ) {
materialPath = name;
nameChanged = true;
}
bool isAbstract = false;
Material * newMaterial = nullptr;
if ( name.endsWith( QLatin1StringView( !isEffect ? ".bgsm" : ".bgem" ), Qt::CaseInsensitive ) ) {
if ( bsVersion >= 151 && !nameChanged ) {
const NifItem * i = nif->getItem( index, "Material" );
isAbstract = ( i && nif->get<bool>( i, "Is Modified" ) );
}
if ( isEffect )
newMaterial = new EffectMaterial( name, nif, ( isAbstract ? index : QModelIndex() ) );
else
newMaterial = new ShaderMaterial( name, nif, ( isAbstract ? index : QModelIndex() ) );
}
material = newMaterial;
if ( bsVersion >= 151 && !isAbstract )
const_cast< NifModel * >(nif)->loadFO76Material( index, newMaterial );

if ( newMaterial && !newMaterial->isValid() )
delete newMaterial;
else
material = newMaterial;
}

void BSShaderLightingProperty::setSFMaterial( const QString & mat_name )
{
sfMaterialDB_ID = std::uint64_t(-1);
if ( mat_name == sfMaterialPath ) {
if ( mat_name == materialPath ) {
const NifModel * nif = scene->nifModel;
const NifItem * i = nif->getItem( iBlock, "Material" );
if ( i && nif->get<bool>( i, "Is Modified" ) ) {
Expand All @@ -1002,7 +1026,7 @@ void BSShaderLightingProperty::setSFMaterial( const QString & mat_name )
return;
}
} else {
sfMaterialPath = mat_name;
materialPath = mat_name;
}
loadSFMaterial();
}
Expand All @@ -1017,8 +1041,8 @@ void BSShaderLightingProperty::loadSFMaterial()
sfMatDataBuf.clear();
const NifModel * nif = scene->nifModel;
const CE2Material * mat = nullptr;
if ( !sfMaterialPath.isEmpty() ) {
std::string fullPath( Game::GameManager::get_full_path( sfMaterialPath, "materials/", ".mat" ) );
if ( !materialPath.isEmpty() ) {
std::string fullPath( Game::GameManager::get_full_path( materialPath, "materials/", ".mat" ) );
try {
CE2MaterialDB * materials = nif->getCE2Materials();
if ( materials )
Expand Down Expand Up @@ -1143,7 +1167,7 @@ QString BSShaderLightingProperty::fileName( int id ) const
return QString();

// Fallout 4 or 76 BGSM file
if ( bsVersion >= 130 && material && typeid(*material) == typeid(ShaderMaterial) ) {
if ( bsVersion >= 130 && material && material->isShaderMaterial() ) {
// BSLSP
auto m = static_cast<ShaderMaterial *>(material);
if ( m->isValid() ) {
Expand Down Expand Up @@ -1199,7 +1223,7 @@ QString BSShaderLightingProperty::fileName( int id ) const

if ( bsVersion < 151 )
return QString();
} else if ( bsVersion >= 130 && material && typeid(*material) == typeid(EffectMaterial) ) {
} else if ( bsVersion >= 130 && material && material->isEffectMaterial() ) {
// From Fallout 4 or 76 effect material file
auto m = static_cast<EffectMaterial*>(material);
if ( m->isValid() ) {
Expand Down Expand Up @@ -1308,17 +1332,12 @@ void BSLightingShaderProperty::updateImpl( const NifModel * nif, const QModelInd
BSShaderLightingProperty::updateImpl( nif, index );

if ( index == iBlock ) {
if ( name.endsWith(".bgsm", Qt::CaseInsensitive) && bsVersion < 170 ) {
setMaterial( new ShaderMaterial( name, nif ) );
if ( bsVersion >= 151 )
const_cast< NifModel * >(nif)->loadFO76Material( index, material );
} else {
setMaterial( nullptr );
}
updateParams(nif);
if ( bsVersion < 170 )
setMaterial( nif, index, false );
updateParams( nif );
}
else if ( index == iTextureSet ) {
updateParams(nif);
updateParams( nif );
}
}

Expand Down Expand Up @@ -1547,16 +1566,11 @@ void BSEffectShaderProperty::updateImpl( const NifModel * nif, const QModelIndex
if ( index == iBlock ) {
if ( bsVersion < 83 )
return;
if ( name.endsWith(".bgem", Qt::CaseInsensitive) && bsVersion < 170 ) {
setMaterial( new EffectMaterial( name, nif ) );
if ( bsVersion >= 151 )
const_cast< NifModel * >(nif)->loadFO76Material( index, material );
} else {
setMaterial( nullptr );
}
updateParams(nif);
if ( bsVersion < 170 )
setMaterial( nif, index, true );
updateParams( nif );
} else if ( index == iTextureSet ) {
updateParams(nif);
updateParams( nif );
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/gl/glproperty.h
Original file line number Diff line number Diff line change
Expand Up @@ -757,9 +757,9 @@ class BSShaderLightingProperty : public Property
const CE2Material * sf_material = nullptr;
std::uint64_t sfMaterialDB_ID = std::uint64_t(-1); // -2 when using an edited material
bool sf_material_valid = false;
QString sfMaterialPath;
QString materialPath;
AllocBuffers sfMatDataBuf;
void setMaterial( Material * newMaterial );
void setMaterial( const NifModel * nif, const QModelIndex & index, bool isEffect );
void setSFMaterial( const QString & mat_name );
void loadSFMaterial();
const CE2Material * createDefaultSFMaterial();
Expand Down
2 changes: 1 addition & 1 deletion src/gl/renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1691,7 +1691,7 @@ bool Renderer::setupProgramCE1( const NifModel * nif, Program * prog, Shape * me
prog->uniSampler( bsprop, SAMP_LIGHTING, 7, texunit, lighting, clamp );
prog->uni1i( HAS_MAP_SPEC, int(!bsprop->fileName( 7 ).isEmpty()) );
bool glassEnabled = false;
if ( mat && typeid( *mat ) == typeid( EffectMaterial ) )
if ( mat && mat->isEffectMaterial() )
glassEnabled = static_cast< EffectMaterial * >( mat )->bGlassEnabled;
prog->uni1b( "isGlass", glassEnabled );
}
Expand Down
31 changes: 14 additions & 17 deletions src/io/material.h
Original file line number Diff line number Diff line change
Expand Up @@ -51,30 +51,27 @@ class Material : public QObject
friend class NifModel;

public:
Material( const QString & name, const NifModel * nif );
Material();

bool isValid() const;
bool isValid() const { return readable; }
bool hasAlphaBlend() const { return (bAlphaBlend != 0); }
bool hasAlphaTest() const { return (bAlphaTest != 0); }
bool hasDecal() const { return (bDecal != 0); }
QStringList textures() const;
QString getPath() const;
const QStringList & textures() const { return textureList; }
bool isEffectMaterial() const { return isBGEM; }
bool isShaderMaterial() const { return isBGSM; }
static void createMaterialData( QByteArray & data, const NifModel * nif, const QModelIndex & index );

protected:
bool openFile();
virtual bool readFile();
bool openFile( const QString & name, const NifModel * nif, const QModelIndex & index );
virtual bool readFile( QDataStream & in );

QStringList textureList;

bool fileExists = false;
QString localPath;
//QString absolutePath;

QDataStream in;
QByteArray data;

// Is not JSON format or otherwise unreadable
bool readable = false;
bool isBGEM = false;
bool isBGSM = false;

// BGSM & BGEM shared variables

Expand Down Expand Up @@ -129,10 +126,10 @@ class ShaderMaterial : public Material
friend class NifModel;

public:
ShaderMaterial( const QString & name, const NifModel * nif );
ShaderMaterial( const QString & name, const NifModel * nif, const QModelIndex & index );

protected:
bool readFile() override final;
bool readFile( QDataStream & in ) override final;

quint8 bEnableEditorAlphaRef = 0;
quint8 bRimLighting = 0;
Expand Down Expand Up @@ -210,10 +207,10 @@ class EffectMaterial : public Material
friend class NifModel;

public:
EffectMaterial( const QString & name, const NifModel * nif );
EffectMaterial( const QString & name, const NifModel * nif, const QModelIndex & index );

protected:
bool readFile() override final;
bool readFile( QDataStream & in ) override final;

quint8 bBloodEnabled = 0;
quint8 bEffectLightingEnabled = 0;
Expand Down
Loading

0 comments on commit 8f48df7

Please sign in to comment.