Refactored BitmapImageSource (moved core functionality into a new class - BitmapImage). Changed BitmapTransitionSource to use BitmapImage - implements #102

master
HomeWorld 2014-02-08 14:40:00 +02:00
parent 6a46761c3c
commit 96e400fd91
6 changed files with 373 additions and 306 deletions

View File

@ -62,7 +62,8 @@
<WindowsSDK80Path Condition="('$(WindowsSDK80Path)'=='')And(!Exists('C:\Program Files (x86)\Windows Kits\8.0\'))">$(WindowsSdkDir)</WindowsSDK80Path>
</PropertyGroup>
<PropertyGroup Label="MSBuild Dynamic Preprocessor Definitions">
<DynamicDefines> </DynamicDefines>
<DynamicDefines>
</DynamicDefines>
</PropertyGroup>
<PropertyGroup>
<_ProjectFileVersion>10.0.30319.1</_ProjectFileVersion>
@ -252,6 +253,7 @@
<ItemGroup>
<ClCompile Include="Source\API.cpp" />
<ClCompile Include="Source\BandwidthAnalysis.cpp" />
<ClCompile Include="Source\BitmapImage.cpp" />
<ClCompile Include="Source\BitmapImageSource.cpp" />
<ClCompile Include="Source\BitmapTransitionSource.cpp" />
<ClCompile Include="Source\BlankAudioPlayback.cpp" />
@ -300,6 +302,7 @@
<ClCompile Include="Source\WindowStuff.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="Source\BitmapImage.h" />
<ClInclude Include="Source\CodeTokenizer.h" />
<ClInclude Include="Source\CrashDumpHandler.h" />
<ClInclude Include="Source\D3D10System.h" />

View File

@ -145,6 +145,9 @@
<ClCompile Include="Source\Encoder_NVENC.cpp">
<Filter>Source</Filter>
</ClCompile>
<ClCompile Include="Source\BitmapImage.cpp">
<Filter>Source</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="Source\D3D10System.h">
@ -186,6 +189,9 @@
<ClInclude Include="Source\Settings.h">
<Filter>Headers</Filter>
</ClInclude>
<ClInclude Include="Source\BitmapImage.h">
<Filter>Headers</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<None Include="cursor1.cur">

284
Source/BitmapImage.cpp Normal file
View File

@ -0,0 +1,284 @@
#include "BitmapImage.h"
void *BI_def_bitmap_create(int width, int height) {return Allocate(width * height * 4);}
void BI_def_bitmap_set_opaque(void *bitmap, BOOL opaque) {}
BOOL BI_def_bitmap_test_opaque(void *bitmap) {return false;}
unsigned char *BI_def_bitmap_get_buffer(void *bitmap) {return (unsigned char*)bitmap;}
void BI_def_bitmap_destroy(void *bitmap) {Free(bitmap);}
void BI_def_bitmap_modified(void *bitmap) {}
BitmapImage::BitmapImage()
{
bitmap_callbacks.bitmap_create = BI_def_bitmap_create;
bitmap_callbacks.bitmap_destroy = BI_def_bitmap_destroy;
bitmap_callbacks.bitmap_get_buffer = BI_def_bitmap_get_buffer;
bitmap_callbacks.bitmap_modified = BI_def_bitmap_modified;
bitmap_callbacks.bitmap_set_opaque = BI_def_bitmap_set_opaque;
bitmap_callbacks.bitmap_test_opaque = BI_def_bitmap_test_opaque;
}
BitmapImage::~BitmapImage()
{
if(bIsAnimatedGif)
{
gif_finalise(&gif);
Free(animationFrameCache);
Free(animationFrameData);
}
if(lpGifData)
Free(lpGifData);
EnableFileMonitor(false);
delete texture;
}
//----------------------------------------------------------------------------
void BitmapImage::CreateErrorTexture(void)
{
LPBYTE textureData = (LPBYTE)Allocate(32*32*4);
msetd(textureData, 0xFF0000FF, 32*32*4);
texture = CreateTexture(32, 32, GS_RGB, textureData, FALSE);
fullSize.Set(32.0f, 32.0f);
Free(textureData);
}
//----------------------------------------------------------------------------
void BitmapImage::SetPath(String path)
{
filePath = path;
}
void BitmapImage::EnableFileMonitor(bool bMonitor)
{
if (changeMonitor)
{
OSMonitorFileDestroy(changeMonitor);
changeMonitor = NULL;
}
if (bMonitor)
changeMonitor = OSMonitorFileStart(filePath);
}
void BitmapImage::Init(void)
{
if(bIsAnimatedGif)
{
bIsAnimatedGif = false;
gif_finalise(&gif);
Free(animationFrameCache);
animationFrameCache = NULL;
Free(animationFrameData);
animationFrameData = NULL;
}
if(lpGifData)
{
Free(lpGifData);
lpGifData = NULL;
}
animationTimes.Clear();
delete texture;
texture = NULL;
CTSTR lpBitmap = filePath;
if(!lpBitmap || !*lpBitmap)
{
AppWarning(TEXT("BitmapImage::Init: Empty path"));
CreateErrorTexture();
return;
}
//------------------------------------
if(GetPathExtension(lpBitmap).CompareI(TEXT("gif")))
{
bool bFail = false;
gif_create(&gif, &bitmap_callbacks);
XFile gifFile;
if(!gifFile.Open(lpBitmap, XFILE_READ, XFILE_OPENEXISTING))
{
AppWarning(TEXT("BitmapImage::Init: could not open gif file '%s'"), lpBitmap);
CreateErrorTexture();
return;
}
DWORD fileSize = (DWORD)gifFile.GetFileSize();
lpGifData = (LPBYTE)Allocate(fileSize);
gifFile.Read(lpGifData, fileSize);
gif_result result;
do
{
result = gif_initialise(&gif, fileSize, lpGifData);
if(result != GIF_OK && result != GIF_WORKING)
{
bFail = true;
break;
}
}while(result != GIF_OK);
if(gif.frame_count > 1)
{
if(result == GIF_OK || result == GIF_WORKING)
bIsAnimatedGif = true;
}
if(bIsAnimatedGif)
{
gif_decode_frame(&gif, 0);
texture = CreateTexture(gif.width, gif.height, GS_RGBA, gif.frame_image, FALSE, FALSE);
animationFrameCache = (BYTE **)Allocate(gif.frame_count * sizeof(BYTE *));
memset(animationFrameCache, 0, gif.frame_count * sizeof(BYTE *));
animationFrameData = (BYTE *)Allocate(gif.frame_count * gif.width * gif.height * 4);
memset(animationFrameData, 0, gif.frame_count * gif.width * gif.height * 4);
for(UINT i=0; i<gif.frame_count; i++)
{
float frameTime = float(gif.frames[i].frame_delay)*0.01f;
if (frameTime == 0.0f)
frameTime = 0.1f;
animationTimes << frameTime;
if (gif_decode_frame(&gif, i) != GIF_OK)
Log (TEXT("BitmapImage: Warning, couldn't decode frame %d of %s"), i, lpBitmap);
}
gif_decode_frame(&gif, 0);
fullSize.x = float(gif.width);
fullSize.y = float(gif.height);
curTime = 0.0f;
curFrame = 0;
lastDecodedFrame = 0;
}
else
{
gif_finalise(&gif);
Free(lpGifData);
lpGifData = NULL;
}
}
if(!bIsAnimatedGif)
{
texture = GS->CreateTextureFromFile(lpBitmap, TRUE);
if(!texture)
{
AppWarning(TEXT("BitmapImage::Init: could not create texture '%s'"), lpBitmap);
CreateErrorTexture();
return;
}
fullSize.x = float(texture->Width());
fullSize.y = float(texture->Height());
}
}
Vect2 BitmapImage::GetSize(void) const
{
return fullSize;
}
Texture* BitmapImage::GetTexture(void) const
{
return texture;
}
void BitmapImage::Tick(float fSeconds)
{
if(bIsAnimatedGif)
{
UINT totalLoops = (UINT)gif.loop_count;
if(totalLoops >= 0xFFFF)
totalLoops = 0;
if(!totalLoops || curLoop < totalLoops)
{
UINT newFrame = curFrame;
curTime += fSeconds;
while(curTime > animationTimes[newFrame])
{
curTime -= animationTimes[newFrame];
if(++newFrame == animationTimes.Num())
{
if(!totalLoops || ++curLoop < totalLoops)
newFrame = 0;
else if (curLoop == totalLoops)
{
newFrame--;
break;
}
}
}
if(newFrame != curFrame)
{
UINT lastFrame;
if (!animationFrameCache[newFrame])
{
//animation might have looped, if so make sure we decode from frame 0
if (newFrame < lastDecodedFrame)
lastFrame = 0;
else
lastFrame = lastDecodedFrame + 1;
//we need to decode any frames we missed for consistency
for (UINT i = lastFrame; i < newFrame; i++)
{
if (gif_decode_frame(&gif, i) != GIF_OK)
return;
}
//now decode and display the actual frame we want
int ret = gif_decode_frame(&gif, newFrame);
if (ret == GIF_OK)
{
animationFrameCache[newFrame] = animationFrameData + (newFrame * (gif.width * gif.height * 4));
memcpy(animationFrameCache[newFrame], gif.frame_image, gif.width * gif.height * 4);
}
lastDecodedFrame = newFrame;
}
if (animationFrameCache[newFrame])
texture->SetImage(animationFrameCache[newFrame], GS_IMAGEFORMAT_RGBA, gif.width*4);
curFrame = newFrame;
}
}
}
if (updateImageTime)
{
updateImageTime -= fSeconds;
if (updateImageTime <= 0.0f)
{
updateImageTime = 0.0f;
Init();
}
}
if (changeMonitor && OSFileHasChanged(changeMonitor))
updateImageTime = 1.0f;
}

40
Source/BitmapImage.h Normal file
View File

@ -0,0 +1,40 @@
#pragma once
#include "Main.h"
#include "libnsgif.h"
class BitmapImage{
Texture *texture;
Vect2 fullSize;
bool bIsAnimatedGif;
gif_animation gif;
LPBYTE lpGifData;
List<float> animationTimes;
BYTE **animationFrameCache;
BYTE *animationFrameData;
UINT curFrame, curLoop, lastDecodedFrame;
float curTime;
float updateImageTime;
String filePath;
OSFileChangeData *changeMonitor;
gif_bitmap_callback_vt bitmap_callbacks;
void CreateErrorTexture(void);
public:
BitmapImage();
~BitmapImage();
void SetPath(String path);
void EnableFileMonitor(bool bMonitor);
void Init(void);
Vect2 GetSize(void) const;
Texture* GetTexture(void) const;
void Tick(float fSeconds);
};

View File

@ -18,16 +18,9 @@
#include "Main.h"
#include "libnsgif.h"
#include "BitmapImage.h"
void *def_bitmap_create(int width, int height) {return Allocate(width * height * 4);}
void def_bitmap_set_opaque(void *bitmap, BOOL opaque) {}
BOOL def_bitmap_test_opaque(void *bitmap) {return false;}
unsigned char *def_bitmap_get_buffer(void *bitmap) {return (unsigned char*)bitmap;}
void def_bitmap_destroy(void *bitmap) {Free(bitmap);}
void def_bitmap_modified(void *bitmap) {return;}
struct ColorSelectionData
{
HDC hdcDesktop;
@ -121,22 +114,11 @@ struct ConfigDesktopSourceInfo
StringList strClasses;
};
gif_bitmap_callback_vt bitmap_callbacks =
{
def_bitmap_create,
def_bitmap_destroy,
def_bitmap_get_buffer,
def_bitmap_set_opaque,
def_bitmap_test_opaque,
def_bitmap_modified
};
class BitmapImageSource : public ImageSource
{
Texture *texture;
BitmapImage bitmapImage;
Vect2 fullSize;
XElement *data;
bool bUseColorKey;
@ -146,35 +128,14 @@ class BitmapImageSource : public ImageSource
DWORD opacity;
DWORD color;
bool bIsAnimatedGif;
gif_animation gif;
LPBYTE lpGifData;
List<float> animationTimes;
BYTE **animationFrameCache;
BYTE *animationFrameData;
UINT curFrame, curLoop, lastDecodedFrame;
float curTime;
float updateImageTime;
Shader *colorKeyShader, *alphaIgnoreShader;
OSFileChangeData *changeMonitor;
void CreateErrorTexture()
{
LPBYTE textureData = (LPBYTE)Allocate(32*32*4);
msetd(textureData, 0xFF0000FF, 32*32*4);
texture = CreateTexture(32, 32, GS_RGB, textureData, FALSE);
fullSize.Set(32.0f, 32.0f);
Free(textureData);
}
public:
BitmapImageSource(XElement *data)
{
//EnableMemoryTracking(true);
this->data = data;
UpdateSettings();
colorKeyShader = CreatePixelShaderFromFile(TEXT("shaders\\ColorKey_RGB.pShader"));
@ -185,107 +146,19 @@ public:
~BitmapImageSource()
{
if(bIsAnimatedGif)
{
gif_finalise(&gif);
Free(animationFrameCache);
Free(animationFrameData);
}
if(lpGifData)
Free(lpGifData);
delete colorKeyShader;
delete alphaIgnoreShader;
if (changeMonitor)
OSMonitorFileDestroy(changeMonitor);
delete texture;
}
void Tick(float fSeconds)
{
if(bIsAnimatedGif)
{
UINT totalLoops = (UINT)gif.loop_count;
if(totalLoops >= 0xFFFF)
totalLoops = 0;
if(!totalLoops || curLoop < totalLoops)
{
UINT newFrame = curFrame;
curTime += fSeconds;
while(curTime > animationTimes[newFrame])
{
curTime -= animationTimes[newFrame];
if(++newFrame == animationTimes.Num())
{
if(!totalLoops || ++curLoop < totalLoops)
newFrame = 0;
else if (curLoop == totalLoops)
{
newFrame--;
break;
}
}
}
if(newFrame != curFrame)
{
UINT lastFrame;
if (!animationFrameCache[newFrame])
{
//animation might have looped, if so make sure we decode from frame 0
if (newFrame < lastDecodedFrame)
lastFrame = 0;
else
lastFrame = lastDecodedFrame + 1;
//we need to decode any frames we missed for consistency
for (UINT i = lastFrame; i < newFrame; i++)
{
if (gif_decode_frame(&gif, i) != GIF_OK)
return;
}
//now decode and display the actual frame we want
int ret = gif_decode_frame(&gif, newFrame);
if (ret == GIF_OK)
{
animationFrameCache[newFrame] = animationFrameData + (newFrame * (gif.width * gif.height * 4));
memcpy(animationFrameCache[newFrame], gif.frame_image, gif.width * gif.height * 4);
}
lastDecodedFrame = newFrame;
}
if (animationFrameCache[newFrame])
texture->SetImage(animationFrameCache[newFrame], GS_IMAGEFORMAT_RGBA, gif.width*4);
curFrame = newFrame;
}
}
}
if (updateImageTime)
{
updateImageTime -= fSeconds;
if (updateImageTime <= 0.0f)
{
updateImageTime = 0.0f;
UpdateSettings();
}
}
if (changeMonitor && OSFileHasChanged(changeMonitor))
updateImageTime = 1.0f;
bitmapImage.Tick(fSeconds);
}
void Render(const Vect2 &pos, const Vect2 &size)
{
Texture *texture = bitmapImage.GetTexture();
if(texture)
{
if(bUseColorKey)
@ -316,126 +189,9 @@ public:
void UpdateSettings()
{
if(bIsAnimatedGif)
{
bIsAnimatedGif = false;
gif_finalise(&gif);
Free(animationFrameCache);
animationFrameCache = NULL;
Free(animationFrameData);
animationFrameData = NULL;
}
if(lpGifData)
{
Free(lpGifData);
lpGifData = NULL;
}
animationTimes.Clear();
delete texture;
texture = NULL;
CTSTR lpBitmap = data->GetString(TEXT("path"));
if(!lpBitmap || !*lpBitmap)
{
AppWarning(TEXT("BitmapImageSource::UpdateSettings: Empty path"));
CreateErrorTexture();
return;
}
//------------------------------------
if(GetPathExtension(lpBitmap).CompareI(TEXT("gif")))
{
bool bFail = false;
gif_create(&gif, &bitmap_callbacks);
XFile gifFile;
if(!gifFile.Open(lpBitmap, XFILE_READ, XFILE_OPENEXISTING))
{
AppWarning(TEXT("BitmapImageSource::UpdateSettings: could not open gif file '%s'"), lpBitmap);
CreateErrorTexture();
return;
}
DWORD fileSize = (DWORD)gifFile.GetFileSize();
lpGifData = (LPBYTE)Allocate(fileSize);
gifFile.Read(lpGifData, fileSize);
gif_result result;
do
{
result = gif_initialise(&gif, fileSize, lpGifData);
if(result != GIF_OK && result != GIF_WORKING)
{
bFail = true;
break;
}
}while(result != GIF_OK);
if(gif.frame_count > 1)
{
if(result == GIF_OK || result == GIF_WORKING)
bIsAnimatedGif = true;
}
if(bIsAnimatedGif)
{
gif_decode_frame(&gif, 0);
texture = CreateTexture(gif.width, gif.height, GS_RGBA, gif.frame_image, FALSE, FALSE);
animationFrameCache = (BYTE **)Allocate(gif.frame_count * sizeof(BYTE *));
memset(animationFrameCache, 0, gif.frame_count * sizeof(BYTE *));
animationFrameData = (BYTE *)Allocate(gif.frame_count * gif.width * gif.height * 4);
memset(animationFrameData, 0, gif.frame_count * gif.width * gif.height * 4);
for(UINT i=0; i<gif.frame_count; i++)
{
float frameTime = float(gif.frames[i].frame_delay)*0.01f;
if (frameTime == 0.0f)
frameTime = 0.1f;
animationTimes << frameTime;
if (gif_decode_frame(&gif, i) != GIF_OK)
Log (TEXT("BitmapImageSource: Warning, couldn't decode frame %d of %s"), i, data->GetString(TEXT("path")));
}
gif_decode_frame(&gif, 0);
fullSize.x = float(gif.width);
fullSize.y = float(gif.height);
curTime = 0.0f;
curFrame = 0;
lastDecodedFrame = 0;
}
else
{
gif_finalise(&gif);
Free(lpGifData);
lpGifData = NULL;
}
}
if(!bIsAnimatedGif)
{
texture = GS->CreateTextureFromFile(lpBitmap, TRUE);
if(!texture)
{
AppWarning(TEXT("BitmapImageSource::UpdateSettings: could not create texture '%s'"), lpBitmap);
CreateErrorTexture();
return;
}
fullSize.x = float(texture->Width());
fullSize.y = float(texture->Height());
}
bitmapImage.SetPath(data->GetString(TEXT("path")));
bitmapImage.EnableFileMonitor(data->GetInt(TEXT("monitor"), 0) == 1);
bitmapImage.Init();
//------------------------------------
@ -444,16 +200,6 @@ public:
if(opacity > 100)
opacity = 100;
if (changeMonitor)
{
OSMonitorFileDestroy(changeMonitor);
changeMonitor = NULL;
}
int monitor = data->GetInt(TEXT("monitor"), 0);
if (monitor)
changeMonitor = OSMonitorFileStart(lpBitmap);
bool bNewUseColorKey = data->GetInt(TEXT("useColorKey"), 0) != 0;
keyColor = data->GetInt(TEXT("keyColor"), 0xFFFFFFFF);
keySimilarity = data->GetInt(TEXT("keySimilarity"), 10);
@ -462,7 +208,7 @@ public:
bUseColorKey = bNewUseColorKey;
}
Vect2 GetSize() const {return fullSize;}
Vect2 GetSize() const {return bitmapImage.GetSize();}
};

View File

@ -20,6 +20,8 @@
#include "Main.h"
#include <time.h>
#include "BitmapImage.h"
#define MIN_TRANSITION_TIME 3
#define MAX_TRANSITION_TIME 600
@ -29,7 +31,7 @@ extern "C" double round(double val);
class BitmapTransitionSource : public ImageSource
{
List<Texture*> textures;
List<BitmapImage*> bitmapImages;
Vect2 fullSize;
double baseAspect;
@ -55,17 +57,6 @@ class BitmapTransitionSource : public ImageSource
return int( ( (double)rand() / (RAND_MAX + 1) ) * limit );
}
void CreateErrorTexture()
{
LPBYTE textureData = (LPBYTE)Allocate(32*32*4);
msetd(textureData, 0xFF0000FF, 32*32*4);
textures << CreateTexture(32, 32, GS_RGB, textureData, FALSE);
fullSize.Set(32.0f, 32.0f);
Free(textureData);
}
public:
BitmapTransitionSource(XElement *data)
{
@ -76,13 +67,16 @@ public:
~BitmapTransitionSource()
{
for(UINT i=0; i<textures.Num(); i++)
delete textures[i];
for(UINT i=0; i<bitmapImages.Num(); i++)
delete bitmapImages[i];
}
void Tick(float fSeconds)
{
if(bTransitioning && textures.Num() > 1)
for(UINT i=0; i<bitmapImages.Num(); i++)
bitmapImages[i]->Tick(fSeconds);
if(bTransitioning && bitmapImages.Num() > 1)
{
if(bDisableFading)
curFadeValue = fadeTime;
@ -97,14 +91,14 @@ public:
if(bRandomize)
{
curTexture = nextTexture;
while((nextTexture = lrand(textures.Num())) == curTexture);
while((nextTexture = lrand(bitmapImages.Num())) == curTexture);
}
else
{
if(++curTexture == textures.Num())
if(++curTexture == bitmapImages.Num())
curTexture = 0;
nextTexture = (curTexture == textures.Num()-1) ? 0 : curTexture+1;
nextTexture = (curTexture == bitmapImages.Num()-1) ? 0 : curTexture+1;
}
}
}
@ -126,7 +120,7 @@ public:
Vect2 pos = Vect2(0.0f, 0.0f);
Vect2 size = fullSize;
Vect2 itemSize = Vect2((float)textures[texID]->Width(), (float)textures[texID]->Height());
Vect2 itemSize = bitmapImages[texID]->GetSize();
double sourceAspect = double(itemSize.x)/double(itemSize.y);
if(!CloseDouble(baseAspect, sourceAspect))
@ -151,14 +145,14 @@ public:
Vect2 lr;
lr = pos + (size/fullSize*startSize);
DrawSprite(textures[texID], (curAlpha<<24) | 0xFFFFFF, pos.x, pos.y, lr.x, lr.y);
DrawSprite(bitmapImages[texID]->GetTexture(), (curAlpha<<24) | 0xFFFFFF, pos.x, pos.y, lr.x, lr.y);
}
void Render(const Vect2 &pos, const Vect2 &size)
{
if(textures.Num())
if(bitmapImages.Num())
{
if(bTransitioning && textures.Num() > 1)
if(bTransitioning && bitmapImages.Num() > 1)
{
float curAlpha = MIN(curFadeValue/fadeTime, 1.0f);
if(bFadeInOnly)
@ -175,9 +169,9 @@ public:
void UpdateSettings()
{
for(UINT i=0; i<textures.Num(); i++)
delete textures[i];
textures.Clear();
for(UINT i=0; i<bitmapImages.Num(); i++)
delete bitmapImages[i];
bitmapImages.Clear();
//------------------------------------
@ -194,27 +188,21 @@ public:
continue;
}
Texture *texture = GS->CreateTextureFromFile(strBitmap, TRUE);
if(!texture)
{
AppWarning(TEXT("BitmapTransitionSource::UpdateSettings: could not create texture '%s'"), strBitmap.Array());
continue;
}
BitmapImage *bitmapImage = new BitmapImage;
bitmapImage->SetPath(strBitmap);
bitmapImage->EnableFileMonitor(false);
bitmapImage->Init();
if(bFirst)
{
fullSize.x = float(texture->Width());
fullSize.y = float(texture->Height());
fullSize = bitmapImage->GetSize();
baseAspect = double(fullSize.x)/double(fullSize.y);
bFirst = false;
}
textures << texture;
bitmapImages << bitmapImage;
}
if(textures.Num() == 0)
CreateErrorTexture();
//------------------------------------
transitionTime = data->GetFloat(TEXT("transitionTime"));
@ -237,14 +225,14 @@ public:
if(bRandomize)
{
srand( (unsigned)time( NULL ) );
if(textures.Num() > 1)
if(bitmapImages.Num() > 1)
{
curTexture = lrand(textures.Num());
while((nextTexture = lrand(textures.Num())) == curTexture);
curTexture = lrand(bitmapImages.Num());
while((nextTexture = lrand(bitmapImages.Num())) == curTexture);
}
}
else
nextTexture = (curTexture == textures.Num()-1) ? 0 : curTexture+1;
nextTexture = (curTexture == bitmapImages.Num()-1) ? 0 : curTexture+1;
bTransitioning = false;
curFadeValue = 0.0f;