commit 4c50605cb46fc4d3ad825f1f67565e100ef1ed1d
parent ee046840344c8d9dd305aa165af7fa7ee06e9c62
Author: Egor Achkasov <eaachkasov@edu.hse.ru>
Date: Thu, 27 Mar 2025 21:53:13 +0100
Make vizrays callable
Diffstat:
| M | GNUmakefile | | | 21 | ++++----------------- |
| A | inc/viz.h | | | 28 | ++++++++++++++++++++++++++++ |
| D | src/vizrays.c | | | 340 | ------------------------------------------------------------------------------- |
| M | test/test.c | | | 95 | +++++++++++++++++++++++++++++++++++++------------------------------------------ |
| D | test/test.h | | | 11 | ----------- |
| A | viz/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();
+}