1 //  SuperTuxKart - a fun racing game with go-kart
2 //  Copyright (C) 2018 SuperTuxKart-Team
3 //
4 //  This program is free software; you can redistribute it and/or
5 //  modify it under the terms of the GNU General Public License
6 //  as published by the Free Software Foundation; either version 3
7 //  of the License, or (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program; if not, write to the Free Software
16 //  Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
17 
18 #ifndef HEADER_SP_TEXTURE_HPP
19 #define HEADER_SP_TEXTURE_HPP
20 
21 #include "graphics/gl_headers.hpp"
22 #include "utils/log.hpp"
23 #include "utils/no_copy.hpp"
24 
25 #include <atomic>
26 #include <cassert>
27 #include <memory>
28 #include <string>
29 
30 #include <dimension2d.h>
31 
32 namespace irr
33 {
34     namespace video { class IImageLoader; class IImage; }
35 }
36 
37 class Material;
38 
39 using namespace irr;
40 
41 namespace SP
42 {
43 
44 class SPTexture : public NoCopy
45 {
46 private:
47     std::string m_path;
48 
49     std::string m_cache_directory;
50 
51     GLuint m_texture_name = 0;
52 
53     std::atomic_uint m_width;
54 
55     std::atomic_uint m_height;
56 
57     Material* m_material;
58 
59     const bool m_undo_srgb;
60 
61     // ------------------------------------------------------------------------
62     void squishCompressImage(uint8_t* rgba, int width, int height, int pitch,
63                              void* blocks, unsigned flags);
64     // ------------------------------------------------------------------------
65     void generateHQMipmap(void* in,
66                           const std::vector<std::pair<core::dimension2du,
67                           unsigned> >&, uint8_t* out);
68     // ------------------------------------------------------------------------
69     void generateQuickMipmap(std::shared_ptr<video::IImage> first_image,
70                              const std::vector<std::pair<core::dimension2du,
71                              unsigned> >&, uint8_t* out);
72     // ------------------------------------------------------------------------
73     std::shared_ptr<video::IImage>
74                                getImageFromPath(const std::string& path) const;
75     // ------------------------------------------------------------------------
76     std::shared_ptr<video::IImage> getMask(const core::dimension2du& s) const;
77     // ------------------------------------------------------------------------
78     void applyMask(video::IImage* texture, video::IImage* mask);
79     // ------------------------------------------------------------------------
createTransparent()80     void createTransparent()
81     {
82 #ifndef SERVER_ONLY
83         glBindTexture(GL_TEXTURE_2D, m_texture_name);
84         static uint32_t data[4] = { 0, 0, 0, 0 };
85         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0,
86 #ifdef USE_GLES2
87             GL_RGBA,
88 #else
89             GL_BGRA,
90 #endif
91             GL_UNSIGNED_BYTE, data);
92         glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0,
93 #ifdef USE_GLES2
94             GL_RGBA,
95 #else
96             GL_BGRA,
97 #endif
98             GL_UNSIGNED_BYTE, data);
99         glBindTexture(GL_TEXTURE_2D, 0);
100         m_width.store(2);
101         m_height.store(2);
102 #endif
103     }
104     // ------------------------------------------------------------------------
createWhite(bool private_init=true)105     void createWhite(bool private_init = true)
106     {
107 #ifndef SERVER_ONLY
108         glBindTexture(GL_TEXTURE_2D, m_texture_name);
109         static int32_t data[4] = { -1, -1, -1, -1 };
110         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 2, 2, 0,
111 #ifdef USE_GLES2
112             GL_RGBA,
113 #else
114             GL_BGRA,
115 #endif
116             GL_UNSIGNED_BYTE, data);
117         glTexImage2D(GL_TEXTURE_2D, 1, GL_RGBA, 1, 1, 0,
118 #ifdef USE_GLES2
119             GL_RGBA,
120 #else
121             GL_BGRA,
122 #endif
123             GL_UNSIGNED_BYTE, data);
124         glBindTexture(GL_TEXTURE_2D, 0);
125         if (private_init)
126         {
127             m_width.store(2);
128             m_height.store(2);
129         }
130         else
131         {
132             m_width.store(0);
133             m_height.store(0);
134         }
135 #endif
136     }
137     // ------------------------------------------------------------------------
138     SPTexture(bool white);
139     // ------------------------------------------------------------------------
140     bool texImage2d(std::shared_ptr<video::IImage> texture,
141         std::shared_ptr<video::IImage> mipmaps);
142     // ------------------------------------------------------------------------
143     bool compressedTexImage2d(std::shared_ptr<video::IImage> texture,
144                               const std::vector<std::pair<core::dimension2du,
145                               unsigned> >& mipmap_sizes);
146     // ------------------------------------------------------------------------
147     bool saveCompressedTexture(std::shared_ptr<video::IImage> texture,
148                               const std::vector<std::pair<core::dimension2du,
149                               unsigned> >& sizes,
150                               const std::string& cache_location);
151     // ------------------------------------------------------------------------
152     std::vector<std::pair<core::dimension2du, unsigned> >
153                        compressTexture(std::shared_ptr<video::IImage> texture);
154     // ------------------------------------------------------------------------
155     bool useTextureCache(const std::string& full_path, std::string* cache_loc);
156     // ------------------------------------------------------------------------
157     std::shared_ptr<video::IImage> getTextureCache(const std::string& path,
158         std::vector<std::pair<core::dimension2du, unsigned> >* sizes);
159 
160 public:
161     // ------------------------------------------------------------------------
getWhiteTexture()162     static std::shared_ptr<SPTexture> getWhiteTexture()
163     {
164         SPTexture* tex = new SPTexture(true/*white*/);
165         tex->m_path = "unicolor_white";
166         return std::shared_ptr<SPTexture>(tex);
167     }
168     // ------------------------------------------------------------------------
getTransparentTexture()169     static std::shared_ptr<SPTexture> getTransparentTexture()
170     {
171         SPTexture* tex = new SPTexture(false/*white*/);
172         return std::shared_ptr<SPTexture>(tex);
173     }
174     // ------------------------------------------------------------------------
175     SPTexture(const std::string& path, Material* m, bool undo_srgb,
176               const std::string& container_id);
177     // ------------------------------------------------------------------------
178     ~SPTexture();
179     // ------------------------------------------------------------------------
getPath() const180     const std::string& getPath() const                       { return m_path; }
181     // ------------------------------------------------------------------------
182     std::shared_ptr<video::IImage> getTextureImage() const;
183     // ------------------------------------------------------------------------
getOpenGLTextureName() const184     GLuint getOpenGLTextureName() const              { return m_texture_name; }
185     // ------------------------------------------------------------------------
initialized() const186     bool initialized() const
187                         { return m_width.load() != 0 && m_height.load() != 0; }
188     // ------------------------------------------------------------------------
getWidth() const189     unsigned getWidth() const                        { return m_width.load(); }
190     // ------------------------------------------------------------------------
getHeight() const191     unsigned getHeight() const                      { return m_height.load(); }
192     // ------------------------------------------------------------------------
193     bool threadedLoad();
194 
195 
196 };
197 
198 }
199 
200 #endif
201