Files
armorpaint/paint/sources/io/import_obj.c
T
2026-08-24 08:32:08 +02:00

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);
}
}