/* ************************ Copyright Terrain Experts Inc. Terrain Experts Inc (TERREX) reserves all rights to this source code unless otherwise specified in writing by the President of TERREX. This copyright may be updated in the future, in which case that version supercedes this one. ------------------- Terrex Experts Inc. 4400 East Broadway #314 Tucson, AZ 85711 info@terrex.com Tel: (520) 323-7990 ************************ */ #include #include #include /* trpage_material.cpp This source file contains the methods for trpgMatTable, trpgTextureEnv, trpgMaterial, and trpgTexTable. You should only modify this code if you want to add data to these classes. */ #include #include #ifdef _MSC_VER #define strcasecmp _stricmp #endif /* Write Material Table class Keeps track of the materials that have been added. */ // Constructor trpgMatTable::trpgMatTable() { numTable = numMat = 0; } trpgMatTable::~trpgMatTable() { } // Reset function void trpgMatTable::Reset() { numTable = 0; numMat = 0; materialMap.clear(); } // Validity check bool trpgMatTable::isValid() const { if(materialMap.size()==0) return false; // get an iterator for the materialMap MaterialMapType::const_iterator itr = materialMap.begin(); for ( ; itr != materialMap.end( ); itr++) { if(!(*itr).second.isValid()) { return false; } } return true; } // Set functions void trpgMatTable::SetNumTable(int no) { if ((no < 0) || (no==numTable)) return; numTable = no; } void trpgMatTable::SetNumMaterial(int /*no*/) { // This method is obsolete since we're using the project handle // and a map to store the materials, instead of a vector } void trpgMatTable::SetMaterial(int nm,const trpgMaterial &mat) { materialMap[nm] = mat; numMat = materialMap.size(); } #define CEQ(ca,cb) (ca.red == cb.red && ca.green == cb.green && ca.blue == cb.blue) int trpgMatTable::AddMaterial(const trpgMaterial &mat,bool lookForExisting) { trpgMaterial cmat = mat; // necessary? // having a shadeModel of 999 indicates that the entry is free. I thought this would // work fine, until I realized that evidently most of the time the shademodel isn't set // at all. Now my kludge takes so much work it's almost worth doing it right. if (cmat.shadeModel>100) cmat.shadeModel=trpgMaterial::Smooth; int baseMat=0; bool spaceInTable=false; //int offset=baseMat; if (lookForExisting) { // Look for a matching base material minus the textures //for (baseMat = 0;baseMat < numMat;baseMat++) { MaterialMapType::const_iterator itr = materialMap.begin(); for ( ; itr != materialMap.end( ); itr++) { baseMat = itr->first; const trpgMaterial &bm = itr->second; if (bm.shadeModel==999) { // this is an 'empty' entry. Means we won't find it, either. spaceInTable=true; break; } // Compare structures if (CEQ(cmat.color,bm.color) && CEQ(cmat.ambient,bm.ambient) && CEQ(cmat.diffuse,bm.diffuse) && CEQ(cmat.specular,bm.specular) && CEQ(cmat.emission,bm.emission) && cmat.shininess == bm.shininess && cmat.shadeModel == bm.shadeModel && cmat.pointSize == bm.pointSize && cmat.lineWidth == bm.lineWidth && cmat.cullMode == bm.cullMode && cmat.alphaFunc == bm.alphaFunc && cmat.alphaRef == bm.alphaRef && cmat.attrSet.fid == bm.attrSet.fid && cmat.attrSet.smc == bm.attrSet.smc && cmat.attrSet.stp == bm.attrSet.stp && cmat.attrSet.swc == bm.attrSet.swc && cmat.autoNormal == bm.autoNormal && cmat.texEnvs.size() == bm.texEnvs.size()) { // Test the texture envs bool isSame=true; unsigned int i; for (i=0;i(&(*itr).second); } bool trpgMatTable::Read(trpgReadBuffer &buf) { trpgMaterial mat; trpgToken matTok; int32 len; bool status; int i,j; int nMat,nTable; try { buf.Get(nTable); buf.Get(nMat); if (nTable <= 0 || nMat < 0) throw 1; // Read the materials for (i=0;iSetEnvMode(envMode); break; case TRPGMAT_TXENV_FILTER: buf.Get(minFilter); buf.Get(magFilter); tenv->SetMinFilter(minFilter); tenv->SetMagFilter(magFilter); break; case TRPGMAT_TXENV_WRAP: buf.Get(wrapS); buf.Get(wrapT); tenv->SetWrap(wrapS,wrapT); break; case TRPGMAT_TXENV_BORDER: buf.Get(borderCol); tenv->SetBorderColor(borderCol); break; default: // Don't know this token. Skip break; } } catch (...) { return NULL; } return tenv; } bool trpgTextureEnv::Read(trpgReadBuffer &buf) { trpgr_Parser parse; textureEnvCB teCb; // Texture environment is a bunch of tokens in random order // Interface to it with a parser teCb.tenv = this; parse.AddCallback(TRPGMAT_TXENV_MODE,&teCb,false); parse.AddCallback(TRPGMAT_TXENV_FILTER,&teCb,false); parse.AddCallback(TRPGMAT_TXENV_WRAP,&teCb,false); parse.AddCallback(TRPGMAT_TXENV_BORDER,&teCb,false); parse.Parse(buf); return isValid(); } /* Write Material class Material representation. */ // Constructor trpgMaterial::trpgMaterial() { Reset(); } trpgMaterial::~trpgMaterial() { } // Reset function void trpgMaterial::Reset() { color = trpgColor(1,1,1); ambient = trpgColor(0,0,0); diffuse = trpgColor(1,1,1); specular = trpgColor(0,0,0); emission = trpgColor(0,0,0); shininess = 0; shadeModel = 999; // kludge to identify 'empty' material table entries pointSize = 1; lineWidth = 1; cullMode = Back; alphaFunc = GreaterThan; alphaRef = 0; alpha = 1.0; autoNormal = false; numTex = 0; texids.resize(0); texEnvs.resize(0); numTile = 0; isBump = false; attrSet.fid = -1; attrSet.smc = -1; attrSet.stp = -1; attrSet.swc = -1; handle = -1; writeHandle = false; } // Validity check bool trpgMaterial::isValid() const { // Only thing we really care about is texture if (numTex < 0) return false; for (int i=0;i= texids.size()) return; texids[no] = id; texEnvs[no] = env; } int trpgMaterial::AddTexture(int id,const trpgTextureEnv &env) { texids.push_back(id); texEnvs.push_back(env); numTex++; return numTex-1; } void trpgMaterial::SetNumTiles(int no) { numTile = no; } int trpgMaterial::AddTile() { return(++numTile); } void trpgMaterial::SetIsBumpMap(bool val) { isBump = val; } void trpgMaterial::SetAttr(int attrCode,int val) { switch (attrCode) { case TR_FID: attrSet.fid = val; break; case TR_SMC: attrSet.smc = val; break; case TR_STP: attrSet.stp = val; break; case TR_SWC: attrSet.swc = val; break; } return; } // Write to buffer bool trpgMaterial::Write(trpgWriteBuffer &buf) { if (!isValid()) return false; buf.Begin(TRPGMATERIAL); // Bundle the basic material parameters together buf.Begin(TRPGMAT_BASIC); buf.Add(color); buf.Add(ambient); buf.Add(diffuse); buf.Add(specular); buf.Add(emission); buf.Add(shininess); buf.Add(numTile); buf.End(); // Most everything else is a single token. // This is inefficient, but expandable buf.Begin(TRPGMAT_SHADE); buf.Add(shadeModel); buf.End(); buf.Begin(TRPGMAT_SIZES); buf.Add(pointSize); buf.Add(lineWidth); buf.End(); buf.Begin(TRPGMAT_CULL); buf.Add(cullMode); buf.End(); buf.Begin(TRPGMAT_ALPHA); buf.Add(alphaFunc); buf.Add(alphaRef); buf.Add(alpha); buf.End(); buf.Begin(TRPGMAT_NORMAL); buf.Add((int32)autoNormal); buf.End(); buf.Begin(TRPGMAT_TEXTURE); buf.Add(numTex); for (int i=0;i= 2.3, handle will be set to a unique identifier. **/ if(writeHandle) { buf.Begin(TRPGMAT_HANDLE); buf.Add((int)handle); buf.End(); } buf.End(); return true; } /* *************** Material Read methods *************** */ // Get methods bool trpgMaterial::GetColor(trpgColor &col) const { if (!isValid()) return false; col = color; return true; } bool trpgMaterial::GetAmbient(trpgColor &col) const { if (!isValid()) return false; col = ambient; return true; } bool trpgMaterial::GetDiffuse(trpgColor &col) const { if (!isValid()) return false; col = diffuse; return true; } bool trpgMaterial::GetSpecular(trpgColor &col) const { if (!isValid()) return false; col = specular; return true; } bool trpgMaterial::GetEmission(trpgColor &col) const { if (!isValid()) return false; col = emission; return true; } bool trpgMaterial::GetShininess(float64 &shin) const { if (!isValid()) return false; shin = shininess; return true; } bool trpgMaterial::GetShadeModel(int &sm) const { if (!isValid()) return false; sm = shadeModel; return true; } bool trpgMaterial::GetPointSize(float64 &ps) const { if (!isValid()) return false; ps = pointSize; return true; } bool trpgMaterial::GetLineWidth(float64 &lw) const { if (!isValid()) return false; lw = lineWidth; return true; } bool trpgMaterial::GetCullMode(int32 &cull) const { if (!isValid()) return false; cull = cullMode; return true; } bool trpgMaterial::GetAlphaFunc(int &af) const { if (!isValid()) return false; af = alphaFunc; return true; } bool trpgMaterial::GetAlphaRef(float64 &ar) const { if (!isValid()) return false; ar = alphaRef; return true; } bool trpgMaterial::GetAlpha(float64 &a) const { if (!isValid()) return false; a = alpha; return true; } bool trpgMaterial::GetAutoNormal(bool &an) const { if (!isValid()) return false; an = autoNormal; return true; } bool trpgMaterial::GetNumTexture(int &no) const { if (!isValid()) return false; no = numTex; return true; } bool trpgMaterial::GetTexture(int no,int &id,trpgTextureEnv &te) const { if (!isValid() || no < 0 || no >= numTex) return false; id = texids[no]; te = texEnvs[no]; return true; } bool trpgMaterial::GetNumTile(int &no) const { if (!isValid()) return false; no = numTile; return true; } bool trpgMaterial::GetIsBumpMap(bool &ret) const { if (!isValid()) return false; ret = isBump; return true; } bool trpgMaterial::GetAttr(int attrCode,int &ret) const { switch (attrCode) { case TR_FID: ret = attrSet.fid; break; case TR_SMC: ret = attrSet.smc; break; case TR_STP: ret = attrSet.stp; break; case TR_SWC: ret = attrSet.swc; break; default: return false; } return true; } /* Material CB Used to parse tokens for a material. */ class materialCB : public trpgr_Callback { public: void * Parse(trpgToken,trpgReadBuffer &); trpgMaterial *mat; }; void * materialCB::Parse(trpgToken tok,trpgReadBuffer &buf) { trpgColor color; float64 shininess; int shadeModel; float64 size; int cullMode; int alphaFunc; float64 alphaRef,alpha; bool autoNormal; int numTex,texId; trpgToken envTok; trpgTextureEnv texEnv; int32 len,numtile; bool status; int i; try { switch (tok) { case TRPGMAT_BASIC: buf.Get(color); mat->SetColor(color); buf.Get(color); mat->SetAmbient(color); buf.Get(color); mat->SetDiffuse(color); buf.Get(color); mat->SetSpecular(color); buf.Get(color); mat->SetEmission(color); buf.Get(shininess); mat->SetShininess(shininess); buf.Get(numtile); mat->SetNumTiles(numtile); break; case TRPGMAT_SHADE: buf.Get(shadeModel); mat->SetShadeModel(shadeModel); break; case TRPGMAT_SIZES: buf.Get(size); mat->SetPointSize(size); buf.Get(size); mat->SetLineWidth(size); break; case TRPGMAT_CULL: buf.Get(cullMode); mat->SetCullMode(cullMode); break; case TRPGMAT_ALPHA: buf.Get(alphaFunc); buf.Get(alphaRef); buf.Get(alpha); mat->SetAlphaFunc(alphaFunc); mat->SetAlphaRef(alphaRef); mat->SetAlpha(alpha); break; case TRPGMAT_NORMAL: { int32 tmp; buf.Get(tmp); if (tmp) autoNormal = true; else autoNormal = false; mat->SetAutoNormal(autoNormal); } break; case TRPGMAT_TEXTURE: buf.Get(numTex); for (i=0;iAddTexture(texId,texEnv); } break; case TRPGMAT_BUMP: { int32 tmp; buf.Get(tmp); bool isBump = (tmp) ? true : false; mat->SetIsBumpMap(isBump); } break; case TRPGMAT_ATTR: { int tmp; buf.Get(tmp); mat->SetAttr(trpgMaterial::TR_FID,tmp); buf.Get(tmp); mat->SetAttr(trpgMaterial::TR_SMC,tmp); buf.Get(tmp); mat->SetAttr(trpgMaterial::TR_STP,tmp); buf.Get(tmp); mat->SetAttr(trpgMaterial::TR_SWC,tmp); } break; case TRPGMAT_HANDLE: { int hdl; buf.Get(hdl); mat->SetHandle(hdl); } break; default: break; } } catch (...) { return NULL; } return mat; } bool trpgMaterial::Read(trpgReadBuffer &buf) { trpgr_Parser parse; materialCB matCb; // Material is just a bunch of unordered tokens. // Interface to it with a generic parser matCb.mat = this; parse.AddCallback(TRPGMAT_BASIC,&matCb,false); parse.AddCallback(TRPGMAT_SHADE,&matCb,false); parse.AddCallback(TRPGMAT_SIZES,&matCb,false); parse.AddCallback(TRPGMAT_CULL,&matCb,false); parse.AddCallback(TRPGMAT_ALPHA,&matCb,false); parse.AddCallback(TRPGMAT_NORMAL,&matCb,false); parse.AddCallback(TRPGMAT_TEXTURE,&matCb,false); parse.AddCallback(TRPGMAT_BUMP,&matCb,false); parse.AddCallback(TRPGMAT_ATTR,&matCb,false); parse.AddCallback(TRPGMAT_HANDLE,&matCb,false); parse.Parse(buf); return isValid(); } /* Texture Really just a container for a texture name and use count. The use count is used for paging. */ // Constructor trpgTexture::trpgTexture() { mode = External; type = trpg_Unknown; numLayer = -1; name = NULL; useCount = 0; sizeX = sizeY = -1; addr.file = 0; addr.offset = 0; addr.col = -1; addr.row = -1; isMipmap = false; writeHandle = false; handle = -1; } // Copy construction trpgTexture::trpgTexture(const trpgTexture &in): trpgReadWriteable(in) { mode = in.mode; type = in.type; numLayer = in.numLayer; // RGBX name = NULL; SetName(in.name); useCount = in.useCount; sizeX = in.sizeX; sizeY = in.sizeY; addr.file = in.addr.file; addr.offset = in.addr.offset; addr.row = in.addr.row; addr.col = in.addr.col; isMipmap = in.isMipmap; // storageSize + levelOffset handle = in.handle; writeHandle = in.writeHandle; } // Destruction trpgTexture::~trpgTexture() { Reset(); } // Reset void trpgTexture::Reset() { mode = External; type = trpg_Unknown; numLayer = -1; if (name) delete [] name; name = NULL; useCount = 0; sizeX = sizeY = -1; addr.file = 0; addr.offset = 0; addr.row = -1; addr.col = -1; isMipmap = false; storageSize.clear(); levelOffset.clear(); handle = -1; writeHandle = false; } // Valid if we've got a name bool trpgTexture::isValid() const { switch (mode) { case External: return (name != NULL); break; case Local: return (type != trpg_Unknown && sizeX != -1 && sizeY != -1); break; case Global: return (type != trpg_Unknown); break; case Template: return (type != trpg_Unknown && sizeX != -1 && sizeY != -1); break; default: return false; } return false; } // Set Name void trpgTexture::SetName(const char *inName) { if (name) delete [] name; name = NULL; if (!inName) return; name = new char[strlen(inName)+1]; strcpy(name,inName); } // Get Name bool trpgTexture::GetName(char *outName,int outLen) const { if (!isValid()) return false; int len = (name) ? strlen(name) : 0; strncpy(outName,name,MIN(len,outLen)+1); return true; } void trpgTexture::SetImageMode(ImageMode inMode) { mode = inMode; } bool trpgTexture::GetImageMode(ImageMode &outMode) const { outMode = mode; return true; } void trpgTexture::SetImageType(ImageType inType) { type = inType; } bool trpgTexture::GetImageType(ImageType &outType) const { outType = type; return true; } void trpgTexture::SetImageSize(const trpg2iPoint &inSize) { sizeX = inSize.x; sizeY = inSize.y; } bool trpgTexture::GetImageSize(trpg2iPoint &outSize) const { if (mode != Local && mode != Template) return false; outSize.x = sizeX; outSize.y = sizeY; return true; } void trpgTexture::SetIsMipmap(bool val) { isMipmap = val; } bool trpgTexture::GetIsMipmap(bool &ret) const { ret = isMipmap; return true; } bool trpgTexture::GetImageAddr(trpgwAppAddress &outAddr) const { if (mode != Local) return false; outAddr = addr; return true; } void trpgTexture::SetImageAddr(const trpgwAppAddress &inAddr) { addr = inAddr; } bool trpgTexture::GetImageDepth(int32 &depth) const { switch (type) { case trpg_RGB8: depth = 3; break; case trpg_RGBA8: depth = 4; break; case trpg_INT8: depth = 1; break; case trpg_INTA8: depth = 2; break; case trpg_FXT1: depth = 3; break; case trpg_RGBX: depth = numLayer; break; case trpg_DXT1: depth = 3; break; case trpg_DXT3: depth = 3; break; case trpg_DXT5: depth = 3; break; case trpg_MCM5: depth = 5; break; case trpg_MCM6R: case trpg_MCM6A: depth = 6; break; case trpg_MCM7RA: case trpg_MCM7AR: depth = 7; break; default: depth = -1; break; } return true; } void trpgTexture::SetNumLayer(int layers) { numLayer = layers; } bool trpgTexture::GetNumLayer(int &layers) const { if (!isValid()) return false; GetImageDepth(layers); return true; } // Use count management void trpgTexture::SetNumTile(int num) { useCount = num; } void trpgTexture::AddTile() { useCount++; } bool trpgTexture::GetNumTile(int &num) const { if (!isValid()) return false; num = useCount; return true; } // Copy operator trpgTexture &trpgTexture::operator = (const trpgTexture &in) { mode = in.mode; type = in.type; if (in.name) SetName(in.name); useCount = in.useCount; sizeX = in.sizeX; sizeY = in.sizeY; // RGBX numLayer = in.numLayer; isMipmap = in.isMipmap; addr = in.addr; writeHandle = in.writeHandle; handle = in.handle; return *this; } // Equality operator int trpgTexture::operator == (const trpgTexture &in) const { if (mode != in.mode) return 0; switch (mode) { case External: if (!in.name && !name) return 1; if (!in.name || !name) return 0; return (!strcmp(in.name,name)); break; case Local: if (type == in.type && sizeX == in.sizeX && sizeY == in.sizeY && isMipmap == in.isMipmap && addr.file == in.addr.file && addr.offset == in.addr.offset && addr.row == in.addr.row && addr.col==in.addr.col ) return 1; break; case Global: case Template: if (type == in.type && sizeX == in.sizeX && sizeY == in.sizeY && isMipmap == in.isMipmap) return 1; } return 0; } // Utility functions int32 trpgTexture::CalcNumMipmaps() const { // We're going to assume these are powers of two. // If not, then the writer's a moron. // :))) The comment line above made me really loughing, Steve. - Nick int bval = MAX(sizeX,sizeY); // Now look for the highest bit int p2; for (p2=0;p2<32;p2++) if ((1<(this))->CalcMipLevelSizes(); int totSize = 0; for (unsigned int i=0;i= 0 && miplevel < CalcNumMipmaps() ) { if ( !storageSize.size() ) CalcMipLevelSizes(); return storageSize[miplevel]; } return 0; } int32 trpgTexture::MipLevelOffset(int miplevel) { if ( miplevel > 0 && miplevel < CalcNumMipmaps() ) { if ( !levelOffset.size() ) CalcMipLevelSizes(); return levelOffset[miplevel]; } return 0; } // Write function bool trpgTexture::Write(trpgWriteBuffer &buf) { if (!isValid()) return false; buf.Begin(TRPGTEXTURE); buf.Add(name); buf.Add(useCount); // New in 2.0 from here down buf.Add((unsigned char)mode); buf.Add((unsigned char)type); buf.Add(sizeX); buf.Add(sizeY); buf.Add(addr.file); buf.Add(addr.offset); buf.Add((int32)isMipmap); if(writeHandle) { buf.Add((int32)handle); } buf.End(); return true; } // Read function bool trpgTexture::Read(trpgReadBuffer &buf) { char texName[1024]; try { buf.Get(texName,1023); SetName(texName); buf.Get(useCount); mode = External; // New in 2.0 from here down unsigned char bval; buf.Get(bval); mode = (trpgTexture::ImageMode)bval; buf.Get(bval); type = (trpgTexture::ImageType)bval; GetImageDepth(numLayer); // heh buf.Get(sizeX); buf.Get(sizeY); buf.Get(addr.file); buf.Get(addr.offset); int32 ival; buf.Get(ival); // Read the handle if we can.. try { if(!buf.Get((int32 &)handle)) { handle = -1; } else { writeHandle = true; } } catch (...) { handle = -1; } isMipmap = (ival) ? true : false; } catch (...) { return false; } if (!isValid()) return false; // calculate the mip level sizes CalcMipLevelSizes(); return true; } void trpgTexture::CalcMipLevelSizes() { int num_miplevels = (isMipmap ? CalcNumMipmaps() : 1); int level_size = 0; int level_offset = 0; int block_size = 0; int pixel_size = 0; int pad_size = 0; bool isDXT = false; bool isFXT = false; switch (type) { case trpg_DXT1: isDXT = true; block_size = 8; break; case trpg_DXT3: case trpg_DXT5: isDXT = true; block_size = 16; break; case trpg_RGB8: pad_size = 4; pixel_size = 3; break; case trpg_RGBA8: pad_size = 4; pixel_size = 4; break; case trpg_RGBX: pad_size = 4; pixel_size = numLayer; break; case trpg_MCM5: pad_size = 4; pixel_size = 5; break; case trpg_MCM6R: case trpg_MCM6A: pad_size = 4; pixel_size = 6; break; case trpg_MCM7RA: case trpg_MCM7AR: pad_size = 4; pixel_size = 7; break; case trpg_INT8: pad_size = 4; pixel_size = 1; break; case trpg_INTA8: pad_size = 4; pixel_size = 2; break; case trpg_FXT1: isFXT = true; break; default: break; } levelOffset.clear(); storageSize.clear(); levelOffset.push_back(level_offset); if ( isDXT ) { // DXT compressed int num_x_blocks = ((sizeX/4)+(sizeX%4?1:0)); int num_y_blocks = ((sizeY/4)+(sizeY%4?1:0)); level_size = num_x_blocks * num_y_blocks * block_size; storageSize.push_back(level_size); for ( int i = 1; i < num_miplevels; i++ ) { level_offset += level_size; levelOffset.push_back(level_offset); num_x_blocks /= 2; num_y_blocks /= 2; num_x_blocks = MAX(1,num_x_blocks); num_y_blocks = MAX(1,num_y_blocks); level_size = num_x_blocks * num_y_blocks * block_size; storageSize.push_back(level_size); } return; } if ( isFXT) { // bits per pixel and size int bpp = 4; int x = sizeX; int y = sizeY; int nummiplevels = (isMipmap ? CalcNumMipmaps() : 1); for (int i = 0; i < nummiplevels; i++) { if (i > 0) levelOffset.push_back(level_offset); x = ( x + 0x7 ) & ~0x7; y = ( y + 0x3 ) & ~0x3; // Number of bytes level_size = ( x * y * bpp ) >> 3; storageSize.push_back(level_size); level_offset += level_size; if (x > 1) x /= 2; if (y > 1) y /= 2; } return; } { int x_size = sizeX; int y_size = sizeY; // Pad to a given size, if necessary int row_size = x_size * pixel_size; if (pad_size > 0) { int left = row_size%pad_size; if (left) row_size += pad_size - left; } level_size = row_size * y_size; storageSize.push_back(level_size); for ( int i = 1; i < num_miplevels; i++ ) { level_offset += level_size; levelOffset.push_back(level_offset); x_size /= 2; y_size /= 2; x_size = MAX(1,x_size); y_size = MAX(1,y_size); row_size = x_size * pixel_size; if (pad_size > 0) { int left = row_size%pad_size; if (left) row_size += pad_size - left; } level_size = row_size * y_size; storageSize.push_back(level_size); } } } /* Texture Table Just a list of texture names so we can index. */ // Constructor trpgTexTable::trpgTexTable() { currentRow = -1; currentCol = -1; } trpgTexTable::trpgTexTable(const trpgTexTable &in): trpgReadWriteable(in) { *this = in; } // Reset function void trpgTexTable::Reset() { errMess[0] = '\0'; textureMap.clear(); currentRow = -1; currentCol = -1; } // Destructor trpgTexTable::~trpgTexTable() { Reset(); } // Validity check bool trpgTexTable::isValid() const { if (!textureMap.size()) { strcpy(errMess, "Texture table list is empty"); return false; } TextureMapType::const_iterator itr = textureMap.begin(); for ( ; itr != textureMap.end( ); itr++) { if(!itr->second.isValid()) { strcpy(errMess, "A texture in the texture table is invalid"); return false; } } return true; } // Set functions void trpgTexTable::SetNumTextures(int /*no*/) { // obsolete. This method doesn't need to do anything since we're using a map instead of a vector. // texList.resize(no); } int trpgTexTable::AddTexture(const trpgTexture &inTex) { TeAttrHdl hdl = inTex.GetHandle(); if(hdl==-1) { // if no handle is specified, we will use an index as the handle (just like before 2.3) hdl = textureMap.size(); } TextureMapType::iterator itr = textureMap.find(hdl); // Don't overwrite the texture if it was already there if(itr==textureMap.end()) textureMap[hdl] = inTex; return hdl; } int trpgTexTable::FindAddTexture(const trpgTexture &inTex) { TextureMapType::iterator itr = textureMap.begin(); for ( ; itr != textureMap.end( ); itr++) { trpgTexture tx = itr->second; if(tx == inTex) { return itr->first; } } return AddTexture(inTex); } void trpgTexTable::SetTexture(int id,const trpgTexture &inTex) { if (id < 0) return; textureMap[id] = inTex; } // Copy operator trpgTexTable &trpgTexTable::operator = (const trpgTexTable &in) { Reset(); TextureMapType::const_iterator itr = in.textureMap.begin(); for ( ; itr != in.textureMap.end( ); itr++) { trpgTexture tex = itr->second; in.GetTexture(itr->first,tex); AddTexture(tex); } return *this; } // Write Texture table bool trpgTexTable::Write(trpgWriteBuffer &buf) { int32 numTex; if (!isValid()) return false; buf.Begin(TRPGTEXTABLE2); numTex = textureMap.size(); buf.Add(numTex); TextureMapType::iterator itr = textureMap.begin(); for ( ; itr != textureMap.end( ); itr++) { itr->second.Write(buf); } buf.End(); return true; } /* *********** Read Texture Table *********** */ // Get functions bool trpgTexTable::GetNumTextures(int &no) const { no = textureMap.size(); if (!isValid()) return false; return true; } bool trpgTexTable::GetTexture(int id,trpgTexture &ret) const { if (!isValid()) return false; if (id < 0) return false; TextureMapType::const_iterator itr = textureMap.find(id); if(itr == textureMap.end()) { return false; } ret = itr->second; return true; } const trpgTexture *trpgTexTable::GetTextureRef(int id) const { if (id < 0) return false; TextureMapType::const_iterator itr = textureMap.find(id); if(itr == textureMap.end()) { return false; } const trpgTexture *ret = &(itr->second); return ret; } const trpgTexture *trpgTexTable::FindByName(const char *name, int &texid) const { TextureMapType::const_iterator itr = textureMap.begin(); for ( ; itr != textureMap.end( ); itr++) { char thisName[1024]; thisName[0] = '\0'; itr->second.GetName(thisName,1023); if(strcasecmp(thisName,name)==0) { texid = itr->first; return &(itr->second); } } return false; } bool trpgTexTable::Read(trpgReadBuffer &buf) { int32 numTex; trpgToken texTok; int32 len; try { buf.Get(numTex); for (int i=0;i=2.3) if((currentRow!=-1)&&(currentCol!=-1)) { trpgwAppAddress taddr; tex.GetImageAddr(taddr); taddr.col = currentCol; taddr.row = currentRow; tex.SetImageAddr(taddr); } AddTexture(tex); buf.PopLimit(); if (!status) throw 1; } } catch (...) { return false; } return true; } /* ************** Local Material ************** */ trpgLocalMaterial::trpgLocalMaterial() { baseMat = -1; sx = sy = ex = ey = destWidth = destHeight = 0; addr.resize(1); addr[0].file = 0; addr[0].offset = 0; addr[0].col = -1; addr[0].row = -1; } trpgLocalMaterial::~trpgLocalMaterial() { } void trpgLocalMaterial::SetBaseMaterial(int32 subTable,int32 inMatID) { baseMatTable = subTable; baseMat = inMatID; } void trpgLocalMaterial::Reset() { baseMat = -1; sx = sy = ex = ey = destWidth = destHeight = 0; // storageSize.resize(0); addr.resize(1); addr[0].file = 0; addr[0].offset = 0; addr[0].col = -1; addr[0].row = -1; } bool trpgLocalMaterial::GetBaseMaterial(int32 &subTable,int32 &matID) const { if (!isValid()) return false; subTable = baseMatTable; matID = baseMat; return true; } void trpgLocalMaterial::SetSubImageInfo(const SubImageInfo &info) { sx = info.sx; sy = info.sy; ex = info.ex; ey = info.ey; destWidth = info.destWidth; destHeight = info.destHeight; } bool trpgLocalMaterial::GetSubImageInfo(SubImageInfo &info) const { if (!isValid()) return false; info.sx = sx; info.sy = sy; info.ex = ex; info.ey = ey; info.destWidth = destWidth; info.destHeight = destHeight; return true; } void trpgLocalMaterial::SetAddr(const trpgwAppAddress &inAddr) { addr[0] = inAddr; } void trpgLocalMaterial::SetNthAddr(unsigned int subtable, const trpgwAppAddress &inAddr) { if (addr.size()<=subtable) addr.resize(subtable+1); addr[subtable] = inAddr; } bool trpgLocalMaterial::GetAddr(trpgwAppAddress &inAddr) const { if (!isValid()) return false; inAddr = addr[0]; return true; } bool trpgLocalMaterial::GetNthAddr(unsigned int subtable, trpgwAppAddress &inAddr) const { if (!isValid()) return false; if (addr.size()<=subtable) return false; inAddr = addr[subtable]; return true; } bool trpgLocalMaterial::GetNumLocals(int &numLocals) const { if (!isValid()) return false; // not checking for tile local, that's up to you. numLocals=addr.size(); return true; } /*bool trpgLocalMaterial::SetStorageSizes(int level,vector *inSizes) { storageSize.resize(inSizes->size()); for (int i=0;isize();i++) storageSize[i] = (*inSizes)[i]; return true; }*/ /*bool trpgLocalMaterial::GetStorageSizes(const vector *retSize) { if (!isValid()) return false; retSize = storageSize; return true; }*/ bool trpgLocalMaterial::isValid() const { if (baseMat < 0) return false; return true; } // Write method bool trpgLocalMaterial::Write(trpgWriteBuffer &buf) { if (!isValid()) return false; buf.Begin(TRPGLOCALMATERIAL); // Write the data buf.Add(baseMatTable); buf.Add(baseMat); buf.Add(sx); buf.Add(sy); buf.Add(ex); buf.Add(ey); buf.Add(destWidth); buf.Add(destHeight); buf.Add(addr[0].file); buf.Add(addr[0].offset); // and in case there's more... int numAddrs=(int)(addr.size()); if (numAddrs>1) { buf.Add(numAddrs-1); // suppressed due to breaking old readers. for (int i=1;i