#include "stdafx.h" #include "cPortal.h" #include "cByteStream.h" /* Portal Types: 01 - Type 1 models 02 - Type 2 models (Modelgroups) 03 - Animations 04 - Palettes 05 - Texture lookups 06 - Textures 08 - Texture Lookups 0A - Sounds 0D - Dungeon Parts 0E - UI text 0F - palette lookups? 13 - Worldinfo 22 - String lists 25 - More string lists 27 - Magic Strings 31 - Character creation strings */ PFNGLCOMPRESSEDTEXIMAGE2DARBPROC glCompressedTexImage2DARB; cPortal::cPortal() { m_tfPortal = new cTurbineFile(); m_tfPortal->LoadFile("client_portal.dat"); TCHAR szEXEPathname[_MAX_PATH]; GetModuleFileName(NULL, szEXEPathname, _MAX_PATH); *(strrchr(szEXEPathname, '\\')+1) = 0; strcat(szEXEPathname, "client_highres.dat"); FILE *ftest = fopen(szEXEPathname,"rb"); if (ftest) { fclose(ftest); m_tfPortalHighRes = new cTurbineFile(); m_tfPortalHighRes->LoadFile("client_highres.dat"); } else m_tfPortalHighRes = NULL; } cPortal::~cPortal() { if (m_tfPortal) delete m_tfPortal; if (m_tfPortalHighRes) delete m_tfPortalHighRes; } cPortalFile * cPortal::OpenEntry( DWORD dwID ) { cPortalFile *tp = NULL; if (m_tfPortalHighRes) tp = m_tfPortalHighRes->OpenEntry(dwID); if (tp) return tp; else return m_tfPortal->OpenEntry(dwID); } int cPortal::HighestPowerOfTwo(DWORD In) { int tp = -1; for (int i=0;i<32;i++) { if (In & 1) tp = i; In >>= 1; } return tp; } DWORD cPortal::FindTexturePalette(DWORD Texture, std::vector *vPaletteSwaps, float fTransTex, float fTransPix) { //TODO: Implement the transparency! cPortalFile *pfTex = OpenEntry(Texture); if (!pfTex) return 0; //redirect if it can find it if ((Texture & 0xFF000000) == 0x05000000) { DWORD NumIDs = *((DWORD *) (pfTex->data + 9)); for (DWORD i=13; i<=13 + NumIDs*4; i+=4) { DWORD tp = FindGraphic(*((DWORD *) (pfTex->data + i)), vPaletteSwaps, fTransTex, fTransPix); if (tp) { m_mGraphicEdgeCache[Texture] = m_mGraphicEdgeCache[*((DWORD *) (pfTex->data + i))]; return tp; } } } return 0; } DWORD cPortal::FindGraphic(DWORD ID, std::vector *vPaletteSwaps, float fTransTex, float fTransPix) { //Pull it out of the cache, if possible... QWORD Hash = ID | ((QWORD) ID << 32); int num = 0; if (vPaletteSwaps) { for (std::vector::iterator i = vPaletteSwaps->begin(); i != vPaletteSwaps->end(); i++) { Hash += num*((QWORD) i->newPalette << 40); Hash += num*((QWORD) i->length << 32); Hash += num*((QWORD) i->offset << 24); Hash += num++; } } Hash += (QWORD) (*((DWORD *) &fTransTex))*72; Hash += (QWORD) (*((DWORD *) &fTransPix))*9727; if (m_mGraphicCache.find(Hash) != m_mGraphicCache.end()) return m_mGraphicCache[Hash]; //Open object and make sure it exists... cPortalFile *pfUI = OpenEntry(ID); if (!pfUI) return 0; cByteStream pBS(pfUI->data, pfUI->length); pBS.ReadBegin(); //Load and parse image DWORD dwPicID = pBS.ReadDWORD(); DWORD unk = pBS.ReadDWORD(); DWORD sizeX = pBS.ReadDWORD(); DWORD sizeY = pBS.ReadDWORD(); DWORD format = pBS.ReadDWORD(); DWORD length = pBS.ReadDWORD(); if (format == 0x1F4) //JPEG return 0; //If it's a palettized image, form the palette and transparencies DWORD palette = 0; DWORD *newPalette = 0; cPortalFile *pfPal = 0; bool newPalUsed = false; if ((format == 0x65) || (format == 0x29)) { //Form the palette we're going to use memcpy(&palette, pfUI->data+24+length, sizeof(DWORD)); pfPal = OpenEntry(palette); DWORD palentries = *((DWORD *) (pfPal->data+4)); //Copy a new palette if we have to, otherwise just pull from memory newPalUsed = true; newPalette = new DWORD[palentries]; memcpy(newPalette, pfPal->data+8, palentries*sizeof(DWORD)); //Perform paletteswaps if (vPaletteSwaps) { for (std::vector::iterator i = vPaletteSwaps->begin(); i != vPaletteSwaps->end(); i++) { cPortalFile *pfPalNew = m_Portal->OpenEntry(0x04000000 | i->newPalette); if (!pfPalNew) return false; if (format == 0x29) //256 entries memcpy(&newPalette[i->offset], pfPalNew->data+8+(i->offset*sizeof(DWORD)), (i->length*sizeof(DWORD))); else //2048 entries memcpy(&newPalette[i->offset*8], pfPalNew->data+8+(i->offset*sizeof(DWORD))*8, (i->length*sizeof(DWORD))*8); } } //Overall Transparency DWORD tpf = ((DWORD) (0xFF * (1.0f-fTransTex))) << 24; for (DWORD i=0;i= 0x31545844) return 0; //Generate the OpenGL texture GLuint dwid = 0; glGenTextures( 1, &dwid ); glBindTexture(GL_TEXTURE_2D, dwid); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR); glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR); if ((sizeX2 == sizeX) && (sizeY2 == sizeY) && (format != 0x65) && (format != 0x29)) { //If it's just immediately loadable without any processing, do it! if (format == 0x31545844) glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, sizeX2,sizeY2, 0, length, pfUI->data+24); else if (format == 0x35545844) glCompressedTexImage2DARB(GL_TEXTURE_2D, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, sizeX2,sizeY2, 0, length, pfUI->data+24); else if (format == 0x15) glTexImage2D(GL_TEXTURE_2D, 0, 4, sizeX2,sizeY2, 0, GL_BGRA, GL_UNSIGNED_BYTE, pfUI->data+24); else if (format == 0xF3) glTexImage2D(GL_TEXTURE_2D, 0, 3, sizeX2,sizeY2, 0, GL_RGB, GL_UNSIGNED_BYTE, pfUI->data+24); else if (format == 0x14) glTexImage2D(GL_TEXTURE_2D, 0, 3, sizeX2,sizeY2, 0, GL_BGR, GL_UNSIGNED_BYTE, pfUI->data+24); else if ((format == 0x1C) || (format == 0xF4)) glTexImage2D(GL_TEXTURE_2D, 0, 1, sizeX2,sizeY2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, pfUI->data+24); else if ((format == 0x17) || (format == 0x1A)) //16-bit grayscale? glTexImage2D(GL_TEXTURE_2D, 0, 1, sizeX2,sizeY2, 0, GL_LUMINANCE, GL_UNSIGNED_SHORT, pfUI->data+24); else return NULL; } else { //Padding will be required, unfortunately... BYTE *tex = new BYTE[sizeX2*sizeY2*4]; ZeroMemory(tex, sizeX2*sizeY2*4); for (DWORD y=0;ydata+24+(3*(sizeX*y+x)))) | 0xFF000000; break; case 0x15: //RGBA (32-bit color) *((DWORD *) &tex[4*sizeX2*y + x*4]) = *((DWORD *) (pfUI->data+24+(4*(sizeX*y+x)))); break; case 0x65: //2-byte indexed, palette ID follows encoded data { WORD index = *((WORD *)(pfUI->data+24+(2*(sizeX*y+x)))); *((DWORD *) &tex[4*sizeX2*y + x*4]) = newPalette[index]/* & 0x7FFFFFFF*/; } break; case 0x29: //1-byte indexed, palette ID follows encoded data { BYTE index = *((BYTE *)(pfUI->data+24+(sizeX*y+x))); *((DWORD *) &tex[4*sizeX2*y + x*4]) = newPalette[index]/* & 0x7FFFFFFF*/; } break; case 0x1C: //1-byte grayscale case 0xF4: { DWORD index = *((BYTE *)(pfUI->data+24+(sizeX*y+x))); *((DWORD *) &tex[4*sizeX2*y + x*4]) = index | (index << 8) | (index << 16) | 0xFF000000; } break; default: { return NULL; } } } else *((DWORD *) &tex[4*sizeX2*y + x*4]) = 0x00000000; } } glTexImage2D(GL_TEXTURE_2D, 0, 4, sizeX2,sizeY2, 0, GL_BGRA, GL_UNSIGNED_BYTE, tex); delete []tex; } //Store info to our caches POINTf tpoint( (float) sizeX/sizeX2, (float) sizeY/sizeY2 ); m_mGraphicEdgeCache[ID] = tpoint; m_mGraphicCache[Hash] = dwid; //Clean up if (newPalUsed) delete []newPalette; return dwid; } POINTf cPortal::GetGraphicEdges(DWORD ID) { if (m_mGraphicEdgeCache.find(ID) == m_mGraphicEdgeCache.end()) { POINTf tpzero( 0, 0 ); return tpzero; } return m_mGraphicEdgeCache[ID]; } DWORD cPortal::GetPoolSize() { DWORD size = 0; if (m_tfPortalHighRes) size += m_tfPortalHighRes->GetPoolSize(); size += m_tfPortal->GetPoolSize(); return size; }