1 /**
2  * @file
3  * @brief PNG and texture loading functionality
4 **/
5 
6 #pragma once
7 
8 #include "tilepick.h"
9 
10 enum MipMapOptions
11 {
12     MIPMAP_CREATE,
13     MIPMAP_NONE,
14     MIPMAP_MAX,
15 };
16 
17 // Arbitrary post-load texture processing
18 typedef bool(*tex_proc_func)(unsigned char *pixels, unsigned int w,
19     unsigned int h);
20 
21 class GenericTexture
22 {
23 public:
24     GenericTexture();
25     virtual ~GenericTexture();
26 
27     bool load_texture(const char *filename, MipMapOptions mip_opt,
28                       tex_proc_func proc = nullptr,
29                       bool force_power_of_two = true);
30     bool load_texture(unsigned char *pixels, unsigned int w, unsigned int h,
31                       MipMapOptions mip_opt, int offsetx=-1, int offsety=-1);
32     void unload_texture();
33 
width()34     unsigned int width() const { return m_width; }
height()35     unsigned int height() const { return m_height; }
36     void bind() const;
37 
orig_width()38     unsigned int orig_width() const { return m_orig_width; }
orig_height()39     unsigned int orig_height() const { return m_orig_height; }
40 
41 protected:
42     unsigned int m_handle;
43     unsigned int m_width;
44     unsigned int m_height;
45 
46     unsigned int m_orig_width;
47     unsigned int m_orig_height;
48 };
49 
50 class TilesTexture : public GenericTexture
51 {
52 public:
53     TilesTexture();
54 
55     void set_info(int max, tile_info_func *info);
56     inline const tile_info &get_info(tileidx_t idx) const;
57     inline bool get_coords(tileidx_t idx, int ofs_x, int ofs_y,
58                            float &pos_sx, float &pos_sy,
59                            float &pos_ex, float &pos_ey,
60                            float &tex_sx, float &tex_sy,
61                            float &tex_ex, float &tex_ey,
62                            bool centre = true, int ymin = -1, int ymax = -1,
63                            float tile_x = TILE_X, float tile_y = TILE_Y) const;
64 
65 protected:
66     int m_tile_max;
67     tile_info_func *m_info_func;
68 };
69 
get_info(tileidx_t idx)70 inline const tile_info &TilesTexture::get_info(tileidx_t idx) const
71 {
72     ASSERT(m_info_func);
73     return m_info_func(idx);
74 }
75 
get_coords(tileidx_t idx,int ofs_x,int ofs_y,float & pos_sx,float & pos_sy,float & pos_ex,float & pos_ey,float & tex_sx,float & tex_sy,float & tex_ex,float & tex_ey,bool centre,int ymin,int ymax,float tile_x,float tile_y)76 inline bool TilesTexture::get_coords(tileidx_t idx, int ofs_x, int ofs_y,
77                                      float &pos_sx, float &pos_sy,
78                                      float &pos_ex, float &pos_ey,
79                                      float &tex_sx, float &tex_sy,
80                                      float &tex_ex, float &tex_ey,
81                                      bool centre, int ymin, int ymax,
82                                      float tile_x, float tile_y) const
83 {
84     const tile_info &inf = get_info(idx);
85 
86     float fwidth  = m_width;
87     float fheight = m_height;
88 
89     // Centre tiles on x, but allow taller tiles to extend upwards.
90     int size_ox = centre ? TILE_X / 2 - inf.width / 2 : 0;
91     int size_oy = centre ? TILE_Y - inf.height : 0;
92 
93     int pos_sy_adjust = ofs_y + inf.offset_y + size_oy;
94     int pos_ey_adjust = pos_sy_adjust + inf.ey - inf.sy;
95 
96     int sy = pos_sy_adjust;
97     if (ymin >= 0)
98         sy = max(ymin, sy);
99 
100     int ey = pos_ey_adjust;
101     if (ymax >= 0)
102         ey = min(ymax, ey);
103 
104     // Nothing to draw.
105     if (sy >= ey)
106         return false;
107 
108     pos_sx += (ofs_x + inf.offset_x + size_ox) / tile_x;
109     pos_sy += sy / tile_y;
110     pos_ex = pos_sx + (inf.ex - inf.sx) / tile_x;
111     pos_ey = pos_sy + (ey - sy) / tile_y;
112 
113     tex_sx = inf.sx / fwidth;
114     tex_sy = (inf.sy + sy - pos_sy_adjust) / fheight;
115     tex_ex = inf.ex / fwidth;
116     tex_ey = (inf.ey + ey - pos_ey_adjust) / fheight;
117 
118     return true;
119 }
120 
121 class ImageManager
122 {
123 public:
124     ImageManager();
125     virtual ~ImageManager();
126 
127     bool load_textures(bool need_mips);
128     void unload_textures();
129     inline const tile_info &tile_def_info(tile_def tile) const;
130 
131     FixedVector<TilesTexture, TEX_MAX> m_textures;
132 };
133 
134 // TODO: This function should be moved elsewhere (where?) and called by
135 // the ImageManager.
tile_def_info(tile_def tile)136 inline const tile_info &ImageManager::tile_def_info(tile_def tile) const
137 {
138     const auto tex_id = get_tile_texture(tile.tile);
139     return m_textures[tex_id].get_info(tile.tile);
140 }
141