18using namespace helios;
21 return addPatch(
make_vec3(0, 0, 0),
make_vec2(1, 1),
make_SphericalCoord(0, 0),
make_RGBAcolor(0, 0, 0, 1));
37 if (size.
x < 1e-6f || size.
y < 1e-6f) {
38 helios_runtime_error(
"ERROR (Context::addPatch): Size of patch must be greater than 1e-6 to avoid numerical precision issues.");
41 auto *patch_new = (
new Patch(color, 0, currentUUID));
50 patch_new->rotate(-rotation.
elevation,
"x");
53 patch_new->rotate(-rotation.
azimuth,
"z");
56 patch_new->translate(center);
58 primitives[currentUUID] = patch_new;
61 patch_new->context_ptr =
this;
64 std::string mat_label = generateMaterialLabel(color,
"",
false);
66 patch_new->materialID = addMaterial_internal(mat_label, color,
"");
71 materials[patch_new->materialID].reference_count++;
74 invalidateAllUUIDsCache();
75 return currentUUID - 1;
79 addTexture(texture_file);
82 const std::vector<helios::vec2> uv = {{0.f, 0.f}, {1.f, 0.f}, {1.f, 1.f}, {0.f, 1.f}};
84 auto *patch_new = (
new Patch(texture_file, uv, textures, 0, currentUUID));
90 assert(size.
x > 0.f && size.
y > 0.f);
94 patch_new->rotate(-rotation.
elevation,
"x");
97 patch_new->rotate(-rotation.
azimuth,
"z");
100 patch_new->translate(center);
102 primitives[currentUUID] = patch_new;
105 patch_new->context_ptr =
this;
108 std::string mat_label = generateMaterialLabel(
make_RGBAcolor(0, 0, 0, 1), texture_file,
false);
110 patch_new->materialID = addMaterial_internal(mat_label,
make_RGBAcolor(0, 0, 0, 1), texture_file);
115 materials[patch_new->materialID].reference_count++;
118 invalidateAllUUIDsCache();
119 return currentUUID - 1;
123 if (size.
x < 1e-6f || size.
y < 1e-6f) {
124 helios_runtime_error(
"ERROR (Context::addPatch): Size of patch must be greater than 1e-6 to avoid numerical precision issues.");
127 if (uv_center.
x - 0.5 * uv_size.
x < -1e-3 || uv_center.
y - 0.5 * uv_size.
y < -1e-3 || uv_center.
x + 0.5 * uv_size.
x - 1.f > 1e-3 || uv_center.
y + 0.5 * uv_size.
y - 1.f > 1e-3) {
128 helios_runtime_error(
"ERROR (Context::addPatch): Invalid texture coordinates. uv_center-0.5*uv_size should be >=0 and uv_center+0.5*uv_size should be <=1.");
131 addTexture(texture_file);
133 const std::vector<helios::vec2> uv = {uv_center +
make_vec2(-0.5f * uv_size.
x, -0.5f * uv_size.
y), uv_center +
make_vec2(+0.5f * uv_size.
x, -0.5f * uv_size.
y), uv_center +
make_vec2(+0.5f * uv_size.
x, +0.5f * uv_size.
y),
134 uv_center +
make_vec2(-0.5f * uv_size.
x, +0.5f * uv_size.
y)};
136 auto *patch_new = (
new Patch(texture_file, uv, textures, 0, currentUUID));
142 assert(size.
x > 0.f && size.
y > 0.f);
146 patch_new->rotate(-rotation.
elevation,
"x");
149 patch_new->rotate(-rotation.
azimuth,
"z");
152 patch_new->translate(center);
154 primitives[currentUUID] = patch_new;
157 patch_new->context_ptr =
this;
160 std::string mat_label = generateMaterialLabel(
make_RGBAcolor(0, 0, 0, 1), texture_file,
false);
162 patch_new->materialID = addMaterial_internal(mat_label,
make_RGBAcolor(0, 0, 0, 1), texture_file);
167 materials[patch_new->materialID].reference_count++;
170 invalidateAllUUIDsCache();
171 return currentUUID - 1;
183 auto *tri_new = (
new Triangle(vertex0, vertex1, vertex2, color, 0, currentUUID));
187 api_warnings.
addWarning(
"addTriangle_malformed_triangle",
"Triangle has near-zero surface area (< 1e-10).");
191 primitives[currentUUID] = tri_new;
194 tri_new->context_ptr =
this;
197 std::string mat_label = generateMaterialLabel(color,
"",
false);
199 tri_new->materialID = addMaterial_internal(mat_label, color,
"");
204 materials[tri_new->materialID].reference_count++;
207 invalidateAllUUIDsCache();
208 return currentUUID - 1;
212 addTexture(texture_file);
214 const std::vector<helios::vec2> uv{uv0, uv1, uv2};
216 auto *tri_new = (
new Triangle(vertex0, vertex1, vertex2, texture_file, uv, textures, 0, currentUUID));
220 api_warnings.
addWarning(
"addTriangle_malformed_triangle",
"Triangle has near-zero surface area (< 1e-10).");
224 primitives[currentUUID] = tri_new;
227 tri_new->context_ptr =
this;
230 std::string mat_label = generateMaterialLabel(
make_RGBAcolor(0, 0, 0, 1), texture_file,
false);
232 tri_new->materialID = addMaterial_internal(mat_label,
make_RGBAcolor(0, 0, 0, 1), texture_file);
237 materials[tri_new->materialID].reference_count++;
240 invalidateAllUUIDsCache();
241 return currentUUID - 1;
257 auto *voxel_new = (
new Voxel(color, 0, currentUUID));
259 if (size.
x * size.
y * size.
z == 0) {
263 voxel_new->scale(size);
266 voxel_new->rotate(rotation,
"z");
269 voxel_new->translate(center);
271 primitives[currentUUID] = voxel_new;
274 voxel_new->context_ptr =
this;
277 std::string mat_label = generateMaterialLabel(color,
"",
false);
279 voxel_new->materialID = addMaterial_internal(mat_label, color,
"");
284 materials[voxel_new->materialID].reference_count++;
287 invalidateAllUUIDsCache();
288 return currentUUID - 1;
292 getPrimitivePointer_private(UUID)->translate(shift);
299 for (
uint UUID: UUIDs) {
300 getPrimitivePointer_private(UUID)->applyTransform(T);
305 getPrimitivePointer_private(UUID)->rotate(rotation_rad, axis);
309 if (rotation_rad == 0) {
314 if (strcmp(axis,
"z") == 0) {
316 }
else if (strcmp(axis,
"y") == 0) {
318 }
else if (strcmp(axis,
"x") == 0) {
321 helios_runtime_error(
"ERROR (Context::rotatePrimitive): Rotation axis should be one of x, y, or z.");
325 for (
uint UUID: UUIDs) {
326 if (strcmp(axis,
"z") != 0 && getPrimitivePointer_private(UUID)->getType() ==
PRIMITIVE_TYPE_VOXEL) {
327 warnings.
addWarning(
"voxel_rotation_z_only",
"Voxels can only be rotated about the z-axis. Ignoring this rotation.");
329 getPrimitivePointer_private(UUID)->applyTransform(T);
331 warnings.
report(std::cerr);
335 getPrimitivePointer_private(UUID)->rotate(rotation_rad, axis);
339 if (rotation_rad == 0) {
347 for (
uint UUID: UUIDs) {
349 warnings.
addWarning(
"voxel_rotation_z_only",
"Voxels can only be rotated about the z-axis. Ignoring this rotation.");
351 getPrimitivePointer_private(UUID)->applyTransform(T);
353 warnings.
report(std::cerr);
357 getPrimitivePointer_private(UUID)->rotate(rotation_rad, origin, axis);
361 if (rotation_rad == 0) {
369 for (
uint UUID: UUIDs) {
371 warnings.
addWarning(
"voxel_rotation_z_only",
"Voxels can only be rotated about the z-axis. Ignoring this rotation.");
373 getPrimitivePointer_private(UUID)->applyTransform(T);
375 warnings.
report(std::cerr);
381 helios_runtime_error(
"ERROR (Context::setPrimitiveNormal): UUID of " + std::to_string(UUID) +
" not found in the context.");
385 auto *prim = getPrimitivePointer_private(UUID);
392 float d = std::clamp(oldN * newN, -1.f, 1.f);
393 float angle = acosf(d);
396 axis = (std::fabs(oldN.
x) < std::fabs(oldN.
z)) ?
cross(oldN, {1, 0, 0}) :
cross(oldN, {0, 0, 1});
406 prim->getTransformationMatrix(M_old);
418 helios::vec3 t1{M_delta[0] * t0.
x + M_delta[1] * t0.y + M_delta[2] * t0.z, M_delta[4] * t0.x + M_delta[5] * t0.y + M_delta[6] * t0.z, M_delta[8] * t0.x + M_delta[9] * t0.y + M_delta[10] * t0.z};
424 targ = normalize(targ);
428 float twist = std::atan2(newN *
cross(t1, targ),
437 float temp[16], M_new[16];
442 prim->setTransformationMatrix(M_new);
446 for (
uint UUID: UUIDs) {
458 auto *prim = getPrimitivePointer_private(UUID);
459 vec3 oldN = prim->getNormal();
480 auto *prim = getPrimitivePointer_private(UUID);
481 vec3 oldN = prim->getNormal();
498 helios_runtime_error(
"ERROR (Context::scalePrimitive): UUID of " + std::to_string(UUID) +
" not found in the context.");
501 if (S.
x == 1 && S.
y == 1 && S.
z == 1) {
508 getPrimitivePointer_private(UUID)->applyTransform(T);
512 for (
uint UUID: UUIDs) {
520 helios_runtime_error(
"ERROR (Context::scalePrimitiveAboutPoint): UUID of " + std::to_string(UUID) +
" not found in the context.");
523 if (S.
x == 1 && S.
y == 1 && S.
z == 1) {
527 getPrimitivePointer_private(UUID)->scale(S, point);
531 for (
uint UUID: UUIDs) {
537 for (
uint UUID: UUIDs) {
543 if (primitives.find(UUID) == primitives.end()) {
544 helios_runtime_error(
"ERROR (Context::deletePrimitive): UUID of " + std::to_string(UUID) +
" not found in the context.");
547 Primitive *prim = primitives.at(UUID);
549 for (
const auto &[label, type]: prim->primitive_data_types) {
550 decrementPrimitiveDataLabelCounter(label);
553 if (prim->getParentObjectID() != 0) {
555 uint ObjID = prim->getParentObjectID();
557 objects.at(ObjID)->deleteChildPrimitive(UUID);
558 if (getObjectPointer_private(ObjID)->getPrimitiveUUIDs().empty()) {
561 objects.erase(ObjID);
567 materials[prim->materialID].reference_count--;
570 primitives.erase(UUID);
571 dirty_deleted_primitives.push_back(UUID);
572 invalidateAllUUIDsCache();
576 std::vector<uint> UUIDs_copy(UUIDs.size());
578 for (
uint UUID: UUIDs) {
587 if (primitives.find(UUID) == primitives.end()) {
588 helios_runtime_error(
"ERROR (Context::copyPrimitive): UUID of " + std::to_string(UUID) +
" not found in the context.");
592 uint parentID = primitives.at(UUID)->getParentObjectID();
593 bool textureoverride = primitives.at(UUID)->isTextureColorOverridden();
596 Patch *p = getPatchPointer_private(UUID);
597 const std::vector<vec2> &uv = p->getTextureUV();
598 const vec2 &size = p->getSize();
599 float solid_fraction = p->getArea() / (size.
x * size.
y);
601 if (!p->hasTexture()) {
602 patch_new = (
new Patch(p->getColorRGBA(), parentID, currentUUID));
604 const std::string &texture_file = p->getTextureFile();
605 if (uv.size() == 4) {
606 patch_new = (
new Patch(texture_file.c_str(), solid_fraction, parentID, currentUUID));
607 patch_new->setTextureUV(uv);
609 patch_new = (
new Patch(texture_file.c_str(), solid_fraction, parentID, currentUUID));
614 p->getTransformationMatrix(transform);
615 patch_new->setTransformationMatrix(transform);
616 primitives[currentUUID] = patch_new;
618 Triangle *p = getTrianglePointer_private(UUID);
619 const std::vector<vec3> &vertices = p->getVertices();
620 const std::vector<vec2> &uv = p->getTextureUV();
622 if (!p->hasTexture()) {
623 tri_new = (
new Triangle(vertices.at(0), vertices.at(1), vertices.at(2), p->getColorRGBA(), parentID, currentUUID));
625 const std::string &texture_file = p->getTextureFile();
626 float solid_fraction = p->getSolidFraction();
627 tri_new = (
new Triangle(vertices.at(0), vertices.at(1), vertices.at(2), texture_file.c_str(), uv, solid_fraction, parentID, currentUUID));
631 p->getTransformationMatrix(transform);
632 tri_new->setTransformationMatrix(transform);
633 primitives[currentUUID] = tri_new;
635 Voxel *p = getVoxelPointer_private(UUID);
638 voxel_new = (
new Voxel(p->getColorRGBA(), parentID, currentUUID));
644 p->getTransformationMatrix(transform);
645 voxel_new->setTransformationMatrix(transform);
646 primitives[currentUUID] = voxel_new;
650 Primitive *new_prim = getPrimitivePointer_private(currentUUID);
651 new_prim->context_ptr =
this;
652 new_prim->materialID = primitives.at(UUID)->materialID;
654 materials[new_prim->materialID].reference_count++;
658 if (textureoverride) {
659 getPrimitivePointer_private(currentUUID)->overrideTextureColor();
663 invalidateAllUUIDsCache();
664 return currentUUID - 1;
667Primitive *Context::getPrimitivePointer_private(
uint UUID)
const {
669 if (primitives.find(UUID) == primitives.end()) {
670 helios_runtime_error(
"ERROR (Context::getPrimitivePointer_private): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
673 return primitives.at(UUID);
677 return primitives.find(UUID) != primitives.end();
684 for (
uint UUID: UUIDs) {
692Patch *Context::getPatchPointer_private(
uint UUID)
const {
694 if (primitives.find(UUID) == primitives.end()) {
695 helios_runtime_error(
"ERROR (Context::getPatchPointer_private): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
696 }
else if (primitives.at(UUID)->getType() != PRIMITIVE_TYPE_PATCH) {
697 helios_runtime_error(
"ERROR (Context::getPatchPointer_private): UUID of " + std::to_string(UUID) +
" is not a patch.");
700 return dynamic_cast<Patch *
>(primitives.at(UUID));
705 if (primitives.find(UUID) == primitives.end()) {
706 helios_runtime_error(
"ERROR (Context::getPatchSize): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
708 helios_runtime_error(
"ERROR (Context::getPatchSize): UUID of " + std::to_string(UUID) +
" is not a patch.");
711 return dynamic_cast<Patch *
>(primitives.at(UUID))->getSize();
716 if (primitives.find(UUID) == primitives.end()) {
717 helios_runtime_error(
"ERROR (Context::getPatchCenter): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
719 helios_runtime_error(
"ERROR (Context::getPatchCenter): UUID of " + std::to_string(UUID) +
" is not a patch.");
722 return dynamic_cast<Patch *
>(primitives.at(UUID))->getCenter();
725Triangle *Context::getTrianglePointer_private(
uint UUID)
const {
727 if (primitives.find(UUID) == primitives.end()) {
728 helios_runtime_error(
"ERROR (Context::getTrianglePointer_private): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
729 }
else if (primitives.at(UUID)->getType() != PRIMITIVE_TYPE_TRIANGLE) {
730 helios_runtime_error(
"ERROR (Context::getTrianglePointer_private): UUID of " + std::to_string(UUID) +
" is not a triangle.");
733 return dynamic_cast<Triangle *
>(primitives.at(UUID));
738 if (primitives.find(UUID) == primitives.end()) {
739 helios_runtime_error(
"ERROR (Context::getTriangleVertex): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
741 helios_runtime_error(
"ERROR (Context::getTriangleVertex): UUID of " + std::to_string(UUID) +
" is not a triangle.");
742 }
else if (number > 2) {
743 helios_runtime_error(
"ERROR (Context::getTriangleVertex): Vertex index must be one of 0, 1, or 2.");
746 return dynamic_cast<Triangle *
>(primitives.at(UUID))->getVertex(number);
751 if (primitives.find(UUID) == primitives.end()) {
752 helios_runtime_error(
"ERROR (Context::setTriangleVertices): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
755 dynamic_cast<Triangle *
>(primitives.at(UUID))->setVertices(vertex0, vertex1, vertex2);
758Voxel *Context::getVoxelPointer_private(
uint UUID)
const {
760 if (primitives.find(UUID) == primitives.end()) {
761 helios_runtime_error(
"ERROR (Context::getVoxelPointer): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
762 }
else if (primitives.at(UUID)->getType() != PRIMITIVE_TYPE_VOXEL) {
763 helios_runtime_error(
"ERROR (Context::getVoxelPointer): UUID of " + std::to_string(UUID) +
" is not a voxel.");
766 return dynamic_cast<Voxel *
>(primitives.at(UUID));
771 if (primitives.find(UUID) == primitives.end()) {
772 helios_runtime_error(
"ERROR (Context::getVoxelSize): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
774 helios_runtime_error(
"ERROR (Context::getVoxelSize): UUID of " + std::to_string(UUID) +
" is not a patch.");
777 return dynamic_cast<Voxel *
>(primitives.at(UUID))->getSize();
782 if (primitives.find(UUID) == primitives.end()) {
783 helios_runtime_error(
"ERROR (Context::getVoxelCenter): UUID of " + std::to_string(UUID) +
" does not exist in the Context.");
785 helios_runtime_error(
"ERROR (Context::getVoxelCenter): UUID of " + std::to_string(UUID) +
" is not a patch.");
788 return dynamic_cast<Voxel *
>(primitives.at(UUID))->getCenter();
792 if (include_hidden_primitives) {
793 return primitives.size();
796 for (
const auto &[UUID, primitive]: primitives) {
797 if (!primitive->ishidden) {
807 for (
const auto &[UUID, primitive]: primitives) {
817 for (
const auto &[UUID, primitive]: primitives) {
818 if (primitive->getType() ==
PRIMITIVE_TYPE_PATCH && (include_hidden_primitives || !primitive->ishidden)) {
828Primitive::~Primitive() =
default;
830uint Primitive::getUUID()
const {
838void Primitive::setParentObjectID(
uint objID) {
839 parent_object_ID = objID;
842uint Primitive::getParentObjectID()
const {
843 return parent_object_ID;
846void Primitive::getTransformationMatrix(
float (&T)[16])
const {
847 std::memcpy(T, transform, 16 *
sizeof(
float));
850void Primitive::setTransformationMatrix(
float (&T)[16]) {
851 std::memcpy(transform, T, 16 *
sizeof(
float));
855float Patch::getArea()
const {
856 const vec2 &size = getSize();
858 return size.
x * size.
y * solid_fraction;
861float Triangle::getArea()
const {
862 const std::vector<vec3> &vertices = getVertices();
866 return area * solid_fraction;
869float Voxel::getArea()
const {
870 const vec3 size(transform[0], transform[5], transform[10]);
872 return 2.f * size.x * size.y + 2.f * size.x * size.z + 2.f * size.y * size.z;
875vec3 Patch::getNormal()
const {
876 return normalize(
make_vec3(transform[2], transform[6], transform[10]));
879vec3 Triangle::getNormal()
const {
880 const std::vector<vec3> &vertices = getVertices();
881 return normalize(
cross(vertices[1] - vertices[0], vertices[2] - vertices[1]));
884vec3 Voxel::getNormal()
const {
888std::vector<vec3> Patch::getVertices()
const {
889 std::vector<vec3> vertices(4);
891 const std::vector<vec3> Y = {{-0.5f, -0.5f, 0.f}, {0.5f, -0.5f, 0.f}, {0.5f, 0.5f, 0.f}, {-0.5f, 0.5f, 0.f}};
893 for (
int i = 0; i < 4; i++) {
894 vertices[i].x = transform[0] * Y[i].x + transform[1] * Y[i].y + transform[2] * Y[i].z + transform[3];
895 vertices[i].y = transform[4] * Y[i].x + transform[5] * Y[i].y + transform[6] * Y[i].z + transform[7];
896 vertices[i].z = transform[8] * Y[i].x + transform[9] * Y[i].y + transform[10] * Y[i].z + transform[11];
901std::vector<vec3> Triangle::getVertices()
const {
902 std::vector<vec3> vertices(3);
904 const std::vector<vec3> Y = {{0.f, 0.f, 0.f}, {0.f, 1.f, 0.f}, {1.f, 1.f, 0.f}};
906 for (
int i = 0; i < 3; i++) {
907 vertices[i].x = transform[0] * Y[i].x + transform[1] * Y[i].y + transform[2] * Y[i].z + transform[3];
908 vertices[i].y = transform[4] * Y[i].x + transform[5] * Y[i].y + transform[6] * Y[i].z + transform[7];
909 vertices[i].z = transform[8] * Y[i].x + transform[9] * Y[i].y + transform[10] * Y[i].z + transform[11];
914std::vector<vec3> Voxel::getVertices()
const {
915 std::vector<vec3> vertices(8);
917 const std::vector<vec3> Y = {{-0.5f, -0.5f, -0.5f}, {0.5f, -0.5f, -0.5f}, {0.5f, 0.5f, -0.5f}, {-0.5f, 0.5f, -0.5f}, {-0.5f, -0.5f, 0.5f}, {0.5f, -0.5f, 0.5f}, {0.5f, 0.5f, 0.5f}, {-0.5f, 0.5f, 0.5f}};
920 for (
int i = 0; i < 8; i++) {
921 vertices[i].x = transform[0] * Y[i].x + transform[1] * Y[i].y + transform[2] * Y[i].z + transform[3];
922 vertices[i].y = transform[4] * Y[i].x + transform[5] * Y[i].y + transform[6] * Y[i].z + transform[7];
923 vertices[i].z = transform[8] * Y[i].x + transform[9] * Y[i].y + transform[10] * Y[i].z + transform[11];
928RGBcolor Primitive::getColor()
const {
929 if (context_ptr ==
nullptr) {
930 helios_runtime_error(
"ERROR (Primitive::getColor): Primitive not associated with a Context. Use Context::getPrimitiveColor() instead.");
932 const Material &mat = context_ptr->materials.at(materialID);
936RGBcolor Primitive::getColorRGB()
const {
937 if (context_ptr ==
nullptr) {
938 helios_runtime_error(
"ERROR (Primitive::getColorRGB): Primitive not associated with a Context. Use Context::getPrimitiveColor() instead.");
940 const Material &mat = context_ptr->materials.at(materialID);
944RGBAcolor Primitive::getColorRGBA()
const {
945 if (context_ptr ==
nullptr) {
946 helios_runtime_error(
"ERROR (Primitive::getColorRGBA): Primitive not associated with a Context. Use Context::getPrimitiveColorRGBA() instead.");
948 const Material &mat = context_ptr->materials.at(materialID);
953 if (context_ptr ==
nullptr) {
954 helios_runtime_error(
"ERROR (Primitive::setColor): Primitive not associated with a Context. Use Context::setPrimitiveColor() instead.");
957 if (context_ptr->isMaterialShared(materialID)) {
958 materialID = context_ptr->copyMaterialForPrimitive(UUID);
960 context_ptr->materials.at(materialID).color =
make_RGBAcolor(newcolor, 1.f);
965 if (context_ptr ==
nullptr) {
966 helios_runtime_error(
"ERROR (Primitive::setColor): Primitive not associated with a Context. Use Context::setPrimitiveColor() instead.");
969 if (context_ptr->isMaterialShared(materialID)) {
970 materialID = context_ptr->copyMaterialForPrimitive(UUID);
972 context_ptr->materials.at(materialID).color = newcolor;
976bool Primitive::hasTexture()
const {
977 if (context_ptr ==
nullptr) {
978 helios_runtime_error(
"ERROR (Primitive::hasTexture): Primitive not associated with a Context.");
980 const Material &mat = context_ptr->materials.at(materialID);
984std::string Primitive::getTextureFile()
const {
985 if (context_ptr ==
nullptr) {
986 helios_runtime_error(
"ERROR (Primitive::getTextureFile): Primitive not associated with a Context. Use Context::getPrimitiveTextureFile() instead.");
988 const Material &mat = context_ptr->materials.at(materialID);
992void Primitive::setTextureFile(
const char *texture) {
993 if (context_ptr ==
nullptr) {
994 helios_runtime_error(
"ERROR (Primitive::setTextureFile): Primitive not associated with a Context. Use Context::setPrimitiveTextureFile() instead.");
997 if (context_ptr->isMaterialShared(materialID)) {
998 materialID = context_ptr->copyMaterialForPrimitive(UUID);
1000 context_ptr->materials.at(materialID).texture_file = texture;
1004std::vector<vec2> Primitive::getTextureUV() {
1008void Primitive::setTextureUV(
const std::vector<vec2> &a_uv) {
1013void Primitive::overrideTextureColor() {
1014 if (context_ptr ==
nullptr) {
1015 helios_runtime_error(
"ERROR (Primitive::overrideTextureColor): Primitive not associated with a Context. Use Context::overridePrimitiveTextureColor() instead.");
1018 if (context_ptr->isMaterialShared(materialID)) {
1019 materialID = context_ptr->copyMaterialForPrimitive(UUID);
1021 context_ptr->materials.at(materialID).texture_color_overridden =
true;
1025void Primitive::useTextureColor() {
1026 if (context_ptr ==
nullptr) {
1027 helios_runtime_error(
"ERROR (Primitive::useTextureColor): Primitive not associated with a Context. Use Context::usePrimitiveTextureColor() instead.");
1030 if (context_ptr->isMaterialShared(materialID)) {
1031 materialID = context_ptr->copyMaterialForPrimitive(UUID);
1033 context_ptr->materials.at(materialID).texture_color_overridden =
false;
1037bool Primitive::isTextureColorOverridden()
const {
1038 if (context_ptr ==
nullptr) {
1039 helios_runtime_error(
"ERROR (Primitive::isTextureColorOverridden): Primitive not associated with a Context. Use Context::isPrimitiveTextureColorOverridden() instead.");
1041 const Material &mat = context_ptr->materials.at(materialID);
1045float Primitive::getSolidFraction()
const {
1046 return solid_fraction;
1049void Primitive::setSolidFraction(
float solidFraction) {
1050 solid_fraction = solidFraction;
1055 return ((c.
y - a.
y) * (b.
x - a.
x) - (c.
x - a.
x) * (b.
y - a.
y) >= 0);
1059 makeTransformationMatrix(vertex0, vertex1, vertex2);
1063void Primitive::applyTransform(
float (&T)[16]) {
1064 if (parent_object_ID != 0) {
1065 static bool compound_transform_warning_shown =
false;
1066 if (!compound_transform_warning_shown) {
1067 std::cerr <<
"WARNING (Primitive::applyTransform): Cannot transform individual primitives within a compound object. Use the setter function for objects." << std::endl;
1068 compound_transform_warning_shown =
true;
1073 matmult(T, transform, transform);
1077void Primitive::scale(
const vec3 &S) {
1078 if (parent_object_ID != 0) {
1079 static bool compound_scale_warning_shown =
false;
1080 if (!compound_scale_warning_shown) {
1081 std::cerr <<
"WARNING (Primitive::scale): Cannot scale individual primitives within a compound object. Use the setter function for objects." << std::endl;
1082 compound_scale_warning_shown =
true;
1086 if (S.
x == 0 || S.
y == 0 || S.
z == 0) {
1088 }
else if (S.
x == 1 && S.
y == 1 && S.
z == 1) {
1094 matmult(T, transform, transform);
1098void Primitive::scale(
const vec3 &S,
const vec3 &point) {
1099 if (parent_object_ID != 0) {
1100 static bool compound_scale_point_warning_shown =
false;
1101 if (!compound_scale_point_warning_shown) {
1102 std::cerr <<
"WARNING (Primitive::scale): Cannot scale individual primitives within a compound object. Use the setter function for objects." << std::endl;
1103 compound_scale_point_warning_shown =
true;
1107 if (S.
x == 0 || S.
y == 0 || S.
z == 0) {
1109 }
else if (S.
x == 1 && S.
y == 1 && S.
z == 1) {
1115 matmult(T, transform, transform);
1120 if (parent_object_ID != 0) {
1121 static bool compound_translate_warning_shown =
false;
1122 if (!compound_translate_warning_shown) {
1123 std::cerr <<
"WARNING (Primitive::translate): Cannot translate individual primitives within a compound object. Use the setter function for objects." << std::endl;
1124 compound_translate_warning_shown =
true;
1129 if (shift == nullorigin) {
1135 matmult(T, transform, transform);
1139void Patch::rotate(
float rotation_radians,
const char *rotation_axis_xyz_string) {
1140 if (parent_object_ID != 0) {
1141 std::cerr <<
"WARNING (Patch::rotate): Cannot rotate individual primitives within a compound object. Use the setter function for objects." << std::endl;
1144 if (rotation_radians == 0) {
1148 if (strcmp(rotation_axis_xyz_string,
"z") == 0) {
1151 matmult(Rz, transform, transform);
1152 }
else if (strcmp(rotation_axis_xyz_string,
"y") == 0) {
1155 matmult(Ry, transform, transform);
1156 }
else if (strcmp(rotation_axis_xyz_string,
"x") == 0) {
1159 matmult(Rx, transform, transform);
1166void Patch::rotate(
float rotation_radians,
const helios::vec3 &rotation_axis_vector) {
1167 if (parent_object_ID != 0) {
1168 std::cerr <<
"WARNING (Patch::rotate): Cannot rotate individual primitives within a compound object. Use the setter function for objects." << std::endl;
1171 if (rotation_radians == 0) {
1182 if (parent_object_ID != 0) {
1183 std::cerr <<
"WARNING (Patch::rotate): Cannot rotate individual primitives within a compound object. Use the setter function for objects." << std::endl;
1186 if (rotation_radians == 0) {
1196void Triangle::rotate(
float rotation_radians,
const char *rotation_axis_xyz_string) {
1197 if (parent_object_ID != 0) {
1198 std::cerr <<
"WARNING (Triangle::rotate): Cannot rotate individual primitives within a compound object. Use the setter function for objects." << std::endl;
1201 if (rotation_radians == 0) {
1205 if (strcmp(rotation_axis_xyz_string,
"z") == 0) {
1208 matmult(Rz, transform, transform);
1209 }
else if (strcmp(rotation_axis_xyz_string,
"y") == 0) {
1212 matmult(Ry, transform, transform);
1213 }
else if (strcmp(rotation_axis_xyz_string,
"x") == 0) {
1216 matmult(Rx, transform, transform);
1223void Triangle::rotate(
float rotation_radians,
const helios::vec3 &rotation_axis_vector) {
1224 if (parent_object_ID != 0) {
1225 std::cerr <<
"WARNING (Triangle::rotate): Cannot rotate individual primitives within a compound object. Use the setter function for objects." << std::endl;
1228 if (rotation_radians == 0) {
1238void Triangle::rotate(
float rotation_radians,
const helios::vec3 &origin,
const helios::vec3 &rotation_axis_vector) {
1239 if (parent_object_ID != 0) {
1240 std::cerr <<
"WARNING (Triangle::rotate): Cannot rotate individual primitives within a compound object. Use the setter function for objects." << std::endl;
1243 if (rotation_radians == 0) {
1253void Voxel::rotate(
float rotation_radians,
const char *rotation_axis_xyz_string) {
1254 if (parent_object_ID != 0) {
1255 static bool voxel_compound_rotate_warning_shown =
false;
1256 if (!voxel_compound_rotate_warning_shown) {
1257 std::cerr <<
"WARNING (Voxel::rotate): Cannot rotate individual primitives within a compound object. Use the setter function for objects." << std::endl;
1258 voxel_compound_rotate_warning_shown =
true;
1262 if (rotation_radians == 0) {
1268 matmult(Rz, transform, transform);
1272void Voxel::rotate(
float rotation_radians,
const helios::vec3 &rotation_axis_vector) {
1273 static bool voxel_rotate_vec3_warning_shown =
false;
1274 if (!voxel_rotate_vec3_warning_shown) {
1275 std::cerr <<
"WARNING (Voxel::rotate) - Voxels can only be rotated about the z-axis. Ignoring this call to rotate()." << std::endl;
1276 voxel_rotate_vec3_warning_shown =
true;
1281 static bool voxel_rotate_vec3_origin_warning_shown =
false;
1282 if (!voxel_rotate_vec3_origin_warning_shown) {
1283 std::cerr <<
"WARNING (Voxel::rotate) - Voxels can only be rotated about the z-axis. Ignoring this call to rotate()." << std::endl;
1284 voxel_rotate_vec3_origin_warning_shown =
true;
1379 double inv[16], det, invV1[16];
1381 inv[0] = V1[5] * V1[10] * V1[15] - V1[5] * V1[11] * V1[14] - V1[9] * V1[6] * V1[15] + V1[9] * V1[7] * V1[14] + V1[13] * V1[6] * V1[11] - V1[13] * V1[7] * V1[10];
1383 inv[4] = -V1[4] * V1[10] * V1[15] + V1[4] * V1[11] * V1[14] + V1[8] * V1[6] * V1[15] - V1[8] * V1[7] * V1[14] - V1[12] * V1[6] * V1[11] + V1[12] * V1[7] * V1[10];
1385 inv[8] = V1[4] * V1[9] * V1[15] - V1[4] * V1[11] * V1[13] - V1[8] * V1[5] * V1[15] + V1[8] * V1[7] * V1[13] + V1[12] * V1[5] * V1[11] - V1[12] * V1[7] * V1[9];
1387 inv[12] = -V1[4] * V1[9] * V1[14] + V1[4] * V1[10] * V1[13] + V1[8] * V1[5] * V1[14] - V1[8] * V1[6] * V1[13] - V1[12] * V1[5] * V1[10] + V1[12] * V1[6] * V1[9];
1389 inv[1] = -V1[1] * V1[10] * V1[15] + V1[1] * V1[11] * V1[14] + V1[9] * V1[2] * V1[15] - V1[9] * V1[3] * V1[14] - V1[13] * V1[2] * V1[11] + V1[13] * V1[3] * V1[10];
1391 inv[5] = V1[0] * V1[10] * V1[15] - V1[0] * V1[11] * V1[14] - V1[8] * V1[2] * V1[15] + V1[8] * V1[3] * V1[14] + V1[12] * V1[2] * V1[11] - V1[12] * V1[3] * V1[10];
1393 inv[9] = -V1[0] * V1[9] * V1[15] + V1[0] * V1[11] * V1[13] + V1[8] * V1[1] * V1[15] - V1[8] * V1[3] * V1[13] - V1[12] * V1[1] * V1[11] + V1[12] * V1[3] * V1[9];
1395 inv[13] = V1[0] * V1[9] * V1[14] - V1[0] * V1[10] * V1[13] - V1[8] * V1[1] * V1[14] + V1[8] * V1[2] * V1[13] + V1[12] * V1[1] * V1[10] - V1[12] * V1[2] * V1[9];
1397 inv[2] = V1[1] * V1[6] * V1[15] - V1[1] * V1[7] * V1[14] - V1[5] * V1[2] * V1[15] + V1[5] * V1[3] * V1[14] + V1[13] * V1[2] * V1[7] - V1[13] * V1[3] * V1[6];
1399 inv[6] = -V1[0] * V1[6] * V1[15] + V1[0] * V1[7] * V1[14] + V1[4] * V1[2] * V1[15] - V1[4] * V1[3] * V1[14] - V1[12] * V1[2] * V1[7] + V1[12] * V1[3] * V1[6];
1401 inv[10] = V1[0] * V1[5] * V1[15] - V1[0] * V1[7] * V1[13] - V1[4] * V1[1] * V1[15] + V1[4] * V1[3] * V1[13] + V1[12] * V1[1] * V1[7] - V1[12] * V1[3] * V1[5];
1403 inv[14] = -V1[0] * V1[5] * V1[14] + V1[0] * V1[6] * V1[13] + V1[4] * V1[1] * V1[14] - V1[4] * V1[2] * V1[13] - V1[12] * V1[1] * V1[6] + V1[12] * V1[2] * V1[5];
1405 inv[3] = -V1[1] * V1[6] * V1[11] + V1[1] * V1[7] * V1[10] + V1[5] * V1[2] * V1[11] - V1[5] * V1[3] * V1[10] - V1[9] * V1[2] * V1[7] + V1[9] * V1[3] * V1[6];
1407 inv[7] = V1[0] * V1[6] * V1[11] - V1[0] * V1[7] * V1[10] - V1[4] * V1[2] * V1[11] + V1[4] * V1[3] * V1[10] + V1[8] * V1[2] * V1[7] - V1[8] * V1[3] * V1[6];
1409 inv[11] = -V1[0] * V1[5] * V1[11] + V1[0] * V1[7] * V1[9] + V1[4] * V1[1] * V1[11] - V1[4] * V1[3] * V1[9] - V1[8] * V1[1] * V1[7] + V1[8] * V1[3] * V1[5];
1411 inv[15] = V1[0] * V1[5] * V1[10] - V1[0] * V1[6] * V1[9] - V1[4] * V1[1] * V1[10] + V1[4] * V1[2] * V1[9] + V1[8] * V1[1] * V1[6] - V1[8] * V1[2] * V1[5];
1413 det = V1[0] * inv[0] + V1[1] * inv[4] + V1[2] * inv[8] + V1[3] * inv[12];
1420 for (
int i = 0; i < 16; i++)
1421 invV1[i] = inv[i] * det;
1423 for (
int i = 0; i < 4; i++) {
1424 for (
int j = 0; j < 4; j++) {
1425 transform[j + i * 4] = 0.f;
1430 for (
int i = 0; i < 4; i++) {
1431 for (
int j = 0; j < 4; j++) {
1432 for (
int k = 0; k < 4; k++) {
1433 transform[j + i * 4] += V2[k + i * 4] * float(invV1[j + k * 4]);
1443 assert(a_color.
r >= 0 && a_color.
r <= 1 && a_color.
g >= 0 && a_color.
g <= 1 && a_color.
b >= 0 && a_color.
b <= 1);
1444 parent_object_ID = a_parent_objID;
1447 solid_fraction = 1.f;
1449 context_ptr =
nullptr;
1453Patch::Patch(
const char *a_texturefile,
float a_solid_fraction,
uint a_parent_objID,
uint a_UUID) {
1456 parent_object_ID = a_parent_objID;
1459 solid_fraction = a_solid_fraction;
1461 context_ptr =
nullptr;
1465Patch::Patch(
const char *a_texturefile,
const std::vector<helios::vec2> &a_uv, std::map<std::string, Texture> &textures,
uint a_parent_objID,
uint a_UUID) {
1468 parent_object_ID = a_parent_objID;
1473 for (
auto &uv_vert: uv) {
1474 uv_vert.x = std::min(uv_vert.x, 1.f);
1475 uv_vert.y = std::min(uv_vert.y, 1.f);
1478 solid_fraction = textures.at(a_texturefile).getSolidFraction(uv);
1480 context_ptr =
nullptr;
1485 const std::vector<vec3> &vertices = getVertices();
1486 float l = (vertices.at(1) - vertices.at(0)).magnitude();
1487 float w = (vertices.at(3) - vertices.at(0)).magnitude();
1492 return make_vec3(transform[3], transform[7], transform[11]);
1496 makeTransformationMatrix(a_vertex0, a_vertex1, a_vertex2);
1497 parent_object_ID = a_parent_objID;
1500 solid_fraction = 1.f;
1502 context_ptr =
nullptr;
1506Triangle::Triangle(
const helios::vec3 &a_vertex0,
const helios::vec3 &a_vertex1,
const helios::vec3 &a_vertex2,
const char *a_texturefile,
const std::vector<helios::vec2> &a_uv,
float solid_fraction,
uint a_parent_objID,
uint a_UUID) {
1507 makeTransformationMatrix(a_vertex0, a_vertex1, a_vertex2);
1508 parent_object_ID = a_parent_objID;
1513 this->solid_fraction = solid_fraction;
1515 context_ptr =
nullptr;
1519Triangle::Triangle(
const helios::vec3 &a_vertex0,
const helios::vec3 &a_vertex1,
const helios::vec3 &a_vertex2,
const char *a_texturefile,
const std::vector<helios::vec2> &a_uv, std::map<std::string, Texture> &textures,
uint a_parent_objID,
1521 makeTransformationMatrix(a_vertex0, a_vertex1, a_vertex2);
1522 parent_object_ID = a_parent_objID;
1527 for (
auto &uv_vert: uv) {
1528 uv_vert.x = std::min(uv_vert.x, 1.f);
1529 uv_vert.y = std::min(uv_vert.y, 1.f);
1531 solid_fraction = 1.f;
1533 solid_fraction = textures.at(a_texturefile).getSolidFraction(uv);
1535 context_ptr =
nullptr;
1539vec3 Triangle::getVertex(
int vertex_index)
const {
1540 if (vertex_index < 0 || vertex_index > 2) {
1544 const std::vector<vec3> Y = {{0.f, 0.f, 0.f}, {0.f, 1.f, 0.f}, {1.f, 1.f, 0.f}};
1548 vertex.
x = transform[0] * Y[vertex_index].x + transform[1] * Y[vertex_index].y + transform[2] * Y[vertex_index].z + transform[3];
1549 vertex.
y = transform[4] * Y[vertex_index].x + transform[5] * Y[vertex_index].y + transform[6] * Y[vertex_index].z + transform[7];
1550 vertex.
z = transform[8] * Y[vertex_index].x + transform[9] * Y[vertex_index].y + transform[10] * Y[vertex_index].z + transform[11];
1555vec3 Triangle::getCenter()
const {
1560 vec3 center0(1.f / 3.f, 2.f / 3.f, 0.f);
1563 center.
x = transform[0] * center0.x + transform[1] * center0.y + transform[2] * center0.z + transform[3];
1564 center.
y = transform[4] * center0.x + transform[5] * center0.y + transform[6] * center0.z + transform[7];
1565 center.
z = transform[8] * center0.x + transform[9] * center0.y + transform[10] * center0.z + transform[11];
1573 assert(a_color.
r >= 0 && a_color.
r <= 1 && a_color.
g >= 0 && a_color.
g <= 1 && a_color.
b >= 0 && a_color.
b <= 1);
1574 solid_fraction = 1.f;
1575 parent_object_ID = a_parent_objID;
1579 context_ptr =
nullptr;
1583float Voxel::getVolume() {
1584 const vec3 &size = getSize();
1586 return size.
x * size.
y * size.
z;
1589vec3 Voxel::getCenter()
const {
1590 return make_vec3(transform[3], transform[7], transform[11]);
1593vec3 Voxel::getSize()
const {
1594 vec3 n0(0, 0, 0), nx(1, 0, 0), ny(0, 1, 0), nz(0, 0, 1);
1595 vec3 n0_T, nx_T, ny_T, nz_T;
1602 float x = (nx_T - n0_T).magnitude();
1603 float y = (ny_T - n0_T).magnitude();
1604 float z = (nz_T - n0_T).magnitude();