1 // Copyright 2015-2018 the openage authors. See copying.md for legal info.
2
3 #include <epoxy/gl.h>
4 #include <SDL2/SDL.h>
5 #include <sys/stat.h>
6 #include <sys/types.h>
7 #include <sstream>
8
9 #include "console/console.h"
10 #include "engine.h"
11 #include "gamedata/color.gen.h"
12 #include "gamestate/game_main.h"
13 #include "gamestate/game_spec.h"
14 #include "input/input_manager.h"
15 #include "log/log.h"
16 #include "terrain/terrain.h"
17 #include "unit/action.h"
18 #include "unit/command.h"
19 #include "unit/producer.h"
20 #include "unit/unit.h"
21 #include "unit/unit_texture.h"
22 #include "util/timer.h"
23 #include "util/externalprofiler.h"
24 #include "renderer/text.h"
25 #include "game_renderer.h"
26
27 namespace openage {
28
RenderOptions()29 RenderOptions::RenderOptions()
30 :
31 OptionNode{"RendererOptions"},
32 draw_debug{this, "draw_debug", false},
33 terrain_blending{this, "terrain_blending", true} {
34 }
35
GameRenderer(Engine * e)36 GameRenderer::GameRenderer(Engine *e)
37 :
38 engine{e} {
39
40 // set options structure
41 this->settings.set_parent(this->engine);
42
43 // engine callbacks
44 this->engine->register_draw_action(this);
45
46 // fetch asset loading dir
47 util::Path asset_dir = engine->get_root_dir()["assets"];
48
49 // load textures and stuff
50 gaben = new Texture{asset_dir["gaben.png"]};
51
52 std::vector<gamedata::palette_color> player_color_lines = util::read_csv_file<gamedata::palette_color>(
53 asset_dir["converted/player_palette.docx"]
54 );
55
56 std::unique_ptr<GLfloat[]> playercolors = std::make_unique<GLfloat[]>(player_color_lines.size() * 4);
57 for (size_t i = 0; i < player_color_lines.size(); i++) {
58 auto line = &player_color_lines[i];
59 playercolors[i*4] = line->r / 255.0;
60 playercolors[i*4 + 1] = line->g / 255.0;
61 playercolors[i*4 + 2] = line->b / 255.0;
62 playercolors[i*4 + 3] = line->a / 255.0;
63 }
64
65 // shader initialisation
66 // read shader source codes and create shader objects for wrapping them.
67 const char *shader_header_code = "#version 120\n";
68 std::string equals_epsilon_code = asset_dir["shaders/equalsEpsilon.glsl"].open().read();
69 std::string texture_vert_code = asset_dir["shaders/maptexture.vert.glsl"].open().read();
70 auto plaintexture_vert = std::make_unique<shader::Shader>(
71 GL_VERTEX_SHADER,
72 std::initializer_list<const char *>{shader_header_code, texture_vert_code.c_str()}
73 );
74
75 std::string texture_frag_code = asset_dir["shaders/maptexture.frag.glsl"].open().read();
76 auto plaintexture_frag = std::make_unique<shader::Shader>(
77 GL_FRAGMENT_SHADER,
78 std::initializer_list<const char *>{shader_header_code, texture_frag_code.c_str()}
79 );
80
81 std::string teamcolor_frag_code = asset_dir["shaders/teamcolors.frag.glsl"].open().read();
82 std::stringstream ss;
83 ss << player_color_lines.size();
84 auto teamcolor_frag = std::make_unique<shader::Shader>(
85 GL_FRAGMENT_SHADER,
86 std::initializer_list<const char *>{
87 shader_header_code,
88 ("#define NUM_OF_PLAYER_COLORS " + ss.str() + "\n").c_str(),
89 equals_epsilon_code.c_str(),
90 teamcolor_frag_code.c_str()
91 }
92 );
93
94 std::string alphamask_vert_code = asset_dir["shaders/alphamask.vert.glsl"].open().read();
95 auto alphamask_vert = std::make_unique<shader::Shader>(
96 GL_VERTEX_SHADER,
97 std::initializer_list<const char *>{shader_header_code, alphamask_vert_code.c_str()}
98 );
99
100 std::string alphamask_frag_code = asset_dir["shaders/alphamask.frag.glsl"].open().read();
101 auto alphamask_frag = std::make_unique<shader::Shader>(
102 GL_FRAGMENT_SHADER,
103 std::initializer_list<const char *>{shader_header_code, alphamask_frag_code.c_str()}
104 );
105
106 std::string texturefont_vert_code = asset_dir["shaders/texturefont.vert.glsl"].open().read();
107 auto texturefont_vert = std::make_unique<shader::Shader>(
108 GL_VERTEX_SHADER,
109 std::initializer_list<const char *>{shader_header_code, texturefont_vert_code.c_str()}
110 );
111
112 std::string texturefont_frag_code = asset_dir["shaders/texturefont.frag.glsl"].open().read();
113 auto texturefont_frag = std::make_unique<shader::Shader>(
114 GL_FRAGMENT_SHADER,
115 std::initializer_list<const char *>{shader_header_code, texturefont_frag_code.c_str()}
116 );
117
118 // create program for rendering simple textures
119 texture_shader::program = new shader::Program(plaintexture_vert.get(), plaintexture_frag.get());
120 texture_shader::program->link();
121 texture_shader::texture = texture_shader::program->get_uniform_id("texture");
122 texture_shader::tex_coord = texture_shader::program->get_attribute_id("tex_coordinates");
123 texture_shader::program->use();
124 glUniform1i(texture_shader::texture, 0);
125 texture_shader::program->stopusing();
126
127
128 // create program for tinting textures at alpha-marked pixels
129 // with team colors
130 teamcolor_shader::program = new shader::Program(plaintexture_vert.get(), teamcolor_frag.get());
131 teamcolor_shader::program->link();
132 teamcolor_shader::texture = teamcolor_shader::program->get_uniform_id("texture");
133 teamcolor_shader::tex_coord = teamcolor_shader::program->get_attribute_id("tex_coordinates");
134 teamcolor_shader::player_id_var = teamcolor_shader::program->get_uniform_id("player_number");
135 teamcolor_shader::alpha_marker_var = teamcolor_shader::program->get_uniform_id("alpha_marker");
136 teamcolor_shader::player_color_var = teamcolor_shader::program->get_uniform_id("player_color");
137 teamcolor_shader::program->use();
138 glUniform1i(teamcolor_shader::texture, 0);
139 glUniform1f(teamcolor_shader::alpha_marker_var, 254.0/255.0);
140 // fill the teamcolor shader's player color table:
141 glUniform4fv(teamcolor_shader::player_color_var, 64, playercolors.get());
142 teamcolor_shader::program->stopusing();
143
144
145 // create program for drawing textures that are alpha-masked before
146 alphamask_shader::program = new shader::Program(alphamask_vert.get(), alphamask_frag.get());
147 alphamask_shader::program->link();
148 alphamask_shader::base_coord = alphamask_shader::program->get_attribute_id("base_tex_coordinates");
149 alphamask_shader::mask_coord = alphamask_shader::program->get_attribute_id("mask_tex_coordinates");
150 alphamask_shader::show_mask = alphamask_shader::program->get_uniform_id("show_mask");
151 alphamask_shader::base_texture = alphamask_shader::program->get_uniform_id("base_texture");
152 alphamask_shader::mask_texture = alphamask_shader::program->get_uniform_id("mask_texture");
153 alphamask_shader::program->use();
154 glUniform1i(alphamask_shader::base_texture, 0);
155 glUniform1i(alphamask_shader::mask_texture, 1);
156 alphamask_shader::program->stopusing();
157
158 // Create program for texture based font rendering
159 texturefont_shader::program = new shader::Program(texturefont_vert.get(), texturefont_frag.get());
160 texturefont_shader::program->link();
161 texturefont_shader::texture = texturefont_shader::program->get_uniform_id("texture");
162 texturefont_shader::color = texturefont_shader::program->get_uniform_id("color");
163 texturefont_shader::tex_coord = texturefont_shader::program->get_attribute_id("tex_coordinates");
164 texturefont_shader::program->use();
165 glUniform1i(texturefont_shader::texture, 0);
166 texturefont_shader::program->stopusing();
167
168 // Renderer keybinds
169 // TODO: a renderer settings struct
170 // would allow these to be put somewher better
171 input::ActionManager &action = this->engine->get_action_manager();
172 auto &global_input_context = engine->get_input_manager().get_global_context();
__anonc259fb1f0102(const input::action_arg_t &) 173 global_input_context.bind(action.get("TOGGLE_BLENDING"), [this](const input::action_arg_t &) {
174 this->settings.terrain_blending.value = !this->settings.terrain_blending.value;
175 });
__anonc259fb1f0202(const input::action_arg_t &) 176 global_input_context.bind(action.get("TOGGLE_UNIT_DEBUG"), [this](const input::action_arg_t &) {
177 this->settings.draw_debug.value = !this->settings.draw_debug.value;
178
179 log::log(MSG(dbg) << "Toggle debug grid");
180
181 // TODO remove this hack, use render settings instead
182 UnitAction::show_debug = !UnitAction::show_debug;
183 });
184
185 log::log(MSG(dbg) << "Loaded Renderer");
186 }
187
~GameRenderer()188 GameRenderer::~GameRenderer() {
189 // oh noes, release hl3 before that!
190 delete this->gaben;
191
192 delete texture_shader::program;
193 delete teamcolor_shader::program;
194 delete alphamask_shader::program;
195 delete texturefont_shader::program;
196 }
197
198
on_draw()199 bool GameRenderer::on_draw() {
200 // draw terrain
201 GameMain *game = this->engine->get_game();
202
203 if (game) {
204 // draw gaben, our great and holy protector, bringer of the half-life 3.
205 gaben->draw(this->engine->coord, coord::camgame{0, 0});
206
207 // TODO move render code out of terrain
208 if (game->terrain) {
209 game->terrain->draw(this->engine, &this->settings);
210 }
211 }
212 return true;
213 }
214
game() const215 GameMain *GameRenderer::game() const {
216 return this->engine->get_game();
217 }
218
game_spec() const219 GameSpec *GameRenderer::game_spec() const {
220 return this->game()->get_spec();
221 }
222
223 } // openage
224