| 128 | } |
| 129 | |
| 130 | std::vector<uint8_t> TextureView::sampleNearestPixel( |
| 131 | double u, |
| 132 | double v, |
| 133 | const std::vector<int64_t>& channels) const noexcept { |
| 134 | CESIUM_ASSERT(this->_textureViewStatus == TextureViewStatus::Valid); |
| 135 | std::vector<uint8_t> result(channels.size()); |
| 136 | |
| 137 | if (channels.size() == 0) { |
| 138 | return result; |
| 139 | } |
| 140 | |
| 141 | if (this->_applyTextureTransform && this->_textureTransform) { |
| 142 | glm::dvec2 transformedUvs = this->_textureTransform->applyTransform(u, v); |
| 143 | u = transformedUvs.x; |
| 144 | v = transformedUvs.y; |
| 145 | } |
| 146 | |
| 147 | u = applySamplerWrapS(u, this->_pSampler->wrapS); |
| 148 | v = applySamplerWrapT(v, this->_pSampler->wrapT); |
| 149 | |
| 150 | const ImageAsset& image = |
| 151 | this->_pImageCopy != nullptr ? *this->_pImageCopy : *this->_pImage; |
| 152 | |
| 153 | // For nearest filtering, std::floor is used instead of std::round. |
| 154 | // This is because filtering is supposed to consider the pixel centers. But |
| 155 | // memory access here acts as sampling the beginning of the pixel. Example: |
| 156 | // 0.4 * 2 = 0.8. In a 2x1 pixel image, that should be closer to the left |
| 157 | // pixel's center. But it will round to 1.0 which corresponds to the right |
| 158 | // pixel. So the right pixel has a bigger range than the left one, which is |
| 159 | // incorrect. |
| 160 | double xCoord = std::floor(u * image.width); |
| 161 | double yCoord = std::floor(v * image.height); |
| 162 | |
| 163 | // Clamp to ensure no out-of-bounds data access |
| 164 | int64_t x = glm::clamp( |
| 165 | static_cast<int64_t>(xCoord), |
| 166 | static_cast<int64_t>(0), |
| 167 | static_cast<int64_t>(image.width) - 1); |
| 168 | int64_t y = glm::clamp( |
| 169 | static_cast<int64_t>(yCoord), |
| 170 | static_cast<int64_t>(0), |
| 171 | static_cast<int64_t>(image.height) - 1); |
| 172 | |
| 173 | int64_t pixelIndex = |
| 174 | static_cast<int64_t>(image.bytesPerChannel * image.channels) * |
| 175 | (y * image.width + x); |
| 176 | |
| 177 | // TODO: Currently stb only outputs uint8 pixel types. If that |
| 178 | // changes this should account for additional pixel byte sizes. |
| 179 | const uint8_t* pValue = |
| 180 | reinterpret_cast<const uint8_t*>(image.pixelData.data() + pixelIndex); |
| 181 | for (size_t i = 0; i < result.size(); i++) { |
| 182 | result[i] = *(pValue + channels[i]); |
| 183 | } |
| 184 | |
| 185 | return result; |
| 186 | } |
| 187 | } // namespace CesiumGltf |
no test coverage detected