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 : Filter, ImageType, WrapMode;
9 import gfx.graal.pipeline : CompareOp, FrontFace, PolygonMode, Primitive,
10                             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 bool vertexFormatSupported(in Format f) pure {
243     import std.algorithm : canFind;
244     return supportedVertexFormats.canFind(f);
245 }
246 
247 /// Specifies the function to define the VAO vertex attribs
248 enum VAOAttribFun {
249     /// glVertexAttribPointer
250     f,
251     /// glVertexAttribIPointer
252     i,
253     /// glVertexAttribLPointer
254     d
255 }
256 
257 struct GlVertexFormat {
258     VAOAttribFun fun;
259     GLint size;
260     GLenum type;
261     GLboolean normalized;
262 }
263 
264 GlVertexFormat glVertexFormat(in Format f)
265 in {
266     assert(vertexFormatSupported(f));
267 }
268 body {
269     return glVertexFormats[cast(size_t)f];
270 }
271 
272 private:
273 
274 // TODO: support more formats (unorms, integer...)
275 
276 immutable(GlVertexFormat[]) glVertexFormats;
277 
278 immutable(Format[]) supportedVertexFormats = [
279     Format.r32_sFloat,
280     Format.rg32_sFloat,
281     Format.rgb32_sFloat,
282     Format.rgba32_sFloat,
283 ];
284 
285 shared static this() {
286     import gfx.graal.format : formatDesc, numComponents;
287     import std.algorithm : map, maxElement;
288     import std.exception : assumeUnique;
289 
290     const len = 1 + supportedVertexFormats
291             .map!(f => cast(int)f)
292             .maxElement;
293     auto vertexFormats = new GlVertexFormat[len];
294     foreach (f; supportedVertexFormats) {
295         const fd = formatDesc(f);
296         const size = numComponents(fd.surfaceType);
297         vertexFormats[cast(int)f] = GlVertexFormat(
298             VAOAttribFun.f, size, GL_FLOAT, GL_FALSE
299         );
300     }
301 
302     glVertexFormats = assumeUnique(vertexFormats);
303 }