diff --git a/doomsday/apps/client/include/render/model.h b/doomsday/apps/client/include/render/model.h index b70c355a80..e09ce7b509 100644 --- a/doomsday/apps/client/include/render/model.h +++ b/doomsday/apps/client/include/render/model.h @@ -62,6 +62,8 @@ struct Model : public de::ModelDrawable enum Flag { AutoscaleToThingHeight = 0x1, + ThingOpacityAsAmbientLightAlpha = 0x2, + ThingFullBrightAsAmbientLight = 0x4, DefaultFlags = AutoscaleToThingHeight }; Q_DECLARE_FLAGS(Flags, Flag) diff --git a/doomsday/apps/client/include/render/vissprite.h b/doomsday/apps/client/include/render/vissprite.h index 1ea279fdff..49dd4fe364 100644 --- a/doomsday/apps/client/include/render/vissprite.h +++ b/doomsday/apps/client/include/render/vissprite.h @@ -98,6 +98,7 @@ struct VisEntityLighting { de::Vector4f ambientColor; de::duint vLightListIdx = 0; + bool isFullBright = false; VisEntityLighting() = default; @@ -160,45 +161,39 @@ enum vispspritetype_t /// @ingroup render struct vispsprite_t { - vispspritetype_t type; - ddpsprite_t *psp; - de::Vector3d origin; - world::BspLeaf const *bspLeaf; - VisEntityLighting light; + vispspritetype_t type; + ddpsprite_t * psp; + de::Vector3d origin; + const world::BspLeaf *bspLeaf; + VisEntityLighting light; + float alpha; // overall opacity union vispsprite_data_u { - struct vispsprite_sprite_s { - de::dfloat alpha; - dd_bool isFullBright; - } sprite; struct vispsprite_model_s { - coord_t topZ; ///< global top for silhouette clipping - de::dint flags; ///< for color translation and shadow draw - de::duint id; - de::dint selector; - de::dint pClass; ///< player class (used in translation) - coord_t floorClip; - dd_bool stateFullBright; - dd_bool viewAligned; ///< @c true= Align to view plane. - coord_t secFloor; - coord_t secCeil; - de::dfloat alpha; - de::ddouble visOff[3]; ///< Last-minute offset to coords. - dd_bool floorAdjust; ///< Allow moving sprite to match visible floor. - FrameModelDef *mf; FrameModelDef *nextMF; - de::dfloat yaw; - de::dfloat pitch; - de::dfloat pitchAngleOffset; - de::dfloat yawAngleOffset; - de::dfloat inter; ///< Frame interpolation, 0..1 + coord_t topZ; ///< global top for silhouette clipping + int flags; ///< for color translation and shadow draw + unsigned int id; + int selector; + int pClass; ///< player class (used in translation) + coord_t floorClip; + bool viewAligned; ///< @c true= Align to view plane. + coord_t secFloor; + coord_t secCeil; + double visOff[3]; ///< Last-minute offset to coords. + bool floorAdjust; ///< Allow moving sprite to match visible floor. + float yaw; + float pitch; + float pitchAngleOffset; + float yawAngleOffset; + float inter; ///< Frame interpolation, 0..1 } model; struct vispsprite_model2_s { - render::Model const *model; - render::StateAnimator const *animator; - de::dfloat pitchAngleOffset; - de::dfloat yawAngleOffset; + const render::Model *model; + const render::StateAnimator *animator; + float pitchAngleOffset; + float yawAngleOffset; } model2; } data; }; diff --git a/doomsday/apps/client/net.dengine.client.pack/renderer.pack/shaders/model.dei b/doomsday/apps/client/net.dengine.client.pack/renderer.pack/shaders/model.dei index fb49639d49..df06a72c51 100644 --- a/doomsday/apps/client/net.dengine.client.pack/renderer.pack/shaders/model.dei +++ b/doomsday/apps/client/net.dengine.client.pack/renderer.pack/shaders/model.dei @@ -12,12 +12,12 @@ model.skeletal { variable uGlossiness { value = 100 } variable uReflection { value = 1 } variable uReflectionBlur { value = 10 } - + variable uMapTime {} - + # Mapping when used with ModelDrawable. textureMapping - + include.vertex @@ -36,30 +36,30 @@ model.skeletal { out vec2 vUV; out vec4 vUVBounds[4]; - void main(void) + void main(void) { mat4 bone = vertexBoneTransform(); setTangentSpace(bone); - + // Vertex position. vec4 modelPos = bone * aVertex; calculateEyeDirection(modelPos); - + gl_Position = uMvpMatrix * modelPos; - + vColor = aColor; vUV = aUV; vUVBounds[0] = aBounds; vUVBounds[1] = aBounds2; vUVBounds[2] = aBounds3; - vUVBounds[3] = aBounds4; + vUVBounds[3] = aBounds4; }" - defines $= {'PREDEF_TRANSFORM_UV(uv)' : '', + defines $= {'PREDEF_TRANSFORM_UV(uv)' : '', 'PREDEF_TRANSFORM_EMISSION(color)' : '', 'PREDEF_TRANSFORM_ALPHA(alpha)' : ''} - - include.fragment defines $= {'PREDEF_TRANSFORM_UV(uv)': ''} - + include.vertex @@ -193,25 +193,25 @@ model.skeletal { out vec2 vUV; out vec4 vUVBounds[3]; - void main(void) + void main(void) { mat4 bone = vertexBoneTransform(); setTangentSpace(bone); - + // Vertex position. vec4 modelPos = bone * aVertex; calculateEyeDirection(modelPos); gl_Position = uMvpMatrix * modelPos; - + vColor = aColor; vUV = aUV; vUVBounds[0] = aBounds; vUVBounds[1] = aBounds2; - vUVBounds[2] = aBounds3; + vUVBounds[2] = aBounds3; }" - include.fragment defines $= {'PREDEF_TRANSFORM_UV(uv)': ''} - + include.vertex @@ -283,24 +283,24 @@ model.skeletal { out vec2 vUV; out vec4 vUVBounds[2]; - void main(void) + void main(void) { mat4 bone = vertexBoneTransform(); setTangentSpace(bone); - + // Vertex position. vec4 modelPos = bone * aVertex; calculateEyeDirection(modelPos); gl_Position = uMvpMatrix * modelPos; - + vColor = aColor; vUV = aUV; vUVBounds[0] = aBounds; vUVBounds[1] = aBounds2; }" - include.fragment @@ -310,12 +310,12 @@ model.skeletal { uniform vec3 uColor; // diffuse color multiplier uniform vec2 uOffsetUV; uniform float uMapTime; - + in vec4 vColor; in vec2 vUV; in vec4 vUVBounds[2]; - - void main(void) + + void main(void) { // Calculate UV at the fragment (wrapped inside the bounds). vec2 wrappedUV = vUV + uOffsetUV; @@ -325,18 +325,18 @@ model.skeletal { wrappedUV = fract(wrappedUV); vec2 uv = mapToBounds(wrappedUV, vUVBounds[0]); vec2 normalUV = mapToBounds(wrappedUV, vUVBounds[1]); - - vec3 msNormal = modelSpaceNormalVector(normalUV); + + vec3 msNormal = modelSpaceNormalVector(normalUV); out_FragColor = vColor * vec4(uColor * diffuseLight(msNormal), 1.0) * texture(uTex, uv); if (out_FragColor.a < uAlphaLimit) discard; - out_FragColor.a = uAlpha; - + out_FragColor.a = uAlpha * uAmbientLight.a; + applyFog(); - }" + }" } - + # Shader for special effects. Only uses a diffuse texture map. # No external lighting. shader unlit.diffuse { @@ -352,7 +352,7 @@ model.skeletal { defines $= {'PREDEF_TRANSFORM_UV(uv)' : '', 'PREDEF_TRANSFORM_ALPHA(alpha)' : ''} - + include.vertex vertex = " uniform mat4 uMvpMatrix; @@ -366,14 +366,14 @@ model.skeletal { out vec2 vUV; out vec4 vUVBounds; - void main(void) + void main(void) { mat4 bone = vertexBoneTransform(); - + // Vertex position. vec4 modelPos = bone * aVertex; gl_Position = uMvpMatrix * modelPos; - + vColor = aColor; vUV = aUV; vUVBounds = aBounds; @@ -386,12 +386,12 @@ model.skeletal { uniform vec3 uColor; // diffuse color multiplier uniform vec2 uOffsetUV; uniform float uMapTime; - + in vec4 vColor; in vec2 vUV; in vec4 vUVBounds; - - void main(void) + + void main(void) { // Calculate UV at the fragment (wrapped inside the bounds). vec2 wrappedUV = vUV + uOffsetUV; @@ -400,15 +400,15 @@ model.skeletal { #endif wrappedUV = fract(wrappedUV); vec2 uv = mapToBounds(wrappedUV, vUVBounds); - + vec4 diffuse = vColor * texture(uTex, uv); if (diffuse.a < uAlphaLimit) discard; - + float alphaFactor = uAlpha; #if defined (PREDEF_TRANSFORM_ALPHA) PREDEF_TRANSFORM_ALPHA(alphaFactor); #endif out_FragColor = diffuse * vec4(uColor, alphaFactor); - }" - } + }" + } } diff --git a/doomsday/apps/client/src/render/modelloader.cpp b/doomsday/apps/client/src/render/modelloader.cpp index 469ea5304a..4b1895b0fb 100644 --- a/doomsday/apps/client/src/render/modelloader.cpp +++ b/doomsday/apps/client/src/render/modelloader.cpp @@ -55,6 +55,8 @@ static String const DEF_STATE ("state"); static String const DEF_TEXTURE_MAPPING ("textureMapping"); static String const DEF_TIMELINE ("timeline"); static String const DEF_UP_VECTOR ("up"); +static String const DEF_WEAPON_OPACITY ("opacityFromWeapon"); +static String const DEF_WEAPON_FULLBRIGHT("fullbrightFromWeapon"); static String const DEF_VARIANT ("variant"); static String const SHADER_DEFAULT ("model.skeletal.generic"); @@ -78,7 +80,7 @@ DENG2_PIMPL(ModelLoader) filesys::AssetObserver observer { "model\\..*" }; ModelBank bank { // Using render::Model instances. - [] () -> ModelDrawable * { return new render::Model; } + []() -> ModelDrawable * { return new render::Model; } }; LockableT> pendingModels; @@ -452,6 +454,10 @@ DENG2_PIMPL(ModelLoader) } applyFlagOperation(model.flags, render::Model::AutoscaleToThingHeight, ScriptedInfo::isTrue(asset, DEF_AUTOSCALE)? SetFlags : UnsetFlags); + applyFlagOperation(model.flags, render::Model::ThingOpacityAsAmbientLightAlpha, + ScriptedInfo::isTrue(asset, DEF_WEAPON_OPACITY, true)? SetFlags : UnsetFlags); + applyFlagOperation(model.flags, render::Model::ThingFullBrightAsAmbientLight, + ScriptedInfo::isTrue(asset, DEF_WEAPON_FULLBRIGHT)? SetFlags : UnsetFlags); // Alignment modes. model.alignYaw = parseAlignment(asset, DEF_ALIGNMENT_YAW); diff --git a/doomsday/apps/client/src/render/modelrenderer.cpp b/doomsday/apps/client/src/render/modelrenderer.cpp index d51ea4cc15..4d94a1248b 100644 --- a/doomsday/apps/client/src/render/modelrenderer.cpp +++ b/doomsday/apps/client/src/render/modelrenderer.cpp @@ -96,11 +96,12 @@ DENG2_PIMPL(ModelRenderer) << uFogColor; } - void setupLighting(VisEntityLighting const &lighting, - mobj_t const *excludeSourceMobj) + void setupLighting(const VisEntityLighting &lighting, + const mobj_t *excludeSourceMobj, + float alpha = 1.0f) { // Ambient color and lighting vectors. - setAmbientLight(lighting.ambientColor * .6f); + setAmbientLight(lighting.ambientColor * .6f, alpha); clearLights(); ClientApp::renderSystem().forAllVectorLights(lighting.vLightListIdx, [this, excludeSourceMobj] @@ -115,11 +116,27 @@ DENG2_PIMPL(ModelRenderer) addLight(vlight.direction.xzy(), vlight.color); return LoopContinue; }); + + // Modify the ambient light according to model configuration. + /* + { + Vector4f ambient = uAmbientLight; + if (model.flags & render::Model::ThingAlphaAsAmbientLightAlpha) + { + ambient.w = p.alpha; + } + if (model.flags & render::Model::ThingFullBrightAsAmbientLight) + { + ambient = {1.0f, 1.0f, 1.0f, ambient.w}; + } + uAmbientLight = ambient; + } +*/ } - void setAmbientLight(Vector3f const &ambientIntensity) + void setAmbientLight(Vector3f const &ambientIntensity, float alpha) { - uAmbientLight = Vector4f(ambientIntensity, 1.f); + uAmbientLight = Vector4f(ambientIntensity, alpha); } void clearLights() @@ -329,7 +346,18 @@ void ModelRenderer::render(vispsprite_t const &pspr, mobj_t const *playerMobj) true, /* fixed FOV for psprites */ &xform); - d->setupLighting(pspr.light, playerMobj /* player holding weapon is excluded */); + float opacity = 1.0f; + if (p.model->flags & render::Model::ThingOpacityAsAmbientLightAlpha) + { + opacity = pspr.alpha; + } + + d->setupLighting(pspr.light, playerMobj /* player holding weapon is excluded */, opacity); + + if (p.model->flags & render::Model::ThingFullBrightAsAmbientLight) + { + d->setAmbientLight({1.0f, 1.0f, 1.0f}, opacity); + } GLState::push().setCull(p.model->cull); d->draw(p); diff --git a/doomsday/apps/client/src/render/r_main.cpp b/doomsday/apps/client/src/render/r_main.cpp index da817a32d6..2aae79c252 100644 --- a/doomsday/apps/client/src/render/r_main.cpp +++ b/doomsday/apps/client/src/render/r_main.cpp @@ -103,13 +103,11 @@ static void setupPSpriteParams(rendpspriteparams_t &parm, vispsprite_t const &vs parm.texFlip[1] = false; parm.mat = &matAnimator.material(); - parm.ambientColor[3] = vs.data.sprite.alpha; + parm.ambientColor[3] = vs.alpha; - if (vs.data.sprite.isFullBright) + if (vs.light.isFullBright) { - parm.ambientColor[0] = - parm.ambientColor[1] = - parm.ambientColor[2] = 1; + parm.ambientColor[0] = parm.ambientColor[1] = parm.ambientColor[2] = 1; parm.vLightListIdx = 0; } else @@ -235,9 +233,9 @@ static void setupModelParamsForVisPSprite(vissprite_t &vis, vispsprite_t const & params->shinePitchOffset = vpitch + 90; params->shineTranslateWithViewerPos = false; params->shinepspriteCoordSpace = true; - vis.light.ambientColor[3] = spr.data.model.alpha; + vis.light.ambientColor[3] = spr.alpha; - if ((levelFullBright || spr.data.model.stateFullBright) && + if ((levelFullBright || spr.light.isFullBright) && !spr.data.model.mf->testSubFlag(0, MFF_DIM)) { vis.light.ambientColor[0] = vis.light.ambientColor[1] = vis.light.ambientColor[2] = 1; diff --git a/doomsday/apps/client/src/render/viewports.cpp b/doomsday/apps/client/src/render/viewports.cpp index 6fe0068576..de7606cea1 100644 --- a/doomsday/apps/client/src/render/viewports.cpp +++ b/doomsday/apps/client/src/render/viewports.cpp @@ -804,9 +804,12 @@ static void setupPlayerSprites() spr->psp = &ddpl->pSprites[i]; spr->origin = viewData->current.origin; spr->bspLeaf = &Mobj_BspLeafAtOrigin(*mob); + spr->alpha = spr->psp->alpha; if(!spr->psp->statePtr) continue; + spr->light.isFullBright = (spr->psp->flags & DDPSPF_FULLBRIGHT) != 0; + // First, determine whether this is a model or a sprite. FrameModelDef *mf = nullptr, *nextmf = nullptr; dfloat inter = 0; @@ -868,17 +871,11 @@ static void setupPlayerSprites() viewData->current.angle() / (dfloat) ANGLE_MAX *-360 + spr->data.model.yawAngleOffset + 90; spr->data.model.pitch = viewData->current.pitch * 85 / 110 + spr->data.model.yawAngleOffset; std::memset(spr->data.model.visOff, 0, sizeof(spr->data.model.visOff)); - - spr->data.model.alpha = spr->psp->alpha; - spr->data.model.stateFullBright = (spr->psp->flags & DDPSPF_FULLBRIGHT) != 0; } else { // No, draw a 2D sprite (in Rend_DrawPlayerSprites). spr->type = VPSPR_SPRITE; - - spr->data.sprite.alpha = spr->psp->alpha; - spr->data.sprite.isFullBright = (spr->psp->flags & DDPSPF_FULLBRIGHT) != 0; } } }