-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathrendering.cpp
More file actions
173 lines (147 loc) · 4.73 KB
/
rendering.cpp
File metadata and controls
173 lines (147 loc) · 4.73 KB
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
////////////////////////////////////////////////////////////////////////
//
// rendering.cpp: Put the calculated polys on the screen
//
// Copyright (c) Simon Frankau 2018
//
#ifdef __APPLE__
#include <GLUT/glut.h>
#else
#include <GL/glut.h>
#endif
#include <vector>
#include <png.h>
#include "geom.h"
static const int WIDTH = 2048;
static const int HEIGHT = 2048;
static const Vertex EYE_POS = Vertex(0.0, 0.0, -3.0);
static std::vector<Quad> flatFaces;
static std::vector<GouraudQuad> gouraudFaces;
static std::vector<Vertex> vertices;
static void screenshotPNG(const char *filename)
{
const size_t format_nchannels = 4;
size_t nvals = format_nchannels * WIDTH * HEIGHT;
// Assuming a GLubyte is a png_byte...
std::vector<png_byte> pixels(nvals);
glReadPixels(0, 0, WIDTH, HEIGHT, GL_RGBA, GL_UNSIGNED_BYTE, &pixels[0]);
std::vector<png_byte *> png_rows(HEIGHT);
for (size_t i = 0; i < HEIGHT; i++) {
png_rows[HEIGHT - i - 1] = &pixels[i * WIDTH * format_nchannels];
}
png_structp png = png_create_write_struct(PNG_LIBPNG_VER_STRING,
NULL, NULL, NULL);
if (png == NULL) {
throw std::runtime_error("png_create_write_struct failed");
}
png_infop info = png_create_info_struct(png);
if (info == NULL) {
throw std::runtime_error("png_create_info_struct failed");
}
if (setjmp(png_jmpbuf(png))) {
throw std::runtime_error("Something failed in libpng");
}
FILE *f = fopen(filename, "wb");
png_init_io(png, f);
png_set_IHDR(png, info, WIDTH, HEIGHT, 8, PNG_COLOR_TYPE_RGBA,
PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_write_info(png, info);
png_write_image(png, &png_rows[0]);
png_write_end(png, NULL);
png_destroy_write_struct(&png, &info);
fclose(f);
}
static void drawScene(void)
{
for (std::vector<Quad>::const_iterator iter = flatFaces.begin(),
end = flatFaces.end(); iter != end; ++iter) {
iter->render(vertices);
}
for (std::vector<GouraudQuad>::const_iterator iter = gouraudFaces.begin(),
end = gouraudFaces.end(); iter != end; ++iter) {
iter->render(vertices);
}
}
static void display(void)
{
static bool first = true;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
drawScene();
if (first) {
screenshotPNG("png/scene.png");
first = false;
}
glutSwapBuffers();
}
static void initGL(void)
{
// Flat shading.
glEnable(GL_COLOR_MATERIAL);
// Use depth buffering for hidden surface elimination.
glEnable(GL_DEPTH_TEST);
// Back-face culling.
glEnable(GL_CULL_FACE);
// Setup the view of the cube. Will become a view from inside the
// cube.
glMatrixMode(GL_PROJECTION);
gluPerspective(45.0, // Field of view in degrees
1.0, // Aspect ratio
1.0, // Z near
10.0); // Z far
glMatrixMode(GL_MODELVIEW);
gluLookAt(EYE_POS.x(), EYE_POS.y(), EYE_POS.z(),
0.0, 0.0, 0.0, // Looking at origin
0.0, 1.0, 0.0); // Up is in positive Y direction
}
static bool facesUs(Quad const &q, std::vector<Vertex> const &vs)
{
return dot(paraCentre(q, vs) - EYE_POS,
paraCross(q, vs)) > 0;
}
// Normalise the brightness of non-emitting components
void normaliseBrightness(std::vector<Quad> &qs, std::vector<Vertex> const &vs)
{
const double TARGET = 1.0;
double max = 0.0;
for (std::vector<Quad>::iterator iter = qs.begin(), end = qs.end();
iter != end; ++iter) {
// Only include non-emitters, facing us.
if (!iter->isEmitter && facesUs(*iter, vs)) {
max = std::max(max, iter->screenColour.r);
max = std::max(max, iter->screenColour.g);
max = std::max(max, iter->screenColour.b);
}
}
double scale = max < TARGET ? TARGET / max : 1.0;
for (std::vector<Quad>::iterator iter = qs.begin(), end = qs.end();
iter != end; ++iter) {
if (!iter->isEmitter) {
iter->screenColour = iter->screenColour * scale;
}
}
}
static void render()
{
glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH);
glutInitWindowSize(WIDTH, HEIGHT);
glutCreateWindow("Radiosity demo");
glutDisplayFunc(display);
initGL();
// Render one-off first, so we can get it saved to disk without
// getting it limited to screen size...
display();
glutMainLoop();
}
void renderFlat(std::vector<Quad> f, std::vector<Vertex> v)
{
flatFaces = f;
vertices = v;
render();
}
void renderGouraud(std::vector<GouraudQuad> f, std::vector<Vertex> v)
{
gouraudFaces = f;
vertices = v;
render();
}