3 Copyright (C) 2010-2013 celeron55, Perttu Ahola <celeron55@gmail.com>
4 Copyright (C) 2017 numzero, Lobachevskiy Vitaliy <numzer0@yandex.ru>
5 Copyright (C) 2020 appgurueu, Lars Mueller <appgurulars@gmx.de>
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License along
18 with this program; if not, write to the Free Software Foundation, Inc.,
19 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22 #include "secondstage.h"
23 #include "client/client.h"
24 #include "client/shader.h"
25 #include "client/tile.h"
27 PostProcessingStep::PostProcessingStep(u32 _shader_id, const std::vector<u8> &_texture_map) :
28 shader_id(_shader_id), texture_map(_texture_map)
30 assert(texture_map.size() <= video::MATERIAL_MAX_TEXTURES);
34 void PostProcessingStep::configureMaterial()
36 material.UseMipMaps = false;
37 material.ZBuffer = true;
38 material.ZWriteEnable = video::EZW_ON;
39 for (u32 k = 0; k < texture_map.size(); ++k) {
40 material.TextureLayer[k].AnisotropicFilter = false;
41 material.TextureLayer[k].BilinearFilter = false;
42 material.TextureLayer[k].TrilinearFilter = false;
43 material.TextureLayer[k].TextureWrapU = video::ETC_CLAMP_TO_EDGE;
44 material.TextureLayer[k].TextureWrapV = video::ETC_CLAMP_TO_EDGE;
48 void PostProcessingStep::setRenderSource(RenderSource *_source)
53 void PostProcessingStep::setRenderTarget(RenderTarget *_target)
58 void PostProcessingStep::reset(PipelineContext &context)
62 void PostProcessingStep::run(PipelineContext &context)
65 target->activate(context);
68 material.MaterialType = context.client->getShaderSource()->getShaderInfo(shader_id).material;
70 auto driver = context.device->getVideoDriver();
72 for (u32 i = 0; i < texture_map.size(); i++)
73 material.TextureLayer[i].Texture = source->getTexture(texture_map[i]);
75 static const video::SColor color = video::SColor(0, 0, 0, 255);
76 static const video::S3DVertex vertices[4] = {
77 video::S3DVertex(1.0, -1.0, 0.0, 0.0, 0.0, -1.0,
79 video::S3DVertex(-1.0, -1.0, 0.0, 0.0, 0.0, -1.0,
81 video::S3DVertex(-1.0, 1.0, 0.0, 0.0, 0.0, -1.0,
83 video::S3DVertex(1.0, 1.0, 0.0, 0.0, 0.0, -1.0,
86 static const u16 indices[6] = {0, 1, 2, 2, 3, 0};
87 driver->setMaterial(material);
88 driver->drawVertexPrimitiveList(&vertices, 4, &indices, 2);
91 void PostProcessingStep::setBilinearFilter(u8 index, bool value)
93 assert(index < video::MATERIAL_MAX_TEXTURES);
94 material.TextureLayer[index].BilinearFilter = value;
97 RenderStep *addPostProcessing(RenderPipeline *pipeline, RenderStep *previousStep, v2f scale, Client *client)
99 auto buffer = pipeline->createOwned<TextureBuffer>();
100 auto driver = client->getSceneManager()->getVideoDriver();
102 // configure texture formats
103 video::ECOLOR_FORMAT color_format = video::ECF_A8R8G8B8;
104 if (driver->queryTextureFormat(video::ECF_A16B16G16R16F))
105 color_format = video::ECF_A16B16G16R16F;
107 video::ECOLOR_FORMAT depth_format = video::ECF_D16; // fallback depth format
108 if (driver->queryTextureFormat(video::ECF_D32))
109 depth_format = video::ECF_D32;
110 else if (driver->queryTextureFormat(video::ECF_D24S8))
111 depth_format = video::ECF_D24S8;
114 // init post-processing buffer
115 static const u8 TEXTURE_COLOR = 0;
116 static const u8 TEXTURE_DEPTH = 1;
117 static const u8 TEXTURE_BLOOM = 2;
118 static const u8 TEXTURE_BLOOM_DOWN = 10;
119 static const u8 TEXTURE_BLOOM_UP = 20;
121 buffer->setTexture(TEXTURE_COLOR, scale, "3d_render", color_format);
122 buffer->setTexture(TEXTURE_DEPTH, scale, "3d_depthmap", depth_format);
124 // attach buffer to the previous step
125 previousStep->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, std::vector<u8> { TEXTURE_COLOR }, TEXTURE_DEPTH));
130 // post-processing stage
132 if (g_settings->getBool("enable_bloom")) {
135 buffer->setTexture(TEXTURE_BLOOM, scale, "bloom", color_format);
137 const u8 MIPMAP_LEVELS = 4;
138 v2f downscale = scale * 0.5;
139 for (u8 i = 0; i < MIPMAP_LEVELS; i++) {
140 buffer->setTexture(TEXTURE_BLOOM_DOWN + i, downscale, std::string("bloom_down") + std::to_string(i), color_format);
141 buffer->setTexture(TEXTURE_BLOOM_UP + i, downscale, std::string("bloom_up") + std::to_string(i), color_format);
146 u32 shader_id = client->getShaderSource()->getShader("extract_bloom", TILE_MATERIAL_PLAIN, NDT_MESH);
147 RenderStep *extract_bloom = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_COLOR });
148 extract_bloom->setRenderSource(buffer);
149 extract_bloom->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_BLOOM));
152 shader_id = client->getShaderSource()->getShader("bloom_downsample", TILE_MATERIAL_PLAIN, NDT_MESH);
153 u8 source = TEXTURE_BLOOM;
154 for (u8 i = 0; i < MIPMAP_LEVELS; i++) {
155 auto step = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { source });
156 step->setRenderSource(buffer);
157 step->setBilinearFilter(0, true);
158 step->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, TEXTURE_BLOOM_DOWN + i));
159 source = TEXTURE_BLOOM_DOWN + i;
163 shader_id = client->getShaderSource()->getShader("bloom_upsample", TILE_MATERIAL_PLAIN, NDT_MESH);
164 for (u8 i = MIPMAP_LEVELS - 1; i > 0; i--) {
165 auto step = pipeline->addStep<PostProcessingStep>(shader_id, std::vector<u8> { u8(TEXTURE_BLOOM_DOWN + i - 1), source });
166 step->setRenderSource(buffer);
167 step->setBilinearFilter(0, true);
168 step->setBilinearFilter(1, true);
169 step->setRenderTarget(pipeline->createOwned<TextureBufferOutput>(buffer, u8(TEXTURE_BLOOM_UP + i - 1)));
170 source = TEXTURE_BLOOM_UP + i - 1;
174 // final post-processing
175 shader_id = client->getShaderSource()->getShader("second_stage", TILE_MATERIAL_PLAIN, NDT_MESH);
176 PostProcessingStep *effect = pipeline->createOwned<PostProcessingStep>(shader_id, std::vector<u8> { TEXTURE_COLOR, TEXTURE_BLOOM_UP });
177 pipeline->addStep(effect);
178 effect->setBilinearFilter(1, true); // apply filter to the bloom
179 effect->setRenderSource(buffer);