Giới Thiệu
Bài viết này dành cho các developer C/C++ muốn tích hợp trực tiếp thư viện Console-Swizzler vào dự án của mình để swizzle hoặc unswizzle texture DDS theo cách programmatic – thay vì dùng công cụ dòng lệnh.
Đây là tài liệu tham khảo thực hành, tập trung vào cách sử dụng các API chính, xử lý lỗi đúng cách và các pattern phổ biến trong thực tế.
Kiến Trúc API: Context-Based Design
Console-Swizzler sử dụng pattern context-based API – một thiết kế phổ biến và an toàn trong các thư viện C. Thay vì dùng biến global, mọi trạng thái đều được đóng gói trong một struct SwizContext. Điều này giúp:
- Thread-safe: Mỗi thread có thể có context riêng.
- Tái sử dụng: Một context có thể tái sử dụng cho nhiều texture cùng cấu hình.
- Dễ debug: Tất cả trạng thái nằm trong một object rõ ràng.
Vòng Đời Của SwizContext
swizNewContext()
→ cấu hình context (platform, size, block info...)
→ swizDoSwizzle() hoặc swizDoUnswizzle()
→ [tái sử dụng nếu cần]
→ swizFreeContext()Các Hàm API Chính
Tạo và Hủy Context
c
// Tạo một context mới. Luôn trả về non-NULL hoặc abort nếu hết bộ nhớ.
SwizContext *swizNewContext(void);
// Giải phóng bộ nhớ của context. Luôn gọi khi không còn dùng.
void swizFreeContext(SwizContext *context);Cấu Hình Context
c
// Chọn nền tảng: SWIZ_PLATFORM_PS4 hoặc SWIZ_PLATFORM_SWITCH
void swizContextSetPlatform(SwizContext *context, SwizPlatform platform);
// Kích thước texture theo pixel
void swizContextSetTextureSize(SwizContext *context, uint32_t width, uint32_t height);
// Có mipmaps trong data hay không (0 hoặc 1)
void swizContextSetHasMips(SwizContext *context, int hasMips);
// Thông tin về compression block
// block_width, block_height: kích thước block (thường 4x4 với DXT/BC)
// bytes_per_block: số byte mỗi block (BC1=8, BC3/BC5/BC7=16, v.v.)
void swizContextSetBlockInfo(SwizContext *context,
uint32_t block_width,
uint32_t block_height,
uint32_t bytes_per_block);
// Chỉ cho Nintendo Switch: giá trị gobs_height (1,2,4,8,16,32)
void swizContextSetGobsHeight(SwizContext *context, uint32_t gobs_height);Tính Kích Thước Buffer
c
// Kích thước của swizzled data (bao gồm mips nếu có)
uint32_t swizGetSwizzledSize(SwizContext *context);
// Kích thước của unswizzled data
uint32_t swizGetUnswizzledSize(SwizContext *context);
// Tiện ích: allocate buffer cho unswizzled data (malloc bên trong, caller phải free)
uint8_t *swizAllocUnswizzledData(SwizContext *context);Thực Hiện Swizzle/Unswizzle
c
// Swizzle: raw_data → swizzled_data
SwizError swizDoSwizzle(const uint8_t *raw_data,
uint8_t *swizzled_data,
SwizContext *context);
// Unswizzle: swizzled_data → unswizzled_data
SwizError swizDoUnswizzle(const uint8_t *swizzled_data,
uint8_t *unswizzled_data,
SwizContext *context);Xử Lý Lỗi
c
// Lấy message lỗi có thể đọc được
const char *swizGetErrorMessage(SwizError error);Thông Tin Block Cho Các Định Dạng Phổ Biến
Đây là phần hay bị nhầm lẫn nhất. Bảng sau tóm tắt swizContextSetBlockInfo() cho các định dạng texture phổ biến:
| Định dạng DDS | block_width | block_height | bytes_per_block |
|---|---|---|---|
| BC1 (DXT1) | 4 | 4 | 8 |
| BC2 (DXT3) | 4 | 4 | 16 |
| BC3 (DXT5) | 4 | 4 | 16 |
| BC4 (ATI1) | 4 | 4 | 8 |
| BC5 (ATI2) | 4 | 4 | 16 |
| BC6H | 4 | 4 | 16 |
| BC7 | 4 | 4 | 16 |
| R8G8B8A8 (uncompressed) | 1 | 1 | 4 |
| R16G16B16A16F | 1 | 1 | 8 |
Pattern Thực Tế: Hàm Tiện Ích Unswizzle
Trong thực tế, bạn có thể đóng gói logic trên thành một hàm tái sử dụng:
c
#include "console-swizzler.h"
#include <stdlib.h>
#include <stdio.h>
typedef struct {
uint8_t *data;
uint32_t size;
} TextureBuffer;
/**
* Unswizzle texture PS4.
* @param swizzled Buffer chứa dữ liệu đã swizzle
* @param size Kích thước buffer
* @param width Chiều rộng texture
* @param height Chiều cao texture
* @param has_mips 1 nếu có mipmaps
* @param bw/bh/bpb Block info
* @return TextureBuffer (caller phải free .data), hoặc {NULL, 0} nếu lỗi
*/TextureBuffer unswizzle_ps4(
const uint8_t *swizzled, uint32_t size,
uint32_t width, uint32_t height, int has_mips,
uint32_t bw, uint32_t bh, uint32_t bpb)
{
TextureBuffer result = {NULL, 0};
SwizContext *ctx = swizNewContext();
swizContextSetPlatform(ctx, SWIZ_PLATFORM_PS4);
swizContextSetTextureSize(ctx, width, height);
swizContextSetHasMips(ctx, has_mips);
swizContextSetBlockInfo(ctx, bw, bh, bpb);
if (size < swizGetSwizzledSize(ctx)) {
fprintf(stderr, "[SwizError] Buffer quá nhỏ: cần %u, có %u\n",
swizGetSwizzledSize(ctx), size);
swizFreeContext(ctx);
return result;
}
result.data = swizAllocUnswizzledData(ctx);
result.size = swizGetUnswizzledSize(ctx);
SwizError err = swizDoUnswizzle(swizzled, result.data, ctx);
if (err != SWIZ_OK) {
fprintf(stderr, "[SwizError] %s\n", swizGetErrorMessage(err));
free(result.data);
result.data = NULL;
result.size = 0;
}
swizFreeContext(ctx);
return result;
}Best Practices Khi Tích Hợp Console-Swizzler
1. Luôn kiểm tra kích thước buffer trước khi unswizzle
Gọi swizGetSwizzledSize() và so sánh với kích thước thực tế của dữ liệu. Bỏ qua bước này có thể gây đọc ngoài vùng nhớ hợp lệ.
2. Giải phóng context ngay khi xong
swizFreeContext() phải được gọi trong mọi nhánh code, kể cả khi có lỗi. Cân nhắc dùng goto cleanup pattern trong C để đảm bảo điều này.
3. Không tái sử dụng context với cấu hình khác mà không reset
Nếu muốn xử lý texture có kích thước khác, hãy tạo context mới thay vì sửa context cũ giữa chừng.
4. Đối với Nintendo Switch, xác định đúng gobs_height
Luôn kiểm tra engine của game để chọn giá trị phù hợp. Dùng sai giá trị sẽ cho texture méo nhưng không có thông báo lỗi vì đây là lỗi logic chứ không phải lỗi kỹ thuật.
5. Xử lý swizAllocUnswizzledData có thể trả về NULL
Trong điều kiện bộ nhớ thấp cực đoan, hàm này có thể trả về NULL. Kiểm tra trước khi dùng.
Tham Chiếu Tài Liệu Đầy Đủ
Để xem toàn bộ danh sách hàm và các struct, tham khảo hai trang tài liệu chính thức:
- SwizContext Struct Reference – Toàn bộ hàm cấu hình context
- console-swizzler.h File Reference – Các hàm tiện ích, enum và định nghĩa còn lại
Cả hai đều có trên trang tài liệu tại matyamod.github.io/Console-Swizzler.
Kết Luận
API của Console-Swizzler được thiết kế với triết lý rõ ràng: đơn giản, an toàn và có thể mở rộng. Pattern context-based giúp dễ tích hợp vào bất kỳ dự án C/C++ nào, từ tool nhỏ đến ứng dụng xử lý hàng loạt texture. Với hỗ trợ PS4 và Nintendo Switch cùng tài liệu đầy đủ, Console-Swizzler là lựa chọn đáng tin cậy cho mọi bài toán swizzle texture game console.
