Merge remote-tracking branch 'origin/master'

This commit is contained in:
jacob1 2012-12-06 11:01:46 -05:00
commit 122599763e
16 changed files with 260 additions and 45 deletions

View File

@ -11,8 +11,10 @@
#ifdef WIN
#define PATH_SEP "\\"
#define PATH_SEP_CHAR '\\'
#else
#define PATH_SEP "/"
#define PATH_SEP_CHAR '/'
#endif
//VersionInfoStart
@ -25,7 +27,7 @@
#endif
#ifndef BUILD_NUM
#define BUILD_NUM 249
#define BUILD_NUM 250
#endif
#ifndef SNAPSHOT_ID
@ -91,6 +93,8 @@
#define STAMPS_DIR "stamps"
#define BRUSH_DIR "Brushes"
#define APPDATA_SUBDIR "\\HardWIRED"
//Number of unique thumbnails to have in cache at one time

View File

@ -26,6 +26,13 @@ static char hex[] = "0123456789ABCDEF";
char *exe_name(void);
//Linear interpolation
template <typename T> inline T LinearInterpolate(T val1, T val2, T lowerCoord, T upperCoord, T coord)
{
if(lowerCoord == upperCoord) return val1;
return (((val2 - val1) / (upperCoord - lowerCoord)) * (coord - lowerCoord)) + val1;
}
//Signum function
int isign(float i);

View File

@ -140,7 +140,7 @@ void Client::Initialise(std::string proxyString)
stampsLib.close();
//Begin version check
versionCheckRequest = http_async_req_start(NULL, SERVER "/Startup.json", NULL, 0, 1);
versionCheckRequest = http_async_req_start(NULL, SERVER "/Startup.json", NULL, 0, 0);
if(authUser.ID)
{
@ -367,6 +367,9 @@ std::vector<std::string> Client::DirectorySearch(std::string directory, std::str
std::vector<std::string> Client::DirectorySearch(std::string directory, std::string search, std::vector<std::string> extensions)
{
//Get full file listing
//Normalise directory string, ensure / or \ is present
if(*directory.rbegin() != '/' && *directory.rbegin() != '\\')
directory += PATH_SEP;
std::vector<std::string> directoryList;
#if defined(WIN) && !defined(__GNUC__)
//Windows
@ -717,6 +720,7 @@ void Client::WritePrefs()
void Client::Shutdown()
{
ThumbnailBroker::Ref().Shutdown();
ClearThumbnailRequests();
http_done();
@ -1824,7 +1828,7 @@ Thumbnail * Client::GetThumbnail(int saveID, int saveDate)
{
if(!activeThumbRequests[i])
{
activeThumbRequests[i] = http_async_req_start(NULL, (char *)urlStream.str().c_str(), NULL, 0, 1);
activeThumbRequests[i] = http_async_req_start(NULL, (char *)urlStream.str().c_str(), NULL, 0, 0);
activeThumbRequestTimes[i] = currentTime;
activeThumbRequestCompleteTimes[i] = 0;
activeThumbRequestIDs[i] = idString;

View File

@ -19,6 +19,9 @@ ThumbnailBroker::ThumbnailBroker()
//listenersMutex = PTHREAD_MUTEX_INITIALIZER;
pthread_mutex_init (&listenersMutex, NULL);
pthread_mutex_init (&runningMutex, NULL);
}
ThumbnailBroker::~ThumbnailBroker()
@ -26,6 +29,45 @@ ThumbnailBroker::~ThumbnailBroker()
}
void ThumbnailBroker::assureRunning()
{
pthread_mutex_lock(&runningMutex);
bool running = thumbnailQueueRunning;
thumbnailQueueRunning = true;
pthread_mutex_unlock(&runningMutex);
if(!running)
{
#ifdef DEBUG
std::cout << typeid(*this).name() << " Starting background thread for new " << __FUNCTION__ << " request" << std::endl;
#endif
pthread_create(&thumbnailQueueThread, 0, &ThumbnailBroker::thumbnailQueueProcessHelper, this);
}
}
void ThumbnailBroker::Shutdown()
{
pthread_mutex_lock(&runningMutex);
if(thumbnailQueueRunning)
{
thumbnailQueueRunning = false;
pthread_mutex_unlock(&runningMutex);
pthread_join(thumbnailQueueThread, NULL);
}
else
pthread_mutex_unlock(&runningMutex);
for (std::list<ThumbnailRequest>::iterator iter = currentRequests.begin(), end = currentRequests.end(); iter != end; ++iter)
{
ThumbnailRequest req = *iter;
if(req.HTTPContext)
{
http_async_req_close(req.HTTPContext);
}
}
}
void ThumbnailBroker::RenderThumbnail(GameSave * gameSave, int width, int height, ThumbnailListener * tListener)
{
RenderThumbnail(gameSave, true, true, width, height, tListener);
@ -35,36 +77,20 @@ void ThumbnailBroker::RenderThumbnail(GameSave * gameSave, bool decorations, boo
{
AttachThumbnailListener(tListener);
pthread_mutex_lock(&thumbnailQueueMutex);
bool running = thumbnailQueueRunning;
thumbnailQueueRunning = true;
renderRequests.push_back(ThumbRenderRequest(new GameSave(*gameSave), decorations, fire, width, height, ListenerHandle(tListener->ListenerRand, tListener)));
pthread_mutex_unlock(&thumbnailQueueMutex);
if(!running)
{
#ifdef DEBUG
std::cout << typeid(*this).name() << " Starting background thread for new " << __FUNCTION__ << " request" << std::endl;
#endif
pthread_create(&thumbnailQueueThread, 0, &ThumbnailBroker::thumbnailQueueProcessHelper, this);
}
assureRunning();
}
void ThumbnailBroker::RetrieveThumbnail(int saveID, int saveDate, int width, int height, ThumbnailListener * tListener)
{
AttachThumbnailListener(tListener);
pthread_mutex_lock(&thumbnailQueueMutex);
bool running = thumbnailQueueRunning;
thumbnailQueueRunning = true;
thumbnailRequests.push_back(ThumbnailRequest(saveID, saveDate, width, height, ListenerHandle(tListener->ListenerRand, tListener)));
pthread_mutex_unlock(&thumbnailQueueMutex);
if(!running)
{
#ifdef DEBUG
std::cout << typeid(*this).name() << " Starting background thread for new " << __FUNCTION__ << " request" << std::endl;
#endif
pthread_create(&thumbnailQueueThread, 0, &ThumbnailBroker::thumbnailQueueProcessHelper, this);
}
assureRunning();
}
void * ThumbnailBroker::thumbnailQueueProcessHelper(void * ref)
@ -97,17 +123,33 @@ void ThumbnailBroker::FlushThumbQueue()
void ThumbnailBroker::thumbnailQueueProcessTH()
{
time_t lastAction = time(NULL);
pthread_mutex_lock(&runningMutex);
thumbnailQueueRunning = true;
pthread_mutex_unlock(&runningMutex);
while(true)
{
//Shutdown after 2 seconds of idle
if(time(NULL) - lastAction > 2)
{
pthread_mutex_lock(&thumbnailQueueMutex);
thumbnailQueueRunning = false;
pthread_mutex_unlock(&thumbnailQueueMutex);
#ifdef DEBUG
std::cout << typeid(*this).name() << " Idle shutdown" << std::endl;
#endif
break;
}
pthread_mutex_lock(&runningMutex);
bool running = thumbnailQueueRunning;
pthread_mutex_unlock(&runningMutex);
if(!running)
{
#ifdef DEBUG
std::cout << typeid(*this).name() << " Requested shutdown" << std::endl;
#endif
break;
}
//Renderer
pthread_mutex_lock(&thumbnailQueueMutex);
if(renderRequests.size())
@ -220,7 +262,7 @@ void ThumbnailBroker::thumbnailQueueProcessTH()
std::cout << typeid(*this).name() << " Creating new request for " << req.ID.SaveID << ":" << req.ID.SaveDate << std::endl;
#endif
req.HTTPContext = http_async_req_start(NULL, (char *)urlStream.str().c_str(), NULL, 0, 1);
req.HTTPContext = http_async_req_start(NULL, (char *)urlStream.str().c_str(), NULL, 0, 0);
req.RequestTime = time(NULL);
currentRequests.push_back(req);
}
@ -252,7 +294,6 @@ void ThumbnailBroker::thumbnailQueueProcessTH()
char * data;
int status, data_size, imgw, imgh;
data = http_async_req_stop(req.HTTPContext, &status, &data_size);
free(req.HTTPContext);
if (status == 200 && data)
{
@ -307,6 +348,9 @@ void ThumbnailBroker::thumbnailQueueProcessTH()
}
}
pthread_mutex_lock(&runningMutex);
thumbnailQueueRunning = false;
pthread_mutex_unlock(&runningMutex);
}
void ThumbnailBroker::RetrieveThumbnail(int saveID, int width, int height, ThumbnailListener * tListener)

View File

@ -77,6 +77,7 @@ private:
pthread_mutex_t thumbnailQueueMutex;
pthread_mutex_t listenersMutex;
pthread_mutex_t runningMutex;
pthread_t thumbnailQueueThread;
bool thumbnailQueueRunning;
std::deque<ThumbnailRequest> thumbnailRequests;
@ -91,10 +92,12 @@ private:
static void * thumbnailQueueProcessHelper(void * ref);
void thumbnailQueueProcessTH();
void assureRunning();
public:
ThumbnailBroker();
virtual ~ThumbnailBroker();
void Shutdown();
void FlushThumbQueue();
void RenderThumbnail(GameSave * gameSave, bool decorations, bool fire, int width, int height, ThumbnailListener * tListener);

96
src/game/BitmapBrush.h Normal file
View File

@ -0,0 +1,96 @@
/*
* BitmapBrush.h
*
* Created on: Nov 18, 2012
* Author: Simon Robertshaw
*/
#ifndef BTIMAPBRUSH_H_
#define BTIMAPBRUSH_H_
#include <vector>
#include <cmath>
#include "Brush.h"
class BitmapBrush: public Brush
{
protected:
ui::Point origSize;
unsigned char * origBitmap;
public:
BitmapBrush(std::vector<unsigned char> newBitmap, ui::Point rectSize_):
Brush(ui::Point(0, 0)),
origSize(0, 0)
{
ui::Point newSize = rectSize_;
//Ensure the rect has odd dimentions so we can pull an integer radius with a 1x1 centre
if(!(newSize.X % 2))
newSize.X += 1;
if(!(newSize.Y % 2))
newSize.Y += 1;
radius = (newSize-ui::Point(1, 1))/2;
size = newSize;
origSize = size;
origBitmap = new unsigned char[size.X*size.Y];
std::fill(origBitmap, origBitmap+(size.X*size.Y), 0);
for(int y = 0; y < rectSize_.Y; y++)
{
for(int x = 0; x < rectSize_.X; x++)
{
if(newBitmap[(y*rectSize_.X)+x] >= 128)
origBitmap[(y*size.X)+x] = newBitmap[(y*rectSize_.X)+x];
}
}
SetRadius(radius);
};
virtual void GenerateBitmap()
{
if(origBitmap)
{
if(bitmap)
delete[] bitmap;
bitmap = new unsigned char[size.X*size.Y];
if(size == origSize)
std::copy(origBitmap, origBitmap+(origSize.X*origSize.Y), bitmap);
else
{
//Bilinear interpolation
float factorX = ((float)origSize.X)/((float)size.X);
float factorY = ((float)origSize.Y)/((float)size.Y);
for(int y = 0; y < size.Y; y++)
{
for(int x = 0; x < size.X; x++)
{
float originalY = ((float)y)*factorY;
float originalX = ((float)x)*factorX;
int lowerX = std::floor(originalX);
int upperX = std::min((float)(origSize.X-1), std::floor(originalX+1.0f));
int lowerY = std::floor(originalY);
int upperY = std::min((float)(origSize.Y-1), std::floor(originalY+1.0f));
unsigned char topRight = origBitmap[(lowerY*origSize.X)+upperX];
unsigned char topLeft = origBitmap[(lowerY*origSize.X)+lowerX];
unsigned char bottomRight = origBitmap[(upperY*origSize.X)+upperX];
unsigned char bottomLeft = origBitmap[(upperY*origSize.X)+lowerX];
float top = LinearInterpolate<float>(topLeft, topRight, lowerX, upperX, originalX);
float bottom = LinearInterpolate<float>(bottomLeft, bottomRight, lowerX, upperX, originalX);
float mid = LinearInterpolate<float>(top, bottom, lowerY, upperY, originalY);
bitmap[(y*size.X)+x] = mid > 128 ? 255 : 0;
}
}
}
}
}
virtual ~BitmapBrush()
{
if(origBitmap)
delete[] origBitmap;
}
};
#endif /* BTIMAPBRUSH_H_ */

View File

@ -61,7 +61,7 @@ public:
{
return size;
}
void SetRadius(ui::Point radius)
virtual void SetRadius(ui::Point radius)
{
this->radius = radius;
this->size = radius+radius+ui::Point(1, 1);

View File

@ -987,6 +987,15 @@ void GameController::OpenSavePreview(int saveID, int saveDate)
ui::Engine::Ref().ShowWindow(activePreview->GetView());
}
void GameController::OpenSavePreview()
{
if(gameModel->GetSave())
{
activePreview = new PreviewController(gameModel->GetSave()->GetID(), new SaveOpenCallback(this));
ui::Engine::Ref().ShowWindow(activePreview->GetView());
}
}
void GameController::OpenLocalBrowse()
{
class LocalSaveOpenCallback: public FileSelectedCallback

View File

@ -106,6 +106,7 @@ public:
void OpenLogin();
void OpenTags();
void OpenSavePreview(int saveID, int saveDate);
void OpenSavePreview();
void OpenLocalSaveWindow(bool asCurrent);
void OpenLocalBrowse();
void OpenOptions();

View File

@ -9,6 +9,7 @@
#include "Brush.h"
#include "EllipseBrush.h"
#include "TriangleBrush.h"
#include "BitmapBrush.h"
#include "client/Client.h"
#include "client/GameSave.h"
#include "game/DecorationTool.h"
@ -310,6 +311,26 @@ void GameModel::BuildMenus()
brushList.push_back(new Brush(ui::Point(4, 4)));
brushList.push_back(new TriangleBrush(ui::Point(4, 4)));
//Load more from brushes folder
std::vector<string> brushFiles = Client::Ref().DirectorySearch(BRUSH_DIR, "", ".ptb");
for(int i = 0; i < brushFiles.size(); i++)
{
std::vector<unsigned char> brushData = Client::Ref().ReadFile(brushFiles[i]);
if(!brushData.size())
{
std::cout << "Brushes: Skipping " << brushFiles[i] << ". Could not open" << std::endl;
continue;
}
int dimension = std::sqrt(brushData.size());
if(dimension * dimension != brushData.size())
{
std::cout << "Brushes: Skipping " << brushFiles[i] << ". Invalid bitmap size" << std::endl;
continue;
}
brushList.push_back(new BitmapBrush(brushData, ui::Point(dimension, dimension)));
}
//Set default tools
regularToolset[0] = GetToolFromIdentifier("DEFAULT_PT_DUST");
regularToolset[1] = GetToolFromIdentifier("DEFAULT_PT_NONE");

View File

@ -223,6 +223,10 @@ GameView::GameView():
{
v->c->ReloadSim();
}
void AltActionCallback(ui::Button * sender)
{
v->c->OpenSavePreview();
}
};
reloadButton = new ui::Button(ui::Point(currentX, Size.Y-16), ui::Point(17, 15), "", "Reload the simulation");
reloadButton->SetIcon(IconReload);

View File

@ -156,26 +156,38 @@ void Button::Draw(const Point& screenPos)
void Button::OnMouseUnclick(int x, int y, unsigned int button)
{
if(button != 1)
if(button == 1)
{
return;
if(isButtonDown)
{
isButtonDown = false;
DoAction();
}
}
if(isButtonDown)
else if(button == 3)
{
isButtonDown = false;
DoAction();
}
if(isAltButtonDown)
{
isAltButtonDown = false;
DoAltAction();
}
}
}
void Button::OnMouseClick(int x, int y, unsigned int button)
{
if(button != 1) return;
if(isTogglable)
{
toggle = !toggle;
if(button == 1)
{
if(isTogglable)
{
toggle = !toggle;
}
isButtonDown = true;
}
else if(button == 3)
{
isAltButtonDown = true;
}
isButtonDown = true;
}
void Button::OnMouseEnter(int x, int y)
@ -206,6 +218,14 @@ void Button::DoAction()
actionCallback->ActionCallback(this);
}
void Button::DoAltAction()
{
if(!Enabled)
return;
if(actionCallback)
actionCallback->AltActionCallback(this);
}
void Button::SetActionCallback(ButtonAction * action)
{
if(actionCallback)

View File

@ -20,6 +20,7 @@ class ButtonAction
{
public:
virtual void ActionCallback(ui::Button * sender) {}
virtual void AltActionCallback(ui::Button * sender) {}
virtual void MouseEnterCallback(ui::Button * sender) {}
virtual ~ButtonAction() {}
};
@ -45,6 +46,7 @@ public:
virtual void TextPosition();
inline bool GetState() { return state; }
virtual void DoAction(); //action of button what ever it may be
virtual void DoAltAction(); //action of button what ever it may be
void SetTogglable(bool isTogglable);
bool GetTogglable();
TPT_NO_INLINE bool GetToggleState();
@ -60,7 +62,7 @@ protected:
std::string buttonDisplayText;
std::string ButtonText;
bool isButtonDown, state, isMouseInside, isTogglable, toggle;
bool isButtonDown, isAltButtonDown, state, isMouseInside, isTogglable, toggle;
ButtonAction * actionCallback;
};

View File

@ -50,7 +50,7 @@ Element_CLST::Element_CLST()
int Element_CLST::update(UPDATE_FUNC_ARGS)
{
int r, rx, ry;
float cxy;
float cxy = 0;
for (rx=-2; rx<3; rx++)
for (ry=-2; ry<3; ry++)
if (x+rx>=0 && y+ry>0 && x+rx<XRES && y+ry<YRES && (rx || ry))
@ -76,7 +76,7 @@ int Element_CLST::update(UPDATE_FUNC_ARGS)
cxy = 0.015;
if(parts[i].temp >= 295 && parts[i].temp <350)
cxy = 0.01;
if(parts[i].temp > 350)
if(parts[i].temp >= 350)
cxy = 0.005;
parts[i].vx += cxy*rx;
parts[i].vy += cxy*ry;//These two can be set not to calculate over 350 later. They do virtually nothing over 0.005.

View File

@ -76,7 +76,7 @@ int Element_SWCH::update(UPDATE_FUNC_ARGS)
parts[i].life = parts[r>>8].life;
}
}
else if (rt==PT_SPRK&&parts[i].life==10&&parts[r>>8].ctype!=PT_PSCN&&parts[r>>8].ctype!=PT_NSCN) {
else if (rt==PT_SPRK && parts[i].life==10 && parts[r>>8].life>0 && parts[r>>8].ctype!=PT_PSCN && parts[r>>8].ctype!=PT_NSCN) {
sim->part_change_type(i,x,y,PT_SPRK);
parts[i].ctype = PT_SWCH;
parts[i].life = 4;

View File

@ -149,7 +149,7 @@ int Element_VIBR::update(UPDATE_FUNC_ARGS) {
if (!r)
continue;
//Melts into EXOT
if ((r&0xFF) == PT_EXOT && !(rand()%250))
if ((r&0xFF) == PT_EXOT && !(rand()%250) && !parts[i].life)
{
sim->create_part(i, x, y, PT_EXOT);
}
@ -163,7 +163,7 @@ int Element_VIBR::update(UPDATE_FUNC_ARGS) {
parts[r>>8].tmp += 10;
}
//Absorbs energy particles
if ((sim->elements[r&0xFF].Properties & TYPE_ENERGY))
if ((sim->elements[r&0xFF].Properties & TYPE_ENERGY) && !parts[i].life)
{
parts[i].tmp += 20;
sim->kill_part(r>>8);