#pragma once #include "ofMain.h" #include "ofxBullet.h" #include #include #include #include struct Node { ofxBulletCustomShape* collider; ofMesh col_mesh; ofMesh mesh; ofImage img; ofTexture tex; glm::vec3 scale; glm::vec3 tsne_position; vector raw_embedding; int error; }; struct CameraPosition { glm::vec3 position; glm::quat rotation; float scale; float time; }; class Bullet{ public: void setup(); void update(bool& is_camera_active, Node& chosen_node, vector nn); void draw(); void addMesh(ofMesh _mesh, ofMesh _simple_mesh, Node& _node); float easeInOutCubic(float t); float calculateGridSize(float zoom); void setNewCameraEndpoint(); glm::vec4 getCameraBounds(const ofCamera& cam); bool checkNodeVisibility(const Node& n); glm::vec3 getCameraPosition(); void setNodes(vector& _nodes); void updateTSNEPosition(vector& _nodes); void updateNodeActivation(Node& node); ofxBulletWorldRigid world; vector bounds; ofxBulletCustomShape* boundsShape; ofMaterial boundsMat; ofMaterial shapeMat; float boundsWidth; vector shapes; vector simplifiedShapes; vector positions; ofMaterial logoMat; vector nodes; bool bDrawDebug; ofMesh mesh; ofMesh simple_mesh; ofEasyCam camera; glm::vec3 camera_start_pos; glm::vec3 camera_end_position; bool is_camera_moving; float camera_move_duration; float camera_move_start_time; float deceleration_start_time = 0.0f; glm::vec3 initial_velocity = glm::vec3(0.0f); bool was_camera_active = false; bool print_debug = false; float current_zoom = 0.03f; glm::vec3 transition_start_pos; glm::vec3 camera_velocity = glm::vec3(0.0f); const float ACCELERATION = 100.0f; // Adjust this value const float DECELERATION = 20.0f; // Adjust this value const float MAX_VELOCITY = 50.0f; // Your velocity cap ofLight light; ofTexture tex; bool contr_active; ofShader shader; float gridSize = 20.0f; glm::vec4 cameraBounds; vector nn_nodes; void updateRepulsionNode() { static int frameCount = 0; static const int repulsionInterval = 180; // Apply repulsion every 60 frames if (frameCount % repulsionInterval == 0 && !nodes.empty()) { repulsionNodeIndex = ofRandom(nodes.size()); shouldApplyRepulsion = true; } else if (frameCount % repulsionInterval == repulsionInterval - 1) { shouldApplyRepulsion = false; } frameCount++; } ofRectangle calculateMeshBounds(const ofMesh& mesh) { if (mesh.getVertices().empty()) { return ofRectangle(); } ofVec3f min = mesh.getVertices()[0]; ofVec3f max = min; for (const auto& vertex : mesh.getVertices()) { min.x = std::min(min.x, vertex.x); min.y = std::min(min.y, vertex.y); min.z = std::min(min.z, vertex.z); max.x = std::max(max.x, vertex.x); max.y = std::max(max.y, vertex.y); max.z = std::max(max.z, vertex.z); } return ofRectangle(min.x, min.y, max.x - min.x, max.y - min.y); } void cleanup() { shouldTerminate = true; for (auto& thread : workerThreads) { if (thread.joinable()) { thread.join(); } } } void startCameraMovement(const glm::vec3& target_pos) { camera_start_pos = camera.getPosition(); camera_end_position = target_pos; camera_move_start_time = ofGetElapsedTimef(); is_camera_moving = true; } ~Bullet() { cleanup(); } private: std::vector workerThreads; std::mutex shapeMutex; std::mutex nodesMutex; std::atomic shouldTerminate{false}; std::atomic repulsionNodeIndex{0}; std::atomic shouldApplyRepulsion{false}; const float repulsionRadius = 10.0f; const float repulsionStrength = 1.0f; const int numThreads = std::thread::hardware_concurrency(); const float FORCE_RADIUS = 200.0f; // Radius beyond which force is applied const float FORCE_RADIUS_SQ = FORCE_RADIUS * FORCE_RADIUS; // Squared radius for faster comparisons const float INNER_RADIUS = 10.0f; // Inner radius where objects are considered "arrived" const float INNER_RADIUS_SQ = INNER_RADIUS * INNER_RADIUS; void workerThreadFunction(int threadId); void updateShapeBatch(size_t start, size_t end); bool now = true; bool new_chosen_node; Node last_chosen_node; Node* current_target_node = nullptr; /* random walk vars */ const float RANDOM_WALK_RADIUS = 450.0f; const float RANDOM_WALK_SPEED = 40.0f; // Adjust for slower/faster movement const float TARGET_REACHED_DISTANCE = 5.0f; const float RANDOM_WALK_DELAY = 10.0f; // 5 seconds delay const float SCALE_OUT_START_TIME = 30.0f; // When to start scaling out const float SCALE_OUT_DURATION = 60.0f; // How long to scale out const float INITIAL_SCALE = 0.05f; // Starting scale const float TARGET_SCALE = 0.2f; // Final scale bool is_random_walking = false; float time_at_target = 0.0f; glm::vec3 random_target; float current_scale = INITIAL_SCALE; float random_walk_time = 0.0f; float scale_out_factor = 0.0f; // Generate new random target within bounds glm::vec3 generateRandomTarget() { return glm::vec3( ofRandom(-RANDOM_WALK_RADIUS, RANDOM_WALK_RADIUS), ofRandom(-RANDOM_WALK_RADIUS, RANDOM_WALK_RADIUS), camera.getPosition().z // Keep same Z level ); } };