// //--------------------------------------------------------------------------- // // Copyright(C) 2000-2016 Christoph Oelckers // All rights reserved. // // This program is free software: you can redistribute it and/or modify // it under the terms of the GNU Lesser General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // This program is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License // along with this program. If not, see http://www.gnu.org/licenses/ // //-------------------------------------------------------------------------- // /* ** gl_weapon.cpp ** Weapon sprite drawing ** */ #include "gl/system/gl_system.h" #include "sbar.h" #include "r_utility.h" #include "v_video.h" #include "doomstat.h" #include "d_player.h" #include "g_level.h" #include "g_levellocals.h" #include "gl/system/gl_interface.h" #include "gl/system/gl_cvars.h" #include "gl/renderer/gl_renderer.h" #include "gl/renderer/gl_lightdata.h" #include "gl/renderer/gl_renderstate.h" #include "gl/data/gl_data.h" #include "gl/data/gl_vertexbuffer.h" #include "gl/dynlights/gl_glow.h" #include "gl/scene/gl_drawinfo.h" #include "gl/scene/gl_scenedrawer.h" #include "gl/models/gl_models.h" #include "gl/shaders/gl_shader.h" #include "gl/textures/gl_material.h" #include "gl/renderer/gl_quaddrawer.h" #include "gl/stereo3d/gl_stereo3d.h" EXTERN_CVAR (Bool, r_drawplayersprites) EXTERN_CVAR(Float, transsouls) EXTERN_CVAR(Int, gl_fuzztype) EXTERN_CVAR (Bool, r_deathcamera) //========================================================================== // // R_DrawPSprite // //========================================================================== void GLSceneDrawer::DrawPSprite (player_t * player,DPSprite *psp, float sx, float sy, bool hudModelStep, int OverrideShader, bool alphatexture) { float fU1,fV1; float fU2,fV2; float tx; float x1,y1,x2,y2; float scale; float scalex; float ftexturemid; // [BB] In the HUD model step we just render the model and break out. if ( hudModelStep ) { gl_RenderHUDModel(psp, sx, sy); return; } // decide which patch to use bool mirror; FTextureID lump = sprites[psp->GetSprite()].GetSpriteFrame(psp->GetFrame(), 0, 0., &mirror); if (!lump.isValid()) return; FMaterial * tex = FMaterial::ValidateTexture(lump, true, false); if (!tex) return; gl_RenderState.SetMaterial(tex, CLAMP_XY_NOMIP, 0, OverrideShader, alphatexture); float vw = (float)viewwidth; float vh = (float)viewheight; FloatRect r; tex->GetSpriteRect(&r); // calculate edges of the shape scalex = (320.0f / (240.0f * r_viewwindow.WidescreenRatio)) * vw / 320; tx = sx - (160 - r.left); x1 = tx * scalex + vw/2; if (x1 > vw) return; // off the right side x1 += viewwindowx; tx += r.width; x2 = tx * scalex + vw / 2; if (x2 < 0) return; // off the left side x2 += viewwindowx; // killough 12/98: fix psprite positioning problem ftexturemid = 100.f - sy - r.top; AWeapon * wi=player->ReadyWeapon; if (wi && wi->YAdjust != 0) { float fYAd = wi->YAdjust; if (screenblocks >= 11) { ftexturemid -= fYAd; } else { ftexturemid -= StatusBar->GetDisplacement () * fYAd; } } scale = (SCREENHEIGHT*vw) / (SCREENWIDTH * 200.0f); y1 = viewwindowy + vh / 2 - (ftexturemid * scale); y2 = y1 + (r.height * scale) + 1; if (!(mirror) != !(psp->Flags & PSPF_FLIP)) { fU2 = tex->GetSpriteUL(); fV1 = tex->GetSpriteVT(); fU1 = tex->GetSpriteUR(); fV2 = tex->GetSpriteVB(); } else { fU1 = tex->GetSpriteUL(); fV1 = tex->GetSpriteVT(); fU2 = tex->GetSpriteUR(); fV2 = tex->GetSpriteVB(); } if (tex->GetTransparent() || OverrideShader != -1) { gl_RenderState.AlphaFunc(GL_GEQUAL, 0.f); } gl_RenderState.Apply(); FQuadDrawer qd; qd.Set(0, x1, y1, 0, fU1, fV1); qd.Set(1, x1, y2, 0, fU1, fV2); qd.Set(2, x2, y1, 0, fU2, fV1); qd.Set(3, x2, y2, 0, fU2, fV2); qd.Render(GL_TRIANGLE_STRIP); gl_RenderState.AlphaFunc(GL_GEQUAL, 0.5f); } //========================================================================== // // // //========================================================================== static bool isBright(DPSprite *psp) { if (psp != nullptr && psp->GetState() != nullptr) { bool disablefullbright = false; FTextureID lump = sprites[psp->GetSprite()].GetSpriteFrame(psp->GetFrame(), 0, 0., nullptr); if (lump.isValid()) { FMaterial * tex = FMaterial::ValidateTexture(lump, false, false); if (tex) disablefullbright = tex->tex->gl_info.bDisableFullbright; } return psp->GetState()->GetFullbright() && !disablefullbright; } return false; } //========================================================================== // // R_DrawPlayerSprites // //========================================================================== void GLSceneDrawer::DrawPlayerSprites(sector_t * viewsector, bool hudModelStep) { bool brightflash = false; unsigned int i; int lightlevel=0; FColormap cm; sector_t * fakesec, fs; AActor * playermo=players[consoleplayer].camera; player_t * player=playermo->player; s3d::Stereo3DMode::getCurrentMode().AdjustPlayerSprites(); AActor *camera = r_viewpoint.camera; // this is the same as the software renderer if (!player || !r_drawplayersprites || !camera->player || (player->cheats & CF_CHASECAM) || (r_deathcamera && camera->health <= 0)) return; float bobx, boby, wx, wy; DPSprite *weapon; P_BobWeapon(camera->player, &bobx, &boby, r_viewpoint.TicFrac); // Interpolate the main weapon layer once so as to be able to add it to other layers. if ((weapon = camera->player->FindPSprite(PSP_WEAPON)) != nullptr) { if (weapon->firstTic) { wx = weapon->x; wy = weapon->y; } else { wx = weapon->oldx + (weapon->x - weapon->oldx) * r_viewpoint.TicFrac; wy = weapon->oldy + (weapon->y - weapon->oldy) * r_viewpoint.TicFrac; } } else { wx = 0; wy = 0; } if (FixedColormap) { lightlevel=255; cm.Clear(); fakesec = viewsector; } else { fakesec = gl_FakeFlat(viewsector, &fs, in_area, false); // calculate light level for weapon sprites lightlevel = gl_ClampLight(fakesec->lightlevel); // calculate colormap for weapon sprites if (viewsector->e->XFloor.ffloors.Size() && !(level.flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING)) { TArray & lightlist = viewsector->e->XFloor.lightlist; for(i=0;ifloorplane.ZatPoint(r_viewpoint.Pos); } if (lightbottomviewz) { cm = lightlist[i].extra_colormap; lightlevel = gl_ClampLight(*lightlist[i].p_lightlevel); break; } } } else { cm=fakesec->Colormap; if (level.flags3 & LEVEL3_NOCOLOREDSPRITELIGHTING) cm.ClearColor(); } lightlevel = gl_CalcLightLevel(lightlevel, getExtraLight(), true); if (glset.lightmode == 8) { // Korshun: the way based on max possible light level for sector like in software renderer. float min_L = 36.0 / 31.0 - ((lightlevel / 255.0) * (63.0 / 31.0)); // Lightlevel in range 0-63 if (min_L < 0) min_L = 0; else if (min_L > 1.0) min_L = 1.0; lightlevel = (1.0 - min_L) * 255; } else { lightlevel = (2 * lightlevel + 255) / 3; } lightlevel = gl_CheckSpriteGlow(viewsector, lightlevel, playermo->Pos()); } // Korshun: fullbright fog in opengl, render weapon sprites fullbright (but don't cancel out the light color!) if (glset.brightfog && ((level.flags&LEVEL_HASFADETABLE) || cm.FadeColor != 0)) { lightlevel = 255; } PalEntry ThingColor = (playermo->RenderStyle.Flags & STYLEF_ColorIsFixed) ? playermo->fillcolor : 0xffffff; ThingColor.a = 255; visstyle_t vis; vis.RenderStyle = STYLE_Count; vis.Alpha = playermo->Alpha; vis.Invert = false; playermo->AlterWeaponSprite(&vis); FRenderStyle RenderStyle; if (vis.RenderStyle == STYLE_Count) RenderStyle = playermo->RenderStyle; else RenderStyle = vis.RenderStyle; if (vis.Invert) { // this only happens for Strife's inverted weapon sprite RenderStyle.Flags |= STYLEF_InvertSource; } if (RenderStyle.AsDWORD == 0) { // This is RenderStyle None. return; } // Set the render parameters int OverrideShader = -1; float trans = 0.f; if (RenderStyle.BlendOp >= STYLEOP_Fuzz && RenderStyle.BlendOp <= STYLEOP_FuzzOrRevSub) { RenderStyle.CheckFuzz(); if (RenderStyle.BlendOp == STYLEOP_Fuzz) { if (gl_fuzztype != 0) { // Todo: implement shader selection here RenderStyle = LegacyRenderStyles[STYLE_Translucent]; OverrideShader = gl_fuzztype + 4; trans = 0.99f; // trans may not be 1 here } else { RenderStyle.BlendOp = STYLEOP_Shadow; } } } gl_SetRenderStyle(RenderStyle, false, false); if (RenderStyle.Flags & STYLEF_TransSoulsAlpha) { trans = transsouls; } else if (RenderStyle.Flags & STYLEF_Alpha1) { trans = 1.f; } else if (trans == 0.f) { trans = vis.Alpha; } // now draw the different layers of the weapon gl_RenderState.EnableBrightmap(true); PalEntry finalcol(ThingColor.a, ThingColor.r * viewsector->SpecialColors[sector_t::sprites].r / 255, ThingColor.g * viewsector->SpecialColors[sector_t::sprites].g / 255, ThingColor.b * viewsector->SpecialColors[sector_t::sprites].b / 255); gl_RenderState.SetObjectColor(finalcol); gl_RenderState.AlphaFunc(GL_GEQUAL, gl_mask_sprite_threshold); // hack alert! Rather than changing everything in the underlying lighting code let's just temporarily change // light mode here to draw the weapon sprite. int oldlightmode = glset.lightmode; if (glset.lightmode == 8) glset.lightmode = 2; for(DPSprite *psp = player->psprites; psp != nullptr && psp->GetID() < PSP_TARGETCENTER; psp = psp->GetNext()) { if (psp->GetState() != nullptr) { FColormap cmc = cm; int ll = lightlevel; if (isBright(psp)) { if (fakesec == viewsector || in_area != area_below) { cmc.MakeWhite(); } else { // under water areas keep most of their color for fullbright objects cmc.LightColor.r = (3 * cmc.LightColor.r + 0xff) / 4; cmc.LightColor.g = (3*cmc.LightColor.g + 0xff)/4; cmc.LightColor.b = (3*cmc.LightColor.b + 0xff)/4; } ll = 255; } // set the lighting parameters if (RenderStyle.BlendOp == STYLEOP_Shadow) { gl_RenderState.SetColor(0.2f, 0.2f, 0.2f, 0.33f, cmc.Desaturation); } else { if (gl_lights && GLRenderer->mLightCount && FixedColormap == CM_DEFAULT && gl_light_sprites) { gl_SetDynSpriteLight(playermo, NULL); } SetColor(ll, 0, cmc, trans, true); } if (psp->firstTic) { // Can't interpolate the first tic. psp->firstTic = false; psp->oldx = psp->x; psp->oldy = psp->y; } float sx = psp->oldx + (psp->x - psp->oldx) * r_viewpoint.TicFrac; float sy = psp->oldy + (psp->y - psp->oldy) * r_viewpoint.TicFrac; if (psp->Flags & PSPF_ADDBOB) { sx += bobx; sy += boby; } if (psp->Flags & PSPF_ADDWEAPON && psp->GetID() != PSP_WEAPON) { sx += wx; sy += wy; } DrawPSprite(player, psp, sx, sy, hudModelStep, OverrideShader, !!(RenderStyle.Flags & STYLEF_RedIsAlpha)); } } gl_RenderState.SetObjectColor(0xffffffff); gl_RenderState.SetDynLight(0, 0, 0); gl_RenderState.EnableBrightmap(false); glset.lightmode = oldlightmode; } //========================================================================== // // R_DrawPlayerSprites // //========================================================================== void GLSceneDrawer::DrawTargeterSprites() { AActor * playermo=players[consoleplayer].camera; player_t * player=playermo->player; if(!player || playermo->renderflags&RF_INVISIBLE || !r_drawplayersprites || GLRenderer->mViewActor!=playermo) return; gl_RenderState.EnableBrightmap(false); gl_RenderState.BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); gl_RenderState.AlphaFunc(GL_GEQUAL,gl_mask_sprite_threshold); gl_RenderState.BlendEquation(GL_FUNC_ADD); gl_RenderState.ResetColor(); gl_RenderState.SetTextureMode(TM_MODULATE); // The Targeter's sprites are always drawn normally. for (DPSprite *psp = player->FindPSprite(PSP_TARGETCENTER); psp != nullptr; psp = psp->GetNext()) { if (psp->GetState() != nullptr) DrawPSprite(player, psp, psp->x, psp->y, false, 0, false); } }