STL Loader
This commit is contained in:
@@ -1,20 +0,0 @@
|
|||||||
# Copyright (c) 2026 Dominic Masters
|
|
||||||
#
|
|
||||||
# This software is released under the MIT License.
|
|
||||||
# https://opensource.org/licenses/MIT
|
|
||||||
|
|
||||||
include(FetchContent)
|
|
||||||
|
|
||||||
if(NOT TARGET fast_obj)
|
|
||||||
FetchContent_Declare(
|
|
||||||
fast_obj
|
|
||||||
GIT_REPOSITORY https://github.com/thisistherk/fast_obj.git
|
|
||||||
GIT_TAG master
|
|
||||||
)
|
|
||||||
FetchContent_MakeAvailable(fast_obj)
|
|
||||||
endif()
|
|
||||||
|
|
||||||
set(fast_obj_FOUND TRUE)
|
|
||||||
set(FAST_OBJ_INCLUDE_DIRS "${fast_obj_SOURCE_DIR}")
|
|
||||||
set(FAST_OBJ_LIBRARIES fast_obj)
|
|
||||||
mark_as_advanced(FAST_OBJ_INCLUDE_DIRS FAST_OBJ_LIBRARIES fast_obj_FOUND)
|
|
||||||
@@ -32,15 +32,6 @@ if(NOT yyjson_FOUND)
|
|||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if(NOT fast_obj_FOUND)
|
|
||||||
find_package(fast_obj REQUIRED)
|
|
||||||
if(fast_obj_FOUND)
|
|
||||||
target_link_libraries(${DUSK_LIBRARY_TARGET_NAME} PUBLIC fast_obj)
|
|
||||||
else()
|
|
||||||
message(FATAL_ERROR "fast_obj not found. Please ensure fast_obj is correctly fetched.")
|
|
||||||
endif()
|
|
||||||
endif()
|
|
||||||
|
|
||||||
if(NOT Lua_FOUND)
|
if(NOT Lua_FOUND)
|
||||||
find_package(Lua REQUIRED)
|
find_package(Lua REQUIRED)
|
||||||
if(Lua_FOUND AND NOT TARGET Lua::Lua)
|
if(Lua_FOUND AND NOT TARGET Lua::Lua)
|
||||||
|
|||||||
@@ -216,4 +216,9 @@
|
|||||||
#define assertStrLenMax(str, len, message) ((void)0)
|
#define assertStrLenMax(str, len, message) ((void)0)
|
||||||
#define assertStrLenMin(str, len, message) ((void)0)
|
#define assertStrLenMin(str, len, message) ((void)0)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#define assertStructSize(struct, size) \
|
||||||
|
_Static_assert(sizeof(struct) == size, "Size of " #struct " must be " #size)
|
||||||
|
|
||||||
|
// EOF
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
#include "asset/asset.h"
|
#include "asset/asset.h"
|
||||||
#include "assert/assert.h"
|
#include "assert/assert.h"
|
||||||
#include "util/memory.h"
|
#include "util/memory.h"
|
||||||
|
#include "util/math.h"
|
||||||
|
|
||||||
errorret_t assetFileInit(
|
errorret_t assetFileInit(
|
||||||
assetfile_t *file,
|
assetfile_t *file,
|
||||||
@@ -70,6 +71,19 @@ errorret_t assetFileRead(
|
|||||||
) {
|
) {
|
||||||
assertNotNull(file, "Asset file cannot be NULL.");
|
assertNotNull(file, "Asset file cannot be NULL.");
|
||||||
assertNotNull(file->zipFile, "Asset file must be opened before reading.");
|
assertNotNull(file->zipFile, "Asset file must be opened before reading.");
|
||||||
|
|
||||||
|
if(buffer == NULL) {
|
||||||
|
size_t bytesRemaining = bufferSize;
|
||||||
|
uint8_t tempBuffer[256];
|
||||||
|
while(bytesRemaining > 0) {
|
||||||
|
size_t chunkSize = mathMin(bytesRemaining, sizeof(tempBuffer));
|
||||||
|
errorChain(assetFileRead(file, tempBuffer, chunkSize));
|
||||||
|
file->position += chunkSize;
|
||||||
|
bytesRemaining -= chunkSize;
|
||||||
|
}
|
||||||
|
file->lastRead = bufferSize;
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
// I assume zip_fread takes buffer NULL for skipping?
|
// I assume zip_fread takes buffer NULL for skipping?
|
||||||
zip_int64_t bytesRead = zip_fread(file->zipFile, buffer, bufferSize);
|
zip_int64_t bytesRead = zip_fread(file->zipFile, buffer, bufferSize);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
# Sources
|
# Sources
|
||||||
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
target_sources(${DUSK_LIBRARY_TARGET_NAME}
|
||||||
PUBLIC
|
PUBLIC
|
||||||
|
assetmeshloader.c
|
||||||
assettextureloader.c
|
assettextureloader.c
|
||||||
assettilesetloader.c
|
assettilesetloader.c
|
||||||
)
|
)
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "asset/loader/display/assetmeshloader.h"
|
||||||
|
#include "asset/asset.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
#include "util/endian.h"
|
||||||
|
#include "util/memory.h"
|
||||||
|
|
||||||
|
errorret_t assetMeshLoader(assetfile_t *file) {
|
||||||
|
assertNotNull(file, "Asset file cannot be null");
|
||||||
|
|
||||||
|
assetmeshoutput_t *output = (assetmeshoutput_t *)file->output;
|
||||||
|
assertNotNull(output, "Output cannot be null");
|
||||||
|
assertNotNull(output->outMesh, "Output mesh cannot be null");
|
||||||
|
assertNotNull(output->outVertices, "Output vertices cannot be null");
|
||||||
|
|
||||||
|
// STL file loading
|
||||||
|
errorChain(assetFileOpen(file));
|
||||||
|
|
||||||
|
// Skip the 80 byte header
|
||||||
|
errorChain(assetFileRead(file, NULL, 80));
|
||||||
|
if(file->lastRead != 80) errorThrow("Failed to skip STL header");
|
||||||
|
|
||||||
|
uint32_t triangleCount;
|
||||||
|
errorChain(assetFileRead(file, &triangleCount, sizeof(uint32_t)));
|
||||||
|
if(file->lastRead != sizeof(uint32_t)) errorThrow("Failed read tri count");
|
||||||
|
// normalize
|
||||||
|
triangleCount = endianLittleToHost32(triangleCount);
|
||||||
|
|
||||||
|
// Allocate mesh and vertex data
|
||||||
|
errorret_t ret;
|
||||||
|
meshvertex_t *verts = memoryAllocate(
|
||||||
|
sizeof(meshvertex_t) * triangleCount * 3
|
||||||
|
);
|
||||||
|
*output->outVertices = verts;
|
||||||
|
|
||||||
|
// Read triangle data
|
||||||
|
for(uint32_t i = 0; i < triangleCount; i++) {
|
||||||
|
assetmeshstltriangle_t triData;
|
||||||
|
ret = assetFileRead(file, &triData, sizeof(triData));
|
||||||
|
if(ret.code != ERROR_OK) {
|
||||||
|
memoryFree(verts);
|
||||||
|
errorChain(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(file->lastRead != sizeof(triData)) {
|
||||||
|
memoryFree(verts);
|
||||||
|
errorThrow("Failed to read triangle data");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip normals, we don't use them
|
||||||
|
|
||||||
|
// Fix endianess of of data
|
||||||
|
for(uint8_t j = 0; j < 3; j++) {
|
||||||
|
verts[i * 3 + j].color.r = (uint8_t)(endianLittleToHostFloat(
|
||||||
|
triData.normal[0]
|
||||||
|
) * 255.0f);
|
||||||
|
verts[i * 3 + j].color.g = (uint8_t)(endianLittleToHostFloat(
|
||||||
|
triData.normal[1]
|
||||||
|
) * 255.0f);
|
||||||
|
verts[i * 3 + j].color.b = (uint8_t)(endianLittleToHostFloat(
|
||||||
|
triData.normal[2]
|
||||||
|
) * 255.0f);
|
||||||
|
verts[i * 3 + j].color.a = 0xFF;
|
||||||
|
|
||||||
|
verts[i * 3 + j].uv[0] = 0.0f; // No UV data in STL, just set to 0
|
||||||
|
verts[i * 3 + j].uv[1] = 0.0f;
|
||||||
|
|
||||||
|
for(uint8_t k = 0; k < 3; k++) {
|
||||||
|
verts[i * 3 + j].pos[k] = endianLittleToHostFloat(
|
||||||
|
triData.positions[j][k]
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert Z-Up to Y-Up
|
||||||
|
float_t temp = verts[i * 3 + j].pos[1];
|
||||||
|
verts[i * 3 + j].pos[1] = verts[i * 3 + j].pos[2];
|
||||||
|
verts[i * 3 + j].pos[2] = temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Finally, init mesh
|
||||||
|
ret = meshInit(
|
||||||
|
output->outMesh,
|
||||||
|
MESH_PRIMITIVE_TYPE_TRIANGLES,
|
||||||
|
triangleCount * 3,
|
||||||
|
verts
|
||||||
|
);
|
||||||
|
if(ret.code != ERROR_OK) {
|
||||||
|
memoryFree(verts);
|
||||||
|
errorChain(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = assetFileClose(file);
|
||||||
|
if(ret.code != ERROR_OK) {
|
||||||
|
errorCatch(errorPrint(meshDispose(output->outMesh)));
|
||||||
|
memoryFree(verts);
|
||||||
|
errorChain(ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
errorOk();
|
||||||
|
}
|
||||||
|
|
||||||
|
errorret_t assetMeshLoad(
|
||||||
|
const char_t *path,
|
||||||
|
mesh_t *outMesh,
|
||||||
|
meshvertex_t **outVertices
|
||||||
|
) {
|
||||||
|
assertNotNull(path, "Path cannot be null");
|
||||||
|
assertNotNull(outMesh, "Output mesh cannot be null");
|
||||||
|
assertNotNull(outVertices, "Output vertices cannot be null");
|
||||||
|
|
||||||
|
assetmeshoutput_t output = { outMesh, outVertices };
|
||||||
|
return assetLoad(path, &assetMeshLoader, NULL, &output);
|
||||||
|
}
|
||||||
@@ -0,0 +1,46 @@
|
|||||||
|
/**
|
||||||
|
* Copyright (c) 2026 Dominic Masters
|
||||||
|
*
|
||||||
|
* This software is released under the MIT License.
|
||||||
|
* https://opensource.org/licenses/MIT
|
||||||
|
*/
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
#include "asset/asset.h"
|
||||||
|
#include "display/mesh/mesh.h"
|
||||||
|
#include "assert/assert.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
mesh_t *outMesh;
|
||||||
|
meshvertex_t **outVertices;
|
||||||
|
} assetmeshoutput_t;
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
typedef struct {
|
||||||
|
vec3 normal;
|
||||||
|
float_t positions[3][3];
|
||||||
|
uint16_t attributeByteCount;
|
||||||
|
} assetmeshstltriangle_t;
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
assertStructSize(assetmeshstltriangle_t, 50);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loader for mesh assets.
|
||||||
|
*
|
||||||
|
* @param file Asset file to load the mesh from.
|
||||||
|
* @return Any error that occurs during loading.
|
||||||
|
*/
|
||||||
|
errorret_t assetMeshLoader(assetfile_t *file);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Handler for mesh assets.
|
||||||
|
*
|
||||||
|
* @param file Asset file to load the mesh from.
|
||||||
|
* @return Any error that occurs during loading.
|
||||||
|
*/
|
||||||
|
errorret_t assetMeshLoad(
|
||||||
|
const char_t *path,
|
||||||
|
mesh_t *outMesh,
|
||||||
|
meshvertex_t **outVertices
|
||||||
|
);
|
||||||
+11
-17
@@ -20,19 +20,17 @@
|
|||||||
#include "game/game.h"
|
#include "game/game.h"
|
||||||
#include "display/mesh/quad.h"
|
#include "display/mesh/quad.h"
|
||||||
|
|
||||||
|
#include "asset/loader/display/assetmeshloader.h"
|
||||||
|
|
||||||
engine_t ENGINE;
|
engine_t ENGINE;
|
||||||
// texture_t TEXTURE;
|
|
||||||
// color_t TEXTURE_COLORS[] = {
|
|
||||||
// COLOR_RED, COLOR_GREEN, COLOR_MAGENTA, COLOR_CYAN,
|
|
||||||
// COLOR_BLUE, COLOR_WHITE, COLOR_YELLOW, COLOR_BLACK,
|
|
||||||
// COLOR_CYAN, COLOR_MAGENTA, COLOR_GREEN, COLOR_RED,
|
|
||||||
// COLOR_WHITE, COLOR_BLUE, COLOR_BLACK, COLOR_YELLOW
|
|
||||||
// };
|
|
||||||
entityid_t ent1;
|
entityid_t ent1;
|
||||||
componentid_t ent1Pos;
|
componentid_t ent1Pos;
|
||||||
componentid_t ent1Mesh;
|
componentid_t ent1Mesh;
|
||||||
componentid_t ent1Mat;
|
componentid_t ent1Mat;
|
||||||
|
|
||||||
|
mesh_t loadedMesh;
|
||||||
|
meshvertex_t *loadedVertices;
|
||||||
|
|
||||||
errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
||||||
memoryZero(&ENGINE, sizeof(engine_t));
|
memoryZero(&ENGINE, sizeof(engine_t));
|
||||||
ENGINE.running = true;
|
ENGINE.running = true;
|
||||||
@@ -57,27 +55,23 @@ errorret_t engineInit(const int32_t argc, const char_t **argv) {
|
|||||||
entityPositionLookAt(
|
entityPositionLookAt(
|
||||||
cam,
|
cam,
|
||||||
camPos,
|
camPos,
|
||||||
(vec3){ 0.0f, 0.0f, 0.0f },
|
(vec3){ 0.0f, 20.0f, 0.0f },
|
||||||
(vec3){ 0.0f, 1.0f, 0.0f },
|
(vec3){ 0.0f, 1.0f, 0.0f },
|
||||||
(vec3){ 3.0f, 3.0f, 3.0f }
|
(vec3){ 50.0f, 70.0f, 50.0f }
|
||||||
);
|
);
|
||||||
componentid_t camCam = entityAddComponent(cam, COMPONENT_TYPE_CAMERA);
|
componentid_t camCam = entityAddComponent(cam, COMPONENT_TYPE_CAMERA);
|
||||||
entityCameraSetZFar(cam, camCam, 100.0f);
|
entityCameraSetZFar(cam, camCam, 500.0f);
|
||||||
|
|
||||||
ent1 = entityManagerAdd();
|
ent1 = entityManagerAdd();
|
||||||
ent1Pos = entityAddComponent(ent1, COMPONENT_TYPE_POSITION);
|
ent1Pos = entityAddComponent(ent1, COMPONENT_TYPE_POSITION);
|
||||||
ent1Mesh = entityAddComponent(ent1, COMPONENT_TYPE_MESH);
|
ent1Mesh = entityAddComponent(ent1, COMPONENT_TYPE_MESH);
|
||||||
ent1Mat = entityAddComponent(ent1, COMPONENT_TYPE_MATERIAL);
|
ent1Mat = entityAddComponent(ent1, COMPONENT_TYPE_MATERIAL);
|
||||||
|
|
||||||
// textureInit(&TEXTURE, 4, 4, TEXTURE_FORMAT_RGBA, (texturedata_t){
|
errorChain(assetMeshLoad("test/RosaTh.stl", &loadedMesh, &loadedVertices));
|
||||||
// .rgbaColors = TEXTURE_COLORS
|
entityMeshSetMesh(ent1, ent1Mesh, &loadedMesh);
|
||||||
// });
|
|
||||||
|
|
||||||
entityMeshSetMesh(ent1, ent1Mesh, &QUAD_MESH_SIMPLE);
|
|
||||||
|
|
||||||
shadermaterial_t *mat = entityMaterialGetShaderMaterial(ent1, ent1Mat);
|
shadermaterial_t *mat = entityMaterialGetShaderMaterial(ent1, ent1Mat);
|
||||||
mat->unlit.color = COLOR_MAGENTA;
|
mat->unlit.color = COLOR_WHITE;
|
||||||
// mat->unlit.texture = &TEXTURE;
|
|
||||||
|
|
||||||
// EOF
|
// EOF
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user