# Copyright 2007, Linden Research, Inc. # License: GPLv2 with special exceptions # http://secondlife.com/developers/opensource/gplv2 # Index: indra/newview/llfloaterimagepreview.cpp =================================================================== --- indra/newview/llfloaterimagepreview.cpp (revision 62604) +++ indra/newview/llfloaterimagepreview.cpp (working copy) @@ -13,6 +13,7 @@ #include "llimagebmp.h" #include "llimagetga.h" #include "llimagejpeg.h" +#include "llimageobj.h" #include "llagent.h" #include "llbutton.h" @@ -305,6 +306,10 @@ { codec = IMG_CODEC_JPEG; } + else if( 0 == strnicmp(ext, ".obj", 4) ) + { + codec = IMG_CODEC_OBJ; + } LLPointer raw_image = new LLImageRaw; @@ -362,6 +367,21 @@ } } break; + case IMG_CODEC_OBJ: + { + LLPointer obj_image = new LLImageOBJ; + + if (!obj_image->load(src_filename)) + { + return false; + } + + if (!obj_image->decode(raw_image)) + { + return false; + } + } + break; default: return false; } Index: indra/newview/llviewermenu.cpp =================================================================== --- indra/newview/llviewermenu.cpp (revision 62604) +++ indra/newview/llviewermenu.cpp (working copy) @@ -224,7 +224,7 @@ #if LL_WINDOWS static const char* SOUND_EXTENSIONS = ".wav"; -static const char* IMAGE_EXTENSIONS = ".tga .bmp .jpg .jpeg"; +static const char* IMAGE_EXTENSIONS = ".tga .bmp .jpg .jpeg .obj"; static const char* ANIM_EXTENSIONS = ".bvh"; #ifdef _CORY_TESTING static const char* GEOMETRY_EXTENSIONS = ".slg"; Index: indra/newview/llfilepicker.cpp =================================================================== --- indra/newview/llfilepicker.cpp (revision 62604) +++ indra/newview/llfilepicker.cpp (working copy) @@ -29,7 +29,7 @@ #if LL_WINDOWS #define SOUND_FILTER L"Sounds (*.wav)\0*.wav\0" -#define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg)\0*.tga;*.bmp;*.jpg;*.jpeg\0" +#define IMAGE_FILTER L"Images (*.tga; *.bmp; *.jpg; *.jpeg; *.obj)\0*.tga;*.bmp;*.jpg;*.jpeg;*.obj\0" #define ANIM_FILTER L"Animations (*.bvh)\0*.bvh\0" #ifdef _CORY_TESTING #define GEOMETRY_FILTER L"SL Geometry (*.slg)\0*.slg\0" @@ -1149,7 +1149,7 @@ case FFLOAD_ANIM: caption += "Animations (*.bvh)"; break; case FFLOAD_IMAGE: - caption += "Images (*.tga; *.bmp; *.jpg; *.jpeg)"; break; + caption += "Images (*.tga; *.bmp; *.jpg; *.jpeg; *.obj)"; break; default:; break; } Index: indra/llimage/llimageobj.cpp =================================================================== --- indra/llimage/llimageobj.cpp (revision 0) +++ indra/llimage/llimageobj.cpp (revision 0) @@ -0,0 +1,259 @@ +/** + * @file llimagebmp.cpp + * + * Copyright (c) 2007-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#include "linden_common.h" + +#include "llimagebmp.h" +#include "llimageobj.h" +#include "llerror.h" +#include "lldarray.h" +#include "v3math.h" + +#include +#include +#include +#include + +struct LLImageOBJFacePoint +{ + U32 vertex, texture, normal; +}; + +struct LLImageOBJFace +{ + std::vector index; +}; + + +BOOL LLImageOBJ::updateData() +{ + return TRUE; +} + + +static void decodeVertex2RGB( U8* dst, LLVector3 p, LLVector3& min, LLVector3& max) +{ + p -= min; + dst[VX] = (U8)llround( p.mV[VX] / max.mV[VX] * 255.0f ); + dst[VY] = (U8)llround( p.mV[VY] / max.mV[VY] * 255.0f ); + dst[VZ] = (U8)llround( p.mV[VZ] / max.mV[VZ] * 255.0f ); +} + + +BOOL LLImageOBJ::decode(LLImageRaw* raw_image, F32 decode_time) +{ + resetLastError(); + + // Check to make sure that this instance has been initialized with data + U8* mdata = getData(); + if (!mdata || (0 == getDataSize())) + { + setLastError("Uninitialized instance of LLImageOBJ"); + return FALSE; + } + + std::string copy_of_data((char*)mdata, getDataSize()); + std::basic_istringstream istr(copy_of_data); + + std::vector vertices; + std::vector normals; + std::vector textures; // similar to uv map + std::vector faces; // triangular or polygonic indexes to vertices, normals, & textures + + while( istr.good() ) + { + switch( istr.get() ) + { + case '\n': continue; + case 'v': + { + char n = istr.get(); + LLVector3 v; + if( n == ' ' ) + { + istr >> v.mV[VX] >> v.mV[VY] >> v.mV[VZ]; + if(istr.fail()) + { + setLastError("Invalid vertex data in OBJ file"); + return FALSE; + } + vertices.push_back(v); + } + else + if( n == 'n' ) + { + istr >> v.mV[VX] >> v.mV[VY] >> v.mV[VZ]; + if(istr.fail()) + { + setLastError("Invalid vertex normal data in OBJ file"); + return FALSE; + } + normals.push_back(v); + } + else + if( n == 't' ) + { + istr >> v.mV[VX] >> v.mV[VY]; + if(istr.fail()) + { + setLastError("Invalid vertex texture data in OBJ file"); + return FALSE; + } + v.mV[VZ] = 1.0; + textures.push_back(v); + } + break; + } + case 'f': // face indices + { + LLImageOBJFace f; + while( istr.good() ) + { + char c = istr.get(); + if( c == '\r' ) + c = istr.get(); + if( c == '\n' ) + break; + LLImageOBJFacePoint p; + istr >> p.vertex; + if( istr.fail() ) + { + setLastError("Invalid face vertex index data in OBJ file"); + return FALSE; + } + p.texture = 0; + p.normal = 0; + if( istr.get() != '/' ) + { + istr.unget(); + f.index.push_back(p); + continue; + } + c = istr.get(); + if( '0' <= c && c <= '9' ) + { + istr.unget(); + istr >> p.texture; + if( istr.fail() ) + { + setLastError("Invalid face texture index data in OBJ file"); + return FALSE; + } + c = istr.get(); + } + if( c != '/' ) + { + istr.unget(); + f.index.push_back(p); + continue; + } + istr >> p.normal; + if( istr.fail() ) + { + setLastError("Invalid face normal index data in OBJ file"); + return FALSE; + } + f.index.push_back(p); + } + faces.push_back(f); + } + case '#': // # - comment + case 'o': // o - object name + case 'g': // g - group + case 'm': // mtllib - material lib + case 'l': // ll - line + case 'u': // usemtl - use material + default: + { + while( istr.good() && istr.get() != '\n' ); + } + } + } + if( istr.bad() ) + { + setLastError("Unable to read OBJ data"); + return FALSE; + } + + if( 3 > vertices.size() ) + { + setLastError("OBJ file lacks vertex data"); + return FALSE; + } + + // *NOTE: we assume normals exists in the data, but we could generate them + // based on the standard for OBJ files being a model that has all convex faces by default + //if( 0 == normals.size() ) + //{ + // setLastError("OBJ file lacks vertex normal data"); + // return FALSE; + //} + //if( vertices.size() != normals.size() ) + //{ + // setLastError("Unsupported vertex normal topology"); + // return FALSE; + //} + + // *NOTE: We could do arbitrary vertices, but for now we use a + // default method for straight-forward 64x64 covex-face spheric topology conversion + // to retain intended sharpness + // this may be different for more cylindric topology, or those that lack a polar vertex + if( 3970 != vertices.size() ) // 3970 = (64 rows - 1 (overlap)) * (64 cols - 1 (overlap)) + 1 pole ? + { + setLastError("Conversion requires a 64x64 point spheric mesh"); + return FALSE; + } + + raw_image->resize(64, 64, 3); + + // *NOTE: We could, instead, trace the faces and determine if a spheric topology is possible. + // Then, mutate non-convex areas to proportional locations on a new sphere, + // which would create a new uv-index map and avoid subsequent ray-casts for those areas. + // For now, we don't use face data. + + // assume we don't have to perform a model rotation + + // assume we don't have to perform a model diagonal flip + + // determine scale + LLVector3 min, max; + min = max = vertices[0]; + for(U32 i = 1; i < vertices.size(); ++i) + update_min_max(min,max,vertices[i]); + max -= min; + + // use default uv assumption: vertex and texture indices match. + // we could implement an auto-rotate/flip/adjust model to texture alignment. + U8* dst = raw_image->getData(); + for(U32 u = 0; u < 63; ++u) + { + for(U32 v = 0; v < 63; ++v) + { + decodeVertex2RGB( dst, vertices[u*63+v], min, max); + dst += 3; + } + decodeVertex2RGB( dst, vertices[u*63+0], min, max); + dst += 3; + } + for(U32 u = 0, v = 0; v < 63; ++v) + { + decodeVertex2RGB( dst, vertices[u*63+v], min, max); + dst += 3; + } + decodeVertex2RGB( dst, vertices[0*63+63+1], min, max); // ? + + return TRUE; +} + + +BOOL LLImageOBJ::encode(const LLImageRaw* raw_image, F32 encode_time) +{ + resetLastError(); + + setLastError("llimageobj attempted to encode raw image!"); + return FALSE; +} Index: indra/llimage/llimageobj.h =================================================================== --- indra/llimage/llimageobj.h (revision 0) +++ indra/llimage/llimageobj.h (revision 0) @@ -0,0 +1,26 @@ +/** + * @file llimageobj.h + * @brief Image implementation for OBJ. + * + * Copyright (c) 2001-$CurrentYear$, Linden Research, Inc. + * $License$ + */ + +#ifndef LL_LLIMAGEOBJ_H +#define LL_LLIMAGEOBJ_H + +#include "llimage.h" + +// This class blindy converts OBJ files to a sculpt map image for preview & upload + +class LLImageOBJ : public LLImageFormatted +{ +public: + LLImageOBJ() : LLImageFormatted(IMG_CODEC_OBJ) {}; + + /*virtual*/ BOOL updateData(); + /*virtual*/ BOOL decode(LLImageRaw* raw_image, F32 time=0.0); + /*virtual*/ BOOL encode(const LLImageRaw* raw_image, F32 time=0.0); +}; + +#endif Index: indra/llimage/llimage.cpp =================================================================== --- indra/llimage/llimage.cpp (revision 62604) +++ indra/llimage/llimage.cpp (working copy) @@ -27,6 +27,7 @@ #include "llimagejpeg.h" #endif #include "llimagedxt.h" +#include "llimageobj.h" //--------------------------------------------------------------------------- // LLImageBase @@ -1085,7 +1086,8 @@ { "jpg", IMG_CODEC_JPEG }, { "jpeg", IMG_CODEC_JPEG }, { "mip", IMG_CODEC_DXT }, - { "dxt", IMG_CODEC_DXT } + { "dxt", IMG_CODEC_DXT }, + { "obj", IMG_CODEC_OBJ } }; #define NUM_FILE_EXTENSIONS sizeof(file_extensions)/sizeof(file_extensions[0]) @@ -1185,6 +1187,9 @@ case IMG_CODEC_DXT: image = new LLImageDXT(); break; + case IMG_CODEC_OBJ: + image = new LLImageOBJ(); + break; default: return false; } @@ -1273,6 +1278,9 @@ case IMG_CODEC_DXT: image = new LLImageDXT(); break; + case IMG_CODEC_OBJ: + image = new LLImageOBJ(); + break; default: image = NULL; break; Index: indra/llimage/llimage.h =================================================================== --- indra/llimage/llimage.h (revision 62604) +++ indra/llimage/llimage.h (working copy) @@ -47,7 +47,8 @@ IMG_CODEC_TGA = 4, IMG_CODEC_JPEG = 5, IMG_CODEC_DXT = 6, - IMG_CODEC_EOF = 7 + IMG_CODEC_OBJ = 7, + IMG_CODEC_EOF = 8 }; //============================================================================ Index: indra/llimage/files.lst =================================================================== --- indra/llimage/files.lst (revision 62604) +++ indra/llimage/files.lst (working copy) @@ -3,5 +3,6 @@ llimage/llimagedxt.cpp llimage/llimagej2c.cpp llimage/llimagejpeg.cpp +llimage/llimageobj.cpp llimage/llimagetga.cpp llimage/llimageworker.cpp