e92e5f152582258af9b0c73d59713a68f1be8764
[vg.git] / src / vg / 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 #include "vg/vg.h"
6 #include "vg/vg_log.h"
7
8 #define VG_TEXTURE_NO_MIP 0x1
9 #define VG_TEXTURE_REPEAT 0x2
10 #define VG_TEXTURE_CLAMP 0x4
11 #define VG_TEXTURE_NEAREST 0x8
12 #define VG_TEXTURE_ALLOCATED_INTERNAL 0x10
13
14 #define QOI_IMPLEMENTATION
15 #define QOI_MALLOC vg_alloc
16 #define QOI_FREE vg_free
17
18 #include "phoboslab/qoi.h"
19
20 struct vg_tex2d
21 {
22 const char *path;
23 u32 flags;
24 GLuint name;
25 };
26
27 struct vg_sprite
28 {
29 v4f uv_xywh;
30 };
31
32 static void vg_tex2d_bind( vg_tex2d *tex, u32 id )
33 {
34 if( !(tex->flags & VG_TEXTURE_ALLOCATED_INTERNAL) )
35 {
36 vg_error( "Tried to use '%s' while unloaded!\n", tex->path );
37 return;
38 }
39
40 glActiveTexture( GL_TEXTURE0 + id );
41 glBindTexture( GL_TEXTURE_2D, tex->name );
42 }
43
44 static inline void vg_tex2d_mipmap(void)
45 {
46 glGenerateMipmap( GL_TEXTURE_2D );
47 }
48
49 static inline void vg_tex2d_linear(void)
50 {
51 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
52 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
53 }
54
55 static inline void vg_tex2d_nearest(void)
56 {
57 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST );
58 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST );
59 }
60
61 static inline void vg_tex2d_linear_mipmap(void)
62 {
63 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
64 GL_LINEAR_MIPMAP_LINEAR );
65 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
66 }
67
68 static inline void vg_tex2d_repeat(void)
69 {
70 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
71 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
72 }
73
74 static inline void vg_tex2d_clamp(void)
75 {
76 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE );
77 glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE );
78 }
79
80 static GLuint vg_tex2d_rgba( const char *path )
81 {
82 i64 length;
83 u8 *src_data = vg_asset_read_s( path, &length );
84
85 GLuint texture_name;
86 glGenTextures( 1, &texture_name );
87 glBindTexture( GL_TEXTURE_2D, texture_name );
88
89 if( src_data )
90 {
91 qoi_desc info;
92 u8 *tex_buffer = qoi_decode( src_data, length, &info, 4 );
93
94 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, info.width, info.height,
95 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_buffer );
96
97 vg_free( tex_buffer );
98 vg_free( src_data );
99 }
100 else
101 {
102 u32 tex_err[4] =
103 {
104 0xffff00ff,
105 0xff000000,
106 0xff000000,
107 0xffff00ff
108 };
109
110 vg_error( "Loading texture failed (%s)\n", path );
111 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 2, 2,
112 0, GL_RGBA, GL_UNSIGNED_BYTE, tex_err );
113 }
114
115 return texture_name;
116 }
117
118 static void vg_tex2d_init( vg_tex2d *textures[], int num )
119 {
120 for( int i=0; i<num; i ++ )
121 {
122 vg_tex2d *tex = textures[i];
123 tex->name = vg_tex2d_rgba( tex->path );
124 if( !(tex->flags & VG_TEXTURE_NO_MIP) )
125 vg_tex2d_mipmap();
126
127 if( tex->flags & VG_TEXTURE_NEAREST )
128 {
129 if( tex->flags & VG_TEXTURE_NO_MIP )
130 vg_error( "Invalid texture settings\n" );
131 else
132 vg_tex2d_nearest();
133 }
134 else
135 {
136 if( tex->flags & VG_TEXTURE_NO_MIP )
137 vg_tex2d_linear();
138 else
139 vg_tex2d_linear_mipmap();
140 }
141
142 if( tex->flags & VG_TEXTURE_CLAMP )
143 vg_tex2d_clamp();
144 else
145 vg_tex2d_repeat();
146
147 tex->flags |= VG_TEXTURE_ALLOCATED_INTERNAL;
148 }
149 }
150
151 static void vg_tex2d_free( vg_tex2d *textures[], int num )
152 {
153 for( int i = 0; i < num; i ++ )
154 {
155 glDeleteTextures( 1, &textures[i]->name );
156 }
157 }
158
159 #endif /* VG_TEX_H */