hermespy-rt

Minimalistic signal processing ray-tracer in C
git clone https://git.ea.contact/hermespy-rt
Log | Files | Refs

commit 4c50605cb46fc4d3ad825f1f67565e100ef1ed1d
parent ee046840344c8d9dd305aa165af7fa7ee06e9c62
Author: Egor Achkasov <eaachkasov@edu.hse.ru>
Date:   Thu, 27 Mar 2025 21:53:13 +0100

Make vizrays callable

Diffstat:
MGNUmakefile | 21++++-----------------
Ainc/viz.h | 28++++++++++++++++++++++++++++
Dsrc/vizrays.c | 340-------------------------------------------------------------------------------
Mtest/test.c | 95+++++++++++++++++++++++++++++++++++++------------------------------------------
Dtest/test.h | 11-----------
Aviz/vizrays.c | 313+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
6 files changed, 390 insertions(+), 418 deletions(-)

diff --git a/GNUmakefile b/GNUmakefile @@ -2,15 +2,13 @@ CC := gcc CFLAGS := -Wall -Wextra -Wno-builtin-declaration-mismatch LDFLAGS := -lm -SRC := src/materials.c src/scene.c src/compute_paths.c test/test.c -VIZRAYS_SRC := src/scene.c src/vizrays.c +SRC := src/materials.c src/scene.c src/compute_paths.c test/test.c viz/vizrays.c SCENE_FROMSIONNA_SRC := src/scene.c src/materials.c src/scene_fromSionna.c TARGET := test.elf -VIZRAYS_TARGET := vizrays.elf SCENE_FROMSIONNA_TARGET := scene_fromSionna.elf -.PHONY: all dbg clean vizrays vizrays_dbg scene_fromSionna scene_fromSionna_dbg +.PHONY: all dbg clean scene_fromSionna scene_fromSionna_dbg all: CFLAGS += -O3 all: $(TARGET) @@ -18,30 +16,19 @@ all: $(TARGET) dbg: CFLAGS += -g -O0 dbg: $(TARGET) -vizrays: CFLAGS += -O3 -vizrays: LDFLAGS += -lGL -lGLU -lglut -vizrays: $(VIZRAYS_TARGET) - -vizrays_dbg: CFLAGS += -g -O0 -vizrays_dbg: LDFLAGS += -lGL -lGLU -lglut -vizrays_dbg: $(VIZRAYS_TARGET) - scene_fromSionna: CFLAGS += -O3 scene_fromSionna: $(SCENE_FROMSIONNA_TARGET) scene_fromSionna_dbg: CFLAGS += -g -O0 scene_fromSionna_dbg: $(SCENE_FROMSIONNA_TARGET) +$(TARGET): LDFLAGS += -lGL -lGLU -lglut $(TARGET): $(SRC) $(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@ -$(VIZRAYS_TARGET): $(VIZRAYS_SRC) - $(CC) $(CFLAGS) $^ $(LDFLAGS) -o $@ - $(SCENE_FROMSIONNA_TARGET): $(SCENE_FROMSIONNA_SRC) $(CC) $(CFLAGS) $^ -o $@ clean: - rm -f $(TARGET) $(VIZRAYS_TARGET) rt rt.*.so *.bin *.elf + rm -f $(TARGET) $(SCENE_FROMSIONNA_TARGET) rt rt.*.so *.bin *.elf *.o rm -rf __pycache__ - diff --git a/inc/viz.h b/inc/viz.h @@ -0,0 +1,28 @@ +/* Visualization utils. +The implementation files are located in viz/ +All of them require OpenGL and GLUT +add -lGL -lGLU -lglut to compile +*/ + +#ifndef VIZ_H +#define VIZ_H + +#include "scene.h" /* for Scene */ +#include "compute_paths.h" /* for RaysInfo */ +#include "common.h" /* for IN */ + +#include <stdint.h> /* for uint32_t */ + +/** Visualize rays in a 3D scene. + * + * \param raysInfo pointer to a RaysInfo structure + * \param scene pointer to a loaded scene in HRT format (see scene.h). Can be NULL + * \param numTx number of transmitters + */ +void vizrays( + IN RaysInfo *raysInfo, + IN Scene *scene, + IN uint32_t numTx +); + +#endif diff --git a/src/vizrays.c b/src/vizrays.c @@ -1,340 +0,0 @@ -#include "../inc/vec3.h" /* for Vec3 */ -#include "../inc/scene.h" /* for Scene, Mesh, scene_load */ -#include "../inc/ray.h" /* for Ray */ - -#include "../test/test.h" /* for g_numPaths, g_numBounces, g_numTx, g_numRx */ - -#include <GL/glut.h> -#include <stdio.h> -#include <stdlib.h> -#include <math.h> -#include <stdint.h> -#include <ctype.h> /* for tolower */ - -/** - * Structs - */ - -typedef struct { - Vec3 o, t; - float d; - float lastX, lastY; - float yaw, pitch, roll; -} Camera; - -/** - * Globals - */ - -Camera g_cam = { - {0.f, 0.f, 5.f}, - {0.f, 0.f, 0.f}, - 5.f, - 0.f, 0.f, - 0.f, 0.f, 0.f -}; -uint8_t g_mouseDown = 0; - -Ray* g_rays = NULL; -uint8_t *g_active = NULL; - -Scene g_scene = {0}; - -uint32_t g_bounce_cur = 0; - -/** - * Loading functions - */ - -void loadRays(const char* filename) { - FILE* file = fopen(filename, "rb"); - if (!file) { - printf("Failed to open file\n"); - exit(8); - } - - uint32_t fileSize = (g_numBounces + 1) * g_numTx * g_numPaths * 2 * 3; - g_rays = (Ray*)malloc(fileSize * sizeof(float)); - if (fread(g_rays, sizeof(float), fileSize, file) != fileSize) { - printf("Failed to read rays\n"); - exit(8); - } - fclose(file); - - /* active.bin */ - file = fopen("active.bin", "rb"); - if (!file) { - printf("Failed to open file\n"); - exit(8); - } - uint32_t activeSize = (g_numBounces + 1) * (g_numTx * g_numPaths / 8 + 1); - g_active = (uint8_t*)malloc(activeSize * sizeof(uint8_t)); - if (fread(g_active, sizeof(uint8_t), activeSize, file) != activeSize) { - printf("Failed to read active\n"); - exit(8); - } - fclose(file); -} - -/** - * Draw functions - */ - -void drawScene() { - glBegin(GL_TRIANGLES); - for (uint32_t i = 0; i < g_scene.num_meshes; i++) { - Mesh* mesh = &g_scene.meshes[i]; - float mesh_color = (float)i / g_scene.num_meshes; - glColor3f(mesh_color, 1.f - mesh_color, 0.f); - - for (uint32_t j = 0; j < mesh->num_triangles; j++) { - uint32_t idx = mesh->is[j * 3]; - Vec3 v1 = mesh->vs[idx]; - idx = mesh->is[j * 3 + 1]; - Vec3 v2 = mesh->vs[idx]; - idx = mesh->is[j * 3 + 2]; - Vec3 v3 = mesh->vs[idx]; - glVertex3f(v1.x, v1.y, v1.z); - glVertex3f(v2.x, v2.y, v2.z); - glVertex3f(v3.x, v3.y, v3.z); - } - } - glEnd(); -} - -void drawRays() { - float color = (float)g_bounce_cur / g_numBounces; - glColor3f(color, 0.0f, 1.0f - color); - - uint8_t active_bit = 1; - uint32_t num_skipped = 0; - for (uint32_t tx = 0; tx < g_numTx; ++tx) { - glBegin(GL_LINES); - - uint32_t active_byte = (tx * (g_numBounces + 1) + g_bounce_cur) * (g_numPaths / 8 + 1); - uint32_t ray_ind_base = (tx * (g_numBounces + 1) + g_bounce_cur) * g_numPaths; - - for (uint32_t path = 0; path < g_numPaths; ++path, active_bit <<= 1) { - if (!active_bit) { - active_byte++; - active_bit = 1; - } - if (!(g_active[active_byte] & active_bit)) - { - num_skipped++; - continue; - } - - uint32_t idx = ray_ind_base + path; - GLfloat x = g_rays[idx].o.x; - GLfloat y = g_rays[idx].o.y; - GLfloat z = g_rays[idx].o.z; - /* Origin */ - glVertex3f(x, y, z); - /* Destination */ - glVertex3f( - x + g_rays[idx].d.x, - y + g_rays[idx].d.y, - z + g_rays[idx].d.z - ); - } - glEnd(); - - /* Draw points */ - glPointSize(5.0f); - glBegin(GL_POINTS); - active_byte = g_bounce_cur * (g_numTx * g_numPaths / 8 + 1); - active_bit = 1; - for (uint32_t path = 0; path < g_numPaths; ++path) { - if (!active_bit) { - active_byte++; - active_bit = 1; - } - if (!(g_active[active_byte] & active_bit)) - continue; - uint32_t idx = ray_ind_base + path; - glVertex3f(g_rays[idx].o.x, g_rays[idx].o.y, g_rays[idx].o.z); - } - glEnd(); - } - - printf("\rSkipped %d paths", num_skipped); - fflush(stdout); -} - -/** - * Callbacks - */ - -void reshape(int w, int h) { - glViewport(0, 0, w, h); - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective(60.0f, (float)w/h, 0.1f, 1000.0f); - glMatrixMode(GL_MODELVIEW); -} - -void display() { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - glLoadIdentity(); - - /* Look at target from camera position */ - gluLookAt( - g_cam.o.x, g_cam.o.y, g_cam.o.z, - g_cam.t.x, g_cam.t.y, g_cam.t.z, - 0.0f, 1.0f, 0.0f - ); - - drawScene(); - drawRays(); - - glutSwapBuffers(); -} - -void updateCamera() { - float x = g_cam.d * cosf(g_cam.pitch) * cosf(g_cam.yaw); - float y = g_cam.d * sinf(g_cam.pitch); - float z = g_cam.d * cosf(g_cam.pitch) * sinf(g_cam.yaw); - - g_cam.o.x = g_cam.t.x + x; - g_cam.o.y = g_cam.t.y + y; - g_cam.o.z = g_cam.t.z + z; - - gluLookAt(g_cam.o.x, g_cam.o.y, g_cam.o.z, - g_cam.t.x, g_cam.t.y, g_cam.t.z, - 0.f, 1.f, 0.f); -} - -void keyboard(unsigned char key, int x, int y) { - float moveSpeed = 0.1f; - float tiltSpeed = 0.15f; - /* Speed up if SHIFT is down */ - if (glutGetModifiers() & GLUT_ACTIVE_SHIFT) { - moveSpeed *= 5; - key = tolower(key); - } - - /* Calculate forward direction */ - Vec3 dir = { - g_cam.t.x - g_cam.o.x, - g_cam.t.y - g_cam.o.y, - g_cam.t.z - g_cam.o.z - }; - float norm = sqrtf(dir.x * dir.x + dir.y * dir.y + dir.z * dir.z); - Vec3 forward = {dir.x / norm, dir.y / norm, dir.z / norm}; - - /* Calculate right vector (cross product of forward and up (0,0,1)) */ - norm = sqrtf(forward.z * forward.z + forward.x * forward.x); - Vec3 right = {forward.z / norm, 0.0f, -forward.x / norm}; - - switch (key) { - case 'w': /* Move target forward */ - g_cam.t.x += forward.x * moveSpeed; - g_cam.t.z += forward.z * moveSpeed; - break; - case 's': /* Move target backward */ - g_cam.t.x -= forward.x * moveSpeed; - g_cam.t.z -= forward.z * moveSpeed; - break; - case 'a': /* Move target left */ - g_cam.t.x += right.x * moveSpeed; - g_cam.t.z += right.z * moveSpeed; - break; - case 'd': /* Move target right */ - g_cam.t.x -= right.x * moveSpeed; - g_cam.t.z -= right.z * moveSpeed; - break; - - case 'q': /* Roll left */ - g_cam.roll += tiltSpeed; - break; - case 'e': /* Roll right */ - g_cam.roll -= tiltSpeed; - break; - - case 'x': /* Increase g_curBounce */ - if (g_bounce_cur < g_numBounces) g_bounce_cur++; - break; - case 'z': /* Decrease g_curBounce */ - if (g_bounce_cur > 0) g_bounce_cur--; - break; - } - - updateCamera(); - glutPostRedisplay(); -} - -void mouse(int button, int state, int x, int y) { - if (button == GLUT_LEFT_BUTTON) { - g_mouseDown = (state == GLUT_DOWN); - g_cam.lastX = x; - g_cam.lastY = y; - } - /* Handle scroll wheel */ - else if (button == 3) { /* Scroll up */ - g_cam.d = fmaxf(0.1f, g_cam.d - 0.5f); /* Prevent going too close */ - updateCamera(); - glutPostRedisplay(); - } - else if (button == 4) { /* Scroll down */ - g_cam.d += 0.5f; - updateCamera(); - glutPostRedisplay(); - } -} - -void mouseMotion(int x, int y) { - if (!g_mouseDown) return; - - float sensitivity = 0.005f; - float dx = (float)(x - g_cam.lastX); - float dy = (float)(y - g_cam.lastY); - - g_cam.yaw -= dx * sensitivity; - g_cam.pitch -= dy * sensitivity; - - /* Clamp pitch to prevent flipping */ - if (g_cam.pitch > 1.5f) g_cam.pitch = 1.5f; - if (g_cam.pitch < -1.5f) g_cam.pitch = -1.5f; - - g_cam.lastX = x; - g_cam.lastY = y; - - updateCamera(); - glutPostRedisplay(); -} - -/** - * Main - */ - -int main(int argc, char** argv) { - const char* rays_filename = "rays.bin"; - - /* Load ray data */ - loadRays(rays_filename); - if (argc > 1) - g_scene = scene_load(argv[1]); - - /* Initialize GLUT */ - glutInit(&argc, argv); - glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); - glutInitWindowSize(800, 600); - glutCreateWindow("Ray Visualization"); - - /* Set up OpenGL */ - glEnable(GL_DEPTH_TEST); - glClearColor(0.f, 0.f, 0.f, 1.0f); - - /* Register callbacks */ - glutDisplayFunc(display); - glutReshapeFunc(reshape); - glutKeyboardFunc(keyboard); - glutMouseFunc(mouse); - glutMotionFunc(mouseMotion); - - updateCamera(); - glutMainLoop(); - - return 0; -} diff --git a/test/test.c b/test/test.c @@ -2,8 +2,7 @@ #include "../inc/scene.h" /* for Scene, scene_load */ #include "../inc/vec3.h" /* for Vec3 */ #include "../inc/ray.h" /* for Ray */ - -#include "test.h" /* for g_numRx, g_numTx, g_numPaths, g_numBounces */ +#include "../inc/viz.h" /* for vizrays */ #include <stdio.h> /* for fprintf */ #include <stdlib.h> /* for malloc */ @@ -15,56 +14,65 @@ int main(int argc, char **argv) return 1; } - Vec3 rx_positions[1] = {{0.0, 0.0, .5}}; - Vec3 tx_positions[1] = {{0.0, 0.0, .5}}; - Vec3 rx_velocities[1] = {{0.0, 0.0, 0.0}}; - Vec3 tx_velocities[1] = {{0.0, 0.0, 0.0}}; - float carrier_frequency = 3.0; /* 3 GHz */ + uint32_t numRx = 1; + uint32_t numTx = 1; + uint32_t numPaths = 30000; + uint32_t numBounces = 3; + + Vec3 rx_pos[1] = {{0.0, 0.0, .5}}; + Vec3 tx_pos[1] = {{0.0, 0.0, .5}}; + Vec3 rx_vel[1] = {{0.0, 0.0, 0.0}}; + Vec3 tx_vel[1] = {{0.0, 0.0, 0.0}}; + + float carrier_frequency_ghz = 3.0; + ChannelInfo chanInfo_los = { .num_rays = 1, - .directions_rx = (Vec3*)malloc(g_numRx * g_numTx * sizeof(Vec3)), - .directions_tx = (Vec3*)malloc(g_numRx * g_numTx * sizeof(Vec3)), - .a_te_re = (float*)malloc(g_numRx * g_numTx * sizeof(float)), - .a_te_im = (float*)malloc(g_numRx * g_numTx * sizeof(float)), - .a_tm_re = (float*)malloc(g_numRx * g_numTx * sizeof(float)), - .a_tm_im = (float*)malloc(g_numRx * g_numTx * sizeof(float)), - .tau = (float*)malloc(g_numRx * g_numTx * sizeof(float)), - .freq_shift = (float*)malloc(g_numRx * g_numTx * sizeof(float)), + .directions_rx = (Vec3*)malloc(numRx * numTx * sizeof(Vec3)), + .directions_tx = (Vec3*)malloc(numRx * numTx * sizeof(Vec3)), + .a_te_re = (float*)malloc(numRx * numTx * sizeof(float)), + .a_te_im = (float*)malloc(numRx * numTx * sizeof(float)), + .a_tm_re = (float*)malloc(numRx * numTx * sizeof(float)), + .a_tm_im = (float*)malloc(numRx * numTx * sizeof(float)), + .tau = (float*)malloc(numRx * numTx * sizeof(float)), + .freq_shift = (float*)malloc(numRx * numTx * sizeof(float)), }; RaysInfo raysInfo_los = { - .rays = (Ray*)malloc(g_numRx * g_numTx * sizeof(Ray)), - .rays_active = (uint8_t*)malloc(g_numRx * g_numTx * sizeof(uint8_t) / 8 + 1) + .rays = (Ray*)malloc(numRx * numTx * sizeof(Ray)), + .rays_active = (uint8_t*)malloc(numRx * numTx * sizeof(uint8_t) / 8 + 1) }; ChannelInfo chanInfo_scat = { - .num_rays = g_numBounces * g_numPaths, - .directions_rx = (Vec3*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(Vec3)), - .directions_tx = (Vec3*)malloc(g_numPaths * sizeof(Vec3)), - .a_te_re = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(float)), - .a_te_im = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(float)), - .a_tm_re = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(float)), - .a_tm_im = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(float)), - .tau = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(float)), - .freq_shift = (float*)malloc(g_numRx * g_numTx * g_numBounces * g_numPaths * sizeof(float)), + .num_rays = numBounces * numPaths, + .directions_rx = (Vec3*)malloc(numRx * numTx * numBounces * numPaths * sizeof(Vec3)), + .directions_tx = (Vec3*)malloc(numPaths * sizeof(Vec3)), + .a_te_re = (float*)malloc(numRx * numTx * numBounces * numPaths * sizeof(float)), + .a_te_im = (float*)malloc(numRx * numTx * numBounces * numPaths * sizeof(float)), + .a_tm_re = (float*)malloc(numRx * numTx * numBounces * numPaths * sizeof(float)), + .a_tm_im = (float*)malloc(numRx * numTx * numBounces * numPaths * sizeof(float)), + .tau = (float*)malloc(numRx * numTx * numBounces * numPaths * sizeof(float)), + .freq_shift = (float*)malloc(numRx * numTx * numBounces * numPaths * sizeof(float)), }; RaysInfo raysInfo_scat = { - .num_bounces = g_numBounces + 1, - .num_rays = g_numPaths, - .rays = (Ray*)malloc(g_numRx * g_numTx * (g_numBounces + 1) * g_numPaths * sizeof(Ray)), - .rays_active = (uint8_t*)malloc(g_numRx * g_numTx * (g_numBounces + 1) * (g_numPaths / 8 + 1) * sizeof(uint8_t)) + .num_bounces = numBounces + 1, + .num_rays = numPaths, + .rays = (Ray*)malloc(numRx * numTx * (numBounces + 1) * numPaths * sizeof(Ray)), + .rays_active = (uint8_t*)malloc(numRx * numTx * (numBounces + 1) * (numPaths / 8 + 1) * sizeof(uint8_t)) }; + Scene scene = scene_load(argv[1]); + compute_paths( &scene, - rx_positions, - tx_positions, - rx_velocities, - tx_velocities, - carrier_frequency, - g_numRx, g_numTx, g_numPaths, g_numBounces, + rx_pos, tx_pos, + rx_vel, tx_vel, + carrier_frequency_ghz, + numRx, numTx, numPaths, numBounces, &chanInfo_los, &raysInfo_los, &chanInfo_scat, &raysInfo_scat ); + vizrays(&raysInfo_scat, &scene, numTx); + /* Save the results */ FILE *f; @@ -73,20 +81,7 @@ int main(int argc, char **argv) fwrite(data, sizeof(dt), size, f); \ fclose(f); - WRITE_BIN( - "rays.bin", - raysInfo_scat.rays, - float, - g_numRx * g_numTx * (g_numBounces + 1) * g_numPaths * 6 - ); - WRITE_BIN( - "active.bin", - raysInfo_scat.rays_active, - uint8_t, - g_numRx * g_numTx * (g_numBounces + 1) * (g_numPaths / 8 + 1) - ); - /* Use this macro to write what you would like to inspect to a binary file */ /* Example: */ - /* WRITE_BIN("los_directions_rx.bin", los.directions_rx, float, g_numRx * g_numTx * 3); */ + /* WRITE_BIN("los_directions_rx.bin", los.directions_rx, float, numRx * numTx * 3); */ } diff --git a/test/test.h b/test/test.h @@ -1,11 +0,0 @@ -#ifndef TEST_H -#define TEST_H - -#include <stdint.h> - -uint32_t g_numPaths = 10000; -uint32_t g_numBounces = 3; -uint32_t g_numTx = 1; -uint32_t g_numRx = 1; - -#endif diff --git a/viz/vizrays.c b/viz/vizrays.c @@ -0,0 +1,313 @@ +#include "../inc/viz.h" /* for vizrays */ +#include "../inc/vec3.h" /* for Vec3 */ +#include "../inc/scene.h" /* for Scene, Mesh, scene_load */ +#include "../inc/ray.h" /* for Ray */ + +#include <GL/glut.h> +#include <stdio.h> +#include <stdlib.h> +#include <math.h> +#include <stdint.h> +#include <ctype.h> /* for tolower */ + +/** + * Structs + */ + +typedef struct { + Vec3 o, t; + float d; + float lastX, lastY; + float yaw, pitch, roll; +} Camera; + +/** + * Globals + */ + +Camera g_cam = { + {0.f, 0.f, 5.f}, + {0.f, 0.f, 0.f}, + 5.f, + 0.f, 0.f, + 0.f, 0.f, 0.f +}; +uint8_t g_mouseDown = 0; + +Ray* g_rays = NULL; +uint8_t *g_active = NULL; +Scene* g_scene = NULL; + +uint32_t g_numTx = 0; +uint32_t g_numPaths = 0; +uint32_t g_numBounces = 0; + +uint32_t g_bounce_cur = 0; + +/** + * Draw functions + */ + +void drawScene() { + glBegin(GL_TRIANGLES); + for (uint32_t i = 0; i < g_scene->num_meshes; i++) { + Mesh* mesh = &g_scene->meshes[i]; + float mesh_color = (float)i / g_scene->num_meshes; + glColor3f(mesh_color, 1.f - mesh_color, 0.f); + + for (uint32_t j = 0; j < mesh->num_triangles; j++) { + uint32_t idx = mesh->is[j * 3]; + Vec3 v1 = mesh->vs[idx]; + idx = mesh->is[j * 3 + 1]; + Vec3 v2 = mesh->vs[idx]; + idx = mesh->is[j * 3 + 2]; + Vec3 v3 = mesh->vs[idx]; + glVertex3f(v1.x, v1.y, v1.z); + glVertex3f(v2.x, v2.y, v2.z); + glVertex3f(v3.x, v3.y, v3.z); + } + } + glEnd(); +} + +void drawRays() { + float color = (float)g_bounce_cur / g_numBounces; + glColor3f(color, 0.0f, 1.0f - color); + + uint8_t active_bit = 1; + uint32_t num_skipped = 0; + for (uint32_t tx = 0; tx < g_numTx; ++tx) { + glBegin(GL_LINES); + + uint32_t active_byte = (tx * (g_numBounces + 1) + g_bounce_cur) * (g_numPaths / 8 + 1); + uint32_t ray_ind_base = (tx * (g_numBounces + 1) + g_bounce_cur) * g_numPaths; + + for (uint32_t path = 0; path < g_numPaths; ++path, active_bit <<= 1) { + if (!active_bit) { + active_byte++; + active_bit = 1; + } + if (!(g_active[active_byte] & active_bit)) + { + num_skipped++; + continue; + } + + uint32_t idx = ray_ind_base + path; + GLfloat x = g_rays[idx].o.x; + GLfloat y = g_rays[idx].o.y; + GLfloat z = g_rays[idx].o.z; + /* Origin */ + glVertex3f(x, y, z); + /* Destination */ + glVertex3f( + x + g_rays[idx].d.x, + y + g_rays[idx].d.y, + z + g_rays[idx].d.z + ); + } + glEnd(); + + /* Draw points */ + glPointSize(5.0f); + glBegin(GL_POINTS); + active_byte = g_bounce_cur * (g_numTx * g_numPaths / 8 + 1); + active_bit = 1; + for (uint32_t path = 0; path < g_numPaths; ++path) { + if (!active_bit) { + active_byte++; + active_bit = 1; + } + if (!(g_active[active_byte] & active_bit)) + continue; + uint32_t idx = ray_ind_base + path; + glVertex3f(g_rays[idx].o.x, g_rays[idx].o.y, g_rays[idx].o.z); + } + glEnd(); + } + + printf("\rSkipped %d paths", num_skipped); + fflush(stdout); +} + +/** + * Callbacks + */ + +void reshape(int w, int h) { + glViewport(0, 0, w, h); + glMatrixMode(GL_PROJECTION); + glLoadIdentity(); + gluPerspective(60.0f, (float)w/h, 0.1f, 1000.0f); + glMatrixMode(GL_MODELVIEW); +} + +void display() { + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glLoadIdentity(); + + /* Look at target from camera position */ + gluLookAt( + g_cam.o.x, g_cam.o.y, g_cam.o.z, + g_cam.t.x, g_cam.t.y, g_cam.t.z, + 0.0f, 1.0f, 0.0f + ); + + if (g_scene) drawScene(); + drawRays(); + + glutSwapBuffers(); +} + +void updateCamera() { + float x = g_cam.d * cosf(g_cam.pitch) * cosf(g_cam.yaw); + float y = g_cam.d * sinf(g_cam.pitch); + float z = g_cam.d * cosf(g_cam.pitch) * sinf(g_cam.yaw); + + g_cam.o.x = g_cam.t.x + x; + g_cam.o.y = g_cam.t.y + y; + g_cam.o.z = g_cam.t.z + z; + + gluLookAt(g_cam.o.x, g_cam.o.y, g_cam.o.z, + g_cam.t.x, g_cam.t.y, g_cam.t.z, + 0.f, 1.f, 0.f); +} + +void keyboard(unsigned char key, int x, int y) { + float moveSpeed = 0.1f; + float tiltSpeed = 0.15f; + /* Speed up if SHIFT is down */ + if (glutGetModifiers() & GLUT_ACTIVE_SHIFT) { + moveSpeed *= 5; + key = tolower(key); + } + + /* Calculate forward direction */ + Vec3 dir = { + g_cam.t.x - g_cam.o.x, + g_cam.t.y - g_cam.o.y, + g_cam.t.z - g_cam.o.z + }; + float norm = sqrtf(dir.x * dir.x + dir.y * dir.y + dir.z * dir.z); + Vec3 forward = {dir.x / norm, dir.y / norm, dir.z / norm}; + + /* Calculate right vector (cross product of forward and up (0,0,1)) */ + norm = sqrtf(forward.z * forward.z + forward.x * forward.x); + Vec3 right = {forward.z / norm, 0.0f, -forward.x / norm}; + + switch (key) { + case 'w': /* Move target forward */ + g_cam.t.x += forward.x * moveSpeed; + g_cam.t.z += forward.z * moveSpeed; + break; + case 's': /* Move target backward */ + g_cam.t.x -= forward.x * moveSpeed; + g_cam.t.z -= forward.z * moveSpeed; + break; + case 'a': /* Move target left */ + g_cam.t.x += right.x * moveSpeed; + g_cam.t.z += right.z * moveSpeed; + break; + case 'd': /* Move target right */ + g_cam.t.x -= right.x * moveSpeed; + g_cam.t.z -= right.z * moveSpeed; + break; + + case 'q': /* Roll left */ + g_cam.roll += tiltSpeed; + break; + case 'e': /* Roll right */ + g_cam.roll -= tiltSpeed; + break; + + case 'x': /* Increase g_curBounce */ + if (g_bounce_cur < g_numBounces) g_bounce_cur++; + break; + case 'z': /* Decrease g_curBounce */ + if (g_bounce_cur > 0) g_bounce_cur--; + break; + } + + updateCamera(); + glutPostRedisplay(); +} + +void mouse(int button, int state, int x, int y) { + if (button == GLUT_LEFT_BUTTON) { + g_mouseDown = (state == GLUT_DOWN); + g_cam.lastX = x; + g_cam.lastY = y; + } + /* Handle scroll wheel */ + else if (button == 3) { /* Scroll up */ + g_cam.d = fmaxf(0.1f, g_cam.d - 0.5f); /* Prevent going too close */ + updateCamera(); + glutPostRedisplay(); + } + else if (button == 4) { /* Scroll down */ + g_cam.d += 0.5f; + updateCamera(); + glutPostRedisplay(); + } +} + +void mouseMotion(int x, int y) { + if (!g_mouseDown) return; + + float sensitivity = 0.005f; + float dx = (float)(x - g_cam.lastX); + float dy = (float)(y - g_cam.lastY); + + g_cam.yaw -= dx * sensitivity; + g_cam.pitch -= dy * sensitivity; + + /* Clamp pitch to prevent flipping */ + if (g_cam.pitch > 1.5f) g_cam.pitch = 1.5f; + if (g_cam.pitch < -1.5f) g_cam.pitch = -1.5f; + + g_cam.lastX = x; + g_cam.lastY = y; + + updateCamera(); + glutPostRedisplay(); +} + +/** + * vizrays + */ + +void vizrays( + IN RaysInfo *raysInfo, + IN Scene *scene, + IN uint32_t numTx +) +{ + g_rays = raysInfo->rays; + g_active = raysInfo->rays_active; + g_scene = scene; + g_numTx = numTx; + g_numPaths = raysInfo->num_rays; + g_numBounces = raysInfo->num_bounces; + + /* Initialize GLUT */ + int fake_argc = 1; + char *fake_argv[] = {"vizrays"}; + glutInit(&fake_argc, fake_argv); + glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGB | GLUT_DEPTH); + glutInitWindowSize(800, 600); + glutCreateWindow("Ray Visualization"); + + /* Set up OpenGL */ + glEnable(GL_DEPTH_TEST); + glClearColor(0.f, 0.f, 0.f, 1.0f); + + /* Register callbacks */ + glutDisplayFunc(display); + glutReshapeFunc(reshape); + glutKeyboardFunc(keyboard); + glutMouseFunc(mouse); + glutMotionFunc(mouseMotion); + + updateCamera(); + glutMainLoop(); +}