recording mode added
This commit is contained in:
@@ -2,12 +2,16 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <atomic>
|
||||||
|
#include <mutex>
|
||||||
|
|
||||||
#include "../util/grid/grid3.hpp"
|
#include "../util/grid/grid3.hpp"
|
||||||
#include "../util/grid/g3_serialization.hpp"
|
#include "../util/grid/g3_serialization.hpp"
|
||||||
#include "../util/output/bmpwriter.hpp"
|
#include "../util/output/bmpwriter.hpp"
|
||||||
#include "../util/output/frame.hpp"
|
#include "../util/output/frame.hpp"
|
||||||
#include "../util/timing_decorator.cpp"
|
#include "../util/timing_decorator.cpp"
|
||||||
#include "../util/noise/pnoise2.hpp"
|
#include "../util/noise/pnoise2.hpp"
|
||||||
|
#include "../util/output/aviwriter.hpp"
|
||||||
|
|
||||||
#include "../imgui/imgui.h"
|
#include "../imgui/imgui.h"
|
||||||
#include "../imgui/backends/imgui_impl_glfw.h"
|
#include "../imgui/backends/imgui_impl_glfw.h"
|
||||||
@@ -31,6 +35,13 @@ bool textureInitialized = false;
|
|||||||
bool updatePreview = false;
|
bool updatePreview = false;
|
||||||
bool previewRequested = false;
|
bool previewRequested = false;
|
||||||
|
|
||||||
|
// Add AVI recording variables
|
||||||
|
std::atomic<bool> isRecordingAVI{false};
|
||||||
|
std::atomic<bool> recordingRequested{false};
|
||||||
|
std::atomic<int> recordingFramesRemaining{0};
|
||||||
|
std::vector<frame> recordedFrames;
|
||||||
|
std::mutex recordingMutex;
|
||||||
|
|
||||||
struct Shared {
|
struct Shared {
|
||||||
std::mutex mutex;
|
std::mutex mutex;
|
||||||
VoxelGrid grid;
|
VoxelGrid grid;
|
||||||
@@ -81,15 +92,16 @@ void livePreview(VoxelGrid& grid, defaults& config, const Camera& cam) {
|
|||||||
|
|
||||||
updatePreview = false;
|
updatePreview = false;
|
||||||
textureInitialized = true;
|
textureInitialized = true;
|
||||||
|
if (isRecordingAVI) {
|
||||||
|
std::lock_guard<std::mutex> recLock(recordingMutex);
|
||||||
|
currentPreviewFrame.compressFrameLZ78();
|
||||||
|
recordedFrames.push_back(currentPreviewFrame);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool savePreview(VoxelGrid& grid, defaults& config, const Camera& cam) {
|
bool savePreview(VoxelGrid& grid, defaults& config, const Camera& cam) {
|
||||||
TIME_FUNCTION;
|
TIME_FUNCTION;
|
||||||
|
|
||||||
std::vector<uint8_t> renderBuffer;
|
|
||||||
size_t width = config.outWidth;
|
|
||||||
size_t height = config.outHeight;
|
|
||||||
|
|
||||||
// Render the view
|
// Render the view
|
||||||
frame output = grid.renderFrame(cam, Vec2i(config.outWidth, config.outHeight), frame::colormap::RGB);
|
frame output = grid.renderFrame(cam, Vec2i(config.outWidth, config.outHeight), frame::colormap::RGB);
|
||||||
//grid.renderOut(renderBuffer, width, height, cam);
|
//grid.renderOut(renderBuffer, width, height, cam);
|
||||||
@@ -105,7 +117,42 @@ bool savePreview(VoxelGrid& grid, defaults& config, const Camera& cam) {
|
|||||||
// }
|
// }
|
||||||
|
|
||||||
return success;
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
|
void startAVIRecording(int frameCount) {
|
||||||
|
std::lock_guard<std::mutex> lock(recordingMutex);
|
||||||
|
recordedFrames.clear();
|
||||||
|
recordedFrames.reserve(frameCount);
|
||||||
|
recordingFramesRemaining = frameCount;
|
||||||
|
recordingRequested = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void stopAndSaveAVI(defaults& config, const std::string& filename) {
|
||||||
|
std::lock_guard<std::mutex> lock(recordingMutex);
|
||||||
|
|
||||||
|
if (!recordedFrames.empty()) {
|
||||||
|
auto now = std::chrono::system_clock::now();
|
||||||
|
auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||||
|
now.time_since_epoch()).count();
|
||||||
|
std::string finalFilename = "output/recording_" + std::to_string(timestamp) + ".avi";
|
||||||
|
|
||||||
|
|
||||||
|
std::cout << "Saving AVI with " << recordedFrames.size() << " frames..." << std::endl;
|
||||||
|
|
||||||
|
// Save using the new streaming method
|
||||||
|
bool success = AVIWriter::saveAVIFromCompressedFrames(finalFilename, recordedFrames, config.outWidth, config.outHeight, config.fps);
|
||||||
|
|
||||||
|
if (success) {
|
||||||
|
std::cout << "AVI saved to: " << finalFilename << std::endl;
|
||||||
|
} else {
|
||||||
|
std::cout << "Failed to save AVI: " << finalFilename << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
recordedFrames.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
isRecordingAVI = false;
|
||||||
|
recordingFramesRemaining = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void glfw_error_callback(int error, const char* description)
|
static void glfw_error_callback(int error, const char* description)
|
||||||
@@ -182,6 +229,9 @@ int main() {
|
|||||||
if (supposedGrid) {
|
if (supposedGrid) {
|
||||||
grid = std::move(*supposedGrid);
|
grid = std::move(*supposedGrid);
|
||||||
gridInitialized = true;
|
gridInitialized = true;
|
||||||
|
config.gridDepth = grid.getDepth();
|
||||||
|
config.gridHeight = grid.getHeight();
|
||||||
|
config.gridWidth = grid.getWidth();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -220,6 +270,14 @@ int main() {
|
|||||||
bool cameraMoved = false;
|
bool cameraMoved = false;
|
||||||
double lastUpdateTime = glfwGetTime();
|
double lastUpdateTime = glfwGetTime();
|
||||||
|
|
||||||
|
// AVI recording variables
|
||||||
|
int recordingDurationFrames = 300; // 10 seconds at 30fps
|
||||||
|
std::string aviFilename = "output/recording.avi";
|
||||||
|
|
||||||
|
// For frame-based timing (not real time)
|
||||||
|
int frameCounter = 0;
|
||||||
|
float animationTime = 0.0f;
|
||||||
|
|
||||||
while (!glfwWindowShouldClose(window)) {
|
while (!glfwWindowShouldClose(window)) {
|
||||||
double currentTime = glfwGetTime();
|
double currentTime = glfwGetTime();
|
||||||
double deltaTime = currentTime - lastFrameTime;
|
double deltaTime = currentTime - lastFrameTime;
|
||||||
@@ -235,6 +293,10 @@ int main() {
|
|||||||
accumulator = targetFrameTime;
|
accumulator = targetFrameTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Frame-based timing for animations (independent of real time)
|
||||||
|
frameCounter++;
|
||||||
|
animationTime = frameCounter / config.fps; // Time in seconds based on frame count
|
||||||
|
|
||||||
glfwPollEvents();
|
glfwPollEvents();
|
||||||
|
|
||||||
// Start the Dear ImGui frame
|
// Start the Dear ImGui frame
|
||||||
@@ -248,6 +310,7 @@ int main() {
|
|||||||
if(ImGui::CollapsingHeader("output", ImGuiTreeNodeFlags_DefaultOpen)) {
|
if(ImGui::CollapsingHeader("output", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
ImGui::SliderInt("Width", &config.outWidth, 256, 4096);
|
ImGui::SliderInt("Width", &config.outWidth, 256, 4096);
|
||||||
ImGui::SliderInt("Height", &config.outHeight, 256, 4096);
|
ImGui::SliderInt("Height", &config.outHeight, 256, 4096);
|
||||||
|
ImGui::SliderFloat("FPS", &config.fps, 1.0f, 120.0f);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ImGui::CollapsingHeader("Grid Settings", ImGuiTreeNodeFlags_DefaultOpen)) {
|
if (ImGui::CollapsingHeader("Grid Settings", ImGuiTreeNodeFlags_DefaultOpen)) {
|
||||||
@@ -275,7 +338,30 @@ int main() {
|
|||||||
// cam.rotatePitch(camPitch);
|
// cam.rotatePitch(camPitch);
|
||||||
|
|
||||||
savePreview(grid, config, cam);
|
savePreview(grid, config, cam);
|
||||||
cameraMoved = true; // Force preview update after generation
|
cameraMoved = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// AVI Recording Controls
|
||||||
|
ImGui::Separator();
|
||||||
|
ImGui::Text("AVI Recording:");
|
||||||
|
|
||||||
|
if (!isRecordingAVI) {
|
||||||
|
ImGui::InputInt("Frames to Record", &recordingDurationFrames, 30, 300);
|
||||||
|
recordingDurationFrames = std::max(30, recordingDurationFrames); // Minimum 1 second at 30fps
|
||||||
|
|
||||||
|
if (ImGui::Button("Start AVI Recording")) {
|
||||||
|
startAVIRecording(recordingDurationFrames);
|
||||||
|
ImGui::OpenPopup("Recording Started");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ImGui::TextColored(ImVec4(1, 0, 0, 1), "RECORDING");
|
||||||
|
ImGui::Text("Frames captured: %d / %d",
|
||||||
|
recordedFrames.size(),
|
||||||
|
recordingDurationFrames);
|
||||||
|
|
||||||
|
if (ImGui::Button("Stop Recording Early")) {
|
||||||
|
isRecordingAVI = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Display camera controls
|
// Display camera controls
|
||||||
@@ -360,26 +446,47 @@ int main() {
|
|||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update preview if camera moved or enough time has passed
|
// Auto-rotation controls
|
||||||
if (gridInitialized && !updatePreview) {
|
{
|
||||||
double timeSinceLastUpdate = currentTime - lastUpdateTime;
|
ImGui::Begin("Animation Controls");
|
||||||
if (autoRotate) {
|
|
||||||
// Update rotation time
|
|
||||||
autoRotationTime += deltaTime;
|
|
||||||
|
|
||||||
// Calculate new view direction using spherical coordinates
|
ImGui::Text("Auto-Rotation:");
|
||||||
// This creates smooth 360-degree rotation with different speeds
|
|
||||||
|
// Toggle button for auto-rotation
|
||||||
|
if (ImGui::Button(autoRotate ? "Stop Auto-Rotation" : "Start Auto-Rotation")) {
|
||||||
|
autoRotate = !autoRotate;
|
||||||
|
if (autoRotate) {
|
||||||
|
autoRotationTime = 0.0f;
|
||||||
|
initialViewDir = Vec3f(camvX, camvY, camvZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ImGui::Button(autoRotateView ? "Stop Looking Around" : "Start Looking Around")) {
|
||||||
|
autoRotateView = !autoRotateView;
|
||||||
|
if (autoRotateView) {
|
||||||
|
autoRotationAngle = 0.0f;
|
||||||
|
initialViewDir = Vec3f(camvX, camvY, camvZ);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (autoRotate) {
|
||||||
|
ImGui::SameLine();
|
||||||
|
ImGui::Text("(Running)");
|
||||||
|
|
||||||
|
// Use frame-based timing for animation
|
||||||
|
float frameTime = 1.0f / config.fps;
|
||||||
|
autoRotationTime += frameTime; // Use constant frame time, not real time
|
||||||
|
|
||||||
|
// Calculate new view direction using frame-based timing
|
||||||
float angleX = autoRotationTime * rotationSpeedX;
|
float angleX = autoRotationTime * rotationSpeedX;
|
||||||
float angleY = autoRotationTime * rotationSpeedY;
|
float angleY = autoRotationTime * rotationSpeedY;
|
||||||
float angleZ = autoRotationTime * rotationSpeedZ;
|
float angleZ = autoRotationTime * rotationSpeedZ;
|
||||||
|
|
||||||
// Create rotation matrix or calculate new direction
|
|
||||||
// Using simple parametric equation for a sphere
|
|
||||||
camvX = sinf(angleX) * cosf(angleY);
|
camvX = sinf(angleX) * cosf(angleY);
|
||||||
camvY = sinf(angleY) * sinf(angleZ);
|
camvY = sinf(angleY) * sinf(angleZ);
|
||||||
camvZ = cosf(angleX) * cosf(angleZ);
|
camvZ = cosf(angleX) * cosf(angleZ);
|
||||||
|
|
||||||
// Normalize the direction vector (optional but good practice)
|
// Normalize
|
||||||
float length = sqrtf(camvX * camvX + camvY * camvY + camvZ * camvZ);
|
float length = sqrtf(camvX * camvX + camvY * camvY + camvZ * camvZ);
|
||||||
if (length > 0.001f) {
|
if (length > 0.001f) {
|
||||||
camvX /= length;
|
camvX /= length;
|
||||||
@@ -387,7 +494,7 @@ int main() {
|
|||||||
camvZ /= length;
|
camvZ /= length;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update camera position to orbit around grid center
|
// Update camera position
|
||||||
camX = config.gridWidth / 2.0f + rotationRadius * camvX;
|
camX = config.gridWidth / 2.0f + rotationRadius * camvX;
|
||||||
camY = config.gridHeight / 2.0f + rotationRadius * camvY;
|
camY = config.gridHeight / 2.0f + rotationRadius * camvY;
|
||||||
camZ = config.gridDepth / 2.0f + rotationRadius * camvZ;
|
camZ = config.gridDepth / 2.0f + rotationRadius * camvZ;
|
||||||
@@ -397,91 +504,6 @@ int main() {
|
|||||||
cam.posfor.direction = Vec3f(camvX, camvY, camvZ);
|
cam.posfor.direction = Vec3f(camvX, camvY, camvZ);
|
||||||
|
|
||||||
cameraMoved = true;
|
cameraMoved = true;
|
||||||
}
|
|
||||||
|
|
||||||
if (autoRotateView) {
|
|
||||||
// Update rotation angle based on time
|
|
||||||
autoRotationAngle += deltaTime;
|
|
||||||
|
|
||||||
// Calculate rotation angles (in radians)
|
|
||||||
float yaw = autoRotationAngle * yawSpeed * (3.14159f / 180.0f); // Convert to radians
|
|
||||||
float pitch = sinf(autoRotationAngle * 0.7f) * pitchSpeed * (3.14159f / 180.0f);
|
|
||||||
float roll = sinf(autoRotationAngle * 0.3f) * rollSpeed * (3.14159f / 180.0f);
|
|
||||||
|
|
||||||
// Start with forward direction
|
|
||||||
Vec3f forward = initialViewDir;
|
|
||||||
|
|
||||||
// Apply yaw rotation (around Y axis)
|
|
||||||
float cosYaw = cosf(yaw);
|
|
||||||
float sinYaw = sinf(yaw);
|
|
||||||
Vec3f tempForward;
|
|
||||||
tempForward.x = forward.x * cosYaw + forward.z * sinYaw;
|
|
||||||
tempForward.y = forward.y;
|
|
||||||
tempForward.z = -forward.x * sinYaw + forward.z * cosYaw;
|
|
||||||
forward = tempForward;
|
|
||||||
|
|
||||||
// Apply pitch rotation (around X axis)
|
|
||||||
float cosPitch = cosf(pitch);
|
|
||||||
float sinPitch = sinf(pitch);
|
|
||||||
tempForward.x = forward.x;
|
|
||||||
tempForward.y = forward.y * cosPitch - forward.z * sinPitch;
|
|
||||||
tempForward.z = forward.y * sinPitch + forward.z * cosPitch;
|
|
||||||
forward = tempForward;
|
|
||||||
|
|
||||||
// Normalize the direction
|
|
||||||
float length = sqrtf(forward.x * forward.x + forward.y * forward.y + forward.z * forward.z);
|
|
||||||
if (length > 0.001f) {
|
|
||||||
forward.x /= length;
|
|
||||||
forward.y /= length;
|
|
||||||
forward.z /= length;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update view direction variables
|
|
||||||
camvX = forward.x;
|
|
||||||
camvY = forward.y;
|
|
||||||
camvZ = forward.z;
|
|
||||||
|
|
||||||
// Update camera
|
|
||||||
cam.posfor.direction = Vec3f(camvX, camvY, camvZ);
|
|
||||||
|
|
||||||
cameraMoved = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cameraMoved || timeSinceLastUpdate > 0.1) { // Update at least every 0.1 seconds
|
|
||||||
livePreview(grid, config, cam);
|
|
||||||
lastUpdateTime = currentTime;
|
|
||||||
cameraMoved = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
ImGui::Separator();
|
|
||||||
ImGui::Text("Auto-Rotation:");
|
|
||||||
|
|
||||||
// Toggle button for auto-rotation
|
|
||||||
if (ImGui::Button(autoRotate ? "Stop Auto-Rotation" : "Start Auto-Rotation")) {
|
|
||||||
autoRotate = !autoRotate;
|
|
||||||
if (autoRotate) {
|
|
||||||
// Reset rotation time when starting
|
|
||||||
autoRotationTime = 0.0f;
|
|
||||||
// Save initial positions
|
|
||||||
initialViewDir = Vec3f(camvX, camvY, camvZ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::Button(autoRotateView ? "Stop Looking Around" : "Start Looking Around")) {
|
|
||||||
autoRotateView = !autoRotateView;
|
|
||||||
if (autoRotateView) {
|
|
||||||
// Reset rotation when starting
|
|
||||||
autoRotationAngle = 0.0f;
|
|
||||||
// Save current view direction as initial
|
|
||||||
initialViewDir = Vec3f(camvX, camvY, camvZ);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (autoRotate) {
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::Text("(Running)");
|
|
||||||
|
|
||||||
// Sliders to control rotation speeds
|
// Sliders to control rotation speeds
|
||||||
ImGui::SliderFloat("X Speed", &rotationSpeedX, 0.01f, 1.0f);
|
ImGui::SliderFloat("X Speed", &rotationSpeedX, 0.01f, 1.0f);
|
||||||
@@ -490,87 +512,101 @@ int main() {
|
|||||||
|
|
||||||
// Slider for orbit radius
|
// Slider for orbit radius
|
||||||
ImGui::SliderFloat("Orbit Radius", &rotationRadius, 10.0f, 200.0f);
|
ImGui::SliderFloat("Orbit Radius", &rotationRadius, 10.0f, 200.0f);
|
||||||
|
|
||||||
// Reset button
|
|
||||||
if (ImGui::Button("Reset to Center")) {
|
|
||||||
camX = config.gridWidth / 2.0f;
|
|
||||||
camY = config.gridHeight / 2.0f;
|
|
||||||
camZ = config.gridDepth / 2.0f;
|
|
||||||
cam.posfor.origin = Vec3f(camX, camY, camZ);
|
|
||||||
cameraMoved = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (autoRotateView) {
|
if (autoRotateView) {
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
ImGui::TextColored(ImVec4(0, 1, 0, 1), " ACTIVE");
|
ImGui::TextColored(ImVec4(0, 1, 0, 1), " ACTIVE");
|
||||||
|
|
||||||
|
// Use frame-based timing
|
||||||
|
float frameTime = 1.0f / config.fps;
|
||||||
|
autoRotationAngle += frameTime;
|
||||||
|
|
||||||
|
// Calculate rotation angles using frame-based timing
|
||||||
|
float yaw = autoRotationAngle * yawSpeed * (3.14159f / 180.0f);
|
||||||
|
float pitch = sinf(autoRotationAngle * 0.7f) * pitchSpeed * (3.14159f / 180.0f);
|
||||||
|
|
||||||
|
// Apply rotations
|
||||||
|
Vec3f forward = initialViewDir;
|
||||||
|
|
||||||
|
// Yaw rotation (around Y axis)
|
||||||
|
float cosYaw = cosf(yaw);
|
||||||
|
float sinYaw = sinf(yaw);
|
||||||
|
Vec3f tempForward;
|
||||||
|
tempForward.x = forward.x * cosYaw + forward.z * sinYaw;
|
||||||
|
tempForward.y = forward.y;
|
||||||
|
tempForward.z = -forward.x * sinYaw + forward.z * cosYaw;
|
||||||
|
forward = tempForward;
|
||||||
|
|
||||||
|
// Pitch rotation (around X axis)
|
||||||
|
float cosPitch = cosf(pitch);
|
||||||
|
float sinPitch = sinf(pitch);
|
||||||
|
tempForward.x = forward.x;
|
||||||
|
tempForward.y = forward.y * cosPitch - forward.z * sinPitch;
|
||||||
|
tempForward.z = forward.y * sinPitch + forward.z * cosPitch;
|
||||||
|
forward = tempForward;
|
||||||
|
|
||||||
|
// Normalize
|
||||||
|
float length = sqrtf(forward.x * forward.x + forward.y * forward.y + forward.z * forward.z);
|
||||||
|
if (length > 0.001f) {
|
||||||
|
forward.x /= length;
|
||||||
|
forward.y /= length;
|
||||||
|
forward.z /= length;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update view direction
|
||||||
|
camvX = forward.x;
|
||||||
|
camvY = forward.y;
|
||||||
|
camvZ = forward.z;
|
||||||
|
|
||||||
|
// Update camera
|
||||||
|
cam.posfor.direction = Vec3f(camvX, camvY, camvZ);
|
||||||
|
|
||||||
|
cameraMoved = true;
|
||||||
|
|
||||||
// Show current view direction
|
// Show current view direction
|
||||||
ImGui::Text("Current View: (%.3f, %.3f, %.3f)", camvX, camvY, camvZ);
|
ImGui::Text("Current View: (%.3f, %.3f, %.3f)", camvX, camvY, camvZ);
|
||||||
|
|
||||||
// Sliders to control rotation speeds
|
// Sliders to control rotation speeds
|
||||||
ImGui::SliderFloat("Yaw Speed", &yawSpeed, 0.1f, 5.0f, "%.2f deg/sec");
|
ImGui::SliderFloat("Yaw Speed", &yawSpeed, 0.1f, 5.0f, "%.2f deg/sec");
|
||||||
ImGui::SliderFloat("Pitch Speed", &pitchSpeed, 0.0f, 2.0f, "%.2f deg/sec");
|
ImGui::SliderFloat("Pitch Speed", &pitchSpeed, 0.0f, 2.0f, "%.2f deg/sec");
|
||||||
ImGui::SliderFloat("Roll Speed", &rollSpeed, 0.0f, 1.0f, "%.2f deg/sec");
|
}
|
||||||
|
|
||||||
// Add some presets
|
// Record button during animations
|
||||||
|
if ((autoRotate || autoRotateView) && !isRecordingAVI) {
|
||||||
ImGui::Separator();
|
ImGui::Separator();
|
||||||
ImGui::Text("Presets:");
|
if (ImGui::Button("Record Animation to AVI")) {
|
||||||
|
startAVIRecording(recordingDurationFrames);
|
||||||
if (ImGui::Button("Slow Pan")) {
|
|
||||||
yawSpeed = 0.3f;
|
|
||||||
pitchSpeed = 0.1f;
|
|
||||||
rollSpeed = 0.0f;
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("Full Exploration")) {
|
|
||||||
yawSpeed = 0.8f;
|
|
||||||
pitchSpeed = 0.5f;
|
|
||||||
rollSpeed = 0.2f;
|
|
||||||
}
|
|
||||||
ImGui::SameLine();
|
|
||||||
if (ImGui::Button("Reset View")) {
|
|
||||||
// Reset to forward view
|
|
||||||
camvX = 0.0f;
|
|
||||||
camvY = 0.0f;
|
|
||||||
camvZ = 1.0f;
|
|
||||||
cam.posfor.direction = Vec3f(camvX, camvY, camvZ);
|
|
||||||
cameraMoved = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Progress indicator
|
|
||||||
float progress = fmodf(autoRotationAngle * yawSpeed / 360.0f, 1.0f);
|
|
||||||
ImGui::ProgressBar(progress, ImVec2(-1, 0));
|
|
||||||
ImGui::Text("Full rotation progress: %.1f%%", progress * 100.0f);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui::Button("Save Screenshot During Rotation")) {
|
|
||||||
if (autoRotate) {
|
|
||||||
// Generate filename with timestamp
|
|
||||||
auto now = std::chrono::system_clock::now();
|
|
||||||
auto timestamp = std::chrono::duration_cast<std::chrono::milliseconds>(
|
|
||||||
now.time_since_epoch()).count();
|
|
||||||
std::string filename = "output/rotation_frame_" +
|
|
||||||
std::to_string(timestamp) + ".bmp";
|
|
||||||
|
|
||||||
// Save current frame
|
|
||||||
frame output = grid.renderFrame(cam, Vec2i(config.outWidth, config.outHeight),
|
|
||||||
frame::colormap::RGB);
|
|
||||||
BMPWriter::saveBMP(filename.c_str(), output);
|
|
||||||
|
|
||||||
ImGui::OpenPopup("Screenshot Saved");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Popup notification
|
ImGui::End();
|
||||||
if (ImGui::BeginPopupModal("Screenshot Saved", NULL,
|
|
||||||
ImGuiWindowFlags_AlwaysAutoResize)) {
|
|
||||||
ImGui::Text("Screenshot saved during rotation!");
|
|
||||||
if (ImGui::Button("OK")) {
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
}
|
}
|
||||||
ImGui::EndPopup();
|
|
||||||
|
// Handle AVI recording start request
|
||||||
|
if (recordingRequested) {
|
||||||
|
isRecordingAVI = true;
|
||||||
|
recordingRequested = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check if recording should stop
|
||||||
|
if (isRecordingAVI && recordedFrames.size() >= recordingDurationFrames) {
|
||||||
|
stopAndSaveAVI(config, aviFilename);
|
||||||
|
ImGui::OpenPopup("Recording Complete");
|
||||||
|
}
|
||||||
|
|
||||||
|
// Update preview if camera moved or enough time has passed
|
||||||
|
if (gridInitialized && !updatePreview) {
|
||||||
|
double timeSinceLastUpdate = currentTime - lastUpdateTime;
|
||||||
|
|
||||||
|
// Update preview if needed
|
||||||
|
if (cameraMoved || timeSinceLastUpdate > 0.1) {
|
||||||
|
livePreview(grid, config, cam);
|
||||||
|
lastUpdateTime = currentTime;
|
||||||
|
cameraMoved = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Reset accumulator for next frame
|
// Reset accumulator for next frame
|
||||||
accumulator -= targetFrameTime;
|
accumulator -= targetFrameTime;
|
||||||
|
|
||||||
@@ -581,30 +617,23 @@ int main() {
|
|||||||
glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
|
glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
// std::cout << "rendering" << std::endl;
|
|
||||||
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData());
|
||||||
|
|
||||||
glfwSwapBuffers(window);
|
glfwSwapBuffers(window);
|
||||||
//mainlogicthread.join();
|
|
||||||
|
|
||||||
// std::cout << "swapping buffers" << std::endl;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Cleanup
|
||||||
// std::cout << "shutting down" << std::endl;
|
|
||||||
ImGui_ImplOpenGL3_Shutdown();
|
ImGui_ImplOpenGL3_Shutdown();
|
||||||
ImGui_ImplGlfw_Shutdown();
|
ImGui_ImplGlfw_Shutdown();
|
||||||
ImGui::DestroyContext();
|
ImGui::DestroyContext();
|
||||||
|
|
||||||
|
|
||||||
// std::cout << "destroying" << std::endl;
|
|
||||||
glfwDestroyWindow(window);
|
glfwDestroyWindow(window);
|
||||||
if (textu != 0) {
|
if (textu != 0) {
|
||||||
glDeleteTextures(1, &textu);
|
glDeleteTextures(1, &textu);
|
||||||
textu = 0;
|
textu = 0;
|
||||||
}
|
}
|
||||||
glfwTerminate();
|
glfwTerminate();
|
||||||
// std::cout << "printing" << std::endl;
|
|
||||||
FunctionTimer::printStats(FunctionTimer::Mode::ENHANCED);
|
FunctionTimer::printStats(FunctionTimer::Mode::ENHANCED);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|||||||
Reference in New Issue
Block a user