void CDecalsDrawerGL4::UpdateOverlap_Initialize() { glClearStencil(0); glClear(GL_STENCIL_BUFFER_BIT); //glClearColor(0.0f, 0.5f, 0.0f, 1.0f); //glClear(GL_COLOR_BUFFER_BIT); glStencilFunc(GL_ALWAYS, 0, 0xFF); glStencilOp(GL_INCR_WRAP, GL_INCR_WRAP, GL_INCR_WRAP); CVertexArray* va = GetVertexArray(); va->Initialize(); for (Decal& d: decals) { DRAW_DECAL(va, &d); } va->DrawArray2dT(GL_QUADS); /*const size_t datasize = 4 * OVERLAP_TEST_TEXTURE_SIZE * OVERLAP_TEST_TEXTURE_SIZE; unsigned char* img = new unsigned char[datasize]; memset(img, 0, datasize); glReadPixels(0, 0, OVERLAP_TEST_TEXTURE_SIZE, OVERLAP_TEST_TEXTURE_SIZE, GL_RGBA, GL_UNSIGNED_BYTE, img); CBitmap bitmap(img, OVERLAP_TEST_TEXTURE_SIZE, OVERLAP_TEST_TEXTURE_SIZE); bitmap.Save("decals.png", true); delete[] img;*/ }
std::vector<int> CDecalsDrawerGL4::UpdateOverlap_CheckQueries() { // query the results of the last issued test (if any pixels were rendered for the decal) std::vector<int> candidatesForRemoval; candidatesForRemoval.reserve(waitingOverlapGlQueries.size()); for (auto& p: waitingOverlapGlQueries) { GLint rendered = GL_FALSE; glGetQueryObjectiv(p.second, GL_QUERY_RESULT, &rendered); glDeleteQueries(1, &p.second); if (rendered == GL_FALSE) { candidatesForRemoval.push_back(p.first); } } waitingOverlapGlQueries.clear(); // no candidates left, restart with stage 0 if (candidatesForRemoval.empty()) { overlapStage = 0; return candidatesForRemoval; } //FIXME comment auto sortBeginIt = candidatesForRemoval.begin(); auto sortEndIt = candidatesForRemoval.end(); while (sortBeginIt != sortEndIt) { std::sort(sortBeginIt, sortEndIt, [&](const int& idx1, const int& idx2){ return decals[idx1].generation < decals[idx2].generation; }); sortEndIt = std::partition(sortBeginIt+1, sortEndIt, [&](const int& idx){ return !Overlap(decals[*sortBeginIt], decals[idx]); }); ++sortBeginIt; } auto eraseIt = sortEndIt; // free one decal (+ remove it from the overlap texture) int freed = 0; CVertexArray* va = GetVertexArray(); glStencilFunc(GL_ALWAYS, 0, 0xFF); glStencilOp(GL_DECR_WRAP, GL_DECR_WRAP, GL_DECR_WRAP); va->Initialize(); for (auto it = candidatesForRemoval.begin(); it != eraseIt; ++it) { const int curIndex = *it; const Decal& d = decals[curIndex]; DRAW_DECAL(va, &d); FreeDecal(curIndex); freed++; } va->DrawArray2dT(GL_QUADS); candidatesForRemoval.erase(candidatesForRemoval.begin(), eraseIt); //FIXME LOG_L(L_ERROR, "Query freed: %i of %i (decals:%i groups:%i)", freed, int(candidatesForRemoval.size()), int(decals.size() - freeIds.size()), int(groups.size())); // overlap texture changed, so need to retest the others return candidatesForRemoval; }
void CDecalsDrawerGL4::UpdateOverlap_GenerateQueries(const std::vector<int>& candidatesForOverlap) { glStencilFunc(GL_GREATER, MAX_OVERLAP, 0xFF); glStencilOp(GL_KEEP, GL_KEEP, GL_KEEP); CVertexArray* va = GetVertexArray(); for (int i: candidatesForOverlap) { Decal& d0 = decals[i]; GLuint q; glGenQueries(1, &q); glBeginQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE, q); va->Initialize(); DRAW_DECAL(va, &d0); va->DrawArray2dT(GL_QUADS); glEndQuery(GL_ANY_SAMPLES_PASSED_CONSERVATIVE); waitingOverlapGlQueries.emplace_back(i, q); } }
void CDecalsDrawerGL4::GenerateAtlasTexture() { std::unordered_map<std::string, STex> textures; GetBuildingDecals(textures); GetGroundScars(textures); GetFallbacks(textures); CQuadtreeAtlasAlloc atlas; atlas.SetNonPowerOfTwo(globalRendering->supportNPOTs); atlas.SetMaxSize(globalRendering->maxTextureSize, globalRendering->maxTextureSize); for (auto it = textures.begin(); it != textures.end(); ++it) { if (it->second.id == 0) continue; const float maxSize = 1024; //512; int2 size = it->second.size; if (size.x > maxSize) { size.y = size.y * (maxSize / size.x); size.x = maxSize; } if (size.y > maxSize) { size.x = size.x * (maxSize / size.y); size.y = maxSize; } atlas.AddEntry(it->first, size); } /*bool success =*/ atlas.Allocate(); glGenTextures(1, &atlasTex); glBindTexture(GL_TEXTURE_2D, atlasTex); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR_MIPMAP_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_ANISOTROPY_EXT, 4.0f); glSpringTexStorage2D(GL_TEXTURE_2D, atlas.GetMaxMipMaps(), GL_RGBA8, atlas.GetAtlasSize().x, atlas.GetAtlasSize().y); FBO fb; if (!fb.IsValid()) { LOG_L(L_ERROR, "[%s] framebuffer not valid", __FUNCTION__); return; } fb.Bind(); fb.AttachTexture(atlasTex); if (!fb.CheckStatus(LOG_SECTION_DECALS_GL4)) { LOG_L(L_ERROR, "[%s] Couldn't render to FBO!", __FUNCTION__); return; } glViewport(0, 0, atlas.GetAtlasSize().x, atlas.GetAtlasSize().y); glSpringMatrix2dProj(atlas.GetAtlasSize().x, atlas.GetAtlasSize().y); glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // transparent black glClear(GL_COLOR_BUFFER_BIT); glActiveTexture(GL_TEXTURE0); glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glBlendFunc(GL_ONE, GL_ZERO); glDisable(GL_DEPTH_TEST); CVertexArray va; for (auto& p: textures) { if (p.second.id == 0) continue; const float4 texCoords = atlas.GetTexCoords(p.first); const float4 absCoords = atlas.GetEntry(p.first); atlasTexs[p.first] = SAtlasTex(texCoords); glColor4f(1.0f, 1.0f, 1.0f, 1.0f); glBindTexture(GL_TEXTURE_2D, p.second.id); va.Initialize(); va.AddVertex2dT(absCoords.x, absCoords.y, 0.0f, 0.0f); va.AddVertex2dT(absCoords.z+1, absCoords.y, 1.0f, 0.0f); //FIXME why +1? va.AddVertex2dT(absCoords.x, absCoords.w+1, 0.0f, 1.0f); va.AddVertex2dT(absCoords.z+1, absCoords.w+1, 1.0f, 1.0f); //FIXME why +1? va.DrawArray2dT(GL_TRIANGLE_STRIP); glDeleteTextures(1, &p.second.id); } fb.Unbind(); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBindTexture(GL_TEXTURE_2D, atlasTex); glGenerateMipmap(GL_TEXTURE_2D); #ifdef DEBUG_SAVE_ATLAS glSaveTexture(atlasTex, "x_decal_atlas.png"); #endif }