#include #include #include #include #include #include #include "../bella_engine_sdk/src/bella_sdk/bella_engine.h" // For rendering and scene creation in Bella #include "../bella_engine_sdk/src/dl_core/dl_main.inl" // Core functionality from the Diffuse Logic engine // oomer's helper utility code to make main cpp smaller #include "../oom/oom_license.h" // oomer's helper code for licenses #include "../oom/oom_bella_long.h" // more oomer's helper code for bella, but has long data #include "../oom/oom_bella_engine.h" // oomer's helper code for bella rendering #include "../oom/oom_bella_premade.h" // oomer's helper code for bella scenes #include "../oom/oom_bella_misc.h" // oomer's hlper code for bella misc code //============================================================================== // GLOBAL VARIABLES AND FUNCTIONS //============================================================================== // Vec3 is a simple struct that holds a 3D vector //struct Vec3 { // float x, y, z; //}; // BoundingBox is a simple struct that holds a bounding box struct BoundingBox { dl::Vec3 min; dl::Vec3 max; // getCenter is a simple function that returns the center of the bounding box dl::Vec3 getCenter() const { return { (min.x + max.x) * 0.5f, (min.y + max.y) * 0.5f, (min.z + max.z) * 0.5f }; } // getRadius is a simple function that returns the radius of the bounding box float getRadius() const { dl::Vec3 center = getCenter(); // Calculate distance from center to each corner and return the maximum float dx = std::max(std::abs(center.x - min.x), std::abs(center.x - max.x)); float dy = std::max(std::abs(center.y - min.y), std::abs(center.y - max.y)); float dz = std::max(std::abs(center.z - min.z), std::abs(center.z - max.z)); // Pythagorean distance to the furthest corner return std::sqrt(dx*dx + dy*dy + dz*dz); } }; //============================================================================== // MAIN FUNCTION //============================================================================== int DL_main(dl::Args& args) { BoundingBox bbox = {{1000000.0f, 1000000.0f, 1000000.0f}, // min point {-1000000.0f, -1000000.0f, -1000000.0f} }; // max point // Always put this before args to setup callbacks for Bella's log events int s_oomBellaLogContext = 0; dl::subscribeLog(&s_oomBellaLogContext, oom::bella::log); dl::flushStartupMessages(); args.add("tp", "thirdparty", "", "prints third party licenses"); args.add("li", "licenseinfo", "", "prints license info"); args.add( "n", "number", "", "number of plot points"); args.add( "zo", "zoffset", "", "z offset"); args.add( "sf", "sinefreq", "", "sine frequency"); args.add( "sa", "sineampl", "", "sine amplitude"); args.add( "s", "scale", "", "scale"); args.add( "m", "modulus", "", "modulus"); args.add( "r", "render", "", "render"); args.add( "or", "orbit", "10", "orbit"); args.add( "pm", "printMatrix", "", "print matrix4"); args.add( "em", "eachmaterial", "", "each voxel has own material"); args.add( "sv", "scalevoxel", "", "each voxel has own scale"); args.add( "cv", "colorvariation", "", "adsd color variation"); if (args.helpRequested()) { std::cout << args.help("poomer-bella-sine (C) 2025 Harvey Fong","", "1.0") << std::endl; return 0; } if (args.have("--licenseinfo")) { std::cout << "poomer-bella-sine (C) 2025 Harvey Fong" << std::endl; std::cout << oom::license::printLicense() << std::endl; return 0; } if (args.have("--thirdparty")) { std::cout << oom::license::printBellaSDK() << "\n====\n" << std::endl; return 0; } int argNumPlotPoints = 100; if (args.have("--number")) { argNumPlotPoints = std::stoi(args.value("--number").buf()); } float argSineFreq = 0.1; if (args.have("--sinefreq")) { argSineFreq = std::stof(args.value("--sinefreq").buf()); } float argSineAmpl = 10.0; if (args.have("--sineampl")) { argSineAmpl = std::stof(args.value("--sineampl").buf()); } float argZOffset = argSineAmpl; if (args.have("--zoffset")) { argZOffset = std::stof(args.value("--zoffset").buf()); } double argScale = 1.0; if (args.have("--scale")) { argScale = std::stod(args.value("--scale").buf()); } int argModulus = 10; if (args.have("--modulus")) { argModulus = std::stoi(args.value("--modulus").buf()); } float argColorVariation = 0.55f; if (args.have("--colorvariation")) { argColorVariation = std::stof(args.value("--colorvariation").buf()); } // Create a Bella Engine instance and load the default scene definitions ( all the nodes ) dl::bella_sdk::Engine engine; engine.scene().loadDefs(); // Create an engine observer that we subscribe to catch Engine event callbacks oom::bella::MyEngineObserver engineObserver; engine.subscribe(&engineObserver); // Get the scene auto belScene = engine.scene(); // use oom helper to populate the scene with default voxel objects // this returns a tuple of the world node, the mesh voxel node, the liquid voxel node, and the voxel node // The latter 3 are unparented, and the world node is parented to the scene root // This is a convenience function, see oom_bella_premade.h for more details auto [ belWorld, belMeshVoxel, belLiqVoxel, belVoxel ] = oom::bella::defaultSceneVoxel(belScene); auto belVoxelMat1 = belScene.createNode("quickMaterial", "oomVoxelMat1"); auto belVoxelMat2 = belScene.createNode("quickMaterial", "oomVoxelMat2"); auto belColor1 = belScene.createNode("color", "oomColor1"); auto belColor2 = belScene.createNode("color", "oomColor2"); belColor1["color"] = dl::Rgba{1.0f, 0.0f, 0.0f, 1.0f}; belColor2["color"] = dl::Rgba{1.0f, 0.0f, 0.0f, 1.0f}; belVoxelMat1["color"] |= belColor1.output("outColor"); belVoxelMat2["color"] |= belColor2.output("outColor"); if (args.have("--colorvariation")) { dl::logCustom("Color variation: %f", argColorVariation); belColor1["variation"] = argColorVariation; belColor2["variation"] = argColorVariation; } if (args.have("--eachmaterial")) { dl::logCustom("Outputing a separate material for each voxel"); } for (int i = 0; i < argNumPlotPoints; i+=1) { auto eachVoxel = belScene.createNode("xform", dl::String::format("eachVoxelXform%04d",i)); dl::bella_sdk::Node eachVoxelMat; if (args.have("--eachmaterial")) { eachVoxelMat = belScene.createNode("quickMaterial", dl::String::format("eachVoxelMat%04d",i)); eachVoxelMat["color"] = dl::Rgba{ (i%255)/255.0f, 0.0f, 0.0f, 1.0f}; } eachVoxel.parentTo(belWorld); if (i%argModulus == 0) { belMeshVoxel.parentTo(eachVoxel); } else { belVoxel.parentTo(eachVoxel); } dl::Mat4 myXform = dl::Mat4::identity; dl::Mat4 myTranslate = dl::Mat4::identity; dl::Mat4 myScale = dl::Mat4::identity; // Calculate the position of each point in the sine wave double myX = i; double myY = 0.0; double myZ = argZOffset + argSineAmpl * sin(argSineFreq * i); // Update bounding box if (myX < bbox.min.x) bbox.min.x = myX; if (myY < bbox.min.y) bbox.min.y = myY; if (myZ < bbox.min.z) bbox.min.z = myZ; if (myX > bbox.max.x) bbox.max.x = myX; if (myY > bbox.max.y) bbox.max.y = myY; if (myZ > bbox.max.z) bbox.max.z = myZ; myTranslate = dl::math::makeTranslation( myX, myY, myZ); myScale = dl::math::makeScale<4>( argScale, argScale, argScale); // Override scale above if arg is passed if (args.have("--scalevoxel")) { dl::logCustom("Scale voxel: %f", (i%argModulus+5)*0.5); myScale = dl::math::makeScale<4>( (i%argModulus+5)*0.5, (i%argModulus+5)*0.5, (i%argModulus+5)*0.5); } // This is called matrix concatenation or composition myXform = myTranslate * myScale * myXform; if (args.have("--printMatrix")) { dl::logCustom("\nXform %d", static_cast(i)); dl::logInfo("Mat4: %f %f %f %f", myXform.m00, myXform.m01, myXform.m02, myXform.m03); dl::logInfo("Mat4: %f %f %f %f", myXform.m10, myXform.m11, myXform.m12, myXform.m13); dl::logInfo("Mat4: %f %f %f %f", myXform.m20, myXform.m21, myXform.m22, myXform.m23); dl::logInfo("Mat4: %f %f %f %f", myXform.m30, myXform.m31, myXform.m32, myXform.m33); } // apply the matrix to the voxel eachVoxel["steps"][0]["xform"] = myXform; if (i%argModulus == 0) { // alternate between voxel materials via modulus math eachVoxel["material"] = belVoxelMat1; } else { eachVoxel["material"] = belVoxelMat2; } // Possible override to use a different material for each voxel if (args.have("--eachmaterial")) { eachVoxel["material"] = eachVoxelMat; } } dl::Vec3 centerOfPlots = bbox.getCenter(); dl::logInfo("Bounding Box Center: (%f, %f, %f)", centerOfPlots.x, centerOfPlots.y, centerOfPlots.z); float radiusOfPlots = bbox.getRadius(); dl::logInfo("Bounding Box Radius: %f", radiusOfPlots); auto belCameraPath = belScene.cameraPath(); // Since camera can be instanced, we get the full path of th one currently define din scene settings auto belCamera = belScene.camera(); auto belCameraXform = belCameraPath.parent(); // thus the parent of the camera path is the xform node 99% of the time //auto targetCenter = dl::Vec3{ centerOfPlots.x, centerOfPlots.y, centerOfPlots.z }; // get a Transformation Matrix that will position the camera to view the entire scene dl::Mat4 newCamXform = dl::bella_sdk::zoomExtents(belCameraPath, centerOfPlots, radiusOfPlots); // Apply to camera xform belCameraXform["steps"][0]["xform"] = newCamXform; if (args.have("--render")) { engine.start(); while(engine.rendering()) { std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } } // orbit camera around plot points if (args.have("--orbit")) { int numFrames = std::stoi(args.value("--orbit").buf()); belCamera["resolution"] = dl::Vec2{100, 100}; for (int i = 0; i < numFrames; i++) { auto offset = dl::Vec2 {i*0.25, 0.0}; dl::bella_sdk::orbitCamera(engine.scene().cameraPath(),offset); auto belBeautyPass = belScene.beautyPass(); belBeautyPass["outputName"] = dl::String::format("poomer-bella-sine-%04d", i); engine.start(); while(engine.rendering()) { std::this_thread::sleep_for(std::chrono::milliseconds(1000)); } } } dl::logInfo("Writing scene to file"); belScene.write("poomer-bella-sine.bsa"); return 0; }