From c82e07514d9c197277f1681a9544d18f0595319a Mon Sep 17 00:00:00 2001 From: rtri Date: Thu, 17 Mar 2016 19:55:12 +0100 Subject: [PATCH] fix #5175 --- rts/Game/Camera.cpp | 8 +- rts/Game/Camera.h | 2 +- rts/Rendering/FarTextureHandler.cpp | 211 +++++++++++++--------------- rts/Rendering/FarTextureHandler.h | 26 ++-- 4 files changed, 112 insertions(+), 135 deletions(-) diff --git a/rts/Game/Camera.cpp b/rts/Game/Camera.cpp index ee9d7cf97d2..7a50381a4c9 100644 --- a/rts/Game/Camera.cpp +++ b/rts/Game/Camera.cpp @@ -103,7 +103,7 @@ void CCamera::Update(bool updateDirs, bool updateMats, bool updatePort) if (updateDirs) UpdateDirsFromRot(rot); if (updateMats) - UpdateMatrices(); + UpdateMatrices(globalRendering->viewSizeX, globalRendering->viewSizeY, globalRendering->aspectRatio); if (updatePort) UpdateViewPort(globalRendering->viewPosX, 0, globalRendering->viewSizeX, globalRendering->viewSizeY); @@ -154,15 +154,15 @@ void CCamera::UpdateFrustum() } } -void CCamera::UpdateMatrices() +void CCamera::UpdateMatrices(unsigned int vsx, unsigned int vsy, float var) { // recalculate the projection transform switch (projType) { case PROJTYPE_PERSP: { - gluPerspectiveSpring(globalRendering->aspectRatio, frustumScales.z, frustumScales.w); + gluPerspectiveSpring(var, frustumScales.z, frustumScales.w); } break; case PROJTYPE_ORTHO: { - glOrthoScaledSpring(globalRendering->viewSizeX, globalRendering->viewSizeY, frustumScales.z, frustumScales.w); + glOrthoScaledSpring(vsx, vsy, frustumScales.z, frustumScales.w); } break; default: { assert(false); diff --git a/rts/Game/Camera.h b/rts/Game/Camera.h index 87cd38a17d3..32ae9e9d1dd 100644 --- a/rts/Game/Camera.h +++ b/rts/Game/Camera.h @@ -188,7 +188,7 @@ class CCamera public: void UpdateViewRange(); void UpdateFrustum(); - void UpdateMatrices(); + void UpdateMatrices(unsigned int vsx, unsigned int vsy, float var); void UpdateViewPort(int px, int py, int sx, int sy); private: diff --git a/rts/Rendering/FarTextureHandler.cpp b/rts/Rendering/FarTextureHandler.cpp index b6ae73fa53d..66fd8222fe5 100644 --- a/rts/Rendering/FarTextureHandler.cpp +++ b/rts/Rendering/FarTextureHandler.cpp @@ -4,21 +4,14 @@ #include "FarTextureHandler.h" #include "Game/Camera.h" -#include "Game/GameVersion.h" #include "Rendering/UnitDrawer.h" #include "Rendering/GlobalRendering.h" #include "Rendering/Env/ISky.h" #include "Rendering/GL/VertexArray.h" -#include "Rendering/Textures/Bitmap.h" -#include "Rendering/Textures/S3OTextureHandler.h" #include "Rendering/Models/3DModel.h" #include "Sim/Objects/SolidObject.h" #include "System/myMath.h" #include "System/Log/ILog.h" -#include "System/bitops.h" - -#include "string.h" - #define LOG_SECTION_FAR_TEXTURE_HANDLER "FarTextureHandler" LOG_REGISTER_SECTION_GLOBAL(LOG_SECTION_FAR_TEXTURE_HANDLER) @@ -29,28 +22,27 @@ LOG_REGISTER_SECTION_GLOBAL(LOG_SECTION_FAR_TEXTURE_HANDLER) #endif #define LOG_SECTION_CURRENT LOG_SECTION_FAR_TEXTURE_HANDLER +#define NUM_ICON_ORIENTATIONS 8 -CFarTextureHandler* farTextureHandler = NULL; -const int CFarTextureHandler::iconSizeX = 32; -const int CFarTextureHandler::iconSizeY = 32; -const int CFarTextureHandler::numOrientations = 8; +CFarTextureHandler* farTextureHandler = nullptr; CFarTextureHandler::CFarTextureHandler() { farTextureID = 0; usedFarTextures = 0; - // ATI supports 16K textures, which might be a bit too much - // for this purpose,so we limit it to 4K - const int maxTexSize = std::min(globalRendering->maxTextureSize, 4096); - - texSizeX = maxTexSize; - texSizeY = std::max(iconSizeY, 4 * numOrientations * iconSizeX * iconSizeY / texSizeX); // minimum space for 4 icons - texSizeY = next_power_of_2(texSizeY); + // ATI supports 16K textures, but that might be a bit too much + // for this purpose so limit the atlas to 4K (still sufficient) + iconSize.x = 32 * 4; + iconSize.y = 32 * 4; + texSize.x = std::min(globalRendering->maxTextureSize, 4096); + texSize.y = std::max(iconSize.y, 4 * NUM_ICON_ORIENTATIONS * iconSize.x * iconSize.y / texSize.x); // minimum space for 4 icons + texSize.y = next_power_of_2(texSize.y); - if (SpringVersion::IsHeadless()) - return; + #ifdef HEADLESS + return; + #endif if (!fbo.IsValid()) { LOG_L(L_WARNING, "framebuffer not valid!"); @@ -63,12 +55,12 @@ CFarTextureHandler::CFarTextureHandler() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texSizeX, texSizeY, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texSize.x, texSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0); fbo.Bind(); fbo.AttachTexture(farTextureID); - const bool status = fbo.CheckStatus("FARTEXTURE"); - if (status) { + + if (fbo.CheckStatus("FARTEXTURE")) { glClearColor(0.0f, 0.0f, 0.0f, 0.0f); glClear(GL_COLOR_BUFFER_BIT); } @@ -81,7 +73,7 @@ CFarTextureHandler::CFarTextureHandler() CFarTextureHandler::~CFarTextureHandler() { glDeleteTextures(1, &farTextureID); - queuedForRender.clear(); + drawQueue.clear(); } @@ -90,30 +82,25 @@ CFarTextureHandler::~CFarTextureHandler() */ int2 CFarTextureHandler::GetTextureCoordsInt(const int farTextureNum, const int orientation) const { - const int texnum = (farTextureNum * numOrientations) + orientation; + const int texnum = (farTextureNum * NUM_ICON_ORIENTATIONS) + orientation; - const int row = texnum / (texSizeX / iconSizeX); - const int col = texnum - row * (texSizeX / iconSizeX); + const int row = texnum / (texSize.x / iconSize.x); + const int col = texnum - row * (texSize.x / iconSize.x); return int2(col, row); } - /** * @brief Returns the TexCoords of a FarTexture in the TextureAtlas. */ float2 CFarTextureHandler::GetTextureCoords(const int farTextureNum, const int orientation) const { - float2 texcoords; + const int2 texIndex = GetTextureCoordsInt(farTextureNum, orientation); - const int texnum = (farTextureNum * numOrientations) + orientation; + float2 texCoors; + texCoors.x = (float(iconSize.x) / texSize.x) * texIndex.x; + texCoors.y = (float(iconSize.y) / texSize.y) * texIndex.y; - const int row = texnum / (texSizeX / iconSizeX); - const int col = texnum - row * (texSizeX / iconSizeX); - - texcoords.x = (float(iconSizeX) / texSizeX) * col; - texcoords.y = (float(iconSizeY) / texSizeY) * row; - - return texcoords; + return texCoors; } @@ -122,7 +109,7 @@ bool CFarTextureHandler::HaveFarIcon(const CSolidObject* obj) const const int teamID = obj->team; const int modelID = obj->model->id; - return ((cache.size() > teamID) && (cache[teamID].size() > modelID) && (cache[teamID][modelID] != 0)); + return ((iconCache.size() > teamID) && (iconCache[teamID].size() > modelID) && (iconCache[teamID][modelID] != 0)); } @@ -134,25 +121,20 @@ void CFarTextureHandler::CreateFarTexture(const CSolidObject* obj) const S3DModel* model = obj->model; // make space in the std::vectors - if (obj->team >= (int)cache.size()) - cache.resize(obj->team + 1); + if (obj->team >= (int)iconCache.size()) + iconCache.resize(obj->team + 1); - if (model->id >= (int)cache[obj->team].size()) - cache[obj->team].resize(model->id + 1, 0); + if (model->id >= (int)iconCache[obj->team].size()) + iconCache[obj->team].resize(model->id + 1, 0); - cache[obj->team][model->id] = -1; + iconCache[obj->team][model->id] = -1; // enough free space in the atlas? if (!CheckResizeAtlas()) return; - // NOTE: - // the icons are RTT'ed using a snapshot of the - // current state (advModelShading, sunDir, etc) - // and will not track later state-changes - fbo.Bind(); - fbo.CreateRenderBuffer(GL_DEPTH_ATTACHMENT_EXT, GL_DEPTH_COMPONENT16, texSizeX, texSizeY); + fbo.CreateRenderBuffer(GL_DEPTH_ATTACHMENT_EXT, GL_DEPTH_COMPONENT16, texSize.x, texSize.y); fbo.CheckStatus("FARTEXTURE"); glPushAttrib(GL_ALL_ATTRIB_BITS); @@ -165,51 +147,48 @@ void CFarTextureHandler::CreateFarTexture(const CSolidObject* obj) glFogf(GL_FOG_END, 1e6); glFogf(GL_FOG_DENSITY, 1.0f); + // NOTE: + // the icons are RTT'ed using a snapshot of the + // current state (advModelShading, sunDir, etc) + // and will not track later state-changes unitDrawer->SetupOpaqueDrawing(false); unitDrawer->PushModelRenderState(model); unitDrawer->SetTeamColour(obj->team); - const float modelRadius = model->GetDrawRadius(); + // can pick any perspective-type + CCamera iconCam(CCamera::CAMTYPE_PLAYER); + CMatrix44f viewMat; + + // twice the radius is not quite far away enough for some models + viewMat.Translate(float3(0.0f, 0.0f, -obj->GetDrawRadius() * (2.0f + 1.0f))); + viewMat.Scale(float3(-1.0f, 1.0f, 1.0f)); + viewMat.RotateX(-60.0f * (M_PI / 180.0f)); // overwrite the matrices set by SetupOpaqueDrawing // - // RTT with a top-down view; the view-matrix must be - // on the PROJECTION stack for the model shaders - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadIdentity(); - glOrtho(-modelRadius, modelRadius, -modelRadius, modelRadius, -modelRadius, modelRadius); - glRotatef(45.0f, 1.0f, 0.0f, 0.0f); - glScalef(-1.0f, 1.0f, 1.0f); - - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); - glLoadIdentity(); - - for (int orient = 0; orient < numOrientations; ++orient) { + // RTT with a 60-degree top-down view and 1:1 AR perspective + // model shaders expect view-matrix on the PROJECTION stack! + iconCam.UpdateMatrices(1, 1, 1.0f); + iconCam.SetProjMatrix(iconCam.GetProjectionMatrix() * viewMat); + iconCam.SetViewMatrix(viewMat.LoadIdentity()); + iconCam.LoadMatrices(); + + for (int orient = 0; orient < NUM_ICON_ORIENTATIONS; ++orient) { // setup viewport const int2 pos = GetTextureCoordsInt(usedFarTextures, orient); - glViewport(pos.x * iconSizeX, pos.y * iconSizeY, iconSizeX, iconSizeY); + glViewport(pos.x * iconSize.x, pos.y * iconSize.y, iconSize.x, iconSize.y); glClear(GL_DEPTH_BUFFER_BIT); glPushMatrix(); - glTranslatef(0.0f, -model->height * 0.5f, 0.0f); - - // draw model + // draw (static-pose) model model->DrawStatic(); - glPopMatrix(); - // rotate by 360 / numOrientations degrees for the next orientation - glRotatef(-360.0f / numOrientations, 0.0f, 1.0f, 0.0f); + // rotate for the next orientation + glRotatef(-360.0f / NUM_ICON_ORIENTATIONS, 0.0f, 1.0f, 0.0f); } - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - unitDrawer->PopModelRenderState(model); unitDrawer->ResetOpaqueDrawing(false); @@ -219,62 +198,61 @@ void CFarTextureHandler::CreateFarTexture(const CSolidObject* obj) fbo.Detach(GL_DEPTH_ATTACHMENT_EXT); fbo.Unbind(); - cache[obj->team][model->id] = ++usedFarTextures; + iconCache[obj->team][model->id] = ++usedFarTextures; } void CFarTextureHandler::DrawFarTexture(const CSolidObject* obj, CVertexArray* va) { - const int farTextureNum = cache[obj->team][obj->model->id]; + const int farTextureNum = iconCache[obj->team][obj->model->id]; // not found in the atlas if (farTextureNum <= 0) return; - const float3 interPos = obj->drawPos + UpVector * obj->model->height * 0.5f; - // indicates the orientation to draw - static const int USHRT_MAX_ = (1 << 16); - const int orient_step = USHRT_MAX_ / numOrientations; + const int USHRT_MAX_ = (1 << 16) - 1; + const int orientStep = USHRT_MAX_ / NUM_ICON_ORIENTATIONS; int orient = GetHeadingFromVector(-camera->GetDir().x, -camera->GetDir().z) - obj->heading; - orient += USHRT_MAX_; // make it positive only - orient += (orient_step >> 1); // we want that frontdir is from -orient_step/2 upto orient_step/2 - orient %= USHRT_MAX_; // we have an angle so it's periodical - orient /= orient_step; // get the final direction index - - const float iconSizeX = float(this->iconSizeX) / texSizeX; - const float iconSizeY = float(this->iconSizeY) / texSizeY; - const float2 texcoords = GetTextureCoords(farTextureNum - 1, orient); - - const float3 curad = camera->GetUp() * obj->model->radius; - const float3 crrad = camera->GetRight() * obj->model->radius; - - va->AddVertexQT(interPos - curad + crrad, texcoords.x, texcoords.y ); - va->AddVertexQT(interPos + curad + crrad, texcoords.x, texcoords.y + iconSizeY); - va->AddVertexQT(interPos + curad - crrad, texcoords.x + iconSizeX, texcoords.y + iconSizeY); - va->AddVertexQT(interPos - curad - crrad, texcoords.x + iconSizeX, texcoords.y ); + orient += USHRT_MAX_; // make it positive only + orient += (orientStep >> 1); // we want that frontdir is from -orientStep/2 upto orientStep/2 + orient %= USHRT_MAX_; // we have an angle so it's periodical + orient /= orientStep; // get the final direction index + + const float2 objIconSize = {float(iconSize.x) / texSize.x, float(iconSize.y) / texSize.y}; + const float2 objTexCoors = GetTextureCoords(farTextureNum - 1, orient); + + // have to draw above ground, or quad will be clipped + const float3 pos = obj->drawPos + UpVector * obj->GetDrawRadius() * 0.5f; + const float3 upv = camera->GetUp() * obj->GetDrawRadius(); + const float3 rgv = camera->GetRight() * obj->GetDrawRadius(); + + va->AddVertexQT(pos - upv + rgv, objTexCoors.x, objTexCoors.y ); + va->AddVertexQT(pos + upv + rgv, objTexCoors.x, objTexCoors.y + objIconSize.y); + va->AddVertexQT(pos + upv - rgv, objTexCoors.x + objIconSize.x, objTexCoors.y + objIconSize.y); + va->AddVertexQT(pos - upv - rgv, objTexCoors.x + objIconSize.x, objTexCoors.y ); } void CFarTextureHandler::Queue(const CSolidObject* obj) { - queuedForRender.push_back(obj); + drawQueue.push_back(obj); } void CFarTextureHandler::Draw() { - if (queuedForRender.empty()) + if (drawQueue.empty()) return; if (!fbo.IsValid()) { - queuedForRender.clear(); + drawQueue.clear(); return; } // create new far-icons - for (const CSolidObject* obj: queuedForRender) { + for (const CSolidObject* obj: drawQueue) { if (!HaveFarIcon(obj)) { CreateFarTexture(obj); } @@ -294,8 +272,9 @@ void CFarTextureHandler::Draw() CVertexArray* va = GetVertexArray(); va->Initialize(); - va->EnlargeArrays(queuedForRender.size() * 4, 0, VA_SIZE_T); - for (const CSolidObject* obj: queuedForRender) { + va->EnlargeArrays(drawQueue.size() * 4, 0, VA_SIZE_T); + + for (const CSolidObject* obj: drawQueue) { DrawFarTexture(obj, va); } @@ -303,36 +282,37 @@ void CFarTextureHandler::Draw() glDisable(GL_ALPHA_TEST); } - queuedForRender.clear(); + drawQueue.clear(); } bool CFarTextureHandler::CheckResizeAtlas() { - const unsigned int maxSprites = ((texSizeX / iconSizeX) * (texSizeY / iconSizeY) / numOrientations) - 1; + const unsigned int maxSprites = ((texSize.x / iconSize.x) * (texSize.y / iconSize.y) / NUM_ICON_ORIENTATIONS) - 1; if (usedFarTextures + 1 <= maxSprites) return true; - const int oldTexSizeY = texSizeY; + const int oldTexSizeY = texSize.y; if (globalRendering->supportNPOTs) { - texSizeY += std::max(iconSizeY, 4 * numOrientations * iconSizeX * iconSizeY / texSizeX); // make space for minimum 4 additional icons + // make space for minimum 4 additional icons + texSize.y += std::max(iconSize.y, 4 * NUM_ICON_ORIENTATIONS * iconSize.x * iconSize.y / texSize.x); } else { - texSizeY <<= 1; + texSize.y <<= 1; } - if (texSizeY > globalRendering->maxTextureSize) { + if (texSize.y > globalRendering->maxTextureSize) { LOG_L(L_DEBUG, "Out of farTextures"); - texSizeY = oldTexSizeY; + texSize.y = oldTexSizeY; return false; } - unsigned char* oldPixels = new unsigned char[texSizeX*texSizeY*4]; + std::vector oldPixels(texSize.x * texSize.y * 4); glBindTexture(GL_TEXTURE_2D, farTextureID); - glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, oldPixels); //TODO use the FBO? - memset(oldPixels + texSizeX*oldTexSizeY*4, 0, texSizeX*(texSizeY - oldTexSizeY)*4); + glGetTexImage(GL_TEXTURE_2D, 0, GL_RGBA, GL_UNSIGNED_BYTE, &oldPixels[0]); //TODO use the FBO? + memset(&oldPixels[0] + texSize.x*oldTexSizeY*4, 0, texSize.x*(texSize.y - oldTexSizeY)*4); GLuint newFarTextureID; glGenTextures(1, &newFarTextureID); @@ -341,8 +321,7 @@ bool CFarTextureHandler::CheckResizeAtlas() glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texSizeX, texSizeY, 0, GL_RGBA, GL_UNSIGNED_BYTE, oldPixels); - delete[] oldPixels; + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, texSize.x, texSize.y, 0, GL_RGBA, GL_UNSIGNED_BYTE, &oldPixels[0]); fbo.Bind(); fbo.DetachAll(); diff --git a/rts/Rendering/FarTextureHandler.h b/rts/Rendering/FarTextureHandler.h index b56cb0555b7..db5fc1d6cd7 100644 --- a/rts/Rendering/FarTextureHandler.h +++ b/rts/Rendering/FarTextureHandler.h @@ -24,26 +24,24 @@ class CFarTextureHandler void Draw(); private: - int texSizeX; - int texSizeY; - - static const int iconSizeX; - static const int iconSizeY; - static const int numOrientations; - - std::vector queuedForRender; - std::vector< std::vector > cache; - - FBO fbo; - unsigned int farTextureID; - unsigned int usedFarTextures; - bool HaveFarIcon(const CSolidObject* obj) const; bool CheckResizeAtlas(); float2 GetTextureCoords(const int farTextureNum, const int orientation) const; void DrawFarTexture(const CSolidObject* obj, CVertexArray*); int2 GetTextureCoordsInt(const int farTextureNum, const int orientation) const; void CreateFarTexture(const CSolidObject* obj); + +private: + int2 texSize; + int2 iconSize; + + std::vector drawQueue; + std::vector< std::vector > iconCache; + + FBO fbo; + + unsigned int farTextureID; + unsigned int usedFarTextures; }; extern CFarTextureHandler* farTextureHandler;