Пример #1
0
void SubPalette::initialize(const RGBAPixel& c) {
	RGBAPixel center = rgba(
		(OctreePalette2::BIN_FOR_COLOR(rgba_red(c)) * 256 + 128) / OctreePalette2::BINS,
		(OctreePalette2::BIN_FOR_COLOR(rgba_green(c)) * 256 + 128) / OctreePalette2::BINS,
		(OctreePalette2::BIN_FOR_COLOR(rgba_blue(c)) * 256 + 128) / OctreePalette2::BINS,
		(OctreePalette2::BIN_FOR_COLOR(rgba_alpha(c)) * 256 + 128) / OctreePalette2::BINS
	);

	int nearest = 256 * 256 * 4;
	for (size_t i = 0; i < palette_colors.size(); i++) {
		int distance = rgba_distance2(palette_colors[i], center);
		if (distance < nearest)
			nearest = distance;
		if (nearest == 0)
			break;
	}

	double tmp = sqrt(nearest) + 2 * sqrt(2) * (128 / OctreePalette2::BINS);
	int nearest_dist = (tmp * tmp) + 1;
	for (size_t i = 0; i < palette_colors.size(); i++) {
		int distance = rgba_distance2(palette_colors[i], center);
		if (distance <= nearest_dist)
			colors.push_back(i);
	}

	initialized = true;
}
Пример #2
0
int Octree::findNearestColor(const Octree* octree, RGBAPixel color) {
	assert(octree != nullptr);

	uint8_t red = rgba_red(color);
	uint8_t green = rgba_green(color);
	uint8_t blue = rgba_blue(color);
	uint8_t alpha = rgba_alpha(color);

	const Octree* node = octree;
	for (int i = 7; i >= 8 - OCTREE_COLOR_BITS; i--) {
		if (node->hasColor())
			break;
		int index = (nth_bit(red, i) << 3) | (nth_bit(green, i) << 2) | nth_bit(blue, i) << 1 | nth_bit(alpha, i);
		if (node->hasChildren(index))
			node = node->getChildren(index);
		else
			break;
	}

	if (node->hasColor())
		return node->getColorID();
	auto& colors = node->subtree_colors;
	int min_distance = -1;
	int best_color = -1;
	for (auto it = colors.begin(); it != colors.end(); ++it) {
		int distance = rgba_distance2(color, it->second);
		if (best_color == -1 || distance < min_distance) {
			min_distance = distance;
			best_color = it->first;
		}
	}
	// this shouldn't happen if all the colors are cached
	assert(best_color != -1);
	return best_color;
}
Пример #3
0
void Octree::setColor(RGBAPixel color) {
	reference++;
	red += rgba_red(color);
	green += rgba_green(color);
	blue += rgba_blue(color);
	alpha += rgba_alpha(color);
}
Пример #4
0
int OctreePalette2::getNearestColor(const RGBAPixel& color) {
	// find the belonging sub palette for this color and ask it for the nearest color
	int bins = OctreePalette2::BINS;
	size_t index = OctreePalette2::BIN_FOR_COLOR(rgba_red(color));
	index += bins * OctreePalette2::BIN_FOR_COLOR(rgba_green(color));
	index += bins * bins * OctreePalette2::BIN_FOR_COLOR(rgba_blue(color));
	index += bins * bins * bins * OctreePalette2::BIN_FOR_COLOR(rgba_alpha(color));
	assert(index < sub_palettes.size());
	if (sub_palettes[index] == nullptr)
		sub_palettes[index] = new SubPalette(colors);
	return sub_palettes[index]->getNearestColor(color);
}
Пример #5
0
Octree* Octree::findOrCreateNode(Octree* octree, RGBAPixel color) {
	assert(octree != nullptr);

	uint8_t red = rgba_red(color);
	uint8_t green = rgba_green(color);
	uint8_t blue = rgba_blue(color);
	uint8_t alpha = rgba_alpha(color);

	Octree* node = octree;
	for (int i = 7; i >= 8 - OCTREE_COLOR_BITS; i--) {
		int index = (nth_bit(red, i) << 3) | (nth_bit(green, i) << 2) | nth_bit(blue, i) << 1 | nth_bit(alpha, i);
		node = node->getChildren(index);
		assert(node != nullptr);
	}
	return node;
}
Пример #6
0
bool TextureImage::load(const std::string& path, int size, int blur, double water_opacity) {
	// at first try to load the texture file
	if (!original.readPNG(path + "/" + name + ".png")) {
		// make sure the texture image does not have zero dimension
		// even if the texture does not exist / is broken
		this->setSize(size, size);
		original = original_resized = *this;
		return false;
	}

	// check if this is an animated texture, calculate how many frames it has
	// also make sure there are exactly n frames, so height mod width = 0
	if ((original.getHeight() % original.getWidth()) != 0) {
		LOG(WARNING) << "Texture '" << name << "' has odd size: " << original.getWidth()
				<< "x" << original.getHeight();
	}
	frame_count = original.getHeight() / original.getWidth();

	// now resize the texture image
	// resize some textures with the nearest neighbor interpolation:
	// - transparent leaves
	// - redstone
	// because smooth interpolation causes here half-transparent pixel which are not
	// good for performance and makes redstone looking not very good and identifiable,
	// instead of that the nearest neighbor interpolation preserves the pixelated
	// style of the textures and prevents fuzziness when resizing
	if ((util::startswith(name, "leaves") && !util::endswith(name, "opaque"))
		|| util::startswith(name, "redstone_dust"))
		original.resize(original_resized, size, size * frame_count, InterpolationType::NEAREST);
	else
		original.resize(original_resized, size, size * frame_count);

	int width = original_resized.getWidth();
	int height = original_resized.getHeight();
	// apply a blur to the texture if wanted
	// this is useful if you use small texture sizes (< 6 maybe) to prevent grainy textures
	if (blur != 0) {
		for (int i = 0; i < frame_count; i++) {
			RGBAImage frame;
			// process every frame individually
			original_resized.clip(0, width * i, width, width).blur(frame, blur);
			original_resized.simpleBlit(frame, 0, width * i);
		}
	}

	// apply opacity factor to water textures
	if (util::startswith(name, "water_") && water_opacity != 1.0) {
		for (int x = 0; x < width; x++) {
			for (int y = 0; y < height; y++) {
				RGBAPixel& pixel = original_resized.pixel(x, y);
				uint8_t alpha = std::min(255.0, rgba_alpha(pixel) * water_opacity);
				pixel = rgba(rgba_red(pixel), rgba_green(pixel), rgba_blue(pixel), alpha);
			}
		}
	}

	// assign actual texture to parent RGBAImage object
	// uses first frame if this is an animated texture
	this->setSize(size, size);
	this->simpleAlphaBlit(getFrame(0), 0, 0);
	return true;
}