widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #03005
[Merge] lp:~widelands-dev/widelands/glsl into lp:widelands
SirVer has proposed merging lp:~widelands-dev/widelands/glsl into lp:widelands.
Requested reviews:
Widelands Developers (widelands-dev)
Related bugs:
Bug #984372 in widelands: "opengl-es support"
https://bugs.launchpad.net/widelands/+bug/984372
For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/glsl/+merge/240363
Ports the GL terrain rendering to shaders, staying compatible with OpenGL 2 (so that targeting OpenGL ES 2 for mobile is easy).
This does not yet remove the use of OpenGL 1 (fixed pipeline) from Widelands as there is still code for blitting GLSurfaces that needs to be ported, but this is the major work.
--
https://code.launchpad.net/~widelands-dev/widelands/glsl/+merge/240363
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/glsl into lp:widelands.
=== modified file 'src/game_io/game_preload_packet.cc'
--- src/game_io/game_preload_packet.cc 2014-10-12 08:39:48 +0000
+++ src/game_io/game_preload_packet.cc 2014-11-01 20:50:47 +0000
@@ -27,7 +27,7 @@
#include "base/time_string.h"
#include "graphic/graphic.h"
#include "graphic/in_memory_image.h"
-#include "graphic/render/minimaprenderer.h"
+#include "graphic/minimap_renderer.h"
#include "graphic/surface.h"
#include "logic/game.h"
#include "logic/game_data_error.h"
=== modified file 'src/graphic/CMakeLists.txt'
--- src/graphic/CMakeLists.txt 2014-07-15 05:12:37 +0000
+++ src/graphic/CMakeLists.txt 2014-11-01 20:50:47 +0000
@@ -39,18 +39,18 @@
wl_library(graphic_surface
SRCS
compositemode.h
- render/gl_surface.cc
- render/gl_surface.h
- render/gl_surface_screen.cc
- render/gl_surface_screen.h
- render/gl_surface_texture.cc
- render/gl_surface_texture.h
- render/gl_utils.cc
- render/gl_utils.h
- render/sdl_helper.cc
- render/sdl_helper.h
- render/sdl_surface.cc
- render/sdl_surface.h
+ gl/surface.cc
+ gl/surface.h
+ gl/surface_screen.cc
+ gl/surface_screen.h
+ gl/surface_texture.cc
+ gl/surface_texture.h
+ gl/utils.cc
+ gl/utils.h
+ sdl/surface.cc
+ sdl/surface.h
+ sdl/utils.cc
+ sdl/utils.h
surface.cc
surface.h
surface_cache.cc
@@ -82,27 +82,34 @@
font_handler.h
font_handler1.cc
font_handler1.h
+ game_renderer.cc
+ game_renderer.h
+ gl/dither_program.cc
+ gl/dither_program.h
+ gl/fields_to_draw.h
+ gl/game_renderer.cc
+ gl/game_renderer.h
+ gl/road_program.cc
+ gl/road_program.h
+ gl/terrain_program.cc
+ gl/terrain_program.h
graphic.cc
graphic.h
image_transformations.cc
image_transformations.h
in_memory_image.cc
in_memory_image.h
- render/gamerenderer.cc
- render/gamerenderer.h
- render/gamerenderer_gl.cc
- render/gamerenderer_gl.h
- render/gamerenderer_sdl.cc
- render/gamerenderer_sdl.h
- render/minimaprenderer.cc
- render/minimaprenderer.h
- render/terrain_sdl.cc
- render/terrain_sdl.h
- render/vertex.h
+ minimap_renderer.cc
+ minimap_renderer.h
rendertarget.cc
rendertarget.h
richtext.cc
richtext.h
+ sdl/game_renderer.cc
+ sdl/game_renderer.h
+ sdl/terrain.cc
+ sdl/terrain.h
+ sdl/vertex.h
text_parser.cc
text_parser.h
texture.cc
=== renamed file 'src/graphic/render/gamerenderer.cc' => 'src/graphic/game_renderer.cc'
--- src/graphic/render/gamerenderer.cc 2014-09-10 17:52:49 +0000
+++ src/graphic/game_renderer.cc 2014-11-01 20:50:47 +0000
@@ -17,7 +17,7 @@
*
*/
-#include "graphic/render/gamerenderer.h"
+#include "graphic/game_renderer.h"
#include "base/macros.h"
#include "graphic/graphic.h"
=== renamed file 'src/graphic/render/gamerenderer.h' => 'src/graphic/game_renderer.h'
--- src/graphic/render/gamerenderer.h 2014-09-10 08:55:04 +0000
+++ src/graphic/game_renderer.h 2014-11-01 20:50:47 +0000
@@ -17,8 +17,8 @@
*
*/
-#ifndef WL_GRAPHIC_RENDER_GAMERENDERER_H
-#define WL_GRAPHIC_RENDER_GAMERENDERER_H
+#ifndef WL_GRAPHIC_GAME_RENDERER_H
+#define WL_GRAPHIC_GAME_RENDERER_H
#include <boost/utility.hpp>
@@ -99,4 +99,4 @@
DISALLOW_COPY_AND_ASSIGN(GameRenderer);
};
-#endif // end of include guard: WL_GRAPHIC_RENDER_GAMERENDERER_H
+#endif // end of include guard: WL_GRAPHIC_GAME_RENDERER_H
=== added directory 'src/graphic/gl'
=== added file 'src/graphic/gl/dither_program.cc'
--- src/graphic/gl/dither_program.cc 1970-01-01 00:00:00 +0000
+++ src/graphic/gl/dither_program.cc 2014-11-01 20:50:47 +0000
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2006-2014 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "graphic/gl/dither_program.h"
+
+#include "graphic/gl/fields_to_draw.h"
+#include "graphic/gl/surface_texture.h"
+#include "graphic/graphic.h"
+#include "graphic/image_io.h"
+#include "graphic/surface_cache.h"
+#include "graphic/texture.h"
+#include "io/fileread.h"
+#include "io/filesystem/layered_filesystem.h"
+
+namespace {
+
+using namespace Widelands;
+
+const char kDitherVertexShader[] = R"(
+#version 120
+
+// Attributes.
+attribute float attr_brightness;
+attribute vec2 attr_position;
+attribute vec2 attr_texture_position;
+attribute vec2 attr_dither_texture_position;
+
+// Output of vertex shader.
+varying vec2 var_texture_position;
+varying vec2 var_dither_texture_position;
+varying float var_brightness;
+
+void main() {
+ var_texture_position = attr_texture_position;
+ var_dither_texture_position = attr_dither_texture_position;
+ var_brightness = attr_brightness;
+ vec4 p = vec4(attr_position, 0., 1.);
+ gl_Position = gl_ProjectionMatrix * p;
+}
+)";
+
+const char kDitherFragmentShader[] = R"(
+#version 120
+
+uniform sampler2D u_dither_texture;
+uniform sampler2D u_terrain_texture;
+
+varying float var_brightness;
+varying vec2 var_texture_position;
+varying vec2 var_dither_texture_position;
+
+void main() {
+ vec4 clr = texture2D(u_terrain_texture, var_texture_position);
+ clr.rgb *= var_brightness;
+ clr.a = 1. - texture2D(u_dither_texture, var_dither_texture_position).a;
+ gl_FragColor = clr;
+}
+)";
+
+// Returns the texture mask for the dithering step.
+const GLSurfaceTexture* get_dither_edge_texture() {
+ constexpr char kFilename[] = "world/pics/edge.png";
+ constexpr char kCacheName[] = "gltex#world/pics/edge.png";
+
+ if (Surface* surface = g_gr->surfaces().get(kCacheName))
+ return dynamic_cast<GLSurfaceTexture*>(surface);
+
+ SDL_Surface* sdlsurf = load_image_as_sdl_surface(kFilename, g_fs);
+ GLSurfaceTexture* edgetexture = new GLSurfaceTexture(sdlsurf, true);
+ g_gr->surfaces().insert(kCacheName, edgetexture, false);
+ return edgetexture;
+}
+
+} // namespace
+
+DitherProgram::DitherProgram() {
+ gl_program_.build(kDitherVertexShader, kDitherFragmentShader);
+
+ attr_brightness_ = glGetAttribLocation(gl_program_.object(), "attr_brightness");
+ attr_dither_texture_position_ =
+ glGetAttribLocation(gl_program_.object(), "attr_dither_texture_position");
+ attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
+ attr_texture_position_ =
+ glGetAttribLocation(gl_program_.object(), "attr_texture_position");
+
+ u_dither_texture_ = glGetUniformLocation(gl_program_.object(), "u_dither_texture");
+ u_terrain_texture_ = glGetUniformLocation(gl_program_.object(), "u_terrain_texture");
+}
+
+void DitherProgram::add_vertex(const FieldsToDraw::Field& field,
+ const int order_index,
+ const int terrain) {
+ vertices_[terrain].emplace_back();
+ PerVertexData& back = vertices_[terrain].back();
+
+ back.x = field.x;
+ back.y = field.y;
+ back.texture_x = field.texture_x;
+ back.texture_y = field.texture_y;
+ back.brightness = field.brightness;
+
+ switch (order_index) {
+ case 0:
+ back.dither_texture_x = 0.;
+ back.dither_texture_y = 0.;
+ break;
+ case 1:
+ back.dither_texture_x = 1.;
+ back.dither_texture_y = 0.;
+ break;
+ case 2:
+ back.dither_texture_x = 0.5;
+ back.dither_texture_y = 1.;
+ break;
+ }
+}
+
+void DitherProgram::maybe_add_dithering_triangle(
+ const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
+ const FieldsToDraw& fields_to_draw,
+ const int idx1,
+ const int idx2,
+ const int idx3,
+ const int my_terrain,
+ const int other_terrain) {
+ if (my_terrain == other_terrain) {
+ return;
+ }
+ if (terrains.get_unmutable(my_terrain).dither_layer() <
+ terrains.get_unmutable(other_terrain).dither_layer()) {
+ add_vertex(fields_to_draw.at(idx1), 0, other_terrain);
+ add_vertex(fields_to_draw.at(idx2), 1, other_terrain);
+ add_vertex(fields_to_draw.at(idx3), 2, other_terrain);
+ }
+}
+
+void DitherProgram::draw(const DescriptionMaintainer<TerrainDescription>& terrains,
+ const FieldsToDraw& fields_to_draw) {
+ glUseProgram(gl_program_.object());
+
+ glEnableVertexAttribArray(attr_brightness_);
+ glEnableVertexAttribArray(attr_dither_texture_position_);
+ glEnableVertexAttribArray(attr_position_);
+ glEnableVertexAttribArray(attr_texture_position_);
+
+ if (vertices_.size() != terrains.size()) {
+ vertices_.resize(terrains.size());
+ }
+ for (auto& container : vertices_) {
+ container.clear();
+ }
+
+ for (size_t current_index = 0; current_index < fields_to_draw.size(); ++current_index) {
+ const FieldsToDraw::Field& field = fields_to_draw.at(current_index);
+
+ // The bottom right neighbor fields_to_draw is needed for both triangles
+ // associated with this field. If it is not in fields_to_draw, there is no need to
+ // draw any triangles.
+ const int brn_index = fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy + 1);
+ if (brn_index == -1) {
+ continue;
+ }
+
+ // Dithering triangles for Down triangle.
+ const int bln_index =
+ fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
+ if (bln_index != -1) {
+ maybe_add_dithering_triangle(terrains, fields_to_draw,
+ brn_index, current_index, bln_index, field.ter_d, field.ter_r);
+
+ const int terrain_dd = fields_to_draw.at(bln_index).ter_r;
+ maybe_add_dithering_triangle(terrains, fields_to_draw,
+ bln_index, brn_index, current_index, field.ter_d, terrain_dd);
+
+ const int ln_index = fields_to_draw.calculate_index(field.fx - 1, field.fy);
+ if (ln_index != -1) {
+ const int terrain_l = fields_to_draw.at(ln_index).ter_r;
+ maybe_add_dithering_triangle(terrains, fields_to_draw,
+ current_index, bln_index, brn_index, field.ter_d, terrain_l);
+ }
+ }
+
+ // Dithering for right triangle.
+ const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
+ if (rn_index != -1) {
+ maybe_add_dithering_triangle(terrains, fields_to_draw,
+ current_index, brn_index, rn_index, field.ter_r, field.ter_d);
+ int terrain_rr = fields_to_draw.at(rn_index).ter_d;
+ maybe_add_dithering_triangle(terrains, fields_to_draw,
+ brn_index, rn_index, current_index, field.ter_r, terrain_rr);
+
+ const int trn_index =
+ fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy - 1);
+ if (trn_index != -1) {
+ const int terrain_u = fields_to_draw.at(trn_index).ter_d;
+ maybe_add_dithering_triangle(terrains, fields_to_draw,
+ rn_index, current_index, brn_index, field.ter_r, terrain_u);
+ }
+ }
+ }
+
+ // Set the sampler texture unit to 0
+ glActiveTexture(GL_TEXTURE0);
+ glUniform1i(u_dither_texture_, 0);
+ glBindTexture(GL_TEXTURE_2D, get_dither_edge_texture()->get_gl_texture());
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
+
+ glActiveTexture(GL_TEXTURE1);
+ glUniform1i(u_terrain_texture_, 1);
+
+ // Which triangles to draw?
+ glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
+ for (size_t i = 0; i < vertices_.size(); ++i) {
+ const auto& current_data = vertices_[i];
+ if (current_data.empty()) {
+ continue;
+ }
+ glBindTexture(
+ GL_TEXTURE_2D,
+ g_gr->get_maptexture_data(terrains.get_unmutable(i).get_texture())->get_texture());
+
+ glBufferData(GL_ARRAY_BUFFER,
+ sizeof(PerVertexData) * current_data.size(),
+ current_data.data(),
+ GL_STREAM_DRAW);
+
+ const auto set_attrib_pointer = [](const int vertex_index, int num_items, int offset) {
+ glVertexAttribPointer(vertex_index,
+ num_items,
+ GL_FLOAT,
+ GL_FALSE,
+ sizeof(PerVertexData),
+ reinterpret_cast<void*>(offset));
+ };
+ set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
+ set_attrib_pointer(attr_dither_texture_position_, 2, offsetof(PerVertexData, dither_texture_x));
+ set_attrib_pointer(attr_position_, 2, offsetof(PerVertexData, x));
+ set_attrib_pointer(attr_texture_position_, 2, offsetof(PerVertexData, texture_x));
+
+ glDrawArrays(GL_TRIANGLES, 0, current_data.size());
+ }
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ glDisableVertexAttribArray(attr_brightness_);
+ glDisableVertexAttribArray(attr_dither_texture_position_);
+ glDisableVertexAttribArray(attr_position_);
+ glDisableVertexAttribArray(attr_texture_position_);
+
+ glActiveTexture(GL_TEXTURE0);
+
+ // Release Program object.
+ glUseProgram(0);
+}
=== added file 'src/graphic/gl/dither_program.h'
--- src/graphic/gl/dither_program.h 1970-01-01 00:00:00 +0000
+++ src/graphic/gl/dither_program.h 2014-11-01 20:50:47 +0000
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2006-2014 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_GRAPHIC_GL_DITHER_PROGRAM_H
+#define WL_GRAPHIC_GL_DITHER_PROGRAM_H
+
+#include "graphic/gl/fields_to_draw.h"
+#include "graphic/gl/utils.h"
+#include "logic/description_maintainer.h"
+#include "logic/world/terrain_description.h"
+
+class DitherProgram {
+public:
+ DitherProgram();
+
+ // Draws the terrain.
+ void draw(const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
+ const FieldsToDraw& fields_to_draw);
+
+private:
+ // Adds the triangle between the indexes (which index 'fields_to_draw' to
+ // vertices_ if the my_terrain != other_terrain and the dither_layer()
+ // agree.
+ void maybe_add_dithering_triangle(
+ const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
+ const FieldsToDraw& fields_to_draw,
+ int idx1,
+ int idx2,
+ int idx3,
+ int my_terrain,
+ int other_terrain);
+
+ // Adds the 'field' as an vertex to the 'vertices_' entry for 'terrain'. The
+ // 'order_index' defines which texture position will be used for this
+ // vertcx.
+ void add_vertex(const FieldsToDraw::Field& field, int order_index, int terrain);
+
+ struct PerVertexData {
+ float x;
+ float y;
+ float texture_x;
+ float texture_y;
+ float brightness;
+ float dither_texture_x;
+ float dither_texture_y;
+ };
+
+ // The program used for drawing the terrain.
+ Gl::Program gl_program_;
+
+ // The buffer that contains the data to be rendered.
+ Gl::Buffer gl_array_buffer_;
+
+ // Attributes.
+ GLint attr_position_;
+ GLint attr_texture_position_;
+ GLint attr_dither_texture_position_;
+ GLint attr_brightness_;
+
+ // Uniforms.
+ GLint u_terrain_texture_;
+ GLint u_dither_texture_;
+
+ // Objects below are here to avoid memory allocations on each frame, they
+ // could theoretically also always be recreated. Index as follows:
+ // vertices_[terrain_index][vertex_index]
+ std::vector<std::vector<PerVertexData>> vertices_;
+};
+
+#endif // end of include guard: WL_GRAPHIC_GL_DITHER_PROGRAM_H
=== added file 'src/graphic/gl/fields_to_draw.h'
--- src/graphic/gl/fields_to_draw.h 1970-01-01 00:00:00 +0000
+++ src/graphic/gl/fields_to_draw.h 2014-11-01 20:50:47 +0000
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2006-2014 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_GRAPHIC_GL_FIELDS_TO_DRAW_H
+#define WL_GRAPHIC_GL_FIELDS_TO_DRAW_H
+
+#include <vector>
+
+#include <stdint.h>
+
+// Helper struct that contains the data needed for drawing all fields. All
+// methods are inlined for performance reasons.
+class FieldsToDraw {
+public:
+ struct Field {
+ int fx, fy; // geometric coordinates (i.e. map coordinates that can be out of bounds).
+ float x, y; // Pixel position relative to top left.
+ float texture_x, texture_y; // Texture coordinates.
+ float brightness; // brightness of the pixel
+ uint8_t ter_r, ter_d; // Texture index of the right and down triangle.
+ uint8_t roads; // Bitmask of roads to render, see logic/roadtype.h.
+ };
+
+ FieldsToDraw(int minfx, int maxfx, int minfy, int maxfy)
+ : min_fx_(minfx),
+ max_fx_(maxfx),
+ min_fy_(minfy),
+ max_fy_(maxfy),
+ w_(max_fx_ - min_fx_ + 1),
+ h_(max_fy_ - min_fy_ + 1) {
+ fields_.resize(w_ * h_);
+ }
+
+ // Calculates the index of the given field with ('fx', 'fy') being geometric
+ // coordinates in the map. Returns -1 if this field is not in the fields_to_draw.
+ inline int calculate_index(int fx, int fy) const {
+ uint16_t xidx = fx - min_fx_;
+ if (xidx >= w_) {
+ return -1;
+ }
+ uint16_t yidx = fy - min_fy_;
+ if (yidx >= h_) {
+ return -1;
+ }
+ return yidx * w_ + xidx;
+ }
+
+ // The number of fields to draw.
+ inline size_t size() const {
+ return fields_.size();
+ }
+
+ // Get the field at 'index' which must be in bound.
+ inline const Field& at(const int index) const {
+ return fields_.at(index);
+ }
+
+ // Returns a mutable field at 'index' which must be in bound.
+ inline Field* mutable_field(const int index) {
+ return &fields_[index];
+ }
+
+private:
+ // Minimum and maximum field coordinates (geometric) to render. Can be negative.
+ const int min_fx_;
+ const int max_fx_;
+ const int min_fy_;
+ const int max_fy_;
+
+ // Width and height in number of fields.
+ const int w_;
+ const int h_;
+
+ std::vector<Field> fields_;
+};
+
+
+#endif // end of include guard: WL_GRAPHIC_GL_FIELDS_TO_DRAW_H
=== renamed file 'src/graphic/render/gamerenderer_gl.cc' => 'src/graphic/gl/game_renderer.cc'
--- src/graphic/render/gamerenderer_gl.cc 2014-09-20 09:37:47 +0000
+++ src/graphic/gl/game_renderer.cc 2014-11-01 20:50:47 +0000
@@ -17,484 +17,63 @@
*
*/
-#include "graphic/render/gamerenderer_gl.h"
-
-#include <SDL_image.h>
-
+#include "graphic/gl/game_renderer.h"
+
+#include <memory>
+
+#include "graphic/gl/dither_program.h"
+#include "graphic/gl/fields_to_draw.h"
+#include "graphic/gl/road_program.h"
+#include "graphic/gl/surface.h"
+#include "graphic/gl/terrain_program.h"
#include "graphic/graphic.h"
-#include "graphic/image_io.h"
-#include "graphic/render/gl_surface.h"
#include "graphic/rendertarget.h"
-#include "graphic/surface_cache.h"
#include "graphic/texture.h"
-#include "io/fileread.h"
-#include "io/filesystem/layered_filesystem.h"
#include "logic/editor_game_base.h"
#include "logic/player.h"
-#include "logic/world/terrain_description.h"
#include "logic/world/world.h"
#include "wui/mapviewpixelconstants.h"
#include "wui/mapviewpixelfunctions.h"
#include "wui/overlay_manager.h"
+namespace {
+
using namespace Widelands;
-static const uint32_t PatchSize = 4;
-
-GameRendererGL::GameRendererGL() :
- m_patch_vertices_size(0),
- m_patch_indices_size(0),
- m_edge_vertices_size(0),
- m_road_vertices_size(0)
-{
-}
-
-GameRendererGL::~GameRendererGL()
-{
-}
-
-const GLSurfaceTexture * GameRendererGL::get_dither_edge_texture()
-{
- const std::string fname = "world/pics/edge.png";
- const std::string cachename = std::string("gltex#") + fname;
-
- if (Surface* surface = g_gr->surfaces().get(cachename))
- return dynamic_cast<GLSurfaceTexture *>(surface);
-
- SDL_Surface* sdlsurf = load_image_as_sdl_surface(fname, g_fs);
- GLSurfaceTexture* edgetexture = new GLSurfaceTexture(sdlsurf, true);
- g_gr->surfaces().insert(cachename, edgetexture, false);
- return edgetexture;
-}
-
-uint32_t GameRendererGL::patch_index(const Coords & f) const
-{
- uint32_t x = f.x - m_patch_size.x;
- uint32_t y = f.y - m_patch_size.y;
-
- assert(x < m_patch_size.w);
- assert(y < m_patch_size.h);
-
- uint32_t outerx = x / PatchSize;
- uint32_t outery = y / PatchSize;
- uint32_t innerx = x % PatchSize;
- uint32_t innery = y % PatchSize;
-
- return
- (outery * (m_patch_size.w / PatchSize) + outerx) * (PatchSize * PatchSize) +
- innery * PatchSize + innerx;
-}
-
-uint8_t GameRendererGL::field_brightness(const FCoords & coords) const
-{
- uint32_t brightness;
- brightness = 144 + coords.field->get_brightness();
- brightness = (brightness * 255) / 160;
- if (brightness > 255)
- brightness = 255;
-
- if (m_player && !m_player->see_all()) {
- const Map & map = m_egbase->map();
- const Player::Field & pf = m_player->fields()[Map::get_index(coords, map.get_width())];
+// Returns the brightness value in [0, 1.] for 'fcoords' at 'gametime' for
+// 'player' (which can be nullptr).
+float field_brightness(const FCoords& fcoords,
+ const uint32_t gametime,
+ const Map& map,
+ const Player* const player) {
+ uint32_t brightness = 144 + fcoords.field->get_brightness();
+ brightness = std::min<uint32_t>(255, (brightness * 255) / 160);
+
+ if (player && !player->see_all()) {
+ const Player::Field& pf = player->fields()[Map::get_index(fcoords, map.get_width())];
if (pf.vision == 0) {
- return 0;
+ return 0.;
} else if (pf.vision == 1) {
- static const uint32_t DecayTime = 20000;
- Duration time_ago = m_egbase->get_gametime() - pf.time_node_last_unseen;
- if (time_ago < DecayTime)
- brightness = (brightness * (2 * DecayTime - time_ago)) / (2 * DecayTime);
- else
+ static const uint32_t kDecayTimeInMs = 20000;
+ const Duration time_ago = gametime - pf.time_node_last_unseen;
+ if (time_ago < kDecayTimeInMs) {
+ brightness = (brightness * (2 * kDecayTimeInMs - time_ago)) / (2 * kDecayTimeInMs);
+ } else {
brightness = brightness / 2;
- }
- }
-
- return brightness;
-}
-
-void GameRendererGL::draw()
-{
- const World & world = m_egbase->world();
- if (m_terrain_freq.size() < world.terrains().get_nitems()) {
- m_terrain_freq.resize(world.terrains().get_nitems());
- m_terrain_edge_freq.resize(world.terrains().get_nitems());
- }
-
- m_surface = dynamic_cast<GLSurface *>(m_dst->get_surface());
- if (!m_surface)
- return;
- m_rect = m_dst->get_rect();
- m_surface_offset = m_dst_offset + m_rect.top_left() + m_dst->get_offset();
-
- m_patch_size.x = m_minfx - 1;
- m_patch_size.y = m_minfy;
- m_patch_size.w = ((m_maxfx - m_minfx + 2 + PatchSize) / PatchSize) * PatchSize;
- m_patch_size.h = ((m_maxfy - m_minfy + 1 + PatchSize) / PatchSize) * PatchSize;
-
- glScissor
- (m_rect.x, m_surface->height() - m_rect.y - m_rect.h,
- m_rect.w, m_rect.h);
- glEnable(GL_SCISSOR_TEST);
-
- prepare_terrain_base();
- draw_terrain_base();
- if (g_gr->caps().gl.multitexture && g_gr->caps().gl.max_tex_combined >= 2) {
- prepare_terrain_dither();
- draw_terrain_dither();
- }
- prepare_roads();
- draw_roads();
- draw_objects();
-
- glDisable(GL_SCISSOR_TEST);
-}
-
-template<typename vertex>
-void GameRendererGL::compute_basevertex(const Coords & coords, vertex & vtx) const
-{
- const Map & map = m_egbase->map();
- Coords ncoords(coords);
- map.normalize_coords(ncoords);
- FCoords fcoords = map.get_fcoords(ncoords);
- Point pix;
- MapviewPixelFunctions::get_basepix(coords, pix.x, pix.y);
- pix.y -= fcoords.field->get_height() * HEIGHT_FACTOR;
- pix += m_surface_offset;
- vtx.x = pix.x;
- vtx.y = pix.y;
- Point tex;
- MapviewPixelFunctions::get_basepix(coords, tex.x, tex.y);
- vtx.tcx = float(tex.x) / TEXTURE_WIDTH;
- vtx.tcy = float(tex.y) / TEXTURE_HEIGHT;
- uint8_t brightness = field_brightness(fcoords);
- vtx.color[0] = vtx.color[1] = vtx.color[2] = brightness;
- vtx.color[3] = 255;
-}
-
-void GameRendererGL::count_terrain_base(TerrainIndex ter)
-{
- if (ter >= m_terrain_freq.size())
- m_terrain_freq.resize(ter + 1);
- m_terrain_freq[ter] += 1;
-}
-
-void GameRendererGL::add_terrain_base_triangle
- (TerrainIndex ter, const Coords & p1, const Coords & p2, const Coords & p3)
-{
- uint32_t index = m_patch_indices_indexs[ter];
- m_patch_indices[index++] = patch_index(p1);
- m_patch_indices[index++] = patch_index(p2);
- m_patch_indices[index++] = patch_index(p3);
- m_patch_indices_indexs[ter] = index;
-}
-
-void GameRendererGL::collect_terrain_base(bool onlyscan)
-{
- const Map & map = m_egbase->map();
-
- uint32_t index = 0;
- for (uint32_t outery = 0; outery < m_patch_size.h / PatchSize; ++outery) {
- for (uint32_t outerx = 0; outerx < m_patch_size.w / PatchSize; ++outerx) {
- for (uint32_t innery = 0; innery < PatchSize; ++innery) {
- for (uint32_t innerx = 0; innerx < PatchSize; ++innerx) {
- Coords coords
- (m_patch_size.x + outerx * PatchSize + innerx,
- m_patch_size.y + outery * PatchSize + innery);
-
- if (onlyscan) {
- assert(index == patch_index(coords));
- compute_basevertex(coords, m_patch_vertices[index]);
- ++index;
- }
-
- if (coords.x >= m_minfx && coords.y >= m_minfy && coords.x <= m_maxfx && coords.y <= m_maxfy) {
- Coords ncoords(coords);
- map.normalize_coords(ncoords);
- FCoords fcoords = map.get_fcoords(ncoords);
- TerrainIndex ter_d = fcoords.field->get_terrains().d;
- TerrainIndex ter_r = fcoords.field->get_terrains().r;
-
- if (onlyscan) {
- count_terrain_base(ter_d);
- count_terrain_base(ter_r);
- } else {
- Coords brn(coords.x + (coords.y & 1), coords.y + 1);
- Coords bln(brn.x - 1, brn.y);
- Coords rn(coords.x + 1, coords.y);
-
- add_terrain_base_triangle(ter_d, coords, bln, brn);
- add_terrain_base_triangle(ter_r, coords, brn, rn);
- }
- }
- }
- }
- }
- }
-}
-
-void GameRendererGL::prepare_terrain_base()
-{
- static_assert(sizeof(BaseVertex) == 32, "assert(sizeof(basevertex) == 32) failed.");
-
- uint32_t reqsize = m_patch_size.w * m_patch_size.h;
- if (reqsize > 0x10000)
- throw wexception("Too many vertices; decrease screen resolution");
-
- if (reqsize > m_patch_vertices_size) {
- m_patch_vertices.reset(new BaseVertex[reqsize]);
- m_patch_vertices_size = reqsize;
- }
-
- m_terrain_freq.assign(m_terrain_freq.size(), 0);
-
- collect_terrain_base(true);
-
- m_terrain_freq_cum.resize(m_terrain_freq.size());
- uint32_t nrtriangles = 0;
- for (uint32_t idx = 0; idx < m_terrain_freq.size(); ++idx) {
- m_terrain_freq_cum[idx] = nrtriangles;
- nrtriangles += m_terrain_freq[idx];
- }
-
- if (3 * nrtriangles > m_patch_indices_size) {
- m_patch_indices.reset(new uint16_t[3 * nrtriangles]);
- m_patch_indices_size = 3 * nrtriangles;
- }
-
- m_patch_indices_indexs.resize(m_terrain_freq.size());
- for (TerrainIndex ter = 0; ter < m_terrain_freq.size(); ++ter)
- m_patch_indices_indexs[ter] = 3 * m_terrain_freq_cum[ter];
-
- collect_terrain_base(false);
-
- for (TerrainIndex ter = 0; ter < m_terrain_freq.size(); ++ter) {
- assert(m_patch_indices_indexs[ter] == 3 * (m_terrain_freq_cum[ter] + m_terrain_freq[ter]));
- }
-}
-
-void GameRendererGL::draw_terrain_base()
-{
- const World & world = m_egbase->world();
-
- glMatrixMode(GL_TEXTURE);
- glLoadIdentity();
-
- glVertexPointer(2, GL_FLOAT, sizeof(BaseVertex), &m_patch_vertices[0].x);
- glTexCoordPointer(2, GL_FLOAT, sizeof(BaseVertex), &m_patch_vertices[0].tcx);
- glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(BaseVertex), &m_patch_vertices[0].color);
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
-
- glColor3f(1.0, 1.0, 1.0);
- glDisable(GL_BLEND);
-
- for (TerrainIndex ter = 0; ter < m_terrain_freq.size(); ++ter) {
- if (!m_terrain_freq[ter])
- continue;
-
- const Texture & texture =
- *g_gr->get_maptexture_data
- (world.terrain_descr(ter).get_texture());
- glBindTexture(GL_TEXTURE_2D, texture.get_texture());
- glDrawRangeElements
- (GL_TRIANGLES,
- 0, m_patch_size.w * m_patch_size.h - 1,
- 3 * m_terrain_freq[ter], GL_UNSIGNED_SHORT,
- &m_patch_indices[3 * m_terrain_freq_cum[ter]]);
- }
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
-}
-
-void GameRendererGL::add_terrain_dither_triangle
- (bool onlyscan, TerrainIndex ter, const Coords & edge1, const Coords & edge2, const Coords & opposite)
-{
- if (onlyscan) {
- assert(ter < m_terrain_edge_freq.size());
- m_terrain_edge_freq[ter] += 1;
- } else {
- static const float TyZero = 1.0 / TEXTURE_HEIGHT;
- static const float TyOne = 1.0 - TyZero;
-
- uint32_t index = m_terrain_edge_indexs[ter];
- compute_basevertex(edge1, m_edge_vertices[index]);
- m_edge_vertices[index].edgex = 0.0;
- m_edge_vertices[index].edgey = TyZero;
- ++index;
- compute_basevertex(edge2, m_edge_vertices[index]);
- m_edge_vertices[index].edgex = 1.0;
- m_edge_vertices[index].edgey = TyZero;
- ++index;
- compute_basevertex(opposite, m_edge_vertices[index]);
- m_edge_vertices[index].edgex = 0.5;
- m_edge_vertices[index].edgey = TyOne;
- ++index;
- m_terrain_edge_indexs[ter] = index;
- }
-}
-
-void GameRendererGL::collect_terrain_dither(bool onlyscan)
-{
- const Map & map = m_egbase->map();
- const World & world = m_egbase->world();
-
- for (int32_t fy = m_minfy; fy <= m_maxfy; ++fy) {
- for (int32_t fx = m_minfx; fx <= m_maxfx; ++fx) {
- Coords ncoords(fx, fy);
- map.normalize_coords(ncoords);
- FCoords fcoords = map.get_fcoords(ncoords);
-
- TerrainIndex ter_d = fcoords.field->get_terrains().d;
- TerrainIndex ter_r = fcoords.field->get_terrains().r;
- TerrainIndex ter_u = map.tr_n(fcoords).field->get_terrains().d;
- TerrainIndex ter_rr = map.r_n(fcoords).field->get_terrains().d;
- TerrainIndex ter_l = map.l_n(fcoords).field->get_terrains().r;
- TerrainIndex ter_dd = map.bl_n(fcoords).field->get_terrains().r;
- int32_t lyr_d = world.terrain_descr(ter_d).dither_layer();
- int32_t lyr_r = world.terrain_descr(ter_r).dither_layer();
- int32_t lyr_u = world.terrain_descr(ter_u).dither_layer();
- int32_t lyr_rr = world.terrain_descr(ter_rr).dither_layer();
- int32_t lyr_l = world.terrain_descr(ter_l).dither_layer();
- int32_t lyr_dd = world.terrain_descr(ter_dd).dither_layer();
-
- Coords f(fx, fy);
- Coords rn(fx + 1, fy);
- Coords brn(fx + (fy & 1), fy + 1);
- Coords bln(brn.x - 1, brn.y);
-
- if (lyr_r > lyr_d) {
- add_terrain_dither_triangle(onlyscan, ter_r, brn, f, bln);
- } else if (ter_d != ter_r) {
- add_terrain_dither_triangle(onlyscan, ter_d, f, brn, rn);
- }
- if ((lyr_u > lyr_r) || (lyr_u == lyr_r && ter_u != ter_r)) {
- add_terrain_dither_triangle(onlyscan, ter_u, rn, f, brn);
- }
- if (lyr_rr > lyr_r) {
- add_terrain_dither_triangle(onlyscan, ter_rr, brn, rn, f);
- }
- if ((lyr_l > lyr_d) || (lyr_l == lyr_d && ter_l != ter_d)) {
- add_terrain_dither_triangle(onlyscan, ter_l, f, bln, brn);
- }
- if (lyr_dd > lyr_d) {
- add_terrain_dither_triangle(onlyscan, ter_dd, bln, brn, f);
- }
- }
- }
-}
-
-/*
- * Schematic of triangle neighborhood:
- *
- * *
- * / \
- * / u \
- * (f)/ \
- * *------*------* (r)
- * \ l / \ r / \
- * \ / \ / \
- * \/ d \/ rr \
- * *------*------* (br)
- * \ dd /
- * \ /
- * \/
- * *
- */
-void GameRendererGL::prepare_terrain_dither()
-{
- static_assert(sizeof(DitherVertex) == 32, "assert(sizeof(dithervertex) == 32) failed.");
-
- m_terrain_edge_freq.assign(m_terrain_edge_freq.size(), 0);
-
- collect_terrain_dither(true);
-
- uint32_t nrtriangles = 0;
- m_terrain_edge_freq_cum.resize(m_terrain_edge_freq.size());
- for (TerrainIndex ter = 0; ter < m_terrain_edge_freq.size(); ++ter) {
- m_terrain_edge_freq_cum[ter] = nrtriangles;
- nrtriangles += m_terrain_edge_freq[ter];
- }
-
- if (3 * nrtriangles > m_edge_vertices_size) {
- m_edge_vertices.reset(new DitherVertex[3 * nrtriangles]);
- m_edge_vertices_size = 3 * nrtriangles;
- }
-
- m_terrain_edge_indexs.resize(m_terrain_edge_freq_cum.size());
- for (TerrainIndex ter = 0; ter < m_terrain_edge_freq.size(); ++ter)
- m_terrain_edge_indexs[ter] = 3 * m_terrain_edge_freq_cum[ter];
-
- collect_terrain_dither(false);
-
- for (TerrainIndex ter = 0; ter < m_terrain_edge_freq.size(); ++ter) {
- assert(m_terrain_edge_indexs[ter] == 3 * (m_terrain_edge_freq_cum[ter] + m_terrain_edge_freq[ter]));
- }
-}
-
-void GameRendererGL::draw_terrain_dither()
-{
- if (m_edge_vertices_size == 0)
- return;
-
- glVertexPointer(2, GL_FLOAT, sizeof(DitherVertex), &m_edge_vertices[0].x);
- glTexCoordPointer(2, GL_FLOAT, sizeof(DitherVertex), &m_edge_vertices[0].tcx);
- glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(DitherVertex), &m_edge_vertices[0].color);
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
-
- glActiveTextureARB(GL_TEXTURE1_ARB);
- glClientActiveTextureARB(GL_TEXTURE1_ARB);
- glTexCoordPointer(2, GL_FLOAT, sizeof(DitherVertex), &m_edge_vertices[0].edgex);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- GLuint edge = get_dither_edge_texture()->get_gl_texture();
- glBindTexture(GL_TEXTURE_2D, edge);
- glEnable(GL_TEXTURE_2D);
- glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_COMBINE_ARB);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_RGB_ARB, GL_REPLACE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_RGB_ARB, GL_PREVIOUS);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_RGB_ARB, GL_SRC_COLOR);
- glTexEnvi(GL_TEXTURE_ENV, GL_COMBINE_ALPHA_ARB, GL_REPLACE);
- glTexEnvi(GL_TEXTURE_ENV, GL_SOURCE0_ALPHA_ARB, GL_TEXTURE);
- glTexEnvi(GL_TEXTURE_ENV, GL_OPERAND0_ALPHA_ARB, GL_SRC_ALPHA);
- glActiveTextureARB(GL_TEXTURE0_ARB);
- glClientActiveTextureARB(GL_TEXTURE0_ARB);
-
- glEnable(GL_BLEND);
- glBlendFunc(GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA);
-
- for (TerrainIndex ter = 0; ter < m_terrain_freq.size(); ++ter) {
- if (!m_terrain_edge_freq[ter])
- continue;
-
- const Texture & texture =
- *g_gr->get_maptexture_data
- (m_egbase->world().terrain_descr(ter).get_texture());
- glBindTexture(GL_TEXTURE_2D, texture.get_texture());
- glDrawArrays
- (GL_TRIANGLES,
- 3 * m_terrain_edge_freq_cum[ter], 3 * m_terrain_edge_freq[ter]);
- }
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
- glActiveTextureARB(GL_TEXTURE1_ARB);
- glClientActiveTextureARB(GL_TEXTURE1_ARB);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glDisable(GL_TEXTURE_2D);
- glActiveTextureARB(GL_TEXTURE0_ARB);
- glClientActiveTextureARB(GL_TEXTURE0_ARB);
-}
-
-uint8_t GameRendererGL::field_roads(const FCoords & coords) const
-{
+ }
+ }
+ }
+ return brightness / 255.;
+}
+
+// Returns the road that should be rendered here. The format is like in field,
+// but this is not the physically present road, but the one that should be
+// drawn (i.e. taking into account if there is fog of war involved or road
+// building overlays enabled).
+uint8_t field_roads(const FCoords& coords, const Map& map, const Player* const player) {
uint8_t roads;
- const Map & map = m_egbase->map();
- if (m_player && !m_player->see_all()) {
- const Player::Field & pf = m_player->fields()[Map::get_index(coords, map.get_width())];
+ if (player && !player->see_all()) {
+ const Player::Field& pf = player->fields()[Map::get_index(coords, map.get_width())];
roads = pf.roads | map.overlay_manager().get_road_overlay(coords);
} else {
roads = coords.field->get_roads();
@@ -503,159 +82,111 @@
return roads;
}
-void GameRendererGL::prepare_roads()
-{
- const Map & map = m_egbase->map();
-
- m_road_freq[0] = 0;
- m_road_freq[1] = 0;
-
- for (int32_t fy = m_minfy; fy <= m_maxfy; ++fy) {
- for (int32_t fx = m_minfx; fx <= m_maxfx; ++fx) {
- Coords ncoords(fx, fy);
- map.normalize_coords(ncoords);
- FCoords fcoords = map.get_fcoords(ncoords);
- uint8_t roads = field_roads(fcoords);
-
- for (int dir = 0; dir < 3; ++dir) {
- uint8_t road = (roads >> (2 * dir)) & Road_Mask;
- if (road >= Road_Normal && road <= Road_Busy) {
- ++m_road_freq[road - Road_Normal];
- }
- }
- }
- }
-
- uint32_t nrquads = m_road_freq[0] + m_road_freq[1];
- if (4 * nrquads > m_road_vertices_size) {
- m_road_vertices.reset(new BaseVertex[4 * nrquads]);
- m_road_vertices_size = 4 * nrquads;
- }
-
- uint32_t indexs[2];
- indexs[0] = 0;
- indexs[1] = 4 * m_road_freq[0];
-
- for (int32_t fy = m_minfy; fy <= m_maxfy; ++fy) {
- for (int32_t fx = m_minfx; fx <= m_maxfx; ++fx) {
- Coords ncoords(fx, fy);
- map.normalize_coords(ncoords);
- FCoords fcoords = map.get_fcoords(ncoords);
- uint8_t roads = field_roads(fcoords);
-
- uint8_t road = (roads >> Road_East) & Road_Mask;
- if (road >= Road_Normal && road <= Road_Busy) {
- uint32_t index = indexs[road - Road_Normal];
- BaseVertex start, end;
- compute_basevertex(Coords(fx, fy), start);
- compute_basevertex(Coords(fx + 1, fy), end);
- m_road_vertices[index] = start;
- m_road_vertices[index].y -= 2;
- m_road_vertices[index].tcy -= 2.0 / TEXTURE_HEIGHT;
- ++index;
- m_road_vertices[index] = start;
- m_road_vertices[index].y += 2;
- m_road_vertices[index].tcy += 2.0 / TEXTURE_HEIGHT;
- ++index;
- m_road_vertices[index] = end;
- m_road_vertices[index].y += 2;
- m_road_vertices[index].tcy += 2.0 / TEXTURE_HEIGHT;
- ++index;
- m_road_vertices[index] = end;
- m_road_vertices[index].y -= 2;
- m_road_vertices[index].tcy -= 2.0 / TEXTURE_HEIGHT;
- ++index;
- indexs[road - Road_Normal] = index;
- }
-
- road = (roads >> Road_SouthEast) & Road_Mask;
- if (road >= Road_Normal && road <= Road_Busy) {
- uint32_t index = indexs[road - Road_Normal];
- BaseVertex start, end;
- compute_basevertex(Coords(fx, fy), start);
- compute_basevertex(Coords(fx + (fy & 1), fy + 1), end);
- m_road_vertices[index] = start;
- m_road_vertices[index].x += 3;
- m_road_vertices[index].tcx += 3.0 / TEXTURE_HEIGHT;
- ++index;
- m_road_vertices[index] = start;
- m_road_vertices[index].x -= 3;
- m_road_vertices[index].tcx -= 3.0 / TEXTURE_HEIGHT;
- ++index;
- m_road_vertices[index] = end;
- m_road_vertices[index].x -= 3;
- m_road_vertices[index].tcx -= 3.0 / TEXTURE_HEIGHT;
- ++index;
- m_road_vertices[index] = end;
- m_road_vertices[index].x += 3;
- m_road_vertices[index].tcx += 3.0 / TEXTURE_HEIGHT;
- ++index;
- indexs[road - Road_Normal] = index;
- }
-
- road = (roads >> Road_SouthWest) & Road_Mask;
- if (road >= Road_Normal && road <= Road_Busy) {
- uint32_t index = indexs[road - Road_Normal];
- BaseVertex start, end;
- compute_basevertex(Coords(fx, fy), start);
- compute_basevertex(Coords(fx + (fy & 1) - 1, fy + 1), end);
- m_road_vertices[index] = start;
- m_road_vertices[index].x += 3;
- m_road_vertices[index].tcx += 3.0 / TEXTURE_HEIGHT;
- ++index;
- m_road_vertices[index] = start;
- m_road_vertices[index].x -= 3;
- m_road_vertices[index].tcx -= 3.0 / TEXTURE_HEIGHT;
- ++index;
- m_road_vertices[index] = end;
- m_road_vertices[index].x -= 3;
- m_road_vertices[index].tcx -= 3.0 / TEXTURE_HEIGHT;
- ++index;
- m_road_vertices[index] = end;
- m_road_vertices[index].x += 3;
- m_road_vertices[index].tcx += 3.0 / TEXTURE_HEIGHT;
- ++index;
- indexs[road - Road_Normal] = index;
- }
- }
- }
-
- assert(indexs[0] == 4 * m_road_freq[0]);
- assert(indexs[1] == 4 * nrquads);
-}
-
-void GameRendererGL::draw_roads()
-{
- if (!m_road_freq[0] && !m_road_freq[1])
+} // namespace
+
+// Explanation of how drawing works:
+// Schematic of triangle neighborhood:
+//
+// *
+// / \
+// / u \
+// (f)/ \
+// *------*------* (r)
+// \ l / \ r / \
+// \ / \ / \
+// \/ d \/ rr \
+// *------*------* (br)
+// \ dd /
+// \ /
+// \/
+// *
+//
+// Each field (f) owns two triangles: (r)ight & (d)own. When we look at the
+// field, we have to make sure to schedule drawing the triangles. This is done
+// by of these triangles is done by TerrainProgram.
+//
+// To draw dithered edges, we have to look at the neighboring triangles for the
+// two triangles too: If a neighboring triangle has another texture and our
+// dither layer is smaller, we have to draw a dithering triangle too - this lets the neighboring
+// texture
+// bleed into our triangle.
+//
+// The dither triangle is the triangle that should be partially (either r or
+// d). Example: if r and d have different textures and r.dither_layer >
+// d.dither_layer, then we will repaint d with the dither texture as mask.
+
+
+std::unique_ptr<TerrainProgram> GlGameRenderer::terrain_program_;
+std::unique_ptr<DitherProgram> GlGameRenderer::dither_program_;
+std::unique_ptr<RoadProgram> GlGameRenderer::road_program_;
+
+GlGameRenderer::GlGameRenderer() {
+}
+
+GlGameRenderer::~GlGameRenderer() {
+}
+
+void GlGameRenderer::draw() {
+ if (terrain_program_ == nullptr) {
+ terrain_program_.reset(new TerrainProgram());
+ dither_program_.reset(new DitherProgram());
+ road_program_.reset(new RoadProgram());
+ }
+
+ GLSurface* surface = dynamic_cast<GLSurface*>(m_dst->get_surface());
+ if (!surface)
return;
- GLuint rt_normal =
- dynamic_cast<const GLSurfaceTexture &>
- (g_gr->get_road_texture(Widelands::Road_Normal)).get_gl_texture();
- GLuint rt_busy =
- dynamic_cast<const GLSurfaceTexture &>
- (g_gr->get_road_texture(Widelands::Road_Busy)).get_gl_texture();
-
- glVertexPointer(2, GL_FLOAT, sizeof(BaseVertex), &m_road_vertices[0].x);
- glTexCoordPointer(2, GL_FLOAT, sizeof(BaseVertex), &m_road_vertices[0].tcx);
- glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(BaseVertex), &m_road_vertices[0].color);
- glEnableClientState(GL_VERTEX_ARRAY);
- glEnableClientState(GL_TEXTURE_COORD_ARRAY);
- glEnableClientState(GL_COLOR_ARRAY);
-
- glDisable(GL_BLEND);
-
- if (m_road_freq[0]) {
- glBindTexture(GL_TEXTURE_2D, rt_normal);
- glDrawArrays(GL_QUADS, 0, 4 * m_road_freq[0]);
- }
-
- if (m_road_freq[1]) {
- glBindTexture(GL_TEXTURE_2D, rt_busy);
- glDrawArrays(GL_QUADS, 4 * m_road_freq[0], 4 * m_road_freq[1]);
- }
-
- glDisableClientState(GL_VERTEX_ARRAY);
- glDisableClientState(GL_TEXTURE_COORD_ARRAY);
- glDisableClientState(GL_COLOR_ARRAY);
+ const Rect& bounding_rect = m_dst->get_rect();
+ const Point surface_offset = m_dst_offset + bounding_rect.top_left() + m_dst->get_offset();
+
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ glScissor(bounding_rect.x,
+ surface->height() - bounding_rect.y - bounding_rect.h,
+ bounding_rect.w,
+ bounding_rect.h);
+ glEnable(GL_SCISSOR_TEST);
+
+ Map& map = m_egbase->map();
+ const uint32_t gametime = m_egbase->get_gametime();
+
+ FieldsToDraw fields_to_draw(m_minfx, m_maxfx, m_minfy, m_maxfy);
+ for (int32_t fy = m_minfy; fy <= m_maxfy; ++fy) {
+ for (int32_t fx = m_minfx; fx <= m_maxfx; ++fx) {
+ FieldsToDraw::Field& f =
+ *fields_to_draw.mutable_field(fields_to_draw.calculate_index(fx, fy));
+
+ f.fx = fx;
+ f.fy = fy;
+
+ Coords coords(fx, fy);
+ int x, y;
+ MapviewPixelFunctions::get_basepix(coords, x, y);
+
+ map.normalize_coords(coords);
+ const FCoords& fcoords = map.get_fcoords(coords);
+
+ f.texture_x = float(x) / TEXTURE_WIDTH;
+ f.texture_y = float(y) / TEXTURE_HEIGHT;
+ f.x = x + surface_offset.x;
+ f.y = y + surface_offset.y - fcoords.field->get_height() * HEIGHT_FACTOR;
+
+ f.ter_d = fcoords.field->terrain_d();
+ f.ter_r = fcoords.field->terrain_r();
+
+ f.brightness = field_brightness(fcoords, gametime, map, m_player);
+
+ f.roads = field_roads(fcoords, map, m_player);
+ }
+ }
+
+ const World& world = m_egbase->world();
+ terrain_program_->draw(world.terrains(), fields_to_draw);
+ dither_program_->draw(world.terrains(), fields_to_draw);
+ road_program_->draw(fields_to_draw);
+
+ draw_objects();
+
+ glDisable(GL_SCISSOR_TEST);
}
=== renamed file 'src/graphic/render/gamerenderer_gl.h' => 'src/graphic/gl/game_renderer.h'
--- src/graphic/render/gamerenderer_gl.h 2014-09-14 16:08:13 +0000
+++ src/graphic/gl/game_renderer.h 2014-11-01 20:50:47 +0000
@@ -17,112 +17,32 @@
*
*/
-#ifndef WL_GRAPHIC_RENDER_GAMERENDERER_GL_H
-#define WL_GRAPHIC_RENDER_GAMERENDERER_GL_H
+#ifndef WL_GRAPHIC_GL_GAME_RENDERER_H
+#define WL_GRAPHIC_GL_GAME_RENDERER_H
#include <memory>
-#include <vector>
-
-#include "base/rect.h"
-#include "graphic/render/gamerenderer.h"
-#include "logic/widelands.h"
-
-namespace Widelands {
-struct Coords;
-struct FCoords;
-class World;
-}
-
-class GLSurface;
-class GLSurfaceTexture;
+
+#include "graphic/game_renderer.h"
+#include "graphic/gl/utils.h"
+
+class TerrainProgram;
+class DitherProgram;
+class RoadProgram;
/**
* OpenGL implementation of @ref GameRenderer.
*/
-class GameRendererGL : public GameRenderer {
+class GlGameRenderer : public GameRenderer {
public:
- GameRendererGL();
- virtual ~GameRendererGL();
+ GlGameRenderer();
+ virtual ~GlGameRenderer();
private:
- struct BaseVertex {
- float x;
- float y;
- float tcx;
- float tcy;
- uint8_t color[4];
- uint32_t pad[3];
- };
-
- struct DitherVertex {
- float x;
- float y;
- float tcx;
- float tcy;
- float edgex;
- float edgey;
- uint8_t color[4];
- uint32_t pad[1];
- };
-
- const GLSurfaceTexture * get_dither_edge_texture();
+ static std::unique_ptr<TerrainProgram> terrain_program_;
+ static std::unique_ptr<DitherProgram> dither_program_;
+ static std::unique_ptr<RoadProgram> road_program_;
void draw() override;
- void prepare_terrain_base();
- void collect_terrain_base(bool onlyscan);
- void count_terrain_base(Widelands::TerrainIndex ter);
- void add_terrain_base_triangle
- (Widelands::TerrainIndex ter,
- const Widelands::Coords & p1, const Widelands::Coords & p2, const Widelands::Coords & p3);
- void draw_terrain_base();
- void prepare_terrain_dither();
- void collect_terrain_dither(bool onlyscan);
- void add_terrain_dither_triangle
- (bool onlyscan, Widelands::TerrainIndex ter,
- const Widelands::Coords & edge1, const Widelands::Coords & edge2,
- const Widelands::Coords & opposite);
- void draw_terrain_dither();
- void prepare_roads();
- void draw_roads();
-
- uint32_t patch_index(const Widelands::Coords & f) const;
- uint8_t field_brightness(const Widelands::FCoords & coords) const;
- uint8_t field_roads(const Widelands::FCoords & coords) const;
- template<typename vertex>
- void compute_basevertex(const Widelands::Coords & coords, vertex & vtx) const;
-
- /**
- * The following variables are only valid during rendering.
- */
- /*@{*/
- GLSurface * m_surface;
-
- /// Bounding rectangle inside the destination surface
- Rect m_rect;
-
- /// Translation from map pixel coordinates to surface pixel coordinates
- /// (relative to the top-left corner of the surface, @b not relative
- /// to the bounding rectangle)
- Point m_surface_offset;
-
- Rect m_patch_size;
- std::unique_ptr<BaseVertex[]> m_patch_vertices;
- uint32_t m_patch_vertices_size;
- std::unique_ptr<uint16_t[]> m_patch_indices;
- uint32_t m_patch_indices_size;
- std::vector<uint32_t> m_patch_indices_indexs;
- std::vector<uint32_t> m_terrain_freq;
- std::vector<uint32_t> m_terrain_freq_cum;
- std::unique_ptr<DitherVertex[]> m_edge_vertices;
- uint32_t m_edge_vertices_size;
- std::vector<uint32_t> m_terrain_edge_freq;
- std::vector<uint32_t> m_terrain_edge_freq_cum;
- std::vector<uint32_t> m_terrain_edge_indexs;
-
- uint32_t m_road_freq[2];
- std::unique_ptr<BaseVertex[]> m_road_vertices;
- uint32_t m_road_vertices_size;
- /*@}*/
};
-#endif // end of include guard: WL_GRAPHIC_RENDER_GAMERENDERER_GL_H
+#endif // end of include guard: WL_GRAPHIC_GL_GAME_RENDERER_H
=== added file 'src/graphic/gl/road_program.cc'
--- src/graphic/gl/road_program.cc 1970-01-01 00:00:00 +0000
+++ src/graphic/gl/road_program.cc 2014-11-01 20:50:47 +0000
@@ -0,0 +1,232 @@
+/*
+ * Copyright (C) 2006-2014 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "graphic/gl/road_program.h"
+
+#include <cmath>
+
+#include "base/log.h"
+#include "graphic/gl/fields_to_draw.h"
+#include "graphic/graphic.h"
+#include "graphic/texture.h"
+#include "logic/roadtype.h"
+
+namespace {
+
+// We target OpenGL 2.1 for the desktop here.
+// TODO(sirver): In the end we need to replace gl_ProjectionMatrix. It is not
+// supported in ES and more modern Open GL version.
+const char kRoadVertexShader[] = R"(
+#version 120
+
+// Attributes.
+attribute vec2 attr_position;
+attribute vec2 attr_texture_position;
+attribute float attr_texture_mix;
+attribute float attr_brightness;
+
+// Outputs.
+varying vec2 out_texture_position;
+varying float out_texture_mix;
+varying float out_brightness;
+
+void main() {
+ out_texture_position = attr_texture_position;
+ out_texture_mix = attr_texture_mix;
+ out_brightness = attr_brightness;
+ gl_Position = gl_ProjectionMatrix * vec4(attr_position, 0., 1.);
+}
+)";
+
+const char kRoadFragmentShader[] = R"(
+#version 120
+
+// Inputs.
+varying vec2 out_texture_position;
+varying float out_texture_mix;
+varying float out_brightness;
+
+uniform sampler2D u_normal_road_texture;
+uniform sampler2D u_busy_road_texture;
+
+void main() {
+ vec4 normal_road_color = texture2D(u_normal_road_texture, out_texture_position);
+ vec4 busy_road_color = texture2D(u_busy_road_texture, out_texture_position);
+ vec4 color = mix(normal_road_color, busy_road_color, out_texture_mix);
+ color.rgb *= out_brightness;
+ gl_FragColor = color;
+}
+)";
+
+} // namespace
+
+RoadProgram::RoadProgram() {
+ gl_program_.build(kRoadVertexShader, kRoadFragmentShader);
+
+ attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
+ attr_texture_position_ =
+ glGetAttribLocation(gl_program_.object(), "attr_texture_position");
+ attr_texture_mix_ = glGetAttribLocation(gl_program_.object(), "attr_texture_mix");
+ attr_brightness_ = glGetAttribLocation(gl_program_.object(), "attr_brightness");
+
+ u_normal_road_texture_ = glGetUniformLocation(gl_program_.object(), "u_normal_road_texture");
+ u_busy_road_texture_ = glGetUniformLocation(gl_program_.object(), "u_busy_road_texture");
+}
+
+void RoadProgram::add_road(const FieldsToDraw::Field& start,
+ const FieldsToDraw::Field& end,
+ const Widelands::RoadType road_type) {
+ static constexpr float kRoadThicknessInPixels = 3.;
+ const float delta_x = end.x - start.x;
+ const float delta_y = end.y - start.y;
+ const float vector_length = std::hypot(delta_x, delta_y);
+
+ // Find the reciprocal unit vector, so that we can calculate start and end
+ // points for the quad that will make the road.
+ const float dx = -delta_y / vector_length;
+ const float dy = delta_x / vector_length;
+
+ const float texture_mix = road_type == Widelands::Road_Normal ? 0. : 1.;
+ const PerVertexData p1 = {
+ start.x + kRoadThicknessInPixels * dx, start.y + kRoadThicknessInPixels * dy,
+ 0., 0.,
+ start.brightness,
+ texture_mix,
+ };
+ const PerVertexData p2 = {
+ start.x - kRoadThicknessInPixels * dx, start.y - kRoadThicknessInPixels * dy,
+ 0., 1.,
+ start.brightness,
+ texture_mix,
+ };
+ const PerVertexData p3 = {
+ end.x + kRoadThicknessInPixels * dx, end.y + kRoadThicknessInPixels * dy,
+ 1., 0.,
+ end.brightness,
+ texture_mix,
+ };
+ const PerVertexData p4 = {
+ end.x - kRoadThicknessInPixels * dx, end.y - kRoadThicknessInPixels * dy,
+ 1., 1.,
+ end.brightness,
+ texture_mix,
+ };
+
+ // As OpenGl does not support drawing quads in modern days and we have a
+ // bunch of roads that might not be neighbored, we need to add two triangles
+ // for each road. :(. Another alternative would be to use primitive restart,
+ // but that is a fairly recent OpenGL feature.
+ vertices_.emplace_back(p1);
+ vertices_.emplace_back(p2);
+ vertices_.emplace_back(p3);
+ vertices_.emplace_back(p2);
+ vertices_.emplace_back(p3);
+ vertices_.emplace_back(p4);
+}
+
+void RoadProgram::draw(const FieldsToDraw& fields_to_draw) {
+ vertices_.clear();
+
+ for (size_t current_index = 0; current_index < fields_to_draw.size(); ++current_index) {
+ const FieldsToDraw::Field& field = fields_to_draw.at(current_index);
+
+ // Road to right neighbor.
+ const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
+ if (rn_index != -1) {
+ const Widelands::RoadType road =
+ static_cast<Widelands::RoadType>(field.roads & Widelands::Road_Mask);
+ if (road != Widelands::Road_None) {
+ add_road(field, fields_to_draw.at(rn_index), road);
+ }
+ }
+
+ // Road to bottom right neighbor.
+ const int brn_index = fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy + 1);
+ if (brn_index != -1) {
+ const Widelands::RoadType road =
+ static_cast<Widelands::RoadType>((field.roads >> 2) & Widelands::Road_Mask);
+ if (road != Widelands::Road_None) {
+ add_road(field, fields_to_draw.at(brn_index), road);
+ }
+ }
+
+ // Road to bottom right neighbor.
+ const int bln_index =
+ fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
+ if (brn_index != -1) {
+ const Widelands::RoadType road =
+ static_cast<Widelands::RoadType>((field.roads >> 4) & Widelands::Road_Mask);
+ if (road != Widelands::Road_None) {
+ add_road(field, fields_to_draw.at(bln_index), road);
+ }
+ }
+ }
+
+ glUseProgram(gl_program_.object());
+
+ glEnableVertexAttribArray(attr_position_);
+ glEnableVertexAttribArray(attr_texture_position_);
+ glEnableVertexAttribArray(attr_brightness_);
+ glEnableVertexAttribArray(attr_texture_mix_);
+
+ glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
+ glBufferData(
+ GL_ARRAY_BUFFER, sizeof(PerVertexData) * vertices_.size(), vertices_.data(), GL_STREAM_DRAW);
+
+ const auto set_attrib_pointer = [](const int vertex_index, int num_items, int offset) {
+ glVertexAttribPointer(vertex_index,
+ num_items,
+ GL_FLOAT,
+ GL_FALSE,
+ sizeof(PerVertexData),
+ reinterpret_cast<void*>(offset));
+ };
+ set_attrib_pointer(attr_position_, 2, offsetof(PerVertexData, x));
+ set_attrib_pointer(attr_texture_position_, 2, offsetof(PerVertexData, texture_x));
+ set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
+ set_attrib_pointer(attr_texture_mix_, 1, offsetof(PerVertexData, texture_mix));
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ // Bind the textures.
+ const GLuint rt_normal = dynamic_cast<const GLSurfaceTexture&>(
+ g_gr->get_road_texture(Widelands::Road_Normal)).get_gl_texture();
+ const GLuint rt_busy = dynamic_cast<const GLSurfaceTexture&>(
+ g_gr->get_road_texture(Widelands::Road_Busy)).get_gl_texture();
+
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, rt_normal);
+ glUniform1i(u_normal_road_texture_, 0);
+
+ glActiveTexture(GL_TEXTURE1);
+ glBindTexture(GL_TEXTURE_2D, rt_busy);
+ glUniform1i(u_busy_road_texture_, 1);
+
+ glDrawArrays(GL_TRIANGLES, 0, vertices_.size());
+
+ glDisableVertexAttribArray(attr_position_);
+ glDisableVertexAttribArray(attr_texture_position_);
+ glDisableVertexAttribArray(attr_brightness_);
+ glDisableVertexAttribArray(attr_texture_mix_);
+
+ glActiveTexture(GL_TEXTURE0);
+
+ glUseProgram(0);
+
+}
=== added file 'src/graphic/gl/road_program.h'
--- src/graphic/gl/road_program.h 1970-01-01 00:00:00 +0000
+++ src/graphic/gl/road_program.h 2014-11-01 20:50:47 +0000
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2006-2014 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_GRAPHIC_GL_ROAD_PROGRAM_H
+#define WL_GRAPHIC_GL_ROAD_PROGRAM_H
+
+#include <vector>
+
+#include "base/macros.h"
+#include "graphic/gl/fields_to_draw.h"
+#include "graphic/gl/utils.h"
+#include "logic/roadtype.h"
+
+class RoadProgram {
+public:
+ // Compiles the program. Throws on error.
+ RoadProgram();
+
+ // Draws the roads.
+ void draw(const FieldsToDraw& fields_to_draw);
+
+private:
+ struct PerVertexData {
+ float x;
+ float y;
+ float texture_x;
+ float texture_y;
+ float brightness;
+
+ // This is a hack: we want to draw busy and normal roads in the same
+ // run, but since samplers (apparently?) cannot be passed through
+ // attribute arrays, we instead sample twice (busy and normal) and mix
+ // them together with 'texture_mix' which is either 1 or 0.
+ float texture_mix;
+ };
+ static_assert(sizeof(PerVertexData) == 24, "Wrong padding.");
+
+ // Adds a road from 'start' to 'end' to be rendered in this frame using the
+ // correct texture for 'road_type'.
+ void add_road(const FieldsToDraw::Field& start,
+ const FieldsToDraw::Field& end,
+ const Widelands::RoadType road_type);
+
+ // The buffer that will contain 'vertices_' for rendering.
+ Gl::Buffer gl_array_buffer_;
+
+ // The program used for drawing the roads.
+ Gl::Program gl_program_;
+
+ // Attributes.
+ GLint attr_position_;
+ GLint attr_texture_position_;
+ GLint attr_brightness_;
+ GLint attr_texture_mix_;
+
+ // Uniforms.
+ GLint u_normal_road_texture_;
+ GLint u_busy_road_texture_;
+
+ // All vertices that get rendered this frame.
+ std::vector<PerVertexData> vertices_;
+
+ DISALLOW_COPY_AND_ASSIGN(RoadProgram);
+};
+
+#endif // end of include guard: WL_GRAPHIC_GL_ROAD_PROGRAM_H
=== renamed file 'src/graphic/render/gl_surface.cc' => 'src/graphic/gl/surface.cc'
--- src/graphic/render/gl_surface.cc 2014-07-14 10:45:44 +0000
+++ src/graphic/gl/surface.cc 2014-11-01 20:50:47 +0000
@@ -17,15 +17,15 @@
*
*/
-#include "graphic/render/gl_surface.h"
+#include "graphic/gl/surface.h"
#include <cassert>
#include <cmath>
#include <cstdlib>
#include "base/macros.h"
+#include "graphic/gl/surface_texture.h"
#include "graphic/graphic.h"
-#include "graphic/render/gl_surface_texture.h"
uint16_t GLSurface::width() const {
return m_w;
=== renamed file 'src/graphic/render/gl_surface.h' => 'src/graphic/gl/surface.h'
--- src/graphic/render/gl_surface.h 2014-07-26 10:43:23 +0000
+++ src/graphic/gl/surface.h 2014-11-01 20:50:47 +0000
@@ -17,8 +17,8 @@
*
*/
-#ifndef WL_GRAPHIC_RENDER_GL_SURFACE_H
-#define WL_GRAPHIC_RENDER_GL_SURFACE_H
+#ifndef WL_GRAPHIC_GL_SURFACE_H
+#define WL_GRAPHIC_GL_SURFACE_H
#include <memory>
@@ -56,4 +56,4 @@
std::unique_ptr<uint8_t[]> m_pixels;
};
-#endif // end of include guard: WL_GRAPHIC_RENDER_GL_SURFACE_H
+#endif // end of include guard: WL_GRAPHIC_GL_SURFACE_H
=== renamed file 'src/graphic/render/gl_surface_screen.cc' => 'src/graphic/gl/surface_screen.cc'
--- src/graphic/render/gl_surface_screen.cc 2014-07-25 11:14:03 +0000
+++ src/graphic/gl/surface_screen.cc 2014-11-01 20:50:47 +0000
@@ -16,12 +16,12 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "graphic/render/gl_surface_screen.h"
+#include "graphic/gl/surface_screen.h"
#include <algorithm>
#include <cassert>
-#include "graphic/render/gl_utils.h"
+#include "graphic/gl/utils.h"
GLSurfaceScreen::GLSurfaceScreen(uint16_t w, uint16_t h)
{
@@ -49,7 +49,7 @@
}
const SDL_PixelFormat & GLSurfaceScreen::format() const {
- return gl_rgba_format();
+ return Gl::gl_rgba_format();
}
void GLSurfaceScreen::lock(Surface::LockMode mode)
=== renamed file 'src/graphic/render/gl_surface_screen.h' => 'src/graphic/gl/surface_screen.h'
--- src/graphic/render/gl_surface_screen.h 2014-07-26 10:43:23 +0000
+++ src/graphic/gl/surface_screen.h 2014-11-01 20:50:47 +0000
@@ -16,10 +16,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef WL_GRAPHIC_RENDER_GL_SURFACE_SCREEN_H
-#define WL_GRAPHIC_RENDER_GL_SURFACE_SCREEN_H
+#ifndef WL_GRAPHIC_GL_SURFACE_SCREEN_H
+#define WL_GRAPHIC_GL_SURFACE_SCREEN_H
-#include "graphic/render/gl_surface.h"
+#include "graphic/gl/surface.h"
/**
* This surface represents the screen in OpenGL mode.
@@ -39,4 +39,4 @@
void swap_rows();
};
-#endif // end of include guard: WL_GRAPHIC_RENDER_GL_SURFACE_SCREEN_H
+#endif // end of include guard:
=== renamed file 'src/graphic/render/gl_surface_texture.cc' => 'src/graphic/gl/surface_texture.cc'
--- src/graphic/render/gl_surface_texture.cc 2014-09-20 09:37:47 +0000
+++ src/graphic/gl/surface_texture.cc 2014-11-01 20:50:47 +0000
@@ -16,19 +16,34 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "graphic/render/gl_surface_texture.h"
+#include "graphic/gl/surface_texture.h"
#include <cassert>
#include "base/wexception.h"
-#include "gl_surface.h" // for glew.h
+#include "graphic/gl/surface.h"
+#include "graphic/gl/utils.h"
#include "graphic/graphic.h"
-#include "graphic/render/gl_utils.h"
GLuint GLSurfaceTexture::gl_framebuffer_id_;
static bool use_arb_;
+namespace {
+
+// Return the smallest power of two greater than or equal to \p x.
+uint32_t next_power_of_two(uint32_t x)
+{
+ uint32_t pot = 1;
+
+ while (pot < x)
+ pot *= 2;
+
+ return pot;
+}
+
+} // namespace
+
/**
* Initial global resources needed for fast offscreen rendering.
*/
@@ -160,7 +175,6 @@
SDL_FreeSurface(surface);
glPopAttrib();
- handle_glerror();
}
GLSurfaceTexture::~GLSurfaceTexture()
@@ -170,7 +184,6 @@
void GLSurfaceTexture::init(uint16_t w, uint16_t h)
{
- handle_glerror();
m_w = w;
m_h = h;
if (m_w <= 0 || m_h <= 0) {
@@ -193,12 +206,10 @@
// makes no difference
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
- handle_glerror();
}
const SDL_PixelFormat & GLSurfaceTexture::format() const {
- return gl_rgba_format();
+ return Gl::gl_rgba_format();
}
void GLSurfaceTexture::lock(LockMode mode) {
=== renamed file 'src/graphic/render/gl_surface_texture.h' => 'src/graphic/gl/surface_texture.h'
--- src/graphic/render/gl_surface_texture.h 2014-09-20 09:37:47 +0000
+++ src/graphic/gl/surface_texture.h 2014-11-01 20:50:47 +0000
@@ -16,10 +16,10 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef WL_GRAPHIC_RENDER_GL_SURFACE_TEXTURE_H
-#define WL_GRAPHIC_RENDER_GL_SURFACE_TEXTURE_H
+#ifndef WL_GRAPHIC_GL_SURFACE_TEXTURE_H
+#define WL_GRAPHIC_GL_SURFACE_TEXTURE_H
-#include "graphic/render/gl_surface.h"
+#include "graphic/gl/surface.h"
struct SDL_Surface;
@@ -73,4 +73,4 @@
uint16_t m_tex_w, m_tex_h;
};
-#endif // end of include guard: WL_GRAPHIC_RENDER_GL_SURFACE_TEXTURE_H
+#endif // end of include guard: WL_GRAPHIC_GL_SURFACE_TEXTURE_H
=== added file 'src/graphic/gl/terrain_program.cc'
--- src/graphic/gl/terrain_program.cc 1970-01-01 00:00:00 +0000
+++ src/graphic/gl/terrain_program.cc 2014-11-01 20:50:47 +0000
@@ -0,0 +1,184 @@
+/*
+ * Copyright (C) 2006-2014 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include "graphic/gl/terrain_program.h"
+
+#include "graphic/gl/fields_to_draw.h"
+#include "graphic/graphic.h"
+#include "graphic/texture.h"
+
+namespace {
+
+using namespace Widelands;
+
+// QuickRef:
+// http://www.cs.unh.edu/~cs770/docs/glsl-1.20-quickref.pdf
+// Full specification:
+// http://www.opengl.org/registry/doc/GLSLangSpec.Full.1.20.8.pdf
+// We target OpenGL 2.1 for the desktop here.
+// TODO(sirver): In the end we need to replace gl_ProjectionMatrix. It is not
+// supported in ES and more modern Open GL version.
+const char kTerrainVertexShader[] = R"(
+#version 120
+
+// Attributes.
+attribute vec2 attr_position;
+attribute float attr_brightness;
+attribute vec2 attr_texture_position;
+
+// Output of vertex shader.
+varying float var_brightness;
+varying vec2 var_texture_position;
+
+void main() {
+ var_texture_position = attr_texture_position;
+ var_brightness = attr_brightness;
+ vec4 p = vec4(attr_position, 0., 1.);
+ gl_Position = gl_ProjectionMatrix * p;
+}
+)";
+
+const char kTerrainFragmentShader[] = R"(
+#version 120
+
+uniform sampler2D u_terrain_texture;
+
+varying float var_brightness;
+varying vec2 var_texture_position;
+
+void main() {
+ vec4 clr = texture2D(u_terrain_texture, var_texture_position);
+ clr.rgb *= var_brightness;
+ gl_FragColor = clr;
+}
+)";
+
+} // namespace
+
+TerrainProgram::TerrainProgram() {
+ gl_program_.build(kTerrainVertexShader, kTerrainFragmentShader);
+
+ attr_position_ = glGetAttribLocation(gl_program_.object(), "attr_position");
+ attr_texture_position_ =
+ glGetAttribLocation(gl_program_.object(), "attr_texture_position");
+ attr_brightness_ = glGetAttribLocation(gl_program_.object(), "attr_brightness");
+
+ u_terrain_texture_ = glGetUniformLocation(gl_program_.object(), "u_terrain_texture");
+}
+
+void TerrainProgram::gl_draw(int num_vertices,
+ const DescriptionMaintainer<TerrainDescription>& terrains) {
+ glUseProgram(gl_program_.object());
+
+ glEnableVertexAttribArray(attr_position_);
+ glEnableVertexAttribArray(attr_texture_position_);
+ glEnableVertexAttribArray(attr_brightness_);
+
+ glBindBuffer(GL_ARRAY_BUFFER, gl_array_buffer_.object());
+ glBufferData(GL_ARRAY_BUFFER,
+ sizeof(TerrainProgram::PerVertexData) * num_vertices,
+ vertices_.data(),
+ GL_STREAM_DRAW);
+
+ const auto set_attrib_pointer = [](const int vertex_index, int num_items, int offset) {
+ glVertexAttribPointer(vertex_index,
+ num_items,
+ GL_FLOAT,
+ GL_FALSE,
+ sizeof(TerrainProgram::PerVertexData),
+ reinterpret_cast<void*>(offset));
+ };
+ set_attrib_pointer(attr_position_, 2, offsetof(PerVertexData, x));
+ set_attrib_pointer(attr_brightness_, 1, offsetof(PerVertexData, brightness));
+ set_attrib_pointer(attr_texture_position_, 2, offsetof(PerVertexData, texture_x));
+
+ glBindBuffer(GL_ARRAY_BUFFER, 0);
+
+ // Set the sampler texture unit to 0
+ glActiveTexture(GL_TEXTURE0);
+ glUniform1i(u_terrain_texture_, 0);
+
+ // Which triangles to draw?
+ for (size_t i = 0; i < terrains_to_indices_.size(); ++i) {
+ const auto& indices = terrains_to_indices_[i];
+ if (indices.empty()) {
+ continue;
+ }
+ glBindTexture(
+ GL_TEXTURE_2D,
+ g_gr->get_maptexture_data(terrains.get_unmutable(i).get_texture())->get_texture());
+ glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, indices.data());
+ }
+
+ glDisableVertexAttribArray(attr_position_);
+ glDisableVertexAttribArray(attr_texture_position_);
+ glDisableVertexAttribArray(attr_brightness_);
+
+ glUseProgram(0);
+}
+
+void TerrainProgram::draw(const DescriptionMaintainer<TerrainDescription>& terrains,
+ const FieldsToDraw& fields_to_draw) {
+ if (vertices_.size() < fields_to_draw.size()) {
+ vertices_.resize(fields_to_draw.size());
+ terrains_to_indices_.resize(terrains.size());
+ }
+ for (auto& container : terrains_to_indices_) {
+ container.clear();
+ container.reserve(fields_to_draw.size());
+ }
+
+ for (size_t current_index = 0; current_index < fields_to_draw.size(); ++current_index) {
+ const FieldsToDraw::Field& field = fields_to_draw.at(current_index);
+
+ PerVertexData& vertex = vertices_[current_index];
+ vertex.texture_x = field.texture_x;
+ vertex.texture_y = field.texture_y;
+ vertex.x = field.x;
+ vertex.y = field.y;
+ vertex.brightness = field.brightness;
+
+ // The bottom right neighbor fields_to_draw is needed for both triangles
+ // associated with this field. If it is not in fields_to_draw, there is no need to
+ // draw any triangles.
+ const int brn_index = fields_to_draw.calculate_index(field.fx + (field.fy & 1), field.fy + 1);
+ if (brn_index == -1) {
+ continue;
+ }
+
+ // Down triangle.
+ const int bln_index =
+ fields_to_draw.calculate_index(field.fx + (field.fy & 1) - 1, field.fy + 1);
+ if (bln_index != -1) {
+ terrains_to_indices_[field.ter_d].push_back(current_index);
+ terrains_to_indices_[field.ter_d].push_back(bln_index);
+ terrains_to_indices_[field.ter_d].push_back(brn_index);
+ }
+
+ // Right triangle.
+ const int rn_index = fields_to_draw.calculate_index(field.fx + 1, field.fy);
+ if (rn_index != -1) {
+ terrains_to_indices_[field.ter_r].push_back(current_index);
+ terrains_to_indices_[field.ter_r].push_back(brn_index);
+ terrains_to_indices_[field.ter_r].push_back(rn_index);
+ }
+ }
+
+ gl_draw(fields_to_draw.size(), terrains);
+}
=== added file 'src/graphic/gl/terrain_program.h'
--- src/graphic/gl/terrain_program.h 1970-01-01 00:00:00 +0000
+++ src/graphic/gl/terrain_program.h 2014-11-01 20:50:47 +0000
@@ -0,0 +1,80 @@
+/*
+ * Copyright (C) 2006-2014 by the Widelands Development Team
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef WL_GRAPHIC_GL_TERRAIN_PROGRAM_H
+#define WL_GRAPHIC_GL_TERRAIN_PROGRAM_H
+
+#include <vector>
+
+#include "graphic/gl/utils.h"
+#include "logic/description_maintainer.h"
+#include "logic/world/terrain_description.h"
+
+class FieldsToDraw;
+
+class TerrainProgram {
+public:
+ // Compiles the program. Throws on errors.
+ TerrainProgram();
+
+ // Draws the terrain.
+ void draw(const DescriptionMaintainer<Widelands::TerrainDescription>& terrains,
+ const FieldsToDraw& fields_to_draw);
+
+private:
+ struct PerVertexData {
+ float x;
+ float y;
+ float brightness;
+ float texture_x;
+ float texture_y;
+ };
+ static_assert(sizeof(PerVertexData) == 20, "Wrong padding.");
+
+ void gl_draw(int num_vertices,
+ const DescriptionMaintainer<Widelands::TerrainDescription>& terrains);
+
+ // The buffer that will contain 'vertices_' for rendering.
+ Gl::Buffer gl_array_buffer_;
+
+ // The program used for drawing the terrain.
+ Gl::Program gl_program_;
+
+ // Attributes.
+ GLint attr_position_;
+ GLint attr_texture_position_;
+ GLint attr_brightness_;
+
+ // Uniforms.
+ GLint u_terrain_texture_;
+
+ // Objects below are kept around to avoid memory allocations on each frame.
+ // They could theoretically also be recreated.
+
+ // All vertices that are going to get rendered this frame.
+ std::vector<PerVertexData> vertices_;
+
+ // A map from terrain index in world.terrains() to indices in 'vertices_'
+ // that have this terrain type.
+ std::vector<std::vector<uint16_t>> terrains_to_indices_;
+
+ DISALLOW_COPY_AND_ASSIGN(TerrainProgram);
+};
+
+#endif // end of include guard: WL_GRAPHIC_GL_TERRAIN_PROGRAM_H
=== renamed file 'src/graphic/render/gl_utils.cc' => 'src/graphic/gl/utils.cc'
--- src/graphic/render/gl_utils.cc 2014-06-01 18:00:48 +0000
+++ src/graphic/gl/utils.cc 2014-11-01 20:50:47 +0000
@@ -16,24 +16,39 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#include "graphic/render/gl_utils.h"
+#include "graphic/gl/utils.h"
+
+#include <memory>
+#include <string>
#include <SDL_video.h>
#include "base/log.h"
-
-/**
- * Return the smallest power of two greater than or equal to \p x.
- */
-uint32_t next_power_of_two(uint32_t x)
-{
- uint32_t pot = 1;
-
- while (pot < x)
- pot *= 2;
-
- return pot;
-}
+#include "base/wexception.h"
+
+namespace Gl {
+
+namespace {
+
+// Returns a readable string for a GL_*_SHADER 'type' for debug output.
+std::string shader_to_string(GLenum type) {
+ if (type == GL_VERTEX_SHADER) {
+ return "vertex";
+ }
+ if (type == GL_FRAGMENT_SHADER) {
+ return "fragment";
+ }
+ return "unknown";
+}
+
+// Creates one OpenGL buffer.
+GLuint create_buffer() {
+ GLuint buffer = 0;
+ glGenBuffers(1, &buffer);
+ return buffer;
+}
+
+} // namespace
/**
* \return the standard 32-bit RGBA format that we use in OpenGL
@@ -63,7 +78,6 @@
GLenum _handle_glerror(const char * file, unsigned int line)
{
GLenum err = glGetError();
-#ifndef NDEBUG
if (err == GL_NO_ERROR)
return err;
@@ -95,6 +109,107 @@
default:
log("unknown\n");
}
-#endif
return err;
}
+
+// Thin wrapper around a Shader object to ensure proper cleanup.
+class Shader {
+public:
+ Shader(GLenum type);
+ ~Shader();
+
+ GLuint object() const {
+ return shader_object_;
+ }
+
+ // Compiles 'source'. Throws an exception on error.
+ void compile(const char* source);
+
+private:
+ const GLenum type_;
+ const GLuint shader_object_;
+
+ DISALLOW_COPY_AND_ASSIGN(Shader);
+};
+
+Shader::Shader(GLenum type) : type_(type), shader_object_(glCreateShader(type)) {
+ if (!shader_object_) {
+ throw wexception("Could not create %s shader.", shader_to_string(type).c_str());
+ }
+}
+
+Shader::~Shader() {
+ if (shader_object_) {
+ glDeleteShader(shader_object_);
+ }
+}
+
+void Shader::compile(const char* source) {
+ glShaderSource(shader_object_, 1, &source, nullptr);
+
+ glCompileShader(shader_object_);
+ GLint compiled;
+ glGetShaderiv(shader_object_, GL_COMPILE_STATUS, &compiled);
+ if (!compiled) {
+ GLint infoLen = 0;
+ glGetShaderiv(shader_object_, GL_INFO_LOG_LENGTH, &infoLen);
+ if (infoLen > 1) {
+ std::unique_ptr<char[]> infoLog(new char[infoLen]);
+ glGetShaderInfoLog(shader_object_, infoLen, NULL, infoLog.get());
+ throw wexception(
+ "Error compiling %s shader:\n%s", shader_to_string(type_).c_str(), infoLog.get());
+ }
+ }
+}
+
+Buffer::Buffer() : buffer_object_(create_buffer()) {
+ if (!buffer_object_) {
+ throw wexception("Could not create GL program.");
+ }
+}
+
+Buffer::~Buffer() {
+ if (buffer_object_) {
+ glDeleteBuffers(1, &buffer_object_);
+ }
+}
+
+Program::Program() : program_object_(glCreateProgram()) {
+ if (!program_object_) {
+ throw wexception("Could not create GL program.");
+ }
+}
+
+Program::~Program() {
+ if (program_object_) {
+ glDeleteProgram(program_object_);
+ }
+}
+
+void Program::build(const char* vertex_shader_source, const char* fragment_shader_source) {
+ vertex_shader_.reset(new Shader(GL_VERTEX_SHADER));
+ vertex_shader_->compile(vertex_shader_source);
+ glAttachShader(program_object_, vertex_shader_->object());
+
+ fragment_shader_.reset(new Shader(GL_FRAGMENT_SHADER));
+ fragment_shader_->compile(fragment_shader_source);
+ glAttachShader(program_object_, fragment_shader_->object());
+
+ glLinkProgram(program_object_);
+
+ // Check the link status
+ GLint linked;
+ glGetProgramiv(program_object_, GL_LINK_STATUS, &linked);
+ if (!linked) {
+ GLint infoLen = 0;
+ glGetProgramiv(program_object_, GL_INFO_LOG_LENGTH, &infoLen);
+
+ if (infoLen > 1) {
+ std::unique_ptr<char[]> infoLog(new char[infoLen]);
+ glGetProgramInfoLog(program_object_, infoLen, NULL, infoLog.get());
+ throw wexception("Error linking:\n%s", infoLog.get());
+ }
+ }
+}
+
+} // namespace Gl
=== renamed file 'src/graphic/render/gl_utils.h' => 'src/graphic/gl/utils.h'
--- src/graphic/render/gl_utils.h 2014-07-05 16:41:51 +0000
+++ src/graphic/gl/utils.h 2014-11-01 20:50:47 +0000
@@ -16,25 +16,74 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
-#ifndef WL_GRAPHIC_RENDER_GL_UTILS_H
-#define WL_GRAPHIC_RENDER_GL_UTILS_H
+#ifndef WL_GRAPHIC_GL_UTILS_H
+#define WL_GRAPHIC_GL_UTILS_H
#define NO_SDL_GLEXT
+#include <memory>
+
#include <GL/glew.h>
#include <SDL_opengl.h>
#include <stdint.h>
+#include "base/macros.h"
+
struct SDL_PixelFormat;
-uint32_t next_power_of_two(uint32_t x);
+namespace Gl {
+
+class Shader;
+
const SDL_PixelFormat & gl_rgba_format();
GLenum _handle_glerror(const char * file, unsigned int line);
+// Thin wrapper around a OpenGL program object to ensure proper cleanup. Throws
+// on all errors.
+class Program {
+public:
+ Program();
+ ~Program();
+
+ GLuint object() const {
+ return program_object_;
+ }
+
+ // Creates and compiles 'vertex_shader_source' and 'fragment_shader_source'
+ // into shader objects. Then links them into the program.
+ void build(const char* vertex_shader_source, const char* fragment_shader_source);
+
+private:
+ const GLuint program_object_;
+ std::unique_ptr<Shader> vertex_shader_;
+ std::unique_ptr<Shader> fragment_shader_;
+
+ DISALLOW_COPY_AND_ASSIGN(Program);
+};
+
+// Thin wrapper around a OpenGL buffer object to ensure proper cleanup. Throws
+// on all errors.
+class Buffer {
+public:
+ Buffer();
+ ~Buffer();
+
+ GLuint object() const {
+ return buffer_object_;
+ }
+
+private:
+ const GLuint buffer_object_;
+
+ DISALLOW_COPY_AND_ASSIGN(Buffer);
+};
+
+} // namespace Gl
+
/**
* handle_glerror() is intended to make debugging of OpenGL easier. It logs the
* error code returned by glGetError and returns the error code.
*/
-#define handle_glerror() _handle_glerror(__FILE__, __LINE__)
+#define handle_glerror() Gl::_handle_glerror(__FILE__, __LINE__)
-#endif // end of include guard: WL_GRAPHIC_RENDER_GL_UTILS_H
+#endif // end of include guard: WL_GRAPHIC_GL_UTILS_H
=== modified file 'src/graphic/graphic.cc'
--- src/graphic/graphic.cc 2014-09-20 09:37:47 +0000
+++ src/graphic/graphic.cc 2014-11-01 20:50:47 +0000
@@ -35,12 +35,12 @@
#include "graphic/animation.h"
#include "graphic/diranimations.h"
#include "graphic/font_handler.h"
+#include "graphic/gl/surface_screen.h"
#include "graphic/image.h"
#include "graphic/image_io.h"
#include "graphic/image_transformations.h"
-#include "graphic/render/gl_surface_screen.h"
-#include "graphic/render/sdl_surface.h"
#include "graphic/rendertarget.h"
+#include "graphic/sdl/surface.h"
#include "graphic/surface_cache.h"
#include "graphic/texture.h"
#include "io/fileread.h"
@@ -100,6 +100,10 @@
if (opengl) {
log("Graphics: Trying opengl\n");
+
+ // TODO(sirver): We should explicitly request an OpenGL 2.? core context
+ // here instead of relying on SDL to give us whatever.
+
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
flags |= SDL_OPENGL;
}
@@ -151,6 +155,9 @@
// about opengl and set the rendering capabilities.
log ("Graphics: OpenGL: OpenGL enabled\n");
+ // See http://stackoverflow.com/questions/13558073/program-crash-on-glgenvertexarrays-call for
+ // the next line.
+ glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (err != GLEW_OK) {
log("glewInit returns %i\nYour OpenGL installation must be __very__ broken.\n", err);
@@ -207,10 +214,6 @@
log("Graphics: OpenGL: Number of stencil buffer bits: %u\n", glInt);
m_caps.gl.stencil_buffer_bits = glInt;
- glGetIntegerv(GL_MAX_TEXTURE_UNITS, &glInt);
- log("Graphics: OpenGL: Maximum number of textures for multitextures: %u\n", glInt);
- m_caps.gl.max_tex_combined = glInt;
-
const char * str = reinterpret_cast<const char *>(glGetString(GL_VERSION));
m_caps.gl.major_version = atoi(str);
m_caps.gl.minor_version = strstr(str, ".")?atoi(strstr(str, ".") + 1):0;
@@ -227,12 +230,6 @@
(m_caps.gl.tex_power_of_two?"must have a size power of two\n":
"may have any size\n");
- m_caps.gl.multitexture =
- ((strstr(extensions, "GL_ARB_multitexture") != nullptr) &&
- (strstr(extensions, "GL_ARB_texture_env_combine") != nullptr));
- log("Graphics: OpenGL: Multitexture capabilities ");
- log(m_caps.gl.multitexture ? "sufficient\n" : "insufficient, only basic terrain rendering possible\n");
-
DIAG_OFF("-Wold-style-cast")
m_caps.gl.blendequation = GLEW_VERSION_1_4 || GLEW_ARB_imaging;
DIAG_ON ("-Wold-style-cast")
=== modified file 'src/graphic/graphic.h'
--- src/graphic/graphic.h 2014-07-14 10:45:44 +0000
+++ src/graphic/graphic.h 2014-11-01 20:50:47 +0000
@@ -56,10 +56,6 @@
int aux_buffers;
/// Whether the BlendEquation support is available
bool blendequation;
- /// Maximum number of textures that can be combined
- int max_tex_combined;
- /// Whether multitexturing is supported
- bool multitexture;
};
/**
=== modified file 'src/graphic/image_transformations.cc'
--- src/graphic/image_transformations.cc 2014-07-26 10:43:23 +0000
+++ src/graphic/image_transformations.cc 2014-11-01 20:50:47 +0000
@@ -28,7 +28,7 @@
#include "base/macros.h"
#include "graphic/color.h"
#include "graphic/graphic.h"
-#include "graphic/render/sdl_surface.h"
+#include "graphic/sdl/surface.h"
#include "graphic/surface.h"
#include "graphic/surface_cache.h"
=== renamed file 'src/graphic/render/minimaprenderer.cc' => 'src/graphic/minimap_renderer.cc'
--- src/graphic/render/minimaprenderer.cc 2014-09-10 08:55:04 +0000
+++ src/graphic/minimap_renderer.cc 2014-11-01 20:50:47 +0000
@@ -17,7 +17,7 @@
*
*/
-#include "graphic/render/minimaprenderer.h"
+#include "graphic/minimap_renderer.h"
#include <memory>
=== renamed file 'src/graphic/render/minimaprenderer.h' => 'src/graphic/minimap_renderer.h'
--- src/graphic/render/minimaprenderer.h 2014-09-10 08:55:04 +0000
+++ src/graphic/minimap_renderer.h 2014-11-01 20:50:47 +0000
@@ -17,8 +17,8 @@
*
*/
-#ifndef WL_GRAPHIC_RENDER_MINIMAPRENDERER_H
-#define WL_GRAPHIC_RENDER_MINIMAPRENDERER_H
+#ifndef WL_GRAPHIC_MINIMAP_RENDERER_H
+#define WL_GRAPHIC_MINIMAP_RENDERER_H
#include <memory>
@@ -66,4 +66,4 @@
(const Widelands::EditorGameBase& egbase, Widelands::Player const* player,
const Point& viewpoint, MiniMapLayer layers, StreamWrite* const streamwrite);
-#endif // end of include guard: WL_GRAPHIC_RENDER_MINIMAPRENDERER_H
+#endif // end of include guard: WL_GRAPHIC_MINIMAP_RENDERER_H
=== removed directory 'src/graphic/render'
=== added directory 'src/graphic/sdl'
=== renamed file 'src/graphic/render/gamerenderer_sdl.cc' => 'src/graphic/sdl/game_renderer.cc'
--- src/graphic/render/gamerenderer_sdl.cc 2014-09-10 08:55:04 +0000
+++ src/graphic/sdl/game_renderer.cc 2014-11-01 20:50:47 +0000
@@ -17,10 +17,10 @@
*
*/
-#include "graphic/render/gamerenderer_sdl.h"
+#include "graphic/sdl/game_renderer.h"
-#include "graphic/render/terrain_sdl.h"
#include "graphic/rendertarget.h"
+#include "graphic/sdl/terrain.h"
#include "logic/field.h"
#include "logic/map.h"
#include "logic/player.h"
@@ -56,13 +56,13 @@
}
-void GameRendererSDL::draw()
+void SdlGameRenderer::draw()
{
draw_terrain();
draw_objects();
}
-void GameRendererSDL::draw_terrain()
+void SdlGameRenderer::draw_terrain()
{
if (m_player && !m_player->see_all())
m_dst->get_surface()->fill_rect(m_dst->get_rect(), RGBAColor(0, 0, 0, 255));
@@ -239,7 +239,7 @@
* / d \/
* (bl) *------* (br)
*/
-void GameRendererSDL::draw_field
+void SdlGameRenderer::draw_field
(RenderTarget & dst,
const Vertex & f_vert,
const Vertex & r_vert,
=== renamed file 'src/graphic/render/gamerenderer_sdl.h' => 'src/graphic/sdl/game_renderer.h'
--- src/graphic/render/gamerenderer_sdl.h 2014-07-05 16:41:51 +0000
+++ src/graphic/sdl/game_renderer.h 2014-11-01 20:50:47 +0000
@@ -17,10 +17,10 @@
*
*/
-#ifndef WL_GRAPHIC_RENDER_GAMERENDERER_SDL_H
-#define WL_GRAPHIC_RENDER_GAMERENDERER_SDL_H
+#ifndef WL_GRAPHIC_SDL_GAME_RENDERER_H
+#define WL_GRAPHIC_SDL_GAME_RENDERER_H
-#include "graphic/render/gamerenderer.h"
+#include "graphic/game_renderer.h"
struct Texture;
struct Vertex;
@@ -28,7 +28,7 @@
/**
* Software-rendering implementation of @ref GameRenderer.
*/
-class GameRendererSDL : public GameRenderer {
+class SdlGameRenderer : public GameRenderer {
protected:
void draw() override;
@@ -52,4 +52,4 @@
const Texture & f_r_texture);
};
-#endif // end of include guard: WL_GRAPHIC_RENDER_GAMERENDERER_SDL_H
+#endif // end of include guard: WL_GRAPHIC_SDL_GAME_RENDERER_H
=== renamed file 'src/graphic/render/sdl_surface.cc' => 'src/graphic/sdl/surface.cc'
--- src/graphic/render/sdl_surface.cc 2014-07-14 10:45:44 +0000
+++ src/graphic/sdl/surface.cc 2014-11-01 20:50:47 +0000
@@ -17,7 +17,7 @@
*
*/
-#include "graphic/render/sdl_surface.h"
+#include "graphic/sdl/surface.h"
#include <cassert>
=== renamed file 'src/graphic/render/sdl_surface.h' => 'src/graphic/sdl/surface.h'
--- src/graphic/render/sdl_surface.h 2014-07-26 10:43:23 +0000
+++ src/graphic/sdl/surface.h 2014-11-01 20:50:47 +0000
@@ -17,8 +17,8 @@
*
*/
-#ifndef WL_GRAPHIC_RENDER_SDL_SURFACE_H
-#define WL_GRAPHIC_RENDER_SDL_SURFACE_H
+#ifndef WL_GRAPHIC_SDL_SURFACE_H
+#define WL_GRAPHIC_SDL_SURFACE_H
#include "base/rect.h"
#include "graphic/color.h"
@@ -72,5 +72,4 @@
bool m_free_surface_on_delete;
};
-
-#endif // end of include guard: WL_GRAPHIC_RENDER_SDL_SURFACE_H
+#endif // end of include guard: WL_GRAPHIC_SDL_SURFACE_H
=== renamed file 'src/graphic/render/terrain_sdl.cc' => 'src/graphic/sdl/terrain.cc'
--- src/graphic/render/terrain_sdl.cc 2013-07-26 20:19:36 +0000
+++ src/graphic/sdl/terrain.cc 2014-11-01 20:50:47 +0000
@@ -17,7 +17,7 @@
*
*/
-#include "graphic/render/terrain_sdl.h"
+#include "graphic/sdl/terrain.h"
/// get lambda and mu so that
/// lambda * u + mu * v = (1 0)^T with u = (u1 u2)^T and v = (v1 v2)^T
=== renamed file 'src/graphic/render/terrain_sdl.h' => 'src/graphic/sdl/terrain.h'
--- src/graphic/render/terrain_sdl.h 2014-07-25 22:17:48 +0000
+++ src/graphic/sdl/terrain.h 2014-11-01 20:50:47 +0000
@@ -17,16 +17,16 @@
*
*/
-#ifndef WL_GRAPHIC_RENDER_TERRAIN_SDL_H
-#define WL_GRAPHIC_RENDER_TERRAIN_SDL_H
+#ifndef WL_GRAPHIC_SDL_TERRAIN_H
+#define WL_GRAPHIC_SDL_TERRAIN_H
#include <cassert>
#include "base/log.h"
#include "base/macros.h"
#include "graphic/graphic.h"
-#include "graphic/render/sdl_surface.h"
-#include "graphic/render/vertex.h"
+#include "graphic/sdl/surface.h"
+#include "graphic/sdl/vertex.h"
#include "graphic/texture.h"
#include "logic/roadtype.h"
#include "random/random.h"
@@ -665,4 +665,4 @@
// TODO(unknown): similar textures may not need dithering
}
-#endif // end of include guard: WL_GRAPHIC_RENDER_TERRAIN_SDL_H
+#endif // end of include guard: WL_GRAPHIC_SDL_TERRAIN_H
=== renamed file 'src/graphic/render/sdl_helper.cc' => 'src/graphic/sdl/utils.cc'
--- src/graphic/render/sdl_helper.cc 2014-07-14 10:45:44 +0000
+++ src/graphic/sdl/utils.cc 2014-11-01 20:50:47 +0000
@@ -17,7 +17,7 @@
*
*/
-#include "graphic/render/sdl_helper.h"
+#include "graphic/sdl/utils.h"
#include <cassert>
=== renamed file 'src/graphic/render/sdl_helper.h' => 'src/graphic/sdl/utils.h'
--- src/graphic/render/sdl_helper.h 2014-07-05 16:41:51 +0000
+++ src/graphic/sdl/utils.h 2014-11-01 20:50:47 +0000
@@ -17,8 +17,8 @@
*
*/
-#ifndef WL_GRAPHIC_RENDER_SDL_HELPER_H
-#define WL_GRAPHIC_RENDER_SDL_HELPER_H
+#ifndef WL_GRAPHIC_SDL_UTILS_H
+#define WL_GRAPHIC_SDL_UTILS_H
#include <stdint.h>
@@ -26,4 +26,4 @@
SDL_Surface * empty_sdl_surface(int16_t w, int16_t h);
-#endif // end of include guard: WL_GRAPHIC_RENDER_SDL_HELPER_H
+#endif // end of include guard: WL_GRAPHIC_SDL_UTILS_H
=== renamed file 'src/graphic/render/vertex.h' => 'src/graphic/sdl/vertex.h'
--- src/graphic/render/vertex.h 2014-07-05 16:41:51 +0000
+++ src/graphic/sdl/vertex.h 2014-11-01 20:50:47 +0000
@@ -17,8 +17,8 @@
*
*/
-#ifndef WL_GRAPHIC_RENDER_VERTEX_H
-#define WL_GRAPHIC_RENDER_VERTEX_H
+#ifndef WL_GRAPHIC_SDL_VERTEX_H
+#define WL_GRAPHIC_SDL_VERTEX_H
#include "base/point.h"
@@ -36,4 +36,4 @@
int32_t b, tx, ty;
};
-#endif // end of include guard: WL_GRAPHIC_RENDER_VERTEX_H
+#endif // end of include guard: WL_GRAPHIC_SDL_VERTEX_H
=== modified file 'src/graphic/surface.cc'
--- src/graphic/surface.cc 2014-07-17 13:26:23 +0000
+++ src/graphic/surface.cc 2014-11-01 20:50:47 +0000
@@ -21,9 +21,9 @@
#include <SDL.h>
-#include "graphic/render/gl_surface_texture.h"
-#include "graphic/render/sdl_helper.h"
-#include "graphic/render/sdl_surface.h"
+#include "graphic/gl/surface_texture.h"
+#include "graphic/sdl/surface.h"
+#include "graphic/sdl/utils.h"
extern bool g_opengl;
=== modified file 'src/graphic/text/sdl_ttf_font.cc'
--- src/graphic/text/sdl_ttf_font.cc 2014-09-10 16:57:31 +0000
+++ src/graphic/text/sdl_ttf_font.cc 2014-11-01 20:50:47 +0000
@@ -22,7 +22,7 @@
#include <SDL_ttf.h>
#include <boost/format.hpp>
-#include "graphic/render/sdl_helper.h"
+#include "graphic/sdl/utils.h"
#include "graphic/surface.h"
#include "graphic/surface_cache.h"
#include "graphic/text/rt_errors.h"
=== modified file 'src/graphic/text/test/render_richtext.cc'
--- src/graphic/text/test/render_richtext.cc 2014-09-20 09:37:47 +0000
+++ src/graphic/text/test/render_richtext.cc 2014-11-01 20:50:47 +0000
@@ -31,7 +31,7 @@
#include "base/log.h"
#include "graphic/image_io.h"
-#include "graphic/render/sdl_surface.h"
+#include "graphic/sdl/surface.h"
#include "graphic/text/rt_errors.h"
#include "graphic/text/test/render.h"
#include "io/filesystem/filesystem.h"
=== modified file 'src/graphic/texture.h'
--- src/graphic/texture.h 2014-09-20 09:37:47 +0000
+++ src/graphic/texture.h 2014-11-01 20:50:47 +0000
@@ -27,7 +27,7 @@
#include <stdint.h>
#include "graphic/colormap.h"
-#include "graphic/render/gl_surface_texture.h"
+#include "graphic/gl/surface_texture.h"
/// Textures have a fixed size and are squares.
/// TEXTURE_HEIGHT is just defined for easier understanding of the code.
=== modified file 'src/logic/description_maintainer.h'
--- src/logic/description_maintainer.h 2014-09-14 11:31:58 +0000
+++ src/logic/description_maintainer.h 2014-11-01 20:50:47 +0000
@@ -36,6 +36,9 @@
// Returns the number of entries in the container.
size_t get_nitems() const {return items_.size();}
+ // TODO(sirver): Remove get_nitems().
+
+ size_t size() const {return items_.size();}
// Returns the entry with the given 'name' if it exists or nullptr.
T* exists(const std::string& name) const;
=== modified file 'src/logic/map_info.cc'
--- src/logic/map_info.cc 2014-09-20 09:37:47 +0000
+++ src/logic/map_info.cc 2014-11-01 20:50:47 +0000
@@ -28,7 +28,7 @@
#include "config.h"
#include "graphic/graphic.h"
#include "graphic/image_io.h"
-#include "graphic/render/minimaprenderer.h"
+#include "graphic/minimap_renderer.h"
#include "graphic/surface.h"
#include "io/filesystem/filesystem.h"
#include "io/filesystem/layered_filesystem.h"
=== modified file 'src/wui/mapview.cc'
--- src/wui/mapview.cc 2014-09-10 13:03:40 +0000
+++ src/wui/mapview.cc 2014-11-01 20:50:47 +0000
@@ -20,10 +20,10 @@
#include "wui/mapview.h"
#include "base/macros.h"
+#include "graphic/gl/game_renderer.h"
#include "graphic/graphic.h"
-#include "graphic/render/gamerenderer_gl.h"
-#include "graphic/render/gamerenderer_sdl.h"
#include "graphic/rendertarget.h"
+#include "graphic/sdl/game_renderer.h"
#include "logic/map.h"
#include "logic/player.h"
#include "wlapplication.h"
@@ -98,10 +98,10 @@
if (!m_renderer) {
if (g_opengl) {
- m_renderer.reset(new GameRendererGL());
+ m_renderer.reset(new GlGameRenderer());
} else
{
- m_renderer.reset(new GameRendererSDL());
+ m_renderer.reset(new SdlGameRenderer());
}
}
if (upcast(InteractivePlayer const, interactive_player, &intbase())) {
=== modified file 'src/wui/mapviewpixelconstants.h'
--- src/wui/mapviewpixelconstants.h 2014-07-05 16:41:51 +0000
+++ src/wui/mapviewpixelconstants.h 2014-11-01 20:50:47 +0000
@@ -21,9 +21,8 @@
#define WL_WUI_MAPVIEWPIXELCONSTANTS_H
// These are constants with the unit pixel.
-#define TRIANGLE_WIDTH 64
-#define TRIANGLE_HEIGHT 32
-#define HEIGHT_FACTOR 5
-
+constexpr int TRIANGLE_WIDTH = 64;
+constexpr int TRIANGLE_HEIGHT = 32;
+constexpr int HEIGHT_FACTOR = 5;
#endif // end of include guard: WL_WUI_MAPVIEWPIXELCONSTANTS_H
=== modified file 'src/wui/mapviewpixelfunctions.h'
--- src/wui/mapviewpixelfunctions.h 2014-09-10 08:55:04 +0000
+++ src/wui/mapviewpixelfunctions.h 2014-11-01 20:50:47 +0000
@@ -30,19 +30,18 @@
namespace MapviewPixelFunctions {
-float calc_brightness
- (int32_t const l,
- int32_t const r,
- int32_t const tl,
- int32_t const tr,
- int32_t const bl,
- int32_t const br);
-
-Point calc_pix_difference(const Widelands::Map &, Point, Point);
-uint32_t calc_pix_distance(const Widelands::Map &, Point, Point);
-
-uint32_t get_map_end_screen_x(const Widelands::Map &);
-uint32_t get_map_end_screen_y(const Widelands::Map &);
+float calc_brightness(int32_t l, int32_t r, int32_t tl, int32_t tr, int32_t bl, int32_t br);
+
+Point calc_pix_difference(const Widelands::Map&, Point, Point);
+uint32_t calc_pix_distance(const Widelands::Map&, Point, Point);
+
+inline uint32_t get_map_end_screen_x(const Widelands::Map& map) {
+ return map.get_width() * TRIANGLE_WIDTH;
+}
+
+inline uint32_t get_map_end_screen_y(const Widelands::Map& map) {
+ return map.get_height() * TRIANGLE_HEIGHT;
+}
/**
* Calculate the coordinates of the triangle the given point in pixels is in.
@@ -53,80 +52,37 @@
* the point is in. But this should be fully correct for all but the most
* bizarre triangle shapes, and acceptable even for them.
*/
-Widelands::NodeAndTriangle<> calc_node_and_triangle
- (const Widelands::Map &, uint32_t x, uint32_t y);
-
-void normalize_pix(const Widelands::Map &, Point & p);
-
-/**
- * Calculate the on-screen position of the node without taking height into
- * account.
- */
-void get_basepix(Widelands::Coords fc, int32_t & px, int32_t & py);
-
-/**
- * Calculate the on-screen position of the node.
- */
-void get_pix(Widelands::FCoords fc, int32_t & px, int32_t & py);
-
-void get_pix
- (const Widelands::Map &, Widelands::Coords c, int32_t & px, int32_t & py);
-
-void get_save_pix
- (const Widelands::Map &, Widelands::Coords c, int32_t & px, int32_t & py);
-}
-
-// Implementation follows:
-// The rest of the content of this file is only here to be inlined. It should
-// have been in the cc file otherwise. Now objectcode modularity is not
-// achieved, but only sourcecode modularity is required.
-
-inline uint32_t MapviewPixelFunctions::get_map_end_screen_x
- (const Widelands::Map & map)
-{
- return map.get_width() * TRIANGLE_WIDTH;
-}
-inline uint32_t MapviewPixelFunctions::get_map_end_screen_y
- (const Widelands::Map & map)
-{
- return map.get_height() * TRIANGLE_HEIGHT;
-}
-
-/*
-===============
-Calculate the on-screen position of the node without taking height
-into account.
-===============
-*/
-inline void MapviewPixelFunctions::get_basepix
- (Widelands::Coords const c, int32_t & px, int32_t & py)
-{
+Widelands::NodeAndTriangle<> calc_node_and_triangle(const Widelands::Map&, uint32_t x, uint32_t y);
+
+void normalize_pix(const Widelands::Map&, Point& p);
+
+// Calculate the on-screen position of the node without taking height into
+// account.
+inline void get_basepix(const Widelands::Coords& c, int32_t& px, int32_t& py) {
py = c.y * TRIANGLE_HEIGHT;
px = c.x * TRIANGLE_WIDTH + (c.y & 1) * (TRIANGLE_WIDTH / 2);
}
-
-inline void MapviewPixelFunctions::get_pix
- (Widelands::FCoords const fc, int32_t & px, int32_t & py)
-{
+/**
+ * Calculate the on-screen position of the node.
+ */
+inline void get_pix(const Widelands::FCoords& fc, int32_t& px, int32_t& py) {
get_basepix(fc, px, py);
py -= fc.field->get_height() * HEIGHT_FACTOR;
}
-inline void MapviewPixelFunctions::get_pix
- (const Widelands::Map & map, const Widelands::Coords c,
- int32_t & px, int32_t & py)
-{
+inline void
+get_pix(const Widelands::Map& map, const Widelands::Coords& c, int32_t& px, int32_t& py) {
get_pix(map.get_fcoords(c), px, py);
}
// fx and fy might be out of range, must be normalized for the field
// theres no need for such a function for FCoords, since x, y out of range
// but field valid doesn't make sense
-inline void MapviewPixelFunctions::get_save_pix
- (const Widelands::Map & map, Widelands::Coords const c,
- int32_t & px, int32_t & py)
-{
+inline void get_save_pix(const Widelands::Map& map,
+ const Widelands::Coords& c,
+ int32_t& px,
+ int32_t& py) {
Widelands::Coords c1 = c;
map.normalize_coords(c1);
Widelands::FCoords fc = map.get_fcoords(c1);
@@ -135,4 +91,6 @@
get_pix(fc, px, py);
}
+} // namespace MapviewPixelFunctions
+
#endif // end of include guard: WL_WUI_MAPVIEWPIXELFUNCTIONS_H
=== modified file 'src/wui/minimap.cc'
--- src/wui/minimap.cc 2014-09-10 08:55:04 +0000
+++ src/wui/minimap.cc 2014-11-01 20:50:47 +0000
@@ -24,7 +24,7 @@
#include "base/i18n.h"
#include "graphic/graphic.h"
#include "graphic/in_memory_image.h"
-#include "graphic/render/minimaprenderer.h"
+#include "graphic/minimap_renderer.h"
#include "graphic/rendertarget.h"
#include "graphic/surface.h"
#include "logic/map.h"
=== modified file 'src/wui/minimap.h'
--- src/wui/minimap.h 2014-09-10 08:55:04 +0000
+++ src/wui/minimap.h 2014-11-01 20:50:47 +0000
@@ -22,7 +22,7 @@
#include <boost/signals2.hpp>
-#include "graphic/render/minimaprenderer.h"
+#include "graphic/minimap_renderer.h"
#include "ui_basic/button.h"
#include "ui_basic/unique_window.h"
References