src/gl/gridprogram.cpp

Mon, 02 Mar 2020 11:08:13 +0200

author
Teemu Piippo <teemu@hecknology.net>
date
Mon, 02 Mar 2020 11:08:13 +0200
changeset 66
77c819262b7a
parent 64
f99d52b1646b
child 70
f21b800b02a4
permissions
-rw-r--r--

added a method to find out if the view is perpendicular to grid

53
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
1 /*
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
2 * LDForge: LDraw parts authoring CAD
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
3 * Copyright (C) 2020 Teemu Piippo
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
4 *
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
5 * This program is free software: you can redistribute it and/or modify
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
6 * it under the terms of the GNU General Public License as published by
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
7 * the Free Software Foundation, either version 3 of the License, or
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
8 * (at your option) any later version.
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
9 *
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
10 * This program is distributed in the hope that it will be useful,
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
13 * GNU General Public License for more details.
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
14 *
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
15 * You should have received a copy of the GNU General Public License
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
17 */
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
18
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
19 #include "gridprogram.h"
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
20
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
21 // Based on https://stackoverflow.com/q/30842755
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
22 const char vertexShaderSource[] = R"(
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
23 #version 330 core
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
24
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
25 layout (location = 0) in vec2 in_position;
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
26 uniform mat4 view;
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
27 uniform mat4 projection;
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
28 uniform mat4 model;
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
29 smooth out vec2 ex_uv;
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
30 const mat4 stretch = mat4(vec4(10000, 0, 0, 0), vec4(0, 10000, 0, 0), vec4(0, 0, 10000, 0), vec4(0, 0, 0, 1));
64
f99d52b1646b grid snapping now also works with transformed grids
Teemu Piippo <teemu@hecknology.net>
parents: 55
diff changeset
31 uniform mat4 grid;
53
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
32
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
33 void main()
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
34 {
64
f99d52b1646b grid snapping now also works with transformed grids
Teemu Piippo <teemu@hecknology.net>
parents: 55
diff changeset
35 gl_Position = projection * view * model * grid * stretch * vec4(in_position, 0.0, 1.0);
53
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
36 ex_uv = in_position;
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
37 }
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
38 )";
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
39
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
40 const char fragmentShaderSource[] = R"(
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
41 #version 330 core
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
42
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
43 out vec4 color;
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
44 smooth in vec2 ex_uv;
55
cb81ecb5fb23 grid stuff
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
45 uniform vec4 gridColor;
54
a4055f67b9c7 made the grid look nicer
Teemu Piippo <teemu@hecknology.net>
parents: 53
diff changeset
46 const float pi = 3.14159265f;
53
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
47
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
48 void main(void)
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
49 {
54
a4055f67b9c7 made the grid look nicer
Teemu Piippo <teemu@hecknology.net>
parents: 53
diff changeset
50 float dx = fract(ex_uv.y / 0.0001f);
a4055f67b9c7 made the grid look nicer
Teemu Piippo <teemu@hecknology.net>
parents: 53
diff changeset
51 float dy = fract(ex_uv.x / 0.0001f);
a4055f67b9c7 made the grid look nicer
Teemu Piippo <teemu@hecknology.net>
parents: 53
diff changeset
52 /* compute distance to nearest unit line */
a4055f67b9c7 made the grid look nicer
Teemu Piippo <teemu@hecknology.net>
parents: 53
diff changeset
53 float d = min(min(min(dy, dx), 1 - dy), 1 - dx);
a4055f67b9c7 made the grid look nicer
Teemu Piippo <teemu@hecknology.net>
parents: 53
diff changeset
54 /* use an extreme sigmoid to bring out the grid shape */
a4055f67b9c7 made the grid look nicer
Teemu Piippo <teemu@hecknology.net>
parents: 53
diff changeset
55 d = pow(1 - d, 50);
a4055f67b9c7 made the grid look nicer
Teemu Piippo <teemu@hecknology.net>
parents: 53
diff changeset
56 /* fade the grid towards extreme co-ordinates */
a4055f67b9c7 made the grid look nicer
Teemu Piippo <teemu@hecknology.net>
parents: 53
diff changeset
57 d = (1.0f - 20 * max(abs(ex_uv.x), abs(ex_uv.y))) * d;
a4055f67b9c7 made the grid look nicer
Teemu Piippo <teemu@hecknology.net>
parents: 53
diff changeset
58 /* add dashes */
a4055f67b9c7 made the grid look nicer
Teemu Piippo <teemu@hecknology.net>
parents: 53
diff changeset
59 d *= (1 + cos(ex_uv.y / 0.00001f * pi)) * 0.5f;
a4055f67b9c7 made the grid look nicer
Teemu Piippo <teemu@hecknology.net>
parents: 53
diff changeset
60 d *= (1 + cos(ex_uv.x / 0.00001f * pi)) * 0.5f;
55
cb81ecb5fb23 grid stuff
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
61 color = vec4(gridColor.xyz, gridColor.w * d);
53
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
62 }
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
63 )";
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
64
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
65 static const glm::vec2 data[] = {{-1, -1}, {-1, 1}, {1, 1}, {1, -1}};
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
66
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
67 GridProgram::GridProgram(QObject* parent) :
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
68 QObject{parent},
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
69 buffer{QOpenGLBuffer::VertexBuffer},
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
70 vertexShader{QOpenGLShader::Vertex},
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
71 fragmentShader{QOpenGLShader::Fragment}
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
72 {
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
73 }
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
74
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
75 void GridProgram::initialize()
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
76 {
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
77 if (not isInitialized)
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
78 {
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
79 this->initializeOpenGLFunctions();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
80 this->isInitialized = true;
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
81 this->program.emplace(this);
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
82 gl::buildShaders(&*this->program, ::vertexShaderSource, ::fragmentShaderSource);
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
83 this->program->bind();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
84 this->buffer.create();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
85 this->buffer.bind();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
86 this->buffer.setUsagePattern(QOpenGLBuffer::StaticDraw);
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
87 this->buffer.allocate(data, countof(data) * sizeof data[0]);
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
88 this->vertexArrayObject.create();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
89 this->vertexArrayObject.bind();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
90 this->program->enableAttributeArray(0);
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
91 this->program->setAttributeBuffer(0, GL_FLOAT, 0, 2, 0);
55
cb81ecb5fb23 grid stuff
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
92 this->program->setUniformVector("gridColor", this->gridColor);
53
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
93 this->vertexArrayObject.release();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
94 this->buffer.release();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
95 this->program->release();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
96 this->checkForGLErrors();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
97 }
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
98 }
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
99
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
100 void GridProgram::setViewMatrix(const glm::mat4& newViewMatrix)
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
101 {
64
f99d52b1646b grid snapping now also works with transformed grids
Teemu Piippo <teemu@hecknology.net>
parents: 55
diff changeset
102 this->setMatrix("view", newViewMatrix);
53
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
103 }
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
104
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
105 void GridProgram::setProjectionMatrix(const glm::mat4& newProjectionMatrix)
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
106 {
64
f99d52b1646b grid snapping now also works with transformed grids
Teemu Piippo <teemu@hecknology.net>
parents: 55
diff changeset
107 this->setMatrix("projection", newProjectionMatrix);
53
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
108 }
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
109
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
110 void GridProgram::setModelMatrix(const glm::mat4& newModelMatrix)
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
111 {
64
f99d52b1646b grid snapping now also works with transformed grids
Teemu Piippo <teemu@hecknology.net>
parents: 55
diff changeset
112 this->setMatrix("model", newModelMatrix);
f99d52b1646b grid snapping now also works with transformed grids
Teemu Piippo <teemu@hecknology.net>
parents: 55
diff changeset
113 }
f99d52b1646b grid snapping now also works with transformed grids
Teemu Piippo <teemu@hecknology.net>
parents: 55
diff changeset
114
f99d52b1646b grid snapping now also works with transformed grids
Teemu Piippo <teemu@hecknology.net>
parents: 55
diff changeset
115 void GridProgram::setGridMatrix(const glm::mat4& newGridMatrix)
f99d52b1646b grid snapping now also works with transformed grids
Teemu Piippo <teemu@hecknology.net>
parents: 55
diff changeset
116 {
f99d52b1646b grid snapping now also works with transformed grids
Teemu Piippo <teemu@hecknology.net>
parents: 55
diff changeset
117 this->setMatrix("grid", newGridMatrix);
f99d52b1646b grid snapping now also works with transformed grids
Teemu Piippo <teemu@hecknology.net>
parents: 55
diff changeset
118 }
f99d52b1646b grid snapping now also works with transformed grids
Teemu Piippo <teemu@hecknology.net>
parents: 55
diff changeset
119
f99d52b1646b grid snapping now also works with transformed grids
Teemu Piippo <teemu@hecknology.net>
parents: 55
diff changeset
120 void GridProgram::setMatrix(const char* name, const glm::mat4& matrix)
f99d52b1646b grid snapping now also works with transformed grids
Teemu Piippo <teemu@hecknology.net>
parents: 55
diff changeset
121 {
53
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
122 Q_ASSERT(this->isInitialized);
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
123 this->program->bind();
64
f99d52b1646b grid snapping now also works with transformed grids
Teemu Piippo <teemu@hecknology.net>
parents: 55
diff changeset
124 this->program->setUniformMatrix(name, matrix);
53
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
125 this->program->release();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
126 this->checkForGLErrors();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
127 }
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
128
55
cb81ecb5fb23 grid stuff
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
129 void GridProgram::setGridColor(const QColor& newGridColor)
cb81ecb5fb23 grid stuff
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
130 {
cb81ecb5fb23 grid stuff
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
131 const glm::vec4 vec = gl::colorToVector4(newGridColor);
cb81ecb5fb23 grid stuff
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
132 if (this->isInitialized)
cb81ecb5fb23 grid stuff
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
133 {
cb81ecb5fb23 grid stuff
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
134 this->program->bind();
cb81ecb5fb23 grid stuff
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
135 this->program->setUniformVector("gridColor", vec);
cb81ecb5fb23 grid stuff
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
136 this->program->release();
cb81ecb5fb23 grid stuff
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
137 this->checkForGLErrors();
cb81ecb5fb23 grid stuff
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
138 }
cb81ecb5fb23 grid stuff
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
139 else
cb81ecb5fb23 grid stuff
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
140 {
cb81ecb5fb23 grid stuff
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
141 this->gridColor = vec;
cb81ecb5fb23 grid stuff
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
142 }
cb81ecb5fb23 grid stuff
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
143 }
cb81ecb5fb23 grid stuff
Teemu Piippo <teemu@hecknology.net>
parents: 54
diff changeset
144
53
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
145 void GridProgram::draw()
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
146 {
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
147 this->program->bind();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
148 this->vertexArrayObject.bind();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
149 glDrawArrays(GL_QUADS, 0, countof(data));
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
150 this->vertexArrayObject.release();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
151 this->program->release();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
152 this->checkForGLErrors();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
153 }
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
154
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
155 void GridProgram::teardown()
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
156 {
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
157 this->vertexArrayObject.destroy();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
158 this->buffer.destroy();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
159 this->program.reset();
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
160 }
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
161
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
162 void GridProgram::checkForGLErrors()
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
163 {
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
164 gl::checkForGLErrors(qobject_cast<QWidget*>(this->parent()));
3af627f7a40f added grid program
Teemu Piippo <teemu@hecknology.net>
parents:
diff changeset
165 }

mercurial