CInfoTextureCombiner::CInfoTextureCombiner() : CPboInfoTexture("info") , disabled(true) { texSize = (configHandler->GetBool("HighResInfoTexture")) ? int2(mapDims.pwr2mapx, mapDims.pwr2mapy) : int2(mapDims.pwr2mapx >> 1, mapDims.pwr2mapy >> 1); //texSize = (configHandler->GetBool("HighResInfoTexture")) ? int2(512, 512) : int2(256, 256); texChannels = 4; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); 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); // precision hint: // GL_RGBA8 hasn't enough precision for subtle blending operations, // cause we update the texture slowly with alpha values of 0.05, so // per update the change is too subtle. With just 8bits per channel // the update is too less to change the texture value at all. The // texture keeps unchanged then and never reaches the wanted final // state, keeping `shadow` images of the old state. // Testing showed that 10bits per channel are already good enough to // counter this, GL_RGBA16 would be another solution, but needs twice // as much texture memory + bandwidth. // Also GL3.x enforces that GL_RGB10_A2 must be renderable. glSpringTexStorage2D(GL_TEXTURE_2D, -1, GL_RGB10_A2, texSize.x, texSize.y); if (FBO::IsSupported()) { fbo.Bind(); fbo.AttachTexture(texture); /*bool status =*/ fbo.CheckStatus("CInfoTextureCombiner"); glClearColor(0.5f, 0.5f, 0.5f, 1.0f); if (fbo.IsValid()) glClear(GL_COLOR_BUFFER_BIT); FBO::Unbind(); // create mipmaps glBindTexture(GL_TEXTURE_2D, texture); glGenerateMipmap(GL_TEXTURE_2D); } shader = shaderHandler->CreateProgramObject("[CInfoTextureCombiner]", "CInfoTextureCombiner", false); if (!fbo.IsValid() /*|| !shader->IsValid()*/) { // don't check shader (it gets created/switched at runtime) throw opengl_error(""); } }
CLegacyInfoTextureHandler::CLegacyInfoTextureHandler() : drawMode(drawNormal) , updateTextureState(0) , extraTextureUpdateRate(0) , returnToLOS(false) , highResLosTex(false) , highResInfoTexWanted(false) { if (!infoTextureHandler) infoTextureHandler = this; infoTexPBO.Bind(); infoTexPBO.New(mapDims.pwr2mapx * mapDims.pwr2mapy * 4); infoTexPBO.Unbind(); highResLosTex = configHandler->GetBool("HighResLos"); extraTextureUpdateRate = std::max(4, configHandler->GetInt("ExtraTextureUpdateRate") - 1); memset(&infoTextureIDs[0], 0, sizeof(infoTextureIDs)); glGenTextures(NUM_INFOTEXTURES - 1, &infoTextureIDs[1]); infoTextures.reserve(NUM_INFOTEXTURES); infoTextures.emplace_back("", 0, int2(0,0)); for (unsigned int i = 1; i < NUM_INFOTEXTURES; i++) { BaseGroundDrawMode e = (BaseGroundDrawMode)i; bool hiresTex = false; if (e == drawLos && highResLosTex) hiresTex = true; if (e == drawHeight) hiresTex = true; int2 texSize(mapDims.pwr2mapx>>1, mapDims.pwr2mapy>>1); if (hiresTex) texSize = int2(mapDims.pwr2mapx, mapDims.pwr2mapy); glBindTexture(GL_TEXTURE_2D, infoTextureIDs[i]); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_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, texSize.x, texSize.y); infoTextures.emplace_back(DrawModeToName(e), infoTextureIDs[i], texSize); } Update(); }
CLosTexture::CLosTexture() : CPboInfoTexture("los") , uploadTex(0) { texSize = losHandler->los.size; texChannels = 1; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); 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_R8, texSize.x, texSize.y); infoTexPBO.Bind(); infoTexPBO.New(texSize.x * texSize.y * texChannels * 2, GL_STREAM_DRAW); infoTexPBO.Unbind(); if (FBO::IsSupported()) { fbo.Bind(); fbo.AttachTexture(texture); /*bool status =*/ fbo.CheckStatus("CLosTexture"); FBO::Unbind(); } if (!fbo.IsValid()) throw opengl_error(""); const std::string vertexCode = R"( #version 410 core layout(location = 0) in vec3 aVertexPos; layout(location = 1) in vec2 aTexCoords; // ignored out vec2 vTexCoords; void main() { vTexCoords = aVertexPos.xy * 0.5 + 0.5; gl_Position = vec4(aVertexPos, 1.0); } )"; const std::string fragmentCode = R"( #version 410 core uniform sampler2D tex0; in vec2 vTexCoords; layout(location = 0) out vec4 fFragColor; void main() { vec2 f = texture(tex0, vTexCoords).rg; float c = (f.r + f.g) * 200000.0; fFragColor = vec4(c); } )"; const char* errorFormats[2] = { "%s-shader compilation error: %s", "%s-shader validation error: %s", }; shader = shaderHandler->CreateProgramObject("[CLosTexture]", "CLosTexture"); shader->AttachShaderObject(shaderHandler->CreateShaderObject(vertexCode, "", GL_VERTEX_SHADER)); shader->AttachShaderObject(shaderHandler->CreateShaderObject(fragmentCode, "", GL_FRAGMENT_SHADER)); shader->Link(); if (!shader->IsValid()) { LOG_L(L_ERROR, errorFormats[0], shader->GetName().c_str(), shader->GetLog().c_str()); throw opengl_error(""); } shader->Enable(); shader->SetUniform("tex0", 0); shader->Disable(); shader->Validate(); if (!shader->IsValid()) { LOG_L(L_ERROR, errorFormats[1], shader->GetName().c_str(), shader->GetLog().c_str()); throw opengl_error(""); } glGenTextures(1, &uploadTex); glBindTexture(GL_TEXTURE_2D, uploadTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_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_RG8, texSize.x, texSize.y); }
CHeightTexture::CHeightTexture() : CPboInfoTexture("height") , CEventClient("[CHeightTexture]", 271990, false) , needUpdate(true) { eventHandler.AddClient(this); texSize = int2(mapDims.mapxp1, mapDims.mapyp1); texChannels = 4; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_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, texSize.x, texSize.y); glGenTextures(1, &paletteTex); glBindTexture(GL_TEXTURE_2D, paletteTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); glSpringTexStorage2D(GL_TEXTURE_2D, 1, GL_RGBA8, 256, 2); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 256, 1, GL_RGBA, GL_UNSIGNED_BYTE, &CHeightLinePalette::paletteColored[0].r); glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 1, 256, 1, GL_RGBA, GL_UNSIGNED_BYTE, &CHeightLinePalette::paletteBlackAndWhite[0].r); if (FBO::IsSupported()) { fbo.Bind(); fbo.AttachTexture(texture); /*bool status =*/ fbo.CheckStatus("CHeightTexture"); FBO::Unbind(); } if (!fbo.IsValid()) throw opengl_error(""); const std::string vertexCode = R"( #version 410 core layout(location = 0) in vec3 aVertexPos; layout(location = 1) in vec2 aTexCoords; // ignored out vec2 vTexCoords; void main() { gl_Position = vec4(0.0, 0.0, 0.0, 1.0); gl_Position.xy = aVertexPos.xy * 2.0 - 1.0; vTexCoords = aVertexPos.st; } )"; const std::string fragmentCode = R"( #version 410 core uniform sampler2D texHeight; uniform sampler2D texPalette; uniform float paletteOffset; in vec2 vTexCoords; layout(location = 0) out vec4 fFragColor; void main() { float h = texture(texHeight, vTexCoords).r; vec2 tc = vec2(h * (8. / 256.), paletteOffset); fFragColor = texture(texPalette, tc); } )"; const char* errorFormats[2] = { "%s-shader compilation error: %s", "%s-shader validation error: %s", }; shader = shaderHandler->CreateProgramObject("[CHeightTexture]", "CHeightTexture"); shader->AttachShaderObject(shaderHandler->CreateShaderObject(vertexCode, "", GL_VERTEX_SHADER)); shader->AttachShaderObject(shaderHandler->CreateShaderObject(fragmentCode, "", GL_FRAGMENT_SHADER)); shader->Link(); if (!shader->IsValid()) { LOG_L(L_ERROR, errorFormats[0], shader->GetName().c_str(), shader->GetLog().c_str()); throw opengl_error(""); } shader->Enable(); shader->SetUniform("texHeight", 0); shader->SetUniform("texPalette", 1); shader->SetUniform("paletteOffset", configHandler->GetBool("ColorElev") ? 0.0f : 1.0f); shader->Disable(); shader->Validate(); if (!shader->IsValid()) { LOG_L(L_ERROR, errorFormats[1], shader->GetName().c_str(), shader->GetLog().c_str()); throw opengl_error(""); } }
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"); }
CRadarTexture::CRadarTexture() : CPboInfoTexture("radar") , uploadTexRadar(0) , uploadTexJammer(0) { texSize = losHandler->radar.size; texChannels = 2; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_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_RG8, texSize.x, texSize.y); infoTexPBO.Bind(); infoTexPBO.New(texSize.x * texSize.y * texChannels * sizeof(unsigned short), GL_STREAM_DRAW); infoTexPBO.Unbind(); if (FBO::IsSupported()) { fbo.Bind(); fbo.AttachTexture(texture); /*bool status =*/ fbo.CheckStatus("CRadarTexture"); FBO::Unbind(); } const std::string vertexCode = R"( varying vec2 texCoord; void main() { texCoord = gl_Vertex.xy * 0.5 + 0.5; gl_Position = vec4(gl_Vertex.xyz, 1.0); } )"; const std::string fragmentCode = R"( uniform sampler2D texLoS; uniform sampler2D texRadar; uniform sampler2D texJammer; varying vec2 texCoord; void main() { float los = texture2D(texLoS, texCoord).r; vec2 fr = texture2D(texRadar, texCoord).rg; vec2 fj = texture2D(texJammer, texCoord).rg; float cr = (fr.r + fr.g) * 200000.0; float cj = (fj.r + fj.g) * 200000.0; gl_FragColor = vec4(cr, los * cj, 0.0f, 0.0f); } )"; shader = shaderHandler->CreateProgramObject("[CRadarTexture]", "CRadarTexture", false); shader->AttachShaderObject(shaderHandler->CreateShaderObject(vertexCode, "", GL_VERTEX_SHADER)); shader->AttachShaderObject(shaderHandler->CreateShaderObject(fragmentCode, "", GL_FRAGMENT_SHADER)); shader->Link(); if (!shader->IsValid()) { const char* fmt = "%s-shader compilation error: %s"; LOG_L(L_ERROR, fmt, shader->GetName().c_str(), shader->GetLog().c_str()); } else { shader->Enable(); shader->SetUniform("texRadar", 1); shader->SetUniform("texJammer", 0); shader->SetUniform("texLoS", 2); shader->Disable(); shader->Validate(); if (!shader->IsValid()) { const char* fmt = "%s-shader validation error: %s"; LOG_L(L_ERROR, fmt, shader->GetName().c_str(), shader->GetLog().c_str()); } } if (fbo.IsValid() && shader->IsValid()) { glGenTextures(1, &uploadTexRadar); glBindTexture(GL_TEXTURE_2D, uploadTexRadar); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_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_RG8, texSize.x, texSize.y); glGenTextures(1, &uploadTexJammer); glBindTexture(GL_TEXTURE_2D, uploadTexJammer); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_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_RG8, texSize.x, texSize.y); } if (!fbo.IsValid() || !shader->IsValid()) { throw opengl_error(""); } }
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 }
CLosTexture::CLosTexture() : CPboInfoTexture("los") , uploadTex(0) { texSize = int2(losHandler->losSizeX, losHandler->losSizeY); texChannels = 1; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); 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_R8, texSize.x, texSize.y); infoTexPBO.Bind(); infoTexPBO.New(texSize.x * texSize.y * texChannels * 2, GL_STREAM_DRAW); infoTexPBO.Unbind(); if (FBO::IsSupported()) { fbo.Bind(); fbo.AttachTexture(texture); /*bool status =*/ fbo.CheckStatus("CLosTexture"); FBO::Unbind(); } const std::string vertexCode = R"( varying vec2 texCoord; void main() { texCoord = gl_Vertex.xy * 0.5 + 0.5; gl_Position = vec4(gl_Vertex.xyz, 1.0); } )"; const std::string fragmentCode = R"( uniform sampler2D tex0; varying vec2 texCoord; void main() { vec2 f = texture2D(tex0, texCoord).rg; float c = (f.r + f.g) * 200000.0; gl_FragColor = vec4(c); } )"; shader = shaderHandler->CreateProgramObject("[CLosTexture]", "CLosTexture", false); shader->AttachShaderObject(shaderHandler->CreateShaderObject(vertexCode, "", GL_VERTEX_SHADER)); shader->AttachShaderObject(shaderHandler->CreateShaderObject(fragmentCode, "", GL_FRAGMENT_SHADER)); shader->Link(); if (!shader->IsValid()) { const char* fmt = "%s-shader compilation error: %s"; LOG_L(L_ERROR, fmt, shader->GetName().c_str(), shader->GetLog().c_str()); } else { shader->Enable(); shader->SetUniform("tex0", 0); shader->Disable(); shader->Validate(); if (!shader->IsValid()) { const char* fmt = "%s-shader validation error: %s"; LOG_L(L_ERROR, fmt, shader->GetName().c_str(), shader->GetLog().c_str()); } } if (fbo.IsValid() && shader->IsValid()) { glGenTextures(1, &uploadTex); glBindTexture(GL_TEXTURE_2D, uploadTex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_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_RG8, texSize.x, texSize.y); } }
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); }