1 /* PointerShader.cpp
2 Copyright (c) 2014 by Michael Zahniser
3
4 Endless Sky is free software: you can redistribute it and/or modify it under the
5 terms of the GNU General Public License as published by the Free Software
6 Foundation, either version 3 of the License, or (at your option) any later version.
7
8 Endless Sky is distributed in the hope that it will be useful, but WITHOUT ANY
9 WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
10 PARTICULAR PURPOSE. See the GNU General Public License for more details.
11 */
12
13 #include "PointerShader.h"
14
15 #include "Color.h"
16 #include "Point.h"
17 #include "Screen.h"
18 #include "Shader.h"
19
20 #include <stdexcept>
21
22 using namespace std;
23
24 namespace {
25 Shader shader;
26 GLint scaleI;
27 GLint centerI;
28 GLint angleI;
29 GLint sizeI;
30 GLint offsetI;
31 GLint colorI;
32
33 GLuint vao;
34 GLuint vbo;
35 }
36
37
38
Init()39 void PointerShader::Init()
40 {
41 static const char *vertexCode =
42 "// vertex pointer shader\n"
43 "uniform vec2 scale;\n"
44 "uniform vec2 center;\n"
45 "uniform vec2 angle;\n"
46 "uniform vec2 size;\n"
47 "uniform float offset;\n"
48
49 "in vec2 vert;\n"
50 "out vec2 coord;\n"
51
52 "void main() {\n"
53 " coord = vert * size.x;\n"
54 " vec2 base = center + angle * (offset - size.y * (vert.x + vert.y));\n"
55 " vec2 wing = vec2(angle.y, -angle.x) * (size.x * .5 * (vert.x - vert.y));\n"
56 " gl_Position = vec4((base + wing) * scale, 0, 1);\n"
57 "}\n";
58
59 static const char *fragmentCode =
60 "// fragment pointer shader\n"
61 "uniform vec4 color = vec4(1, 1, 1, 1);\n"
62 "uniform vec2 size;\n"
63
64 "in vec2 coord;\n"
65 "out vec4 finalColor;\n"
66
67 "void main() {\n"
68 " float height = (coord.x + coord.y) / size.x;\n"
69 " float taper = height * height * height;\n"
70 " taper *= taper * .5 * size.x;\n"
71 " float alpha = clamp(.8 * min(coord.x, coord.y) - taper, 0, 1);\n"
72 " alpha *= clamp(1.8 * (1. - height), 0, 1);\n"
73 " finalColor = color * alpha;\n"
74 "}\n";
75
76 shader = Shader(vertexCode, fragmentCode);
77 scaleI = shader.Uniform("scale");
78 centerI = shader.Uniform("center");
79 angleI = shader.Uniform("angle");
80 sizeI = shader.Uniform("size");
81 offsetI = shader.Uniform("offset");
82 colorI = shader.Uniform("color");
83
84 // Generate the vertex data for drawing sprites.
85 glGenVertexArrays(1, &vao);
86 glBindVertexArray(vao);
87
88 glGenBuffers(1, &vbo);
89 glBindBuffer(GL_ARRAY_BUFFER, vbo);
90
91 GLfloat vertexData[] = {
92 0.f, 0.f,
93 0.f, 1.f,
94 1.f, 0.f,
95 };
96 glBufferData(GL_ARRAY_BUFFER, sizeof(vertexData), vertexData, GL_STATIC_DRAW);
97
98 glEnableVertexAttribArray(shader.Attrib("vert"));
99 glVertexAttribPointer(shader.Attrib("vert"), 2, GL_FLOAT, GL_FALSE, 2 * sizeof(GLfloat), nullptr);
100
101 // unbind the VBO and VAO
102 glBindBuffer(GL_ARRAY_BUFFER, 0);
103 glBindVertexArray(0);
104 }
105
106
107
Draw(const Point & center,const Point & angle,float width,float height,float offset,const Color & color)108 void PointerShader::Draw(const Point ¢er, const Point &angle, float width, float height, float offset, const Color &color)
109 {
110 Bind();
111
112 Add(center, angle, width, height, offset, color);
113
114 Unbind();
115 }
116
117
118
Bind()119 void PointerShader::Bind()
120 {
121 if(!shader.Object())
122 throw runtime_error("PointerShader: Bind() called before Init().");
123
124 glUseProgram(shader.Object());
125 glBindVertexArray(vao);
126
127 GLfloat scale[2] = {2.f / Screen::Width(), -2.f / Screen::Height()};
128 glUniform2fv(scaleI, 1, scale);
129 }
130
131
132
Add(const Point & center,const Point & angle,float width,float height,float offset,const Color & color)133 void PointerShader::Add(const Point ¢er, const Point &angle, float width, float height, float offset, const Color &color)
134 {
135 GLfloat c[2] = {static_cast<float>(center.X()), static_cast<float>(center.Y())};
136 glUniform2fv(centerI, 1, c);
137
138 GLfloat a[2] = {static_cast<float>(angle.X()), static_cast<float>(angle.Y())};
139 glUniform2fv(angleI, 1, a);
140
141 GLfloat size[2] = {width, height};
142 glUniform2fv(sizeI, 1, size);
143
144 glUniform1f(offsetI, offset);
145
146 glUniform4fv(colorI, 1, color.Get());
147
148 glDrawArrays(GL_TRIANGLES, 0, 3);
149 }
150
151
152
Unbind()153 void PointerShader::Unbind()
154 {
155 glBindVertexArray(0);
156 glUseProgram(0);
157 }
158