summaryrefslogtreecommitdiff
path: root/thirdparty/basis_universal/basisu_pvrtc1_4.h
diff options
context:
space:
mode:
authorJuan Linietsky <reduzio@gmail.com>2019-09-26 23:16:44 -0300
committerJuan Linietsky <reduzio@gmail.com>2020-02-11 12:02:36 +0100
commit4aea9f74e650743fe6585d5230dd6e5f6c94c478 (patch)
tree5ee02ffbe4ec128317e3c7cdca4861f6a39fb382 /thirdparty/basis_universal/basisu_pvrtc1_4.h
parent263bebe0237b85b1343ba17b117c8c43287ecc57 (diff)
Rewritten StreamTexture for better code reuse, added basis universal support
Diffstat (limited to 'thirdparty/basis_universal/basisu_pvrtc1_4.h')
-rw-r--r--thirdparty/basis_universal/basisu_pvrtc1_4.h369
1 files changed, 369 insertions, 0 deletions
diff --git a/thirdparty/basis_universal/basisu_pvrtc1_4.h b/thirdparty/basis_universal/basisu_pvrtc1_4.h
new file mode 100644
index 0000000000..71c4fba1d8
--- /dev/null
+++ b/thirdparty/basis_universal/basisu_pvrtc1_4.h
@@ -0,0 +1,369 @@
+// basisu_pvrtc1_4.cpp
+// Copyright (C) 2019 Binomial LLC. All Rights Reserved.
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+// http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+#pragma once
+#include "basisu_gpu_texture.h"
+
+namespace basisu
+{
+ enum
+ {
+ PVRTC2_MIN_WIDTH = 16,
+ PVRTC2_MIN_HEIGHT = 8,
+ PVRTC4_MIN_WIDTH = 8,
+ PVRTC4_MIN_HEIGHT = 8
+ };
+
+ struct pvrtc4_block
+ {
+ uint32_t m_modulation;
+ uint32_t m_endpoints;
+
+ pvrtc4_block() : m_modulation(0), m_endpoints(0) { }
+
+ inline bool operator== (const pvrtc4_block& rhs) const
+ {
+ return (m_modulation == rhs.m_modulation) && (m_endpoints == rhs.m_endpoints);
+ }
+
+ inline void clear()
+ {
+ m_modulation = 0;
+ m_endpoints = 0;
+ }
+
+ inline bool get_block_uses_transparent_modulation() const
+ {
+ return (m_endpoints & 1) != 0;
+ }
+
+ inline bool is_endpoint_opaque(uint32_t endpoint_index) const
+ {
+ static const uint32_t s_bitmasks[2] = { 0x8000U, 0x80000000U };
+ return (m_endpoints & s_bitmasks[open_range_check(endpoint_index, 2U)]) != 0;
+ }
+
+ // Returns raw endpoint or 8888
+ color_rgba get_endpoint(uint32_t endpoint_index, bool unpack) const;
+
+ color_rgba get_endpoint_5554(uint32_t endpoint_index) const;
+
+ static uint32_t get_component_precision_in_bits(uint32_t c, uint32_t endpoint_index, bool opaque_endpoint)
+ {
+ static const uint32_t s_comp_prec[4][4] =
+ {
+ // R0 G0 B0 A0 R1 G1 B1 A1
+ { 4, 4, 3, 3 }, { 4, 4, 4, 3 }, // transparent endpoint
+
+ { 5, 5, 4, 0 }, { 5, 5, 5, 0 } // opaque endpoint
+ };
+ return s_comp_prec[open_range_check(endpoint_index, 2U) + (opaque_endpoint * 2)][open_range_check(c, 4U)];
+ }
+
+ static color_rgba get_color_precision_in_bits(uint32_t endpoint_index, bool opaque_endpoint)
+ {
+ static const color_rgba s_color_prec[4] =
+ {
+ color_rgba(4, 4, 3, 3), color_rgba(4, 4, 4, 3), // transparent endpoint
+ color_rgba(5, 5, 4, 0), color_rgba(5, 5, 5, 0) // opaque endpoint
+ };
+ return s_color_prec[open_range_check(endpoint_index, 2U) + (opaque_endpoint * 2)];
+ }
+
+ inline uint32_t get_modulation(uint32_t x, uint32_t y) const
+ {
+ assert((x < 4) && (y < 4));
+ return (m_modulation >> ((y * 4 + x) * 2)) & 3;
+ }
+
+ // Scaled by 8
+ inline const uint32_t* get_scaled_modulation_values(bool block_uses_transparent_modulation) const
+ {
+ static const uint32_t s_block_scales[2][4] = { { 0, 3, 5, 8 }, { 0, 4, 4, 8 } };
+ return s_block_scales[block_uses_transparent_modulation];
+ }
+
+ // Scaled by 8
+ inline uint32_t get_scaled_modulation(uint32_t x, uint32_t y) const
+ {
+ return get_scaled_modulation_values(get_block_uses_transparent_modulation())[get_modulation(x, y)];
+ }
+
+ inline void byte_swap()
+ {
+ m_modulation = byteswap32(m_modulation);
+ m_endpoints = byteswap32(m_endpoints);
+ }
+
+ // opaque endpoints: 554, 555
+ // transparent endpoints: 3443 or 3444
+ inline void set_endpoint_raw(uint32_t endpoint_index, const color_rgba& c, bool opaque_endpoint)
+ {
+ assert(endpoint_index < 2);
+ const uint32_t m = m_endpoints & 1;
+ uint32_t r = c[0], g = c[1], b = c[2], a = c[3];
+
+ uint32_t packed;
+
+ if (opaque_endpoint)
+ {
+ if (!endpoint_index)
+ {
+ // 554
+ // 1RRRRRGGGGGBBBBM
+ assert((r < 32) && (g < 32) && (b < 16));
+ packed = 0x8000 | (r << 10) | (g << 5) | (b << 1) | m;
+ }
+ else
+ {
+ // 555
+ // 1RRRRRGGGGGBBBBB
+ assert((r < 32) && (g < 32) && (b < 32));
+ packed = 0x8000 | (r << 10) | (g << 5) | b;
+ }
+ }
+ else
+ {
+ if (!endpoint_index)
+ {
+ // 3443
+ // 0AAA RRRR GGGG BBBM
+ assert((r < 16) && (g < 16) && (b < 8) && (a < 8));
+ packed = (a << 12) | (r << 8) | (g << 4) | (b << 1) | m;
+ }
+ else
+ {
+ // 3444
+ // 0AAA RRRR GGGG BBBB
+ assert((r < 16) && (g < 16) && (b < 16) && (a < 8));
+ packed = (a << 12) | (r << 8) | (g << 4) | b;
+ }
+ }
+
+ assert(packed <= 0xFFFF);
+
+ if (endpoint_index)
+ m_endpoints = (m_endpoints & 0xFFFFU) | (packed << 16);
+ else
+ m_endpoints = (m_endpoints & 0xFFFF0000U) | packed;
+ }
+ };
+
+ typedef vector2D<pvrtc4_block> pvrtc4_block_vector2D;
+
+ uint32_t pvrtc4_swizzle_uv(uint32_t XSize, uint32_t YSize, uint32_t XPos, uint32_t YPos);
+
+ class pvrtc4_image
+ {
+ public:
+ inline pvrtc4_image() :
+ m_width(0), m_height(0), m_block_width(0), m_block_height(0), m_wrap_addressing(false), m_uses_alpha(false)
+ {
+ }
+
+ inline pvrtc4_image(uint32_t width, uint32_t height, bool wrap_addressing = false) :
+ m_width(0), m_height(0), m_block_width(0), m_block_height(0), m_wrap_addressing(false), m_uses_alpha(false)
+ {
+ resize(width, height);
+ set_wrap_addressing(wrap_addressing);
+ }
+
+ inline void clear()
+ {
+ m_width = 0;
+ m_height = 0;
+ m_block_width = 0;
+ m_block_height = 0;
+ m_blocks.clear();
+ m_uses_alpha = false;
+ m_wrap_addressing = false;
+ }
+
+ inline void resize(uint32_t width, uint32_t height)
+ {
+ if ((width == m_width) && (height == m_height))
+ return;
+
+ m_width = width;
+ m_height = height;
+
+ m_block_width = (width + 3) >> 2;
+ m_block_height = (height + 3) >> 2;
+
+ m_blocks.resize(m_block_width, m_block_height);
+ }
+
+ inline uint32_t get_width() const { return m_width; }
+ inline uint32_t get_height() const { return m_height; }
+
+ inline uint32_t get_block_width() const { return m_block_width; }
+ inline uint32_t get_block_height() const { return m_block_height; }
+
+ inline const pvrtc4_block_vector2D &get_blocks() const { return m_blocks; }
+ inline pvrtc4_block_vector2D &get_blocks() { return m_blocks; }
+
+ inline uint32_t get_total_blocks() const { return m_block_width * m_block_height; }
+
+ inline bool get_uses_alpha() const { return m_uses_alpha; }
+ inline void set_uses_alpha(bool uses_alpha) { m_uses_alpha = uses_alpha; }
+
+ inline void set_wrap_addressing(bool wrapping) { m_wrap_addressing = wrapping; }
+ inline bool get_wrap_addressing() const { return m_wrap_addressing; }
+
+ inline bool are_blocks_equal(const pvrtc4_image& rhs) const
+ {
+ return m_blocks == rhs.m_blocks;
+ }
+
+ inline void set_to_black()
+ {
+ memset(m_blocks.get_ptr(), 0, m_blocks.size_in_bytes());
+ }
+
+ inline bool get_block_uses_transparent_modulation(uint32_t bx, uint32_t by) const
+ {
+ return m_blocks(bx, by).get_block_uses_transparent_modulation();
+ }
+
+ inline bool is_endpoint_opaque(uint32_t bx, uint32_t by, uint32_t endpoint_index) const
+ {
+ return m_blocks(bx, by).is_endpoint_opaque(endpoint_index);
+ }
+
+ color_rgba get_endpoint(uint32_t bx, uint32_t by, uint32_t endpoint_index, bool unpack) const
+ {
+ assert((bx < m_block_width) && (by < m_block_height));
+ return m_blocks(bx, by).get_endpoint(endpoint_index, unpack);
+ }
+
+ inline uint32_t get_modulation(uint32_t x, uint32_t y) const
+ {
+ assert((x < m_width) && (y < m_height));
+ return m_blocks(x >> 2, y >> 2).get_modulation(x & 3, y & 3);
+ }
+
+ // Returns true if the block uses transparent modulation.
+ bool get_interpolated_colors(uint32_t x, uint32_t y, color_rgba* pColors) const;
+
+ color_rgba get_pixel(uint32_t x, uint32_t y, uint32_t m) const;
+
+ inline color_rgba get_pixel(uint32_t x, uint32_t y) const
+ {
+ assert((x < m_width) && (y < m_height));
+ return get_pixel(x, y, m_blocks(x >> 2, y >> 2).get_modulation(x & 3, y & 3));
+ }
+
+ void deswizzle()
+ {
+ pvrtc4_block_vector2D temp(m_blocks);
+
+ for (uint32_t y = 0; y < m_block_height; y++)
+ for (uint32_t x = 0; x < m_block_width; x++)
+ m_blocks(x, y) = temp[pvrtc4_swizzle_uv(m_block_width, m_block_height, x, y)];
+ }
+
+ void swizzle()
+ {
+ pvrtc4_block_vector2D temp(m_blocks);
+
+ for (uint32_t y = 0; y < m_block_height; y++)
+ for (uint32_t x = 0; x < m_block_width; x++)
+ m_blocks[pvrtc4_swizzle_uv(m_block_width, m_block_height, x, y)] = temp(x, y);
+ }
+
+ void unpack_all_pixels(image& img) const
+ {
+ img.crop(m_width, m_height);
+
+ for (uint32_t y = 0; y < m_height; y++)
+ for (uint32_t x = 0; x < m_width; x++)
+ img(x, y) = get_pixel(x, y);
+ }
+
+ void unpack_block(image &dst, uint32_t block_x, uint32_t block_y)
+ {
+ for (uint32_t y = 0; y < 4; y++)
+ for (uint32_t x = 0; x < 4; x++)
+ dst(x, y) = get_pixel(block_x * 4 + x, block_y * 4 + y);
+ }
+
+ inline int wrap_or_clamp_x(int x) const
+ {
+ return m_wrap_addressing ? posmod(x, m_width) : clamp<int>(x, 0, m_width - 1);
+ }
+
+ inline int wrap_or_clamp_y(int y) const
+ {
+ return m_wrap_addressing ? posmod(y, m_height) : clamp<int>(y, 0, m_height - 1);
+ }
+
+ inline int wrap_or_clamp_block_x(int bx) const
+ {
+ return m_wrap_addressing ? posmod(bx, m_block_width) : clamp<int>(bx, 0, m_block_width - 1);
+ }
+
+ inline int wrap_or_clamp_block_y(int by) const
+ {
+ return m_wrap_addressing ? posmod(by, m_block_height) : clamp<int>(by, 0, m_block_height - 1);
+ }
+
+ inline vec2F get_interpolation_factors(uint32_t x, uint32_t y) const
+ {
+ // 0 1 2 3
+ // 2 3 0 1
+ // .5 .75 0 .25
+ static const float s_interp[4] = { 2, 3, 0, 1 };
+ return vec2F(s_interp[x & 3], s_interp[y & 3]);
+ }
+
+ inline color_rgba interpolate(int x, int y,
+ const color_rgba& p, const color_rgba& q,
+ const color_rgba& r, const color_rgba& s) const
+ {
+ static const int s_interp[4] = { 2, 3, 0, 1 };
+ const int u_interp = s_interp[x & 3];
+ const int v_interp = s_interp[y & 3];
+
+ color_rgba result;
+
+ for (uint32_t c = 0; c < 4; c++)
+ {
+ int t = p[c] * 4 + u_interp * ((int)q[c] - (int)p[c]);
+ int b = r[c] * 4 + u_interp * ((int)s[c] - (int)r[c]);
+ int v = t * 4 + v_interp * (b - t);
+ if (c < 3)
+ {
+ v >>= 1;
+ v += (v >> 5);
+ }
+ else
+ {
+ v += (v >> 4);
+ }
+ assert((v >= 0) && (v < 256));
+ result[c] = static_cast<uint8_t>(v);
+ }
+
+ return result;
+ }
+
+ uint32_t m_width, m_height;
+ pvrtc4_block_vector2D m_blocks;
+ uint32_t m_block_width, m_block_height;
+
+ bool m_wrap_addressing;
+ bool m_uses_alpha;
+ };
+
+} // namespace basisu