00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "triloader.h"
00024 #include "common/misc/progressmonitor.h"
00025 #include "common/misc/stringutils.h"
00026 #include "common/misc/types.h"
00027
00028 #include <cctype>
00029 #include <IL/il.h>
00030
00031
00032
00033 #ifdef VERBOSE
00034 #include <iostream>
00035 #endif // VERBOSE
00036
00037 using namespace sheep;
00038 using namespace std;
00039
00040 TRILoader::TRILoader() {}
00041
00042 void TRILoader::Load(const string &filename,
00043 IMeshBuilder &builder,
00044 int option_mask ,
00045 ProgressMonitor *progmon )
00046 {
00047 m_path = StringUtils::GetPath(filename);
00048 m_texture_filename =
00049 StringUtils::RemoveExtension(StringUtils::GetFilename(filename)) + ".png";
00050
00051 m_geombuilder = builder.GeometryBuilder();
00052 m_matbuilder = builder.MaterialBuilder();
00053
00054 m_option_mask = option_mask;
00055
00056 m_progmon = progmon;
00057
00058 m_comment_ptr = 0;
00059
00060 open_geometry_file(filename);
00061 open_texture_file(m_texture_filename);
00062
00063 if(m_progmon) {
00064 m_stream.Seek(0, BinaryStream::SeekFromEnd);
00065 m_progmon->StartJob(0, m_stream.Tell());
00066 m_stream.Seek(0, BinaryStream::SeekFromBeginning);
00067 }
00068
00069 read_geometry_file();
00070
00071 if(m_progmon)
00072 m_progmon->Done();
00073
00074 close_texture_file();
00075 close_geometry_file();
00076 }
00077
00078 void TRILoader::read_error() {
00079
00080 throw ReadingException(m_offset);
00081 }
00082
00083 void TRILoader::open_geometry_file(const string &filename) {
00084 m_stream.Open(filename, BinaryStream::InputStream);
00085
00086 if(!m_stream.IsOpen())
00087 throw FileNotFoundException(filename);
00088
00089 m_offset = 0;
00090 }
00091
00092 void TRILoader::read_geometry_file() {
00093
00094
00095 char endian[2];
00096
00097 m_stream.Read(&endian[0]);
00098 m_stream.Read(&endian[1]);
00099
00100 if(!((endian[0] == 'B' || endian[0] == 'L') && endian[1] == 'E'))
00101 read_error();
00102
00103 if(endian[0] == 'B')
00104 m_stream.SetEndianness(BinaryStream::BigEndian);
00105 else m_stream.SetEndianness(BinaryStream::LittleEndian);
00106
00107
00108 int32 nvertices;
00109 m_stream.Read(&nvertices);
00110
00111
00112 int32 nfaces;
00113 m_stream.Read(&nfaces);
00114
00115
00116 for(int i = 0; i < 4; ++i) {
00117 char dummy;
00118 m_stream.Read(&dummy);
00119 }
00120
00121 m_geombuilder->BeginSubMesh("");
00122
00123
00124 for(int i = 0; i < nvertices; ++i) {
00125 float32 x, y, z;
00126 m_stream.Read(&x);
00127 m_stream.Read(&y);
00128 m_stream.Read(&z);
00129
00130 m_vertex_id[i] = m_geombuilder->AppendVertex(Vector3(x, y, z));
00131
00132 if(m_progmon) {
00133
00134 if((i & 4095) == 0)
00135 m_progmon->SetJobProgress(m_stream.Tell());
00136 }
00137 }
00138
00139
00140 for(int i = 0; i < nfaces; ++i) {
00141 uint32 v0, v1, v2;
00142 m_stream.Read(&v0);
00143 m_stream.Read(&v1);
00144 m_stream.Read(&v2);
00145
00146 IMeshBuilder::FeatureId vertex_id[3];
00147 vertex_id[0] = m_vertex_id[v0];
00148 vertex_id[1] = m_vertex_id[v1];
00149 vertex_id[2] = m_vertex_id[v2];
00150
00151 const IMeshBuilder::FeatureId face_id = m_geombuilder->AppendFace(3, vertex_id);
00152
00153 if(m_comment_ptr) {
00154 IMeshBuilder::FeatureId texcood_id[3];
00155
00156 for(int i = 0; i < 3; ++i) {
00157 const int u = strtol(m_comment_ptr, &m_comment_ptr, 10);
00158 const int v = strtol(m_comment_ptr, &m_comment_ptr, 10);
00159
00160 Vector2 vt;
00161 vt.m_x = (static_cast<Real>(u) + 0.5) / m_texture_width;
00162 vt.m_y = (static_cast<Real>(v) + 0.5) / m_texture_height;
00163
00164 texcood_id[i] = m_geombuilder->AppendTexCoord(vt);
00165 }
00166
00167 m_geombuilder->SetFaceTexCoords(face_id, 3, texcood_id);
00168 }
00169
00170 if(m_progmon) {
00171
00172 if((i & 4095) == 0)
00173 m_progmon->SetJobProgress(m_stream.Tell());
00174 }
00175 }
00176
00177 if(m_matbuilder && m_comment_ptr) {
00178 ILuint image_id;
00179
00180 ilGenImages(1, &image_id);
00181 ilBindImage(image_id);
00182
00183 if(TryLoadingImage(m_path, m_texture_filename)) {
00184 const int w = ilGetInteger(IL_IMAGE_WIDTH);
00185 const int h = ilGetInteger(IL_IMAGE_HEIGHT);
00186
00187 unsigned char *texels = new unsigned char[w * h * 3];
00188
00189 ilCopyPixels(0, 0, 0, w, h, 1, IL_RGB, IL_UNSIGNED_BYTE, texels);
00190 ilDeleteImages(1, &image_id);
00191
00192 assert(m_matbuilder);
00193
00194 const IMeshBuilder::FeatureId material_id = m_matbuilder->BeginMaterial("");
00195 m_matbuilder->SetTexture(w, h, texels);
00196 m_matbuilder->EndMaterial();
00197
00198 m_geombuilder->SetMaterial(material_id);
00199 } else {
00200
00201
00202
00203
00204 if(m_option_mask & STOP_ON_MISSING_FILE_BIT)
00205 throw FileNotFoundException(m_texture_filename);
00206
00207
00208 }
00209 }
00210
00211 m_geombuilder->EndSubMesh();
00212 }
00213
00214 void TRILoader::close_geometry_file() {
00215 m_stream.Close();
00216 }
00217
00218 void TRILoader::open_texture_file(const string &filename) {
00219 const int PNG_BYTES_TO_CHECK = 8;
00220 png_byte header[PNG_BYTES_TO_CHECK];
00221
00222 FILE *f = TryOpeningFile(m_path, filename, "rb");
00223
00224 if(!f) {
00225 if(m_option_mask & STOP_ON_MISSING_FILE_BIT) {
00226
00227 throw FileNotFoundException(filename);
00228 } else return;
00229 }
00230
00231 if(fread(header, 1, PNG_BYTES_TO_CHECK, f) < PNG_BYTES_TO_CHECK)
00232 read_error();
00233
00234 if(png_sig_cmp(header, 0, PNG_BYTES_TO_CHECK))
00235 read_error();
00236
00237 m_png_ptr = png_create_read_struct(
00238 PNG_LIBPNG_VER_STRING,
00239 NULL,
00240 NULL,
00241 NULL);
00242
00243 if(!m_png_ptr) {
00244 fclose(f);
00245 read_error();
00246 }
00247
00248 m_info_ptr = png_create_info_struct(m_png_ptr);
00249
00250 if(!m_info_ptr) {
00251 png_destroy_read_struct(
00252 &m_png_ptr,
00253 NULL,
00254 NULL);
00255 fclose(f);
00256 read_error();
00257 }
00258
00259 m_end_info = png_create_info_struct(m_png_ptr);
00260
00261 if(!m_end_info) {
00262 png_destroy_read_struct(
00263 &m_png_ptr,
00264 &m_info_ptr,
00265 NULL);
00266 fclose(f);
00267 read_error();
00268 }
00269
00270 png_init_io(m_png_ptr, f);
00271 png_set_sig_bytes(m_png_ptr, PNG_BYTES_TO_CHECK);
00272 png_read_info(m_png_ptr, m_info_ptr);
00273
00274 fclose(f);
00275
00276 m_texture_width = png_get_image_width(m_png_ptr, m_info_ptr);
00277 m_texture_height = png_get_image_height(m_png_ptr, m_info_ptr);
00278
00279 png_textp text_ptr;
00280 int ncomments;
00281
00282 png_get_text(m_png_ptr, m_info_ptr, &text_ptr, &ncomments);
00283
00284 if(ncomments < 1) {
00285 png_destroy_read_struct(
00286 &m_png_ptr,
00287 &m_info_ptr,
00288 &m_end_info);
00289 read_error();
00290 }
00291
00292 if(strcmp(text_ptr[0].key, "uv") != 0) {
00293 png_destroy_read_struct(
00294 &m_png_ptr,
00295 &m_info_ptr,
00296 &m_end_info);
00297 read_error();
00298 }
00299
00300 m_comment_ptr = text_ptr[0].text;
00301 assert(m_comment_ptr);
00302 }
00303
00304 void TRILoader::close_texture_file() {
00305 if(m_comment_ptr) {
00306 png_destroy_read_struct(
00307 &m_png_ptr,
00308 &m_info_ptr,
00309 &m_end_info);
00310 m_comment_ptr = 0;
00311 }
00312 }