1 ///////////////////////////////////////////////////////////////////////////////
2 //            Copyright (C) 2004-2011 by The Allacrost Project
3 //            Copyright (C) 2012-2016 by Bertram (Valyria Tear)
4 //                         All Rights Reserved
5 //
6 // This code is licensed under the GNU GPL version 2. It is free software
7 // and you may modify it and/or redistribute it under the terms of this license.
8 // See http://www.gnu.org/copyleft/gpl.html for details.
9 ///////////////////////////////////////////////////////////////////////////////
10 
11 /** ****************************************************************************
12 *** \file    image_base.h
13 *** \author  Tyler Olsen, roots@allacrost.org
14 *** \author  Yohann Ferreira, yohann ferreira orange fr
15 *** \brief   Header file for image base classes
16 ***
17 *** This file contains several classes that represent various types of images
18 *** and image data manipulated by the video engine. All of these classes are
19 *** embedded in the private_video namespace, and thus are of no concern to
20 *** those who simply wish to use the video engine API. Below is a list and
21 *** short description of all the classes represented defined in this header:
22 ***
23 *** - <b>ImageMemory</b> is a class used for loading and manipulating raw
24 *** image data stored in a system side buffer (ie not in texture memory)
25 ***
26 *** - <b>BaseTexture</b> describes a sub-rectangle contained within a
27 *** texture sheet. In other words, it can essentially be viewed as a pointer
28 *** to an image's location in texture memory. It is an abstract class.
29 ***
30 *** - <b>ImageTexture</b> derives from BaseTexture and adds a filename
31 *** and tag information to the member data. This is used to internally
32 *** represent an image that has been loaded from a file and any special
33 *** properties of that image data.
34 ***
35 *** \note There are more derived classes from this set in other areas of the
36 *** code. In particular, there is a TextTexture and TextElement class
37 *** defined in the text.h header file.
38 *** ***************************************************************************/
39 
40 #ifndef __IMAGE_BASE_HEADER__
41 #define __IMAGE_BASE_HEADER__
42 
43 #include "color.h"
44 #include "texture.h"
45 
46 #include <string>
47 #include <vector>
48 
49 namespace vt_video
50 {
51 
52 namespace private_video
53 {
54 
55 /** ****************************************************************************
56 *** \brief A wrapper around an image buffer in system memory
57 ***
58 *** This class is used to pass image texture data between the CPU and GPU.
59 *** There are also several routines for performing manipulations on the raw
60 *** image data. This class may also be used as a temporary holder for pixel
61 *** data.
62 ***
63 *** \note All of the members of this class are public, so you must be careful
64 *** not to assign them to an incorrect value.
65 ***
66 *** \todo Write copy constructor and copy assignment operator to avoid double
67 *** memory frees
68 *** ***************************************************************************/
69 class ImageMemory
70 {
71 public:
72     ImageMemory();
73     explicit ImageMemory(const SDL_Surface* surface);
74 
~ImageMemory()75     ~ImageMemory()
76     {}
77 
GetWidth()78     size_t GetWidth() const {
79         return _width;
80     }
81 
GetHeight()82     size_t GetHeight() const {
83         return _height;
84     }
85 
GetSize2D()86     size_t GetSize2D() const {
87         return _width * _height;
88     }
89 
GetBytesPerPixel()90     size_t GetBytesPerPixel() const {
91         return _rgb_format ? 3 : 4;
92     }
93 
94     /** \brief Loads raw image data from a file and stores the data in the class members
95     *** \param filename The name of the image file to load.
96     *** \return True if the image was loaded successfully, false if it was not
97     **/
98     bool LoadImage(const std::string &filename);
99 
100     /** \brief Saves raw image data to a file
101     *** \param filename The full filename of the image to save in PNG format.
102     *** \return True if the image was saved successfully, false if it was not
103     **/
104     bool SaveImage(const std::string &filename);
105 
106     /** \brief Converts the image data to grayscale format
107     *** \note Calling this function when the image data is already grayscaled will create the
108     *** exact same grayscaled image, but still take CPU time to do the conversion. There is
109     *** no way
110     *** \note You can not convert from grayscale back to the original image. If you wish to
111     *** do that, you must re-load or otherwise re-create the original.
112     **/
113     void ConvertToGrayscale();
114 
115     /** \brief Converts the RGBA pixel buffer to a RGB one
116     *** \note Upon conversion, this function will also reduced the memory size pointed to
117     *** by pixels to 3/4s of its original size, since the alpha information is no longer
118     *** neeeded.
119     **/
120     void RGBAToRGB();
121 
122     /** \brief Set the class members by making a copy of a texture sheet
123     *** \param texture A pointer to the TexSheet to be copied
124     ***
125     *** This function effectively copies a texture (in video memory) to a system-side memory buffer
126     **/
127     void CopyFromTexture(TexSheet *texture);
128 
129     /** \brief Set the class members by making a copy of a texture sheet image
130     *** \param img A pointer to the image to be copied
131     ***
132     *** This function effectively copies an image (in video memory) to a system-side memory buffer
133     **/
134     void CopyFromImage(BaseTexture *img);
135 
136     /** \brief delete an image and allocate a new one of specified size
137     *** \param width_ width of the new image
138     *** \param heigt_ height of the new image
139     *** \throws std::bad_alloc when allocation failed (because std::vector can throw that)
140     *** \TODO use an enum instead of bool for better readability
141     **/
142     void Resize(size_t width, size_t height, bool is_rgb);
143 
144     //! \brief Wrapper of glGetTexImage on the image pixels.
145     void GlGetTexImage();
146 
147     //! \brief Wrapper of glTexSubImage on the image pixels at the given coordinates.
148     void GlTexSubImage(int32_t x, int32_t y);
149 
150     //! \brief Wrapper of glReadPixels on the image pixels at the given coordinates.
151     void GlReadPixels(int32_t x, int32_t y);
152 
153     //! \brief Copy a texture at given pixel coordinates.
154     void CopyFrom(const ImageMemory& src, uint32_t src_offset, uint32_t dst_bytes, uint32_t dst_offset);
155     void CopyFrom(const ImageMemory& src, uint32_t src_offset);
156 
157     //! \brief Flip the image pixels vertically.
158     void VerticalFlip();
159 
160 private:
161     //! \brief The width of the image data (in pixels)
162     size_t _width;
163 
164     //! \brief The height of the image data (in pixels)
165     size_t _height;
166 
167     //! \brief Buffer of data, usually of size width * height * 4 (RGBA, 8 bits per component)
168     std::vector<uint8_t> _pixels;
169 
170     //! \brief Set to true if the data is in RGB format, false if the data is in RGBA format.
171     bool _rgb_format;
172 }; // class ImageMemory
173 
174 
175 /** ****************************************************************************
176 *** \brief Represents the location and properties of an image in texture memory
177 ***
178 *** This class can be thought of as a pointer to the image in texture (GPU)
179 *** memory. The TextureManager singleton has a container filled with each
180 *** instance of this object (and its derivative classes), which primarily
181 *** serves to prevent the duplication of the same image data in more than one
182 *** location in texture memory.
183 ***
184 *** \note Whenever you create an instance of this class or one of its child
185 *** classes and you intend to have some piece of code use it, you MUST remember
186 *** to call AddReference() at least once, otherwise bad things can happen.
187 ***
188 *** \note Objects of this class are intended to be constructed via the new
189 *** operator. The copy constructor and copy assignment operator are kept
190 *** private because we do not wish to allow duplicate pointers to the same
191 *** texture data, as this greatly complicates the reference counting system.
192 ***
193 *** \note Although this class is not abstract, typically we do not create any
194 *** instances of it. Instead, we create instances of its derivative classes.
195 *** ***************************************************************************/
196 class BaseTexture
197 {
198     friend class VideoEngine;
199 
200 public:
201     BaseTexture();
202     BaseTexture(uint32_t width_, uint32_t height_);
203     BaseTexture(TexSheet *texture_sheet_, uint32_t width_, uint32_t height_);
204 
205     virtual ~BaseTexture();
206 
207     // ---------- Public members
208 
209     //! \brief A pointer to the texture sheet where the image is contained.
210     TexSheet *texture_sheet;
211 
212     //! \brief The image's width and height as stored in the texture sheet, in pixels
213     uint32_t width, height;
214 
215     //! \brief The coordiates of where the image is located in the texture sheet (in pixels)
216     int32_t x, y;
217 
218     /** \brief The actual uv coordinates.
219     *** This is a little redundant, but saves effort on floating point calcuations.
220     *** u1 and v1 are the upper-left UV coordinates, while u2 and v2 correspond to
221     *** the lower-right. They are expressed in the [0.0, 1.0] range.
222     **/
223     float u1, v1, u2, v2;
224 
225     //! \brief True if the image should be drawn smoothed (using GL_LINEAR)
226     bool smooth;
227 
228     /** \brief The number of times that this image is refereced by ImageDescriptors
229     *** This is used to determine when the image may be safely deleted.
230     **/
231     int32_t ref_count;
232 
233     // ---------- Public methods
234 
235     /** \brief Decrements the reference count by one
236     *** \return True if there are no more references to the image
237     **/
238     bool RemoveReference();
239 
240     //! \brief Increments the reference count by one
AddReference()241     void AddReference() {
242         ref_count++;
243     }
244 
245 private:
246     BaseTexture(const BaseTexture &copy);
247     BaseTexture &operator=(const BaseTexture &copy);
248 }; // class BaseTexture
249 
250 
251 /** ****************************************************************************
252 *** \brief Represents a single image that is loaded and stored in a texture sheet.
253 ***
254 *** This object is intended to reperesent a texture image that was created by
255 *** loading an image file. The TextureManager singleton keeps a std::map of all
256 *** ImageTexture objects created, using the concatenated filename and tags of
257 *** each object as the map key. When creating a new ImageTexture object, you
258 *** should generally do the following:
259 ***
260 *** -# First make sure that the filename + tags is not already located in the
261 ***    image map in the TextureController class
262 *** -# Invoke the class constructor if the map search found no matching entry
263 *** -# Call the TextureManager to insert the new image into a texture sheet
264 *** -# If insertion was successful, call AddReference()
265 *** -# If insertion was successful, add the new object to the TextureManager's
266 ***    image map
267 ***
268 *** \note Like its base class, this class is only intended to be created via the
269 *** new operator, and the copy constructor and copy assignment operator are kept
270 *** private to avoid complex reference management requirements.
271 *** ***************************************************************************/
272 class ImageTexture : public BaseTexture
273 {
274 public:
275     ImageTexture(const std::string &filename_, const std::string &tags_, int32_t width_, int32_t height_);
276     ImageTexture(TexSheet *texture_sheet_, const std::string &filename_, const std::string &tags_, int32_t width_, int32_t height_);
277 
278     virtual ~ImageTexture() override;
279 
280     // ---------- Public members
281 
282     /** \brief The name of the image file where this texture data was loaded from
283     *** This is stored for every image file to prevent duplicate copies of the same image file data
284     *** in multiple ImageTextures, and also in case for when the image data needs to be reloaded.
285     *** The reload case may happen when a context change happens, such a screen resolution change or
286     *** a toggle between fullscreen and windowed modes.
287     **/
288     std::string filename;
289 
290     /** \brief Retains various tags used to uniquely identify the image when certain properties are applied
291     ***
292     *** Tags should always be presented in the same order, since the tag information is used in the key
293     *** to lookup the image in the TextureManager's image map. The list of tags below is sorted from highest
294     *** priority (should be at the beginning of the tag) to lowest priority (should be at the end of the tag).
295     ***
296     *** -# \<Xrow_ROWS>: used for multi image elements. "row" is the row number of this particular element
297     ***    while "ROWS" is the total number of rows of elements in the multi image
298     *** -# \<Ycol_COLS>: used for multi image elements. "col" is the column number of this particular element
299     ***    while "COLS" is the total number of columns of elements in the multi image
300     *** -# \<G>: used to indicate that this image texture has been converted to grayscale mode
301     ***
302     *** \note Please remember to document new tags here when they are added
303     **/
304     std::string tags;
305 
306 private:
307     ImageTexture(const ImageTexture &copy);
308     ImageTexture &operator=(const ImageTexture &copy);
309 }; // class ImageTexture : public BaseTexture
310 
311 } // namespace private_video
312 
313 } // namespace vt_video
314 
315 #endif // __IMAGE_BASE_HEADER__
316