1 module gfx.gl3.conv;
2 
3 package:
4 
5 import gfx.bindings.opengl.gl;
6 import gfx.graal.buffer : BufferUsage, IndexType;
7 import gfx.graal.format : Format;
8 import gfx.graal.image : CompSwizzle, Filter, ImageType, Swizzle, WrapMode;
9 import gfx.graal.pipeline : BlendOp, BlendFactor, CompareOp, FrontFace,
10                             PolygonMode, Primitive, ShaderStage, StencilOp;
11 
12 GLenum toGl(in BufferUsage usage) pure {
13     switch (usage) {
14     case BufferUsage.transferSrc: return GL_COPY_READ_BUFFER;
15     case BufferUsage.transferDst: return GL_COPY_WRITE_BUFFER;
16     case BufferUsage.uniform: return GL_UNIFORM_BUFFER;
17     case BufferUsage.index: return GL_ELEMENT_ARRAY_BUFFER;
18     case BufferUsage.vertex: return GL_ARRAY_BUFFER;
19     case BufferUsage.indirect: return GL_DRAW_INDIRECT_BUFFER;
20     default: return 0;
21     }
22 }
23 
24 GLenum toGlTexTarget(in ImageType type, in bool ms) pure {
25     final switch (type) {
26     case ImageType.d1:          return GL_TEXTURE_1D;
27     case ImageType.d1Array:     return GL_TEXTURE_1D_ARRAY;
28     case ImageType.d2:
29         return ms ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
30     case ImageType.d2Array:
31         return ms ? GL_TEXTURE_2D_MULTISAMPLE_ARRAY : GL_TEXTURE_2D_ARRAY;
32     case ImageType.d3:          return GL_TEXTURE_3D;
33     case ImageType.cube:        return GL_TEXTURE_CUBE_MAP;
34     case ImageType.cubeArray:   return GL_TEXTURE_CUBE_MAP_ARRAY;
35     }
36 }
37 
38 GLenum toGlImgFmt(in Format graalFormat) pure {
39     switch (graalFormat) {
40     case Format.r8_uNorm:       return GL_R8;
41     case Format.rg8_uNorm:      return GL_RG8;
42     case Format.rgba8_uNorm:    return GL_RGBA8;
43     case Format.r8_sInt:        return GL_R8I;
44     case Format.rg8_sInt:       return GL_RG8I;
45     case Format.rgba8_sInt:     return GL_RGBA8I;
46     case Format.r8_uInt:        return GL_R8UI;
47     case Format.rg8_uInt:       return GL_RG8UI;
48     case Format.rgba8_uInt:     return GL_RGBA8UI;
49     case Format.r16_uNorm:      return GL_R16;
50     case Format.rg16_uNorm:     return GL_RG16;
51     case Format.rgba16_uNorm:   return GL_RGBA16;
52     case Format.r16_sInt:       return GL_R16I;
53     case Format.rg16_sInt:      return GL_RG16I;
54     case Format.rgba16_sInt:    return GL_RGBA16I;
55     case Format.r16_uInt:       return GL_R16UI;
56     case Format.rg16_uInt:      return GL_RG16UI;
57     case Format.rgba16_uInt:    return GL_RGBA16UI;
58     case Format.d16_uNorm:      return GL_DEPTH_COMPONENT16;
59     case Format.x8d24_uNorm:    return GL_DEPTH_COMPONENT24;
60     case Format.d32_sFloat:     return GL_DEPTH_COMPONENT32F;
61     case Format.d24s8_uNorm:    return GL_DEPTH24_STENCIL8;
62     case Format.s8_uInt:        return GL_STENCIL_INDEX8;
63     default:
64         import std.format : format;
65         throw new Exception(format("Gfx-GL3: Format.%s is not supported.", graalFormat));
66     }
67 }
68 
69 GLenum toSubImgFmt(in Format graalFormat) pure {
70     switch(graalFormat) {
71     case Format.r8_uNorm:       return GL_RED;
72     case Format.rg8_uNorm:      return GL_RG;
73     case Format.rgba8_uNorm:    return GL_RGBA;
74     case Format.r8_sInt:        return GL_RED;
75     case Format.rg8_sInt:       return GL_RG;
76     case Format.rgba8_sInt:     return GL_RGBA;
77     case Format.r8_uInt:        return GL_RED;
78     case Format.rg8_uInt:       return GL_RG;
79     case Format.rgba8_uInt:     return GL_RGBA;
80     case Format.r16_uNorm:      return GL_RED;
81     case Format.rg16_uNorm:     return GL_RG;
82     case Format.rgba16_uNorm:   return GL_RGBA;
83     case Format.r16_sInt:       return GL_RED;
84     case Format.rg16_sInt:      return GL_RG;
85     case Format.rgba16_sInt:    return GL_RGBA;
86     case Format.r16_uInt:       return GL_RED;
87     case Format.rg16_uInt:      return GL_RG;
88     case Format.rgba16_uInt:    return GL_RGBA;
89     case Format.d16_uNorm:      return GL_DEPTH_COMPONENT;
90     case Format.x8d24_uNorm:    return GL_DEPTH_COMPONENT;
91     case Format.d32_sFloat:     return GL_DEPTH_COMPONENT;
92     case Format.d24s8_uNorm:    return GL_DEPTH_COMPONENT;
93     case Format.s8_uInt:        return GL_STENCIL_INDEX;
94     default:
95         import std.format : format;
96         throw new Exception(format("Gfx-GL3: Format.%s is not supported.", graalFormat));
97     }
98 }
99 
100 GLenum toSubImgType(in Format graalFormat) pure {
101     switch(graalFormat) {
102     case Format.r8_uNorm:
103     case Format.rg8_uNorm:
104     case Format.rgba8_uNorm:
105     case Format.r8_sInt:
106     case Format.rg8_sInt:
107     case Format.rgba8_sInt:
108     case Format.r8_uInt:
109     case Format.rg8_uInt:
110     case Format.rgba8_uInt:
111         return GL_UNSIGNED_BYTE;
112     case Format.r16_uNorm:
113     case Format.rg16_uNorm:
114     case Format.rgba16_uNorm:
115     case Format.r16_sInt:
116     case Format.rg16_sInt:
117     case Format.rgba16_sInt:
118     case Format.r16_uInt:
119     case Format.rg16_uInt:
120     case Format.rgba16_uInt:
121     case Format.d16_uNorm:
122         return GL_UNSIGNED_SHORT;
123     case Format.x8d24_uNorm:
124         return GL_UNSIGNED_INT;
125     case Format.d32_sFloat:
126         return GL_FLOAT;
127     case Format.d24s8_uNorm:
128         return GL_UNSIGNED_INT;
129     case Format.s8_uInt:
130         return GL_UNSIGNED_BYTE;
131     default:
132         import std.format : format;
133         throw new Exception(format("Gfx-GL3: Format.%s is not supported.", graalFormat));
134     }
135 }
136 
137 GLenum toGlMag(in Filter filter) pure {
138     final switch(filter) {
139     case Filter.nearest: return GL_NEAREST;
140     case Filter.linear: return GL_LINEAR;
141     }
142 }
143 GLenum toGlMin(in Filter filter, in Filter mipmap) pure {
144     final switch(filter) {
145     case Filter.nearest:
146         final switch (mipmap) {
147         case Filter.nearest:    return GL_NEAREST_MIPMAP_NEAREST;
148         case Filter.linear:     return GL_NEAREST_MIPMAP_LINEAR;
149         }
150     case Filter.linear:
151         final switch (mipmap) {
152         case Filter.nearest:    return GL_LINEAR_MIPMAP_NEAREST;
153         case Filter.linear:     return GL_LINEAR_MIPMAP_LINEAR;
154         }
155     }
156 }
157 GLenum toGl(in WrapMode mode) pure {
158     final switch (mode) {
159     case WrapMode.repeat:       return GL_REPEAT;
160     case WrapMode.mirrorRepeat: return GL_MIRRORED_REPEAT;
161     case WrapMode.clamp:        return GL_CLAMP_TO_EDGE;
162     case WrapMode.border:       return GL_CLAMP_TO_BORDER;
163     }
164 }
165 
166 GLenum toGl(in CompareOp op) pure {
167     final switch (op) {
168     case CompareOp.never:           return GL_NEVER;
169     case CompareOp.less:            return GL_LESS;
170     case CompareOp.equal:           return GL_EQUAL;
171     case CompareOp.lessOrEqual:     return GL_LEQUAL;
172     case CompareOp.greater:         return GL_GREATER;
173     case CompareOp.notEqual:        return GL_NOTEQUAL;
174     case CompareOp.greaterOrEqual:  return GL_GEQUAL;
175     case CompareOp.always:          return GL_ALWAYS;
176     }
177 }
178 
179 GLenum toGl(in StencilOp op) pure {
180     final switch (op) {
181     case StencilOp.keep:                return GL_KEEP;
182     case StencilOp.zero:                return GL_ZERO;
183     case StencilOp.replace:             return GL_REPLACE;
184     case StencilOp.incrementAndClamp:   return GL_INCR;
185     case StencilOp.decrementAndClamp:   return GL_DECR;
186     case StencilOp.invert:              return GL_INVERT;
187     case StencilOp.incrementAndWrap:    return GL_INCR_WRAP;
188     case StencilOp.decrementAndWrap:    return GL_DECR_WRAP;
189     }
190 }
191 
192 GLenum toGl(in ShaderStage stage) pure {
193     switch (stage) {
194     case ShaderStage.vertex:                    return GL_VERTEX_SHADER;
195     case ShaderStage.tessellationControl:       return GL_TESS_CONTROL_SHADER;
196     case ShaderStage.tessellationEvaluation:    return GL_TESS_EVALUATION_SHADER;
197     case ShaderStage.geometry:                  return GL_GEOMETRY_SHADER;
198     case ShaderStage.fragment:                  return GL_FRAGMENT_SHADER;
199     case ShaderStage.compute:                   return GL_COMPUTE_SHADER;
200     default: assert(false);
201     }
202 }
203 
204 GLenum toGl(in IndexType type) pure {
205     final switch (type) {
206     case IndexType.u16: return GL_UNSIGNED_SHORT;
207     case IndexType.u32: return GL_UNSIGNED_INT;
208     }
209 }
210 
211 GLenum toGl(in Primitive primitive) pure {
212     final switch (primitive) {
213     case Primitive.pointList:               return GL_POINTS;
214     case Primitive.lineList:                return GL_LINES;
215     case Primitive.lineStrip:               return GL_LINE_STRIP;
216     case Primitive.triangleList:            return GL_TRIANGLES;
217     case Primitive.triangleStrip:           return GL_TRIANGLE_STRIP;
218     case Primitive.triangleFan:             return GL_TRIANGLE_FAN;
219     case Primitive.lineListAdjacency:       return GL_LINES_ADJACENCY;
220     case Primitive.lineStripAdjacency:      return GL_LINE_STRIP_ADJACENCY;
221     case Primitive.triangleListAdjacency:   return GL_TRIANGLES_ADJACENCY;
222     case Primitive.triangleStripAdjacency:  return GL_TRIANGLE_STRIP_ADJACENCY;
223     case Primitive.patchList:               return GL_PATCHES;
224     }
225 }
226 
227 GLenum toGl(in FrontFace ff) pure {
228     final switch (ff) {
229     case FrontFace.ccw: return GL_CCW;
230     case FrontFace.cw:  return GL_CW;
231     }
232 }
233 
234 GLenum toGl(in PolygonMode pm) pure {
235     final switch (pm) {
236     case PolygonMode.point: return GL_POINT;
237     case PolygonMode.line:  return GL_LINE;
238     case PolygonMode.fill:  return GL_FILL;
239     }
240 }
241 
242 GLenum toGl(in BlendOp op) {
243     final switch(op) {
244         case BlendOp.add:               return GL_FUNC_ADD;
245         case BlendOp.subtract:          return GL_FUNC_SUBTRACT;
246         case BlendOp.reverseSubtract:   return GL_FUNC_REVERSE_SUBTRACT;
247         case BlendOp.min:               return GL_MIN;
248         case BlendOp.max:               return GL_MAX;
249     }
250 }
251 
252 GLenum toGl(in BlendFactor f) {
253     final switch (f) {
254         case BlendFactor.zero:                  return GL_ZERO;
255         case BlendFactor.one:                   return GL_ONE;
256         case BlendFactor.srcColor:              return GL_SRC_COLOR;
257         case BlendFactor.oneMinusSrcColor:      return GL_ONE_MINUS_SRC_COLOR;
258         case BlendFactor.dstColor:              return GL_DST_COLOR;
259         case BlendFactor.oneMinusDstColor:      return GL_ONE_MINUS_DST_COLOR;
260         case BlendFactor.srcAlpha:              return GL_SRC_ALPHA;
261         case BlendFactor.oneMinusSrcAlpha:      return GL_ONE_MINUS_SRC_ALPHA;
262         case BlendFactor.dstAlpha:              return GL_DST_ALPHA;
263         case BlendFactor.oneMinusDstAlpha:      return GL_ONE_MINUS_DST_ALPHA;
264         case BlendFactor.constantColor:         return GL_CONSTANT_COLOR;
265         case BlendFactor.oneMinusConstantColor: return GL_ONE_MINUS_CONSTANT_COLOR;
266         case BlendFactor.constantAlpha:         return GL_CONSTANT_ALPHA;
267         case BlendFactor.oneMinusConstantAlpha: return GL_ONE_MINUS_CONSTANT_ALPHA;
268         case BlendFactor.srcAlphaSaturate:      return GL_SRC_ALPHA_SATURATE;
269         case BlendFactor.src1Color:             return GL_SRC1_COLOR;
270         case BlendFactor.oneMinusSrc1Color:     return GL_ONE_MINUS_SRC1_COLOR;
271         case BlendFactor.src1Alpha:             return GL_SRC1_ALPHA;
272         case BlendFactor.oneMinusSrc1Alpha:     return GL_ONE_MINUS_SRC1_ALPHA;
273     }
274 }
275 
276 GLint toGl(in CompSwizzle cs)
277 {
278     switch (cs)
279     {
280     case CompSwizzle.zero:  return GL_ZERO;
281     case CompSwizzle.one:   return GL_ONE;
282     case CompSwizzle.r:     return GL_RED;
283     case CompSwizzle.g:     return GL_GREEN;
284     case CompSwizzle.b:     return GL_BLUE;
285     case CompSwizzle.a:     return GL_ALPHA;
286     default: assert(false);
287     }
288 }
289 
290 GLint[4] toGl(in Swizzle swizzle)
291 {
292     const GLint[4] glSw = [
293         swizzle[0] == CompSwizzle.identity ? GL_RED : toGl(swizzle[0]),
294         swizzle[1] == CompSwizzle.identity ? GL_GREEN : toGl(swizzle[1]),
295         swizzle[2] == CompSwizzle.identity ? GL_BLUE : toGl(swizzle[2]),
296         swizzle[3] == CompSwizzle.identity ? GL_ALPHA : toGl(swizzle[3]),
297     ];
298     return glSw;
299 }
300 
301 bool vertexFormatSupported(in Format f) pure {
302     import std.algorithm : canFind;
303     return supportedVertexFormats.canFind(f);
304 }
305 
306 /// Specifies the function to define the VAO vertex attribs
307 enum VAOAttribFun {
308     /// glVertexAttribPointer
309     f,
310     /// glVertexAttribIPointer
311     i,
312     /// glVertexAttribLPointer
313     d
314 }
315 
316 struct GlVertexFormat {
317     VAOAttribFun fun;
318     GLint size;
319     GLenum type;
320     GLboolean normalized;
321 }
322 
323 GlVertexFormat glVertexFormat(in Format f)
324 in {
325     assert(vertexFormatSupported(f));
326 }
327 body {
328     return glVertexFormats[cast(size_t)f];
329 }
330 
331 private:
332 
333 // TODO: support more formats (unorms, integer...)
334 
335 immutable(GlVertexFormat[]) glVertexFormats;
336 
337 immutable(Format[]) supportedVertexFormats = [
338     Format.r32_sFloat,
339     Format.rg32_sFloat,
340     Format.rgb32_sFloat,
341     Format.rgba32_sFloat,
342 ];
343 
344 shared static this() {
345     import gfx.graal.format : formatDesc, numComponents;
346     import std.algorithm : map, maxElement;
347     import std.exception : assumeUnique;
348 
349     const len = 1 + supportedVertexFormats
350             .map!(f => cast(int)f)
351             .maxElement;
352     auto vertexFormats = new GlVertexFormat[len];
353     foreach (f; supportedVertexFormats) {
354         const fd = formatDesc(f);
355         const size = numComponents(fd.surfaceType);
356         vertexFormats[cast(int)f] = GlVertexFormat(
357             VAOAttribFun.f, size, GL_FLOAT, GL_FALSE
358         );
359     }
360 
361     glVertexFormats = assumeUnique(vertexFormats);
362 }