Example #1
0
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
}