00001 #include "global.h"
00002 #include "MercuryTexture.h"
00003 #include "MercuryLog.h"
00004 #include "MercuryFiles.h"
00005 #include "MercuryLog.h"
00006 #include "MercuryMath.h"
00007 #include "MercuryDisplay.h"
00008
00009
00010 #if defined(WIN32)
00011 # include <png.h>
00012 # if defined(_MSC_VER)
00013 # pragma comment(lib, "libpng.lib")
00014 # endif
00015 # pragma warning(disable: 4611)
00016 #else
00017 # include <png.h>
00018 #endif
00019
00020
00021
00022
00023
00024 #define MC_TEXTUREID 1
00025
00026 int ColorBytesToSize(ColorBytes cb)
00027 {
00028 switch (cb)
00029 {
00030 case LUMINANCE_ALPHA:
00031 return 2;
00032 case RGB:
00033 return 3;
00034 case DEPTH_COMPONENT24:
00035 return 3;
00036 case RGBA:
00037 return 4;
00038 case RGBA_FLOAT:
00039 return 16;
00040 default:
00041 ASSERT(!"Invalid Color Byte")
00042 };
00043 return 0;
00044 }
00045
00046 MercuryTexture::MercuryTexture()
00047 :MercuryObject()
00048 {
00049 Init();
00050 }
00051
00052 MercuryTexture::MercuryTexture(const MercuryTexture& texture)
00053 :MercuryObject()
00054 {
00055 Init();
00056 *this = texture;
00057 }
00058
00059 MercuryTexture::~MercuryTexture()
00060 {
00061 SendRemoveMessage();
00062 }
00063
00064 void MercuryTexture::Message( int Message, PStack & data, const MString & name )
00065 {
00066 switch ( Message )
00067 {
00068 case MC_TEXTUREID:
00069 {
00070 const MercuryTexture* t = (const MercuryTexture*)data.PeekItem(0).GetValueV();
00071 const ImageAttrs* imageAttrs = (const ImageAttrs*)data.PeekItem(1).GetValueV();
00072 if(this == t)
00073 {
00074 m_imageAttrs = *imageAttrs;
00075 SetMatrixTainted(true);
00076 MercuryMessageHandler::UnregisterMessage( MC_TEXTUREID, "GetTextureID" );
00077 m_state = LOADED;
00078 }
00079 }
00080 break;
00081 }
00082 }
00083
00084 void MercuryTexture::AutoDestroy()
00085 {
00086 SendRemoveMessage();
00087 if (GetID() > 0)
00088 m_imageAttrs.m_ID = 0;
00089 }
00090
00091 void MercuryTexture::SendRemoveMessage()
00092 {
00093 PStack stack;
00094 stack.PushItemBack(PSElement(GetPath()));
00095 stack.PushItemBack(PSElement((void*)this));
00096 MESSAGEMAN->PostSystemMessage("UnregisterTexture", stack, 0);
00097 m_state = UNLOADED;
00098 }
00099
00100 void MercuryTexture::SendLoadMessage()
00101 {
00102 PStack stack;
00103 stack.PushItemBack(PSElement(GetPath()));
00104 stack.PushItemBack(PSElement((void*)this));
00105 MercuryMessageHandler::RegisterMessage( MC_TEXTUREID, "GetTextureID" );
00106 MESSAGEMAN->PostSystemMessage("LoadTexture", stack, 0);
00107 m_state = UNLOADED;
00108 }
00109
00110 void MercuryTexture::SendLoadFromRaw(RawImageData* data)
00111 {
00112 PStack stack;
00113 stack.PushItemBack(PSElement(GetPath()));
00114 stack.PushItemBack(PSElement((void*)this));
00115 stack.PushItemBack(PSElement((void*)data));
00116 MercuryMessageHandler::RegisterMessage( MC_TEXTUREID, "GetTextureID" );
00117 MESSAGEMAN->PostSystemMessage("LoadTextureRaw", stack, 0);
00118 m_state = UNLOADED;
00119 }
00120
00121 void MercuryTexture::operator=(const MercuryTexture& texture)
00122 {
00123 if (!texture.m_path.empty())
00124 {
00125
00126 if (GetID() > 0)
00127 SendRemoveMessage();
00128
00129 m_attrs = texture.m_attrs;
00130 m_imageAttrs = texture.m_imageAttrs;
00131
00132
00133 SendLoadMessage();
00134 }
00135 }
00136
00137 void RawImageData::CorrectSize()
00138 {
00139 attrs.m_width_original = attrs.m_width;
00140 attrs.m_height_original = attrs.m_height;
00141
00142
00143 if (attrs.m_cube)
00144 {
00145 printf ("*******CorrectSize:\npdata = %lu\nwidth = %lu\nheight = %lu\ncolorbytes = %lu\nCorrectSize\n", data, attrs.m_width, attrs.m_height, (unsigned int)(ColorBytesToSize(attrs.m_ColorByteType)));
00146 return;
00147 }
00148
00149 attrs.m_height = makePow2(attrs.m_height);
00150 attrs.m_width = makePow2(attrs.m_width);
00151
00152 attrs.m_resizeFactor.SetX( (float)attrs.m_width_original / attrs.m_width );
00153 attrs.m_resizeFactor.SetY( (float)attrs.m_height_original / attrs.m_height );
00154
00155 unsigned char* resized;
00156 int chunk = attrs.m_width_original * ColorBytesToSize(attrs.m_ColorByteType);
00157 int newchunk = attrs.m_width * ColorBytesToSize(attrs.m_ColorByteType);
00158 int newsize = attrs.m_height * attrs.m_width * ColorBytesToSize(attrs.m_ColorByteType);
00159
00160 if ((attrs.m_height_original != attrs.m_height) || (attrs.m_width_original != attrs.m_width))
00161 {
00162 resized = new unsigned char[newsize];
00163
00164 memset(resized, 0, newsize);
00165 for (unsigned int i = 0; i < (unsigned)attrs.m_height_original; i++)
00166 {
00167 memcpy(&resized[i * newchunk], &data[i * chunk], chunk);
00168 }
00169 SAFE_DELETE(data);
00170 data = new unsigned char[newsize];
00171 memcpy(data, resized, newsize);
00172 SAFE_DELETE(resized);
00173 }
00174 }
00175
00176 void RawImageData::ToRGBA()
00177 {
00178 if (data == NULL)
00179 {
00180 LOG.Warn("Texture data null, not converting to RGBA.");
00181 return;
00182 }
00183
00184 const unsigned int size = attrs.m_width*attrs.m_height*ColorBytesToSize(RGBA);
00185 unsigned char* tmpdata = new unsigned char[size];
00186 switch(attrs.m_ColorByteType)
00187 {
00188 case RGB:
00189 {
00190
00191 unsigned int opos = 0;
00192 for (unsigned int i = 0; i < size; i++)
00193 {
00194 if(((i+1)%4) == 0)
00195 {
00196 tmpdata[i] = 255;
00197 }
00198 else
00199 {
00200 tmpdata[i] = data[opos++];
00201 }
00202 }
00203 SAFE_DELETE(data);
00204 attrs.m_ColorByteType = RGBA;
00205 data = new unsigned char[size];
00206 memcpy(data, tmpdata, size);
00207 }
00208 break;
00209 default:
00210 break;
00211 }
00212 SAFE_DELETE(tmpdata);
00213 }
00214
00215 void MercuryTexture::CalculateMatrices()
00216 {
00217 if ( IsMatrixTainted() )
00218 {
00219 m_localMatrix.Identity();
00220
00221 MercuryPoint scale = GetScale()*m_imageAttrs.m_resizeFactor;
00222 const MercuryPoint& position = GetPosition();
00223 const MercuryPoint& rotation = GetRot();
00224
00225 if( GetRotMode() == RM_NORMAL )
00226 {
00227 m_localMatrix.Transotale( position.x, position.y, position.z,
00228 rotation.x, rotation.y, rotation.z,
00229 scale.x, scale.y, scale.z );
00230 SetMatrixTainted(false);
00231 }
00232 else
00233 {
00234
00235 m_localMatrix.Translate(position.x, position.y, position.z);
00236
00237 switch ( GetRotMode() )
00238 {
00239 case RM_OFF:
00240 break;
00241 case RM_BILLBOARD:
00242 {
00243 static const MercuryPoint look(0,0,1);
00244 static MercuryPoint directionProj;
00245 static float angle;
00246 static MercuryPoint axis;
00247 static MercuryMatrix world;
00248
00249
00250 directionProj = GetGlobalPosition() - DISPLAY->GetLastCameraPosition();
00251 directionProj.NormalizeSelf();
00252
00253 axis = look.CrossProduct(directionProj);
00254 angle = ACOS(DotProduct(look, directionProj));
00255
00256
00257 world.RotateAngAxis(angle*RADDEG, axis.x, axis.y, axis.z);
00258
00259 m_localMatrix *= world;
00260 }
00261 break;
00262 case RM_MATRIX:
00263 m_localMatrix *= GetAfterMatrix();
00264 break;
00265 case RM_QUATERNION:
00266 {
00267 MercuryMatrix m;
00268 GetRotationQuaternion().toMatrix4(m);
00269 m_localMatrix *= m;
00270 }
00271 break;
00272 default:
00273 break;
00274 };
00275
00276 m_localMatrix.Scale(scale.x, scale.y, scale.z);
00277 SetMatrixTainted(false);
00278 }
00279 }
00280
00281 m_finalMatrix = TextureStack.GetTop() *= m_localMatrix;
00282 }
00283
00284 void MercuryTexture::Prerender()
00285 {
00286 TextureStack.Push();
00287 CalculateMatrices();
00288 TextureStack.Pop();
00289 }
00290
00291
00292 void CaclulateDiv2Texture( const RawImageData & riIn, RawImageData & riOut )
00293 {
00294 riOut.attrs.m_ColorByteType = riIn.attrs.m_ColorByteType;
00295 unsigned cbsize = ColorBytesToSize( riIn.attrs.m_ColorByteType );
00296
00297 if( riIn.attrs.m_height != 1 && riIn.attrs.m_width != 1 )
00298 {
00299 unsigned oHeight = riOut.attrs.m_height = riIn.attrs.m_height / 2;
00300 unsigned oWidth = riOut.attrs.m_width = riIn.attrs.m_width / 2;
00301 riOut.data = new unsigned char[riOut.attrs.m_width * riOut.attrs.m_height * cbsize];
00302
00303 for( unsigned y = 0; y < riOut.attrs.m_height; ++y )
00304 for( unsigned x = 0; x < riOut.attrs.m_width; ++x )
00305 for( unsigned b = 0; b < cbsize; ++b )
00306 {
00307 riOut.data[(x+y*oWidth)*cbsize + b] = (
00308 (unsigned)riIn.data[((x*2+y*2*riIn.attrs.m_width))*cbsize + b] +
00309 (unsigned)riIn.data[((x*2)+1+y*2*riIn.attrs.m_width)*cbsize + b] +
00310 (unsigned)riIn.data[(x*2+(y*2+1)*riIn.attrs.m_width)*cbsize + b] +
00311 (unsigned)riIn.data[((x*2)+1+(y*2+1)*riIn.attrs.m_width)*cbsize + b] ) / 4;
00312 }
00313 } else if( riIn.attrs.m_height != 1 )
00314 {
00315 unsigned oHeight = riOut.attrs.m_height = riIn.attrs.m_height / 2;
00316 unsigned oWidth = riOut.attrs.m_width = riIn.attrs.m_width;
00317 riOut.data = new unsigned char[riOut.attrs.m_width * riOut.attrs.m_height * cbsize];
00318
00319 for( unsigned y = 0; y < riOut.attrs.m_height; ++y )
00320 for( unsigned x = 0; x < riOut.attrs.m_width; ++x )
00321 for( unsigned b = 0; b < cbsize; ++b )
00322 {
00323 riOut.data[(x+y*oWidth)*cbsize + b] = (
00324 (unsigned)riIn.data[(x*2+y*2*riIn.attrs.m_width)*cbsize + b] +
00325 (unsigned)riIn.data[(x*2+(y+1)*2*riIn.attrs.m_width)*cbsize + b] ) / 2;
00326 }
00327 } else if( riIn.attrs.m_width != 1 )
00328 {
00329 unsigned oHeight = riOut.attrs.m_height = riIn.attrs.m_height;
00330 unsigned oWidth = riOut.attrs.m_width = riIn.attrs.m_width / 2;
00331 riOut.data = new unsigned char[riOut.attrs.m_width * riOut.attrs.m_height * cbsize];
00332
00333 for( unsigned y = 0; y < riOut.attrs.m_height; ++y )
00334 for( unsigned x = 0; x < riOut.attrs.m_width; ++x )
00335 for( unsigned b = 0; b < cbsize; ++b )
00336 {
00337 riOut.data[(x+y*oWidth)*cbsize + b] = (
00338 (unsigned)riIn.data[(x*2+y*2*riIn.attrs.m_width)*cbsize + b] +
00339 (unsigned)riIn.data[((x+1)*2+y*2*riIn.attrs.m_width)*cbsize + b] ) / 2;
00340 }
00341 }
00342 }
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362
00363
00364
00365
00366
00367