📄 unitdrawer.cpp
字号:
#include "StdAfx.h"
#include "UnitDrawer.h"
#include "myMath.h"
#include "LogOutput.h"
#include "3DModelParser.h"
#include "Game/Camera.h"
#include "Game/GameHelper.h"
#include "Game/GameSetup.h"
#include "Game/SelectedUnits.h"
#include "Game/Team.h"
#include "Lua/LuaMaterial.h"
#include "Lua/LuaUnitMaterial.h"
#include "Map/BaseGroundDrawer.h"
#include "Map/Ground.h"
#include "Map/ReadMap.h"
#include "Platform/ConfigHandler.h"
#include "Rendering/Env/BaseSky.h"
#include "Rendering/Env/BaseWater.h"
#include "Rendering/FartextureHandler.h"
#include "Rendering/GL/myGL.h"
#include "Rendering/GL/VertexArray.h"
#include "Rendering/GroundDecalHandler.h"
#include "Rendering/IconHandler.h"
#include "Rendering/ShadowHandler.h"
#include "Rendering/Textures/Bitmap.h"
#include "Rendering/Textures/TextureHandler.h"
#include "Sim/Misc/LosHandler.h"
#include "Sim/Misc/RadarHandler.h"
#include "Sim/Units/CommandAI/BuilderCAI.h"
#include "Sim/Units/UnitDef.h"
#include "Sim/Units/UnitDefHandler.h"
#include "Sim/Units/Unit.h"
#include "Sim/Units/UnitHandler.h"
#include "mmgr.h"
CUnitDrawer* unitDrawer;
using namespace std;
static bool luaDrawing = false; // FIXME
static float GetLODFloat(const string& name, float def)
{
// NOTE: the inverse of the value is used
char buf[64];
SNPRINTF(buf, sizeof(buf), "%.3f", def);
const string valueStr = configHandler.GetString(name, buf);
char* end;
float value = (float)strtod(valueStr.c_str(), &end);
if ((end == valueStr.c_str()) || (value <= 0.0f)) {
return (1.0f / def);
}
return (1.0f / value);
}
CUnitDrawer::CUnitDrawer(void)
: showHealthBars(true),
updateFace(0)
{
if (texturehandler == 0) {
texturehandler = SAFE_NEW CTextureHandler;
}
unitDrawDist = configHandler.GetInt("UnitLodDist",200);
unitIconDist = configHandler.GetInt("UnitIconDist",200);
iconLength = 750 * unitIconDist * unitIconDist;
specTexSize = configHandler.GetInt("CubeTexSizeSpecular", 128);
reflTexSize = configHandler.GetInt("CubeTexSizeReflection", 128);
LODScale = GetLODFloat("LODScale", 1.0f);
LODScaleShadow = GetLODFloat("LODScaleShadow", 1.0f);
LODScaleReflection = GetLODFloat("LODScaleReflection", 1.0f);
LODScaleRefraction = GetLODFloat("LODScaleRefraction", 1.0f);
CBitmap white;
white.Alloc(1, 1);
for (int a = 0; a < 4; ++a) {
white.mem[a] = 255;
}
whiteTex=white.CreateTexture(false);
unitAmbientColor=readmap->mapDefParser.GetFloat3(float3(0.4f,0.4f,0.4f),"MAP\\LIGHT\\UnitAmbientColor");
unitSunColor=readmap->mapDefParser.GetFloat3(float3(0.7f,0.7f,0.7f),"MAP\\LIGHT\\UnitSunColor");
float3 specularSunColor=readmap->mapDefParser.GetFloat3(unitSunColor,"MAP\\LIGHT\\SpecularSunColor");
readmap->mapDefParser.GetDef(unitShadowDensity,"0.8","MAP\\LIGHT\\UnitShadowDensity");
advShading=!!configHandler.GetInt("AdvUnitShading", GLEW_ARB_fragment_program ? 1 : 0);
if (advShading && !GLEW_ARB_fragment_program) {
logOutput.Print("You are missing an OpenGL extension needed to use advanced unit shading (GL_ARB_fragment_program)");
advShading = false;
}
if (advShading)
{
unitVP = LoadVertexProgram("unit.vp");
unitFP = LoadFragmentProgram("unit.fp");
unitS3oVP = LoadVertexProgram("units3o.vp");
unitS3oFP = LoadFragmentProgram("units3o.fp");
if (shadowHandler->canUseShadows) {
unitShadowFP = LoadFragmentProgram("unit_shadow.fp");
unitShadowS3oFP = LoadFragmentProgram("units3o_shadow.fp");
unitShadowGenVP = LoadVertexProgram("unit_genshadow.vp");
} else {
unitShadowFP = 0;
unitShadowS3oFP = 0;
unitShadowGenVP = 0;
}
glGenTextures(1,&boxtex);
glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, boxtex);
glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,0,GL_RGBA8,reflTexSize,reflTexSize,0,GL_RGBA,GL_UNSIGNED_BYTE,0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,0,GL_RGBA8,reflTexSize,reflTexSize,0,GL_RGBA,GL_UNSIGNED_BYTE,0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,0,GL_RGBA8,reflTexSize,reflTexSize,0,GL_RGBA,GL_UNSIGNED_BYTE,0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,0,GL_RGBA8,reflTexSize,reflTexSize,0,GL_RGBA,GL_UNSIGNED_BYTE,0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,0,GL_RGBA8,reflTexSize,reflTexSize,0,GL_RGBA,GL_UNSIGNED_BYTE,0);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,0,GL_RGBA8,reflTexSize,reflTexSize,0,GL_RGBA,GL_UNSIGNED_BYTE,0);
glGenTextures(1,&specularTex);
glBindTexture(GL_TEXTURE_CUBE_MAP_ARB, specularTex);
glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP_EXT, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP_ARB, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
CreateSpecularFace(GL_TEXTURE_CUBE_MAP_POSITIVE_X_ARB,specTexSize,float3( 1, 1, 1),float3( 0, 0,-2),float3(0,-2, 0),gs->sunVector,100,specularSunColor);
CreateSpecularFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_X_ARB,specTexSize,float3(-1, 1,-1),float3( 0, 0, 2),float3(0,-2, 0),gs->sunVector,100,specularSunColor);
CreateSpecularFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Y_ARB,specTexSize,float3(-1 ,1,-1),float3( 2, 0, 0),float3(0, 0, 2),gs->sunVector,100,specularSunColor);
CreateSpecularFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_ARB,specTexSize,float3(-1,-1, 1),float3( 2, 0, 0),float3(0, 0,-2),gs->sunVector,100,specularSunColor);
CreateSpecularFace(GL_TEXTURE_CUBE_MAP_POSITIVE_Z_ARB,specTexSize,float3(-1, 1, 1),float3( 2, 0, 0),float3(0,-2, 0),gs->sunVector,100,specularSunColor);
CreateSpecularFace(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_ARB,specTexSize,float3( 1, 1,-1),float3(-2, 0, 0),float3(0,-2, 0),gs->sunVector,100,specularSunColor);
}
}
CUnitDrawer::~CUnitDrawer(void)
{
glDeleteTextures(1, &whiteTex);
if (advShading) {
glSafeDeleteProgram(unitVP);
glSafeDeleteProgram(unitFP);
glSafeDeleteProgram(unitShadowFP);
glSafeDeleteProgram(unitS3oVP);
glSafeDeleteProgram(unitS3oFP);
glSafeDeleteProgram(unitShadowS3oFP);
glSafeDeleteProgram(unitShadowGenVP);
glDeleteTextures(1, &boxtex);
glDeleteTextures(1, &specularTex);
}
std::list<GhostBuilding*>::iterator gbi;
for (gbi = ghostBuildings.begin(); gbi != ghostBuildings.end(); /* no inc */) {
if ((*gbi)->decal) {
(*gbi)->decal->gbOwner = 0;
}
delete *gbi;
gbi = ghostBuildings.erase(gbi);
}
for (gbi = ghostBuildingsS3O.begin(); gbi != ghostBuildingsS3O.end(); /* no inc */) {
if ((*gbi)->decal) {
(*gbi)->decal->gbOwner = 0;
}
delete *gbi;
gbi = ghostBuildingsS3O.erase(gbi);
}
}
void CUnitDrawer::Update(void)
{
while (!tempDrawUnits.empty() && tempDrawUnits.begin()->first < gs->frameNum - 1) {
tempDrawUnits.erase(tempDrawUnits.begin());
}
while (!tempTransparentDrawUnits.empty() && tempTransparentDrawUnits.begin()->first <= gs->frameNum) {
tempTransparentDrawUnits.erase(tempTransparentDrawUnits.begin());
}
}
extern GLfloat FogLand[];
inline void CUnitDrawer::DrawUnitLOD(CUnit* unit)
{
if (unit->isCloaked) {
const LuaMatType matType =
(water->drawReflection) ? LUAMAT_ALPHA_REFLECT : LUAMAT_ALPHA;
LuaUnitMaterial& unitMat = unit->luaMats[matType];
const unsigned lod = unit->CalcLOD(unitMat.GetLastLOD());
unit->currentLOD = lod;
LuaUnitLODMaterial* lodMat = unitMat.GetMaterial(lod);
if ((lodMat != NULL) && lodMat->IsActive()) {
lodMat->AddUnit(unit);
} else {
if (unit->model->textureType) {
drawCloakedS3O.push_back(unit);
} else {
drawCloaked.push_back(unit);
}
}
}
else {
const LuaMatType matType =
(water->drawReflection) ? LUAMAT_OPAQUE_REFLECT : LUAMAT_OPAQUE;
LuaUnitMaterial& unitMat = unit->luaMats[matType];
const unsigned lod = unit->CalcLOD(unitMat.GetLastLOD());
unit->currentLOD = lod;
LuaUnitLODMaterial* lodMat = unitMat.GetMaterial(lod);
if ((lodMat != NULL) && lodMat->IsActive()) {
lodMat->AddUnit(unit);
} else {
if (unit->model->textureType) {
QueS3ODraw(unit, unit->model->textureType);
} else {
unit->Draw();
}
}
}
}
inline void CUnitDrawer::DrawUnit(CUnit* unit)
{
if (unit->lodCount > 0) {
DrawUnitLOD(unit);
return;
}
if (unit->model->textureType) {
if (unit->isCloaked) {
drawCloakedS3O.push_back(unit);
} else {
QueS3ODraw(unit, unit->model->textureType);
}
} else {
if (unit->isCloaked) {
drawCloaked.push_back(unit);
} else {
unit->Draw();
}
}
}
void CUnitDrawer::Draw(bool drawReflection, bool drawRefraction)
{
ASSERT_UNSYNCED_MODE;
vector<CUnit*> drawFar;
vector<CUnit*> drawStat;
drawCloaked.clear();
drawCloakedS3O.clear();
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
glFogfv(GL_FOG_COLOR,FogLand);
vector<CUnit*> drawIcon;
vector<CUnit*> drawRadarIcon;
if (drawReflection) {
CUnit::SetLODFactor(LODScale * LODScaleReflection);
} else if (drawRefraction) {
CUnit::SetLODFactor(LODScale * LODScaleRefraction);
} else {
CUnit::SetLODFactor(LODScale);
}
SetupForUnitDrawing();
#ifdef DIRECT_CONTROL_ALLOWED
CUnit* excludeUnit = drawReflection ? NULL : gu->directControl;
#endif
for (list<CUnit*>::iterator usi = uh->activeUnits.begin(); usi != uh->activeUnits.end(); ++usi) {
CUnit* unit = *usi;
#ifdef DIRECT_CONTROL_ALLOWED
if (unit == excludeUnit) {
continue;
}
#endif
if (unit->noDraw) {
continue;
}
if (camera->InView(unit->midPos, unit->radius + 30)) {
if (gs->Ally(unit->allyteam,gu->myAllyTeam) ||
(unit->losStatus[gu->myAllyTeam] & LOS_INLOS) ||
gu->spectatingFullView) {
if (drawReflection) {
float3 zeroPos;
if (unit->midPos.y < 0.0f) {
zeroPos = unit->midPos;
} else {
const float dif = unit->midPos.y - camera->pos.y;
zeroPos = camera->pos * (unit->midPos.y / dif) +
unit->midPos * (-camera->pos.y / dif);
}
if (ground->GetApproximateHeight(zeroPos.x, zeroPos.z) > unit->radius) {
continue;
}
}
if (drawRefraction) {
if (unit->pos.y > 0.0f) {
continue;
}
}
float sqDist = (unit->pos-camera->pos).SqLength();
float iconDistMult = iconHandler->GetDistance(unit->unitDef->iconType);
float realIconLength = iconLength * (iconDistMult * iconDistMult);
if (sqDist>realIconLength) {
drawIcon.push_back(unit);
unit->isIcon = true;
}
else {
unit->isIcon = false;
float farLength = unit->sqRadius * (unitDrawDist * unitDrawDist);
if (sqDist>farLength) {
drawFar.push_back(unit);
} else {
DrawUnit(unit);
}
if ((sqDist < (unitDrawDist * unitDrawDist * 500)) && showHealthBars) {
drawStat.push_back(unit);
}
}
}
else if (unit->losStatus[gu->myAllyTeam] & LOS_PREVLOS) {
unit->isIcon = true;
if ((!gameSetup || gameSetup->ghostedBuildings) && !(unit->mobility)) {
// it's a building we've had LOS on once,
// add it to the vector of cloaked units
float sqDist = (unit->pos-camera->pos).SqLength();
float iconDistMult = iconHandler->GetDistance(unit->unitDef->iconType);
float realIconLength = iconLength * (iconDistMult * iconDistMult);
if (sqDist < realIconLength) {
if (unit->model->textureType) {
drawCloakedS3O.push_back(unit);
} else {
drawCloaked.push_back(unit);
}
unit->isIcon = false;
}
}
if ((unit->losStatus[gu->myAllyTeam] & LOS_INRADAR)) {
if (!(unit->losStatus[gu->myAllyTeam] & LOS_CONTRADAR)) {
drawRadarIcon.push_back(unit);
} else if (unit->isIcon) {
// this prevents us from drawing icons on top of ghosted buildings
drawIcon.push_back(unit);
}
}
} else if ((unit->losStatus[gu->myAllyTeam] & LOS_INRADAR)) {
drawRadarIcon.push_back(unit);
}
}
}
std::multimap<int, TempDrawUnit>::iterator ti;
for (ti = tempDrawUnits.begin(); ti != tempDrawUnits.end(); ++ti) {
if (camera->InView(ti->second.pos, 100)) {
glPushMatrix();
glTranslatef3(ti->second.pos);
glRotatef(ti->second.rotation * 180 / PI, 0, 1, 0);
ti->second.unitdef->LoadModel(ti->second.team)->DrawStatic();
glPopMatrix();
}
}
DrawQuedS3O();
CleanUpUnitDrawing();
DrawOpaqueShaderUnits();
va = GetVertexArray();
va->Initialize();
glAlphaFunc(GL_GREATER, 0.8f);
glEnable(GL_ALPHA_TEST);
glBindTexture(GL_TEXTURE_2D, fartextureHandler->farTexture);
camNorm = camera->forward;
camNorm.y = -0.1f;
camNorm.Normalize();
glColor3f(1, 1, 1);
glEnable(GL_FOG);
glFogfv(GL_FOG_COLOR, FogLand);
for (vector<CUnit*>::iterator usi = drawFar.begin(); usi != drawFar.end(); usi++) {
DrawFar(*usi);
}
va->DrawArrayTN(GL_QUADS);
if (!drawReflection) {
// Draw unit icons and radar blips.
glAlphaFunc(GL_GREATER, 0.5f);
vector<CUnit*>::iterator ui;
for (ui = drawIcon.begin(); ui != drawIcon.end(); ++ui) {
DrawIcon(*ui, false);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -