summaryrefslogtreecommitdiffstats
path: root/dev/MinGfx/src/shader_program.h
blob: 2bf5f874d337df69609c1f4cad10bc8cb3b7494c (plain) (blame)
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
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
/*
 This file is part of the MinGfx Project.
 
 Copyright (c) 2017,2018 Regents of the University of Minnesota.
 All Rights Reserved.
 
 Original Author(s) of this File:
	Dan Keefe, 2018, University of Minnesota
	
 Author(s) of Significant Updates/Modifications to the File:
	...
 */

#ifndef SRC_SHADERPROGRAM_H_
#define SRC_SHADERPROGRAM_H_

#include "color.h"
#include "matrix4.h"
#include "opengl_headers.h"
#include "point2.h"
#include "point3.h"
#include "texture2d.h"
#include "vector2.h"
#include "vector3.h"

#include <string>
#include <map>

namespace mingfx {

/** A wrapper around GLSL shader programs.  This class supports loading vertex
 and fragment shaders from files or strings, compiling them, and then linking
 them into a shader program.  Uniform variables within the shader programs can 
 be set in order to pass parameters from C++ code into the shader program.
 Textures can also be bound to the shader.  Example usage:
 ~~~
 
 ShaderProgram shader_prog;
 
 void MyGraphicsApp::InitOpenGL() {
    shader_prog.AddVertexShaderFromFile(Platform::findFile("my_shader.vert", searchPath));
    shader_prog.AddFragmentShaderFromFile(Platform::findFile("my_shader.frag", searchPath));
    shader_prog.LinkProgram();
 }
 
 void MyGraphicsApp::DrawUsingOpenGL() {
     // Activate the shader program
     shader_prog.UseProgram();
     
     // Pass uniforms and textures from C++ to the GPU Shader Program
     shader_prog.SetUniform("ModelMatrix", modelMat);
     shader_prog.SetUniform("ViewMatrix", viewMat);
     shader_prog.SetUniform("ProjectionMatrix", projMat);
     shader_prog.SetUniform("LightPosition", Point3(2,2,2));
     shader_prog.BindTexture("SurfaceTexture", my_tex);
 
     // Draw whatever geometry you want now
     mesh1.Draw();
     mesh2.Draw();
 
     // Deactivate the shader program
     shader_prog.StopProgram();
 }
 ~~~
 */
class ShaderProgram {
public:
    /// Creates an empty ShaderProgram object.
    ShaderProgram();
    
    virtual ~ShaderProgram();
    
    
    // ---- These should be called during startup (e.g., in InitOpenGL()) ----
    
    /// Call during initialization but after the OpenGL context has been created
    /// (e.g., inside InitOpenGL()).  This loads the shader from  the file and
    /// compiles it.  An error will be printed to stderr if there are any
    /// compilation errors.
    bool AddVertexShaderFromFile(const std::string &file);

    /// This loads and compiles a shader from a string. An error will be printed
    /// to stderr if there are any compilation errors.
    bool AddVertexShaderFromSource(const std::string &code);
    
    /// Call during initialization but after the OpenGL context has been created
    /// (e.g., inside InitOpenGL()).  This loads the shader from  the file and
    /// compiles it.  An error will be printed to stderr if there are any
    /// compilation errors.
    bool AddFragmentShaderFromFile(const std::string &file);
    
    /// This loads and compiles a shader from a string. An error will be printed
    /// to stderr if there are any compilation errors.
    bool AddFragmentShaderFromSource(const std::string &code);
    
    /// Call this after adding vertex and fragment shaders in order to link them
    /// together to create the full shader program.  An error will be printed to
    /// stderr if there are any linking errors.
    bool LinkProgram();
    

    
    // ---- These should be called during rendering (e.g., in DrawUsingOpenGL()) ----

    /// Call this first to make the shader program active, then call SetUniform() to
    /// pass data from your C++ program into the shader code via the named uniform
    /// variables that appear in the code.  Then render whatever geometry you wish
    /// with your own glDrawArrays() call(s).  Finally, call StopProgram() to turn
    /// off the shader program.
    void UseProgram();
    
    // Set Uniform Variables in the Shader
    
    // MinGfx types
    
    /// Passes the x,y values of point p to the shader program and stores the
    /// result in the shader variable named name, which should be of type vec2.
    void SetUniform(const std::string &name, const Point2 &p);

    /// Passes the x,y values of vector v to the shader program and stores the
    /// result in the shader variable named name, which should be of type vec2.
    void SetUniform(const std::string &name, const Vector2 &v);

    /// Passes the x,y,z,1 values of point p to the shader program and stores the
    /// result in the shader variable named name, which should be of type vec4.
    void SetUniform(const std::string &name, const Point3 &p);

    /// Passes the x,y,z,0 values of vector v to the shader program and stores the
    /// result in the shader variable named name, which should be of type vec4.
    void SetUniform(const std::string &name, const Vector3 &v);

    /// Passes the column-major 16 float values of matrix m to the shader program
    /// and stores the result in the shader variable named name, which should be of type mat4.
    void SetUniform(const std::string &name, const Matrix4 &m);
    
    /// Passes the r,g,b,a values of color c to the shader program and stores the
    /// result in the shader variable named name, which should be of type vec4.
    void SetUniform(const std::string &name, const Color &c);
    
    
    // built-in types
    
    /// Passes the int to the shader program and stores the result in the shader
    /// variable named name, which should be of type int.
    void SetUniform(const std::string &name, int i);

    /// Passes the unsigned int to the shader program and stores the result in the shader
    /// variable named name, which should be of type uint.
    void SetUniform(const std::string &name, unsigned int ui);
    
    /// Passes the float to the shader program and stores the result in the shader
    /// variable named name, which should be of type float.
    void SetUniform(const std::string &name, float f);

    
    // built-in types (arrays)
    
    /// Passes an array of count ints to the shader program and stores the result
    /// in the shader variable named name, which should be of type int name[count].
    void SetUniformArray1(const std::string &name, int *i, int count);

    /// Passes an array of count unsigned ints to the shader program and stores the result
    /// in the shader variable named name, which should be of type uint name[count].
    void SetUniformArray1(const std::string &name, unsigned int *ui, int count);

    /// Passes an array of count floats to the shader program and stores the result
    /// in the shader variable named name, which should be of type float name[count].
    void SetUniformArray1(const std::string &name, float *f, int count);

    
    /// Passes an array of count 2D int arrays to the shader program and stores the result
    /// in the shader variable named name, which should be of type ivec2 name[count].
    void SetUniformArray2(const std::string &name, int *i, int count);

    /// Passes an array of count 2D unsigned int arrays to the shader program and stores the result
    /// in the shader variable named name, which should be of type uivec2 name[count].
    void SetUniformArray2(const std::string &name, unsigned int *ui, int count);

    /// Passes an array of count 2D float arrays to the shader program and stores the result
    /// in the shader variable named name, which should be of type vec2 name[count].
    void SetUniformArray2(const std::string &name, float *f, int count);

    
    /// Passes an array of count 3D int arrays to the shader program and stores the result
    /// in the shader variable named name, which should be of type ivec3 name[count].
    void SetUniformArray3(const std::string &name, int *i, int count);
    
    /// Passes an array of count 3D unsigned int arrays to the shader program and stores the result
    /// in the shader variable named name, which should be of type uivec3 name[count].
    void SetUniformArray3(const std::string &name, unsigned int *ui, int count);

    /// Passes an array of count 3D float arrays to the shader program and stores the result
    /// in the shader variable named name, which should be of type vec3 name[count].
    void SetUniformArray3(const std::string &name, float *f, int count);

    
    /// Passes an array of count 4D int arrays to the shader program and stores the result
    /// in the shader variable named name, which should be of type ivec4 name[count].
    void SetUniformArray4(const std::string &name, int *i, int count);
    
    /// Passes an array of count 4D unsigned int arrays to the shader program and stores the result
    /// in the shader variable named name, which should be of type uivec4 name[count].
    void SetUniformArray4(const std::string &name, unsigned int *ui, int count);
    
    /// Passes an array of count 4D float arrays to the shader program and stores the result
    /// in the shader variable named name, which should be of type vec4 name[count].
    void SetUniformArray4(const std::string &name, float *f, int count);

    
    // Set Textures (Sampler Variables in the Shader)
    
    /// Binds a Texture2D to a sampler2D in the shader program.
    /// This version automatically selects an available texture unit, i.e., one
    /// not already used by this shader program.
    void BindTexture(const std::string &name, const Texture2D &tex);
    
    /// Binds a Texture2D to a sampler2D in the shader program.
    /// This version allows you to specify the texture unit to use.
    void BindTexture(const std::string &name, const Texture2D &tex, int texUnit);
    
    
    /// Call this after rendering geometry to deactivate the shader.
    void StopProgram();

    /// Returns true if the shader program has been successfully compiled and linked.
    bool initialized();
    
private:
    GLuint vertexShader_;
    GLuint fragmentShader_;
    GLuint program_;
    std::map<std::string, int> texBindings_;
};
    
    
} // end namespace

#endif