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 &center, 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 &center, 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