Introduce mipgen frontend. (#120)

* Introduce mipgen frontend.

For now this is fairly simple although it does let you choose a filter.
Another cool feature is that an HTML file is generated which makes it
easy to review the generated miplevels.

This does not expose the Boundary enum to users because it has not yet
been implemented in the core Image library.

* Fix up mipgen per code review.
This commit is contained in:
Philip Rideout
2018-08-21 17:54:27 -07:00
committed by GitHub
parent b587ec3f43
commit e45e7b256d
29 changed files with 429 additions and 0 deletions

View File

@@ -19,9 +19,11 @@
#include <math/vec3.h>
#include <utils/Panic.h>
#include <utils/CString.h>
#include <memory>
#include <vector>
#include <unordered_map>
using namespace image;
@@ -320,4 +322,48 @@ void computeSingleSample(const LinearImage& source, float x, float y, SingleSamp
}
}
// Unlike traditional mipmap generation, our implementation generates all levels from the original
// image, under the premise that this produces a higher quality result.
void generateMipmaps(const LinearImage& source, Filter filter, LinearImage* result, uint32_t mips) {
mips = std::min(mips, getMipmapCount(source));
uint32_t width = source.getWidth();
uint32_t height = source.getHeight();
for (uint32_t n = 0; n < mips; ++n) {
width = std::max(width >> 1, 1u);
height = std::max(height >> 1, 1u);
result[n] = resampleImage(source, width, height, filter);
}
}
uint32_t getMipmapCount(const LinearImage& source) {
uint32_t width = source.getWidth();
uint32_t height = source.getHeight();
uint32_t count = 0;
while (width > 1 || height > 1) {
++count;
width = std::max(width >> 1, 1u);
height = std::max(height >> 1, 1u);
}
return count;
}
Filter filterFromString(const char* rawname) {
using namespace utils;
using namespace std;
static const unordered_map<StaticString, Filter> map = {
{ "BOX", Filter::BOX},
{ "NEAREST", Filter::NEAREST},
{ "HERMITE", Filter::HERMITE},
{ "GAUSSIAN", Filter::GAUSSIAN_SCALARS},
{ "NORMALS", Filter::GAUSSIAN_NORMALS},
{ "MITCHELL", Filter::MITCHELL},
{ "LANCZOS", Filter::LANCZOS},
{ "MINIMUM", Filter::MINIMUM},
};
string name = rawname;
for (auto& c: name) c = toupper((unsigned char) c);
auto iter = map.find({ name.c_str(), name.size() });
return iter == map.end() ? Filter::DEFAULT : iter->second;
}
} // namespace image