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