diff --git a/src/common/textures/textures.h b/src/common/textures/textures.h index b4d3c43ae..13c038b33 100644 --- a/src/common/textures/textures.h +++ b/src/common/textures/textures.h @@ -105,6 +105,8 @@ enum SFlag_Global = 1, }; +class AActor; + struct UserShaderDesc { FString shader; @@ -117,6 +119,8 @@ struct UserShaderDesc std::vector Varyings; UserUniforms Uniforms; TMap ActorFieldBindings; + + void BindActorFields(AActor * act); }; extern TArray usershaders; diff --git a/src/r_data/gldefs.cpp b/src/r_data/gldefs.cpp index 9076b8885..893cb5575 100644 --- a/src/r_data/gldefs.cpp +++ b/src/r_data/gldefs.cpp @@ -50,6 +50,7 @@ #include "texturemanager.h" #include "gameconfigfile.h" #include "m_argv.h" +#include "types.h" void AddLightDefaults(FLightDefaults *defaults, double attnFactor); void AddLightAssociation(const char *actor, const char *frame, const char *light); @@ -299,6 +300,154 @@ void uniform_callback_color4f(FColorCVar &self) do_uniform_set4f(col.r / 255.0, col.g / 255.0, col.b / 255.0, col.a / 255.0, data); } +void setUniformI(UniformField field, int val) +{ + switch(field.Type) + { + case UniformType::Int: + ((int *)field.Value)[0] = val; + break; + case UniformType::Vec4: + ((float *)field.Value)[3] = 1.0f; + case UniformType::Vec3: + ((float *)field.Value)[2] = 0.0f; + case UniformType::Vec2: + ((float *)field.Value)[1] = 0.0f; + case UniformType::Float: + ((float *)field.Value)[0] = val; + break; + } +} + +void setUniformF(UniformField field, float val) +{ + switch(field.Type) + { + case UniformType::Int: + ((int *)field.Value)[0] = val; + break; + case UniformType::Vec4: + ((float *)field.Value)[3] = 1.0f; + case UniformType::Vec3: + ((float *)field.Value)[2] = 0.0f; + case UniformType::Vec2: + ((float *)field.Value)[1] = 0.0f; + case UniformType::Float: + ((float *)field.Value)[0] = val; + break; + } +} + +void setUniformF(UniformField field, const FVector2 &val) +{ + switch(field.Type) + { + case UniformType::Int: + ((int *)field.Value)[0] = val.X; + break; + case UniformType::Vec4: + ((float *)field.Value)[3] = 1.0f; + case UniformType::Vec3: + ((float *)field.Value)[2] = 0.0f; + case UniformType::Vec2: + ((float *)field.Value)[1] = val.Y; + case UniformType::Float: + ((float *)field.Value)[0] = val.X; + break; + } +} + +void setUniformF(UniformField field, const FVector3 &val) +{ + switch(field.Type) + { + case UniformType::Int: + ((int *)field.Value)[0] = val.X; + break; + case UniformType::Vec4: + ((float *)field.Value)[3] = 1.0f; + case UniformType::Vec3: + ((float *)field.Value)[2] = val.Z; + case UniformType::Vec2: + ((float *)field.Value)[1] = val.Y; + case UniformType::Float: + ((float *)field.Value)[0] = val.X; + break; + } +} + +void setUniformF(UniformField field, const FVector4 &val) +{ + switch(field.Type) + { + case UniformType::Int: + ((int *)field.Value)[0] = val.X; + break; + case UniformType::Vec4: + ((float *)field.Value)[3] = val.W; + case UniformType::Vec3: + ((float *)field.Value)[2] = val.Z; + case UniformType::Vec2: + ((float *)field.Value)[1] = val.Y; + case UniformType::Float: + ((float *)field.Value)[0] = val.X; + break; + } +} + +void UserShaderDesc::BindActorFields(AActor * act) +{ + TMapIterator it(ActorFieldBindings); + TMap::Pair * p; + while(it.NextPair(p)) + { + UniformField uniformField = Uniforms.GetField(p->Key); + PField * actorField = dyn_cast(act->GetClass()->FindSymbol(p->Value, true)); + if(actorField && uniformField.Type != UniformType::Undefined) + { + void * addr = reinterpret_cast(act) + actorField->Offset; + + PType * t = actorField->Type; + if(t == TypeUInt32 || t == TypeSInt32) + { + setUniformI(uniformField, *(int*)addr); + } + else if(t == TypeFloat32) + { + setUniformF(uniformField, *(float*)addr); + } + else if(t == TypeFloat64) + { + setUniformF(uniformField, (float)*(double*)addr); + } + else if(t == TypeFVector2) + { + setUniformF(uniformField, *(FVector2*)addr); + } + else if(t == TypeVector2) + { + setUniformF(uniformField, FVector2(*(DVector2*)addr)); + } + else if(t == TypeFVector3) + { + setUniformF(uniformField, *(FVector3*)addr); + } + else if(t == TypeVector3) + { + setUniformF(uniformField, FVector3(*(DVector3*)addr)); + } + else if(t == TypeFVector4 || t == TypeQuaternion) + { + setUniformF(uniformField, *(FVector4*)addr); + } + else if(t == TypeVector4 || t == TypeFQuaternion) + { + setUniformF(uniformField, FVector4(*(DVector4*)addr)); + } + } + } +} + //----------------------------------------------------------------------------- // // ParseVavoomSkybox diff --git a/src/rendering/hwrenderer/hw_models.cpp b/src/rendering/hwrenderer/hw_models.cpp index de8ab1bc7..94fcee51d 100644 --- a/src/rendering/hwrenderer/hw_models.cpp +++ b/src/rendering/hwrenderer/hw_models.cpp @@ -137,6 +137,17 @@ void FHWModelRenderer::SetInterpolation(double inter) void FHWModelRenderer::SetMaterial(FGameTexture *skin, bool clampNoFilter, FTranslationID translation, AActor * act) { state.SetMaterial(skin, UF_Skin, 0, clampNoFilter ? CLAMP_NOFILTER : CLAMP_NONE, translation, -1, act ? act->GetClass() : nullptr); + + int shader = state.getShaderIndex(); + + if(shader >= FIRST_USER_SHADER && act && (act != lastAct || shader != lastShader)) + { // only re-bind uniforms if the actor or the shader have changed + usershaders[shader - FIRST_USER_SHADER].BindActorFields(act); + } + + lastAct = act; + lastShader = shader; + state.SetLightIndex(modellightindex); } diff --git a/src/rendering/hwrenderer/hw_models.h b/src/rendering/hwrenderer/hw_models.h index 6a6810b65..7a3ba01dd 100644 --- a/src/rendering/hwrenderer/hw_models.h +++ b/src/rendering/hwrenderer/hw_models.h @@ -42,6 +42,9 @@ class FHWModelRenderer : public FModelRenderer int boneIndexBase = -1; HWDrawInfo *di; FRenderState &state; + + AActor * lastAct = nullptr; + int lastShader = 0; public: FHWModelRenderer(HWDrawInfo *d, FRenderState &st, int mli) : modellightindex(mli), di(d), state(st) {} diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 61acacd37..1ab44a873 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -241,6 +241,16 @@ void HWSprite::DrawSprite(HWDrawInfo *di, FRenderState &state, bool translucent) if (texture) state.SetMaterial(texture, UF_Sprite, (spritetype == RF_FACESPRITE) ? CTF_Expand : 0, clampmode, translation, OverrideShader, actor ? actor->GetClass() : nullptr); else if (!modelframe) state.EnableTexture(false); + if (actor && texture) + { + int binding = state.getShaderIndex(); + + if(binding >= FIRST_USER_SHADER) + { + usershaders[binding - FIRST_USER_SHADER].BindActorFields(actor); + } + } + //SetColor(lightlevel, rel, Colormap, trans); unsigned int iter = lightlist ? lightlist->Size() : 1;