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