Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for double precision. #229

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
86 changes: 49 additions & 37 deletions cgltf.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@
*
* `cgltf_num_components` is a tiny utility that tells you the dimensionality of
* a certain accessor type. This can be used before `cgltf_accessor_unpack_floats` to help allocate
* the necessary amount of memory. `cgltf_component_size` and `cgltf_calc_size` exist for
* the necessary amount of memory. `cgltf_component_size` and `cgltf_calc_size` exist for
* similar purposes.
*
* `cgltf_accessor_read_float` reads a certain element from a non-sparse accessor and converts it to
Expand All @@ -75,7 +75,7 @@
*
* `cgltf_accessor_read_uint` is similar to its floating-point counterpart, but limited to reading
* vector types and does not support matrix types. The passed-in element size is the number of uints
* in the output buffer, which should be in the range [1, 4]. Returns false if the passed-in
* in the output buffer, which should be in the range [1, 4]. Returns false if the passed-in
* element_size is too small, or if the accessor is sparse.
*
* `cgltf_accessor_read_index` is similar to its floating-point counterpart, but it returns size_t
Expand All @@ -98,7 +98,12 @@ extern "C" {

typedef size_t cgltf_size;
typedef long long int cgltf_ssize;
#ifdef CGLTF_DOUBLE_PRECISION
typedef double cgltf_float;
#else
typedef float cgltf_float;
#endif
typedef float cgltf_float32;
typedef int cgltf_int;
typedef unsigned int cgltf_uint;
typedef int cgltf_bool;
Expand Down Expand Up @@ -1045,7 +1050,7 @@ static cgltf_result cgltf_default_file_read(const struct cgltf_memory_options* m
fclose(file);
return cgltf_result_out_of_memory;
}

cgltf_size read_size = fread(file_data, 1, file_size, file);

fclose(file);
Expand Down Expand Up @@ -1977,7 +1982,7 @@ void cgltf_free(cgltf_data* data)

data->memory.free_func(data->memory.user_data, data->materials);

for (cgltf_size i = 0; i < data->images_count; ++i)
for (cgltf_size i = 0; i < data->images_count; ++i)
{
data->memory.free_func(data->memory.user_data, data->images[i].name);
data->memory.free_func(data->memory.user_data, data->images[i].uri);
Expand Down Expand Up @@ -2141,22 +2146,22 @@ void cgltf_node_transform_local(const cgltf_node* node, cgltf_float* out_matrix)

if (node->has_matrix)
{
memcpy(lm, node->matrix, sizeof(float) * 16);
memcpy(lm, node->matrix, sizeof(cgltf_float) * 16);
}
else
{
float tx = node->translation[0];
float ty = node->translation[1];
float tz = node->translation[2];
cgltf_float tx = node->translation[0];
cgltf_float ty = node->translation[1];
cgltf_float tz = node->translation[2];

float qx = node->rotation[0];
float qy = node->rotation[1];
float qz = node->rotation[2];
float qw = node->rotation[3];
cgltf_float qx = node->rotation[0];
cgltf_float qy = node->rotation[1];
cgltf_float qz = node->rotation[2];
cgltf_float qw = node->rotation[3];

float sx = node->scale[0];
float sy = node->scale[1];
float sz = node->scale[2];
cgltf_float sx = node->scale[0];
cgltf_float sy = node->scale[1];
cgltf_float sz = node->scale[2];

lm[0] = (1 - 2 * qy*qy - 2 * qz*qz) * sx;
lm[1] = (2 * qx*qy + 2 * qz*qw) * sx;
Expand Down Expand Up @@ -2189,18 +2194,18 @@ void cgltf_node_transform_world(const cgltf_node* node, cgltf_float* out_matrix)

while (parent)
{
float pm[16];
cgltf_float pm[16];
cgltf_node_transform_local(parent, pm);

for (int i = 0; i < 4; ++i)
{
float l0 = lm[i * 4 + 0];
float l1 = lm[i * 4 + 1];
float l2 = lm[i * 4 + 2];
cgltf_float l0 = lm[i * 4 + 0];
cgltf_float l1 = lm[i * 4 + 1];
cgltf_float l2 = lm[i * 4 + 2];

float r0 = l0 * pm[0] + l1 * pm[4] + l2 * pm[8];
float r1 = l0 * pm[1] + l1 * pm[5] + l2 * pm[9];
float r2 = l0 * pm[2] + l1 * pm[6] + l2 * pm[10];
cgltf_float r0 = l0 * pm[0] + l1 * pm[4] + l2 * pm[8];
cgltf_float r1 = l0 * pm[1] + l1 * pm[5] + l2 * pm[9];
cgltf_float r2 = l0 * pm[2] + l1 * pm[6] + l2 * pm[10];

lm[i * 4 + 0] = r0;
lm[i * 4 + 1] = r1;
Expand All @@ -2226,7 +2231,7 @@ static cgltf_ssize cgltf_component_read_integer(const void* in, cgltf_component_
case cgltf_component_type_r_32u:
return *((const uint32_t*) in);
case cgltf_component_type_r_32f:
return (cgltf_ssize)*((const float*) in);
return (cgltf_ssize)*((const cgltf_float32*) in);
case cgltf_component_type_r_8:
return *((const int8_t*) in);
case cgltf_component_type_r_8u:
Expand All @@ -2245,7 +2250,7 @@ static cgltf_size cgltf_component_read_index(const void* in, cgltf_component_typ
case cgltf_component_type_r_32u:
return *((const uint32_t*) in);
case cgltf_component_type_r_32f:
return (cgltf_size)((cgltf_ssize)*((const float*) in));
return (cgltf_size)((cgltf_ssize)*((const cgltf_float32*) in));
case cgltf_component_type_r_8u:
return *((const uint8_t*) in);
default:
Expand All @@ -2257,7 +2262,7 @@ static cgltf_float cgltf_component_read_float(const void* in, cgltf_component_ty
{
if (component_type == cgltf_component_type_r_32f)
{
return *((const float*) in);
return *((const cgltf_float32*) in);
}

if (normalized)
Expand Down Expand Up @@ -2396,9 +2401,16 @@ cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_fl
}
element += accessor->offset;

if (accessor->component_type == cgltf_component_type_r_32f && accessor->stride == floats_per_element * sizeof(cgltf_float))
if (accessor->component_type == cgltf_component_type_r_32f && accessor->stride == floats_per_element * sizeof(cgltf_float32))
{
memcpy(out, element, element_count * floats_per_element * sizeof(cgltf_float));
#ifdef CGLTF_DOUBLE_PRECISION
for (cgltf_size i = 0; i < element_count * floats_per_element; ++i)
{
out[i] = ((const cgltf_float32*)element)[i];
}
#else
memcpy(out, element, element_count * floats_per_element * sizeof(cgltf_float32));
#endif
}
else
{
Expand Down Expand Up @@ -2434,7 +2446,7 @@ cgltf_size cgltf_accessor_unpack_floats(const cgltf_accessor* accessor, cgltf_fl
for (cgltf_size reader_index = 0; reader_index < sparse->count; reader_index++, index_data += index_stride, reader_head += accessor->stride)
{
size_t writer_index = cgltf_component_read_index(index_data, sparse->indices_component_type);
float* writer_head = out + writer_index * floats_per_element;
cgltf_float* writer_head = out + writer_index * floats_per_element;

if (!cgltf_element_read_float(reader_head, accessor->type, accessor->component_type, accessor->normalized, writer_head, floats_per_element))
{
Expand Down Expand Up @@ -2756,15 +2768,15 @@ static int cgltf_skip_json(jsmntok_t const* tokens, int i)
return i;
}

static void cgltf_fill_float_array(float* out_array, int size, float value)
static void cgltf_fill_float_array(cgltf_float* out_array, int size, cgltf_float value)
{
for (int j = 0; j < size; ++j)
{
out_array[j] = value;
}
}

static int cgltf_parse_json_float_array(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, float* out_array, int size)
static int cgltf_parse_json_float_array(jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_float* out_array, int size)
{
CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_ARRAY);
if (tokens[i].size != size)
Expand Down Expand Up @@ -3801,7 +3813,7 @@ static int cgltf_parse_json_texture_view(cgltf_options* options, jsmntok_t const
out_texture_view->texcoord = cgltf_json_to_int(tokens + i, json_chunk);
++i;
}
else if (cgltf_json_strcmp(tokens + i, json_chunk, "scale") == 0)
else if (cgltf_json_strcmp(tokens + i, json_chunk, "scale") == 0)
{
++i;
out_texture_view->scale = cgltf_json_to_float(tokens + i, json_chunk);
Expand Down Expand Up @@ -3886,11 +3898,11 @@ static int cgltf_parse_json_pbr_metallic_roughness(cgltf_options* options, jsmnt
if (cgltf_json_strcmp(tokens+i, json_chunk, "metallicFactor") == 0)
{
++i;
out_pbr->metallic_factor =
out_pbr->metallic_factor =
cgltf_json_to_float(tokens + i, json_chunk);
++i;
}
else if (cgltf_json_strcmp(tokens+i, json_chunk, "roughnessFactor") == 0)
else if (cgltf_json_strcmp(tokens+i, json_chunk, "roughnessFactor") == 0)
{
++i;
out_pbr->roughness_factor =
Expand Down Expand Up @@ -4360,11 +4372,11 @@ static int cgltf_parse_json_image(cgltf_options* options, jsmntok_t const* token
int size = tokens[i].size;
++i;

for (int j = 0; j < size; ++j)
for (int j = 0; j < size; ++j)
{
CGLTF_CHECK_KEY(tokens[i]);

if (cgltf_json_strcmp(tokens + i, json_chunk, "uri") == 0)
if (cgltf_json_strcmp(tokens + i, json_chunk, "uri") == 0)
{
i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_image->uri);
}
Expand Down Expand Up @@ -4444,7 +4456,7 @@ static int cgltf_parse_json_sampler(cgltf_options* options, jsmntok_t const* tok
= cgltf_json_to_int(tokens + i, json_chunk);
++i;
}
else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapT") == 0)
else if (cgltf_json_strcmp(tokens + i, json_chunk, "wrapT") == 0)
{
++i;
out_sampler->wrap_t
Expand Down Expand Up @@ -4494,7 +4506,7 @@ static int cgltf_parse_json_texture(cgltf_options* options, jsmntok_t const* tok
out_texture->sampler = CGLTF_PTRINDEX(cgltf_sampler, cgltf_json_to_int(tokens + i, json_chunk));
++i;
}
else if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0)
else if (cgltf_json_strcmp(tokens + i, json_chunk, "source") == 0)
{
++i;
out_texture->image = CGLTF_PTRINDEX(cgltf_image, cgltf_json_to_int(tokens + i, json_chunk));
Expand Down
17 changes: 13 additions & 4 deletions cgltf_write.h
Original file line number Diff line number Diff line change
Expand Up @@ -104,12 +104,21 @@ typedef struct {

#define CGLTF_MIN(a, b) (a < b ? a : b)

#ifdef CGLTF_DOUBLE_PRECISION
#ifdef DBL_DECIMAL_DIG
// DBL_DECIMAL_DIG is C11
#define CGLTF_DECIMAL_DIG (DBL_DECIMAL_DIG)
#else
#define CGLTF_DECIMAL_DIG 17
#endif
#else
#ifdef FLT_DECIMAL_DIG
// FLT_DECIMAL_DIG is C11
#define CGLTF_DECIMAL_DIG (FLT_DECIMAL_DIG)
#else
#define CGLTF_DECIMAL_DIG 9
#endif
#endif

#define CGLTF_SPRINTF(...) { \
assert(context->cursor || (!context->cursor && context->remaining == 0)); \
Expand Down Expand Up @@ -287,7 +296,7 @@ static void cgltf_write_sizeprop(cgltf_write_context* context, const char* label
}
}

static void cgltf_write_floatprop(cgltf_write_context* context, const char* label, float val, float def)
static void cgltf_write_floatprop(cgltf_write_context* context, const char* label, cgltf_float val, cgltf_float def)
{
if (val != def)
{
Expand Down Expand Up @@ -336,7 +345,7 @@ static void cgltf_write_floatarrayprop(cgltf_write_context* context, const char*
context->needs_comma = 1;
}

static bool cgltf_check_floatarray(const float* vals, int dim, float val) {
static bool cgltf_check_floatarray(const cgltf_float* vals, int dim, cgltf_float val) {
while (dim--)
{
if (vals[dim] != val)
Expand Down Expand Up @@ -493,7 +502,7 @@ static void cgltf_write_primitive(cgltf_write_context* context, const cgltf_prim
context->extension_flags |= CGLTF_EXTENSION_FLAG_DRACO_MESH_COMPRESSION;
if (prim->attributes_count == 0 || prim->indices == 0)
{
context->required_extension_flags |= CGLTF_EXTENSION_FLAG_DRACO_MESH_COMPRESSION;
context->required_extension_flags |= CGLTF_EXTENSION_FLAG_DRACO_MESH_COMPRESSION;
}

cgltf_write_line(context, "\"KHR_draco_mesh_compression\": {");
Expand Down Expand Up @@ -714,7 +723,7 @@ static void cgltf_write_material(cgltf_write_context* context, const cgltf_mater
{
cgltf_write_floatarrayprop(context, "attenuationColor", params->attenuation_color, 3);
}
if (params->attenuation_distance < FLT_MAX)
if (params->attenuation_distance < FLT_MAX)
{
cgltf_write_floatprop(context, "attenuationDistance", params->attenuation_distance, FLT_MAX);
}
Expand Down
5 changes: 5 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
cmake_minimum_required( VERSION 2.8 )

option(CGLTF_DOUBLE_PRECISION "Double Precision" OFF)
if(CGLTF_DOUBLE_PRECISION)
add_definitions(-DCGLTF_DOUBLE_PRECISION)
endif()

include_directories( ${CMAKE_CURRENT_SOURCE_DIR} )

set( EXE_NAME cgltf_test )
Expand Down
5 changes: 4 additions & 1 deletion test/test_all.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ def collect_files(path, type, name):
if not os.path.exists("build/"):
os.makedirs("build/")
os.chdir("build/")
os.system("cmake ..")
if '--double-precision' in sys.argv:
os.system("cmake .. -DCGLTF_DOUBLE_PRECISION=ON")
else:
os.system("cmake ..")
if os.system("cmake --build .") != 0:
print("Unable to build.")
exit(1)
Expand Down
9 changes: 6 additions & 3 deletions test/test_conversion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

static bool is_near(cgltf_float a, cgltf_float b)
{
return std::abs(a - b) < 10 * std::numeric_limits<cgltf_float>::min();
return std::abs((float)a - (float)b) < 10 * std::numeric_limits<float>::min();
}

int main(int argc, char** argv)
Expand Down Expand Up @@ -49,15 +49,16 @@ int main(int argc, char** argv)
cgltf_float* dense = (cgltf_float*) malloc(nfloats * sizeof(cgltf_float));
if (cgltf_accessor_unpack_floats(blob, dense, nfloats) < nfloats) {
printf("Unable to completely unpack a sparse accessor.\n");
cgltf_free(data);
return -1;
}
free(dense);
continue;
}
if (blob->has_max && blob->has_min)
{
cgltf_float min0 = std::numeric_limits<float>::max();
cgltf_float max0 = std::numeric_limits<float>::lowest();
cgltf_float min0 = std::numeric_limits<cgltf_float>::max();
cgltf_float max0 = std::numeric_limits<cgltf_float>::lowest();
for (cgltf_size index = 0; index < blob->count; index++)
{
cgltf_accessor_read_float(blob, index, element_float, 16);
Expand All @@ -67,6 +68,7 @@ int main(int argc, char** argv)
if (!is_near(min0, blob->min[0]) || !is_near(max0, blob->max[0]))
{
printf("Computed [%f, %f] but expected [%f, %f]\n", min0, max0, blob->min[0], blob->max[0]);
cgltf_free(data);
return -1;
}
}
Expand All @@ -83,6 +85,7 @@ int main(int argc, char** argv)
if ( min0 != (unsigned int) blob->min[0] || max0 != (unsigned int) blob->max[0] )
{
printf( "Computed [%u, %u] but expected [%u, %u]\n", min0, max0, (unsigned int) blob->min[0], (unsigned int) blob->max[0] );
cgltf_free(data);
return -1;
}
}
Expand Down
4 changes: 2 additions & 2 deletions test/test_math.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,13 +9,13 @@ static void transform(const cgltf_float matrix[16], const cgltf_float source[4],
target[3] = matrix[3] * source[0] + matrix[7] * source[1] + matrix[11] * source[2] + matrix[15] * source[3];
}

static void set(cgltf_float target[3], float x, float y, float z) {
static void set(cgltf_float target[3], cgltf_float x, cgltf_float y, cgltf_float z) {
target[0] = x;
target[1] = y;
target[2] = z;
}

static void check(cgltf_float target[3], float x, float y, float z) {
static void check(cgltf_float target[3], cgltf_float x, cgltf_float y, cgltf_float z) {
if (target[0] != x || target[1] != y || target[2] != z) {
fprintf(stderr, "Mismatch detected.\n");
exit(1);
Expand Down