uMod 2 branch

This commit is contained in:
code@koerner-de.net
2012-03-13 19:02:45 +00:00
parent e3e4d25b54
commit 20cf4fc5a1
80 changed files with 22725 additions and 0 deletions
+859
View File
@@ -0,0 +1,859 @@
/*
This file is part of Universal Modding Engine.
Universal Modding Engine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Universal Modding Engine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Universal Modding Engine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "uMod_Main.h"
uMod_TextureClient::uMod_TextureClient(uMod_TextureServer* server, IDirect3DDevice9* device)
{
Message("uMod_TextureClient::uMod_TextureClient(void): %lu\n", this);
Server = server;
D3D9Device = device;
BoolSaveAllTextures = false;
BoolSaveSingleTexture = false;
KeyBack = 0;
KeySave = 0;
KeyNext = 0;
SavePath[0]=0;
GameName[0]=0;
NumberToMod = 0;
FileToMod = NULL;
if (Server!=NULL)
{
if (Server->AddClient( this, &FileToMod, &NumberToMod))
{
Server=NULL;
NumberToMod = 0;
FileToMod = NULL;
}
else
{
for (int i=0; i<NumberToMod; i++) {FileToMod[i].NumberOfTextures=0; FileToMod[i].Textures = NULL;}
}
}
Mutex = CreateMutex(NULL, false, NULL);
Update = NULL;
NumberOfUpdate = -1;
Bool_CheckAgainNonAdded = false;
FontColour = D3DCOLOR_ARGB(255,255,0,0);
TextureColour = D3DCOLOR_ARGB(255,0,255,0);
}
uMod_TextureClient::~uMod_TextureClient(void)
{
Message("uMod_TextureClient::~uMod_TextureClient(void): %lu\n", this);
if (Server!=NULL) Server->RemoveClient(this);
if (Mutex!=NULL) CloseHandle(Mutex);
if (Update!=NULL) delete [] Update;
if (FileToMod!=NULL)
{
for (int i=0; i<NumberToMod; i++) if (FileToMod[i].Textures!=NULL) delete [] FileToMod[i].Textures;
delete [] FileToMod;
}
}
int uMod_TextureClient::AddTexture( uMod_IDirect3DTexture9* pTexture)
{
void *cpy;
long ret = D3D9Device->QueryInterface( IID_IDirect3DTexture9, &cpy);
if (ret == 0x01000000L) ((uMod_IDirect3DDevice9*)D3D9Device)->SetLastCreatedTexture(NULL); //this texture must no be added twice
else ((uMod_IDirect3DDevice9Ex*) D3D9Device)->SetLastCreatedTexture(NULL); //this texture must no be added twice
if (pTexture->FAKE) return (RETURN_OK); // this is a fake texture
Message("uMod_TextureClient::AddTexture( %lu): %lu (thread: %lu)\n", pTexture, this, GetCurrentThreadId());
MyTypeHash hash;
if (int ret = pTexture->GetHash( hash))
{
Bool_CheckAgainNonAdded = true;
NonAdded_OriginalTextures.Add( pTexture);
return (ret);
}
pTexture->Hash = hash;
if (BoolSaveAllTextures) SaveTexture(pTexture);
if (gl_ErrorState & uMod_ERROR_FATAL) return (RETURN_FATAL_ERROR);
OriginalTextures.Add( pTexture); // add the texture to the list of original texture
return (LookUpToMod(pTexture)); // check if this texture should be modded
}
int uMod_TextureClient::AddTexture( uMod_IDirect3DVolumeTexture9* pTexture)
{
void *cpy;
long ret = D3D9Device->QueryInterface( IID_IDirect3DTexture9, &cpy);
if (ret == 0x01000000L) ((uMod_IDirect3DDevice9*)D3D9Device)->SetLastCreatedVolumeTexture(NULL); //this texture must no be added twice
else ((uMod_IDirect3DDevice9Ex*) D3D9Device)->SetLastCreatedVolumeTexture(NULL); //this texture must no be added twice
if (pTexture->FAKE) return (RETURN_OK); // this is a fake texture
Message("uMod_TextureClient::AddTexture( Volume: %lu): %lu (thread: %lu)\n", pTexture, this, GetCurrentThreadId());
MyTypeHash hash;
if (int ret = pTexture->GetHash( hash))
{
Bool_CheckAgainNonAdded = true;
NonAdded_OriginalVolumeTextures.Add( pTexture);
return (ret);
}
pTexture->Hash = hash;
if (BoolSaveAllTextures) SaveTexture(pTexture);
if (gl_ErrorState & uMod_ERROR_FATAL) return (RETURN_FATAL_ERROR);
OriginalVolumeTextures.Add( pTexture); // add the texture to the list of original texture
return (LookUpToMod(pTexture)); // check if this texture should be modded
}
int uMod_TextureClient::AddTexture( uMod_IDirect3DCubeTexture9* pTexture)
{
void *cpy;
long ret = D3D9Device->QueryInterface( IID_IDirect3DTexture9, &cpy);
if (ret == 0x01000000L) ((uMod_IDirect3DDevice9*)D3D9Device)->SetLastCreatedCubeTexture(NULL); //this texture must no be added twice
else ((uMod_IDirect3DDevice9Ex*) D3D9Device)->SetLastCreatedCubeTexture(NULL); //this texture must no be added twice
if (pTexture->FAKE) return (RETURN_OK); // this is a fake texture
Message("uMod_TextureClient::AddTexture( Cube: %lu): %lu (thread: %lu)\n", pTexture, this, GetCurrentThreadId());
MyTypeHash hash;
if (int ret = pTexture->GetHash( hash))
{
Bool_CheckAgainNonAdded = true;
NonAdded_OriginalCubeTextures.Add( pTexture);
return (ret);
}
pTexture->Hash = hash;
if (BoolSaveAllTextures) SaveTexture(pTexture);
if (gl_ErrorState & uMod_ERROR_FATAL) return (RETURN_FATAL_ERROR);
OriginalCubeTextures.Add( pTexture); // add the texture to the list of original texture
return (LookUpToMod(pTexture)); // check if this texture should be modded
}
int uMod_TextureClient::CheckAgainNonAdded(void)
{
Message("uMod_TextureClient::CheckAgainNonAdded( %u, %u, %u): %lu\n", NonAdded_OriginalTextures.GetNumber(),
NonAdded_OriginalVolumeTextures.GetNumber(), NonAdded_OriginalCubeTextures.GetNumber(), this);
Bool_CheckAgainNonAdded = false;
int num = NonAdded_OriginalTextures.GetNumber();
for (int i=num-1; i>=0; i--)
{
uMod_IDirect3DTexture9* pTexture = NonAdded_OriginalTextures[i];
MyTypeHash hash;
if (pTexture->GetHash( hash) == 0)
{
NonAdded_OriginalTextures.Remove(pTexture);
OriginalTextures.Add( pTexture); // add the texture to the list of original texture
LookUpToMod(pTexture); // check if this texture should be modded
}
}
num = NonAdded_OriginalVolumeTextures.GetNumber();
for (int i=num-1; i>=0; i--)
{
uMod_IDirect3DVolumeTexture9* pTexture = NonAdded_OriginalVolumeTextures[i];
MyTypeHash hash;
if (pTexture->GetHash( hash) == 0)
{
NonAdded_OriginalVolumeTextures.Remove(pTexture);
OriginalVolumeTextures.Add( pTexture); // add the texture to the list of original texture
LookUpToMod(pTexture); // check if this texture should be modded
}
}
num = NonAdded_OriginalCubeTextures.GetNumber();
for (int i=num-1; i>=0; i--)
{
uMod_IDirect3DCubeTexture9* pTexture = NonAdded_OriginalCubeTextures[i];
MyTypeHash hash;
if (pTexture->GetHash( hash) == 0)
{
NonAdded_OriginalCubeTextures.Remove(pTexture);
OriginalCubeTextures.Add( pTexture); // add the texture to the list of original texture
LookUpToMod(pTexture); // check if this texture should be modded
}
}
Message("uMod_TextureClient::CheckAgainNonAdded() END: %lu\n", this);
return (RETURN_OK);
}
int uMod_TextureClient::RemoveTexture( uMod_IDirect3DTexture9* pTexture) // is called from a texture, if it is finally released
{
Message("uMod_TextureClient::RemoveTexture( %lu, %#lX): %lu\n", pTexture, pTexture->Hash, this);
if (gl_ErrorState & uMod_ERROR_FATAL) return (RETURN_FATAL_ERROR);
if (pTexture->FAKE)
{
// we need to set the corresponding FileToMod[X].pTexture to NULL, to avoid a link to a non existing texture object
int ref = pTexture->Reference;
if (ref>=0 && ref<NumberToMod)
{
for (int i=0; i<FileToMod[ref].NumberOfTextures; i++) if (FileToMod[ref].Textures[i] == pTexture)
{
FileToMod[ref].NumberOfTextures--;
for (int j=i; j<FileToMod[ref].NumberOfTextures; j++) FileToMod[ref].Textures[j] = FileToMod[ref].Textures[j+1];
FileToMod[ref].Textures[FileToMod[ref].NumberOfTextures] = NULL;
break;
}
}
}
else
{
if (int ret = OriginalTextures.Remove( pTexture)) return (ret); // remove this texture form the original list
return (NonAdded_OriginalTextures.Remove( pTexture)); // also try to remove this texture form the non_added list
}
return (RETURN_OK);
}
int uMod_TextureClient::RemoveTexture( uMod_IDirect3DVolumeTexture9* pTexture) // is called from a texture, if it is finally released
{
Message("uMod_TextureClient::RemoveTexture( Volume %lu, %#lX): %lu\n", pTexture, pTexture->Hash, this);
if (gl_ErrorState & uMod_ERROR_FATAL) return (RETURN_FATAL_ERROR);
if (pTexture->FAKE)
{
// we need to set the corresponding FileToMod[X].pTexture to NULL, to avoid a link to a non existing texture object
int ref = pTexture->Reference;
if (ref>=0 && ref<NumberToMod)
{
for (int i=0; i<FileToMod[ref].NumberOfTextures; i++) if (FileToMod[ref].Textures[i] == pTexture)
{
FileToMod[ref].NumberOfTextures--;
for (int j=i; j<FileToMod[ref].NumberOfTextures; j++) FileToMod[ref].Textures[j] = FileToMod[ref].Textures[j+1];
FileToMod[ref].Textures[FileToMod[ref].NumberOfTextures] = NULL;
break;
}
}
}
else
{
if (int ret = OriginalVolumeTextures.Remove( pTexture)) return (ret); // remove this texture form the original list
return (NonAdded_OriginalVolumeTextures.Remove( pTexture)); // also try to remove this texture form the non_added list
}
return (RETURN_OK);
}
int uMod_TextureClient::RemoveTexture( uMod_IDirect3DCubeTexture9* pTexture) // is called from a texture, if it is finally released
{
Message("uMod_TextureClient::RemoveTexture( Cube %lu, %#lX): %lu\n", pTexture, pTexture->Hash, this);
if (gl_ErrorState & uMod_ERROR_FATAL) return (RETURN_FATAL_ERROR);
if (pTexture->FAKE)
{
// we need to set the corresponding FileToMod[X].pTexture to NULL, to avoid a link to a non existing texture object
int ref = pTexture->Reference;
if (ref>=0 && ref<NumberToMod)
{
for (int i=0; i<FileToMod[ref].NumberOfTextures; i++) if (FileToMod[ref].Textures[i] == pTexture)
{
FileToMod[ref].NumberOfTextures--;
for (int j=i; j<FileToMod[ref].NumberOfTextures; j++) FileToMod[ref].Textures[j] = FileToMod[ref].Textures[j+1];
FileToMod[ref].Textures[FileToMod[ref].NumberOfTextures] = NULL;
break;
}
}
}
else
{
if (int ret = OriginalCubeTextures.Remove( pTexture)) return (ret); // remove this texture form the original list
return (NonAdded_OriginalCubeTextures.Remove( pTexture)); // also try to remove this texture form the non_added list
}
return (RETURN_OK);
}
int uMod_TextureClient::SaveAllTextures(bool val)
{
Message("uMod_TextureClient::SaveAllTextures( %d): %lu\n", val, this);
BoolSaveAllTextures=val;
return (RETURN_OK);
}
int uMod_TextureClient::SaveSingleTexture(bool val)
{
Message("uMod_TextureClient::SaveSingleTexture( %d): %lu\n", val, this);
if (BoolSaveSingleTexture && !val) //if BoolSaveSingleTexture is set to false and was previously true we switch the SingleTexture back
{
uMod_IDirect3DTexture9* pTexture;
void *cpy;
long ret = D3D9Device->QueryInterface( IID_IDirect3DTexture9, &cpy);
if (ret == 0x01000000L) pTexture = ((uMod_IDirect3DDevice9*)D3D9Device)->GetSingleTexture(); //this texture must no be added twice
else pTexture = ((uMod_IDirect3DDevice9Ex*) D3D9Device)->GetSingleTexture(); //this texture must no be added twice
if (pTexture!=NULL) UnswitchTextures(pTexture);
}
BoolSaveSingleTexture = val;
return (RETURN_OK);
}
int uMod_TextureClient::SetSaveDirectory( wchar_t *dir)
{
Message("uMod_TextureClient::SetSaveDirectory( %ls): %lu\n", dir, this);
int i = 0;
for (i=0; i<MAX_PATH && (dir[i]); i++) SavePath[i] = dir[i];
if (i==MAX_PATH)
{
SavePath[0]=0;
return (RETURN_BAD_ARGUMENT);
}
else SavePath[i]=0;
return (RETURN_OK);
}
int uMod_TextureClient::SetGameName( wchar_t *name)
{
Message("uMod_TextureClient::SetGameName( %ls): %lu\n", name, this);
int i = 0;
for (i=0; i<MAX_PATH && (name[i]); i++) GameName[i] = name[i];
if (i==MAX_PATH)
{
GameName[0]=0;
return (RETURN_BAD_ARGUMENT);
}
else GameName[i]=0;
return (RETURN_OK);
}
int uMod_TextureClient::SaveTexture(uMod_IDirect3DTexture9* pTexture)
{
if (pTexture==NULL) return (RETURN_BAD_ARGUMENT);
if (SavePath[0]==0) {Message("uMod_TextureClient::SaveTexture( %#lX, %lu): %lu, SavePath not set\n", pTexture->Hash, pTexture->m_D3Dtex, this); return (RETURN_TEXTURE_NOT_SAVED);}
wchar_t file[MAX_PATH];
if (GameName[0]) swprintf_s( file, MAX_PATH, L"%ls\\%ls_T_%#lX.dds", SavePath, GameName, pTexture->Hash);
else swprintf_s( file, MAX_PATH, L"%ls\\T_%#lX.dds", SavePath, pTexture->Hash);
Message("uMod_TextureClient::SaveTexture( %ls): %lu\n", file, this);
if (D3D_OK!=D3DXSaveTextureToFileW( file, D3DXIFF_DDS, pTexture->m_D3Dtex, NULL)) return (RETURN_TEXTURE_NOT_SAVED);
return (RETURN_OK);
}
int uMod_TextureClient::SaveTexture(uMod_IDirect3DVolumeTexture9* pTexture)
{
if (pTexture==NULL) return (RETURN_BAD_ARGUMENT);
if (SavePath[0]==0) {Message("uMod_TextureClient::SaveTexture( %#lX, %lu): %lu, SavePath not set\n", pTexture->Hash, pTexture->m_D3Dtex, this); return (RETURN_TEXTURE_NOT_SAVED);}
wchar_t file[MAX_PATH];
if (GameName[0]) swprintf_s( file, MAX_PATH, L"%ls\\%ls_V_%#lX.dds", SavePath, GameName, pTexture->Hash);
else swprintf_s( file, MAX_PATH, L"%ls\\V_%#lX.dds", SavePath, pTexture->Hash);
Message("uMod_TextureClient::SaveTexture( %ls): %lu\n", file, this);
if (D3D_OK!=D3DXSaveTextureToFileW( file, D3DXIFF_DDS, pTexture->m_D3Dtex, NULL)) return (RETURN_TEXTURE_NOT_SAVED);
return (RETURN_OK);
}
int uMod_TextureClient::SaveTexture(uMod_IDirect3DCubeTexture9* pTexture)
{
if (pTexture==NULL) return (RETURN_BAD_ARGUMENT);
if (SavePath[0]==0) {Message("uMod_TextureClient::SaveTexture( %#lX, %lu): %lu, SavePath not set\n", pTexture->Hash, pTexture->m_D3Dtex, this); return (RETURN_TEXTURE_NOT_SAVED);}
wchar_t file[MAX_PATH];
if (GameName[0]) swprintf_s( file, MAX_PATH, L"%ls\\%ls_C_%#lX.dds", SavePath, GameName, pTexture->Hash);
else swprintf_s( file, MAX_PATH, L"%ls\\C_%#lX.dds", SavePath, pTexture->Hash);
Message("uMod_TextureClient::SaveTexture( %ls): %lu\n", file, this);
if (D3D_OK!=D3DXSaveTextureToFileW( file, D3DXIFF_DDS, pTexture->m_D3Dtex, NULL)) return (RETURN_TEXTURE_NOT_SAVED);
return (RETURN_OK);
}
int uMod_TextureClient::AddUpdate(TextureFileStruct* update, int number) //client must delete the update array
{
Message("AddUpdate( %lu, %d): %lu\n", update, number, this);
if (int ret = LockMutex()) {gl_ErrorState |= uMod_ERROR_TEXTURE; return (ret);}
if (Update!=NULL) delete [] Update;
Update = update;
NumberOfUpdate = number;
return (UnlockMutex());
}
int uMod_TextureClient::MergeUpdate(void)
{
if (NumberOfUpdate<0) {return (RETURN_OK);}
if (int ret = LockMutex()) {gl_ErrorState |= uMod_ERROR_TEXTURE ; return (ret);}
Message("uMod_TextureClient::MergeUpdate(): %lu\n", this);
for (int i=0; i<NumberOfUpdate; i++) {Update[i].NumberOfTextures=0; Update[i].Textures = NULL;} // this is already done, but safety comes first ^^
int pos_old=0;
int pos_new=0;
int *to_lookup = NULL;
if (NumberOfUpdate>0) to_lookup = new int[NumberOfUpdate];
int num_to_lookup = 0;
/*
* FileToMod contains the old files (textures) which should replace the target textures (if they are loaded by the game)
* Update contains the new files (textures) which should replace the target textures (if they are loaded by the game)
*
* Both arrays (FileToMod and Update) are sorted according to their hash values.
*
* First we go through both arrays linearly and
* 1) take over the old entry if the hash is the same,
* 2) release old fake texture (if target texture exist and is not in the Update)
* 3) or mark newly added fake texture (if they are not in FileToMod)
*/
while (pos_old<NumberToMod && pos_new<NumberOfUpdate)
{
if (FileToMod[pos_old].Hash > Update[pos_new].Hash) // this fake texture is new
{
to_lookup[num_to_lookup++] = pos_new++; // keep this fake texture in mind, we must search later for it through all original textures
// we increase only the new counter by one
}
else if (FileToMod[pos_old].Hash < Update[pos_new].Hash) // this fake texture is not in the update
{
for (int i=FileToMod[pos_old].NumberOfTextures-1; i>=0; i--) FileToMod[pos_old].Textures[i]->Release(); // we release the fake textures
if (FileToMod[pos_old].Textures!=NULL) delete [] FileToMod[pos_old].Textures; // we delete the memory
FileToMod[pos_old].NumberOfTextures = 0;
FileToMod[pos_old].Textures = NULL;
pos_old++; // we increase only the old counter by one
}
else // the hash value is the same, thus this texture is in the array FileToMod as well as in the array Update
{
if (Update[pos_new].ForceReload)
{
if (FileToMod[pos_old].NumberOfTextures>0)
{
Update[pos_new].Textures = new IDirect3DBaseTexture9*[FileToMod[pos_old].NumberOfTextures];
}
for (int i=0; i<FileToMod[pos_old].NumberOfTextures; i++)
{
IDirect3DBaseTexture9 *base_texture;
int ret = FileToMod[pos_old].Textures[i]->QueryInterface( IID_IDirect3D9, (void**)&base_texture);
switch (ret)
{
case 0x01000000L:
{
uMod_IDirect3DTexture9 *pTexture = (uMod_IDirect3DTexture9*) FileToMod[pos_old].Textures[i];//
uMod_IDirect3DTexture9 *pRefTexture = pTexture->CrossRef_D3Dtex;
pTexture->Release();
i--; //after the Release of the old fake texture FileToMod[pos_old].Textures[i] is overwritten by entries with index greater than i
uMod_IDirect3DTexture9 *fake_Texture;
if (int ret = LoadTexture( & (Update[pos_new]), &fake_Texture)) return (ret);
if (SwitchTextures( fake_Texture, pRefTexture))
{
Message("MergeUpdate(): textures not switched %#lX\n", pRefTexture->Hash);
fake_Texture->Release();
}
else
{
Update[pos_new].Textures[Update[pos_new].NumberOfTextures++] = fake_Texture;
fake_Texture->Reference = pos_new;
}
break;
}
case 0x01000001L:
{
uMod_IDirect3DVolumeTexture9 *pTexture = (uMod_IDirect3DVolumeTexture9*) FileToMod[pos_old].Textures[i];//
uMod_IDirect3DVolumeTexture9 *pRefTexture = pTexture->CrossRef_D3Dtex;
pTexture->Release();
i--; //after the Release of the old fake texture FileToMod[pos_old].Textures[i] is overwritten by entries with index greater than i
uMod_IDirect3DVolumeTexture9 *fake_Texture;
if (int ret = LoadTexture( & (Update[pos_new]), &fake_Texture)) return (ret);
if (SwitchTextures( fake_Texture, pRefTexture))
{
Message("MergeUpdate(): textures not switched %#lX\n", pRefTexture->Hash);
fake_Texture->Release();
}
else
{
Update[pos_new].Textures[Update[pos_new].NumberOfTextures++] = fake_Texture;
fake_Texture->Reference = pos_new;
}
break;
}
case 0x01000002L:
{
uMod_IDirect3DCubeTexture9 *pTexture = (uMod_IDirect3DCubeTexture9*) FileToMod[pos_old].Textures[i];//
uMod_IDirect3DCubeTexture9 *pRefTexture = pTexture->CrossRef_D3Dtex;
pTexture->Release();
i--; //after the Release of the old fake texture FileToMod[pos_old].Textures[i] is overwritten by entries with index greater than i
uMod_IDirect3DCubeTexture9 *fake_Texture;
if (int ret = LoadTexture( & (Update[pos_new]), &fake_Texture)) return (ret);
if (SwitchTextures( fake_Texture, pRefTexture))
{
Message("MergeUpdate(): textures not switched %#lX\n", pRefTexture->Hash);
fake_Texture->Release();
}
else
{
Update[pos_new].Textures[Update[pos_new].NumberOfTextures++] = fake_Texture;
fake_Texture->Reference = pos_new;
}
break;
}
default:
break; // this is no fake texture and QueryInterface failed, because IDirect3DBaseTexture9 object cannot be a IDirect3D9 object ;)
}
}
}
else // the texture might be loaded or not
{
Update[pos_new].NumberOfTextures = FileToMod[pos_old].NumberOfTextures;
Update[pos_new].Textures = FileToMod[pos_old].Textures;
FileToMod[pos_old].NumberOfTextures = 0;
FileToMod[pos_old].Textures = NULL;
}
// we increase both counters by one
pos_old++;
pos_new++;
}
}
while (pos_old<NumberToMod) //this fake textures are not in the Update
{
for (int i=FileToMod[pos_old].NumberOfTextures-1; i>=0; i--) FileToMod[pos_old].Textures[i]->Release(); // we release the fake textures
//for (int i=0; i<FileToMod[pos_old].NumberOfTextures; i++) FileToMod[pos_old].Textures[i]->Release(); // we release the fake textures
if (FileToMod[pos_old].Textures!=NULL) delete [] FileToMod[pos_old].Textures; // we delete the memory
FileToMod[pos_old].Textures = NULL;
pos_old++;
}
while (pos_new<NumberOfUpdate) //this fake textures are newly added
{
to_lookup[num_to_lookup++] = pos_new++; //keep this fake texture in mind, we must search later for it through all original textures
}
if (FileToMod!=NULL)
{
delete [] FileToMod;
}
FileToMod = Update;
NumberToMod = NumberOfUpdate;
NumberOfUpdate = -1;
Update = NULL;
if (num_to_lookup>0)
{
uMod_IDirect3DTexture9* single_texture;
void *cpy;
long ret = D3D9Device->QueryInterface( IID_IDirect3DTexture9, &cpy);
if (ret == 0x01000000L) single_texture = ((uMod_IDirect3DDevice9*)D3D9Device)->GetSingleTexture(); //this texture must no be added twice
else single_texture = ((uMod_IDirect3DDevice9Ex*) D3D9Device)->GetSingleTexture(); //this texture must no be added twice
int num = OriginalTextures.GetNumber();
for (int i=0; i<num; i++) if (OriginalTextures[i]->CrossRef_D3Dtex==NULL || OriginalTextures[i]->CrossRef_D3Dtex==single_texture)
{
UnswitchTextures(OriginalTextures[i]); //this we can do always, so we unswitch the single texture
LookUpToMod( OriginalTextures[i], num_to_lookup, to_lookup);
}
uMod_IDirect3DVolumeTexture9 *single_volume_texture;
if (ret == 0x01000000L) single_volume_texture = ((uMod_IDirect3DDevice9*)D3D9Device)->GetSingleVolumeTexture(); //this texture must no be added twice
else single_volume_texture = ((uMod_IDirect3DDevice9Ex*) D3D9Device)->GetSingleVolumeTexture(); //this texture must no be added twice
num = OriginalVolumeTextures.GetNumber();
for (int i=0; i<num; i++) if (OriginalVolumeTextures[i]->CrossRef_D3Dtex==NULL || OriginalVolumeTextures[i]->CrossRef_D3Dtex==single_volume_texture)
{
UnswitchTextures(OriginalVolumeTextures[i]); //this we can do always, so we unswitch the single texture
LookUpToMod( OriginalVolumeTextures[i], num_to_lookup, to_lookup);
}
uMod_IDirect3DCubeTexture9 *single_cube_texture;
if (ret == 0x01000000L) single_cube_texture = ((uMod_IDirect3DDevice9*)D3D9Device)->GetSingleCubeTexture(); //this texture must no be added twice
else single_cube_texture = ((uMod_IDirect3DDevice9Ex*) D3D9Device)->GetSingleCubeTexture(); //this texture must no be added twice
num = OriginalCubeTextures.GetNumber();
for (int i=0; i<num; i++) if (OriginalCubeTextures[i]->CrossRef_D3Dtex==NULL || OriginalCubeTextures[i]->CrossRef_D3Dtex==single_cube_texture)
{
UnswitchTextures(OriginalCubeTextures[i]); //this we can do always, so we unswitch the single texture
LookUpToMod( OriginalCubeTextures[i], num_to_lookup, to_lookup);
}
}
if (to_lookup != NULL) delete [] to_lookup;
Message("uMod_TextureClient::MergeUpdate() END: %lu\n", this);
CheckAgainNonAdded();
return (UnlockMutex());
}
int uMod_TextureClient::LockMutex(void)
{
if (( gl_ErrorState & (uMod_ERROR_FATAL | uMod_ERROR_MUTEX) )) return (RETURN_NO_MUTEX);
if (WAIT_OBJECT_0!=WaitForSingleObject( Mutex, 100)) return (RETURN_MUTEX_LOCK); //waiting 100ms, to wait infinite pass INFINITE
return (RETURN_OK);
}
int uMod_TextureClient::UnlockMutex(void)
{
if (ReleaseMutex(Mutex)==0) return (RETURN_MUTEX_UNLOCK);
return (RETURN_OK);
}
int uMod_TextureClient::LookUpToMod( MyTypeHash hash, int num_index_list, int *index_list)
{
if(NumberToMod>0)
{
if (index_list==NULL || num_index_list==0)
{
if (hash<FileToMod[0].Hash || hash>FileToMod[NumberToMod-1].Hash) return (-1);
int pos = NumberToMod/2;
int begin = 0;
int end = NumberToMod-1;
// We look in the middle of the interval and each step we halve the interval,
// unless we find the texture or the size of the interval is less than 3.
// Note: contradicting to normal C-code here the interval includes the index "begin" and "end"!
while (begin+1<end) // as long as the interval is longer than two
{
if (hash > FileToMod[pos].Hash) // the new interval is the right half of the actual interval
{
begin = pos+1; // the new interval does not contain the index "pos"
pos = (begin + end)/2; // set "pos" somewhere inside the new interval
}
else if (hash < FileToMod[pos].Hash) // the new interval is the left half of the actual interval
{
end = pos-1; // the new interval does not contain the index "pos"
pos = (begin + end)/2; // set "pos" somewhere inside the new interval
}
else {return (pos); break;} // we hit the correct hash
}
for ( pos=begin; pos<=end; pos++) if (FileToMod[pos].Hash==hash) return (pos);
}
else
{
if (hash<FileToMod[index_list[0]].Hash || hash>FileToMod[index_list[num_index_list-1]].Hash) return (-1);
int pos = num_index_list/2;
int begin = 0;
int end = num_index_list-1;
// We look in the middle of the interval and each step we halve the interval,
// unless we find the texture or the size of the interval is less than 3.
// Note: contradicting to normal C-code here the interval includes the index "begin" and "end"!
while (begin+1<end) // as long as the interval is longer than two
{
if (hash > FileToMod[index_list[pos]].Hash) // the new interval is the right half of the actual interval
{
begin = pos+1; // the new interval does not contain the index "pos"
pos = (begin + end)/2; // set "pos" somewhere inside the new interval
}
else if (hash < FileToMod[index_list[pos]].Hash) // the new interval is the left half of the actual interval
{
end = pos-1; // the new interval does not contain the index "pos"
pos = (begin + end)/2; // set "pos" somewhere inside the new interval
}
else {return (index_list[pos]); break;} // we hit the correct hash
}
for ( pos=begin; pos<=end; pos++) if (FileToMod[index_list[pos]].Hash==hash) return (index_list[pos]);
}
}
return (-1);
}
int uMod_TextureClient::LookUpToMod( uMod_IDirect3DTexture9* pTexture, int num_index_list, int *index_list) // should only be called for original textures
{
Message("uMod_TextureClient::LookUpToMod( %lu): hash: %#lX, %lu\n", pTexture, pTexture->Hash, this);
if (pTexture->CrossRef_D3Dtex!=NULL) return (RETURN_OK); // bug, this texture is already switched
int index = LookUpToMod( pTexture->Hash, num_index_list, index_list);
if (index>=0)
{
uMod_IDirect3DTexture9 *fake_Texture;
if (int ret = LoadTexture( & (FileToMod[index]), &fake_Texture)) return (ret);
if (SwitchTextures( fake_Texture, pTexture))
{
Message("uMod_TextureClient::LookUpToMod(): textures not switched %#lX\n", FileToMod[index].Hash);
fake_Texture->Release();
}
else
{
IDirect3DBaseTexture9 **temp = new IDirect3DBaseTexture9*[FileToMod[index].NumberOfTextures+1];
for (int j=0; j<FileToMod[index].NumberOfTextures; j++) temp[j] = FileToMod[index].Textures[j];
if (FileToMod[index].Textures!=NULL) delete [] FileToMod[index].Textures;
FileToMod[index].Textures = temp;
FileToMod[index].Textures[FileToMod[index].NumberOfTextures++] = fake_Texture;
fake_Texture->Reference = index;
}
}
return (RETURN_OK);
}
int uMod_TextureClient::LookUpToMod( uMod_IDirect3DVolumeTexture9* pTexture, int num_index_list, int *index_list) // should only be called for original textures
{
Message("uMod_TextureClient::LookUpToMod( Volume %lu): hash: %#lX, %lu\n", pTexture, pTexture->Hash, this);
if (pTexture->CrossRef_D3Dtex!=NULL) return (RETURN_OK); // bug, this texture is already switched
int index = LookUpToMod( pTexture->Hash, num_index_list, index_list);
if (index>=0)
{
uMod_IDirect3DVolumeTexture9 *fake_Texture;
if (int ret = LoadTexture( & (FileToMod[index]), &fake_Texture)) return (ret);
if (SwitchTextures( fake_Texture, pTexture))
{
Message("uMod_TextureClient::LookUpToMod(): textures not switched %#lX\n", FileToMod[index].Hash);
fake_Texture->Release();
}
else
{
IDirect3DBaseTexture9 **temp = new IDirect3DBaseTexture9*[FileToMod[index].NumberOfTextures+1];
for (int j=0; j<FileToMod[index].NumberOfTextures; j++) temp[j] = FileToMod[index].Textures[j];
if (FileToMod[index].Textures!=NULL) delete [] FileToMod[index].Textures;
FileToMod[index].Textures = temp;
FileToMod[index].Textures[FileToMod[index].NumberOfTextures++] = fake_Texture;
fake_Texture->Reference = index;
}
}
return (RETURN_OK);
}
int uMod_TextureClient::LookUpToMod( uMod_IDirect3DCubeTexture9* pTexture, int num_index_list, int *index_list) // should only be called for original textures
{
Message("uMod_TextureClient::LookUpToMod( Cube %lu): hash: %#lX, %lu\n", pTexture, pTexture->Hash, this);
if (pTexture->CrossRef_D3Dtex!=NULL) return (RETURN_OK); // bug, this texture is already switched
int index = LookUpToMod( pTexture->Hash, num_index_list, index_list);
if (index>=0)
{
uMod_IDirect3DCubeTexture9 *fake_Texture;
if (int ret = LoadTexture( & (FileToMod[index]), &fake_Texture)) return (ret);
if (SwitchTextures( fake_Texture, pTexture))
{
Message("uMod_TextureClient::LookUpToMod(): textures not switched %#lX\n", FileToMod[index].Hash);
fake_Texture->Release();
}
else
{
IDirect3DBaseTexture9 **temp = new IDirect3DBaseTexture9*[FileToMod[index].NumberOfTextures+1];
for (int j=0; j<FileToMod[index].NumberOfTextures; j++) temp[j] = FileToMod[index].Textures[j];
if (FileToMod[index].Textures!=NULL) delete [] FileToMod[index].Textures;
FileToMod[index].Textures = temp;
FileToMod[index].Textures[FileToMod[index].NumberOfTextures++] = fake_Texture;
fake_Texture->Reference = index;
}
}
return (RETURN_OK);
}
int uMod_TextureClient::LoadTexture( TextureFileStruct* file_in_memory, uMod_IDirect3DTexture9 **ppTexture) // to load fake texture from a file in memory
{
Message("LoadTexture( %lu, %lu, %#lX): %lu\n", file_in_memory, ppTexture, file_in_memory->Hash, this);
if (D3D_OK != D3DXCreateTextureFromFileInMemoryEx( D3D9Device, file_in_memory->pData, file_in_memory->Size, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, (IDirect3DTexture9 **) ppTexture))
//if (D3D_OK != D3DXCreateTextureFromFileInMemory( D3D9Device, file_in_memory->pData, file_in_memory->Size, (IDirect3DTexture9 **) ppTexture))
{
*ppTexture=NULL;
return (RETURN_TEXTURE_NOT_LOADED);
}
(*ppTexture)->FAKE = true;
void *cpy;
long ret = D3D9Device->QueryInterface( IID_IDirect3DTexture9, &cpy);
if (ret == 0x01000000L) ((uMod_IDirect3DDevice9*)D3D9Device)->SetLastCreatedTexture(NULL); //this texture must no be added twice
else ((uMod_IDirect3DDevice9Ex*) D3D9Device)->SetLastCreatedTexture(NULL); //this texture must no be added twice
Message("LoadTexture( %lu, %#lX): DONE\n", *ppTexture, file_in_memory->Hash);
return (RETURN_OK);
}
int uMod_TextureClient::LoadTexture( TextureFileStruct* file_in_memory, uMod_IDirect3DVolumeTexture9 **ppTexture) // to load fake texture from a file in memory
{
Message("LoadTexture( Volume %lu, %lu, %#lX): %lu\n", file_in_memory, ppTexture, file_in_memory->Hash, this);
if (D3D_OK != D3DXCreateVolumeTextureFromFileInMemoryEx( D3D9Device, file_in_memory->pData, file_in_memory->Size, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, (IDirect3DVolumeTexture9 **) ppTexture))
//if (D3D_OK != D3DXCreateVolumeTextureFromFileInMemory( D3D9Device, file_in_memory->pData, file_in_memory->Size, (IDirect3DVolumeTexture9 **) ppTexture))
{
*ppTexture=NULL;
return (RETURN_TEXTURE_NOT_LOADED);
}
(*ppTexture)->FAKE = true;
void *cpy;
long ret = D3D9Device->QueryInterface( IID_IDirect3DTexture9, &cpy);
if (ret == 0x01000000L) ((uMod_IDirect3DDevice9*)D3D9Device)->SetLastCreatedVolumeTexture(NULL); //this texture must no be added twice
else ((uMod_IDirect3DDevice9Ex*) D3D9Device)->SetLastCreatedVolumeTexture(NULL); //this texture must no be added twice
Message("LoadTexture( Volume %lu, %#lX): DONE\n", *ppTexture, file_in_memory->Hash);
return (RETURN_OK);
}
int uMod_TextureClient::LoadTexture( TextureFileStruct* file_in_memory, uMod_IDirect3DCubeTexture9 **ppTexture) // to load fake texture from a file in memory
{
Message("LoadTexture( Cube %lu, %lu, %#lX): %lu\n", file_in_memory, ppTexture, file_in_memory->Hash, this);
if (D3D_OK != D3DXCreateCubeTextureFromFileInMemoryEx( D3D9Device, file_in_memory->pData, file_in_memory->Size, D3DX_DEFAULT, D3DX_DEFAULT, 0, D3DFMT_UNKNOWN, D3DPOOL_MANAGED, D3DX_DEFAULT, D3DX_DEFAULT, 0, NULL, NULL, (IDirect3DCubeTexture9 **) ppTexture))
//if (D3D_OK != D3DXCreateCubeTextureFromFileInMemory( D3D9Device, file_in_memory->pData, file_in_memory->Size, (IDirect3DCubeTexture9 **) ppTexture))
{
*ppTexture=NULL;
return (RETURN_TEXTURE_NOT_LOADED);
}
(*ppTexture)->FAKE = true;
void *cpy;
long ret = D3D9Device->QueryInterface( IID_IDirect3DTexture9, &cpy);
if (ret == 0x01000000L) ((uMod_IDirect3DDevice9*)D3D9Device)->SetLastCreatedCubeTexture(NULL); //this texture must no be added twice
else ((uMod_IDirect3DDevice9Ex*) D3D9Device)->SetLastCreatedCubeTexture(NULL); //this texture must no be added twice
Message("LoadTexture( Cube %lu, %#lX): DONE\n", *ppTexture, file_in_memory->Hash);
return (RETURN_OK);
}
+163
View File
@@ -0,0 +1,163 @@
/*
This file is part of Universal Modding Engine.
Universal Modding Engine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Universal Modding Engine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Universal Modding Engine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef uMod_TEXTUREHANDLER_HPP
#define uMod_TEXTUREHANDLER_HPP
#include <d3d9.h>
#include <d3d10.h>
#include "../uMod_GlobalDefines.h"
#include "..\uMod_Error.h"
class uMod_TextureServer;
/*
* An object of this class is owned by each d3dXX device.
* functions called by the Server are called from the server thread instance.
* All other functions are called from the render thread instance of the game itself.
*/
class uMod_TextureClient
{
public:
uMod_TextureClient(uMod_TextureServer* server);
~uMod_TextureClient(void);
/**
* Enable/Disable the "save all texture" mode. (called from the server)
* @param val
* @return RETURN_OK on success
*/
int SaveAllTextures(bool val);
/**
* Enable/Disable the "save all texture" mode. (called from the server)
* @param val
* @return RETURN_OK on success
*/
int SaveSingleTexture(bool val);
/**
* Set the directory, wher the texture should be stored (called from the server)
* @param dir
* @return RETURN_OK on success
*/
int SetSaveDirectory( wchar_t *dir);
/**
* Set the name of the game (default name of executabel without the extension .exe) (called from the server)
* @param name
* @return RETURN_OK on success
*/
int SetGameName( wchar_t *name);
/**
* Set the key to got to the previous texture (called from the server)
* @param key
* @return RETURN_OK
*/
int SetKeyBack( int key) {if (key>0) KeyBack = key; return (RETURN_OK);}
/**
* Set the key for saving the texture (called from the server)
* @param key
* @return RETURN_OK
*/
int SetKeySave( int key) {if (key>0) KeySave = key; return (RETURN_OK);}
/**
* Set the key to go to the next texture (called from the server)
* @param key
* @return RETURN_OK
*/
int SetKeyNext( int key) {if (key>0) KeyNext = key; return (RETURN_OK);}
/**
* Set the font color "during save single" texture mode. (called from the server)
* @param r red value (0..255)
* @param g green value (0..255)
* @param b blue value (0..255)
* @return
*/
int SetFontColour( DWORD r, DWORD g, DWORD b) {FontColour = D3DCOLOR_ARGB(255, r,g,b); return (RETURN_OK);}
/**
* Set the texture color "during save single" texture mode. (called from the server)
* @param r red value (0..255)
* @param g green value (0..255)
* @param b blue value (0..255)
* @return RETURN_OK
*/
int SetTextureColour( DWORD r, DWORD g, DWORD b) {TextureColour = D3DCOLOR_ARGB(255, r,g,b); return (RETURN_OK);}
/**
* The server add an update to the client.(called from server)
* @param update Pointer to an array of TextureFileStruct, the client \b must delete this array!
* @param number number of entries
* @return RETURN_OK on success
*/
int AddUpdate(TextureFileStruct* update, int number);
/**
* Merge the latest update (called from client -> e.g. uMod_IDirect3DDevice9::BeginScene())
* @return RETURN_OK on success
*/
int MergeUpdate(void);
bool BoolSaveAllTextures; //< true if all textures should be saved
bool BoolSaveSingleTexture; //< true if "save single texture" mode is enabled
int KeyBack; //< key value for going to the previous texture
int KeySave; //< key value for saving the current texture
int KeyNext; //< key value for going to the next texture
D3DCOLOR FontColour; //< color of the message ("save single texture" mode)
D3DCOLOR TextureColour; //< color of the texture ("save single texture" mode)
private:
uMod_TextureServer* Server; //< Pointer to the server
wchar_t SavePath[MAX_PATH]; //< saving directory
wchar_t GameName[MAX_PATH]; //< game name
TextureFileStruct* Update; //< array which stores the file in memory and the hash of each texture to be modded
int NumberOfUpdate; //< number of texture to be modded
/**
* Lock the mutex. The mutex protect the AddUpdate and MergeUpdate function to be called simultaneously.
* @return RETURN_OK on success
*/
int LockMutex();
/**
* Unloock the mutex. The mutex protect the AddUpdate and MergeUpdate function to be called simultaneously.
* @return RETURN_OK on success
*/
int UnlockMutex();
HANDLE Mutex; //< The mutex protect the AddUpdate and MergeUpdate function to be called simultaneously.
int NumberToMod; //< number of texture to be modded
TextureFileStruct* FileToMod; //< array which stores the file in memory and the hash of each texture to be modded
int LookUpToMod( MyTypeHash hash, int num_index_list, int *index_list); // called from LookUpToMod(...);
};
#endif /* uMod_TEXTUREHANDLER_HPP_ */
+828
View File
@@ -0,0 +1,828 @@
/*
This file is part of Universal Modding Engine.
Universal Modding Engine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Universal Modding Engine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Universal Modding Engine. If not, see <http://www.gnu.org/licenses/>.
*/
#include "uMod_Main.h"
uMod_TextureServer::uMod_TextureServer(wchar_t *game)
{
Message("uMod_TextureServer(void): %lu\n", this);
Mutex = CreateMutex(NULL, false, NULL);
Clients = NULL;
NumberOfClients = 0;
LenghtOfClients = 0;
BoolSaveAllTextures = false;
BoolSaveSingleTexture = false;
SavePath[0] = 0;
int len=0;
int path_pos=0;
int dot_pos=0;
for (len=0; len<MAX_PATH && (game[len]); len++)
{
if (game[len]==L'\\' || game[len]==L'/') path_pos=len+1;
else if (game[len]==L'.') dot_pos=len;
}
if (dot_pos>path_pos) len = dot_pos - path_pos;
else len -= path_pos;
for (int i=0; i<len; i++) GameName[i] = game[i+path_pos];
if (len<MAX_PATH) GameName[len] = 0;
else GameName[0] = 0;
KeyBack = 0;
KeySave = 0;
KeyNext = 0;
FontColour = 0u;
TextureColour = 0u;
Pipe.In = INVALID_HANDLE_VALUE;
Pipe.Out = INVALID_HANDLE_VALUE;
}
uMod_TextureServer::~uMod_TextureServer(void)
{
Message("~uMod_TextureServer(void): %lu\n", this);
if (Mutex != NULL) CloseHandle(Mutex);
//delete the files in memory
int num = CurrentMod.GetNumber();
for (int i = 0; i < num; i++) delete[] CurrentMod[i]->pData; //delete the file content of the texture
num = OldMod.GetNumber();
for (int i = 0; i < num; i++) delete[] OldMod[i]->pData; //delete the file content of the texture
if (Pipe.In != INVALID_HANDLE_VALUE ) CloseHandle(Pipe.In);
Pipe.In = INVALID_HANDLE_VALUE;
if (Pipe.Out != INVALID_HANDLE_VALUE) CloseHandle(Pipe.Out);
Pipe.Out = INVALID_HANDLE_VALUE;
}
int uMod_TextureServer::AddClient(uMod_TextureClient *client, TextureFileStruct** update, int* number) // called from a client
{
Message("AddClient(%lu): %lu\n", client, this);
if (int ret = LockMutex())
{
gl_ErrorState |= uMod_ERROR_SERVER;
return (ret);
}
// the following functions must not change the original uMod_IDirect3DDevice9 object
// somehow on game start some uMod_IDirect3DDevice9 object are created, which must rest unchanged!!
// these objects are released and are not used for rendering
client->SetGameName(GameName);
client->SaveAllTextures(BoolSaveAllTextures);
client->SaveSingleTexture(BoolSaveSingleTexture);
client->SetSaveDirectory(SavePath);
if (KeyBack > 0) client->SetKeyBack(KeyBack);
if (KeySave > 0) client->SetKeySave(KeySave);
if (KeyNext > 0) client->SetKeyNext(KeyNext);
if (FontColour>0u)
{
DWORD r = (FontColour>>16)&0xFF;
DWORD g = (FontColour>>8)&0xFF;
DWORD b = (FontColour)&0xFF;
client->SetFontColour( r, g, b);
}
if (TextureColour>0u)
{
DWORD r = (TextureColour>>16)&0xFF;
DWORD g = (TextureColour>>8)&0xFF;
DWORD b = (TextureColour)&0xFF;
client->SetTextureColour( r, g, b);
}
if (int ret = PrepareUpdate( update, number)) return (ret); // get a copy of all texture to be modded
if (NumberOfClients == LenghtOfClients) //allocate more memory
{
uMod_TextureClient** temp = NULL;
try {temp = new uMod_TextureClient*[LenghtOfClients + 10];}
catch (...)
{
gl_ErrorState |= uMod_ERROR_MEMORY | uMod_ERROR_SERVER;
if (int ret = UnlockMutex()) return (ret);
return (RETURN_NO_MEMORY);
}
for (int i=0; i<LenghtOfClients; i++) temp[i] = Clients[i];
if (Clients!=NULL) delete [] Clients;
Clients = temp;
LenghtOfClients += 10;
}
Clients[NumberOfClients++] = client;
return (UnlockMutex());
}
int uMod_TextureServer::RemoveClient(uMod_TextureClient *client) // called from a client
{
Message("RemoveClient(%lu): %lu\n", client);
if (int ret = LockMutex())
{
gl_ErrorState |= uMod_ERROR_SERVER;
return (ret);
}
for (int i = 0; i < NumberOfClients; i++) if (client == Clients[i])
{
NumberOfClients--;
Clients[i] = Clients[NumberOfClients];
break;
}
return (UnlockMutex());
}
int uMod_TextureServer::AddFile( char* buffer, unsigned int size, MyTypeHash hash, bool force) // called from Mainloop()
{
Message("uMod_TextureServer::AddFile( %lu %lu, %#lX, %d): %lu\n", buffer, size, hash, force, this);
TextureFileStruct* temp = NULL;
int num = CurrentMod.GetNumber();
for (int i=0; i<num; i++) if (CurrentMod[i]->Hash == hash) //look through all current textures
{
if (force) {temp = CurrentMod[i]; break;} // we need to reload it
else
{
if (buffer!=NULL) delete [] buffer;
return (RETURN_OK); // we still have added this texture
}
}
if (temp==NULL) // if not found, look through all old textures
{
num = OldMod.GetNumber();
for (int i=0; i<num; i++) if (OldMod[i]->Hash == hash)
{
temp = OldMod[i];
OldMod.Remove(temp);
CurrentMod.Add(temp);
if (force) break; // we must reload it
else
{
if (buffer!=NULL) delete [] buffer;
return (RETURN_OK); // we should not reload it
}
}
}
bool new_file = true;
if (temp!=NULL) //if it was found, we delete the old file content
{
new_file = false;
if (temp->pData!=NULL) delete [] temp->pData;
temp->pData = NULL;
}
else //if it was not found, we need to create a new object
{
new_file = true;
temp = new TextureFileStruct;
temp->Reference = -1;
}
temp->pData = buffer;
/*
try
{
temp->pData = new char[size];
}
catch (...)
{
if (!new_file) CurrentMod.Remove( temp); // if this is a not a new file it is in the list of the CurrentMod
delete temp;
gl_ErrorState |= uMod_ERROR_MEMORY | uMod_ERROR_SERVER;
return (RETURN_NO_MEMORY);
}
*/
for (unsigned int i=0; i<size; i++) temp->pData[i] = buffer[i];
temp->Size = size;
temp->NumberOfTextures = 0;
temp->Textures = NULL;
temp->Hash = hash;
//if (new_file) temp->ForceReload = false; // no need to force a load of the texture
//else
temp->ForceReload = force;
Message("End AddFile(%#lX)\n", hash);
if (new_file) return (CurrentMod.Add(temp)); // new files must be added to the list of the CurrentMod
else return (RETURN_OK);
}
/*
int uMod_TextureServer::AddFile(wchar_t* file_name, MyTypeHash hash, bool force) // called from Mainloop
// this functions does the same, but loads the file content from disk
{
Message("uMod_TextureServer::AddFile( %ls, %#lX, %d): %lu\n", file_name, hash, force, this);
TextureFileStruct* temp = NULL;
int num = CurrentMod.GetNumber();
for (int i = 0; i < num; i++) if (CurrentMod[i]->Hash == hash)
{
if (force) {temp = CurrentMod[i]; break;}
else return (RETURN_OK);
}
if (temp==NULL)
{
num = OldMod.GetNumber();
for (int i = 0; i < num; i++) if (OldMod[i]->Hash == hash)
{
temp = OldMod[i];
OldMod.Remove(temp);
CurrentMod.Add(temp);
if (force) break;
else return (RETURN_OK);
}
}
FILE* file;
if (_wfopen_s(&file, file_name, L"rb") != 0)
{
Message("AddFile( ): file not found\n");
return (RETURN_FILE_NOT_LOADED);
}
fseek (file, 0, SEEK_END);
unsigned int size = ftell(file);
fseek (file, 0, SEEK_SET);
bool new_file = true;
if (temp!=NULL)
{
new_file = false;
if (temp->pData!=NULL) delete [] temp->pData;
temp->pData = NULL;
}
else
{
new_file = true;
temp = new TextureFileStruct;
temp->Reference = -1;
}
try
{
temp->pData = new char[size];
}
catch (...)
{
if (!new_file) CurrentMod.Remove( temp);
delete temp;
gl_ErrorState |= uMod_ERROR_MEMORY | uMod_ERROR_SERVER;
return (RETURN_NO_MEMORY);
}
int result = fread(temp->pData, 1, size, file);
fclose(file);
if (result != size)
{
delete[] temp->pData;
if (!new_file) CurrentMod.Remove( temp);
delete temp;
return (RETURN_FILE_NOT_LOADED);
}
temp->Size = size;
temp->NumberOfTextures = 0;
temp->Textures = NULL;
temp->Hash = hash;
if (new_file) temp->ForceReload = false;
else temp->ForceReload = force;
Message("End AddFile(%#lX)\n", hash);
if (new_file) return (CurrentMod.Add(temp));
else return (RETURN_OK);
}
*/
int uMod_TextureServer::RemoveFile(MyTypeHash hash) // called from Mainloop()
{
Message("RemoveFile( %lu): %lu\n", hash, this);
int num = CurrentMod.GetNumber();
for (int i = 0; i < num; i++) if (CurrentMod[i]->Hash == hash)
{
TextureFileStruct* temp = CurrentMod[i];
CurrentMod.Remove(temp);
return (OldMod.Add(temp));
}
return (RETURN_OK);
}
int uMod_TextureServer::SaveAllTextures(bool val) // called from Mainloop()
{
if (BoolSaveAllTextures == val) return (RETURN_OK);
BoolSaveAllTextures = val;
if (int ret = LockMutex())
{
gl_ErrorState |= uMod_ERROR_SERVER;
return (ret);
}
for (int i = 0; i < NumberOfClients; i++)
{
Clients[i]->SaveAllTextures(BoolSaveAllTextures);
}
return (UnlockMutex());
}
int uMod_TextureServer::SaveSingleTexture(bool val) // called from Mainloop()
{
if (BoolSaveSingleTexture == val) return (RETURN_OK);
BoolSaveSingleTexture = val;
if (int ret = LockMutex())
{
gl_ErrorState |= uMod_ERROR_SERVER;
return (ret);
}
for (int i = 0; i < NumberOfClients; i++)
{
Clients[i]->SaveSingleTexture(BoolSaveSingleTexture);
}
return (UnlockMutex());
}
int uMod_TextureServer::SetSaveDirectory(wchar_t *dir) // called from Mainloop()
{
Message("uMod_TextureServer::SetSaveDirectory( %ls): %lu\n", dir, this);
int i = 0;
for (i = 0; i < MAX_PATH && (dir[i]); i++) SavePath[i] = dir[i];
if (i == MAX_PATH)
{
SavePath[0] = 0;
return (RETURN_BAD_ARGUMENT);
}
else SavePath[i] = 0;
if (int ret = LockMutex())
{
gl_ErrorState |= uMod_ERROR_SERVER;
return (ret);
}
for (int i = 0; i < NumberOfClients; i++)
{
Clients[i]->SetSaveDirectory(SavePath);
}
return (UnlockMutex());
}
int uMod_TextureServer::SetKeyBack(int key) // called from Mainloop()
{
if (KeyBack == key || KeySave == key || KeyNext == key) return (RETURN_OK);
if (int ret = LockMutex())
{
gl_ErrorState |= uMod_ERROR_SERVER;
return (ret);
}
KeyBack = key;
for (int i = 0; i < NumberOfClients; i++)
{
Clients[i]->SetKeyBack(key);
}
return (UnlockMutex());
}
int uMod_TextureServer::SetKeySave(int key) // called from Mainloop()
{
if (KeyBack == key || KeySave == key || KeyNext == key) return (RETURN_OK);
if (int ret = LockMutex())
{
gl_ErrorState |= uMod_ERROR_SERVER;
return (ret);
}
KeySave = key;
for (int i = 0; i < NumberOfClients; i++)
{
Clients[i]->SetKeySave(key);
}
return (UnlockMutex());
}
int uMod_TextureServer::SetKeyNext(int key) // called from Mainloop()
{
if (KeyBack == key || KeySave == key || KeyNext == key) return (RETURN_OK);
if (int ret = LockMutex())
{
gl_ErrorState |= uMod_ERROR_SERVER;
return (ret);
}
KeyNext = key;
for (int i = 0; i < NumberOfClients; i++)
{
Clients[i]->SetKeyNext(key);
}
return (UnlockMutex());
}
int uMod_TextureServer::SetFontColour(DWORD colour) // called from Mainloop()
{
if (colour==0u) return (RETURN_OK);
if (int ret = LockMutex())
{
gl_ErrorState |= uMod_ERROR_SERVER;
return (ret);
}
FontColour = colour;
DWORD r = (FontColour>>16)&0xFF;
DWORD g = (FontColour>>8)&0xFF;
DWORD b = (FontColour)&0xFF;
Message("uMod_TextureServer::SetFontColour( %u %u %u): %lu\n", r ,g ,b, this);
for (int i = 0; i < NumberOfClients; i++)
{
Clients[i]->SetFontColour( r, g, b);
}
return (UnlockMutex());
}
int uMod_TextureServer::SetTextureColour(DWORD colour) // called from Mainloop()
{
if (colour==0u) return (RETURN_OK);
if (int ret = LockMutex())
{
gl_ErrorState |= uMod_ERROR_SERVER;
return (ret);
}
TextureColour = colour;
DWORD r = (TextureColour>>16)&0xFF;
DWORD g = (TextureColour>>8)&0xFF;
DWORD b = (TextureColour)&0xFF;
Message("uMod_TextureServer::SetTextureColour( %u %u %u): %lu\n", r ,g ,b, this);
for (int i = 0; i < NumberOfClients; i++)
{
Clients[i]->SetTextureColour( r, g, b);
}
return (UnlockMutex());
}
int uMod_TextureServer::PropagateUpdate(uMod_TextureClient* client) // called from Mainloop(), send the update to all clients
{
Message("PropagateUpdate(%lu): %lu\n", client, this);
if (int ret = LockMutex())
{
gl_ErrorState |= uMod_ERROR_TEXTURE;
return (ret);
}
if (client != NULL)
{
TextureFileStruct* update;
int number;
if (int ret = PrepareUpdate( &update, &number)) return (ret);
client->AddUpdate(update, number);
}
else
{
for (int i=0; i<NumberOfClients; i++)
{
TextureFileStruct* update;
int number;
if (int ret = PrepareUpdate( &update, &number)) return (ret);
Clients[i]->AddUpdate(update, number);
}
}
return (UnlockMutex());
}
#define cpy_file_struct( a, b) \
{ \
a.ForceReload = b.ForceReload; \
a.pData = b.pData; \
a.Size = b.Size; \
a.NumberOfTextures = b.NumberOfTextures; \
a.Reference = b.Reference; \
a.Textures = b.Textures; \
a.Hash = b.Hash; }
int TextureFileStruct_Compare( const void * elem1, const void * elem2 )
{
TextureFileStruct *tex1 = (TextureFileStruct*)elem1;
TextureFileStruct *tex2 = (TextureFileStruct*)elem2;
if (tex1->Hash < tex2->Hash) return (-1);
if (tex1->Hash > tex2->Hash) return (+1);
return (0);
}
int uMod_TextureServer::PrepareUpdate(TextureFileStruct** update, int* number) // called from the PropagateUpdate() and AddClient.
// Prepare an update for one client. The allocated memory must deleted by the client.
{
Message("PrepareUpdate(%lu, %d): %lu\n", update, number, this);
TextureFileStruct* temp = NULL;
int num = CurrentMod.GetNumber();
if (num>0)
{
try {temp = new TextureFileStruct[num];}
catch (...)
{
gl_ErrorState |= uMod_ERROR_MEMORY | uMod_ERROR_SERVER;
return (RETURN_NO_MEMORY);
}
for (int i=0; i<num; i++) cpy_file_struct(temp[i], (*(CurrentMod[i])));
qsort( temp, num, sizeof(TextureFileStruct), TextureFileStruct_Compare);
}
*update = temp;
*number = num;
return (RETURN_OK);
}
#undef cpy_file_struct
int uMod_TextureServer::LockMutex(void)
{
if (( gl_ErrorState & (uMod_ERROR_FATAL | uMod_ERROR_MUTEX) )) return (RETURN_NO_MUTEX);
if (WAIT_OBJECT_0!=WaitForSingleObject( Mutex, 100)) return (RETURN_MUTEX_LOCK); //waiting 100ms, to wait infinite pass INFINITE
return (RETURN_OK);
}
int uMod_TextureServer::UnlockMutex(void)
{
if (ReleaseMutex( Mutex) == 0) return (RETURN_MUTEX_UNLOCK);
return (RETURN_OK);
}
int uMod_TextureServer::MainLoop(void) // run as a separated thread
{
Message("MainLoop: begin\n");
if (Pipe.In == INVALID_HANDLE_VALUE) return (RETURN_PIPE_NOT_OPENED);
char *buffer;
try {buffer = new char[BIG_BUFSIZE];}
catch (...) {return (RETURN_NO_MEMORY);}
unsigned long num = 0u;
bool update_textures = false;
unsigned int texture_size = 0u;
unsigned int texture_received = 0u;
char *texture_data = (char*)0;
bool texture_force = false;
MyTypeHash texture_hash = 0u;
Message("MainLoop: started\n");
while (1)
{
Message("MainLoop: run\n");
bool ret = ReadFile(Pipe.In, // pipe handle
buffer, // buffer to receive reply
BIG_BUFSIZE, // size of buffer
&num, // number of bytes read
NULL); // not overlapped
Message("MainLoop: read something (%lu)\n", num);
if (ret || GetLastError() == ERROR_MORE_DATA)
{
unsigned int pos = 0;
MsgStruct *commands;
unsigned int size=0u;
while (pos < num)
{
if (texture_received<texture_size)
{
while (pos<num && texture_received<texture_size) texture_data[texture_received++] = buffer[pos++];
if (texture_received==texture_size)
{
AddFile( texture_data, texture_size, texture_hash, texture_force);
texture_data = (char*)0;
texture_size = 0u;
texture_received = 0u;
}
}
else
{
commands = (MsgStruct*) &buffer[pos];
switch (commands->Control)
{
case CONTROL_END_TEXTURES:
{
Message("MainLoop: CONTROL_END_TEXTURES (): %lu\n", this);
update_textures=true;
break;
}
/*
case CONTROL_FORCE_RELOAD_TEXTURE: force=true;
case CONTROL_ADD_TEXTURE:
{
size = commands->Value;
Message("MainLoop: CONTROL_ADD_TEXTURE (%#lX %u, %u %u): %lu\n", commands->Hash, size, sizeof(MsgStruct), sizeof(char), this);
if (pos + sizeof(MsgStruct) + size <= num) AddFile( (wchar_t*) &buffer[pos + sizeof(MsgStruct)], commands->Hash, force);
//update_textures = true;
force = false;
break;
}
*/
case CONTROL_FORCE_RELOAD_TEXTURE_DATA:
{
texture_size = commands->Value;
texture_received = 0u;
texture_hash = commands->Hash;
texture_force=true;
try
{
texture_data = new char[texture_size];
}
catch (...)
{
texture_size = 0u;
texture_data = (char*)0;
gl_ErrorState |= uMod_ERROR_MEMORY | uMod_ERROR_SERVER;
}
Message("MainLoop: CONTROL_FORCE_RELOAD_TEXTURE_DATA (%#lX %u, %u): %lu\n", texture_hash, texture_size, texture_data, this);
break;
}
case CONTROL_ADD_TEXTURE_DATA:
{
texture_size = commands->Value;
texture_received = 0u;
texture_hash = commands->Hash;
texture_force=true;
try
{
texture_data = new char[texture_size];
}
catch (...)
{
texture_size = 0u;
texture_data = (char*)0;
gl_ErrorState |= uMod_ERROR_MEMORY | uMod_ERROR_SERVER;
}
Message("MainLoop: CONTROL_ADD_TEXTURE_DATA (%#lX %u, %u): %lu\n", texture_hash, texture_size, texture_data, this);
break;
}
case CONTROL_REMOVE_TEXTURE:
{
Message("MainLoop: CONTROL_REMOVE_TEXTURE (%#lX): %lu\n", commands->Hash, this);
RemoveFile(commands->Hash);
//update_textures = true;
break;
}
case CONTROL_SAVE_SINGLE:
{
Message("MainLoop: CONTROL_SAVE_SINGLE (%d): %lu\n", commands->Value, this);
if (commands->Value == 0) SaveSingleTexture(false);
else SaveSingleTexture(true);
break;
}
case CONTROL_SAVE_ALL:
{
Message("MainLoop: CONTROL_SAVE_ALL (%d): %lu\n", commands->Value, this);
if (commands->Value == 0) SaveAllTextures(false);
else SaveAllTextures(true);
break;
}
case CONTROL_SET_DIR:
{
size = commands->Value;
if (pos + sizeof(MsgStruct) +size <= num) SetSaveDirectory( (wchar_t*) &buffer[pos + sizeof(MsgStruct)]);
break;
}
case CONTROL_KEY_BACK:
{
Message("MainLoop: CONTROL_KEY_BACK (%#X): %lu\n", commands->Value, this);
SetKeyBack(commands->Value);
break;
}
case CONTROL_KEY_SAVE:
{
Message("MainLoop: CONTROL_KEY_SAVE (%#X): %lu\n", commands->Value, this);
SetKeySave(commands->Value);
break;
}
case CONTROL_KEY_NEXT:
{
Message("MainLoop: CONTROL_KEY_NEXT (%#X): %lu\n", commands->Value, this);
SetKeyNext(commands->Value);
break;
}
case CONTROL_FONT_COLOUR:
{
Message("MainLoop: CONTROL_FONT_COLOUR (%#X): %lu\n", commands->Value, this);
SetFontColour(commands->Value);
break;
}
case CONTROL_TEXTURE_COLOUR:
{
Message("MainLoop: CONTROL_TEXTURE_COLOUR (%#X): %lu\n", commands->Value, this);
SetTextureColour(commands->Value);
break;
}
default:
{
Message("MainLoop: DEFAULT: %lu %lu %#lX\n", commands->Control, commands->Value, commands->Hash, this);
break;
}
}
pos += sizeof(MsgStruct) + size;
}
}
if (update_textures) {PropagateUpdate(); update_textures=false;}
}
else
{
Message("MainLoop: error in ReadFile()\n");
delete [] buffer;
ClosePipe();
return (RETURN_OK);
}
}
delete [] buffer;
return (RETURN_OK);
}
int uMod_TextureServer::OpenPipe(wchar_t *game) // called from InitInstance()
{
Message("OpenPipe: Out\n")
// open first outgoing pipe !!
Pipe.Out = CreateFileW(PIPE_Game2uMod, // pipe name
GENERIC_WRITE, // write access
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
// Exit if an error other than ERROR_PIPE_BUSY occurs.
if (Pipe.Out == INVALID_HANDLE_VALUE) return (RETURN_PIPE_NOT_OPENED);
unsigned int len = 0u;
while (game[len]) len++;
len++; //to send also the zero
unsigned long num;
//send name of this game to uMod_GUI
WriteFile(Pipe.Out, (const void*) game, len * sizeof(wchar_t), &num, NULL);
// now we can open the pipe for reading
Message("OpenPipe: In\n");
Pipe.In = CreateFileW(PIPE_uMod2Game, // pipe name
GENERIC_READ, // read access
0, // no sharing
NULL, // default security attributes
OPEN_EXISTING, // opens existing pipe
0, // default attributes
NULL); // no template file
if (Pipe.In == INVALID_HANDLE_VALUE)
{
CloseHandle(Pipe.In);
Pipe.In = INVALID_HANDLE_VALUE;
return (RETURN_PIPE_NOT_OPENED);
}
Message("OpenPipe: Done\n");
return (RETURN_OK);
}
int uMod_TextureServer::ClosePipe(void) //called from ExitInstance, this must be done, otherwise the Mainloop will wait endless on the ReadFile()
{
Message("ClosePipe:\n");
// We close the outgoing pipe first.
// The GUI will notice that the opposite side of it incoming pipe is closed
// and closes it outgoing (our incoming) pipe and thus cancel the ReadFile() in the Mainloop()
if (Pipe.Out != INVALID_HANDLE_VALUE)
{
DisconnectNamedPipe(Pipe.Out);
CloseHandle(Pipe.Out);
Pipe.Out = INVALID_HANDLE_VALUE;
}
if (Pipe.In != INVALID_HANDLE_VALUE)
{
DisconnectNamedPipe(Pipe.In);
CloseHandle(Pipe.In);
Pipe.In = INVALID_HANDLE_VALUE;
}
return (RETURN_OK);
}
+110
View File
@@ -0,0 +1,110 @@
/*
This file is part of Universal Modding Engine.
Universal Modding Engine is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Universal Modding Engine is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Universal Modding Engine. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef uMod_TEXTURESERVER_H_
#define uMod_TEXTURESERVER_H_
#include "../uMod_GlobalDefines.h"
#include "uMod_ArrayHandler.h"
/*
* An object of this class is created only once.
* The Mainloop functions is executed by a server thread,
* which listen on a pipe.
*
* Functions called by the Client are called from the a thread instance of the game itself.
* Nearly all other functions are called from the server thread instance.
*/
class uMod_TextureClient;
class uMod_TextureServer
{
public:
uMod_TextureServer(wchar_t *name);
~uMod_TextureServer(void);
int AddClient(uMod_TextureClient *client, TextureFileStruct** update, int* number); // called from a Client
int RemoveClient(uMod_TextureClient *client); // called from a Client
int OpenPipe(wchar_t *name); // called on initialization of our d3d9 fake dll
int ClosePipe(void); // called on exit of our d3d9 fake dll
int MainLoop(void); // is executed in a server thread
// following functions are only public for testing purpose !!
// they should be private and only be called from the Mainloop
int AddFile( char* buffer, unsigned int size, MyTypeHash hash, bool force); // called from Mainloop(), if the content of the texture is sent
int AddFile( wchar_t* file_name, MyTypeHash hash, bool force); // called from Mainloop(), if the name and the path to the file is sent
int RemoveFile( MyTypeHash hash); // called from Mainloop()
int SaveAllTextures(bool val); // called from Mainloop()
int SaveSingleTexture(bool val); // called from Mainloop()
int SetSaveDirectory( wchar_t *dir); // called from Mainloop()
int SetKeyBack( int key); // called from Mainloop()
int SetKeySave( int key); // called from Mainloop()
int SetKeyNext( int key); // called from Mainloop()
int SetFontColour(DWORD colour); // called from Mainloop()
int SetTextureColour(DWORD colour); // called from Mainloop()
private:
bool BoolSaveAllTextures;
bool BoolSaveSingleTexture;
wchar_t SavePath[MAX_PATH];
wchar_t GameName[MAX_PATH];
int PropagateUpdate(uMod_TextureClient* client=NULL); // called from Mainloop() if texture are loaded or removed
int PrepareUpdate(TextureFileStruct** update, int* number); // called from PropagateUpdate() and AddClient()
// generate a copy of the current texture to be modded
// the file content of the textures are not copied, the clients get the pointer to the file content
// but the arrays allocate by this function, must be deleted by the client
int LockMutex();
int UnlockMutex();
HANDLE Mutex;
int KeyBack;
int KeySave;
int KeyNext;
DWORD FontColour;
DWORD TextureColour;
PipeStruct Pipe;
uMod_TextureClient** Clients;
int NumberOfClients;
int LenghtOfClients;
uMod_FileHandler CurrentMod; // hold the file content of texture
uMod_FileHandler OldMod; // hold the file content of texture which were added previously but are not needed any more
// this is needed, because a texture clients might not have merged the last update and thus hold pointers to the file content of old textures
};
#endif /* uMod_TEXTURESERVER_H_ */