remove assimp dependency

This commit is contained in:
2025-01-06 12:26:58 -06:00
parent 246ef7a566
commit cd9bafd1c1
4 changed files with 243 additions and 191 deletions

View File

@@ -73,7 +73,6 @@ deps += dependency('qjs-layout',static:true)
deps += dependency('qjs-nota',static:true)
deps += dependency('qjs-miniz',static:true)
deps += dependency('qjs-soloud',static:true)
deps += dependency('assimp')
deps += dependency('physfs')
#deps += dependency('opencv4')

View File

@@ -275,7 +275,7 @@ function make_pipeline(pipeline) {
pipeline.gpu = render._main.make_pipeline(pipeline);
}
var shader_type = "msl";
var shader_type;
function make_shader(sh_file) {
var file = `shaders/${shader_type}/${sh_file}.${shader_type}`
@@ -492,6 +492,10 @@ pipeline_model.fragment = "model.frag"
var quad_model;
render.init = function () {
shader_type = render._main.shader_format()[0];
console.log(render._main.shader_format())
console.log(`shader format ${shader_type}`)
std_sampler = render._main.make_sampler({
min_filter: "nearest",
mag_filter: "nearest",
@@ -1194,7 +1198,7 @@ try{
}
};
if (dmon) dmon.watch('.');
//if (dmon) dmon.watch('.');
function dmon_cb(e)
{

View File

@@ -8,26 +8,26 @@ mkdir -p reflection
# Vertex shaders
for filename in *.vert.hlsl; do
if [ -f "$filename" ]; then echo "compiling ${filename}"
dxc -spirv -T vs_6_0 -Fo "spirv/${filename/.hlsl/.spv}" "$filename"
spirv-cross "spirv/${filename/.hlsl/.spv}" --msl > "msl/${filename/.hlsl/.msl}"
spirv-cross "spirv/${filename/.hlsl/.spv}" --reflect > "reflection/${filename/.hlsl/.json}"
dxc -spirv -T vs_6_0 -Fo "spv/${filename/.hlsl/.spv}" "$filename"
spirv-cross "spv/${filename/.hlsl/.spv}" --msl > "msl/${filename/.hlsl/.msl}"
spirv-cross "spv/${filename/.hlsl/.spv}" --reflect > "reflection/${filename/.hlsl/.json}"
fi
done
# Fragment shaders
for filename in *.frag.hlsl; do
if [ -f "$filename" ]; then echo "compiling ${filename}"
dxc -spirv -T ps_6_0 -Fo "spirv/${filename/.hlsl/.spv}" "$filename"
spirv-cross "spirv/${filename/.hlsl/.spv}" --msl > "msl/${filename/.hlsl/.msl}"
spirv-cross "spirv/${filename/.hlsl/.spv}" --reflect > "reflection/${filename/.hlsl/.json}"
dxc -spirv -T ps_6_0 -Fo "spv/${filename/.hlsl/.spv}" "$filename"
spirv-cross "spv/${filename/.hlsl/.spv}" --msl > "msl/${filename/.hlsl/.msl}"
spirv-cross "spv/${filename/.hlsl/.spv}" --reflect > "reflection/${filename/.hlsl/.json}"
fi
done
# Compute shaders
for filename in *.comp.hlsl; do
if [ -f "$filename" ]; then echo "compiling ${filename}"
dxc -spirv -T cs_6_0 -Fo "spirv/${filename/.hlsl/.spv}" "$filename"
spirv-cross "spirv/${filename/.hlsl/.spv}" --msl > "msl/${filename/.hlsl/.msl}"
spirv-cross "spirv/${filename/.hlsl/.spv}" --reflect > "reflection/${filename/.hlsl/.json}"
dxc -spirv -T cs_6_0 -Fo "spv/${filename/.hlsl/.spv}" "$filename"
spirv-cross "spv/${filename/.hlsl/.spv}" --msl > "msl/${filename/.hlsl/.msl}"
spirv-cross "spv/${filename/.hlsl/.spv}" --reflect > "reflection/${filename/.hlsl/.json}"
fi
done

View File

@@ -30,10 +30,6 @@
#include "cgltf.h"
#include "physfs.h"
#include <assimp/cimport.h>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include <SDL3/SDL.h>
#include <SDL3/SDL_gpu.h>
#include <SDL3/SDL_error.h>
@@ -2010,7 +2006,7 @@ JSC_SCALL(SDL_Window_make_renderer,
JSC_SCALL(SDL_Window_make_gpu,
SDL_Window *win = js2SDL_Window(js,self);
SDL_GPUDevice *gpu = SDL_CreateGPUDevice(SDL_GPU_SHADERFORMAT_SPIRV | SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_MSL, 1, NULL);
SDL_GPUDevice *gpu = SDL_CreateGPUDevice(SDL_GPU_SHADERFORMAT_DXIL | SDL_GPU_SHADERFORMAT_MSL, 1, NULL);
global_gpu = gpu;
return SDL_GPUDevice2js(js,gpu);
@@ -2472,12 +2468,6 @@ JSC_CCALL(renderer_target,
}
)
#include "cgltf.h"
#include <math.h>
#include "cgltf.h"
#include <math.h>
static void generate_normals(float* positions, size_t vertex_count, uint16_t* indices, size_t index_count, int16_t* normal_data) {
// Initialize normals to zero
float* temp_normals = malloc(sizeof(float)*3*vertex_count);
@@ -4427,11 +4417,11 @@ JSC_CCALL(gpu_shader_format,
JSValue arr = JS_NewArray(js);
int i = 0;
if (fmt & SDL_GPU_SHADERFORMAT_PRIVATE) JS_SetPropertyUint32(js, arr, i++, JS_NewString(js, ".private"));
if (fmt & SDL_GPU_SHADERFORMAT_SPIRV) JS_SetPropertyUint32(js, arr, i++, JS_NewString(js, ".spv"));
if (fmt & SDL_GPU_SHADERFORMAT_DXBC) JS_SetPropertyUint32(js, arr, i++, JS_NewString(js, ".dxbc"));
if (fmt & SDL_GPU_SHADERFORMAT_DXIL) JS_SetPropertyUint32(js, arr, i++, JS_NewString(js, ".dxil"));
if (fmt & SDL_GPU_SHADERFORMAT_MSL) JS_SetPropertyUint32(js, arr, i++, JS_NewString(js, ".msl"));
if (fmt & SDL_GPU_SHADERFORMAT_METALLIB) JS_SetPropertyUint32(js, arr, i++, JS_NewString(js, ".metallib"));
if (fmt & SDL_GPU_SHADERFORMAT_SPIRV) JS_SetPropertyUint32(js, arr, i++, JS_NewString(js, "spv"));
if (fmt & SDL_GPU_SHADERFORMAT_DXBC) JS_SetPropertyUint32(js, arr, i++, JS_NewString(js, "dxbc"));
if (fmt & SDL_GPU_SHADERFORMAT_DXIL) JS_SetPropertyUint32(js, arr, i++, JS_NewString(js, "dxil"));
if (fmt & SDL_GPU_SHADERFORMAT_MSL) JS_SetPropertyUint32(js, arr, i++, JS_NewString(js, "msl"));
if (fmt & SDL_GPU_SHADERFORMAT_METALLIB) JS_SetPropertyUint32(js, arr, i++, JS_NewString(js, "metallib"));
return arr;
)
@@ -5940,183 +5930,242 @@ JSC_SCALL(os_system, return number2js(js,system(str)); )
JSC_SCALL(os_model_buffer,
int mesh_idx = 0;
const struct aiScene *scene = aiImportFile(
str,
aiProcess_Triangulate |
aiProcess_GenNormals |
aiProcess_GenUVCoords |
aiProcess_FlipUVs |
aiProcess_OptimizeMeshes |
aiProcess_JoinIdenticalVertices
);
if (!scene) {
JS_ThrowInternalError(js, "Failed to load model: %s", aiGetErrorString());
// Configure cgltf
cgltf_options options;
memset(&options, 0, sizeof(options));
// Parse the file
cgltf_data* data = NULL;
cgltf_result result = cgltf_parse_file(&options, str, &data);
if (result != cgltf_result_success) {
JS_ThrowInternalError(js, "Failed to load glTF model: parse error");
return JS_UNDEFINED;
}
if (mesh_idx < 0 || mesh_idx >= (int)scene->mNumMeshes) {
// Load any external buffers (bin files, images)
result = cgltf_load_buffers(&options, data, str);
if (result != cgltf_result_success) {
cgltf_free(data);
JS_ThrowInternalError(js, "Failed to load glTF model: buffer load error");
return JS_UNDEFINED;
}
// We only check for mesh_idx vs. the count of cgltf_data->meshes
// (though note that glTF organizes data in scenes, nodes, etc.,
// so you might want to handle multiple nodes or node->mesh references)
if (mesh_idx < 0 || mesh_idx >= (int)data->meshes_count) {
cgltf_free(data);
JS_ThrowInternalError(js, "Invalid mesh index");
aiReleaseImport(scene);
return JS_UNDEFINED;
}
JSValue materials[scene->mNumMaterials];
for (int i = 0; i < scene->mNumMaterials; i++) {
/*
Build an array of JS material objects, similar to your old code with Assimp.
For each cgltf_material in data->materials, we store something in materials[i].
This example only sets the "diffuse" property from the PBR base color texture.
More properties (metallic, roughness, etc.) can be added similarly.
*/
JSValue materials[data->materials_count];
for (int i = 0; i < (int)data->materials_count; i++) {
JSValue mat = JS_NewObject(js);
materials[i] = mat;
struct aiMaterial *aimat = scene->mMaterials[i];
struct aiString texPath;
if (aiGetMaterialTexture(aimat, aiTextureType_DIFFUSE, 0, &texPath,NULL,NULL,NULL,NULL,NULL,NULL) == AI_SUCCESS) {
if (texPath.data[0] != '*') {
JS_SetPropertyStr(js,mat,"diffuse", JS_NewString(js,texPath.data));
} else {
struct aiTexture *tex = scene->mTextures[atoi(texPath.data+1)];
if (tex->mHeight == 0) {
void *data = tex->pcData;
size_t size = tex->mWidth;
JS_SetPropertyStr(js,mat,"diffuse", JS_NewArrayBufferCopy(js,data,size));
} else {
size_t size = tex->mWidth*tex->mHeight*4;
void *data = tex->pcData;
JS_SetPropertyStr(js,mat,"diffuse", JS_NewArrayBufferCopy(js,data,size));
}
cgltf_material *cgmat = &data->materials[i];
// Grab the base color texture if it exists
cgltf_texture_view *bc_view = &cgmat->pbr_metallic_roughness.base_color_texture;
if (bc_view->texture && bc_view->texture->image) {
cgltf_image *img = bc_view->texture->image;
// If the image is an external URI
if (img->uri) {
// For glTF 2.0, this often points to a .png/.jpg
JS_SetPropertyStr(js, mat, "diffuse", JS_NewString(js, img->uri));
}
// If it's an embedded buffer view (e.g., "data:" or bufferView-based image)
else if (img->buffer_view) {
size_t size = img->buffer_view->size;
uint8_t *ptr = (uint8_t*)img->buffer_view->buffer->data + img->buffer_view->offset;
JS_SetPropertyStr(js, mat, "diffuse", JS_NewArrayBufferCopy(js, ptr, size));
}
}
}
// Create an array to hold all the models
JSValue ret_arr = JS_NewArray(js);
// Loop over all meshes
for (unsigned int m = 0; m < scene->mNumMeshes; m++) {
struct aiMesh *mesh = scene->mMeshes[m];
if (!mesh->mVertices) {
JS_ThrowInternalError(js, "Mesh %u has no vertices", m);
aiReleaseImport(scene);
return JS_UNDEFINED;
}
size_t num_verts = mesh->mNumVertices;
float *posdata = NULL;
float *normdata = NULL;
float *uvdata = NULL;
float *colordata = NULL;
Uint16 *indicesdata = NULL;
// Positions (float3)
posdata = malloc(sizeof(float)*3*num_verts);
for (size_t i = 0; i < num_verts; i++) {
posdata[i*3+0] = mesh->mVertices[i].x;
posdata[i*3+1] = mesh->mVertices[i].y;
posdata[i*3+2] = mesh->mVertices[i].z;
}
// Normals (float3)
if (mesh->mNormals) {
normdata = malloc(sizeof(float)*3*num_verts);
for (size_t i = 0; i < num_verts; i++) {
normdata[i*3+0] = mesh->mNormals[i].x;
normdata[i*3+1] = mesh->mNormals[i].y;
normdata[i*3+2] = mesh->mNormals[i].z;
}
} else {
normdata = malloc(sizeof(float)*3*num_verts);
for (size_t i = 0; i < num_verts; i++) {
normdata[i*3+0] = 0.0f;
normdata[i*3+1] = 0.0f;
normdata[i*3+2] = 1.0f;
}
}
// UVs (float2)
if (mesh->mTextureCoords[0]) {
uvdata = malloc(sizeof(float)*2*num_verts);
for (size_t i = 0; i < num_verts; i++) {
uvdata[i*2+0] = mesh->mTextureCoords[0][i].x;
uvdata[i*2+1] = mesh->mTextureCoords[0][i].y;
}
} else {
uvdata = malloc(sizeof(float)*2*num_verts);
for (size_t i = 0; i < num_verts; i++) {
uvdata[i*2+0] = 0.0f;
uvdata[i*2+1] = 0.0f;
}
}
// Colors (float4)
if (mesh->mColors[0]) {
colordata = malloc(sizeof(float)*4*num_verts);
for (size_t i = 0; i < num_verts; i++) {
colordata[i*4+0] = mesh->mColors[0][i].r;
colordata[i*4+1] = mesh->mColors[0][i].g;
colordata[i*4+2] = mesh->mColors[0][i].b;
colordata[i*4+3] = mesh->mColors[0][i].a;
}
} else {
colordata = malloc(sizeof(float)*4*num_verts);
for (size_t i = 0; i < num_verts; i++) {
colordata[i*4+0] = 1.0f;
colordata[i*4+1] = 1.0f;
colordata[i*4+2] = 1.0f;
colordata[i*4+3] = 1.0f;
}
}
// Indices
size_t num_faces = mesh->mNumFaces;
size_t index_count = num_faces * 3;
indicesdata = malloc(sizeof(Uint16)*index_count);
for (size_t i = 0; i < num_faces; i++) {
const struct aiFace *face = &mesh->mFaces[i];
indicesdata[i*3+0] = face->mIndices[0];
indicesdata[i*3+1] = face->mIndices[1];
indicesdata[i*3+2] = face->mIndices[2];
}
// Build a JS object for the mesh data
JSValue js_mesh = JS_NewObject(js);
// Positions
JS_SetProperty(js, js_mesh, pos_atom,
make_gpu_buffer(js, posdata, sizeof(float)*3*num_verts, JS_TYPED_ARRAY_FLOAT32, 3, 1, 0));
// UV
JS_SetProperty(js, js_mesh, uv_atom,
make_gpu_buffer(js, uvdata, sizeof(float)*2*num_verts, JS_TYPED_ARRAY_FLOAT32, 2, 1, 0));
// Color
JS_SetProperty(js, js_mesh, color_atom,
make_gpu_buffer(js, colordata, sizeof(float)*4*num_verts, JS_TYPED_ARRAY_FLOAT32, 4, 1, 0));
// Normal
JS_SetProperty(js, js_mesh, norm_atom,
make_gpu_buffer(js, normdata, sizeof(float)*3*num_verts, JS_TYPED_ARRAY_FLOAT32, 3, 1, 0));
// Indices
JS_SetProperty(js, js_mesh, indices_atom,
make_gpu_buffer(js, indicesdata, sizeof(Uint16)*index_count, JS_TYPED_ARRAY_UINT16, 0, 1, 1));
// Metadata
JS_SetProperty(js, js_mesh, vertices_atom, number2js(js, (double)num_verts));
JS_SetProperty(js, js_mesh, count_atom, number2js(js, (double)index_count));
// Build final "model" object with mesh + material
JSValue model_obj = JS_NewObject(js);
JS_SetPropertyStr(js, model_obj, "mesh", js_mesh);
JS_SetPropertyStr(js, model_obj, "material", JS_DupValue(js,materials[mesh->mMaterialIndex]));
// Place into our return array
JS_SetPropertyUint32(js, ret_arr, m, model_obj);
// Cleanup (per-mesh)
free(posdata);
free(normdata);
free(uvdata);
free(colordata);
free(indicesdata);
}
aiReleaseImport(scene);
// Create an array to hold all the "model" objects
JSValue ret_arr = JS_NewArray(js);
/*
Loop over all cgltf_meshes. Each mesh can contain multiple "primitives."
Each primitive can have different attributes (POSITION, NORMAL, etc.)
and references exactly one material.
*/
for (int m = 0; m < (int)data->meshes_count; m++) {
cgltf_mesh *cgmesh = &data->meshes[m];
// Go through each primitive in this mesh
for (int p = 0; p < (int)cgmesh->primitives_count; p++) {
cgltf_primitive *prim = &cgmesh->primitives[p];
if (!prim->attributes) {
// No attributes => no geometry
continue;
}
// We'll collect attribute data in arrays, just like with Assimp
float *posdata = NULL, *normdata = NULL, *uvdata = NULL, *colordata = NULL;
Uint16 *indicesdata = NULL;
size_t num_verts = 0;
size_t index_count = 0;
// Helper function to find an accessor by "POSITION", "NORMAL", "TEXCOORD_0", etc.
// We'll parse it below in parseAttributeFloat.
cgltf_accessor* findAccessor(cgltf_primitive* prim, const char* semantic) {
for (int a = 0; a < (int)prim->attributes_count; a++) {
if (prim->attributes[a].name && strcmp(prim->attributes[a].name, semantic) == 0)
return prim->attributes[a].data;
}
return NULL;
}
// parseAttributeFloat:
// read floats from a cgltf_accessor into outBuffer
// The 'stride' is how many floats we read per element (e.g. 3 for POSITION)
// Returns the number of elements read
size_t parseAttributeFloat(JSContext* js, cgltf_accessor* acc, float** outBuffer, int stride, float defaultVal) {
if (!acc) {
// If the attribute doesn't exist, fill default
size_t count = 0;
*outBuffer = NULL;
return count;
}
size_t count = acc->count;
size_t total_floats = count * stride;
*outBuffer = malloc(total_floats * sizeof(float));
if (!(*outBuffer)) return 0;
for (size_t i = 0; i < count; i++) {
float tmp[4] = { defaultVal, defaultVal, defaultVal, defaultVal };
cgltf_accessor_read_float(acc, i, tmp, 4);
// copy only 'stride' components
for (int c = 0; c < stride; c++)
(*outBuffer)[i*stride + c] = tmp[c];
}
return count;
}
// 1) POSITION
cgltf_accessor *accPos = findAccessor(prim, "POSITION");
num_verts = parseAttributeFloat(js, accPos, &posdata, 3, 0.0f);
// 2) NORMAL
cgltf_accessor *accNorm = findAccessor(prim, "NORMAL");
// If missing normals, default them to (0,0,1)
parseAttributeFloat(js, accNorm, &normdata, 3, 0.0f);
if (!normdata && num_verts > 0) {
normdata = malloc(num_verts*3*sizeof(float));
for (size_t i = 0; i < num_verts; i++) {
normdata[i*3+0] = 0.0f;
normdata[i*3+1] = 0.0f;
normdata[i*3+2] = 1.0f;
}
}
// 3) TEXCOORD_0
cgltf_accessor *accUV = findAccessor(prim, "TEXCOORD_0");
parseAttributeFloat(js, accUV, &uvdata, 2, 0.0f);
if (!uvdata && num_verts > 0) {
uvdata = malloc(num_verts*2*sizeof(float));
for (size_t i = 0; i < num_verts; i++) {
uvdata[i*2+0] = 0.0f;
uvdata[i*2+1] = 0.0f;
}
}
// 4) COLOR_0
cgltf_accessor *accColor = findAccessor(prim, "COLOR_0");
parseAttributeFloat(js, accColor, &colordata, 4, 1.0f);
if (!colordata && num_verts > 0) {
colordata = malloc(num_verts*4*sizeof(float));
for (size_t i = 0; i < num_verts; i++) {
colordata[i*4+0] = 1.0f;
colordata[i*4+1] = 1.0f;
colordata[i*4+2] = 1.0f;
colordata[i*4+3] = 1.0f;
}
}
// 5) Indices (if present)
if (prim->indices) {
cgltf_accessor *idxAcc = prim->indices;
index_count = idxAcc->count;
indicesdata = malloc(index_count*sizeof(Uint16));
if (indicesdata) {
for (size_t i = 0; i < index_count; i++) {
// cgltf_accessor_read_index can read the index as uint32_t
uint32_t val = 0;
val = cgltf_accessor_read_index(idxAcc, i);
// NOTE: if val > 65535, you'll need 32-bit index buffers
indicesdata[i] = (Uint16)val;
}
}
}
// Build a JS object for the mesh data
JSValue js_mesh = JS_NewObject(js);
// Positions
if (posdata && num_verts > 0)
JS_SetProperty(js, js_mesh, pos_atom,
make_gpu_buffer(js, posdata, sizeof(float)*3*num_verts, JS_TYPED_ARRAY_FLOAT32, 3, 1, 0));
// UV
if (uvdata && num_verts > 0)
JS_SetProperty(js, js_mesh, uv_atom,
make_gpu_buffer(js, uvdata, sizeof(float)*2*num_verts, JS_TYPED_ARRAY_FLOAT32, 2, 1, 0));
// Color
if (colordata && num_verts > 0)
JS_SetProperty(js, js_mesh, color_atom,
make_gpu_buffer(js, colordata, sizeof(float)*4*num_verts, JS_TYPED_ARRAY_FLOAT32, 4, 1, 0));
// Normal
if (normdata && num_verts > 0)
JS_SetProperty(js, js_mesh, norm_atom,
make_gpu_buffer(js, normdata, sizeof(float)*3*num_verts, JS_TYPED_ARRAY_FLOAT32, 3, 1, 0));
// Indices
if (indicesdata && index_count > 0)
JS_SetProperty(js, js_mesh, indices_atom,
make_gpu_buffer(js, indicesdata, sizeof(Uint16)*index_count, JS_TYPED_ARRAY_UINT16, 0, 1, 1));
// Metadata
JS_SetProperty(js, js_mesh, vertices_atom, number2js(js, (double)num_verts));
JS_SetProperty(js, js_mesh, count_atom, number2js(js, (double)index_count));
// Build final "model" object with mesh + material
JSValue model_obj = JS_NewObject(js);
JS_SetPropertyStr(js, model_obj, "mesh", js_mesh);
// Figure out the index of the material in data->materials. If prim->material is non-null,
// its index is `prim->material - data->materials`.
int mat_index = -1;
if (prim->material) mat_index = (int)(prim->material - data->materials);
if (mat_index >= 0 && mat_index < (int)data->materials_count)
JS_SetPropertyStr(js, model_obj, "material", JS_DupValue(js, materials[mat_index]));
else
JS_SetPropertyStr(js, model_obj, "material", JS_NewObject(js));
// Place this "model" object into our return array
uint32_t idx_in_array = js_arrlen(js,ret_arr);
JS_SetPropertyUint32(js, ret_arr, idx_in_array, model_obj);
// Cleanup (per-primitive)
if (posdata) free(posdata);
if (normdata) free(normdata);
if (uvdata) free(uvdata);
if (colordata) free(colordata);
if (indicesdata) free(indicesdata);
}
}
cgltf_free(data);
ret = ret_arr;
)