f570b11684fe367af76f8819dec2501050b5e307
[vg.git] / vg_tex.h
1 /* Copyright (C) 2021-2022 Harry Godden (hgn) - All Rights Reserved */
2 #ifndef VG_TEX_H
3 #define VG_TEX_H
4
5 #define VG_GAME
6 #include "vg/vg.h"
7 #include "vg/vg_log.h"
8
9 #define VG_TEXTURE_NO_MIP 0x1
10 #define VG_TEXTURE_REPEAT 0x2
11 #define VG_TEXTURE_CLAMP 0x4
12 #define VG_TEXTURE_NEAREST 0x8
13 #define VG_TEXTURE_ALLOCATED_INTERNAL 0x10
14
15 VG_STATIC void *vg_qoi_malloc( size_t size )
16 {
17 return vg_linear_alloc( vg_mem.scratch, size );
18 }
19
20 VG_STATIC void vg_qoi_free( void *ptr )
21 {
22
23 }
24
25 #define QOI_IMPLEMENTATION
26 #define QOI_NO_STDIO
27 #define QOI_MALLOC(sz) vg_qoi_malloc( sz )
28 #define QOI_FREE(p) vg_qoi_free( p )
29
30 #include "submodules/qoi/qoi.h"
31
32 struct vg_tex2d
33 {
34 const char *path;
35 u32 flags;
36 GLuint name;
37 };
38
39 struct vg_sprite
40 {
41 v4f uv_xywh;
42 };
43
44 VG_STATIC void vg_tex2d_bind( vg_tex2d *tex, u32 id )
45 {
46 if( !(tex->flags & VG_TEXTURE_ALLOCATED_INTERNAL) )
47 {
48 vg_error( "Tried to use '%s' while unloaded!\n", tex->path );
49 return;
50 }
51
52 glActiveTexture( GL_TEXTURE0 + id );
53 glBindTexture( GL_TEXTURE_2D, tex->name );
54 }
55
56 static inline void vg_tex2d_mipmap(void)
57 {
58 glGenerateMipmap( GL_TEXTURE_2D );
59 }
60
61 static inline void vg_tex2d_linear(void)
62 {
63 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
64 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
65 }
66
67 static inline void vg_tex2d_nearest(void)
68 {
69 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
70 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
71 }
72
73 static inline void vg_tex2d_linear_mipmap(void)
74 {
75 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
76 GL_LINEAR_MIPMAP_LINEAR );
77 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
78 }
79
80 static inline void vg_tex2d_repeat(void)
81 {
82 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
83 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
84 }
85
86 static inline void vg_tex2d_clamp(void)
87 {
88 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
89 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
90 }
91
92 VG_STATIC GLuint vg_tex2d_new(void)
93 {
94 GLuint texture_name;
95 glGenTextures( 1, &texture_name );
96 glBindTexture( GL_TEXTURE_2D, texture_name );
97
98 return texture_name;
99 }
100
101 VG_STATIC void vg_tex2d_set_error(void)
102 {
103 u32 tex_err[4] =
104 {
105 0xffff00ff,
106 0xff000000,
107 0xff000000,
108 0xffff00ff
109 };
110
111 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 2, 2,
112 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_err );
113 }
114
115 VG_STATIC void vg_tex2d_qoi( void *mem, u32 size, const char *name )
116 {
117 qoi_desc info;
118 u8 *tex_buffer = qoi_decode( mem, size, &info, 4 );
119
120 if( tex_buffer )
121 {
122 vg_info( "Texture decoded: [%u %u] %s\n",
123 info.width, info.height, name );
124
125 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, info.width, info.height,
126 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_buffer );
127
128 QOI_FREE(tex_buffer);
129 }
130 else
131 {
132 vg_error( "File size: %u\n", size );
133 vg_tex2d_set_error();
134 }
135 }
136
137 /*
138 * TODO: This blocks while we read from file
139 */
140 VG_STATIC GLuint vg_tex2d_rgba( const char *path )
141 {
142 GLuint texture_name = vg_tex2d_new();
143
144 vg_linear_clear( vg_mem.scratch );
145 u32 size;
146 void *file = vg_file_read( vg_mem.scratch, path, &size );
147
148 if( file )
149 {
150 vg_tex2d_qoi( file, size, path );
151 }
152 else
153 {
154 vg_error( "Loading texture failed (%s)\n", path );
155 vg_tex2d_set_error();
156 }
157
158 return texture_name;
159 }
160
161 VG_STATIC void vg_tex2d_init( vg_tex2d *textures[], int num )
162 {
163 for( int i=0; i<num; i ++ )
164 {
165 vg_tex2d *tex = textures[i];
166 tex->name = vg_tex2d_rgba( tex->path );
167 if( !(tex->flags & VG_TEXTURE_NO_MIP) )
168 vg_tex2d_mipmap();
169
170 if( tex->flags & VG_TEXTURE_NEAREST )
171 {
172 if( tex->flags & VG_TEXTURE_NO_MIP )
173 vg_error( "Invalid texture settings\n" );
174 else
175 vg_tex2d_nearest();
176 }
177 else
178 {
179 if( tex->flags & VG_TEXTURE_NO_MIP )
180 vg_tex2d_linear();
181 else
182 vg_tex2d_linear_mipmap();
183 }
184
185 if( tex->flags & VG_TEXTURE_CLAMP )
186 vg_tex2d_clamp();
187 else
188 vg_tex2d_repeat();
189
190 tex->flags |= VG_TEXTURE_ALLOCATED_INTERNAL;
191 }
192 }
193
194 VG_STATIC void vg_tex2d_free( vg_tex2d *textures[], int num )
195 {
196 for( int i = 0; i < num; i ++ )
197 {
198 glDeleteTextures( 1, &textures[i]->name );
199 }
200 }
201
202 #endif /* VG_TEX_H */