1042 lines
31 KiB
C++
1042 lines
31 KiB
C++
/*
|
|
* Copyright (c) 2011-2021, NVIDIA CORPORATION. All rights reserved.
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*
|
|
* SPDX-FileCopyrightText: Copyright (c) 2011-2021 NVIDIA CORPORATION
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
/// @DOC_SKIP (keyword to exclude this file from automatic README.md generation)
|
|
|
|
#pragma once
|
|
|
|
#include <stddef.h>
|
|
#include <stdint.h>
|
|
#include <string>
|
|
#include <atomic>
|
|
#include <algorithm>
|
|
|
|
// use CSF_IMPLEMENTATION define prior including
|
|
// to add actual implementation to this project
|
|
//
|
|
// prior implementation include, supports following options
|
|
//
|
|
// CSF_SUPPORT_ZLIB 0/1 (uses zlib)
|
|
// CSF_SUPPORT_GLTF2 0/1 (uses cgltf)
|
|
//
|
|
// CSF_PARALLEL_WORK 0/1
|
|
// meant for other cadscenefile processing files
|
|
// that want minimal dependencies (as in just this header).
|
|
// It is meant to remove all of the `pragma omp parallel for` code.
|
|
//
|
|
// CSF_DISABLE_FILEMAPPING_SUPPORT 0/1
|
|
// If 1 the implementation will not use the OS-level functionality
|
|
// to support memory mapped files, but rather use traditional file
|
|
// api to load or save using a full in memory copy.
|
|
|
|
|
|
#if defined(__cplusplus)
|
|
#include <utility>
|
|
#if CSF_PARALLEL_WORK || defined(CSF_IMPLEMENTATION)
|
|
#include <mutex>
|
|
#include <thread>
|
|
#include <functional>
|
|
#endif
|
|
#endif
|
|
|
|
extern "C" {
|
|
|
|
#ifdef _WIN32
|
|
#if defined(CSFAPI_EXPORTS)
|
|
#define CSFAPI __declspec(dllexport)
|
|
#elif defined(CSFAPI_IMPORTS)
|
|
#define CSFAPI __declspec(dllimport)
|
|
#else
|
|
#define CSFAPI
|
|
#endif
|
|
#else
|
|
#define CSFAPI
|
|
#endif
|
|
|
|
enum CadSceneFileVersion : int
|
|
{
|
|
// original version
|
|
CADSCENEFILE_VERSION_BASE = 1,
|
|
// add support for material meta information
|
|
CADSCENEFILE_VERSION_MATERIAL = 2,
|
|
// add support for fileflags
|
|
CADSCENEFILE_VERSION_FILEFLAGS = 3,
|
|
// changes CSFNodePart.lineWidth to CSFNodePart.nodeIDX
|
|
CADSCENEFILE_VERSION_PARTNODEIDX = 4,
|
|
// adds support for meta pointers
|
|
CADSCENEFILE_VERSION_META = 5,
|
|
// adds support for vertex and part channels
|
|
CADSCENEFILE_VERSION_GEOMETRYCHANNELS = 6,
|
|
|
|
// binary compatibility
|
|
CADSCENEFILE_VERSION_COMPAT = 2,
|
|
// current stable version
|
|
CADSCENEFILE_VERSION = CADSCENEFILE_VERSION_GEOMETRYCHANNELS,
|
|
// special compatibility
|
|
CADSCENEFILE_VERSION_SUPPORTED = CADSCENEFILE_VERSION_GEOMETRYCHANNELS,
|
|
};
|
|
|
|
enum CadSceneFileStatus : int
|
|
{
|
|
// return codes
|
|
CADSCENEFILE_NOERROR = 0, // Success.
|
|
CADSCENEFILE_ERROR_NOFILE = 1, // The file did not exist or an I/O operation failed.
|
|
CADSCENEFILE_ERROR_VERSION = 2, // The file had an invalid header.
|
|
CADSCENEFILE_ERROR_OPERATION = 3, // Called an operation that cannot be called on this object.
|
|
CADSCENEFILE_ERROR_INVALID = 4, // The file contains invalid data.
|
|
};
|
|
|
|
enum CadSceneFileFlag : uint32_t
|
|
{
|
|
// the loader was fixed so various flags, CADSCENEFILE_FLAG_META_FILE etc.
|
|
// were deprecated and will be recycled in future versions
|
|
|
|
// each node is visited only once during traversal.
|
|
// always set, likely only commandline tools support multiple
|
|
// referencing of nodes
|
|
CADSCENEFILE_FLAG_UNIQUENODES = 1 << 0,
|
|
// all triangles/lines are using strips instead of index lists
|
|
// never set, only special purpose file/application made use of this
|
|
CADSCENEFILE_FLAG_STRIPS = 1 << 1,
|
|
// parts get their own vertex buffer sub-range
|
|
// requires CSFGEOMETRY_PARTCHANNEL_VERTEXRANGE to be available
|
|
CADSCENEFILE_FLAG_PERPARTVERTICES = 1 << 5,
|
|
// degenerate primitives were removed
|
|
CADSCENEFILE_FLAG_NODEGENERATES = 1 << 7,
|
|
};
|
|
|
|
enum CadSceneFileLengths : int
|
|
{
|
|
CADSCENEFILE_LENGTH_STRING = 128,
|
|
CADSCENEFILE_LENGTH_AUXS = 32,
|
|
};
|
|
|
|
|
|
#define CADSCENEFILE_RESTARTINDEX (~0)
|
|
|
|
/*
|
|
|
|
Version History
|
|
---------------
|
|
|
|
1 initial
|
|
2 !binary break
|
|
material allows custom payload
|
|
deprecate geometry matrix
|
|
deprecate geometry part vertex
|
|
3 hasUniqueNodes became a bitflag
|
|
added strip indices flag, file is either strip or non-strip
|
|
4 lineWidth changed to nodeIDX, allows per-part sub-transforms. sub-transforms should be below
|
|
object in hierarchy and not affect geometry bbox
|
|
5 meta information handling
|
|
6 vertex channels using deprecated geometry matrix space
|
|
|
|
Example Structure
|
|
-----------------
|
|
|
|
CSFMaterials
|
|
0 Red
|
|
1 Green
|
|
2 Blue
|
|
|
|
|
|
CSFGeometries (index,vertex & "parts")
|
|
0 Box
|
|
1 Cylinder
|
|
e.g. parts (CSFGeometryPart defines a region in the indexbuffers of CSFGeometry):
|
|
0 mantle
|
|
1 top cap
|
|
2 bottom cap
|
|
|
|
There is no need to have multiple parts, but for experimenting with
|
|
rendering some raw CAD data, having each patch/surface feature individually
|
|
can be useful. A typical CAD file with use one CSFGeometry per Solid (e.g. cube)
|
|
and multiple CSFGeometryParts for each "feature" (face of a cube etc.).
|
|
When performance matters, the parts should be flattened as much as possible.
|
|
|
|
CSFNodes (hierarchy of nodes)
|
|
|
|
A node can also reference a geometry, this way the same geometry
|
|
data can be instanced multiple times.
|
|
If the node references geometry, then it must have an
|
|
array of "CSFNodePart" matching referenced CSFGeometryParts.
|
|
The CSFNodePart encodes the materials/matrix as well as its
|
|
active state.
|
|
|
|
|
|
CSFoffset - nameOFFSET variables
|
|
--------------------------------
|
|
|
|
CSFoffset is only indirectly used during save and load operations.
|
|
As end user you can ignore the various "nameOFFSET" variables
|
|
in all the unions, as well as the pointers array.
|
|
|
|
|
|
CSFBytePacket - meta information
|
|
--------------------------------
|
|
|
|
Additional meta information can be stored in a linear chunk of memory that is
|
|
organized in CSFBytePackets.
|
|
|
|
meta/material.bytes = { [CSFBytePacket A] [Payload A..] [CSFBytePacket B] [Payload B...]...}
|
|
|
|
Tools operating on CSF files are not expected to interpret the meta information.
|
|
They may, however, remove/clone the entire entry on duplication/removal of
|
|
the appropriate material, geometry or node.
|
|
|
|
*/
|
|
|
|
typedef struct _CSFLoaderConfig
|
|
{
|
|
// read only access to loaded csf data
|
|
// means we can use filemappings to avoid allocations
|
|
// for content within the main structs (nodes, geometries...)
|
|
// The primary structs are still allocated for write access,
|
|
// but all pointers within them are mapped.
|
|
// default = 0
|
|
int secondariesReadOnly;
|
|
|
|
// detailed pointer alignment validation (some older files need resaving to pass)
|
|
// default = 1
|
|
int validate;
|
|
|
|
// only relevant for CSF_GLTF2_SUPPORT
|
|
// uses hashes of geometry data to figure out what gltf mesh
|
|
// data is re-used under different materials, and can
|
|
// therefore be mapped to a single CSF geometry.
|
|
// default = 1
|
|
int gltfFindUniqueGeometries;
|
|
} CSFLoaderConfig;
|
|
|
|
typedef uint64_t CSFoffset;
|
|
typedef struct _CSFGuid
|
|
{
|
|
uint32_t value0;
|
|
uint32_t value1;
|
|
uint32_t value2;
|
|
uint32_t value3;
|
|
} CSFGuid;
|
|
|
|
|
|
// optional, if one wants to pack
|
|
// additional meta information into the bytes arrays
|
|
typedef struct _CSFBytePacket
|
|
{
|
|
CSFGuid guid;
|
|
uint32_t numBytes; // size of the payload + size of this header
|
|
} CSFBytePacket;
|
|
|
|
// list of standard GUIDS
|
|
// create your own via random 128-bit value
|
|
// where the first 96-bit are not 0
|
|
|
|
|
|
#define CSFGUID_MATERIAL_GLTF2 \
|
|
{ \
|
|
0, 0, 0, 2 \
|
|
}
|
|
|
|
typedef struct _CSFMaterialGLTF2Texture
|
|
{
|
|
char name[CADSCENEFILE_LENGTH_STRING];
|
|
uint16_t minFilter;
|
|
uint16_t magFilter;
|
|
uint16_t wrapS;
|
|
uint16_t wrapT;
|
|
float scale;
|
|
int coord;
|
|
int xformUsed;
|
|
int xformCoord;
|
|
float xformOffset[2];
|
|
float xformScale[2];
|
|
float xformRotation;
|
|
} CSFMaterialGLTF2Texture;
|
|
|
|
typedef struct _CSFMaterialGLTF2Meta
|
|
{
|
|
CSFBytePacket packet;
|
|
|
|
//-1: unlit
|
|
// 0: metallicRoughness
|
|
// 1: specularGlossiness
|
|
int shadingModel;
|
|
int doubleSided;
|
|
int alphaMode;
|
|
float alphaCutoff;
|
|
float emissiveFactor[3];
|
|
|
|
union
|
|
{
|
|
struct
|
|
{
|
|
float baseColorFactor[4];
|
|
float metallicFactor;
|
|
float roughnessFactor;
|
|
|
|
CSFMaterialGLTF2Texture baseColorTexture;
|
|
CSFMaterialGLTF2Texture metallicRoughnessTexture;
|
|
};
|
|
|
|
struct
|
|
{
|
|
float diffuseFactor[4];
|
|
float specularFactor[3];
|
|
float glossinessFactor;
|
|
|
|
CSFMaterialGLTF2Texture diffuseTexture;
|
|
CSFMaterialGLTF2Texture specularGlossinessTexture;
|
|
};
|
|
};
|
|
|
|
CSFMaterialGLTF2Texture occlusionTexture;
|
|
CSFMaterialGLTF2Texture normalTexture;
|
|
CSFMaterialGLTF2Texture emissiveTexture;
|
|
} CSFMaterialGLTF2Meta;
|
|
|
|
typedef struct _CSFMeta
|
|
{
|
|
char name[CADSCENEFILE_LENGTH_STRING];
|
|
int flags;
|
|
|
|
// access via CSFMeta_getBytePacket
|
|
CSFoffset numBytes;
|
|
union
|
|
{
|
|
CSFoffset bytesOFFSET;
|
|
unsigned char* bytes;
|
|
};
|
|
} CSFMeta;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
typedef struct _CSFMaterial
|
|
{
|
|
char name[CADSCENEFILE_LENGTH_STRING];
|
|
float color[4];
|
|
int type; // arbitrary data
|
|
|
|
|
|
// access via CSFMaterial_getBytePacket
|
|
// or CSFile_getMaterialBytePacket
|
|
uint32_t numBytes;
|
|
union
|
|
{
|
|
CSFoffset bytesOFFSET;
|
|
unsigned char* bytes;
|
|
};
|
|
} CSFMaterial;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
typedef enum _CSFGeometryPartChannel
|
|
{
|
|
// CSFGeometryPartChannelBbox
|
|
CSFGEOMETRY_PARTCHANNEL_BBOX,
|
|
// CSFGeometryPartChannelVertices
|
|
CSFGEOMETRY_PARTCHANNEL_VERTEXRANGE,
|
|
CSFGEOMETRY_PARTCHANNELS,
|
|
} CSFGeometryPartChannel;
|
|
|
|
typedef struct _CSFGeometryPartBbox
|
|
{
|
|
float min[3];
|
|
float max[3];
|
|
} CSFGeometryPartBbox;
|
|
|
|
typedef struct _CSFGeometryPartVertexRange
|
|
{
|
|
uint32_t vertexBegin;
|
|
uint32_t numVertices;
|
|
} CSFGeometryPartVertexRange;
|
|
|
|
typedef enum _CSFGeometryNormalChannel
|
|
{
|
|
// float[3]
|
|
// can extend but must not change order
|
|
CSFGEOMETRY_NORMALCHANNEL_NORMAL,
|
|
CSFGEOMETRY_NORMALCHANNELS,
|
|
} CSFGeometryNormalChannel;
|
|
|
|
typedef enum _CSFGeometryTexChannel
|
|
{
|
|
// float[2]
|
|
// can extend but must not change order
|
|
CSFGEOMETRY_TEXCHANNEL_GENERIC,
|
|
CSFGEOMETRY_TEXCHANNEL_LIGHTMAP,
|
|
CSFGEOMETRY_TEXCHANNELS,
|
|
} CSFGeometryTexChannel;
|
|
|
|
typedef enum _CSFGeometryAuxChannel
|
|
{
|
|
// float[4]
|
|
// can extend but must not change order
|
|
CSFGEOMETRY_AUXCHANNEL_RADIANCE,
|
|
CSFGEOMETRY_AUXCHANNEL_TANGENT,
|
|
CSFGEOMETRY_AUXCHANNELS,
|
|
} CSFGeometryAuxChannel;
|
|
|
|
typedef struct _CSFGeometryPart
|
|
{
|
|
int _deprecated; // deprecated
|
|
int numIndexSolid; // number of triangle indices that the part uses
|
|
int numIndexWire; // number of line indices that the part uses
|
|
} CSFGeometryPart;
|
|
|
|
typedef struct _CSFGeometry
|
|
{
|
|
/*
|
|
Each Geometry stores:
|
|
- optional index buffer triangles (solid)
|
|
- optional index buffer for lines (wire)
|
|
|
|
At least one of the index buffers must be
|
|
present.
|
|
|
|
- vertex buffer (mandatory)
|
|
- optional vertex attribute (normal,tex,aux) buffers
|
|
|
|
Each vertex channel is stored in full for all vertices before
|
|
subsequent channels. Use the channel getter functions.
|
|
Auxiliar data uses the auxStorageOrder array to encode
|
|
what and in which order channels are stored.
|
|
|
|
- parts array
|
|
|
|
index buffer: { part 0 ...., part 1.., part 2......., ...}
|
|
|
|
Each geometry part represents a range within the
|
|
index buffers. The parts are stored ascending
|
|
in the index buffer. To get the starting
|
|
offset, use the sum of the previous parts.
|
|
|
|
- perpart array
|
|
|
|
Allows storing auxiliar per-part channel data (CSFGeometryPartChannel)
|
|
perpartStorageOrder array encodes what and in which
|
|
order the channels are stored.
|
|
Use the channel getter function and size functions.
|
|
*/
|
|
|
|
// ordering of variable is a bit weird due to keeping binary
|
|
// compatibility with past versions
|
|
float _deprecated[4];
|
|
|
|
// CADSCENEFILE_VERSION_GEOMETRYCHANNELS
|
|
/////////////////////////////////////////////////
|
|
int numNormalChannels;
|
|
int numTexChannels;
|
|
int numAuxChannels;
|
|
int numPartChannels;
|
|
|
|
union
|
|
{
|
|
// numAuxChannels
|
|
CSFoffset auxStorageOrderOFFSET;
|
|
_CSFGeometryAuxChannel* auxStorageOrder;
|
|
};
|
|
union
|
|
{
|
|
// 4 * numVertices * numAuxChannels
|
|
CSFoffset auxOFFSET;
|
|
float* aux;
|
|
};
|
|
|
|
union
|
|
{
|
|
// numPartChannels
|
|
CSFoffset perpartStorageOrderOFFSET;
|
|
CSFGeometryPartChannel* perpartStorageOrder;
|
|
};
|
|
union
|
|
{
|
|
// sized implicitly use CSFGeometry_getPerPartSize functions
|
|
CSFoffset perpartOFFSET;
|
|
unsigned char* perpart;
|
|
};
|
|
|
|
// CADSCENEFILE_VERSION_BASE
|
|
/////////////////////////////////////////////////
|
|
int numParts;
|
|
int numVertices;
|
|
int numIndexSolid;
|
|
int numIndexWire;
|
|
|
|
union
|
|
{
|
|
// 3 components * numVertices
|
|
CSFoffset vertexOFFSET;
|
|
float* vertex;
|
|
};
|
|
|
|
union
|
|
{
|
|
// 3 components * numVertices * numNormalChannels
|
|
// canonical order as defined by CSFGeometryNormalChannel
|
|
CSFoffset normalOFFSET;
|
|
float* normal;
|
|
};
|
|
|
|
union
|
|
{
|
|
// 2 components * numVertices * numTexChannels
|
|
// canonical order is defined in CSFGeometryTexChannel
|
|
CSFoffset texOFFSET;
|
|
float* tex;
|
|
};
|
|
|
|
union
|
|
{
|
|
CSFoffset indexSolidOFFSET;
|
|
uint32_t* indexSolid;
|
|
};
|
|
|
|
union
|
|
{
|
|
CSFoffset indexWireOFFSET;
|
|
uint32_t* indexWire;
|
|
};
|
|
|
|
union
|
|
{
|
|
CSFoffset partsOFFSET;
|
|
CSFGeometryPart* parts;
|
|
};
|
|
} CSFGeometry;
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
typedef struct _CSFNodePart
|
|
{
|
|
// CSFNodePart defines the state for the corresponding CSFGeometryPart
|
|
|
|
// allow setting visibility of a part, 0 or 1
|
|
// should always be 1
|
|
int active;
|
|
|
|
// index into csf->materials
|
|
// must alwaye be >= 0
|
|
// ideally all parts of a node use the same material
|
|
int materialIDX;
|
|
|
|
// index into csf->nodes
|
|
// if -1 it uses the matrix of the node it belongs to.
|
|
// This is highly recommended to be used.
|
|
// if >= 0 the nodeIDX should be a child of the
|
|
// part's node.
|
|
int nodeIDX;
|
|
} CSFNodePart;
|
|
|
|
typedef struct _CSFNode
|
|
{
|
|
/*
|
|
CSFNodes form a hierarchy, starting at
|
|
csf->nodes[csf->rootIDX].
|
|
Each node can have children. If CADSCENEFILE_FLAG_UNIQUENODES is set
|
|
the hierarchy is a tree.
|
|
|
|
CSFNodes can also be a simple list of instances if csf->rootIDX <= 0
|
|
in that case nodes must not have children.
|
|
|
|
Each Node stores:
|
|
- the object transform (relative to parent)
|
|
- the world transform (final transform to get from object to world space
|
|
node.worldTM = node.parent.worldTM * node.objectTM;
|
|
- optional geometry reference
|
|
- optional array of node children
|
|
- the parts array is mandatory if a geometry is referenced
|
|
and must be sized to form a 1:1 correspondence to the geometry's parts.
|
|
*/
|
|
|
|
float objectTM[16];
|
|
float worldTM[16];
|
|
|
|
// index into csf->geometries
|
|
// can be -1 (no geometry used) or >= 0
|
|
int geometryIDX;
|
|
|
|
// if geometryIDX >= 0, must match geometry's numParts
|
|
int numParts;
|
|
int numChildren;
|
|
union
|
|
{
|
|
// must exist if geometryIDX >= 0, null otherwise
|
|
CSFoffset partsOFFSET;
|
|
CSFNodePart* parts;
|
|
};
|
|
union
|
|
{
|
|
// array of indices into csf->nodes
|
|
// each must be >= 0
|
|
// array must be != null if numChildren is > 0
|
|
CSFoffset childrenOFFSET;
|
|
int* children;
|
|
};
|
|
} CSFNode;
|
|
|
|
|
|
// All loaders will allocate this header separate from the
|
|
// file data, therefore the header can be safely extended with
|
|
// new versions.
|
|
// New members will be nulled, if the file version
|
|
// was older than what this struct defines.
|
|
|
|
typedef struct _CSFile
|
|
{
|
|
int magic;
|
|
int version;
|
|
|
|
// see CADSCENEFILE_FLAG_??
|
|
uint32_t fileFlags;
|
|
|
|
// used internally for load & save operations, can be ignored
|
|
int numPointers;
|
|
|
|
int numGeometries;
|
|
int numMaterials;
|
|
int numNodes;
|
|
|
|
// index into csf->nodes where the root node is located
|
|
// if negative it means no hierarchy exists and all
|
|
// nodes have no children (flat instance list)
|
|
int rootIDX;
|
|
|
|
union
|
|
{
|
|
// the pointers are used internally for load & save operations
|
|
// no need to specify prior save
|
|
// no need to access post load
|
|
|
|
CSFoffset pointersOFFSET;
|
|
CSFoffset* pointers;
|
|
};
|
|
|
|
union
|
|
{
|
|
CSFoffset geometriesOFFSET;
|
|
CSFGeometry* geometries;
|
|
};
|
|
|
|
union
|
|
{
|
|
CSFoffset materialsOFFSET;
|
|
CSFMaterial* materials;
|
|
};
|
|
|
|
union
|
|
{
|
|
CSFoffset nodesOFFSET;
|
|
CSFNode* nodes;
|
|
};
|
|
|
|
//----------------------------------
|
|
// Only available for version >= CADSCENEFILE_VERSION_META
|
|
|
|
union
|
|
{
|
|
CSFoffset nodeMetasOFFSET;
|
|
CSFMeta* nodeMetas;
|
|
};
|
|
union
|
|
{
|
|
CSFoffset geometryMetasOFFSET;
|
|
CSFMeta* geometryMetas;
|
|
};
|
|
union
|
|
{
|
|
CSFoffset fileMetaOFFSET;
|
|
CSFMeta* fileMeta;
|
|
};
|
|
//----------------------------------
|
|
} CSFile;
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
typedef struct CSFileMemory_s* CSFileMemoryPTR;
|
|
|
|
// Internal allocation wrapper
|
|
// also handles details for loading operations
|
|
CSFAPI CSFileMemoryPTR CSFileMemory_new();
|
|
CSFAPI CSFileMemoryPTR CSFileMemory_newCfg(const CSFLoaderConfig* config);
|
|
|
|
// special value for CSFileMemory_alloc
|
|
#define CSF_MEMORY_ZEROED_FILL ((const void*)1)
|
|
|
|
// alloc functions are thread-safe
|
|
// fill if provided must provide sz bytes, or must be CSF_MEMORY_ZEROED_FILL
|
|
// which clears the allocation to zero
|
|
CSFAPI void* CSFileMemory_alloc(CSFileMemoryPTR mem, size_t sz, const void* fill);
|
|
// fillPartial if provided must provide szPartial bytes and szPartial <= sz
|
|
CSFAPI void* CSFileMemory_allocPartial(CSFileMemoryPTR mem, size_t sz, size_t szPartial, const void* fillPartial);
|
|
// all allocations within will be freed
|
|
CSFAPI void CSFileMemory_delete(CSFileMemoryPTR mem);
|
|
|
|
CSFAPI void CSFileMemory_getCfg(CSFileMemoryPTR mem, CSFLoaderConfig* config);
|
|
CSFAPI int CSFileMemory_areSecondariesReadOnly(CSFileMemoryPTR mem);
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
#if !CSF_DISABLE_FILEMAPPING_SUPPORT
|
|
typedef struct CSFReadMapping_s* CSFReadMappingPTR;
|
|
CSFAPI CSFReadMappingPTR CSFReadMapping_new(const char* filename);
|
|
CSFAPI void CSFReadMapping_delete(CSFReadMappingPTR readMapping);
|
|
CSFAPI size_t CSFReadMapping_getSize(CSFReadMappingPTR readMapping);
|
|
CSFAPI const void* CSFReadMapping_getData(CSFReadMappingPTR readMapping);
|
|
|
|
typedef struct CSFWriteMapping_s* CSFWriteMappingPTR;
|
|
CSFAPI CSFWriteMappingPTR CSFWriteMapping_new(const char* filename, size_t fileSize);
|
|
CSFAPI void CSFWriteMapping_delete(CSFWriteMappingPTR writeMapping);
|
|
CSFAPI size_t CSFWriteMapping_getSize(CSFWriteMappingPTR writeMapping);
|
|
CSFAPI void* CSFWriteMapping_getData(CSFWriteMappingPTR writeMapping);
|
|
#endif
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// The `data` is modified, therefore the raw load operation can be executed only once.
|
|
// It must be preserved for as long as the csf and its internals are accessed.
|
|
// `outcsf` must be separate and not overlap with `data`.
|
|
// If `validate` is non zero, additional checks on pointer and content alignment,
|
|
// ranges etc. is performed.
|
|
CSFAPI int CSFile_loadRaw(CSFile* outcsf, size_t sz, void* data, int validate);
|
|
|
|
// All allocations are done within the provided file memory.
|
|
// It must be preserved for as long as the csf and its internals are accessed
|
|
CSFAPI int CSFile_load(CSFile** outcsf, const char* filename, CSFileMemoryPTR mem);
|
|
|
|
CSFAPI int CSFile_save(const CSFile* csf, const char* filename);
|
|
|
|
|
|
// support for other extensions depends on
|
|
// CSF_ZIP_SUPPORT, CSF_GLTF2_SUPPORT
|
|
|
|
CSFAPI int CSFile_loadExt(CSFile** outcsf, const char* filename, CSFileMemoryPTR mem);
|
|
|
|
CSFAPI int CSFile_saveExt(CSFile* csf, const char* filename);
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// sets all content of _deprecated to zero, automatically done at load
|
|
// recommended to be done prior save
|
|
CSFAPI void CSFile_clearDeprecated(CSFile* csf);
|
|
CSFAPI void CSFGeometry_clearDeprecated(CSFGeometry* geo);
|
|
|
|
// sets up single normal/tex channel based on array existence, automatically done at load
|
|
CSFAPI void CSFile_setupDefaultChannels(CSFile* csf);
|
|
CSFAPI void CSFGeometry_setupDefaultChannels(CSFGeometry* geo);
|
|
|
|
// removes part channels
|
|
CSFAPI void CSFGeometry_removeAllPartChannels(CSFGeometry* geo, CSFileMemoryPTR mem);
|
|
// if channel doesn't exist, allocates it
|
|
// memory wasteful if you do one by one channel at a time
|
|
CSFAPI void CSFGeometry_requirePartChannel(CSFGeometry* geo, CSFileMemoryPTR mem, CSFGeometryPartChannel channel);
|
|
CSFAPI void CSFGeometry_requirePartChannels(CSFGeometry* geo, CSFileMemoryPTR mem, uint32_t numChannels, const CSFGeometryPartChannel* channels);
|
|
CSFAPI void CSFGeometry_removePartChannels(CSFGeometry* geo, CSFileMemoryPTR mem, uint32_t numChannels, const CSFGeometryPartChannel* channels);
|
|
// creates new allocation and copies old
|
|
CSFAPI void CSFGeometry_requireAuxChannel(CSFGeometry* geo, CSFileMemoryPTR mem, CSFGeometryAuxChannel channel);
|
|
|
|
// add byte packet to meta if its guid doesn't already exist
|
|
CSFAPI void CSFMeta_setOrAddBytePacket(CSFMeta** metaPtr, CSFileMemoryPTR csfmem, size_t size, const void* data);
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// returns vec3*numVertices
|
|
CSFAPI const float* CSFGeometry_getNormalChannel(const CSFGeometry* geo, CSFGeometryNormalChannel channel);
|
|
// returns vec2*numVertices
|
|
CSFAPI const float* CSFGeometry_getTexChannel(const CSFGeometry* geo, CSFGeometryTexChannel texChannel);
|
|
// returns vec4*numVertices
|
|
CSFAPI const float* CSFGeometry_getAuxChannel(const CSFGeometry* geo, CSFGeometryAuxChannel channel);
|
|
// returns arbitrary struct array * numParts
|
|
CSFAPI const void* CSFGeometry_getPartChannel(const CSFGeometry* geo, CSFGeometryPartChannel channel);
|
|
|
|
// accumulates partchannel sizes and multiplies with geo->numParts
|
|
CSFAPI size_t CSFGeometry_getPerPartSize(const CSFGeometry* geo);
|
|
// accumulates partchannel sizes and multiplies with provided numParts
|
|
CSFAPI size_t CSFGeometry_getPerPartRequiredSize(const CSFGeometry* geo, int numParts);
|
|
CSFAPI size_t CSFGeometry_getPerPartRequiredOffset(const CSFGeometry* geo, int numParts, CSFGeometryPartChannel channel);
|
|
// single element size
|
|
CSFAPI size_t CSFGeometryPartChannel_getSize(CSFGeometryPartChannel channel);
|
|
|
|
// meta can be nullptr
|
|
CSFAPI const CSFBytePacket* CSFMeta_getBytePacket(const CSFMeta* meta, const CSFGuid guid);
|
|
|
|
CSFAPI const CSFBytePacket* CSFMaterial_getBytePacket(const CSFMaterial* material, const CSFGuid guid);
|
|
CSFAPI const CSFBytePacket* CSFile_getMaterialBytePacket(const CSFile* csf, int materialIDX, const CSFGuid guid);
|
|
|
|
CSFAPI const CSFBytePacket* CSFile_getFileBytePacket(const CSFile* csf, const CSFGuid guid);
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
CSFAPI int CSFile_transform(CSFile* csf); // requires unique nodes
|
|
CSFAPI void CSFMatrix_identity(float*);
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
// The CSFileHandle allows to open a file without fully loading all its
|
|
// content. Only works on uncompressed files.
|
|
// The access to same file is currently NOT thread-safe.
|
|
//
|
|
// Not the most tested / commonly used api
|
|
|
|
typedef struct CSFileHandle_s* CSFileHandlePTR;
|
|
|
|
CSFAPI int CSFileHandle_open(CSFileHandlePTR* pHandle, const char* filename);
|
|
CSFAPI void CSFileHandle_close(CSFileHandlePTR handle);
|
|
|
|
typedef enum CSFileHandleContentBit_e
|
|
{
|
|
CSFILEHANDLE_CONTENT_MATERIAL = 1,
|
|
CSFILEHANDLE_CONTENT_GEOMETRY = 2,
|
|
CSFILEHANDLE_CONTENT_NODE = 4,
|
|
CSFILEHANDLE_CONTENT_GEOMETRYMETA = 8,
|
|
CSFILEHANDLE_CONTENT_NODEMETA = 16,
|
|
CSFILEHANDLE_CONTENT_FILEMETA = 32,
|
|
} CSFileHandleContentBit;
|
|
|
|
// zeros pointer arrays to avoid accidental access
|
|
// fills and returns header passed in
|
|
CSFAPI CSFile* CSFileHandle_loadHeader(CSFileHandlePTR handle, CSFile* header);
|
|
// keeps file offsets
|
|
// fills and returns header passed in
|
|
CSFAPI CSFile* CSFileHandle_rawHeader(CSFileHandlePTR handle, CSFile* header);
|
|
|
|
// Loads the csfile with its primary arrays, but without the data pointed to by an array element.
|
|
// Which arrays should be loaded is provided by the bitflag.
|
|
// The CSFile struct and the arrays are allocated within mem.
|
|
CSFAPI CSFile* CSFileHandle_loadBasics(CSFileHandlePTR handle, uint32_t contentbitsflag, CSFileMemoryPTR mem);
|
|
|
|
// Loads the array elements along with their content, returns an array of the appropriate struct type for num elements.
|
|
// The array and content is allocated within mem
|
|
CSFAPI void* CSFileHandle_loadElements(CSFileHandlePTR handle, CSFileHandleContentBit contentbit, int begin, int num, CSFileMemoryPTR mem);
|
|
|
|
// similar as above but the primary struct array is provided by the pointer, rest of data is allocated into mem
|
|
CSFAPI void* CSFileHandle_loadElementsInto(CSFileHandlePTR handle,
|
|
CSFileHandleContentBit contentbit,
|
|
int begin,
|
|
int num,
|
|
CSFileMemoryPTR mem,
|
|
size_t pimarySize,
|
|
void* primaryArray);
|
|
};
|
|
|
|
#define CSF_logPrintf(outlog, ...) \
|
|
if((outlog)) \
|
|
{ \
|
|
fprintf((outlog), __VA_ARGS__); \
|
|
}
|
|
|
|
inline size_t CSF_alignIndexAllocation(size_t size)
|
|
{
|
|
return (size + 3) & ~3;
|
|
}
|
|
|
|
#ifdef __cplusplus
|
|
|
|
template <typename T>
|
|
inline T* CSFGeometry_getPartChannelT(CSFGeometry* geo, CSFGeometryPartChannel channel)
|
|
{
|
|
return (T*)CSFGeometry_getPartChannel(geo, channel);
|
|
}
|
|
|
|
template <typename T>
|
|
inline const T* CSFGeometry_getPartChannelT(const CSFGeometry* geo, CSFGeometryPartChannel channel)
|
|
{
|
|
return (const T*)CSFGeometry_getPartChannel(geo, channel);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T* CSFileMemory_allocCopyT(CSFileMemoryPTR mem, const T* src, size_t num)
|
|
{
|
|
if(num == 0)
|
|
return nullptr;
|
|
return (T*)CSFileMemory_alloc(mem, sizeof(T) * num, src);
|
|
}
|
|
|
|
template <typename T>
|
|
inline T* CSFileMemory_allocPartialT(CSFileMemoryPTR mem, size_t num, size_t numSrc, const T* src)
|
|
{
|
|
if(num == 0)
|
|
return nullptr;
|
|
return (T*)CSFileMemory_allocPartial(mem, sizeof(T) * num, sizeof(T) * numSrc, src);
|
|
}
|
|
|
|
#if !CSF_DISABLE_FILEMAPPING_SUPPORT
|
|
struct CSFReadMapping
|
|
{
|
|
CSFReadMappingPTR mapping;
|
|
|
|
|
|
CSFReadMapping() {}
|
|
CSFReadMapping(const char* filename) { mapping = CSFReadMapping_new(filename); }
|
|
|
|
CSFReadMapping(CSFReadMapping&& other) noexcept { this->operator=(std::move(other)); };
|
|
CSFReadMapping& operator=(CSFReadMapping&& other)
|
|
{
|
|
mapping = other.mapping;
|
|
other.mapping = nullptr;
|
|
return *this;
|
|
}
|
|
CSFReadMapping(const CSFReadMapping&) = delete;
|
|
CSFReadMapping& operator=(const CSFReadMapping& other) = delete;
|
|
|
|
size_t getSize() const { return mapping ? CSFReadMapping_getSize(mapping) : 0; }
|
|
|
|
const void* getData() const { return mapping ? CSFReadMapping_getData(mapping) : nullptr; }
|
|
|
|
~CSFReadMapping()
|
|
{
|
|
if(mapping)
|
|
{
|
|
CSFReadMapping_delete(mapping);
|
|
}
|
|
}
|
|
};
|
|
|
|
struct CSFWriteMapping
|
|
{
|
|
CSFWriteMappingPTR mapping;
|
|
|
|
CSFWriteMapping() {}
|
|
CSFWriteMapping(const char* filename, size_t fileSize) { mapping = CSFWriteMapping_new(filename, fileSize); }
|
|
|
|
CSFWriteMapping(CSFWriteMapping&& other) noexcept { this->operator=(std::move(other)); };
|
|
CSFWriteMapping& operator=(CSFWriteMapping&& other)
|
|
{
|
|
mapping = other.mapping;
|
|
other.mapping = nullptr;
|
|
return *this;
|
|
}
|
|
CSFWriteMapping(const CSFWriteMapping&) = delete;
|
|
CSFWriteMapping& operator=(const CSFWriteMapping& other) = delete;
|
|
|
|
size_t getSize() const { return mapping ? CSFWriteMapping_getSize(mapping) : 0; }
|
|
|
|
void* getData() const { return mapping ? CSFWriteMapping_getData(mapping) : nullptr; }
|
|
|
|
~CSFWriteMapping()
|
|
{
|
|
if(mapping)
|
|
{
|
|
CSFWriteMapping_delete(mapping);
|
|
}
|
|
}
|
|
};
|
|
#endif
|
|
|
|
#if CSF_PARALLEL_WORK || defined(CSF_IMPLEMENTATION)
|
|
namespace csfutils {
|
|
|
|
#if !defined(NDEBUG) && 0
|
|
#define CSF_DEFAULT_NUM_THREADS 1
|
|
#else
|
|
#define CSF_DEFAULT_NUM_THREADS uint32_t(std::thread::hardware_concurrency())
|
|
#endif
|
|
|
|
inline uint32_t parallel_items(uint64_t numItems,
|
|
std::function<void(uint64_t idx, uint32_t threadIdx, void* userData)> fn,
|
|
void* userData = nullptr,
|
|
uint32_t batchSize = 1,
|
|
uint32_t numThreads = CSF_DEFAULT_NUM_THREADS)
|
|
{
|
|
if(numThreads <= 1 || numItems < numThreads || numItems < batchSize)
|
|
{
|
|
for(uint64_t idx = 0; idx < numItems; idx++)
|
|
{
|
|
fn(idx, 0, userData);
|
|
}
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
std::atomic_uint64_t counter = 0;
|
|
|
|
auto worker = [&](uint32_t threadIdx) {
|
|
uint64_t idxBegin;
|
|
while((idxBegin = counter.fetch_add(batchSize)) < numItems)
|
|
{
|
|
uint64_t idxLast = std::min(numItems, idxBegin + batchSize);
|
|
for(uint64_t idx = idxBegin; idx < idxLast; idx++)
|
|
{
|
|
fn(idx, threadIdx, userData);
|
|
}
|
|
}
|
|
};
|
|
|
|
std::thread* threads = new std::thread[numThreads];
|
|
for(uint32_t i = 0; i < numThreads; i++)
|
|
{
|
|
threads[i] = std::thread(worker, i);
|
|
}
|
|
|
|
for(uint32_t i = 0; i < numThreads; i++)
|
|
{
|
|
threads[i].join();
|
|
}
|
|
delete[] threads;
|
|
|
|
return numThreads;
|
|
}
|
|
}
|
|
|
|
inline uint32_t parallel_ranges(uint64_t numItems,
|
|
std::function<void(uint64_t idxBegin, uint64_t idxEnd, uint32_t threadIdx, void* userData)> fn,
|
|
void* userData = nullptr,
|
|
uint32_t batchSize = 1024,
|
|
uint32_t numThreads = CSF_DEFAULT_NUM_THREADS)
|
|
{
|
|
if(numThreads <= 1 || numItems < numThreads || numItems < batchSize)
|
|
{
|
|
fn(0, numItems, 0, userData);
|
|
return 1;
|
|
}
|
|
else
|
|
{
|
|
std::atomic_uint64_t counter = 0;
|
|
|
|
auto worker = [&](uint32_t threadIdx) {
|
|
uint64_t idxBegin;
|
|
while((idxBegin = counter.fetch_add(batchSize)) < numItems)
|
|
{
|
|
uint64_t idxLast = std::min(numItems, idxBegin + batchSize);
|
|
fn(idxBegin, idxLast, threadIdx, userData);
|
|
}
|
|
};
|
|
|
|
std::thread* threads = new std::thread[numThreads];
|
|
for(uint32_t i = 0; i < numThreads; i++)
|
|
{
|
|
threads[i] = std::thread(worker, i);
|
|
}
|
|
|
|
for(uint32_t i = 0; i < numThreads; i++)
|
|
{
|
|
threads[i].join();
|
|
}
|
|
delete[] threads;
|
|
|
|
return numThreads;
|
|
}
|
|
}
|
|
} // namespace csfutils
|
|
#endif
|
|
#endif
|
|
|
|
#ifdef CSF_IMPLEMENTATION
|
|
#include "cadscenefile.inl"
|
|
#endif
|