diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/citra_qt/debugger/graphics/graphics_surface.cpp | 13 | ||||
| -rw-r--r-- | src/video_core/pica.h | 5 | ||||
| -rw-r--r-- | src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | 3 | ||||
| -rw-r--r-- | src/video_core/texture/texture_decode.cpp | 108 | ||||
| -rw-r--r-- | src/video_core/texture/texture_decode.h | 32 |
5 files changed, 117 insertions, 44 deletions
diff --git a/src/citra_qt/debugger/graphics/graphics_surface.cpp b/src/citra_qt/debugger/graphics/graphics_surface.cpp index c0a72a6ef..bd82b00d4 100644 --- a/src/citra_qt/debugger/graphics/graphics_surface.cpp +++ b/src/citra_qt/debugger/graphics/graphics_surface.cpp | |||
| @@ -568,19 +568,14 @@ void GraphicsSurfaceWidget::OnUpdate() { | |||
| 568 | 568 | ||
| 569 | surface_picture_label->show(); | 569 | surface_picture_label->show(); |
| 570 | 570 | ||
| 571 | unsigned nibbles_per_pixel = GraphicsSurfaceWidget::NibblesPerPixel(surface_format); | ||
| 572 | unsigned stride = nibbles_per_pixel * surface_width / 2; | ||
| 573 | |||
| 574 | // We handle depth formats here because DebugUtils only supports TextureFormats | ||
| 575 | if (surface_format <= Format::MaxTextureFormat) { | 571 | if (surface_format <= Format::MaxTextureFormat) { |
| 576 | |||
| 577 | // Generate a virtual texture | 572 | // Generate a virtual texture |
| 578 | Pica::Texture::TextureInfo info; | 573 | Pica::Texture::TextureInfo info; |
| 579 | info.physical_address = surface_address; | 574 | info.physical_address = surface_address; |
| 580 | info.width = surface_width; | 575 | info.width = surface_width; |
| 581 | info.height = surface_height; | 576 | info.height = surface_height; |
| 582 | info.format = static_cast<Pica::Regs::TextureFormat>(surface_format); | 577 | info.format = static_cast<Pica::Regs::TextureFormat>(surface_format); |
| 583 | info.stride = stride; | 578 | info.SetDefaultStride(); |
| 584 | 579 | ||
| 585 | for (unsigned int y = 0; y < surface_height; ++y) { | 580 | for (unsigned int y = 0; y < surface_height; ++y) { |
| 586 | for (unsigned int x = 0; x < surface_width; ++x) { | 581 | for (unsigned int x = 0; x < surface_width; ++x) { |
| @@ -588,8 +583,12 @@ void GraphicsSurfaceWidget::OnUpdate() { | |||
| 588 | decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), color.a())); | 583 | decoded_image.setPixel(x, y, qRgba(color.r(), color.g(), color.b(), color.a())); |
| 589 | } | 584 | } |
| 590 | } | 585 | } |
| 591 | |||
| 592 | } else { | 586 | } else { |
| 587 | // We handle depth formats here because DebugUtils only supports TextureFormats | ||
| 588 | |||
| 589 | // TODO(yuriks): Convert to newer tile-based addressing | ||
| 590 | unsigned nibbles_per_pixel = GraphicsSurfaceWidget::NibblesPerPixel(surface_format); | ||
| 591 | unsigned stride = nibbles_per_pixel * surface_width / 2; | ||
| 593 | 592 | ||
| 594 | ASSERT_MSG(nibbles_per_pixel >= 2, | 593 | ASSERT_MSG(nibbles_per_pixel >= 2, |
| 595 | "Depth decoder only supports formats with at least one byte per pixel"); | 594 | "Depth decoder only supports formats with at least one byte per pixel"); |
diff --git a/src/video_core/pica.h b/src/video_core/pica.h index b2db609ec..4ab4f1f40 100644 --- a/src/video_core/pica.h +++ b/src/video_core/pica.h | |||
| @@ -275,8 +275,11 @@ struct Regs { | |||
| 275 | case TextureFormat::I8: | 275 | case TextureFormat::I8: |
| 276 | case TextureFormat::A8: | 276 | case TextureFormat::A8: |
| 277 | case TextureFormat::IA4: | 277 | case TextureFormat::IA4: |
| 278 | default: // placeholder for yet unknown formats | ||
| 279 | return 2; | 278 | return 2; |
| 279 | |||
| 280 | default: // placeholder for yet unknown formats | ||
| 281 | UNIMPLEMENTED(); | ||
| 282 | return 0; | ||
| 280 | } | 283 | } |
| 281 | } | 284 | } |
| 282 | 285 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 4167d3161..60380257a 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | |||
| @@ -342,9 +342,8 @@ CachedSurface* RasterizerCacheOpenGL::GetSurface(const CachedSurface& params, bo | |||
| 342 | Pica::Texture::TextureInfo tex_info; | 342 | Pica::Texture::TextureInfo tex_info; |
| 343 | tex_info.width = params.width; | 343 | tex_info.width = params.width; |
| 344 | tex_info.height = params.height; | 344 | tex_info.height = params.height; |
| 345 | tex_info.stride = | ||
| 346 | params.width * CachedSurface::GetFormatBpp(params.pixel_format) / 8; | ||
| 347 | tex_info.format = (Pica::Regs::TextureFormat)params.pixel_format; | 345 | tex_info.format = (Pica::Regs::TextureFormat)params.pixel_format; |
| 346 | tex_info.SetDefaultStride(); | ||
| 348 | tex_info.physical_address = params.addr; | 347 | tex_info.physical_address = params.addr; |
| 349 | 348 | ||
| 350 | for (unsigned y = 0; y < params.height; ++y) { | 349 | for (unsigned y = 0; y < params.height; ++y) { |
diff --git a/src/video_core/texture/texture_decode.cpp b/src/video_core/texture/texture_decode.cpp index a3b05fe81..f13d6e577 100644 --- a/src/video_core/texture/texture_decode.cpp +++ b/src/video_core/texture/texture_decode.cpp | |||
| @@ -9,52 +9,104 @@ | |||
| 9 | #include "common/logging/log.h" | 9 | #include "common/logging/log.h" |
| 10 | #include "common/math_util.h" | 10 | #include "common/math_util.h" |
| 11 | #include "common/vector_math.h" | 11 | #include "common/vector_math.h" |
| 12 | #include "video_core/pica.h" | ||
| 12 | #include "video_core/texture/texture_decode.h" | 13 | #include "video_core/texture/texture_decode.h" |
| 13 | #include "video_core/utils.h" | 14 | #include "video_core/utils.h" |
| 14 | 15 | ||
| 16 | using TextureFormat = Pica::Regs::TextureFormat; | ||
| 17 | |||
| 15 | namespace Pica { | 18 | namespace Pica { |
| 16 | namespace Texture { | 19 | namespace Texture { |
| 17 | 20 | ||
| 18 | Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const TextureInfo& info, | 21 | constexpr size_t TILE_SIZE = 8 * 8; |
| 19 | bool disable_alpha) { | 22 | constexpr size_t ETC1_SUBTILES = 2 * 2; |
| 20 | const unsigned int coarse_x = x & ~7; | 23 | |
| 21 | const unsigned int coarse_y = y & ~7; | 24 | size_t CalculateTileSize(TextureFormat format) { |
| 25 | switch (format) { | ||
| 26 | case TextureFormat::RGBA8: | ||
| 27 | return 4 * TILE_SIZE; | ||
| 28 | |||
| 29 | case TextureFormat::RGB8: | ||
| 30 | return 3 * TILE_SIZE; | ||
| 31 | |||
| 32 | case TextureFormat::RGB5A1: | ||
| 33 | case TextureFormat::RGB565: | ||
| 34 | case TextureFormat::RGBA4: | ||
| 35 | case TextureFormat::IA8: | ||
| 36 | case TextureFormat::RG8: | ||
| 37 | return 2 * TILE_SIZE; | ||
| 38 | |||
| 39 | case TextureFormat::I8: | ||
| 40 | case TextureFormat::A8: | ||
| 41 | case TextureFormat::IA4: | ||
| 42 | return 1 * TILE_SIZE; | ||
| 43 | |||
| 44 | case TextureFormat::I4: | ||
| 45 | case TextureFormat::A4: | ||
| 46 | return TILE_SIZE / 2; | ||
| 47 | |||
| 48 | case TextureFormat::ETC1: | ||
| 49 | return ETC1_SUBTILES * 8; | ||
| 50 | |||
| 51 | case TextureFormat::ETC1A4: | ||
| 52 | return ETC1_SUBTILES * 16; | ||
| 22 | 53 | ||
| 23 | if (info.format != Regs::TextureFormat::ETC1 && info.format != Regs::TextureFormat::ETC1A4) { | 54 | default: // placeholder for yet unknown formats |
| 24 | // TODO(neobrain): Fix code design to unify vertical block offsets! | 55 | UNIMPLEMENTED(); |
| 25 | source += coarse_y * info.stride; | 56 | return 0; |
| 26 | } | 57 | } |
| 58 | } | ||
| 59 | |||
| 60 | Math::Vec4<u8> LookupTexture(const u8* source, unsigned int x, unsigned int y, | ||
| 61 | const TextureInfo& info, bool disable_alpha) { | ||
| 62 | // Coordinate in tiles | ||
| 63 | const unsigned int coarse_x = x / 8; | ||
| 64 | const unsigned int coarse_y = y / 8; | ||
| 27 | 65 | ||
| 28 | // TODO: Assert that width/height are multiples of block dimensions | 66 | // Coordinate inside the tile |
| 67 | const unsigned int fine_x = x % 8; | ||
| 68 | const unsigned int fine_y = y % 8; | ||
| 69 | |||
| 70 | const u8* line = source + coarse_y * info.stride; | ||
| 71 | const u8* tile = line + coarse_x * CalculateTileSize(info.format); | ||
| 72 | return LookupTexelInTile(tile, fine_x, fine_y, info, disable_alpha); | ||
| 73 | } | ||
| 74 | |||
| 75 | Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int y, | ||
| 76 | const TextureInfo& info, bool disable_alpha) { | ||
| 77 | DEBUG_ASSERT(x < 8); | ||
| 78 | DEBUG_ASSERT(y < 8); | ||
| 79 | |||
| 80 | using VideoCore::MortonInterleave; | ||
| 29 | 81 | ||
| 30 | switch (info.format) { | 82 | switch (info.format) { |
| 31 | case Regs::TextureFormat::RGBA8: { | 83 | case Regs::TextureFormat::RGBA8: { |
| 32 | auto res = Color::DecodeRGBA8(source + VideoCore::GetMortonOffset(x, y, 4)); | 84 | auto res = Color::DecodeRGBA8(source + MortonInterleave(x, y) * 4); |
| 33 | return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())}; | 85 | return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())}; |
| 34 | } | 86 | } |
| 35 | 87 | ||
| 36 | case Regs::TextureFormat::RGB8: { | 88 | case Regs::TextureFormat::RGB8: { |
| 37 | auto res = Color::DecodeRGB8(source + VideoCore::GetMortonOffset(x, y, 3)); | 89 | auto res = Color::DecodeRGB8(source + MortonInterleave(x, y) * 3); |
| 38 | return {res.r(), res.g(), res.b(), 255}; | 90 | return {res.r(), res.g(), res.b(), 255}; |
| 39 | } | 91 | } |
| 40 | 92 | ||
| 41 | case Regs::TextureFormat::RGB5A1: { | 93 | case Regs::TextureFormat::RGB5A1: { |
| 42 | auto res = Color::DecodeRGB5A1(source + VideoCore::GetMortonOffset(x, y, 2)); | 94 | auto res = Color::DecodeRGB5A1(source + MortonInterleave(x, y) * 2); |
| 43 | return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())}; | 95 | return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())}; |
| 44 | } | 96 | } |
| 45 | 97 | ||
| 46 | case Regs::TextureFormat::RGB565: { | 98 | case Regs::TextureFormat::RGB565: { |
| 47 | auto res = Color::DecodeRGB565(source + VideoCore::GetMortonOffset(x, y, 2)); | 99 | auto res = Color::DecodeRGB565(source + MortonInterleave(x, y) * 2); |
| 48 | return {res.r(), res.g(), res.b(), 255}; | 100 | return {res.r(), res.g(), res.b(), 255}; |
| 49 | } | 101 | } |
| 50 | 102 | ||
| 51 | case Regs::TextureFormat::RGBA4: { | 103 | case Regs::TextureFormat::RGBA4: { |
| 52 | auto res = Color::DecodeRGBA4(source + VideoCore::GetMortonOffset(x, y, 2)); | 104 | auto res = Color::DecodeRGBA4(source + MortonInterleave(x, y) * 2); |
| 53 | return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())}; | 105 | return {res.r(), res.g(), res.b(), static_cast<u8>(disable_alpha ? 255 : res.a())}; |
| 54 | } | 106 | } |
| 55 | 107 | ||
| 56 | case Regs::TextureFormat::IA8: { | 108 | case Regs::TextureFormat::IA8: { |
| 57 | const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 2); | 109 | const u8* source_ptr = source + MortonInterleave(x, y) * 2; |
| 58 | 110 | ||
| 59 | if (disable_alpha) { | 111 | if (disable_alpha) { |
| 60 | // Show intensity as red, alpha as green | 112 | // Show intensity as red, alpha as green |
| @@ -65,17 +117,17 @@ Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const TextureInfo& | |||
| 65 | } | 117 | } |
| 66 | 118 | ||
| 67 | case Regs::TextureFormat::RG8: { | 119 | case Regs::TextureFormat::RG8: { |
| 68 | auto res = Color::DecodeRG8(source + VideoCore::GetMortonOffset(x, y, 2)); | 120 | auto res = Color::DecodeRG8(source + MortonInterleave(x, y) * 2); |
| 69 | return {res.r(), res.g(), 0, 255}; | 121 | return {res.r(), res.g(), 0, 255}; |
| 70 | } | 122 | } |
| 71 | 123 | ||
| 72 | case Regs::TextureFormat::I8: { | 124 | case Regs::TextureFormat::I8: { |
| 73 | const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 1); | 125 | const u8* source_ptr = source + MortonInterleave(x, y); |
| 74 | return {*source_ptr, *source_ptr, *source_ptr, 255}; | 126 | return {*source_ptr, *source_ptr, *source_ptr, 255}; |
| 75 | } | 127 | } |
| 76 | 128 | ||
| 77 | case Regs::TextureFormat::A8: { | 129 | case Regs::TextureFormat::A8: { |
| 78 | const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 1); | 130 | const u8* source_ptr = source + MortonInterleave(x, y); |
| 79 | 131 | ||
| 80 | if (disable_alpha) { | 132 | if (disable_alpha) { |
| 81 | return {*source_ptr, *source_ptr, *source_ptr, 255}; | 133 | return {*source_ptr, *source_ptr, *source_ptr, 255}; |
| @@ -85,7 +137,7 @@ Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const TextureInfo& | |||
| 85 | } | 137 | } |
| 86 | 138 | ||
| 87 | case Regs::TextureFormat::IA4: { | 139 | case Regs::TextureFormat::IA4: { |
| 88 | const u8* source_ptr = source + VideoCore::GetMortonOffset(x, y, 1); | 140 | const u8* source_ptr = source + MortonInterleave(x, y); |
| 89 | 141 | ||
| 90 | u8 i = Color::Convert4To8(((*source_ptr) & 0xF0) >> 4); | 142 | u8 i = Color::Convert4To8(((*source_ptr) & 0xF0) >> 4); |
| 91 | u8 a = Color::Convert4To8((*source_ptr) & 0xF); | 143 | u8 a = Color::Convert4To8((*source_ptr) & 0xF); |
| @@ -99,7 +151,7 @@ Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const TextureInfo& | |||
| 99 | } | 151 | } |
| 100 | 152 | ||
| 101 | case Regs::TextureFormat::I4: { | 153 | case Regs::TextureFormat::I4: { |
| 102 | u32 morton_offset = VideoCore::GetMortonOffset(x, y, 1); | 154 | u32 morton_offset = MortonInterleave(x, y); |
| 103 | const u8* source_ptr = source + morton_offset / 2; | 155 | const u8* source_ptr = source + morton_offset / 2; |
| 104 | 156 | ||
| 105 | u8 i = (morton_offset % 2) ? ((*source_ptr & 0xF0) >> 4) : (*source_ptr & 0xF); | 157 | u8 i = (morton_offset % 2) ? ((*source_ptr & 0xF0) >> 4) : (*source_ptr & 0xF); |
| @@ -109,7 +161,7 @@ Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const TextureInfo& | |||
| 109 | } | 161 | } |
| 110 | 162 | ||
| 111 | case Regs::TextureFormat::A4: { | 163 | case Regs::TextureFormat::A4: { |
| 112 | u32 morton_offset = VideoCore::GetMortonOffset(x, y, 1); | 164 | u32 morton_offset = MortonInterleave(x, y); |
| 113 | const u8* source_ptr = source + morton_offset / 2; | 165 | const u8* source_ptr = source + morton_offset / 2; |
| 114 | 166 | ||
| 115 | u8 a = (morton_offset % 2) ? ((*source_ptr & 0xF0) >> 4) : (*source_ptr & 0xF); | 167 | u8 a = (morton_offset % 2) ? ((*source_ptr & 0xF0) >> 4) : (*source_ptr & 0xF); |
| @@ -127,15 +179,15 @@ Math::Vec4<u8> LookupTexture(const u8* source, int x, int y, const TextureInfo& | |||
| 127 | bool has_alpha = (info.format == Regs::TextureFormat::ETC1A4); | 179 | bool has_alpha = (info.format == Regs::TextureFormat::ETC1A4); |
| 128 | 180 | ||
| 129 | // ETC1 further subdivides each 8x8 tile into four 4x4 subtiles | 181 | // ETC1 further subdivides each 8x8 tile into four 4x4 subtiles |
| 130 | const int subtile_width = 4; | 182 | constexpr unsigned int subtile_width = 4; |
| 131 | const int subtile_height = 4; | 183 | constexpr unsigned int subtile_height = 4; |
| 184 | |||
| 185 | unsigned int subtile_index = (x / subtile_width) + 2 * (y / subtile_height); | ||
| 186 | size_t subtile_size = has_alpha ? 16 : 8; | ||
| 132 | 187 | ||
| 133 | int subtile_index = ((x / subtile_width) & 1) + 2 * ((y / subtile_height) & 1); | 188 | // TODO(yuriks): Use memcpy instead of reinterpret_cast |
| 134 | unsigned subtile_bytes = has_alpha ? 2 : 1; // TODO: Name... | 189 | const u64* source_ptr = reinterpret_cast<const u64*>(source + subtile_index * subtile_size); |
| 135 | 190 | ||
| 136 | const u64* source_ptr = (const u64*)(source + coarse_x * subtile_bytes * 4 + | ||
| 137 | coarse_y * subtile_bytes * 4 * (info.width / 8) + | ||
| 138 | subtile_index * subtile_bytes * 8); | ||
| 139 | u64 alpha = 0xFFFFFFFFFFFFFFFF; | 191 | u64 alpha = 0xFFFFFFFFFFFFFFFF; |
| 140 | if (has_alpha) { | 192 | if (has_alpha) { |
| 141 | alpha = *source_ptr; | 193 | alpha = *source_ptr; |
| @@ -262,7 +314,7 @@ TextureInfo TextureInfo::FromPicaRegister(const Regs::TextureConfig& config, | |||
| 262 | info.width = config.width; | 314 | info.width = config.width; |
| 263 | info.height = config.height; | 315 | info.height = config.height; |
| 264 | info.format = format; | 316 | info.format = format; |
| 265 | info.stride = Pica::Regs::NibblesPerPixel(info.format) * info.width / 2; | 317 | info.SetDefaultStride(); |
| 266 | return info; | 318 | return info; |
| 267 | } | 319 | } |
| 268 | 320 | ||
diff --git a/src/video_core/texture/texture_decode.h b/src/video_core/texture/texture_decode.h index 0c1438b0f..5c636939a 100644 --- a/src/video_core/texture/texture_decode.h +++ b/src/video_core/texture/texture_decode.h | |||
| @@ -11,21 +11,29 @@ | |||
| 11 | namespace Pica { | 11 | namespace Pica { |
| 12 | namespace Texture { | 12 | namespace Texture { |
| 13 | 13 | ||
| 14 | /// Returns the byte size of a 8*8 tile of the specified texture format. | ||
| 15 | size_t CalculateTileSize(Pica::Regs::TextureFormat format); | ||
| 16 | |||
| 14 | struct TextureInfo { | 17 | struct TextureInfo { |
| 15 | PAddr physical_address; | 18 | PAddr physical_address; |
| 16 | int width; | 19 | unsigned int width; |
| 17 | int height; | 20 | unsigned int height; |
| 18 | int stride; | 21 | ptrdiff_t stride; |
| 19 | Pica::Regs::TextureFormat format; | 22 | Pica::Regs::TextureFormat format; |
| 20 | 23 | ||
| 21 | static TextureInfo FromPicaRegister(const Pica::Regs::TextureConfig& config, | 24 | static TextureInfo FromPicaRegister(const Pica::Regs::TextureConfig& config, |
| 22 | const Pica::Regs::TextureFormat& format); | 25 | const Pica::Regs::TextureFormat& format); |
| 26 | |||
| 27 | /// Calculates stride from format and width, assuming that the entire texture is contiguous. | ||
| 28 | void SetDefaultStride() { | ||
| 29 | stride = Pica::Texture::CalculateTileSize(format) * (width / 8); | ||
| 30 | } | ||
| 23 | }; | 31 | }; |
| 24 | 32 | ||
| 25 | /** | 33 | /** |
| 26 | * Lookup texel located at the given coordinates and return an RGBA vector of its color. | 34 | * Lookup texel located at the given coordinates and return an RGBA vector of its color. |
| 27 | * @param source Source pointer to read data from | 35 | * @param source Source pointer to read data from |
| 28 | * @param s,t Texture coordinates to read from | 36 | * @param x,y Texture coordinates to read from |
| 29 | * @param info TextureInfo object describing the texture setup | 37 | * @param info TextureInfo object describing the texture setup |
| 30 | * @param disable_alpha This is used for debug widgets which use this method to display textures | 38 | * @param disable_alpha This is used for debug widgets which use this method to display textures |
| 31 | * without providing a good way to visualize alpha by themselves. If true, this will return 255 for | 39 | * without providing a good way to visualize alpha by themselves. If true, this will return 255 for |
| @@ -33,8 +41,20 @@ struct TextureInfo { | |||
| 33 | * channel. | 41 | * channel. |
| 34 | * @todo Eventually we should get rid of the disable_alpha parameter. | 42 | * @todo Eventually we should get rid of the disable_alpha parameter. |
| 35 | */ | 43 | */ |
| 36 | Math::Vec4<u8> LookupTexture(const u8* source, int s, int t, const TextureInfo& info, | 44 | Math::Vec4<u8> LookupTexture(const u8* source, unsigned int x, unsigned int y, |
| 37 | bool disable_alpha = false); | 45 | const TextureInfo& info, bool disable_alpha = false); |
| 46 | |||
| 47 | /** | ||
| 48 | * Looks up a texel from a single 8x8 texture tile. | ||
| 49 | * | ||
| 50 | * @param source Pointer to the beginning of the tile. | ||
| 51 | * @param x, y In-tile coordinates to read from. Must be < 8. | ||
| 52 | * @param info TextureInfo describing the texture format. | ||
| 53 | * @param disable_alpha Used for debugging. Sets the result alpha to 255 and either discards the | ||
| 54 | * real alpha or inserts it in an otherwise unused channel. | ||
| 55 | */ | ||
| 56 | Math::Vec4<u8> LookupTexelInTile(const u8* source, unsigned int x, unsigned int y, | ||
| 57 | const TextureInfo& info, bool disable_alpha); | ||
| 38 | 58 | ||
| 39 | } // namespace Texture | 59 | } // namespace Texture |
| 40 | } // namespace Pica | 60 | } // namespace Pica |