initial commit
[dos_imgv] / 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_UNSIGNED_BYTE                0x1401
22 #define GL_FLOAT                                0x1406
23
24 #define GL_LUMINANCE                    0x1909
25 #define GL_RGB                                  0x1907
26 #define GL_RGBA                                 0x1908
27
28 #define GL_SLUMINANCE                   0x8c46
29 #define GL_SRGB                                 0x8c40
30 #define GL_SRGB_ALPHA                   0x8c42
31
32 #define GL_RGBA32F                              0x8814
33 #define GL_RGB32F                               0x8815
34 #define GL_LUMINANCE32F                 0x8818
35
36 #define GL_TEXTURE_2D                   0x0de1
37 #define GL_TEXTURE_WRAP_S               0x2802
38 #define GL_TEXTURE_WRAP_T               0x2803
39 #define GL_TEXTURE_MAG_FILTER   0x2800
40 #define GL_TEXTURE_MIN_FILTER   0x2801
41 #define GL_LINEAR                               0x2601
42 #define GL_LINEAR_MIPMAP_LINEAR 0x2703
43 #define GL_REPEAT                               0x2901
44 #define GL_GENERATE_MIPMAP_SGIS 0x8191
45
46
47 typedef unsigned int GLenum;
48 typedef unsigned int GLuint;
49 typedef int GLint;
50 typedef int GLsizei;
51 typedef void GLvoid;
52
53 /* for the same reason I'll load GL functions dynamically */
54 #ifndef WIN32
55 typedef void (*gl_gen_textures_func)(GLsizei, GLuint*);
56 typedef void (*gl_bind_texture_func)(GLenum, GLuint);
57 typedef void (*gl_tex_parameteri_func)(GLenum, GLenum, GLint);
58 typedef void (*gl_tex_image2d_func)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*);
59 typedef void (*gl_generate_mipmap_func)(GLenum);
60 typedef GLenum (*gl_get_error_func)(void);
61 #else
62 typedef void (__stdcall *gl_gen_textures_func)(GLsizei, GLuint*);
63 typedef void (__stdcall *gl_bind_texture_func)(GLenum, GLuint);
64 typedef void (__stdcall *gl_tex_parameteri_func)(GLenum, GLenum, GLint);
65 typedef void (__stdcall *gl_tex_image2d_func)(GLenum, GLint, GLint, GLsizei, GLsizei, GLint, GLenum, GLenum, const GLvoid*);
66 typedef void (__stdcall *gl_generate_mipmap_func)(GLenum);
67 typedef GLenum (__stdcall *gl_get_error_func)(void);
68 #endif
69
70 static gl_gen_textures_func gl_gen_textures;
71 static gl_bind_texture_func gl_bind_texture;
72 static gl_tex_parameteri_func gl_tex_parameteri;
73 static gl_tex_image2d_func gl_tex_image2d;
74 static gl_generate_mipmap_func gl_generate_mipmap;
75 static gl_get_error_func gl_get_error;
76
77 static int load_glfunc(void);
78
79 unsigned int img_fmt_glfmt(enum img_fmt fmt)
80 {
81         switch(fmt) {
82         case IMG_FMT_GREY8:
83         case IMG_FMT_GREYF:
84                 return GL_LUMINANCE;
85
86         case IMG_FMT_RGB24:
87         case IMG_FMT_RGBF:
88                 return GL_RGB;
89
90         case IMG_FMT_RGBA32:
91         case IMG_FMT_RGBAF:
92                 return GL_RGBA;
93
94         default:
95                 break;
96         }
97         return 0;
98 }
99
100 unsigned int img_fmt_gltype(enum img_fmt fmt)
101 {
102         switch(fmt) {
103         case IMG_FMT_GREY8:
104         case IMG_FMT_RGB24:
105         case IMG_FMT_RGBA32:
106                 return GL_UNSIGNED_BYTE;
107
108         case IMG_FMT_GREYF:
109         case IMG_FMT_RGBF:
110         case IMG_FMT_RGBAF:
111                 return GL_FLOAT;
112
113         default:
114                 break;
115         }
116         return 0;
117 }
118
119 unsigned int img_fmt_glintfmt(enum img_fmt fmt)
120 {
121         switch(fmt) {
122         case IMG_FMT_GREY8:
123                 return GL_LUMINANCE;
124         case IMG_FMT_RGB24:
125                 return GL_RGB;
126         case IMG_FMT_RGBA32:
127                 return GL_RGBA;
128         case IMG_FMT_GREYF:
129                 return GL_LUMINANCE32F;
130         case IMG_FMT_RGBF:
131                 return GL_RGB32F;
132         case IMG_FMT_RGBAF:
133                 return GL_RGBA32F;
134         default:
135                 break;
136         }
137         return 0;
138 }
139
140 unsigned int img_fmt_glintfmt_srgb(enum img_fmt fmt)
141 {
142         switch(fmt) {
143         case IMG_FMT_GREY8:
144                 return GL_SLUMINANCE;
145         case IMG_FMT_RGB24:
146                 return GL_SRGB;
147         case IMG_FMT_RGBA32:
148                 return GL_SRGB_ALPHA;
149         case IMG_FMT_GREYF:
150                 return GL_LUMINANCE32F;
151         case IMG_FMT_RGBF:
152                 return GL_RGB32F;
153         case IMG_FMT_RGBAF:
154                 return GL_RGBA32F;
155         default:
156                 break;
157         }
158         return 0;
159 }
160
161 unsigned int img_glfmt(struct img_pixmap *img)
162 {
163         return img_fmt_glfmt(img->fmt);
164 }
165
166 unsigned int img_gltype(struct img_pixmap *img)
167 {
168         return img_fmt_gltype(img->fmt);
169 }
170
171 unsigned int img_glintfmt(struct img_pixmap *img)
172 {
173         return img_fmt_glintfmt(img->fmt);
174 }
175
176 unsigned int img_glintfmt_srgb(struct img_pixmap *img)
177 {
178         return img_fmt_glintfmt_srgb(img->fmt);
179 }
180
181 unsigned int img_gltexture(struct img_pixmap *img)
182 {
183         unsigned int tex;
184         unsigned int intfmt, fmt, type;
185
186         if(!gl_gen_textures) {
187                 if(load_glfunc() == -1) {
188                         fprintf(stderr, "imago: failed to initialize the OpenGL helpers\n");
189                         return 0;
190                 }
191         }
192
193         intfmt = img_glintfmt(img);
194         fmt = img_glfmt(img);
195         type = img_gltype(img);
196
197         gl_gen_textures(1, &tex);
198         gl_bind_texture(GL_TEXTURE_2D, tex);
199         gl_tex_parameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
200         gl_tex_parameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
201         gl_tex_parameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
202         gl_tex_parameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
203         if(!gl_generate_mipmap) {
204                 gl_tex_parameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP_SGIS, 1);
205                 gl_get_error(); /* clear errors in case SGIS_generate_mipmap is not supported */
206         }
207         gl_tex_image2d(GL_TEXTURE_2D, 0, intfmt, img->width, img->height, 0, fmt, type, img->pixels);
208         if(gl_generate_mipmap) {
209                 gl_generate_mipmap(GL_TEXTURE_2D);
210         }
211         return tex;
212 }
213
214 unsigned int img_gltexture_load(const char *fname)
215 {
216         struct img_pixmap img;
217         unsigned int tex;
218
219         img_init(&img);
220         if(img_load(&img, fname) == -1) {
221                 img_destroy(&img);
222                 return 0;
223         }
224
225         tex = img_gltexture(&img);
226         img_destroy(&img);
227         return tex;
228 }
229
230 unsigned int img_gltexture_read_file(FILE *fp)
231 {
232         struct img_pixmap img;
233         unsigned int tex;
234
235         img_init(&img);
236         if(img_read_file(&img, fp) == -1) {
237                 img_destroy(&img);
238                 return 0;
239         }
240
241         tex = img_gltexture(&img);
242         img_destroy(&img);
243         return tex;
244 }
245
246 unsigned int img_gltexture_read(struct img_io *io)
247 {
248         struct img_pixmap img;
249         unsigned int tex;
250
251         img_init(&img);
252         if(img_read(&img, io) == -1) {
253                 img_destroy(&img);
254                 return 0;
255         }
256
257         tex = img_gltexture(&img);
258         img_destroy(&img);
259         return tex;
260 }
261
262 #if defined(__unix__) || defined(__APPLE__)
263 #include <dlfcn.h>
264
265 #ifndef RTLD_DEFAULT
266 #define RTLD_DEFAULT    ((void*)0)
267 #endif
268
269 #endif
270 #ifdef WIN32
271 #include <windows.h>
272 #endif
273
274 static int load_glfunc(void)
275 {
276 #if defined(__unix__) || defined(__APPLE__)
277         gl_gen_textures = (gl_gen_textures_func)dlsym(RTLD_DEFAULT, "glGenTextures");
278         gl_bind_texture = (gl_bind_texture_func)dlsym(RTLD_DEFAULT, "glBindTexture");
279         gl_tex_parameteri = (gl_tex_parameteri_func)dlsym(RTLD_DEFAULT, "glTexParameteri");
280         gl_tex_image2d = (gl_tex_image2d_func)dlsym(RTLD_DEFAULT, "glTexImage2D");
281         gl_generate_mipmap = (gl_generate_mipmap_func)dlsym(RTLD_DEFAULT, "glGenerateMipmap");
282         gl_get_error = (gl_get_error_func)dlsym(RTLD_DEFAULT, "glGetError");
283 #endif
284
285 #ifdef WIN32
286         HANDLE dll = LoadLibrary("opengl32.dll");
287         if(dll) {
288                 gl_gen_textures = (gl_gen_textures_func)GetProcAddress(dll, "glGenTextures");
289                 gl_bind_texture = (gl_bind_texture_func)GetProcAddress(dll, "glBindTexture");
290                 gl_tex_parameteri = (gl_tex_parameteri_func)GetProcAddress(dll, "glTexParameteri");
291                 gl_tex_image2d = (gl_tex_image2d_func)GetProcAddress(dll, "glTexImage2D");
292                 gl_generate_mipmap = (gl_generate_mipmap_func)GetProcAddress(dll, "glGenerateMipmap");
293                 gl_get_error = (gl_get_error_func)GetProcAddress(dll, "glGetError");
294         }
295 #endif
296
297         return (gl_gen_textures && gl_bind_texture && gl_tex_parameteri && gl_tex_image2d && gl_get_error) ? 0 : -1;
298 }