libacfutils
A general purpose library of utility functions designed to make it easier to develop addons for the X-Plane flight simulator.
Loading...
Searching...
No Matches
lacf_gl_pic.c
1/*
2 * CDDL HEADER START
3 *
4 * This file and its contents are supplied under the terms of the
5 * Common Development and Distribution License ("CDDL"), version 1.0.
6 * You may only use this file in accordance with the terms of version
7 * 1.0 of the CDDL.
8 *
9 * A full copy of the text of the CDDL should have accompanied this
10 * source. A copy of the CDDL is also available via the Internet at
11 * http://www.illumos.org/license/CDDL.
12 *
13 * CDDL HEADER END
14*/
15/*
16 * Copyright 2023 Saso Kiselkov. All rights reserved.
17 */
18
19#include <XPLMGraphics.h>
20
21#include "acfutils/dr.h"
22#include "acfutils/geom.h"
23#include "acfutils/glew.h"
24#include "acfutils/glutils.h"
25#include "acfutils/png.h"
26#include "acfutils/shader.h"
27
29
30#define LACF_GL_PIC_CACHE_SIZE (1 << 10) /* 1 KiB */
31
33 char *path;
34 GLuint tex;
35 uint8_t *pixels;
36 int w, h;
37 double in_use;
38 glutils_cache_t *cache;
39 dr_t proj_matrix;
40 dr_t mv_matrix;
41 GLuint shader;
42};
43
44static const char *vert_shader =
45 "#version 120\n"
46 "uniform mat4 pvm;\n"
47 "attribute vec3 vtx_pos;\n"
48 "attribute vec2 vtx_tex0;\n"
49 "varying vec2 tex_coord;\n"
50 "void main() {\n"
51 " tex_coord = vtx_tex0;\n"
52 " gl_Position = pvm * vec4(vtx_pos, 1.0);\n"
53 "}\n";
54
55static const char *frag_shader =
56 "#version 120\n"
57 "uniform sampler2D tex;\n"
58 "uniform float alpha;\n"
59 "varying vec2 tex_coord;\n"
60 "void main() {\n"
61 " gl_FragColor = texture2D(tex, tex_coord);\n"
62 " gl_FragColor.a *= alpha;\n"
63 "}\n";
64
65static bool_t
66load_image(lacf_gl_pic_t *pic)
67{
68 uint8_t *buf;
69
70 ASSERT(pic != NULL);
71 ASSERT0(pic->tex);
72 ASSERT(pic->path != NULL);
73
74 buf = png_load_from_file_rgba(pic->path, &pic->w, &pic->h);
75 if (buf == NULL)
76 return (B_FALSE);
77
78 glGenTextures(1, &pic->tex);
79 ASSERT(pic->tex != 0);
80 glBindTexture(GL_TEXTURE_2D, pic->tex);
81 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
82 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
83 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, pic->w, pic->h, 0, GL_RGBA,
84 GL_UNSIGNED_BYTE, buf);
85 lacf_free(buf);
86
87 return (B_TRUE);
88}
89
98lacf_gl_pic_t *
99lacf_gl_pic_new(const char *path)
100{
101 lacf_gl_pic_t *pic = safe_calloc(1, sizeof (*pic));
102
103 ASSERT(path != NULL);
104 pic->path = safe_strdup(path);
105 fdr_find(&pic->proj_matrix, "sim/graphics/view/projection_matrix");
106 fdr_find(&pic->mv_matrix, "sim/graphics/view/modelview_matrix");
107
108 return (pic);
109}
110
119lacf_gl_pic_t *
120lacf_gl_pic_new_from_dir(const char *dirpath, const char *filename)
121{
122 char *path;
123 lacf_gl_pic_t *pic;
124
125 ASSERT(dirpath != NULL);
126 ASSERT(filename != NULL);
127 path = mkpathname(dirpath, filename, NULL);
128 pic = lacf_gl_pic_new(path);
129 lacf_free(path);
130
131 return (pic);
132}
133
138void
139lacf_gl_pic_destroy(lacf_gl_pic_t *pic)
140{
141 if (pic == NULL)
142 return;
144 free(pic->path);
145 ZERO_FREE(pic);
146}
147
156bool_t
157lacf_gl_pic_load(lacf_gl_pic_t *pic)
158{
159 ASSERT(pic != NULL);
160 if (pic->tex != 0)
161 return (B_TRUE);
162 return (load_image(pic));
163}
164
175void
176lacf_gl_pic_unload(lacf_gl_pic_t *pic)
177{
178 ASSERT(pic != NULL);
179
180 if (pic->tex != 0) {
181 glDeleteTextures(1, &pic->tex);
182 pic->tex = 0;
183 }
184 if (pic->cache != NULL) {
185 glutils_cache_destroy(pic->cache);
186 pic->cache = NULL;
187 }
188 if (pic->shader != 0) {
189 glDeleteProgram(pic->shader);
190 pic->shader = 0;
191 }
192}
193
199int
200lacf_gl_pic_get_width(lacf_gl_pic_t *pic)
201{
202 ASSERT(pic != NULL);
203 if (pic->w == 0)
204 load_image(pic);
205 return (pic->w);
206}
207
213int
214lacf_gl_pic_get_height(lacf_gl_pic_t *pic)
215{
216 ASSERT(pic != NULL);
217 if (pic->h == 0)
218 load_image(pic);
219 return (pic->h);
220}
221
227GLuint
228lacf_gl_pic_get_tex(lacf_gl_pic_t *pic)
229{
230 ASSERT(pic != NULL);
231 if (pic->tex == 0) {
232 load_image(pic);
233 }
234 return (pic->tex);
235}
236
250void
251lacf_gl_pic_draw(lacf_gl_pic_t *pic, vect2_t pos, vect2_t size,
252 float alpha)
253{
254 mat4 proj_matrix, mv_matrix, pvm;
255
256 ASSERT(pic != NULL);
257
258 VERIFY3F(dr_getvf32(&pic->proj_matrix, (float *)proj_matrix, 0, 16),
259 ==, 16);
260 VERIFY3F(dr_getvf32(&pic->mv_matrix, (float *)mv_matrix, 0, 16),
261 ==, 16);
262 glm_mat4_mul(proj_matrix, mv_matrix, pvm);
263
264 if (pic->shader == 0) {
265 pic->shader = shader_prog_from_text("lacf_gl_pic_shader",
266 vert_shader, frag_shader,
267 "vtx_pos", VTX_ATTRIB_POS,
268 "vtx_tex0", VTX_ATTRIB_TEX0, NULL);
269 ASSERT(pic->shader != 0);
270 }
271 glUseProgram(pic->shader);
272 glUniform1f(glGetUniformLocation(pic->shader, "alpha"), alpha);
273 glUniformMatrix4fv(glGetUniformLocation(pic->shader, "pvm"),
274 1, GL_FALSE, (const GLfloat *)pvm);
275 lacf_gl_pic_draw_custom(pic, pos, size, pic->shader);
276 glUseProgram(0);
277}
278
292void
293lacf_gl_pic_draw_custom(lacf_gl_pic_t *pic, vect2_t pos, vect2_t size,
294 GLuint prog)
295{
296 glutils_quads_t *quads;
297 vect2_t p[4];
298 const vect2_t t[4] = {
299 VECT2(0, 1), VECT2(0, 0), VECT2(1, 0), VECT2(1, 1)
300 };
301
302 ASSERT(pic != NULL);
303
304 if (pic->tex == 0 && !load_image(pic))
305 return;
306 if (IS_NULL_VECT(size))
307 size = VECT2(pic->w, pic->h);
308 if (pic->cache == NULL)
309 pic->cache = glutils_cache_new(LACF_GL_PIC_CACHE_SIZE);
310
311 p[0] = VECT2(pos.x, pos.y);
312 p[1] = VECT2(pos.x, pos.y + size.y);
313 p[2] = VECT2(pos.x + size.x, pos.y + size.y);
314 p[3] = VECT2(pos.x + size.x, pos.y);
315 quads = glutils_cache_get_2D_quads(pic->cache, p, t, 4);
316
317 XPLMBindTexture2d(pic->tex, 0);
318 glUniform1i(glGetUniformLocation(prog, "vtx_tex0"), 0);
319 glutils_draw_quads(quads, prog);
320 XPLMBindTexture2d(0, 0);
321}
#define VERIFY3F(x, op, y)
Definition assert.h:144
#define ASSERT(x)
Definition assert.h:208
#define ASSERT0(x)
Definition assert.h:213
void lacf_free(void *buf)
Definition core.c:49
#define dr_getvf32(__dr, __ff, __off, __num)
Definition dr.h:473
#define fdr_find(dr,...)
Definition dr.h:318
#define IS_NULL_VECT(a)
Definition geom.h:228
#define VECT2(x, y)
Definition geom.h:190
void glutils_cache_destroy(glutils_cache_t *cache)
Definition glutils.c:484
glutils_quads_t * glutils_cache_get_2D_quads(glutils_cache_t *cache, const vect2_t *p, const vect2_t *t, size_t num_pts)
Definition glutils.c:613
void glutils_draw_quads(glutils_quads_t *quads, GLint prog)
Definition glutils.c:387
glutils_cache_t * glutils_cache_new(size_t cap_bytes)
Definition glutils.c:440
char * mkpathname(const char *comp,...)
Definition helpers.c:833
GLuint lacf_gl_pic_get_tex(lacf_gl_pic_t *pic)
void lacf_gl_pic_draw_custom(lacf_gl_pic_t *pic, vect2_t pos, vect2_t size, GLuint prog)
void lacf_gl_pic_unload(lacf_gl_pic_t *pic)
bool_t lacf_gl_pic_load(lacf_gl_pic_t *pic)
lacf_gl_pic_t * lacf_gl_pic_new_from_dir(const char *dirpath, const char *filename)
lacf_gl_pic_t * lacf_gl_pic_new(const char *path)
Definition lacf_gl_pic.c:99
int lacf_gl_pic_get_width(lacf_gl_pic_t *pic)
void lacf_gl_pic_destroy(lacf_gl_pic_t *pic)
void lacf_gl_pic_draw(lacf_gl_pic_t *pic, vect2_t pos, vect2_t size, float alpha)
int lacf_gl_pic_get_height(lacf_gl_pic_t *pic)
#define ZERO_FREE(ptr)
Definition safe_alloc.h:253
static char * safe_strdup(const char *str2)
Definition safe_alloc.h:201
static void * safe_calloc(size_t nmemb, size_t size)
Definition safe_alloc.h:71