Tue 31 Mar 10:06:49 CEST 2026
This commit is contained in:
parent
27c2fa937f
commit
ab91f78965
472
xraysim/xraysim.cxx
Normal file
472
xraysim/xraysim.cxx
Normal file
|
|
@ -0,0 +1,472 @@
|
||||||
|
#include <cstdlib>
|
||||||
|
#include <cstdio>
|
||||||
|
#include <cstring>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <iostream>
|
||||||
|
#include <exception>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include "SimpleGVXR.h"
|
||||||
|
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <tiffio.h>
|
||||||
|
|
||||||
|
float version = 3.14;
|
||||||
|
|
||||||
|
// for synthetic noise
|
||||||
|
#include <random>
|
||||||
|
std::mt19937 generator;
|
||||||
|
double mean = 0.0;
|
||||||
|
double stddev = 1.0;
|
||||||
|
std::normal_distribution<double> normal(mean, stddev);
|
||||||
|
|
||||||
|
void usage () {
|
||||||
|
printf("xraysim v%f\n",version);
|
||||||
|
printf("usage: xraysim [-s(ourcePos) x y z] [-d(etPos) x y z] [-D(detUpVec) x y z]\n");
|
||||||
|
printf(" [-e(nergy) MeV] [-S(caleIntensity) min max range] [-n addgaussnoiseperc]\n");
|
||||||
|
printf(" [-r(otate-z) degree] [-R(otate) x y z]\n");
|
||||||
|
printf(" [-ct(-rotate-z-step) delta_degree] [-cr(-rotate-z-range) degree]\n");
|
||||||
|
printf(" [-w pixels] [-h pixels] [-p pixelsize] [-g openglwinsize]\n");
|
||||||
|
printf(" [-show(_scene)] [-soft(ware_cpu_renderer)] [-o out[%%04d].tif/pgm]\n");
|
||||||
|
printf(" [-u density g/cm3] file.stl [-u density file2.stl]\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
long int millitime() {
|
||||||
|
struct timeval tp;
|
||||||
|
gettimeofday(&tp, NULL);
|
||||||
|
long int ms = tp.tv_sec * 1000 + tp.tv_usec / 1000;
|
||||||
|
return ms;
|
||||||
|
}
|
||||||
|
|
||||||
|
int savePGM(std::string output,std::vector<std::vector<float>> image,
|
||||||
|
float scaleMin, float scaleMax, float scaleRange){
|
||||||
|
int iwidth=image.at(0).size(),
|
||||||
|
iheight=image.size();
|
||||||
|
// Save the image into a image file
|
||||||
|
printf("Saving Xray Image to file %s (Scale min=%f max=%f range=%f)\n",
|
||||||
|
output.c_str(),scaleMin,scaleMax,scaleRange);
|
||||||
|
// normalize to X bits / scaleRange
|
||||||
|
FILE *fd = fopen(output.c_str(),"w+");
|
||||||
|
fprintf(fd,"P2\n");
|
||||||
|
fprintf(fd,"%d %d\n",image.at(0).size(),image.size());
|
||||||
|
fprintf(fd,"%d\n",(int)scaleRange);
|
||||||
|
int k=0,length=image.size()*image.at(0).size();
|
||||||
|
for(int i=0;i<image.size();i++) {
|
||||||
|
for(int j=0;j<image.at(0).size();j++) {
|
||||||
|
float v=(image.at(i).at(j)-scaleMin)/(scaleMax-scaleMin);
|
||||||
|
fprintf(fd,"%d",int(v*scaleRange));
|
||||||
|
k++;
|
||||||
|
if ((k%16)==0) fprintf(fd,"\n");
|
||||||
|
else if (k<length) fprintf(fd," ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fclose(fd);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int saveTIFF(std::string output,std::vector<std::vector<float>> image,
|
||||||
|
float scaleMin, float scaleMax){
|
||||||
|
float scaleRange=65535;
|
||||||
|
int iwidth=image.at(0).size(),
|
||||||
|
iheight=image.size();
|
||||||
|
printf("Saving Xray Image to file %s (Scale min=%f max=%f range=%f)\n",
|
||||||
|
output.c_str(),scaleMin,scaleMax,scaleRange);
|
||||||
|
// Write 16 bit tiff
|
||||||
|
// Open the TIFF file
|
||||||
|
TIFF *output_image;
|
||||||
|
if((output_image = TIFFOpen(output.c_str(), "w")) == NULL){
|
||||||
|
std::cerr << "Unable to write tif file: " << output << std::endl;
|
||||||
|
}
|
||||||
|
TIFFSetField(output_image, TIFFTAG_IMAGEWIDTH, iwidth);
|
||||||
|
TIFFSetField(output_image, TIFFTAG_IMAGELENGTH, iheight);
|
||||||
|
TIFFSetField(output_image, TIFFTAG_SAMPLESPERPIXEL, 1);
|
||||||
|
TIFFSetField(output_image, TIFFTAG_BITSPERSAMPLE, 16);
|
||||||
|
TIFFSetField(output_image, TIFFTAG_ROWSPERSTRIP, iheight);
|
||||||
|
TIFFSetField(output_image, TIFFTAG_ORIENTATION, (int)ORIENTATION_TOPLEFT);
|
||||||
|
TIFFSetField(output_image, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG);
|
||||||
|
TIFFSetField(output_image, TIFFTAG_COMPRESSION, COMPRESSION_NONE);
|
||||||
|
TIFFSetField(output_image, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_MINISBLACK);
|
||||||
|
|
||||||
|
tsize_t image_s;
|
||||||
|
short int *data=(short int*)malloc(iwidth*iheight*2);
|
||||||
|
int k=0;
|
||||||
|
for(int i=0;i<image.size();i++) {
|
||||||
|
for(int j=0;j<image.at(0).size();j++) {
|
||||||
|
float v=(image.at(i).at(j)-scaleMin)/(scaleMax-scaleMin);
|
||||||
|
data[k]=int(v*scaleRange);
|
||||||
|
k++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if((image_s = TIFFWriteEncodedStrip(output_image, 0, (tdata_t) data, iwidth*iheight*2)) == -1)
|
||||||
|
{
|
||||||
|
std::cerr << "Unable to write tif file: " << output << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
TIFFWriteDirectory(output_image);
|
||||||
|
TIFFClose(output_image);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// usage: xraysim [-s x y z] [-e MeV] [-d x y z] [-w pixels] [-h pixels] [-p pixelsize] file.stl
|
||||||
|
int main(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
|
||||||
|
bool showScene=0;
|
||||||
|
bool softRenderer=0;
|
||||||
|
float sourcePosX=-40.0;
|
||||||
|
float sourcePosY=0.0;
|
||||||
|
float sourcePosZ=0.0;
|
||||||
|
float detPosX=10.0;
|
||||||
|
float detPosY=0.0;
|
||||||
|
float detPosZ=0.0;
|
||||||
|
float detUpX=0.0;
|
||||||
|
float detUpY=0.0;
|
||||||
|
float detUpZ=-1.0;
|
||||||
|
float hu[10] = {1000.0,1000.0,1000.0,1000.0,1000.0,
|
||||||
|
1000.0,1000.0,1000.0,1000.0,1000.0};
|
||||||
|
float density[10] = {1.0,1.0,1.0,1.0,1.0,
|
||||||
|
1.0,1.0,1.0,1.0,1.0};
|
||||||
|
|
||||||
|
float energy = 0.08;
|
||||||
|
int width = 640;
|
||||||
|
int height = 320;
|
||||||
|
int glwinsize = 500;
|
||||||
|
|
||||||
|
float pixelSize = 0.5;
|
||||||
|
|
||||||
|
float angleX = 0.0;
|
||||||
|
float angleY = 0.0;
|
||||||
|
float angleZ = 0.0;
|
||||||
|
|
||||||
|
float angleCT = 0.0;
|
||||||
|
float angleCTRange = 360.0;
|
||||||
|
|
||||||
|
float scaleK = 0.0;
|
||||||
|
float scaleRange = 65535;
|
||||||
|
float scaleMin = 0.0;
|
||||||
|
float scaleMax = 0.0;
|
||||||
|
|
||||||
|
float noise = 0.0;
|
||||||
|
|
||||||
|
int parts = 0;
|
||||||
|
int frameIndex = 0;
|
||||||
|
int frames = 1;
|
||||||
|
|
||||||
|
std::string file[10];
|
||||||
|
std::string partLabel[10]={"A","B","C","D","E","F","G","H","I","J"};
|
||||||
|
std::string output="xray.tif";
|
||||||
|
|
||||||
|
setenv("DISPLAY",":0.0",1);
|
||||||
|
|
||||||
|
if (argc<2) { usage(); return EXIT_FAILURE; }
|
||||||
|
for (int i = 1; i < argc; ++i) {
|
||||||
|
if (std::string(argv[i]) == "-o") {
|
||||||
|
if (i + 1 < argc) {
|
||||||
|
i++;
|
||||||
|
output = argv[i];
|
||||||
|
continue;
|
||||||
|
} else { usage(); return EXIT_FAILURE; }
|
||||||
|
}
|
||||||
|
if (std::string(argv[i]) == "-u") {
|
||||||
|
if (i + 1 < argc) {
|
||||||
|
i++;
|
||||||
|
density[parts] = std::stof(argv[i]);
|
||||||
|
continue;
|
||||||
|
} else { usage(); return EXIT_FAILURE; }
|
||||||
|
}
|
||||||
|
if (std::string(argv[i]) == "-e") {
|
||||||
|
if (i + 1 < argc) {
|
||||||
|
i++;
|
||||||
|
energy = std::stof(argv[i]);
|
||||||
|
continue;
|
||||||
|
} else { usage(); return EXIT_FAILURE; }
|
||||||
|
}
|
||||||
|
if (std::string(argv[i]) == "-ct") {
|
||||||
|
if (i + 1 < argc) {
|
||||||
|
i++;
|
||||||
|
angleCT = std::stof(argv[i]);
|
||||||
|
continue;
|
||||||
|
} else { usage(); return EXIT_FAILURE; }
|
||||||
|
}
|
||||||
|
if (std::string(argv[i]) == "-cr") {
|
||||||
|
if (i + 1 < argc) {
|
||||||
|
i++;
|
||||||
|
angleCTRange = std::stof(argv[i]);
|
||||||
|
continue;
|
||||||
|
} else { usage(); return EXIT_FAILURE; }
|
||||||
|
}
|
||||||
|
if (std::string(argv[i]) == "-S") {
|
||||||
|
if (i + 3 < argc) {
|
||||||
|
i++;
|
||||||
|
scaleMin = std::stof(argv[i++]);
|
||||||
|
scaleMax = std::stof(argv[i++]);
|
||||||
|
scaleRange = std::stof(argv[i]);
|
||||||
|
continue;
|
||||||
|
} else { usage(); return EXIT_FAILURE; }
|
||||||
|
}
|
||||||
|
if (std::string(argv[i]) == "-r") {
|
||||||
|
if (i + 1 < argc) {
|
||||||
|
i++;
|
||||||
|
angleZ = std::stof(argv[i]);
|
||||||
|
continue;
|
||||||
|
} else { usage(); return EXIT_FAILURE; }
|
||||||
|
}
|
||||||
|
if (std::string(argv[i]) == "-p") {
|
||||||
|
if (i + 1 < argc) {
|
||||||
|
i++;
|
||||||
|
pixelSize = std::stof(argv[i]);
|
||||||
|
continue;
|
||||||
|
} else { usage(); return EXIT_FAILURE; }
|
||||||
|
}
|
||||||
|
if (std::string(argv[i]) == "-w") {
|
||||||
|
if (i + 1 < argc) {
|
||||||
|
i++;
|
||||||
|
width = std::stoi(argv[i]);
|
||||||
|
continue;
|
||||||
|
} else { usage(); return EXIT_FAILURE; }
|
||||||
|
}
|
||||||
|
if (std::string(argv[i]) == "-h") {
|
||||||
|
if (i + 1 < argc) {
|
||||||
|
i++;
|
||||||
|
height = std::stoi(argv[i]);
|
||||||
|
continue;
|
||||||
|
} else { usage(); return EXIT_FAILURE; }
|
||||||
|
}
|
||||||
|
if (std::string(argv[i]) == "-g") {
|
||||||
|
if (i + 1 < argc) {
|
||||||
|
i++;
|
||||||
|
glwinsize = std::stoi(argv[i]);
|
||||||
|
continue;
|
||||||
|
} else { usage(); return EXIT_FAILURE; }
|
||||||
|
}
|
||||||
|
if (std::string(argv[i]) == "-n") {
|
||||||
|
if (i + 1 < argc) {
|
||||||
|
i++;
|
||||||
|
noise = std::stof(argv[i]);
|
||||||
|
continue;
|
||||||
|
} else { usage(); return EXIT_FAILURE; }
|
||||||
|
}
|
||||||
|
if (std::string(argv[i]) == "-s") {
|
||||||
|
if (i + 3 < argc) {
|
||||||
|
i++;
|
||||||
|
sourcePosX = std::stof(argv[i++]);
|
||||||
|
sourcePosY = std::stof(argv[i++]);
|
||||||
|
sourcePosZ = std::stof(argv[i]);
|
||||||
|
continue;
|
||||||
|
} else { usage(); return EXIT_FAILURE; }
|
||||||
|
}
|
||||||
|
if (std::string(argv[i]) == "-d") {
|
||||||
|
if (i + 3 < argc) {
|
||||||
|
i++;
|
||||||
|
detPosX = std::stof(argv[i++]);
|
||||||
|
detPosY = std::stof(argv[i++]);
|
||||||
|
detPosZ = std::stof(argv[i]);
|
||||||
|
continue;
|
||||||
|
} else { usage(); return EXIT_FAILURE; }
|
||||||
|
}
|
||||||
|
if (std::string(argv[i]) == "-D") {
|
||||||
|
if (i + 3 < argc) {
|
||||||
|
i++;
|
||||||
|
detUpX = std::stof(argv[i++]);
|
||||||
|
detUpY = std::stof(argv[i++]);
|
||||||
|
detUpZ = std::stof(argv[i]);
|
||||||
|
continue;
|
||||||
|
} else { usage(); return EXIT_FAILURE; }
|
||||||
|
}
|
||||||
|
if (std::string(argv[i]) == "-R") {
|
||||||
|
if (i + 3 < argc) {
|
||||||
|
i++;
|
||||||
|
angleX = std::stof(argv[i++]);
|
||||||
|
angleY = std::stof(argv[i++]);
|
||||||
|
angleZ = std::stof(argv[i]);
|
||||||
|
continue;
|
||||||
|
} else { usage(); return EXIT_FAILURE; }
|
||||||
|
}
|
||||||
|
if (std::string(argv[i]) == "-show") {
|
||||||
|
showScene=1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (std::string(argv[i]) == "-soft") {
|
||||||
|
softRenderer=1;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (argv[i][0]!='-') {
|
||||||
|
file[parts++]=argv[i];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (softRenderer) setenv("LIBGL_ALWAYS_SOFTWARE","1",1);
|
||||||
|
// Print the libraries' version
|
||||||
|
std::cout << getVersionOfSimpleGVXR() << std::endl;
|
||||||
|
std::cout << getVersionOfCoreGVXR() << std::endl;
|
||||||
|
|
||||||
|
printf("Creating OpenGL Context and Window\n");
|
||||||
|
// Create an OpenGL context
|
||||||
|
// createOpenGLContext(-1,3,2);
|
||||||
|
// createWindow(-1,1,"VULKAN");
|
||||||
|
createWindow();
|
||||||
|
|
||||||
|
printf("Setting OpenGL Context Window size %d x %d \n",glwinsize,glwinsize);
|
||||||
|
setWindowSize(glwinsize, glwinsize);
|
||||||
|
|
||||||
|
// Set the position of the X-ray source
|
||||||
|
printf("Setting source position %f x %f x %f [cm]\n",sourcePosX, sourcePosY, sourcePosZ);
|
||||||
|
setSourcePosition(sourcePosX, sourcePosY, sourcePosZ, "cm");
|
||||||
|
|
||||||
|
// Set the shape of the X-ray source (here an infinitely small point)
|
||||||
|
usePointSource();
|
||||||
|
|
||||||
|
// The spectrum of the X-ray beam
|
||||||
|
// (here a monochromatic spectrum)
|
||||||
|
printf("Setting monochromatic energy %f MeV\n",energy);
|
||||||
|
setMonoChromatic(energy, "MeV", 1000);
|
||||||
|
|
||||||
|
// Set the position of the X-ray detector (film/cassette)
|
||||||
|
printf("Setting detector position %f x %f x %f [cm]\n",detPosX, detPosY, detPosZ);
|
||||||
|
setDetectorPosition(detPosX, detPosY, detPosZ, "cm");
|
||||||
|
|
||||||
|
// Set the orientation of the X-ray detector (film/cassette)
|
||||||
|
printf("Setting detector up vector %f x %f x %f\n",detUpX, detUpY, detUpZ);
|
||||||
|
setDetectorUpVector(detUpX, detUpY, detUpZ);
|
||||||
|
|
||||||
|
// Set the number of pixel of the X-ray detector
|
||||||
|
printf("Setting detector pixels %d x %d [%f mm]\n",width,height,pixelSize);
|
||||||
|
setDetectorNumberOfPixels(width, height);
|
||||||
|
|
||||||
|
// Set the distance between two successive pixels
|
||||||
|
setDetectorPixelSize(pixelSize, pixelSize, "mm");
|
||||||
|
|
||||||
|
printf("Reading polygon mesh files...\n");
|
||||||
|
// Load a polygon mesh from a STL file as a scenegraph
|
||||||
|
// loadSceneGraph(file, "mm");
|
||||||
|
for(int i=0;i<parts;i++) {
|
||||||
|
printf("[%d] %s (%s) <= %f (g/cm3)\n",i,file[i].c_str(),partLabel[i].c_str(),density[i]);
|
||||||
|
loadMeshFile(partLabel[i], file[i], "mm");
|
||||||
|
// moveToCentre(partLabel[i]);
|
||||||
|
setHU(partLabel[i], 1000);
|
||||||
|
setDensity(partLabel[i], density[i], "g/cm3");
|
||||||
|
}
|
||||||
|
// Set the material properties of all the nodes within the scenegraph
|
||||||
|
// for (unsigned int i = 0; i < getNumberOfChildren("root"); ++i)
|
||||||
|
// {
|
||||||
|
// std::string label = getChildLabel("root", i);
|
||||||
|
// printf("Setting material property for %s <= %f (hu)\n",label.c_str(),hu);
|
||||||
|
// moveToCentre(label);
|
||||||
|
// setHU(label, hu);
|
||||||
|
// }
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
loadSceneGraph("second.stl", "mm");
|
||||||
|
|
||||||
|
for (unsigned int i = 0; i < getNumberOfChildren("root"); ++i)
|
||||||
|
{
|
||||||
|
std::string label = getChildLabel("root", i);
|
||||||
|
printf("Setting material property for %s <= %f (hu)\n",label.c_str(),hu);
|
||||||
|
moveToCentre(label);
|
||||||
|
setHU(label, hu);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
if (angleX!=0.0 || angleY!=0 || angleZ!=0) {
|
||||||
|
printf("Rotating scene by %f %f %f\n",angleX,angleY,angleZ);
|
||||||
|
if (angleX!=0.0) rotateScene(angleX, 1.0, 0.0, 0.0);
|
||||||
|
if (angleY!=0.0) rotateScene(angleY, 0.0, 1.0, 0.0);
|
||||||
|
if (angleZ!=0.0) rotateScene(angleZ, 0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (angleCT!=0.0) frames=(int)((float)angleCTRange/angleCT);
|
||||||
|
int autoScale=0;
|
||||||
|
if (scaleMin==0.0 && scaleMax==0.0) autoScale=1;
|
||||||
|
|
||||||
|
for(frameIndex=0;frameIndex<frames;frameIndex++) {
|
||||||
|
char path[1000];
|
||||||
|
snprintf(path, sizeof(path), output.c_str(), frameIndex);
|
||||||
|
std::string pathStr = path;
|
||||||
|
|
||||||
|
printf("[%d] Computing Xray Image ...\n",frameIndex);
|
||||||
|
// Compute an X-ray image(planar projection/radiograph)
|
||||||
|
|
||||||
|
long int start=millitime();
|
||||||
|
computeXRayImage();
|
||||||
|
long int stop=millitime();
|
||||||
|
|
||||||
|
printf("[%d] Computing Xray Image took %d ms...\n",frameIndex,stop-start);
|
||||||
|
|
||||||
|
std::vector<std::vector<float>> image=getLastXRayImage();
|
||||||
|
|
||||||
|
if (noise!=0.0) {
|
||||||
|
// add relative gaussian noise (rough approximation of xray noise)
|
||||||
|
for(int i=0;i<image.size();i++) {
|
||||||
|
for(int j=0;j<image.at(0).size();j++) {
|
||||||
|
float v = image.at(i).at(j),
|
||||||
|
n = normal(generator)*noise,
|
||||||
|
vn = v+abs(v)*n;
|
||||||
|
image.at(i).at(j)=vn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
int iwidth = image.at(0).size(),
|
||||||
|
iheight = image.size();
|
||||||
|
if (autoScale) {
|
||||||
|
// auto-scale
|
||||||
|
scaleMin=scaleMax=image.at(0).at(0);
|
||||||
|
for(int i=0;i<image.size();i++) {
|
||||||
|
for(int j=0;j<image.at(0).size();j++) {
|
||||||
|
float v=image.at(i).at(j);
|
||||||
|
scaleMin=std::min(scaleMin,v);
|
||||||
|
scaleMax=std::max(scaleMax,v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float imin=1E30,imax=-1E30;
|
||||||
|
for(int i=0;i<image.size();i++) {
|
||||||
|
for(int j=0;j<image.at(0).size();j++) {
|
||||||
|
imin=std::min(imin,image.at(i).at(j));
|
||||||
|
imax=std::max(imax,image.at(i).at(j));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
printf("[%d] Xray Image: %d x %d pixels [%f,%f]\n",frameIndex,image.at(0).size(),image.size(),imin,imax);
|
||||||
|
|
||||||
|
if (path[strlen(path)-1]=='f') {
|
||||||
|
saveTIFF(pathStr,image,scaleMin,scaleMax);
|
||||||
|
}
|
||||||
|
if (path[strlen(path)-1]=='m') {
|
||||||
|
savePGM(pathStr,image,scaleMin,scaleMax,scaleRange);
|
||||||
|
}
|
||||||
|
if (angleCT!=0.0) {
|
||||||
|
printf("[%d] Rotating scene by 0 0 %f\n",frameIndex,angleCT);
|
||||||
|
rotateScene(angleCT, 0.0, 0.0, 1.0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// saveLastSinogram();
|
||||||
|
// saveLastProjectionSet();
|
||||||
|
// saveLastLBuffer();
|
||||||
|
}
|
||||||
|
catch (const std::exception& err)
|
||||||
|
{
|
||||||
|
std::cerr << "FATAL ERROR:\t" << err.what() << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (showScene) {
|
||||||
|
displayScene();
|
||||||
|
std::cout << "press any key to exit...";
|
||||||
|
std::cin.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue
Block a user