void CGrassDrawer::CreateFarTex() { //TODO create normalmap, too? const int sizeMod = 2; const int billboardSize = 256; const int numAngles = 16; const int texSizeX = billboardSize * numAngles; const int texSizeY = billboardSize; if (farTex == 0) { glGenTextures(1, &farTex); glBindTexture(GL_TEXTURE_2D, farTex); 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); glSpringTexStorage2D(GL_TEXTURE_2D, -1, GL_RGBA8, texSizeX, texSizeY); } FBO fboTex; fboTex.Bind(); fboTex.AttachTexture(farTex); fboTex.CheckStatus("GRASSDRAWER1"); FBO fbo; fbo.Bind(); fbo.CreateRenderBuffer(GL_DEPTH_ATTACHMENT_EXT, GL_DEPTH_COMPONENT16, texSizeX * sizeMod, texSizeY * sizeMod); fbo.CreateRenderBuffer(GL_COLOR_ATTACHMENT0_EXT, GL_RGBA8, texSizeX * sizeMod, texSizeY * sizeMod); fbo.CheckStatus("GRASSDRAWER2"); if (!fboTex.IsValid() || !fbo.IsValid()) { grassOff = true; return; } glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glDisable(GL_FOG); glDisable(GL_BLEND); glDisable(GL_ALPHA_TEST); glBindTexture(GL_TEXTURE_2D, grassBladeTex); glEnable(GL_TEXTURE_2D); glEnable(GL_CLIP_PLANE0); glEnable(GL_DEPTH_TEST); glDepthMask(GL_TRUE); glColor4f(1,1,1,1); glViewport(0,0,texSizeX*sizeMod, texSizeY*sizeMod); glClearColor(mapInfo->grass.color.r,mapInfo->grass.color.g,mapInfo->grass.color.b,0.f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClearColor(0.f,0.f,0.f,0.f); static const GLdouble eq[4] = {0.f, 1.f, 0.f, 0.f}; // render turf from different vertical angles for (int a=0;a<numAngles;++a) { glViewport(a*billboardSize*sizeMod, 0, billboardSize*sizeMod, billboardSize*sizeMod); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRotatef(a*90.f/(numAngles-1),1,0,0); //glTranslatef(0,-0.5f,0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-partTurfSize, partTurfSize, partTurfSize, -partTurfSize, -turfSize, turfSize); // has to be applied after the matrix transformations, // cause it uses those an `compiles` them into the clip plane glClipPlane(GL_CLIP_PLANE0, &eq[0]); glCallList(grassDL); } glDisable(GL_CLIP_PLANE0); // scale down the rendered fartextures (MSAA) and write to the final texture glBindFramebufferEXT(GL_READ_FRAMEBUFFER, fbo.fboId); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, fboTex.fboId); glBlitFramebufferEXT(0, 0, texSizeX*sizeMod, texSizeY*sizeMod, 0, 0, texSizeX, texSizeY, GL_COLOR_BUFFER_BIT, GL_LINEAR); // compute mipmaps glBindTexture(GL_TEXTURE_2D, farTex); glGenerateMipmap(GL_TEXTURE_2D); // blur non-rendered areas, so in mipmaps color data isn't blurred with background color { const int mipLevels = std::ceil(std::log((float)(std::max(texSizeX, texSizeY) + 1))); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glEnable(GL_BLEND); glBlendFuncSeparate(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA, GL_ZERO, GL_DST_ALPHA); // copy each mipmap to its predecessor background // -> fill background with blurred color data fboTex.Bind(); for (int mipLevel = mipLevels - 2; mipLevel >= 0; --mipLevel) { fboTex.AttachTexture(farTex, GL_TEXTURE_2D, GL_COLOR_ATTACHMENT0_EXT, mipLevel); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, mipLevel + 1.f); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, mipLevel + 1.f); glViewport(0, 0, texSizeX>>mipLevel, texSizeY>>mipLevel); CVertexArray* va = GetVertexArray(); va->Initialize(); va->AddVertexT(float3(-1.0f, 1.0f, 0.0f), 0.0f, 1.0f); va->AddVertexT(float3( 1.0f, 1.0f, 0.0f), 1.0f, 1.0f); va->AddVertexT(float3( 1.0f, -1.0f, 0.0f), 1.0f, 0.0f); va->AddVertexT(float3(-1.0f, -1.0f, 0.0f), 0.0f, 0.0f); va->DrawArrayT(GL_QUADS); } glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // recreate mipmaps from now blurred base level glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_LOD, -1000.f); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAX_LOD, 1000.f); glGenerateMipmap(GL_TEXTURE_2D); } glViewport(globalRendering->viewPosX, 0, globalRendering->viewSizeX, globalRendering->viewSizeY); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); FBO::Unbind(); //glSaveTexture(farTex, "grassfar.png"); }
void CGlobalRendering::PostInit() { supportNPOTs = GLEW_ARB_texture_non_power_of_two; haveARB = GLEW_ARB_vertex_program && GLEW_ARB_fragment_program; haveGLSL = (glGetString(GL_SHADING_LANGUAGE_VERSION) != NULL); haveGLSL &= GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader; haveGLSL &= !!GLEW_VERSION_2_0; // we want OpenGL 2.0 core functions { const char* glVendor = (const char*) glGetString(GL_VENDOR); const char* glRenderer = (const char*) glGetString(GL_RENDERER); const std::string vendor = (glVendor != NULL)? StringToLower(std::string(glVendor)): ""; const std::string renderer = (glRenderer != NULL)? StringToLower(std::string(glRenderer)): ""; haveATI = (vendor.find("ati ") != std::string::npos) || (vendor.find("amd ") != std::string::npos); haveMesa = (renderer.find("mesa ") != std::string::npos); haveIntel = (vendor.find("intel ") != std::string::npos); haveNvidia = (vendor.find("nvidia ") != std::string::npos); //FIXME Neither Intel's nor Mesa's GLSL implementation seem to be in a workable state atm (date: Nov. 2011) haveGLSL &= !haveIntel; haveGLSL &= !haveMesa; if (haveATI) { // x-series doesn't support NPOTs (but hd-series does) supportNPOTs = (renderer.find(" x") == std::string::npos && renderer.find(" 9") == std::string::npos); } } // use some ATI bugfixes? const int atiHacksCfg = configHandler->GetInt("AtiHacks"); atiHacks = haveATI && (atiHacksCfg < 0); // runtime detect atiHacks |= (atiHacksCfg > 0); // user override // Runtime compress textures? if (GLEW_ARB_texture_compression) { // we don't even need to check it, 'cos groundtextures must have that extension // default to off because it reduces quality (smallest mipmap level is bigger) compressTextures = configHandler->GetBool("CompressTextures"); } // maximum 2D texture size { glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); } // detect if GL_DEPTH_COMPONENT24 is supported (many ATIs don't do so) { // ATI seems to support GL_DEPTH_COMPONENT24 for static textures, but you can't render to them /* GLint state = 0; glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 16, 16, 0, GL_LUMINANCE, GL_FLOAT, NULL); glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &state); support24bitDepthBuffers = (state > 0); */ support24bitDepthBuffers = false; if (FBO::IsSupported() && !atiHacks) { const int fboSizeX = 16, fboSizeY = 16; FBO fbo; fbo.Bind(); fbo.CreateRenderBuffer(GL_COLOR_ATTACHMENT0_EXT, GL_RGBA8, fboSizeX, fboSizeY); fbo.CreateRenderBuffer(GL_DEPTH_ATTACHMENT_EXT, GL_DEPTH_COMPONENT24, fboSizeX, fboSizeY); const GLenum status = fbo.GetStatus(); fbo.Unbind(); support24bitDepthBuffers = (status == GL_FRAMEBUFFER_COMPLETE_EXT); } } // print info LOG( "GL info:\n" "\thaveARB: %i, haveGLSL: %i, ATI hacks: %i\n" "\tFBO support: %i, NPOT-texture support: %i, 24bit Z-buffer support: %i\n" "\tmaximum texture size: %i, compress MIP-map textures: %i", haveARB, haveGLSL, atiHacks, FBO::IsSupported(), supportNPOTs, support24bitDepthBuffers, maxTextureSize, compressTextures ); }
void CGlobalRendering::PostInit() { supportNPOTs = GLEW_ARB_texture_non_power_of_two; haveARB = GLEW_ARB_vertex_program && GLEW_ARB_fragment_program; haveGLSL = (glGetString(GL_SHADING_LANGUAGE_VERSION) != NULL); haveGLSL &= GLEW_ARB_vertex_shader && GLEW_ARB_fragment_shader; haveGLSL &= !!GLEW_VERSION_2_0; // we want OpenGL 2.0 core functions { const char* glVendor = (const char*) glGetString(GL_VENDOR); const char* glRenderer = (const char*) glGetString(GL_RENDERER); const std::string vendor = (glVendor != NULL)? StringToLower(std::string(glVendor)): ""; const std::string renderer = (glRenderer != NULL)? StringToLower(std::string(glRenderer)): ""; haveATI = (vendor.find("ati ") != std::string::npos) || (vendor.find("amd ") != std::string::npos); haveMesa = (renderer.find("mesa ") != std::string::npos) || (renderer.find("gallium ") != std::string::npos); haveIntel = (vendor.find("intel") != std::string::npos); haveNvidia = (vendor.find("nvidia ") != std::string::npos); //FIXME Neither Intel's nor Mesa's GLSL implementation seem to be in a workable state atm (date: Nov. 2011) haveGLSL &= !haveIntel; haveGLSL &= !haveMesa; //FIXME add an user config to force enable it! if (haveATI) { // x-series doesn't support NPOTs (but hd-series does) supportNPOTs = (renderer.find(" x") == std::string::npos && renderer.find(" 9") == std::string::npos); } } // use some ATI bugfixes? const int atiHacksCfg = configHandler->GetInt("AtiHacks"); atiHacks = haveATI && (atiHacksCfg < 0); // runtime detect atiHacks |= (atiHacksCfg > 0); // user override // Runtime compress textures? if (GLEW_ARB_texture_compression) { // we don't even need to check it, 'cos groundtextures must have that extension // default to off because it reduces quality (smallest mipmap level is bigger) compressTextures = configHandler->GetBool("CompressTextures"); } #ifdef GLEW_NV_primitive_restart supportRestartPrimitive = !!(GLEW_NV_primitive_restart); #endif // maximum 2D texture size { glGetIntegerv(GL_MAX_TEXTURE_SIZE, &maxTextureSize); } // retrieve maximu smoothed PointSize float2 aliasedPointSizeRange, smoothPointSizeRange; glGetFloatv(GL_ALIASED_POINT_SIZE_RANGE, (GLfloat*)&aliasedPointSizeRange); glGetFloatv(GL_SMOOTH_POINT_SIZE_RANGE, (GLfloat*)&smoothPointSizeRange); maxSmoothPointSize = std::min(aliasedPointSizeRange.y, smoothPointSizeRange.y); // some GLSL relevant information { glGetIntegerv(GL_MAX_UNIFORM_BUFFER_BINDINGS, &glslMaxUniformBufferBindings); glGetIntegerv(GL_MAX_UNIFORM_BLOCK_SIZE, &glslMaxUniformBufferSize); glGetIntegerv(GL_MAX_VARYING_FLOATS, &glslMaxVaryings); glGetIntegerv(GL_MAX_VERTEX_ATTRIBS, &glslMaxAttributes); glGetIntegerv(GL_MAX_DRAW_BUFFERS, &glslMaxDrawBuffers); glGetIntegerv(GL_MAX_ELEMENTS_INDICES, &glslMaxRecommendedIndices); glGetIntegerv(GL_MAX_ELEMENTS_VERTICES, &glslMaxRecommendedVertices); glslMaxVaryings /= 4; // GL_MAX_VARYING_FLOATS returns max individual floats, we want float4 } // detect if GL_DEPTH_COMPONENT24 is supported (many ATIs don't do so) { // ATI seems to support GL_DEPTH_COMPONENT24 for static textures, but you can't render to them /* GLint state = 0; glTexImage2D(GL_PROXY_TEXTURE_2D, 0, GL_DEPTH_COMPONENT24, 16, 16, 0, GL_LUMINANCE, GL_FLOAT, NULL); glGetTexLevelParameteriv(GL_PROXY_TEXTURE_2D, 0, GL_TEXTURE_WIDTH, &state); support24bitDepthBuffers = (state > 0); */ support24bitDepthBuffers = false; if (FBO::IsSupported() && !atiHacks) { const int fboSizeX = 16, fboSizeY = 16; FBO fbo; fbo.Bind(); fbo.CreateRenderBuffer(GL_COLOR_ATTACHMENT0_EXT, GL_RGBA8, fboSizeX, fboSizeY); fbo.CreateRenderBuffer(GL_DEPTH_ATTACHMENT_EXT, GL_DEPTH_COMPONENT24, fboSizeX, fboSizeY); const GLenum status = fbo.GetStatus(); fbo.Unbind(); support24bitDepthBuffers = (status == GL_FRAMEBUFFER_COMPLETE_EXT); } } // print info LOG( "GL info:\n" "\thaveARB: %i, haveGLSL: %i, ATI hacks: %i\n" "\tFBO support: %i, NPOT-texture support: %i, 24bit Z-buffer support: %i\n" "\tmaximum texture size: %i, compress MIP-map textures: %i\n" "\tmaximum SmoothPointSize: %0.0f, maximum vec4 varying/attributes: %i/%i\n" "\tmaximum drawbuffers: %i, maximum recommended indices/vertices: %i/%i\n" "\tnumber of UniformBufferBindings: %i (%ikB)", haveARB, haveGLSL, atiHacks, FBO::IsSupported(), supportNPOTs, support24bitDepthBuffers, maxTextureSize, compressTextures, maxSmoothPointSize, glslMaxVaryings, glslMaxAttributes, glslMaxDrawBuffers, glslMaxRecommendedIndices, glslMaxRecommendedVertices, glslMaxUniformBufferBindings, glslMaxUniformBufferSize / 1024 ); teamNanospray = configHandler->GetBool("TeamNanoSpray"); }
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 }
void CGrassDrawer::CreateFarTex() { int sizeMod=2; glGenTextures(1, &farTex); glBindTexture(GL_TEXTURE_2D, farTex); 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); glSpringTexStorage2D(GL_TEXTURE_2D, -1, GL_RGBA8, 1024, 64); FBO fboTex; fboTex.Bind(); fboTex.AttachTexture(farTex); fboTex.CheckStatus("GRASSDRAWER1"); FBO fbo; fbo.Bind(); fbo.CreateRenderBuffer(GL_DEPTH_ATTACHMENT_EXT, GL_DEPTH_COMPONENT16, 1024 * sizeMod, 64 * sizeMod); fbo.CreateRenderBuffer(GL_COLOR_ATTACHMENT0_EXT, GL_RGBA8, 1024 * sizeMod, 64 * sizeMod); fbo.CheckStatus("GRASSDRAWER2"); if (!fboTex.IsValid() || !fbo.IsValid()) { grassOff = true; return; } glPushMatrix(); glLoadIdentity(); glMatrixMode(GL_PROJECTION); glPushMatrix(); glDisable(GL_FOG); glDisable(GL_BLEND); glDisable(GL_ALPHA_TEST); glBindTexture(GL_TEXTURE_2D, grassBladeTex); glEnable(GL_TEXTURE_2D); glColor4f(1,1,1,1); glViewport(0,0,1024*sizeMod, 64*sizeMod); glClearColor(0.75f,0.9f,0.75f,0.f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClearColor(0.f,0.f,0.f,0.f); // render turf from different vertical angles for (int a=0;a<16;++a) { glViewport(a*64*sizeMod, 0, 64*sizeMod, 64*sizeMod); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glRotatef((a-1)*90/15.0f,1,0,0); glTranslatef(0,-0.5f,0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); glOrtho(-partTurfSize, partTurfSize, -partTurfSize, partTurfSize, -turfSize, turfSize); glCallList(grassDL); } glViewport(globalRendering->viewPosX, 0, globalRendering->viewSizeX, globalRendering->viewSizeY); glMatrixMode(GL_PROJECTION); glPopMatrix(); glMatrixMode(GL_MODELVIEW); glPopMatrix(); // scale down the rendered fartextures (MSAA) and write to the final texture glBindFramebufferEXT(GL_READ_FRAMEBUFFER, fbo.fboId); glBindFramebufferEXT(GL_DRAW_FRAMEBUFFER, fboTex.fboId); glBlitFramebufferEXT(0, 0, 1024*sizeMod, 64*sizeMod, 0, 0, 1024, 64, GL_COLOR_BUFFER_BIT, GL_LINEAR); fbo.Unbind(); // compute mipmaps glBindTexture(GL_TEXTURE_2D, farTex); glGenerateMipmap(GL_TEXTURE_2D); }