1/// @ref gtc_round 2/// @file glm/gtc/round.inl 3 4#include "../detail/func_integer.hpp" 5 6namespace glm{ 7namespace detail 8{ 9 template <typename T, precision P, template <typename, precision> class vecType, bool compute = false> 10 struct compute_ceilShift 11 { 12 GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & v, T) 13 { 14 return v; 15 } 16 }; 17 18 template <typename T, precision P, template <typename, precision> class vecType> 19 struct compute_ceilShift<T, P, vecType, true> 20 { 21 GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & v, T Shift) 22 { 23 return v | (v >> Shift); 24 } 25 }; 26 27 template <typename T, precision P, template <typename, precision> class vecType, bool isSigned = true> 28 struct compute_ceilPowerOfTwo 29 { 30 GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x) 31 { 32 GLM_STATIC_ASSERT(!std::numeric_limits<T>::is_iec559, "'ceilPowerOfTwo' only accept integer scalar or vector inputs"); 33 34 vecType<T, P> const Sign(sign(x)); 35 36 vecType<T, P> v(abs(x)); 37 38 v = v - static_cast<T>(1); 39 v = v | (v >> static_cast<T>(1)); 40 v = v | (v >> static_cast<T>(2)); 41 v = v | (v >> static_cast<T>(4)); 42 v = compute_ceilShift<T, P, vecType, sizeof(T) >= 2>::call(v, 8); 43 v = compute_ceilShift<T, P, vecType, sizeof(T) >= 4>::call(v, 16); 44 v = compute_ceilShift<T, P, vecType, sizeof(T) >= 8>::call(v, 32); 45 return (v + static_cast<T>(1)) * Sign; 46 } 47 }; 48 49 template <typename T, precision P, template <typename, precision> class vecType> 50 struct compute_ceilPowerOfTwo<T, P, vecType, false> 51 { 52 GLM_FUNC_QUALIFIER static vecType<T, P> call(vecType<T, P> const & x) 53 { 54 GLM_STATIC_ASSERT(!std::numeric_limits<T>::is_iec559, "'ceilPowerOfTwo' only accept integer scalar or vector inputs"); 55 56 vecType<T, P> v(x); 57 58 v = v - static_cast<T>(1); 59 v = v | (v >> static_cast<T>(1)); 60 v = v | (v >> static_cast<T>(2)); 61 v = v | (v >> static_cast<T>(4)); 62 v = compute_ceilShift<T, P, vecType, sizeof(T) >= 2>::call(v, 8); 63 v = compute_ceilShift<T, P, vecType, sizeof(T) >= 4>::call(v, 16); 64 v = compute_ceilShift<T, P, vecType, sizeof(T) >= 8>::call(v, 32); 65 return v + static_cast<T>(1); 66 } 67 }; 68 69 template <bool is_float, bool is_signed> 70 struct compute_ceilMultiple{}; 71 72 template <> 73 struct compute_ceilMultiple<true, true> 74 { 75 template <typename genType> 76 GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) 77 { 78 if(Source > genType(0)) 79 return Source + (Multiple - std::fmod(Source, Multiple)); 80 else 81 return Source + std::fmod(-Source, Multiple); 82 } 83 }; 84 85 template <> 86 struct compute_ceilMultiple<false, false> 87 { 88 template <typename genType> 89 GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) 90 { 91 genType Tmp = Source - genType(1); 92 return Tmp + (Multiple - (Tmp % Multiple)); 93 } 94 }; 95 96 template <> 97 struct compute_ceilMultiple<false, true> 98 { 99 template <typename genType> 100 GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) 101 { 102 if(Source > genType(0)) 103 { 104 genType Tmp = Source - genType(1); 105 return Tmp + (Multiple - (Tmp % Multiple)); 106 } 107 else 108 return Source + (-Source % Multiple); 109 } 110 }; 111 112 template <bool is_float, bool is_signed> 113 struct compute_floorMultiple{}; 114 115 template <> 116 struct compute_floorMultiple<true, true> 117 { 118 template <typename genType> 119 GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) 120 { 121 if(Source >= genType(0)) 122 return Source - std::fmod(Source, Multiple); 123 else 124 return Source - std::fmod(Source, Multiple) - Multiple; 125 } 126 }; 127 128 template <> 129 struct compute_floorMultiple<false, false> 130 { 131 template <typename genType> 132 GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) 133 { 134 if(Source >= genType(0)) 135 return Source - Source % Multiple; 136 else 137 { 138 genType Tmp = Source + genType(1); 139 return Tmp - Tmp % Multiple - Multiple; 140 } 141 } 142 }; 143 144 template <> 145 struct compute_floorMultiple<false, true> 146 { 147 template <typename genType> 148 GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) 149 { 150 if(Source >= genType(0)) 151 return Source - Source % Multiple; 152 else 153 { 154 genType Tmp = Source + genType(1); 155 return Tmp - Tmp % Multiple - Multiple; 156 } 157 } 158 }; 159 160 template <bool is_float, bool is_signed> 161 struct compute_roundMultiple{}; 162 163 template <> 164 struct compute_roundMultiple<true, true> 165 { 166 template <typename genType> 167 GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) 168 { 169 if(Source >= genType(0)) 170 return Source - std::fmod(Source, Multiple); 171 else 172 { 173 genType Tmp = Source + genType(1); 174 return Tmp - std::fmod(Tmp, Multiple) - Multiple; 175 } 176 } 177 }; 178 179 template <> 180 struct compute_roundMultiple<false, false> 181 { 182 template <typename genType> 183 GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) 184 { 185 if(Source >= genType(0)) 186 return Source - Source % Multiple; 187 else 188 { 189 genType Tmp = Source + genType(1); 190 return Tmp - Tmp % Multiple - Multiple; 191 } 192 } 193 }; 194 195 template <> 196 struct compute_roundMultiple<false, true> 197 { 198 template <typename genType> 199 GLM_FUNC_QUALIFIER static genType call(genType Source, genType Multiple) 200 { 201 if(Source >= genType(0)) 202 return Source - Source % Multiple; 203 else 204 { 205 genType Tmp = Source + genType(1); 206 return Tmp - Tmp % Multiple - Multiple; 207 } 208 } 209 }; 210}//namespace detail 211 212 //////////////// 213 // isPowerOfTwo 214 215 template <typename genType> 216 GLM_FUNC_QUALIFIER bool isPowerOfTwo(genType Value) 217 { 218 genType const Result = glm::abs(Value); 219 return !(Result & (Result - 1)); 220 } 221 222 template <typename T, precision P, template <typename, precision> class vecType> 223 GLM_FUNC_QUALIFIER vecType<bool, P> isPowerOfTwo(vecType<T, P> const & Value) 224 { 225 vecType<T, P> const Result(abs(Value)); 226 return equal(Result & (Result - 1), vecType<T, P>(0)); 227 } 228 229 ////////////////// 230 // ceilPowerOfTwo 231 232 template <typename genType> 233 GLM_FUNC_QUALIFIER genType ceilPowerOfTwo(genType value) 234 { 235 return detail::compute_ceilPowerOfTwo<genType, defaultp, tvec1, std::numeric_limits<genType>::is_signed>::call(tvec1<genType, defaultp>(value)).x; 236 } 237 238 template <typename T, precision P, template <typename, precision> class vecType> 239 GLM_FUNC_QUALIFIER vecType<T, P> ceilPowerOfTwo(vecType<T, P> const & v) 240 { 241 return detail::compute_ceilPowerOfTwo<T, P, vecType, std::numeric_limits<T>::is_signed>::call(v); 242 } 243 244 /////////////////// 245 // floorPowerOfTwo 246 247 template <typename genType> 248 GLM_FUNC_QUALIFIER genType floorPowerOfTwo(genType value) 249 { 250 return isPowerOfTwo(value) ? value : static_cast<genType>(1) << findMSB(value); 251 } 252 253 template <typename T, precision P, template <typename, precision> class vecType> 254 GLM_FUNC_QUALIFIER vecType<T, P> floorPowerOfTwo(vecType<T, P> const & v) 255 { 256 return detail::functor1<T, T, P, vecType>::call(floorPowerOfTwo, v); 257 } 258 259 /////////////////// 260 // roundPowerOfTwo 261 262 template <typename genIUType> 263 GLM_FUNC_QUALIFIER genIUType roundPowerOfTwo(genIUType value) 264 { 265 if(isPowerOfTwo(value)) 266 return value; 267 268 genIUType const prev = static_cast<genIUType>(1) << findMSB(value); 269 genIUType const next = prev << static_cast<genIUType>(1); 270 return (next - value) < (value - prev) ? next : prev; 271 } 272 273 template <typename T, precision P, template <typename, precision> class vecType> 274 GLM_FUNC_QUALIFIER vecType<T, P> roundPowerOfTwo(vecType<T, P> const & v) 275 { 276 return detail::functor1<T, T, P, vecType>::call(roundPowerOfTwo, v); 277 } 278 279 //////////////// 280 // isMultiple 281 282 template <typename genType> 283 GLM_FUNC_QUALIFIER bool isMultiple(genType Value, genType Multiple) 284 { 285 return isMultiple(tvec1<genType>(Value), tvec1<genType>(Multiple)).x; 286 } 287 288 template <typename T, precision P, template <typename, precision> class vecType> 289 GLM_FUNC_QUALIFIER vecType<bool, P> isMultiple(vecType<T, P> const & Value, T Multiple) 290 { 291 return (Value % Multiple) == vecType<T, P>(0); 292 } 293 294 template <typename T, precision P, template <typename, precision> class vecType> 295 GLM_FUNC_QUALIFIER vecType<bool, P> isMultiple(vecType<T, P> const & Value, vecType<T, P> const & Multiple) 296 { 297 return (Value % Multiple) == vecType<T, P>(0); 298 } 299 300 ////////////////////// 301 // ceilMultiple 302 303 template <typename genType> 304 GLM_FUNC_QUALIFIER genType ceilMultiple(genType Source, genType Multiple) 305 { 306 return detail::compute_ceilMultiple<std::numeric_limits<genType>::is_iec559, std::numeric_limits<genType>::is_signed>::call(Source, Multiple); 307 } 308 309 template <typename T, precision P, template <typename, precision> class vecType> 310 GLM_FUNC_QUALIFIER vecType<T, P> ceilMultiple(vecType<T, P> const & Source, vecType<T, P> const & Multiple) 311 { 312 return detail::functor2<T, P, vecType>::call(ceilMultiple, Source, Multiple); 313 } 314 315 ////////////////////// 316 // floorMultiple 317 318 template <typename genType> 319 GLM_FUNC_QUALIFIER genType floorMultiple(genType Source, genType Multiple) 320 { 321 return detail::compute_floorMultiple<std::numeric_limits<genType>::is_iec559, std::numeric_limits<genType>::is_signed>::call(Source, Multiple); 322 } 323 324 template <typename T, precision P, template <typename, precision> class vecType> 325 GLM_FUNC_QUALIFIER vecType<T, P> floorMultiple(vecType<T, P> const & Source, vecType<T, P> const & Multiple) 326 { 327 return detail::functor2<T, P, vecType>::call(floorMultiple, Source, Multiple); 328 } 329 330 ////////////////////// 331 // roundMultiple 332 333 template <typename genType> 334 GLM_FUNC_QUALIFIER genType roundMultiple(genType Source, genType Multiple) 335 { 336 return detail::compute_roundMultiple<std::numeric_limits<genType>::is_iec559, std::numeric_limits<genType>::is_signed>::call(Source, Multiple); 337 } 338 339 template <typename T, precision P, template <typename, precision> class vecType> 340 GLM_FUNC_QUALIFIER vecType<T, P> roundMultiple(vecType<T, P> const & Source, vecType<T, P> const & Multiple) 341 { 342 return detail::functor2<T, P, vecType>::call(roundMultiple, Source, Multiple); 343 } 344}//namespace glm 345