225 lines
7.2 KiB
C
225 lines
7.2 KiB
C
|
|
#include "../global.h"
|
|
|
|
void import_obj_run(char *path, bool replace_existing) {
|
|
buffer_t *b = data_get_blob(path);
|
|
import_obj_parse(b, replace_existing);
|
|
data_delete_blob(path);
|
|
}
|
|
|
|
void import_obj_parse(buffer_t *b, bool replace_existing) {
|
|
split_type_t i = g_context->split_by;
|
|
bool is_udim = i == SPLIT_TYPE_UDIM;
|
|
i32 split_code = (i == SPLIT_TYPE_OBJECT || is_udim) ? 'o' : 'u'; // usemtl
|
|
|
|
if (is_udim) {
|
|
raw_mesh_t *part = obj_parse(b, split_code, 0, is_udim);
|
|
char *name = part->name;
|
|
u32_array_t *inda_full = part->inda;
|
|
bool first = true;
|
|
for (i32 i = 0; i < part->udims->length; ++i) {
|
|
u32_array_t *a = part->udims->buffer[i];
|
|
if (a->length == 0) {
|
|
array_free(a);
|
|
free(a);
|
|
continue;
|
|
}
|
|
i32 u = i % part->udims_u;
|
|
i32 v = math_floor(i / (float)part->udims_u);
|
|
i32 id = (1000 + v * 10 + u + 1);
|
|
part->name = string("%s.%s", name, i32_to_string(id));
|
|
part->inda = a;
|
|
if (first) {
|
|
first = false;
|
|
if (replace_existing) {
|
|
import_mesh_make_mesh(part);
|
|
}
|
|
else {
|
|
import_mesh_add_mesh(part);
|
|
}
|
|
}
|
|
else {
|
|
part->posa = i16_array_create_from_array(part->posa);
|
|
part->nora = i16_array_create_from_array(part->nora);
|
|
if (part->texa != NULL) {
|
|
part->texa = i16_array_create_from_array(part->texa);
|
|
}
|
|
import_mesh_add_mesh(part);
|
|
}
|
|
}
|
|
array_free(inda_full);
|
|
free(inda_full);
|
|
array_free(part->udims);
|
|
free(part->udims);
|
|
free(name);
|
|
free(part);
|
|
}
|
|
else {
|
|
raw_mesh_t_array_t *parts = any_array_create_from_raw((void *[]){}, 0);
|
|
raw_mesh_t_array_t *discarded = any_array_create_from_raw((void *[]){}, 0);
|
|
raw_mesh_t *part = obj_parse(b, split_code, 0, false);
|
|
any_array_push(parts, part);
|
|
while (part->has_next) {
|
|
part = obj_parse(b, split_code, part->pos, false);
|
|
// This part does not contain faces (may contain lines only)
|
|
if (part->inda->length == 0) {
|
|
any_array_push(discarded, part);
|
|
continue;
|
|
}
|
|
any_array_push(parts, part);
|
|
}
|
|
if (g_context->split_by == SPLIT_TYPE_MATERIAL) {
|
|
i16_array_t *posa0;
|
|
i16_array_t *posa1;
|
|
i16_array_t *nora0;
|
|
i16_array_t *nora1;
|
|
i16_array_t *texa0;
|
|
i16_array_t *texa1;
|
|
u32_array_t *inda0;
|
|
u32_array_t *inda1;
|
|
// Merge to single object per material
|
|
for (i32 i = 0; i < parts->length; ++i) {
|
|
i32 j = i + 1;
|
|
while (j < parts->length) {
|
|
char *iname = parts->buffer[i]->name;
|
|
char *jname = parts->buffer[j]->name;
|
|
if (string_equals(iname, jname)) {
|
|
posa0 = parts->buffer[i]->posa;
|
|
posa1 = parts->buffer[j]->posa;
|
|
nora0 = parts->buffer[i]->nora;
|
|
nora1 = parts->buffer[j]->nora;
|
|
texa0 = parts->buffer[i]->texa != NULL ? parts->buffer[i]->texa : NULL;
|
|
texa1 = parts->buffer[j]->texa != NULL ? parts->buffer[j]->texa : NULL;
|
|
inda0 = parts->buffer[i]->inda;
|
|
inda1 = parts->buffer[j]->inda;
|
|
i32 voff = math_floor(posa0->length / 4.0);
|
|
// Repack merged positions
|
|
f32_array_t *posa32 = f32_array_create(math_floor(posa0->length / 4.0) * 3 + math_floor(posa1->length / 4.0) * 3);
|
|
for (i32 k = 0; k < math_floor(posa0->length / 4.0); ++k) {
|
|
posa32->buffer[k * 3] = posa0->buffer[k * 4] / 32767.0 * parts->buffer[i]->scale_pos;
|
|
posa32->buffer[k * 3 + 1] = posa0->buffer[k * 4 + 1] / 32767.0 * parts->buffer[i]->scale_pos;
|
|
posa32->buffer[k * 3 + 2] = posa0->buffer[k * 4 + 2] / 32767.0 * parts->buffer[i]->scale_pos;
|
|
}
|
|
for (i32 k = 0; k < math_floor(posa1->length / 4.0); ++k) {
|
|
posa32->buffer[voff * 3 + k * 3] = posa1->buffer[k * 4] / 32767.0 * parts->buffer[j]->scale_pos;
|
|
posa32->buffer[voff * 3 + k * 3 + 1] = posa1->buffer[k * 4 + 1] / 32767.0 * parts->buffer[j]->scale_pos;
|
|
posa32->buffer[voff * 3 + k * 3 + 2] = posa1->buffer[k * 4 + 2] / 32767.0 * parts->buffer[j]->scale_pos;
|
|
}
|
|
f32 scale_pos = 0.0;
|
|
for (i32 k = 0; k < posa32->length; ++k) {
|
|
f32 f = math_abs(posa32->buffer[k]);
|
|
if (scale_pos < f) {
|
|
scale_pos = f;
|
|
}
|
|
}
|
|
f32 inv = 32767 * (1 / (float)scale_pos);
|
|
i16_array_t *posa = i16_array_create(posa0->length + posa1->length);
|
|
for (i32 k = 0; k < math_floor(posa->length / 4.0); ++k) {
|
|
posa->buffer[k * 4] = math_floor(posa32->buffer[k * 3] * inv);
|
|
posa->buffer[k * 4 + 1] = math_floor(posa32->buffer[k * 3 + 1] * inv);
|
|
posa->buffer[k * 4 + 2] = math_floor(posa32->buffer[k * 3 + 2] * inv);
|
|
}
|
|
for (i32 k = 0; k < math_floor(posa0->length / 4.0); ++k) {
|
|
posa->buffer[k * 4 + 3] = posa0->buffer[k * 4 + 3];
|
|
}
|
|
for (i32 k = 0; k < math_floor(posa1->length / 4.0); ++k) {
|
|
posa->buffer[posa0->length + k * 4 + 3] = posa1->buffer[k * 4 + 3];
|
|
}
|
|
// Merge normals and uvs
|
|
i16_array_t *nora = i16_array_create(nora0->length + nora1->length);
|
|
i16_array_t *texa = (texa0 != NULL && texa1 != NULL) ? i16_array_create(texa0->length + texa1->length) : NULL;
|
|
u32_array_t *inda = u32_array_create(inda0->length + inda1->length);
|
|
|
|
for (i32 k = 0; k < nora0->length; ++k) {
|
|
nora->buffer[k] = nora0->buffer[k];
|
|
}
|
|
for (i32 k = 0; k < nora1->length; ++k) {
|
|
nora->buffer[k + nora0->length] = nora1->buffer[k];
|
|
}
|
|
|
|
if (texa != NULL) {
|
|
for (i32 k = 0; k < texa0->length; ++k) {
|
|
texa->buffer[k] = texa0->buffer[k];
|
|
}
|
|
for (i32 k = 0; k < texa1->length; ++k) {
|
|
texa->buffer[k + texa0->length] = texa1->buffer[k];
|
|
}
|
|
}
|
|
|
|
for (i32 k = 0; k < inda0->length; ++k) {
|
|
inda->buffer[k] = inda0->buffer[k];
|
|
}
|
|
for (i32 k = 0; k < inda1->length; ++k) {
|
|
inda->buffer[k + inda0->length] = inda1->buffer[k] + voff;
|
|
}
|
|
|
|
array_free(posa32);
|
|
free(posa32);
|
|
array_free(posa0);
|
|
free(posa0);
|
|
array_free(nora0);
|
|
free(nora0);
|
|
array_free(inda0);
|
|
free(inda0);
|
|
if (texa0 != NULL) {
|
|
array_free(texa0);
|
|
free(texa0);
|
|
}
|
|
array_free(posa1);
|
|
free(posa1);
|
|
array_free(nora1);
|
|
free(nora1);
|
|
array_free(inda1);
|
|
free(inda1);
|
|
if (texa1 != NULL) {
|
|
array_free(texa1);
|
|
free(texa1);
|
|
}
|
|
raw_mesh_t *jpart = parts->buffer[j];
|
|
free(jpart->name);
|
|
free(jpart);
|
|
|
|
parts->buffer[i]->posa = posa;
|
|
parts->buffer[i]->nora = nora;
|
|
parts->buffer[i]->texa = texa;
|
|
parts->buffer[i]->inda = inda;
|
|
parts->buffer[i]->scale_pos = scale_pos;
|
|
array_splice(parts, j, 1);
|
|
}
|
|
else {
|
|
j++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
replace_existing ? import_mesh_make_mesh(parts->buffer[0]) : import_mesh_add_mesh(parts->buffer[0]);
|
|
for (i32 i = 1; i < parts->length; ++i) {
|
|
import_mesh_add_mesh(parts->buffer[i]);
|
|
}
|
|
|
|
for (i32 i = 0; i < parts->length; ++i) {
|
|
free(parts->buffer[i]);
|
|
}
|
|
array_free(parts);
|
|
free(parts);
|
|
for (i32 i = 0; i < discarded->length; ++i) {
|
|
raw_mesh_t *d = discarded->buffer[i];
|
|
array_free(d->posa);
|
|
free(d->posa);
|
|
array_free(d->nora);
|
|
free(d->nora);
|
|
if (d->texa != NULL) {
|
|
array_free(d->texa);
|
|
free(d->texa);
|
|
}
|
|
array_free(d->inda);
|
|
free(d->inda);
|
|
free(d->name);
|
|
free(d);
|
|
}
|
|
array_free(discarded);
|
|
free(discarded);
|
|
}
|
|
}
|