1 /* Copyright (C) 2017 Wildfire Games.
2  * This file is part of 0 A.D.
3  *
4  * 0 A.D. is free software: you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation, either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * 0 A.D. is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with 0 A.D.  If not, see <http://www.gnu.org/licenses/>.
16  */
17 
18 #ifndef INCLUDED_SHADERPROGRAM
19 #define INCLUDED_SHADERPROGRAM
20 
21 #include "graphics/ShaderProgramPtr.h"
22 #include "graphics/Texture.h"
23 #include "lib/ogl.h"
24 #include "lib/file/vfs/vfs_path.h"
25 #include "lib/res/handle.h"
26 
27 #include <map>
28 
29 struct CColor;
30 class CMatrix3D;
31 class CVector3D;
32 class CShaderDefines;
33 class CStrIntern;
34 
35 // Vertex data stream flags
36 enum
37 {
38 	STREAM_POS = (1 << 0),
39 	STREAM_NORMAL = (1 << 1),
40 	STREAM_COLOR = (1 << 2),
41 	STREAM_UV0 = (1 << 3),
42 	STREAM_UV1 = (1 << 4),
43 	STREAM_UV2 = (1 << 5),
44 	STREAM_UV3 = (1 << 6),
45 	STREAM_POSTOUV0 = (1 << 7),
46 	STREAM_POSTOUV1 = (1 << 8),
47 	STREAM_POSTOUV2 = (1 << 9),
48 	STREAM_POSTOUV3 = (1 << 10)
49 };
50 
51 /**
52  * A compiled vertex+fragment shader program.
53  * The implementation may use GL_ARB_{vertex,fragment}_program (ARB assembly syntax)
54  * or GL_ARB_{vertex,fragment}_shader (GLSL), or may use hard-coded fixed-function
55  * multitexturing setup code; the difference is hidden from the caller.
56  *
57  * Texture/uniform IDs are typically strings, corresponding to the names defined in
58  * the shader .xml file. Alternatively (and more efficiently, if used very frequently),
59  * call GetTextureBinding/GetUniformBinding and pass its return value as the ID.
60  * Setting uniforms that the shader .xml doesn't support is harmless.
61  *
62  * For a high-level overview of shaders and materials, see
63  * http://trac.wildfiregames.com/wiki/MaterialSystem
64  */
65 class CShaderProgram
66 {
67 	NONCOPYABLE(CShaderProgram);
68 
69 public:
70 	typedef CStrIntern attrib_id_t;
71 	typedef CStrIntern texture_id_t;
72 	typedef CStrIntern uniform_id_t;
73 	typedef std::pair<int, GLenum> frag_index_pair_t;
74 
75 	/**
76 	 * Construct based on ARB vertex/fragment program files.
77 	 */
78 	static CShaderProgram* ConstructARB(const VfsPath& vertexFile, const VfsPath& fragmentFile,
79 		const CShaderDefines& defines,
80 		const std::map<CStrIntern, int>& vertexIndexes, const std::map<CStrIntern, frag_index_pair_t>& fragmentIndexes,
81 		int streamflags);
82 
83 	/**
84 	 * Construct based on GLSL vertex/fragment shader files.
85 	 */
86 	static CShaderProgram* ConstructGLSL(const VfsPath& vertexFile, const VfsPath& fragmentFile,
87 		const CShaderDefines& defines,
88 		const std::map<CStrIntern, int>& vertexAttribs,
89 		int streamflags);
90 
91 	/**
92 	 * Construct an instance of a pre-defined fixed-function pipeline setup.
93 	 */
94 	static CShaderProgram* ConstructFFP(const std::string& id, const CShaderDefines& defines);
95 
96 	/**
97 	 * Represents a uniform attribute or texture binding.
98 	 * For uniforms:
99 	 *  - ARB shaders store vertex location in 'first', fragment location in 'second'.
100 	 *  - GLSL shaders store uniform location in 'first', data type in 'second'.
101 	 *  - FFP shaders store -1 in 'first', index in 'second'.
102 	 * For textures, all store texture target (e.g. GL_TEXTURE_2D) in 'first', texture unit in 'second'.
103 	 * Non-existent bindings must store -1 in both.
104 	 */
105 	struct Binding
106 	{
BindingBinding107 		Binding(int a, int b) : first(a), second(b) { }
108 
BindingBinding109 		Binding() : first(-1), second(-1) { }
110 
111 		/**
112 		 * Returns whether this uniform attribute is active in the shader.
113 		 * If not then there's no point calling Uniform() to set its value.
114 		 */
ActiveBinding115 		bool Active() { return first != -1 || second != -1; }
116 
117 		int first;
118 		int second;
119 	};
120 
~CShaderProgram()121 	virtual ~CShaderProgram() { }
122 
123 	virtual void Reload() = 0;
124 
125 	/**
126 	 * Returns whether this shader was successfully loaded.
127 	 */
128 	bool IsValid() const;
129 
130 	/**
131 	 * Binds the shader into the GL context. Call this before calling Uniform()
132 	 * or trying to render with it.
133 	 */
134 	virtual void Bind() = 0;
135 
136 	/**
137 	 * Unbinds the shader from the GL context. Call this after rendering with it.
138 	 */
139 	virtual void Unbind() = 0;
140 
141 	/**
142 	 * Returns bitset of STREAM_* value, indicating what vertex data streams the
143 	 * vertex shader needs (e.g. position, color, UV, ...).
144 	 */
145 	int GetStreamFlags() const;
146 
147 
148 	virtual Binding GetTextureBinding(texture_id_t id) = 0;
149 
150 	// Variants of texture binding:
151 	void BindTexture(texture_id_t id, CTexturePtr tex);
152 	virtual void BindTexture(texture_id_t id, Handle tex) = 0;
153 	virtual void BindTexture(texture_id_t id, GLuint tex) = 0;
154 	virtual void BindTexture(Binding id, Handle tex) = 0;
155 
156 
157 	virtual Binding GetUniformBinding(uniform_id_t id) = 0;
158 
159 	// Uniform-setting methods that subclasses must define:
160 	virtual void Uniform(Binding id, float v0, float v1, float v2, float v3) = 0;
161 	virtual void Uniform(Binding id, const CMatrix3D& v) = 0;
162 	virtual void Uniform(Binding id, size_t count, const CMatrix3D* v) = 0;
163 
164 	// Convenient uniform-setting wrappers:
165 
166 	void Uniform(Binding id, int v);
167 	void Uniform(Binding id, float v);
168 	void Uniform(Binding id, float v0, float v1);
169 	void Uniform(Binding id, const CVector3D& v);
170 	void Uniform(Binding id, const CColor& v);
171 
172 	void Uniform(uniform_id_t id, int v);
173 	void Uniform(uniform_id_t id, float v);
174 	void Uniform(uniform_id_t id, float v0, float v1);
175 	void Uniform(uniform_id_t id, const CVector3D& v);
176 	void Uniform(uniform_id_t id, const CColor& v);
177 	void Uniform(uniform_id_t id, float v0, float v1, float v2, float v3);
178 	void Uniform(uniform_id_t id, const CMatrix3D& v);
179 	void Uniform(uniform_id_t id, size_t count, const CMatrix3D* v);
180 
181 	// Vertex attribute pointers (equivalent to glVertexPointer etc):
182 
183 	virtual void VertexPointer(GLint size, GLenum type, GLsizei stride, const void* pointer);
184 	virtual void NormalPointer(GLenum type, GLsizei stride, const void* pointer);
185 	virtual void ColorPointer(GLint size, GLenum type, GLsizei stride, const void* pointer);
186 	virtual void TexCoordPointer(GLenum texture, GLint size, GLenum type, GLsizei stride, const void* pointer);
187 	virtual void VertexAttribPointer(attrib_id_t id, GLint size, GLenum type, GLboolean normalized, GLsizei stride, const void* pointer);
188 	virtual void VertexAttribIPointer(attrib_id_t id, GLint size, GLenum type, GLsizei stride, const void* pointer);
189 
190 	/**
191 	 * Checks that all the required vertex attributes have been set.
192 	 * Call this before calling glDrawArrays/glDrawElements etc to avoid potential crashes.
193 	 */
194 	void AssertPointersBound();
195 
196 protected:
197 	CShaderProgram(int streamflags);
198 
199 	bool m_IsValid;
200 	int m_StreamFlags;
201 
202 	// Non-GLSL client state handling:
203 	void BindClientStates();
204 	void UnbindClientStates();
205 	int m_ValidStreams; // which streams have been specified via VertexPointer etc since the last Bind
206 };
207 
208 #endif // INCLUDED_SHADERPROGRAM
209