00001 #include "gui_gl_material.hpp"
00002 #include "gui_gl_manager.hpp"
00003 #include "gui_out.hpp"
00004
00005 #include <utils_string.hpp>
00006 #include <GL/gl.h>
00007 #include <cmath>
00008
00009 namespace gui {
00010 namespace gl
00011 {
00012 bool material::ONLY_POWER_OF_TWO = true;
00013 uint material::MAXIMUM_SIZE = 128;
00014
00015 material::material(uint uiWidth, uint uiHeight, wrap mWrap, filter mFilter, bool bGPUOnly) :
00016 mType_(TYPE_TEXTURE)
00017 {
00018 pTexData_ = utils::refptr<texture_data>(new texture_data());
00019 pTexData_->uiWidth_ = uiWidth;
00020 pTexData_->uiHeight_ = uiHeight;
00021 pTexData_->mWrap_ = mWrap;
00022 pTexData_->mFilter_ = mFilter;
00023
00024 if (ONLY_POWER_OF_TWO)
00025 {
00026 pTexData_->uiRealWidth_ = pow(2.0f, ceil(log2(uiWidth)));
00027 pTexData_->uiRealHeight_ = pow(2.0f, ceil(log2(uiHeight)));
00028 }
00029 else
00030 {
00031 pTexData_->uiRealWidth_ = uiWidth;
00032 pTexData_->uiRealHeight_ = uiHeight;
00033 }
00034
00035 if (pTexData_->uiRealWidth_ > MAXIMUM_SIZE || pTexData_->uiRealHeight_ > MAXIMUM_SIZE)
00036 {
00037 throw gui::exception("gui::gl::material", "Texture dimensions not supported by graphics card : ("+
00038 utils::to_string(pTexData_->uiRealWidth_)+" x "+
00039 utils::to_string(pTexData_->uiRealHeight_)+")."
00040 );
00041 }
00042
00043 GLint iPreviousID;
00044 glGetIntegerv(GL_TEXTURE_BINDING_2D, &iPreviousID);
00045
00046 glGenTextures(1, &pTexData_->uiTextureHandle_);
00047
00048 glBindTexture(GL_TEXTURE_2D, pTexData_->uiTextureHandle_);
00049 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
00050 pTexData_->uiRealWidth_, pTexData_->uiRealHeight_, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr
00051 );
00052
00053 switch (mWrap)
00054 {
00055 case CLAMP :
00056 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00057 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00058 break;
00059 case REPEAT :
00060 default :
00061 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00062 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
00063 break;
00064 }
00065 switch (mFilter)
00066 {
00067 case LINEAR :
00068 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00069 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00070 break;
00071 case NONE :
00072 default :
00073 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00074 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00075 break;
00076 }
00077
00078 glBindTexture(GL_TEXTURE_2D, iPreviousID);
00079
00080 if (!bGPUOnly)
00081 pTexData_->pData_.resize(uiWidth*uiHeight);
00082 }
00083
00084 material::material(const color& mColor) : mType_(TYPE_COLOR)
00085 {
00086 pColData_ = utils::refptr<color_data>(new color_data());
00087 pColData_->mColor_ = mColor;
00088 }
00089
00090 material::~material()
00091 {
00092 switch (mType_)
00093 {
00094 case TYPE_TEXTURE :
00095 glDeleteTextures(1, &pTexData_->uiTextureHandle_); break;
00096 case TYPE_COLOR :
00097 break;
00098 }
00099 }
00100
00101 material::type material::get_type() const
00102 {
00103 return mType_;
00104 }
00105
00106 color material::get_color() const
00107 {
00108 return pColData_->mColor_;
00109 }
00110
00111 void material::set_wrap(wrap mWrap)
00112 {
00113 GLint iPreviousID;
00114 glGetIntegerv(GL_TEXTURE_BINDING_2D, &iPreviousID);
00115 glBindTexture(GL_TEXTURE_2D, pTexData_->uiTextureHandle_);
00116
00117 switch (mWrap)
00118 {
00119 case CLAMP :
00120 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00121 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00122 break;
00123 case REPEAT :
00124 default :
00125 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00126 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
00127 break;
00128 }
00129
00130 glBindTexture(GL_TEXTURE_2D, iPreviousID);
00131 }
00132
00133 void material::set_filter(filter mFilter)
00134 {
00135 GLint iPreviousID;
00136 glGetIntegerv(GL_TEXTURE_BINDING_2D, &iPreviousID);
00137 glBindTexture(GL_TEXTURE_2D, pTexData_->uiTextureHandle_);
00138
00139 switch (mFilter)
00140 {
00141 case LINEAR :
00142 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00143 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00144 break;
00145 case NONE :
00146 default :
00147 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00148 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00149 break;
00150 }
00151
00152 glBindTexture(GL_TEXTURE_2D, iPreviousID);
00153 }
00154
00155 void material::bind() const
00156 {
00157 glBindTexture(GL_TEXTURE_2D, pTexData_->uiTextureHandle_);
00158 }
00159
00160 const std::vector<ub32color>& material::get_data() const
00161 {
00162 return pTexData_->pData_;
00163 }
00164
00165 std::vector<ub32color>& material::get_data()
00166 {
00167 return pTexData_->pData_;
00168 }
00169
00170 void material::set_pixel(uint x, uint y, const ub32color& mColor)
00171 {
00172 pTexData_->pData_[x + y*pTexData_->uiWidth_] = mColor;
00173 }
00174
00175 const ub32color& material::get_pixel(uint x, uint y) const
00176 {
00177 return pTexData_->pData_[x + y*pTexData_->uiWidth_];
00178 }
00179
00180 ub32color& material::get_pixel(uint x, uint y)
00181 {
00182 return pTexData_->pData_[x + y*pTexData_->uiWidth_];
00183 }
00184
00185 void material::premultiply_alpha()
00186 {
00187 uint imax = pTexData_->uiWidth_*pTexData_->uiHeight_;
00188 for (uint i = 0; i < imax; ++i)
00189 {
00190 ub32color& c = pTexData_->pData_[i];
00191 float a = c.a/255.0f;
00192 c.r *= a;
00193 c.g *= a;
00194 c.b *= a;
00195 }
00196 }
00197
00198 float material::get_width() const
00199 {
00200 switch (mType_)
00201 {
00202 case TYPE_TEXTURE :
00203 return pTexData_->uiWidth_;
00204 case TYPE_COLOR :
00205 return 1.0f;
00206 }
00207
00208 return 1.0f;
00209 }
00210
00211 float material::get_height() const
00212 {
00213 switch (mType_)
00214 {
00215 case TYPE_TEXTURE :
00216 return pTexData_->uiHeight_;
00217 case TYPE_COLOR :
00218 return 1.0f;
00219 }
00220
00221 return 1.0f;
00222 }
00223
00224 float material::get_real_width() const
00225 {
00226 switch (mType_)
00227 {
00228 case TYPE_TEXTURE :
00229 return pTexData_->uiRealWidth_;
00230 case TYPE_COLOR :
00231 return 1.0f;
00232 }
00233
00234 return 1.0f;
00235 }
00236
00237 float material::get_real_height() const
00238 {
00239 switch (mType_)
00240 {
00241 case TYPE_TEXTURE :
00242 return pTexData_->uiRealHeight_;
00243 case TYPE_COLOR :
00244 return 1.0f;
00245 }
00246
00247 return 1.0f;
00248 }
00249
00250 bool material::set_dimensions(uint uiWidth, uint uiHeight)
00251 {
00252 if (uiWidth > pTexData_->uiRealWidth_ || uiHeight > pTexData_->uiRealHeight_)
00253 {
00254
00255 utils::refptr<texture_data> pOldData = pTexData_;
00256 pTexData_ = utils::refptr<texture_data>(new texture_data());
00257 pTexData_->uiWidth_ = uiWidth;
00258 pTexData_->uiHeight_ = uiHeight;
00259 pTexData_->mWrap_ = pOldData->mWrap_;
00260 pTexData_->mFilter_ = pOldData->mFilter_;
00261
00262 if (ONLY_POWER_OF_TWO)
00263 {
00264 pTexData_->uiRealWidth_ = pow(2.0f, ceil(log2(uiWidth)));
00265 pTexData_->uiRealHeight_ = pow(2.0f, ceil(log2(uiHeight)));
00266 }
00267 else
00268 {
00269 pTexData_->uiRealWidth_ = uiWidth;
00270 pTexData_->uiRealHeight_ = uiHeight;
00271 }
00272
00273 if (pTexData_->uiRealWidth_ > MAXIMUM_SIZE || pTexData_->uiRealHeight_ > MAXIMUM_SIZE)
00274 {
00275 pTexData_ = pOldData;
00276 return false;
00277 }
00278
00279 glDeleteTextures(1, &pTexData_->uiTextureHandle_);
00280
00281 GLint iPreviousID;
00282 glGetIntegerv(GL_TEXTURE_BINDING_2D, &iPreviousID);
00283
00284 glGenTextures(1, &pTexData_->uiTextureHandle_);
00285
00286 glBindTexture(GL_TEXTURE_2D, pTexData_->uiTextureHandle_);
00287 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8,
00288 pTexData_->uiRealWidth_, pTexData_->uiRealHeight_, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr
00289 );
00290
00291 switch (pTexData_->mWrap_)
00292 {
00293 case CLAMP :
00294 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
00295 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
00296 break;
00297 case REPEAT :
00298 default :
00299 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
00300 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
00301 break;
00302 }
00303 switch (pTexData_->mFilter_)
00304 {
00305 case LINEAR :
00306 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
00307 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
00308 break;
00309 case NONE :
00310 default :
00311 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
00312 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
00313 break;
00314 }
00315
00316 glBindTexture(GL_TEXTURE_2D, iPreviousID);
00317 return true;
00318 }
00319 else
00320 {
00321 pTexData_->uiWidth_ = uiWidth;
00322 pTexData_->uiHeight_ = uiHeight;
00323 return false;
00324 }
00325 }
00326
00327 void material::update_texture()
00328 {
00329 GLint iPreviousID;
00330 glGetIntegerv(GL_TEXTURE_BINDING_2D, &iPreviousID);
00331
00332 glBindTexture(GL_TEXTURE_2D, pTexData_->uiTextureHandle_);
00333 glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, pTexData_->uiWidth_, pTexData_->uiHeight_,
00334 GL_RGBA, GL_UNSIGNED_BYTE, pTexData_->pData_.data()
00335 );
00336
00337 glBindTexture(GL_TEXTURE_2D, iPreviousID);
00338 }
00339
00340 void material::clear_cache_data_()
00341 {
00342 pTexData_->pData_.clear();
00343 }
00344
00345 uint material::get_handle_()
00346 {
00347 return pTexData_->uiTextureHandle_;
00348 }
00349
00350 void material::check_availability()
00351 {
00352 ONLY_POWER_OF_TWO = !manager::is_gl_extension_supported("GL_ARB_texture_non_power_of_two");
00353 gui::out << "Note : non power of two textures are " << (ONLY_POWER_OF_TWO ? "not " : "") << "supported." << std::endl;
00354 int max;
00355 glGetIntegerv(GL_MAX_TEXTURE_SIZE, &max);
00356 MAXIMUM_SIZE = max;
00357 gui::out << "Note : maximum texture size is " << MAXIMUM_SIZE << "." << std::endl;
00358 }
00359 }
00360 }