summaryrefslogtreecommitdiffstats
path: root/dev/a5-artrender/artrender_app.cc
blob: e0d24c7326c88b6646cc049e67945ac146769edb (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
/** CSci-4611 Assignment 5:  Art Render
 */

#include "artrender_app.h"
#include "config.h"

#include <iostream>
#include <sstream>



using namespace std;

ArtRenderApp::ArtRenderApp() : GraphicsApp(1024,768, "Art Render"),
    shader_style_(0), current_model_(0), light_pos_(1.5, 1.5, 1.5),
    diffuse_ramp_(GL_CLAMP_TO_EDGE), specular_ramp_(GL_CLAMP_TO_EDGE)
{
    // Define a search path for finding data files (images and shaders)
    search_path_.push_back(".");
    search_path_.push_back("./data");
    search_path_.push_back("./shaders");
    search_path_.push_back(DATA_DIR_INSTALL);
    search_path_.push_back(DATA_DIR_BUILD);
    search_path_.push_back(SHADERS_DIR_INSTALL);
    search_path_.push_back(SHADERS_DIR_BUILD);
    
    // NOTE: YOU CAN COMMENT OUT SOME OF THESE IF THE APP IS LOADING TOO SLOWLY
    // THE MODEL_FILES ARRAY JUST NEEDS TO HOLD AT LEAST ONE MODEL.
	// Also, compiling in Release mode will optimize the loading of text files a lot.
    model_files_.push_back("bunny.obj");
    model_files_.push_back("chamferedCube.obj");
    model_files_.push_back("cow.obj");
    model_files_.push_back("hippo.obj");
    model_files_.push_back("maxplanck.obj");
    model_files_.push_back("sphere.obj");
    model_files_.push_back("teapot.obj");
}


ArtRenderApp::~ArtRenderApp() {
}


void ArtRenderApp::InitNanoGUI() {
	// Setup the GUI window
	nanogui::Window* window = new nanogui::Window(screen(), "Shading Style");
	window->setPosition(Eigen::Vector2i(10, 10));
	window->setSize(Eigen::Vector2i(200, 100));
	window->setLayout(new nanogui::GroupLayout());

	new nanogui::Label(window, "Dynamically Reload", "sans-bold");

	nanogui::Button* btnReload = new nanogui::Button(window, "Reload Shaders and Textures");
	btnReload->setCallback(std::bind(&ArtRenderApp::OnReloadBtnPressed, this));


	new nanogui::Label(window, "Rendering Style", "sans-bold");

	nanogui::Button* btnGouraud = new nanogui::Button(window, "Gouraud Shading");
	btnGouraud->setCallback(std::bind(&ArtRenderApp::OnGouraudBtnPressed, this));

	nanogui::Button* btnPhong = new nanogui::Button(window, "Phong Shading");
	btnPhong->setCallback(std::bind(&ArtRenderApp::OnPhongBtnPressed, this));

	nanogui::Button* btnArtsy = new nanogui::Button(window, "Artsy Shading");
	btnArtsy->setCallback(std::bind(&ArtRenderApp::OnArtsyBtnPressed, this));


	new nanogui::Label(window, "Model", "sans-bold");

	for (int i = 0; i < model_files_.size(); i++) {
		nanogui::Button* btn = new nanogui::Button(window, model_files_[i]);
		btn->setCallback([this, i] { this->current_model_ = i; });
		Mesh m;
		m.LoadFromOBJ(Platform::FindFile(model_files_[i], search_path_));
		meshes_.push_back(m);
		EdgeMesh em;
		em.CreateFromMesh(m);
		edge_meshes_.push_back(em);
	}
	screen()->performLayout();
}


void ArtRenderApp::OnLeftMouseDown(const Point2 &pos) {
    Point2 normalizedMousePos = PixelsToNormalizedDeviceCoords(pos);
    float mouseZ = ReadZValueAtPixel(pos);
    uni_cam_.OnButtonDown(normalizedMousePos, mouseZ);
}


void ArtRenderApp::OnLeftMouseDrag(const Point2 &pos, const Vector2 &delta) {
    Point2 normalizedMousePos = PixelsToNormalizedDeviceCoords(pos);
    uni_cam_.OnDrag(normalizedMousePos);
}


void ArtRenderApp::OnLeftMouseUp(const Point2 &pos) {
    Point2 normalizedMousePos = PixelsToNormalizedDeviceCoords(pos);
    uni_cam_.OnButtonUp(normalizedMousePos);
}


void ArtRenderApp::UpdateSimulation(double dt)  {
    uni_cam_.AdvanceAnimation(dt);
}


void ArtRenderApp::OnReloadBtnPressed() {
	LoadShadersAndTextures();
}

void ArtRenderApp::OnGouraudBtnPressed() {
	shader_style_ = 0;
}

void ArtRenderApp::OnPhongBtnPressed() {
	shader_style_ = 1;
}

void ArtRenderApp::OnArtsyBtnPressed() {
	shader_style_ = 2;
}



void ArtRenderApp::InitOpenGL() {
    // Set up the camera in a good position to see the model
	proj_matrix_ = Matrix4::Perspective(30, aspect_ratio(), 0.1f, 50.0f);
    uni_cam_.set_view_matrix(Matrix4::LookAt(Point3(0,0,3), Point3(0,0,0), Vector3(0,1,0)));
    glClearColor(0.7f, 0.7f, 0.7f, 1.0f);

	// Customize the lighting used for the quick shapes default shader to make the
	// ambient really bright since we're using it to draw the yellow "light bulb" 
	// in the scene.
	DefaultShader::LightProperties qs_light;
	qs_light.ambient_intensity = Color(0.8f, 0.8f, 0.8f);
	qs_light.diffuse_intensity = Color(0.4f, 0.4f, 0.4f);
	qs_light.specular_intensity = Color(0.0f, 0.0f, 0.0f);
	quick_shapes_.default_shader()->SetLight(0, qs_light);

	LoadShadersAndTextures();
}


void ArtRenderApp::LoadShadersAndTextures() {
	// (Re)loads and (re)compiles all of the shader programs text files.  And, (re)loads the
	// textures from file as well.

	gouraud_shaderprog_.AddVertexShaderFromFile(Platform::FindFile("gouraud.vert", search_path_));
	gouraud_shaderprog_.AddFragmentShaderFromFile(Platform::FindFile("gouraud.frag", search_path_));
	gouraud_shaderprog_.LinkProgram();

	phong_shaderprog_.AddVertexShaderFromFile(Platform::FindFile("phong.vert", search_path_));
	phong_shaderprog_.AddFragmentShaderFromFile(Platform::FindFile("phong.frag", search_path_));
	phong_shaderprog_.LinkProgram();

	artsy_shaderprog_.AddVertexShaderFromFile(Platform::FindFile("artsy.vert", search_path_));
	artsy_shaderprog_.AddFragmentShaderFromFile(Platform::FindFile("artsy.frag", search_path_));
	artsy_shaderprog_.LinkProgram();

	outline_shaderprog_.AddVertexShaderFromFile(Platform::FindFile("outline.vert", search_path_));
	outline_shaderprog_.AddFragmentShaderFromFile(Platform::FindFile("outline.frag", search_path_));
	outline_shaderprog_.LinkProgram();

	// To try out different shading styles, you can replace diffuse.png and specular.png with
	// some of the other texture files in the data/ directory.
	diffuse_ramp_.InitFromFile(Platform::FindFile("toonDiffuse.png", search_path_));
	diffuse_ramp_.set_wrap_mode(GL_CLAMP_TO_EDGE);

	specular_ramp_.InitFromFile(Platform::FindFile("toonSpecular.png", search_path_));
	specular_ramp_.set_wrap_mode(GL_CLAMP_TO_EDGE);
}


void ArtRenderApp::DrawUsingOpenGL() {
    // Just the identity matrix
    Matrix4 model_matrix;
    
    // Lighting parameters
    static const Color Ia(0.3f, 0.3f, 0.3f, 1.0f);
    static const Color Id(0.7f, 0.7f, 0.7f, 1.0f);
    static const Color Is(1.0f, 1.0f, 1.0f, 1.0f);
    
    // Material parameters
    static const Color ka(1.0f, 0.4f, 0.4f, 1.0f);
    static const Color kd(1.0f, 0.4f, 0.4f, 1.0f);
    static const Color ks(0.6f, 0.6f, 0.6f, 1.0f);
    static const float s = 50.0f;
    
    // Precompute items needed in the shader
    
    // Light positions are usually defined in world space.  For lighting calculations
    // we need the position of the light in view space (a.k.a. eye space).
    Point3 light_in_eye_space = uni_cam_.view_matrix() * light_pos_;
    
    // The shader also needs these matrices
    Matrix4 model_view_matrix = uni_cam_.view_matrix()*model_matrix;
    Matrix4 normal_matrix = model_view_matrix.Inverse().Transpose();
    
    // Make sure the default option to only draw front facing triangles is set
    glEnable(GL_CULL_FACE);
    
	if (shader_style_ == 0) {

		// Render the current model's mesh using the Gouraud shader program
		gouraud_shaderprog_.UseProgram();
		gouraud_shaderprog_.SetUniform("model_view_matrix", model_view_matrix);
		gouraud_shaderprog_.SetUniform("normal_matrix", normal_matrix);
		gouraud_shaderprog_.SetUniform("proj_matrix", proj_matrix_);
		gouraud_shaderprog_.SetUniform("ka", ka);
		gouraud_shaderprog_.SetUniform("kd", kd);
		gouraud_shaderprog_.SetUniform("ks", ks);
		gouraud_shaderprog_.SetUniform("s", s);
		gouraud_shaderprog_.SetUniform("light_in_eye_space", light_in_eye_space);
		gouraud_shaderprog_.SetUniform("Ia", Ia);
		gouraud_shaderprog_.SetUniform("Id", Id);
		gouraud_shaderprog_.SetUniform("Is", Is);
		meshes_[current_model_].Draw();
		gouraud_shaderprog_.StopProgram();

	}
	if (shader_style_ == 1) {

		// Render the current model's mesh using the Phong shader program
		phong_shaderprog_.UseProgram();
		phong_shaderprog_.SetUniform("model_view_matrix", model_view_matrix);
		phong_shaderprog_.SetUniform("normal_matrix", normal_matrix);
		phong_shaderprog_.SetUniform("proj_matrix", proj_matrix_);
		phong_shaderprog_.SetUniform("ka", ka);
		phong_shaderprog_.SetUniform("kd", kd);
		phong_shaderprog_.SetUniform("ks", ks);
		phong_shaderprog_.SetUniform("s", s);
		phong_shaderprog_.SetUniform("light_in_eye_space", light_in_eye_space);
		phong_shaderprog_.SetUniform("Ia", Ia);
		phong_shaderprog_.SetUniform("Id", Id);
		phong_shaderprog_.SetUniform("Is", Is);
		meshes_[current_model_].Draw();
		phong_shaderprog_.StopProgram();

	}
	else if (shader_style_ == 2) {

		// Rendering using the Artsy shader programs

		// Step 1: Use the toon shader to draw the object's mesh
		artsy_shaderprog_.UseProgram();
		artsy_shaderprog_.SetUniform("model_view_matrix", model_view_matrix);
		artsy_shaderprog_.SetUniform("normal_matrix", normal_matrix);
		artsy_shaderprog_.SetUniform("proj_matrix", proj_matrix_);
		artsy_shaderprog_.SetUniform("ka", ka);
		artsy_shaderprog_.SetUniform("kd", kd);
		artsy_shaderprog_.SetUniform("ks", ks);
		artsy_shaderprog_.SetUniform("s", s);
		artsy_shaderprog_.SetUniform("light_in_eye_space", light_in_eye_space);
		artsy_shaderprog_.SetUniform("Ia", Ia);
		artsy_shaderprog_.SetUniform("Id", Id);
		artsy_shaderprog_.SetUniform("Is", Is);
		artsy_shaderprog_.BindTexture("diffuse_ramp", diffuse_ramp_);
		artsy_shaderprog_.BindTexture("specular_ramp", specular_ramp_);
		meshes_[current_model_].Draw();
		artsy_shaderprog_.StopProgram();


		// Step 2: Draw the silhouette edge using the edge mesh and outline shader

		// Disable back face culling so OpenGL will draw both front and back facing triangles
		glDisable(GL_CULL_FACE);

		// Set the OpenGL polygon offset so it will draw triangles even if they
		// exactly on top of another triangle
		glEnable(GL_POLYGON_OFFSET_FILL);
		glPolygonOffset(1, 1);

		static const float thickness = 0.01f;

		// Draw edge mesh
		outline_shaderprog_.UseProgram();
		outline_shaderprog_.SetUniform("model_view_matrix", model_view_matrix);
		outline_shaderprog_.SetUniform("normal_matrix", normal_matrix);
		outline_shaderprog_.SetUniform("proj_matrix", proj_matrix_);
		outline_shaderprog_.SetUniform("thickness", thickness);
		edge_meshes_[current_model_].Draw();
		outline_shaderprog_.StopProgram();

	}

	// Draw a little yellow sphere at the location of the light source
	Matrix4 light_model = Matrix4::Translation(light_pos_ - Point3(0, 0, 0)) *
		Matrix4::Scale(Vector3(0.1f, 0.1f, 0.1f));
	quick_shapes_.DrawSphere(light_model, uni_cam_.view_matrix(), proj_matrix_, Color(1, 1, 0));

    // Draw the UniCam widget when in rotation mode
    uni_cam_.Draw(proj_matrix_);
}