从前面已经看到可以从服务器下载纹理图片,那么下载这些纹理图片,又是什么样的格式呢?在第二人生里,主要有三种格式:JPEG2000、TGA、RAW。虽然对应只有三种格式,但OpenGL里只能使用RAW的格式作为纹理,而JPEG2000和TGA并不能直接作纹理数据使用,因而就需要对这两种格式进行转换和管理。下面就来了解这方面的内容,看看第二人生里是怎么样把JPEG2000和TGA转换为可以使用的纹理格式的。
纹理图片的格式类的继承关系如下:
class LLThreadSafeRefCount
class LLImageBase : public LLThreadSafeRefCount
class LLImageFormatted : public LLImageBase
class LLImageJ2C : public LLImageFormatted
class LLImageTGA : public LLImageFormatted
从上面的继承关系,可以看到LLThreadSafeRefCount类是基类,主要用来作接口的引用计数。现在就先从这个类开始分析,再一个一个派生类进行具体的分析。
LLThreadSafeRefCount类的代码如下:
#001 class LLThreadSafeRefCount
#002 {
#003 public:
创建线程互斥对象。
#004
static void initClass(); // creates sMutex
#005
static void cleanupClass(); // destroys sMutex
#006
#007 private:
保存线程互斥对象。
#008
static LLMutex* sMutex;
#009
下面声明这个类不能实现类拷贝。
#010 private:
#011
LLThreadSafeRefCount(const LLThreadSafeRefCount&); // not implemented
#012
LLThreadSafeRefCount&operator=(const LLThreadSafeRefCount&); // not implemented
#013
#014 protected:
#015
virtual ~LLThreadSafeRefCount(); // use unref()
#016
#017 public:
#018
LLThreadSafeRefCount();
#019
下面是增加这个接口的引用计数。
#020
void ref()
#021
{
#022
if (sMutex) sMutex->lock();
#023
mRef++;
#024
if (sMutex) sMutex->unlock();
#025
}
#026
下面是减少这个接口的引用计数,当引用计数为0时,就删除这个整个类对象,达到释放内存的目的,这跟COM的引用计数是一样的。
#027
S32 unref()
#028
{
#029
llassert(mRef >= 1);
#030
if (sMutex) sMutex->lock();
#031
S32 res = --mRef;
#032
if (sMutex) sMutex->unlock();
#033
if (0 == res)
#034
{
#035
delete this;
#036
return 0;
#037
}
#038
return res;
#039
}
这里是获取引用计数,一般用来判断是否可以在容器里删除类对象。
#040
S32 getNumRefs() const
#041
{
#042
return mRef;
#043
}
#044
#045 private:
#046
S32 mRef;
#047 };
LLThreadSafeRefCount类是跟COM调用的对象引用计数是一样的,都是实现对象生命周期的管理,这种方法在C++是最常用、最简单的管理方法。如果在C++里不使用这种方法管理,在多线程里动态地共享对象就会有问题。比如A线程创建了一个对象OBJ,把这个对象OBJ传送给B线程和C线程,B线程和C线程谁最后做完工作就把对象OBJ删除,由于B线程和C线程之间不会有同步关系,谁最后做完工作是没有确定的,因此删除对象OBJ也是不确定的,如果采用引用计数,就解决这个问题,不用关心谁最后做完工作,这就是引用计数的方便之处。