1 // Copyright 2018 Google LLC
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include "tools/render/rectangle_renderer.h"
16
17 #include <array>
18
19 #include "absl/algorithm/container.h"
20
21 namespace quic_trace {
22 namespace render {
23
24 namespace {
25
26 const char* kVertexShader = R"(
27 in vec2 coord;
28 in vec4 color_in;
29 out vec4 color_mid;
30
31 void main(void) {
32 gl_Position = windowToGl(coord);
33 color_mid = color_in;
34 }
35 )";
36
37 const char* kFragmentShader = R"(
38 in vec4 color_mid;
39 out vec4 color_out;
40
41 void main(void) {
42 color_out = color_mid;
43 }
44 )";
45
46 const char* kLineFragmentShader = R"(
47 out vec4 color_out;
48 void main(void) {
49 color_out = vec4(0, 0, 0, 1);
50 }
51 )";
52
53 } // namespace
54
RectangleRenderer(const ProgramState * state)55 RectangleRenderer::RectangleRenderer(const ProgramState* state)
56 : state_(state),
57 shader_(kVertexShader, kFragmentShader),
58 line_shader_(kVertexShader, kLineFragmentShader) {}
59
AddRectangle(Box box,uint32_t rgba)60 void RectangleRenderer::AddRectangle(Box box, uint32_t rgba) {
61 rgba = __builtin_bswap32(rgba);
62 // This looks like this:
63 // 2 3
64 // 0 1
65 points_.push_back(Point{box.origin.x, box.origin.y, rgba}); // 0
66 points_.push_back(Point{box.origin.x + box.size.x, box.origin.y, rgba}); // 1
67 points_.push_back(Point{box.origin.x, box.origin.y + box.size.y, rgba}); // 2
68 points_.push_back(
69 Point{box.origin.x + box.size.x, box.origin.y + box.size.y, rgba}); // 3
70 }
71
AddRectangleWithBorder(Box box,uint32_t rgba)72 void RectangleRenderer::AddRectangleWithBorder(Box box, uint32_t rgba) {
73 const size_t point_buffer_offset = points_.size();
74 AddRectangle(box, rgba);
75
76 const std::array<uint16_t, 8> lines = {0, 1, 1, 3, 3, 2, 2, 0};
77 line_indices_.resize(line_indices_.size() + 8);
78 absl::c_transform(lines, line_indices_.end() - 8,
79 [=](uint16_t i) { return i + point_buffer_offset; });
80 }
81
Render()82 void RectangleRenderer::Render() {
83 GlVertexBuffer point_buffer;
84 glBufferData(GL_ARRAY_BUFFER, points_.size() * sizeof(Point), points_.data(),
85 GL_STREAM_DRAW);
86
87 const size_t rectangle_count = points_.size() / 4;
88 const size_t point_count = rectangle_count * 6;
89 CHECK(point_count < std::numeric_limits<uint16_t>::max());
90
91 // Transform points of each rectangle into a pair of triangles.
92 auto indices = std::make_unique<uint16_t[]>(point_count);
93 for (int i = 0; i < rectangle_count; i++) {
94 indices[6 * i + 0] = 4 * i + 0;
95 indices[6 * i + 1] = 4 * i + 1;
96 indices[6 * i + 2] = 4 * i + 2;
97 indices[6 * i + 3] = 4 * i + 2;
98 indices[6 * i + 4] = 4 * i + 3;
99 indices[6 * i + 5] = 4 * i + 1;
100 }
101
102 glUseProgram(*shader_);
103 state_->Bind(shader_);
104
105 {
106 GlVertexArray array;
107 glBindVertexArray(*array);
108
109 GlElementBuffer index_buffer;
110 glBufferData(GL_ELEMENT_ARRAY_BUFFER, point_count * sizeof(indices[0]),
111 indices.get(), GL_STREAM_DRAW);
112
113 GlVertexArrayAttrib coord(shader_, "coord");
114 glVertexAttribPointer(*coord, 2, GL_FLOAT, GL_FALSE, sizeof(Point), 0);
115 GlVertexArrayAttrib color(shader_, "color_in");
116 glVertexAttribPointer(*color, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(Point),
117 (void*)offsetof(Point, rgba));
118
119 glDrawElements(GL_TRIANGLES, point_count, GL_UNSIGNED_SHORT, nullptr);
120 points_.clear();
121 }
122
123 glUseProgram(*line_shader_);
124 state_->Bind(line_shader_);
125 {
126 GlVertexArray array;
127 glBindVertexArray(*array);
128
129 GlElementBuffer index_buffer;
130 glBufferData(GL_ELEMENT_ARRAY_BUFFER,
131 line_indices_.size() * sizeof(line_indices_[0]),
132 line_indices_.data(), GL_STREAM_DRAW);
133
134 GlVertexArrayAttrib coord(shader_, "coord");
135 glVertexAttribPointer(*coord, 2, GL_FLOAT, GL_FALSE, sizeof(Point), 0);
136
137 glDrawElements(GL_LINES, line_indices_.size(), GL_UNSIGNED_SHORT, nullptr);
138 line_indices_.clear();
139 }
140 }
141
142 } // namespace render
143 } // namespace quic_trace
144