00001 #include "Util.h"
00002 #include "Message.h"
00003 #include <QDir>
00004 #include <math.h>
00005
00006 namespace apig {
00007
00008
00009
00010
00011 template<class Color>
00012 Image3D<Color>::Image3D(int w, int h, int d, Color* inputData) : AbstractImage3D(w, h, d), data(inputData), wrapMode(CLAMP_TO_EDGE) {
00013 if (w <= 0 || h <= 0 || d <= 0) {
00014 w = h = d = 0;
00015 data = NULL;
00016 }
00017 else if (inputData == NULL) {
00018 data = new Color[w * h * d];
00019 if (data == NULL) {
00020 Message::error("l'allocation memoire pour l'image a echoué");
00021 w = h = d = 0;
00022 }
00023 }
00024 }
00025
00026 template<class Color>
00027 void Image3D<Color>::destroy() {
00028 if (data != NULL) delete[] data;
00029 data = NULL;
00030 w = h = d = 0;
00031 }
00032
00033 template<class Color>
00034 Image3D<Color> Image3D<Color>::clone() const {
00035 if (data == NULL) return Image3D<Color>();
00036 Color *clonedData = new Color[w * h * d];
00037 if (clonedData == NULL) {
00038 Message::error("l'allocation memoire pour l'image a echoué");
00039 return Image3D<Color>();
00040 }
00041 for (int c=0; c<w*h*d; c++)
00042 clonedData[c] = data[c];
00043 return Image3D<Color>(w, h, d, clonedData);
00044 }
00045
00046 template<class Color>
00047 void Image3D<Color>::setBorderColor(Color c) {
00048 borderColor = c;
00049 }
00050
00051 template<class Color>
00052 void Image3D<Color>::setWrapMode(WrapMode mode) {
00053 wrapMode = mode;
00054 }
00055
00056 template<class Color>
00057 void Image3D<Color>::setupBorder(WrapMode mode, Color c) {
00058 wrapMode = mode;
00059 borderColor = c;
00060 }
00061
00062 template<class Color>
00063 Color Image3D<Color>::sample(int i, int j, int k) const {
00064 switch (wrapMode) {
00065 case CLAMP_TO_BORDER : return contains(i, j, k) ? texel(i,j,k) : borderColor;
00066 case REPEAT : return texel(util::modulo(i, w), util::modulo(j, h), util::modulo(k, d));
00067 case MIRRORED_REPEAT : return texel(util::mirror(i,w), util::mirror(j,h), util::mirror(k,d));
00068 case CLAMP_TO_EDGE :
00069 default : return texel(util::clamp(i, 0, w-1), util::clamp(j, 0, h-1), util::clamp(k, 0, d-1));
00070 };
00071 }
00072
00073 template<class Color>
00074 Color Image3D<Color>::interp(float x, float y, float z) const {
00075 int i0 = (int)(floorf(x - 0.5)),
00076 j0 = (int)(floorf(y - 0.5)),
00077 k0 = (int)(floorf(z - 0.5));
00078 float a = x - 0.5 - i0,
00079 b = y - 0.5 - j0,
00080 c = z - 0.5 - k0;
00081 return (1-a) * (1-b) * (1-c) * sample(i0, j0 , k0 ) + a * (1-b) * (1-c) * sample(i0+1, j0 , k0 )
00082 + (1-a) * (1-b) * c * sample(i0, j0 , k0+1) + a * (1-b) * c * sample(i0+1, j0 , k0+1)
00083 + (1-a) * b * (1-c) * sample(i0, j0+1, k0 ) + a * b * (1-c) * sample(i0+1, j0+1, k0 )
00084 + (1-a) * b * c * sample(i0, j0+1, k0+1) + a * b * c * sample(i0+1, j0+1, k0+1);
00085 }
00086
00087
00088
00089
00090 template<class Color>
00091 void Image3D<Color>::loadTexture3D(GLint texFormat, GLenum target) const {
00092 glTexImage3D(target, 0, texFormat, w, h, d, 0, Color::DATA_FORMAT, Color::DATA_TYPE, data);
00093 }
00094
00095 template<class Color>
00096 Image3D<Color> Image3D<Color>::readTexture(Texture *tex) {
00097 int w = tex->getWidth(),
00098 h = tex->getHeight(),
00099 d = tex->getDepth();
00100 Image3D<Color> res(w, h, d, NULL);
00101 if (w < 0 || h < 0 || d < 0)
00102 Message::error("dimensions de la texture non definies");
00103 else {
00104 tex->bind();
00105 glGetTexImage(GL_TEXTURE_3D, 0, Color::DATA_FORMAT, Color::DATA_TYPE, res.data);
00106 }
00107 return res;
00108 }
00109
00110
00111
00112
00113 template<class Color>
00114 Image3D<Color>::Image3D(QString fileName) : AbstractImage3D(0,0,0), data(NULL), wrapMode(CLAMP_TO_EDGE) {
00115 QDir dir(fileName);
00116 if (!dir.exists()) {
00117 Message::error(QString("le sous-répertoire '%1' n'existe pas").arg(fileName));
00118 return;
00119 }
00120 dir.setNameFilters(QStringList("*.png"));
00121 QStringList fileNamesList = dir.entryList(QDir::Files, QDir::Name);
00122
00123 d = fileNamesList.size();
00124 if (d == 0) {
00125 Message::error(QString("aucun fichier image dans le répertoire '%1'").arg(fileName));
00126 return;
00127 }
00128
00129 QImage slice0(dir.filePath(fileNamesList[0]));
00130 w = slice0.width();
00131 h = slice0.height();
00132 data = new Color[w * h * d];
00133 if (data == NULL) {
00134 Message::error("memoire insuffisante pour charger l'image 3D en memoire");
00135 w = h = d = 0;
00136 return;
00137 }
00138
00139 for (int k=0; k<d; k++) {
00140 QImage slice(dir.filePath(fileNamesList[k]));
00141
00142 if (slice.width() != w || slice.height() != h) {
00143 Message::error("les slices d'une image 3D doivent avoir toutes la même taille");
00144 destroy();
00145 return;
00146 }
00147
00148 for (int i=0; i<w; i++) for (int j=0; j<h; j++)
00149 texel(i,j,k) = Color(slice.pixel(i, h-1-j));
00150 }
00151 }
00152
00153 template<class Color>
00154 void Image3D<Color>::save(QString dirName, QString subDirName) const {
00155 if (!loaded()) {
00156 Message::error("l'image ne contient pas de donnees");
00157 return;
00158 }
00159
00160 QDir dir(dirName);
00161 if (!dir.exists()) {
00162 Message::error(QString("le répertoire '%1' n'existe pas").arg(dirName));
00163 return;
00164 }
00165
00166 if (dir.exists(subDirName)) {
00167
00168 QDir subDir = dir;
00169 subDir.cd(subDirName);
00170 QStringList files = subDir.entryList(QDir::Files | QDir::NoSymLinks);
00171 foreach (QString file, files) subDir.remove(file);
00172 }
00173 else if (!dir.mkdir(subDirName)) {
00174 Message::error(QString("impossible de creer le repertoire '%1'").arg(subDirName));
00175 return;
00176 }
00177
00178 QString absDirName = util::filePath(dirName, subDirName);
00179
00180 for (int k=0; k<d; k++) {
00181 QImage slice(w, h, QImage::Format_ARGB32);
00182 for (int i=0; i<w; i++) for (int j=0; j<h; j++)
00183 slice.setPixel(i, h-1-j, texel(i,j,k).toQRgb());
00184 QString fileName = util::filePath(subDirName, QString("slice%1.png").arg(k, 3, 10, QLatin1Char('0')));
00185 if (!image.save(fileName, "PNG"))
00186 Message::error(QString("probleme lors de la sauvegarde du fichier '%1'").arg(fileName));
00187 }
00188 }
00189
00190 }
00191