initial add

This commit is contained in:
2025-12-11 10:37:41 -06:00
commit 37ffac585f
18 changed files with 13695 additions and 0 deletions

133
dxt.c Normal file
View File

@@ -0,0 +1,133 @@
#include "cell.h"
#include <string.h>
#include <stdint.h>
#include <stdlib.h>
#define STB_DXT_IMPLEMENTATION
#include "stb_dxt.h"
// Helper function to map DXT compression types to pixel format strings
static const char* get_dxt_format_string(int type)
{
switch (type) {
case 1: return "bc1";
case 3: return "bc2";
case 5: return "bc3";
default: return "bc3";
}
}
// DXT compression/encoding
JSValue js_dxt_encode(JSContext *js, JSValue this_val, int argc, JSValueConst *argv)
{
if (argc < 1)
return JS_ThrowTypeError(js, "dxt.encode requires an image object");
JSValue width_val = JS_GetPropertyStr(js, argv[0], "width");
JSValue height_val = JS_GetPropertyStr(js, argv[0], "height");
if (JS_IsNull(width_val) || JS_IsNull(height_val)) {
JS_FreeValue(js, width_val);
JS_FreeValue(js, height_val);
return JS_ThrowTypeError(js, "dxt.encode requires width and height properties");
}
int width, height;
if (JS_ToInt32(js, &width, width_val) < 0 || JS_ToInt32(js, &height, height_val) < 0) {
JS_FreeValue(js, width_val);
JS_FreeValue(js, height_val);
return JS_ThrowTypeError(js, "width and height must be numbers");
}
JS_FreeValue(js, width_val);
JS_FreeValue(js, height_val);
if (width < 4 || height < 4)
return JS_ThrowRangeError(js, "width and height must be at least 4 for DXT compression");
// Dimensions must be multiples of 4
if (width % 4 != 0 || height % 4 != 0)
return JS_ThrowRangeError(js, "width and height must be multiples of 4 for DXT compression");
JSValue pixels_val = JS_GetPropertyStr(js, argv[0], "pixels");
size_t pixel_len;
void *pixel_data = js_get_blob_data(js, &pixel_len, pixels_val);
JS_FreeValue(js, pixels_val);
if (pixel_data == NULL) return JS_EXCEPTION;
if (!pixel_data) return JS_ThrowTypeError(js, "pixels blob has no data");
size_t required_size = width * height * 4;
if (pixel_len < required_size)
return JS_ThrowRangeError(js, "pixels buffer too small (need %zu, got %zu)", required_size, pixel_len);
// Get compression options
int compression_type = 5; // Default DXT5/BC3
int high_quality = 1;
if (argc > 1 && JS_IsObject(argv[1])) {
JSValue type_val = JS_GetPropertyStr(js, argv[1], "type");
if (!JS_IsNull(type_val)) {
JS_ToInt32(js, &compression_type, type_val);
}
JS_FreeValue(js, type_val);
JSValue quality_val = JS_GetPropertyStr(js, argv[1], "high_quality");
if (!JS_IsNull(quality_val)) {
high_quality = JS_ToBool(js, quality_val);
}
JS_FreeValue(js, quality_val);
}
// Determine alpha mode based on compression type
int alpha_mode = (compression_type == 1) ? 0 : 1; // BC1=no alpha block, BC3=alpha block
int blocks_x = width / 4;
int blocks_y = height / 4;
int bytes_per_block = (alpha_mode == 0) ? 8 : 16;
size_t output_size = blocks_x * blocks_y * bytes_per_block;
void *output = malloc(output_size);
if (!output)
return JS_ThrowOutOfMemory(js);
int mode = high_quality ? STB_DXT_HIGHQUAL : STB_DXT_NORMAL;
for (int by = 0; by < blocks_y; by++) {
for (int bx = 0; bx < blocks_x; bx++) {
unsigned char block[64]; // 4x4 RGBA = 64 bytes
// Extract 4x4 block
for (int y = 0; y < 4; y++) {
for (int x = 0; x < 4; x++) {
int src_x = bx * 4 + x;
int src_y = by * 4 + y;
int src_idx = (src_y * width + src_x) * 4;
int dst_idx = (y * 4 + x) * 4;
block[dst_idx + 0] = ((unsigned char*)pixel_data)[src_idx + 0];
block[dst_idx + 1] = ((unsigned char*)pixel_data)[src_idx + 1];
block[dst_idx + 2] = ((unsigned char*)pixel_data)[src_idx + 2];
block[dst_idx + 3] = ((unsigned char*)pixel_data)[src_idx + 3];
}
}
int output_idx = (by * blocks_x + bx) * bytes_per_block;
stb_compress_dxt_block(((unsigned char*)output) + output_idx, block, alpha_mode, mode);
}
}
JSValue result = JS_NewObject(js);
JS_SetPropertyStr(js, result, "width", JS_NewInt32(js, width));
JS_SetPropertyStr(js, result, "height", JS_NewInt32(js, height));
JS_SetPropertyStr(js, result, "format", JS_NewString(js, get_dxt_format_string(compression_type)));
JS_SetPropertyStr(js, result, "compression", JS_NewInt32(js, compression_type));
JS_SetPropertyStr(js, result, "pixels", js_new_blob_stoned_copy(js, output, output_size));
free(output);
return result;
}
static const JSCFunctionListEntry js_dxt_funcs[] = {
MIST_FUNC_DEF(dxt, encode, 2)
};
CELL_USE_FUNCS(js_dxt_funcs)