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