msvc project: use multibyte character set (to avoid wide win32 functions)
[andemo] / libs / imago / src / imago_gl.c
1 /*
2 libimago - a multi-format image file input/output library.
3 Copyright (C) 2010-2021 John Tsiombikas <nuclear@member.fsf.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU Lesser General Public License as published
7 by the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU Lesser General Public License for more details.
14
15 You should have received a copy of the GNU Lesser General Public License
16 along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18 #include "imago2.h"
19
20 /* to avoid dependency to OpenGL, I'll define all the relevant GL macros manually */
21 #define GL_UNPACK_ALIGNMENT             0x0cf5
22
23 #define GL_UNSIGNED_BYTE                0x1401
24 #define GL_FLOAT                                0x1406
25
26 #define GL_LUMINANCE                    0x1909
27 #define GL_RGB                                  0x1907
28 #define GL_RGBA                                 0x1908
29
30 #define GL_SLUMINANCE                   0x8c46
31 #define GL_SRGB                                 0x8c40
32 #define GL_SRGB_ALPHA                   0x8c42
33
34 #define GL_RGBA32F                              0x8814
35 #define GL_RGB32F                               0x8815
36 #define GL_LUMINANCE32F                 0x8818
37
38 #define GL_TEXTURE_2D                   0x0de1
39 #define GL_TEXTURE_WRAP_S               0x2802
40 #define GL_TEXTURE_WRAP_T               0x2803
41 #define GL_TEXTURE_MAG_FILTER   0x2800
42 #define GL_TEXTURE_MIN_FILTER   0x2801
43 #define GL_LINEAR                               0x2601
44 #define GL_LINEAR_MIPMAP_LINEAR 0x2703
45 #define GL_REPEAT                               0x2901
46 #define GL_GENERATE_MIPMAP_SGIS 0x8191
47
48
49 typedef unsigned int GLenum;
50 typedef unsigned int GLuint;
51 typedef int GLint;
52 typedef int GLsizei;
53 typedef void GLvoid;
54
55 /* for the same reason I'll load GL functions dynamically */
56 #ifndef WIN32
57 typedef void (*gl_gen_textures_func)(GLsizei, GLuint*);
58 typedef void (*gl_bind_texture_func)(GLenum, GLuint);
59 typedef void (*gl_tex_parameteri_func)(GLenum, GLenum, GLint);
60 typedef void (*gl_tex_image2d_func)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*);
61 typedef void (*gl_generate_mipmap_func)(GLenum);
62 typedef GLenum (*gl_get_error_func)(void);
63 typedef void (*gl_pixel_storei_func)(GLenum, GLint);
64 #else
65 typedef void (__stdcall *gl_gen_textures_func)(GLsizei, GLuint*);
66 typedef void (__stdcall *gl_bind_texture_func)(GLenum, GLuint);
67 typedef void (__stdcall *gl_tex_parameteri_func)(GLenum, GLenum, GLint);
68 typedef void (__stdcall *gl_tex_image2d_func)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*);
69 typedef void (__stdcall *gl_generate_mipmap_func)(GLenum);
70 typedef GLenum (__stdcall *gl_get_error_func)(void);
71 typedef void (__stdcall *gl_pixel_storei_func)(GLenum, GLint);
72 #endif
73
74 static gl_gen_textures_func gl_gen_textures;
75 static gl_bind_texture_func gl_bind_texture;
76 static gl_tex_parameteri_func gl_tex_parameteri;
77 static gl_tex_image2d_func gl_tex_image2d;
78 static gl_generate_mipmap_func gl_generate_mipmap;
79 static gl_get_error_func gl_get_error;
80 static gl_pixel_storei_func gl_pixel_storei;
81
82 static int load_glfunc(void);
83
84 unsigned int img_fmt_glfmt(enum img_fmt fmt)
85 {
86         switch(fmt) {
87         case IMG_FMT_GREY8:
88         case IMG_FMT_GREYF:
89                 return GL_LUMINANCE;
90
91         case IMG_FMT_RGB24:
92         case IMG_FMT_RGBF:
93                 return GL_RGB;
94
95         case IMG_FMT_RGBA32:
96         case IMG_FMT_RGBAF:
97                 return GL_RGBA;
98
99         default:
100                 break;
101         }
102         return 0;
103 }
104
105 unsigned int img_fmt_gltype(enum img_fmt fmt)
106 {
107         switch(fmt) {
108         case IMG_FMT_GREY8:
109         case IMG_FMT_RGB24:
110         case IMG_FMT_RGBA32:
111                 return GL_UNSIGNED_BYTE;
112
113         case IMG_FMT_GREYF:
114         case IMG_FMT_RGBF:
115         case IMG_FMT_RGBAF:
116                 return GL_FLOAT;
117
118         default:
119                 break;
120         }
121         return 0;
122 }
123
124 unsigned int img_fmt_glintfmt(enum img_fmt fmt)
125 {
126         switch(fmt) {
127         case IMG_FMT_GREY8:
128                 return GL_LUMINANCE;
129         case IMG_FMT_RGB24:
130                 return GL_RGB;
131         case IMG_FMT_RGBA32:
132                 return GL_RGBA;
133         case IMG_FMT_GREYF:
134                 return GL_LUMINANCE32F;
135         case IMG_FMT_RGBF:
136                 return GL_RGB32F;
137         case IMG_FMT_RGBAF:
138                 return GL_RGBA32F;
139         default:
140                 break;
141         }
142         return 0;
143 }
144
145 unsigned int img_fmt_glintfmt_srgb(enum img_fmt fmt)
146 {
147         switch(fmt) {
148         case IMG_FMT_GREY8:
149                 return GL_SLUMINANCE;
150         case IMG_FMT_RGB24:
151                 return GL_SRGB;
152         case IMG_FMT_RGBA32:
153                 return GL_SRGB_ALPHA;
154         case IMG_FMT_GREYF:
155                 return GL_LUMINANCE32F;
156         case IMG_FMT_RGBF:
157                 return GL_RGB32F;
158         case IMG_FMT_RGBAF:
159                 return GL_RGBA32F;
160         default:
161                 break;
162         }
163         return 0;
164 }
165
166 unsigned int img_glfmt(struct img_pixmap *img)
167 {
168         return img_fmt_glfmt(img->fmt);
169 }
170
171 unsigned int img_gltype(struct img_pixmap *img)
172 {
173         return img_fmt_gltype(img->fmt);
174 }
175
176 unsigned int img_glintfmt(struct img_pixmap *img)
177 {
178         return img_fmt_glintfmt(img->fmt);
179 }
180
181 unsigned int img_glintfmt_srgb(struct img_pixmap *img)
182 {
183         return img_fmt_glintfmt_srgb(img->fmt);
184 }
185
186 unsigned int img_gltexture(struct img_pixmap *img)
187 {
188         unsigned int tex;
189         unsigned int intfmt, fmt, type;
190
191         if(!gl_gen_textures) {
192                 if(load_glfunc() == -1) {
193                         fprintf(stderr, "imago: failed to initialize the OpenGL helpers\n");
194                         return 0;
195                 }
196         }
197
198         if(img->fmt == IMG_FMT_IDX8) {
199                 struct img_pixmap rgb;
200
201                 img_init(&rgb);
202                 if(img_copy(&rgb, img) == -1 || img_convert(&rgb, IMG_FMT_RGB24)) {
203                         return 0;
204                 }
205                 tex = img_gltexture(&rgb);
206                 img_destroy(&rgb);
207                 return tex;
208         }
209
210         intfmt = img_glintfmt(img);
211         fmt = img_glfmt(img);
212         type = img_gltype(img);
213
214         gl_gen_textures(1, &tex);
215         gl_bind_texture(GL_TEXTURE_2D, tex);
216         gl_tex_parameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
217         gl_tex_parameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
218         gl_tex_parameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
219         gl_tex_parameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
220         gl_pixel_storei(GL_UNPACK_ALIGNMENT, 1);
221         if(!gl_generate_mipmap) {
222                 gl_tex_parameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, 1);
223                 gl_get_error(); /* clear errors in case SGIS_generate_mipmap is not supported */
224         }
225         gl_tex_image2d(GL_TEXTURE_2D, 0, intfmt, img->width, img->height, 0, fmt, type, img->pixels);
226         if(gl_generate_mipmap) {
227                 gl_generate_mipmap(GL_TEXTURE_2D);
228         }
229         return tex;
230 }
231
232 unsigned int img_gltexture_load(const char *fname)
233 {
234         struct img_pixmap img;
235         unsigned int tex;
236
237         img_init(&img);
238         if(img_load(&img, fname) == -1) {
239                 img_destroy(&img);
240                 return 0;
241         }
242
243         tex = img_gltexture(&img);
244         img_destroy(&img);
245         return tex;
246 }
247
248 unsigned int img_gltexture_read_file(FILE *fp)
249 {
250         struct img_pixmap img;
251         unsigned int tex;
252
253         img_init(&img);
254         if(img_read_file(&img, fp) == -1) {
255                 img_destroy(&img);
256                 return 0;
257         }
258
259         tex = img_gltexture(&img);
260         img_destroy(&img);
261         return tex;
262 }
263
264 unsigned int img_gltexture_read(struct img_io *io)
265 {
266         struct img_pixmap img;
267         unsigned int tex;
268
269         img_init(&img);
270         if(img_read(&img, io) == -1) {
271                 img_destroy(&img);
272                 return 0;
273         }
274
275         tex = img_gltexture(&img);
276         img_destroy(&img);
277         return tex;
278 }
279
280 #if defined(__unix__) || defined(__APPLE__)
281 #include <dlfcn.h>
282
283 #ifndef RTLD_DEFAULT
284 #define RTLD_DEFAULT    ((void*)0)
285 #endif
286
287 #endif
288 #ifdef _WIN32
289 #include <windows.h>
290 #endif
291
292 static int load_glfunc(void)
293 {
294 #if defined(__unix__) || defined(__APPLE__)
295         gl_gen_textures = (gl_gen_textures_func)dlsym(RTLD_DEFAULT, "glGenTextures");
296         gl_bind_texture = (gl_bind_texture_func)dlsym(RTLD_DEFAULT, "glBindTexture");
297         gl_tex_parameteri = (gl_tex_parameteri_func)dlsym(RTLD_DEFAULT, "glTexParameteri");
298         gl_tex_image2d = (gl_tex_image2d_func)dlsym(RTLD_DEFAULT, "glTexImage2D");
299         gl_generate_mipmap = (gl_generate_mipmap_func)dlsym(RTLD_DEFAULT, "glGenerateMipmap");
300         gl_get_error = (gl_get_error_func)dlsym(RTLD_DEFAULT, "glGetError");
301         gl_pixel_storei = (gl_pixel_storei_func)dlsym(RTLD_DEFAULT, "glPixelStorei");
302 #endif
303
304 #ifdef _WIN32
305         HANDLE dll = LoadLibrary("opengl32.dll");
306         if(dll) {
307                 gl_gen_textures = (gl_gen_textures_func)GetProcAddress(dll, "glGenTextures");
308                 gl_bind_texture = (gl_bind_texture_func)GetProcAddress(dll, "glBindTexture");
309                 gl_tex_parameteri = (gl_tex_parameteri_func)GetProcAddress(dll, "glTexParameteri");
310                 gl_tex_image2d = (gl_tex_image2d_func)GetProcAddress(dll, "glTexImage2D");
311                 gl_generate_mipmap = (gl_generate_mipmap_func)GetProcAddress(dll, "glGenerateMipmap");
312                 gl_get_error = (gl_get_error_func)GetProcAddress(dll, "glGetError");
313                 gl_pixel_storei = (gl_pixel_storei_func)GetProcAddress(dll, "glPixelStorei");
314         }
315 #endif
316
317         return (gl_gen_textures && gl_bind_texture && gl_tex_parameteri && gl_tex_image2d && gl_get_error && gl_pixel_storei) ? 0 : -1;
318 }