1 // Copyright 2014 Wouter van Oortmerssen. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 // simple rendering interface for OpenGL (ES) (that doesn't depend on its headers)
16
17 enum BlendMode {
18 BLEND_NONE = 0,
19 BLEND_ALPHA,
20 BLEND_ADD,
21 BLEND_ADDALPHA,
22 BLEND_MUL,
23 BLEND_PREMULALPHA
24 };
25
26 enum Primitive { PRIM_TRIS, PRIM_FAN, PRIM_LOOP, PRIM_POINT };
27
28 // Meant to be passed by value.
29 struct Texture {
30 uint id = 0;
31 int3 size { 0 };
32
33 Texture() = default;
TextureTexture34 Texture(int _id, const int2 &_size) : id(_id), size(int3(_size, 0)) {}
TextureTexture35 Texture(int _id, const int3 &_size) : id(_id), size(_size) {}
36 };
37
38 struct Shader {
39 uint vs = 0, ps = 0, cs = 0, program = 0;
40 int mvp_i, col_i, camera_i, light1_i, lightparams1_i, texturesize_i,
41 bones_i, pointscale_i;
42 int max_tex_defined = 0;
43
44 enum { MAX_SAMPLERS = 32 };
45
46 ~Shader();
47
48 string Compile(const char *name, const char *vscode, const char *pscode);
49 string Compile(const char *name, const char *comcode);
50 void Link(const char *name);
51 void Activate(); // Makes shader current;
52 void Set(); // Activate + sets common uniforms.
53 void SetAnim(float3x4 *bones, int num); // Optionally, after Activate().
54 void SetTextures(const vector<Texture> &textures); // Optionally, after Activate().
55 bool SetUniform(string_view name, // Optionally, after Activate().
56 const float *val,
57 int components, int elements = 1);
58 bool SetUniformMatrix(string_view name, const float *val, int components, int elements = 1);
59 bool Dump(string_view filename, bool stripnonascii);
60 };
61
62 struct Textured {
63 vector<Texture> textures;
64
GetTextured65 Texture &Get(size_t i) {
66 textures.resize(max(i + 1, textures.size()));
67 return textures[i];
68 }
69 };
70
71 struct Surface : Textured {
72 size_t numidx;
73 uint ibo;
74 string name;
75 Primitive prim;
76
77 Surface(span<int> indices, Primitive _prim = PRIM_TRIS);
78 ~Surface();
79
80 void Render(Shader *sh);
81 void WritePLY(string &s);
82 };
83
84 struct BasicVert { // common generic format: "PNTC"
85 float3 pos;
86 float3 norm;
87 float2 tc;
88 byte4 col;
89 };
90
91 struct AnimVert : BasicVert { // "PNTCWI"
92 byte4 weights;
93 byte4 indices;
94 };
95
96 struct SpriteVert { // "pT"
97 float2 pos;
98 float2 tc;
99 };
100
101 class Geometry {
102 const size_t vertsize1, vertsize2;
103 string fmt;
104 uint vbo1 = 0, vbo2 = 0, vao = 0;
105
106 public:
107 const size_t nverts;
108
109 template<typename T, typename U = float>
110 Geometry(span<T> verts1, string_view _fmt, span<U> verts2 = span<float>(),
111 size_t elem_multiple = 1)
vertsize1(sizeof (T)* elem_multiple)112 : vertsize1(sizeof(T) * elem_multiple), vertsize2(sizeof(U) * elem_multiple), fmt(_fmt),
113 nverts(verts1.size() / elem_multiple) {
114 assert(verts2.empty() || verts2.size() == verts1.size());
115 Init(verts1.data(), verts2.data());
116 }
117
118 ~Geometry();
119
120 void Init(const void *verts1, const void *verts2);
121
122 void RenderSetup();
123 void BindAsSSBO(Shader *sh, string_view name);
124 bool WritePLY(string &s, size_t nindices);
125 };
126
127 struct Mesh {
128 Geometry *geom;
129 vector<Surface *> surfs;
130 Primitive prim; // If surfs is empty, this determines how to draw the verts.
131 float pointsize = 1; // if prim == PRIM_POINT
132 int numframes = 0, numbones = 0;
133 float3x4 *mats = nullptr;
134 float curanim = 0;
135
136 Mesh(Geometry *_g, Primitive _prim = PRIM_FAN)
geomMesh137 : geom(_g), prim(_prim) {}
138 ~Mesh();
139
140 void Render(Shader *sh);
141 bool SaveAsPLY(string_view filename);
142 };
143
144 struct Light {
145 float4 pos;
146 float2 params;
147 };
148
149
150 extern void OpenGLInit(int samples);
151 extern void OpenGLCleanup();
152 extern void OpenGLFrameStart(const int2 &ssize);
153 extern void LogGLError(const char *file, int line, const char *call);
154
155 extern void Set2DMode(const int2 &ssize, bool lh, bool depthtest = false);
156 extern void Set3DMode(float fovy, float ratio, float znear, float zfar);
157 extern void Set3DOrtho(const float3 ¢er, const float3 &extends);
158 extern bool Is2DMode();
159 extern void ClearFrameBuffer(const float3 &c);
160 extern int SetBlendMode(BlendMode mode);
161 extern void SetPointSprite(float size);
162
163 extern void AppendTransform(const float4x4 &forward, const float4x4 &backward);
164
165 extern string LoadMaterialFile(string_view mfile);
166 extern string ParseMaterialFile(string_view mfile);
167 extern Shader *LookupShader(string_view name);
168 extern void ShaderShutDown();
169
170 extern void DispatchCompute(const int3 &groups);
171 extern void SetImageTexture(uint textureunit, const Texture &tex, int tf);
172 extern uint UniformBufferObject(Shader *sh, const void *data, size_t len,
173 string_view uniformblockname, bool ssbo, uint bo);
174
175 // These must correspond to the constants in color.lobster
176 enum TextureFlag {
177 TF_NONE = 0,
178 TF_CLAMP = 1,
179 TF_NOMIPMAP = 2,
180 TF_NEAREST_MAG = 4,
181 TF_NEAREST_MIN = 8,
182 TF_FLOAT = 16, // rgba32f instead of rgba8
183 TF_WRITEONLY = 32, TF_READWRITE = 64, // Default is readonly.
184 TF_CUBEMAP = 128,
185 TF_MULTISAMPLE = 256,
186 TF_SINGLE_CHANNEL = 512, // Default is RGBA.
187 TF_3D = 1024,
188 TF_BUFFER_HAS_MIPS = 2048,
189 TF_DEPTH = 4096
190 };
191
192 extern Texture CreateTexture(const uchar *buf, const int *dim, int tf = TF_NONE);
193 extern Texture CreateTextureFromFile(string_view name, int tf = TF_NONE);
194 extern Texture CreateBlankTexture(const int2 &size, const float4 &color, int tf = TF_NONE);
195 extern void DeleteTexture(Texture &id);
196 extern void SetTexture(int textureunit, const Texture &tex, int tf = TF_NONE);
197 extern uchar *ReadTexture(const Texture &tex);
198 extern int MaxTextureSize();
199 extern bool SwitchToFrameBuffer(const Texture &tex, bool depth = false, int tf = 0,
200 const Texture &resolvetex = Texture(),
201 const Texture &depthtex = Texture());
202
203 extern uchar *ReadPixels(const int2 &pos, const int2 &size);
204
205 extern uint GenBO_(uint type, size_t bytesize, const void *data);
GenBO(uint type,span<T> d)206 template <typename T> uint GenBO(uint type, span<T> d) {
207 return GenBO_(type, sizeof(T) * d.size(), d.data());
208 }
209 extern void DeleteBO(uint id);
210 extern void RenderArray(Primitive prim, Geometry *geom, uint ibo = 0, size_t tcount = 0);
211
212 template<typename T, typename U = float>
213 void RenderArraySlow(Primitive prim, span<T> vbuf1, string_view fmt,
214 span<int> ibuf = span<int>(), span<U> vbuf2 = span<float>()) {
215 Geometry geom(vbuf1, fmt, vbuf2);
216 if (ibuf.empty()) {
217 RenderArray(prim, &geom);
218 } else {
219 Surface surf(ibuf, prim);
220 RenderArray(prim, &geom, surf.ibo, ibuf.size());
221 }
222 }
223
224 struct GeometryCache {
225 Geometry *quadgeom[2] = { nullptr, nullptr };
226 Geometry *cube_geom[2] = { nullptr, nullptr };
227 uint cube_ibo[2] = { 0, 0 };
228 map<int, Geometry *> circlevbos;
229 map<pair<int, float>, pair<Geometry *, uint>> opencirclevbos;
230
231 ~GeometryCache();
232
233 void RenderUnitSquare(Shader *sh, Primitive prim, bool centered);
234 void RenderQuad(Shader *sh, Primitive prim, bool centered, const float4x4 &trans);
235 void RenderLine2D(Shader *sh, Primitive prim, const float3 &v1, const float3 &v2,
236 float thickness);
237 void RenderLine3D(Shader *sh, const float3 &v1, const float3 &v2, const float3 &campos,
238 float thickness);
239 void RenderUnitCube(Shader *sh, int inside);
240 void RenderCircle(Shader *sh, Primitive prim, int segments, float radius);
241 void RenderOpenCircle(Shader *sh, int segments, float radius, float thickness);
242 };
243
244 extern size_t AttribsSize(string_view fmt);
245
246 extern Mesh *LoadIQM(string_view filename);
247
248 extern float4x4 view2clip;
249
250 struct objecttransforms {
251 float4x4 view2object;
252 float4x4 object2view;
253
objecttransformsobjecttransforms254 objecttransforms() : view2object(1), object2view(1) {}
255 };
256
257 extern objecttransforms otransforms;
258
259 extern vector<Light> lights;
260
261 extern float4 curcolor;
262
263 extern float pointscale, custompointscale;
264
265 extern GeometryCache *geomcache;
266
267 // 2D, since this skips view2object needed for lighting.
Transform2D(const float4x4 & mat,F body)268 template<typename F> void Transform2D(const float4x4 &mat, F body) {
269 auto oldobject2view = otransforms.object2view;
270 otransforms.object2view *= mat;
271 body();
272 otransforms.object2view = oldobject2view;
273 }
274
275 extern bool VRInit();
276 extern void VRShutDown();
277