Ion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
texture.cc
Go to the documentation of this file.
1 
18 #include "ion/gfx/texture.h"
19 
20 #include <algorithm>
21 
22 #include "ion/base/enumhelper.h"
23 #include "ion/base/static_assert.h"
24 #include "ion/math/utils.h"
25 #include "ion/portgfx/glheaders.h"
26 
27 namespace ion {
28 namespace gfx {
29 
31 
36 
37 TextureBase::Face::Face(TextureBase* texture, int sub_image_changed_bit,
38  int mipmaps_changed_start_bit)
39  : sub_images_changed_(sub_image_changed_bit, false, texture),
40  sub_images_(*texture),
41  mipmaps_(mipmaps_changed_start_bit, kMipmapSlotCount, texture) {
43  for (size_t i = 0; i < kMipmapSlotCount; ++i)
44  mipmaps_.Add(ImagePtr());
45 }
46 
48 void TextureBase::Face::SetSubImage(size_t level, const math::Point2ui offset,
49  const ImagePtr& image) {
50  SetSubImage(level, math::Point3ui(offset[0], offset[1], 0), image);
51 }
52 
54 void TextureBase::Face::SetSubImage(size_t level, const math::Point3ui offset,
55  const ImagePtr& image) {
56  sub_images_.push_back(SubImage(level, offset, image));
58  sub_images_changed_.Set(false);
59  sub_images_changed_.Set(true);
60 }
61 
62 void TextureBase::Face::SetImage(size_t level, const ImagePtr& image_in,
64  if (level < kMipmapSlotCount) {
65  if (Image* img = mipmaps_.Get(level).Get())
66  img->RemoveReceiver(texture);
67  mipmaps_.Set(level, image_in);
68  if (Image* img = image_in.Get()) {
69  img->AddReceiver(texture);
70  mipmaps_set_.set(level);
71  } else {
72  mipmaps_set_.reset(level);
73  }
74  }
75 }
76 
78 
83 
84 
86  : sampler_(kSamplerChanged, SamplerPtr(), this),
87  base_level_(kBaseLevelChanged, 0, this),
88  max_level_(kMaxLevelChanged, 1000, this),
89  swizzle_red_(kSwizzleRedChanged, kRed, kRed, kAlpha, this),
90  swizzle_green_(kSwizzleGreenChanged, kGreen, kRed, kAlpha, this),
91  swizzle_blue_(kSwizzleBlueChanged, kBlue, kRed, kAlpha, this),
92  swizzle_alpha_(kSwizzleAlphaChanged, kAlpha, kRed, kAlpha, this),
93  texture_type_(type),
94  immutable_image_(kImmutableImageChanged, ImagePtr(), this),
95  immutable_levels_(0),
96  multisample_samples_(kMultisampleChanged, 0, this),
97  multisample_fixed_sample_locations_(kMultisampleChanged, true, this) {}
98 
100  if (Sampler* sampler = sampler_.Get().Get())
101  sampler->RemoveReceiver(this);
102 }
103 
104 void TextureBase::SetSampler(const SamplerPtr& sampler) {
105  if (Sampler* old_sampler = sampler_.Get().Get())
106  old_sampler->RemoveReceiver(this);
107  sampler_.Set(sampler);
108  if (Sampler* new_sampler = sampler_.Get().Get())
109  new_sampler->AddReceiver(this);
110 }
111 
112 void TextureBase::SetImmutableImage(const ImagePtr& image, size_t levels) {
113  if (image.Get()) {
114  if (immutable_image_.Get().Get()) {
115  LOG(ERROR) << "ION: SetImmutableImage() called on an already immutable "
116  "texture; SetImmutableImage() can only be called once.";
117  } else if (levels == 0) {
118  LOG(ERROR) << "ION: SetImmutableImage() called with levels == 0. A "
119  "texture must have at least one level (the 0th level).";
120  } else {
121  immutable_levels_ = levels;
122  immutable_image_.Set(image);
123  }
124  }
125 }
126 
128 
133 
134 
136  : TextureBase(kTexture),
137  face_(this, kSubImageChanged, kMipmapChanged) {
138 }
139 
140 bool Texture::ExpectedDimensionsForMipmap(const uint32 mipmap_width,
141  const uint32 mipmap_height,
142  const uint32 mipmap_level,
143  const uint32 base_width,
144  const uint32 base_height,
145  uint32* expected_width,
146  uint32* expected_height) {
149  *expected_width = 0;
150  *expected_height = 0;
151 
153  if (mipmap_width != 1 && (mipmap_width & (mipmap_width - 1))) {
154  LOG(ERROR) << "Mipmap width: " << mipmap_width << " is not a power of 2.";
155  return false;
156  }
157  if (mipmap_height != 1 && (mipmap_height & (mipmap_height - 1))) {
158  LOG(ERROR) << "Mipmap height: " << mipmap_height << " is not a power of 2.";
159  return false;
160  }
161 
164  if (mipmap_width != 1 && mipmap_height != 1) {
165  const float base_ratio =
166  static_cast<float>(base_width) / static_cast<float>(base_height);
167  const float mipmap_ratio =
168  static_cast<float>(mipmap_width) / static_cast<float>(mipmap_height);
169  if (base_ratio != mipmap_ratio) {
170  LOG(ERROR) << "Bad aspect ratio for mipmap.";
171  return false;
172  }
173  }
174 
176  const uint32 max_dimension = std::max(base_width, base_height);
177  const uint32 max_level = static_cast<uint32>(math::Log2(max_dimension));
178  if (mipmap_level > max_level) {
179  LOG(ERROR) << "Mipmap level is: " << mipmap_level <<
180  " but maximum level is: " << max_level << ".";
181  return false;
182  }
183 
184  *expected_width = base_width >> mipmap_level;
185  *expected_height = base_height >> mipmap_level;
186 
190  if (base_width != base_height) {
191  *expected_width = std::max(*expected_width, 1U);
192  *expected_height = std::max(*expected_height, 1U);
193  }
194 
195  if (!((mipmap_width == *expected_width) &&
196  (mipmap_height == *expected_height))) {
197  LOG(ERROR) << "***ION: Mipmap level " << mipmap_level << " has incorrect"
198  << " dimensions [" << mipmap_width << "x"
199  << mipmap_height << "], expected [" << *expected_width << "x"
200  << *expected_height << "]. Base dimensions: ("
201  << base_width << ", " << base_height << "). Ignoring.\n";
202  return false;
203  }
204 
205  return true;
206 }
207 
209  for (size_t i = 0; i < kMipmapSlotCount; ++i) {
210  if (Image* image = face_.GetImage(i).Get()) image->RemoveReceiver(this);
211  }
212 }
213 
214 void Texture::OnNotify(const base::Notifier* notifier) {
215  if (GetResourceCount()) {
216  if (notifier == GetSampler().Get()) {
218  } else {
219  for (size_t i = 0; i < kMipmapSlotCount; ++i) {
220  if (notifier == face_.GetImage(i).Get())
221  OnChanged(static_cast<int>(kMipmapChanged + i));
222  }
223  }
224  }
225 }
226 
227 } // namespace gfx
228 
229 namespace base {
230 
231 using gfx::Texture;
232 
234 template <> ION_API
235 const EnumHelper::EnumData<Texture::Swizzle> EnumHelper::GetEnumData() {
236  static const GLenum kValues[] = { GL_RED, GL_GREEN, GL_BLUE, GL_ALPHA };
237  static const char* kStrings[] = { "Red", "Green", "Blue", "Alpha" };
238  ION_STATIC_ASSERT(ARRAYSIZE(kValues) == ARRAYSIZE(kStrings),
239  "EnumHelper size mismatch");
240  return EnumData<Texture::Swizzle>(
241  base::IndexMap<Texture::Swizzle, GLenum>(kValues, ARRAYSIZE(kValues)),
242  kStrings);
243 }
244 
245 } // namespace base
246 
247 } // namespace ion
const ImagePtr GetImage(size_t level) const
Returns the image at the specified mipmap level, or NULL if this is not mipmapped.
Definition: texture.h:198
void SetImage(size_t level, const ImagePtr &image_in, TextureBase *texture)
Sets the image to use for the texture at the specified mipmap level.
Definition: texture.cc:62
int level
T Log2(T n)
Returns the base-2 logarithm of n.
Definition: utils.h:148
std::string type
Definition: printer.cc:353
void SetImmutableImage(const ImagePtr &image, size_t levels)
Sets this texture to be fully allocated and made immutable by OpenGL, in the sense that it cannot cha...
Definition: texture.cc:112
const SamplerPtr & GetSampler() const
Definition: texture.h:92
TextureBase(TextureType type)
The constructor is protected since this is a base class.
Definition: texture.cc:85
Wrapper around a sub-image, which is defined as an image, the xy offset of where it should be placed ...
Definition: texture.h:46
#define LOG(severity)
Logs the streamed message unconditionally with a severity of severity.
Definition: logging.h:216
A Notifier both sends notifications to and receives notifications from other Notifiers.
Definition: notifier.h:35
~TextureBase() override
The destructor is protected because all base::Referent classes must have protected or private destruc...
Definition: texture.cc:99
uint32 offset
void OnChanged(int bit) const
Forwards OnChanged to all resources.
void SetSubImage(size_t level, const math::Point2ui offset, const ImagePtr &image)
Sets the area of the texture starting from the passed xy offset and having the dimensions of the pass...
Definition: texture.cc:48
An Image represents 2D image data that can be used in a texture supplied to a shader.
Definition: image.h:35
T * Get() const
Returns a raw pointer to the instance, which may be NULL.
Definition: sharedptr.h:89
This template class can be used to map between two kinds of indices when the following assumptions ap...
Definition: indexmap.h:40
Texture()
Texture.
Definition: texture.cc:135
const Grid & image
The original monochrome image data, as doubles (0 - 1).
Definition: sdfutils.cc:90
TexturePtr texture
The Texture to add sub-image data to.
Definition: fontimage.cc:107
This is an internal base class for all texture types.
Definition: texture.h:41
static bool ExpectedDimensionsForMipmap(const uint32 mipmap_width, const uint32 mipmap_height, const uint32 mipmap_level, const uint32 base_width, const uint32 base_height, uint32 *expected_width, uint32 *expected_height)
Tests mipmap dimensions to see that they are proportional and in range with respect to base_width and...
Definition: texture.cc:140
~Texture() override
The destructor is protected because all base::Referent classes must have protected or private destruc...
Definition: texture.cc:208
int GetResourceCount() const
Returns the number of resources that this holder holds.
#define ION_STATIC_ASSERT(expr, message)
Copyright 2016 Google Inc.
Definition: static_assert.h:35
Face(TextureBase *texture, int sub_image_changed_bit, int mipmaps_changed_start_bit)
TextureBase::Face.
Definition: texture.cc:37
kMipmapChanged must be last since it is a range of slots.
Definition: texture.h:270
A SharedPtr is a smart shared pointer to an instance of some class that implements reference counting...
Definition: sharedptr.h:60
void SetSampler(const SamplerPtr &sampler)
Sets/returns the Sampler to use for this. This is NULL by default.
Definition: texture.cc:104
A Sampler object represents texture parameters that control how texture data is accessed in shaders...
Definition: sampler.h:29