mirror of
https://github.com/The-Powder-Toy/The-Powder-Toy.git
synced 2025-09-02 20:42:36 +02:00
Make thumbnailbroker more general purpose, image requests for requestbroker, avatars in previewview
This commit is contained in:
@@ -42,7 +42,7 @@ public:
|
|||||||
UpdateInfo(int time, std::string file, BuildType type) : Major(0), Minor(0), Build(0), Time(time), File(file), Type(type) {}
|
UpdateInfo(int time, std::string file, BuildType type) : Major(0), Minor(0), Build(0), Time(time), File(file), Type(type) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class ThumbnailListener;
|
class RequestListener;
|
||||||
class ClientListener;
|
class ClientListener;
|
||||||
class Client: public Singleton<Client> {
|
class Client: public Singleton<Client> {
|
||||||
private:
|
private:
|
||||||
|
@@ -3,7 +3,7 @@
|
|||||||
#include <typeinfo>
|
#include <typeinfo>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
#include "RequestBroker.h"
|
#include "RequestBroker.h"
|
||||||
#include "ThumbnailListener.h"
|
#include "RequestListener.h"
|
||||||
#include "Client.h"
|
#include "Client.h"
|
||||||
#include "HTTP.h"
|
#include "HTTP.h"
|
||||||
#include "GameSave.h"
|
#include "GameSave.h"
|
||||||
@@ -15,14 +15,18 @@
|
|||||||
RequestBroker::RequestBroker()
|
RequestBroker::RequestBroker()
|
||||||
{
|
{
|
||||||
thumbnailQueueRunning = false;
|
thumbnailQueueRunning = false;
|
||||||
//thumbnailQueueMutex = PTHREAD_MUTEX_INITIALIZER;
|
|
||||||
pthread_mutex_init (&thumbnailQueueMutex, NULL);
|
|
||||||
|
|
||||||
//listenersMutex = PTHREAD_MUTEX_INITIALIZER;
|
//listenersMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||||
pthread_mutex_init (&listenersMutex, NULL);
|
pthread_mutex_init (&listenersMutex, NULL);
|
||||||
|
|
||||||
|
|
||||||
pthread_mutex_init (&runningMutex, NULL);
|
pthread_mutex_init (&runningMutex, NULL);
|
||||||
|
|
||||||
|
|
||||||
|
pthread_mutex_init (&requestQueueMutex, NULL);
|
||||||
|
|
||||||
|
|
||||||
|
pthread_mutex_init (&completeQueueMutex, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
RequestBroker::~RequestBroker()
|
RequestBroker::~RequestBroker()
|
||||||
@@ -58,38 +62,63 @@ void RequestBroker::Shutdown()
|
|||||||
else
|
else
|
||||||
pthread_mutex_unlock(&runningMutex);
|
pthread_mutex_unlock(&runningMutex);
|
||||||
|
|
||||||
|
std::vector<Request*>::iterator req = activeRequests.begin();
|
||||||
for (std::list<ThumbnailRequest>::iterator iter = currentRequests.begin(), end = currentRequests.end(); iter != end; ++iter)
|
while(req != activeRequests.end())
|
||||||
{
|
{
|
||||||
ThumbnailRequest req = *iter;
|
(*req)->Cleanup();
|
||||||
if(req.HTTPContext)
|
delete (*req);
|
||||||
{
|
req++;
|
||||||
http_async_req_close(req.HTTPContext);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestBroker::RenderThumbnail(GameSave * gameSave, int width, int height, ThumbnailListener * tListener)
|
void RequestBroker::RenderThumbnail(GameSave * gameSave, int width, int height, RequestListener * tListener)
|
||||||
{
|
{
|
||||||
RenderThumbnail(gameSave, true, true, width, height, tListener);
|
RenderThumbnail(gameSave, true, true, width, height, tListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestBroker::RenderThumbnail(GameSave * gameSave, bool decorations, bool fire, int width, int height, ThumbnailListener * tListener)
|
void RequestBroker::RenderThumbnail(GameSave * gameSave, bool decorations, bool fire, int width, int height, RequestListener * tListener)
|
||||||
{
|
{
|
||||||
AttachThumbnailListener(tListener);
|
ListenerHandle handle = AttachRequestListener(tListener);
|
||||||
pthread_mutex_lock(&thumbnailQueueMutex);
|
|
||||||
renderRequests.push_back(ThumbRenderRequest(new GameSave(*gameSave), decorations, fire, width, height, ListenerHandle(tListener->ListenerRand, tListener)));
|
ThumbRenderRequest * r = new ThumbRenderRequest(new GameSave(*gameSave), decorations, fire, width, height, handle);
|
||||||
pthread_mutex_unlock(&thumbnailQueueMutex);
|
|
||||||
|
pthread_mutex_lock(&requestQueueMutex);
|
||||||
|
requestQueue.push_back(r);
|
||||||
|
pthread_mutex_unlock(&requestQueueMutex);
|
||||||
|
|
||||||
assureRunning();
|
assureRunning();
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestBroker::RetrieveThumbnail(int saveID, int saveDate, int width, int height, ThumbnailListener * tListener)
|
void RequestBroker::RetrieveThumbnail(int saveID, int saveDate, int width, int height, RequestListener * tListener)
|
||||||
{
|
{
|
||||||
AttachThumbnailListener(tListener);
|
std::stringstream urlStream;
|
||||||
pthread_mutex_lock(&thumbnailQueueMutex);
|
urlStream << "http://" << STATICSERVER << "/" << saveID;
|
||||||
thumbnailRequests.push_back(ThumbnailRequest(saveID, saveDate, width, height, ListenerHandle(tListener->ListenerRand, tListener)));
|
if(saveDate)
|
||||||
pthread_mutex_unlock(&thumbnailQueueMutex);
|
{
|
||||||
|
urlStream << "_" << saveDate;
|
||||||
|
}
|
||||||
|
urlStream << "_small.pti";
|
||||||
|
|
||||||
|
RetrieveImage(urlStream.str(), width, height, tListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RequestBroker::RetrieveAvatar(std::string username, int width, int height, RequestListener * tListener)
|
||||||
|
{
|
||||||
|
std::stringstream urlStream;
|
||||||
|
urlStream << "http://" << STATICSERVER << "/avatars/" << username << ".pti";
|
||||||
|
|
||||||
|
RetrieveImage(urlStream.str(), width, height, tListener);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RequestBroker::RetrieveImage(std::string imageUrl, int width, int height, RequestListener * tListener)
|
||||||
|
{
|
||||||
|
ListenerHandle handle = AttachRequestListener(tListener);
|
||||||
|
|
||||||
|
ImageRequest * r = new ImageRequest(imageUrl, width, height, handle);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&requestQueueMutex);
|
||||||
|
requestQueue.push_back(r);
|
||||||
|
pthread_mutex_unlock(&requestQueueMutex);
|
||||||
|
|
||||||
assureRunning();
|
assureRunning();
|
||||||
}
|
}
|
||||||
@@ -102,23 +131,24 @@ void * RequestBroker::thumbnailQueueProcessHelper(void * ref)
|
|||||||
|
|
||||||
void RequestBroker::FlushThumbQueue()
|
void RequestBroker::FlushThumbQueue()
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&thumbnailQueueMutex);
|
pthread_mutex_lock(&completeQueueMutex);
|
||||||
while(thumbnailComplete.size())
|
while(completeQueue.size())
|
||||||
{
|
{
|
||||||
if(CheckThumbnailListener(thumbnailComplete.front().first))
|
if(CheckRequestListener(completeQueue.front()->Listener))
|
||||||
{
|
{
|
||||||
thumbnailComplete.front().first.second->OnThumbnailReady(thumbnailComplete.front().second);
|
completeQueue.front()->Listener.second->OnResponseReady(completeQueue.front()->ResultObject);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
std::cout << typeid(*this).name() << " Listener lost, discarding request" << std::endl;
|
std::cout << typeid(*this).name() << " Listener lost, discarding request" << std::endl;
|
||||||
#endif
|
#endif
|
||||||
delete thumbnailComplete.front().second;
|
completeQueue.front()->Cleanup();
|
||||||
}
|
}
|
||||||
thumbnailComplete.pop_front();
|
delete completeQueue.front();
|
||||||
|
completeQueue.pop();
|
||||||
}
|
}
|
||||||
pthread_mutex_unlock(&thumbnailQueueMutex);
|
pthread_mutex_unlock(&completeQueueMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestBroker::thumbnailQueueProcessTH()
|
void RequestBroker::thumbnailQueueProcessTH()
|
||||||
@@ -150,216 +180,211 @@ void RequestBroker::thumbnailQueueProcessTH()
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(activeRequests.size())
|
||||||
//Renderer
|
|
||||||
pthread_mutex_lock(&thumbnailQueueMutex);
|
|
||||||
if(renderRequests.size())
|
|
||||||
{
|
{
|
||||||
|
std::vector<Request*>::iterator req = activeRequests.begin();
|
||||||
|
while(req != activeRequests.end())
|
||||||
|
{
|
||||||
|
ProcessResponse resultStatus = OK;
|
||||||
|
Request * r = *req;
|
||||||
|
switch(r->Type)
|
||||||
|
{
|
||||||
|
case Request::ThumbnailRender:
|
||||||
|
resultStatus = processThumbnailRender(*(ThumbRenderRequest*)r);
|
||||||
|
break;
|
||||||
|
case Request::Image:
|
||||||
|
resultStatus = processImage(*(ImageRequest*)r);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(resultStatus == Duplicate || resultStatus == Failed || resultStatus == Finished)
|
||||||
|
{
|
||||||
|
req = activeRequests.erase(req);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
req++;
|
||||||
|
}
|
||||||
|
}
|
||||||
lastAction = time(NULL);
|
lastAction = time(NULL);
|
||||||
ThumbRenderRequest req;
|
|
||||||
req = renderRequests.front();
|
|
||||||
renderRequests.pop_front();
|
|
||||||
pthread_mutex_unlock(&thumbnailQueueMutex);
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
std::cout << typeid(*this).name() << " Processing render request" << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Thumbnail * thumbnail = SaveRenderer::Ref().Render(req.Save, req.Decorations, req.Fire);
|
|
||||||
delete req.Save;
|
|
||||||
|
|
||||||
if(thumbnail)
|
|
||||||
{
|
|
||||||
thumbnail->Resize(req.Width, req.Height);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&thumbnailQueueMutex);
|
|
||||||
thumbnailComplete.push_back(std::pair<ListenerHandle, Thumbnail*>(req.CompletedListener, thumbnail));
|
|
||||||
pthread_mutex_unlock(&thumbnailQueueMutex);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//Move any items from the request queue to the processing queue
|
||||||
|
pthread_mutex_lock(&requestQueueMutex);
|
||||||
|
std::vector<Request*>::iterator newReq = requestQueue.begin();
|
||||||
|
while(newReq != requestQueue.end())
|
||||||
|
{
|
||||||
|
if(activeRequests.size() > 5)
|
||||||
|
{
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pthread_mutex_unlock(&thumbnailQueueMutex);
|
activeRequests.push_back(*newReq);
|
||||||
}
|
newReq = requestQueue.erase(newReq);
|
||||||
|
|
||||||
//Renderer
|
|
||||||
pthread_mutex_lock(&thumbnailQueueMutex);
|
|
||||||
if(thumbnailRequests.size())
|
|
||||||
{
|
|
||||||
lastAction = time(NULL);
|
|
||||||
Thumbnail * thumbnail = NULL;
|
|
||||||
|
|
||||||
ThumbnailRequest req;
|
|
||||||
req = thumbnailRequests.front();
|
|
||||||
|
|
||||||
//Check the cache
|
|
||||||
for(std::deque<std::pair<ThumbnailID, Thumbnail*> >::iterator iter = thumbnailCache.begin(), end = thumbnailCache.end(); iter != end; ++iter)
|
|
||||||
{
|
|
||||||
if((*iter).first == req.ID)
|
|
||||||
{
|
|
||||||
thumbnail = (*iter).second;
|
|
||||||
#ifdef DEBUG
|
|
||||||
std::cout << typeid(*this).name() << " " << req.ID.SaveID << ":" << req.ID.SaveDate << " found in cache" << std::endl;
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
pthread_mutex_unlock(&requestQueueMutex);
|
||||||
if(thumbnail)
|
|
||||||
{
|
|
||||||
//Got thumbnail from cache
|
|
||||||
thumbnailRequests.pop_front();
|
|
||||||
pthread_mutex_unlock(&thumbnailQueueMutex);
|
|
||||||
|
|
||||||
for(std::vector<ThumbnailSpec>::iterator specIter = req.SubRequests.begin(), specEnd = req.SubRequests.end(); specIter != specEnd; ++specIter)
|
|
||||||
{
|
|
||||||
Thumbnail * tempThumbnail = new Thumbnail(*thumbnail);
|
|
||||||
tempThumbnail->Resize((*specIter).Width, (*specIter).Height);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&thumbnailQueueMutex);
|
|
||||||
thumbnailComplete.push_back(std::pair<ListenerHandle, Thumbnail*>((*specIter).CompletedListener, tempThumbnail));
|
|
||||||
pthread_mutex_unlock(&thumbnailQueueMutex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Check for ongoing requests
|
|
||||||
bool requested = false;
|
|
||||||
for(std::list<ThumbnailRequest>::iterator iter = currentRequests.begin(), end = currentRequests.end(); iter != end; ++iter)
|
|
||||||
{
|
|
||||||
if((*iter).ID == req.ID)
|
|
||||||
{
|
|
||||||
requested = true;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
std::cout << typeid(*this).name() << " Request for " << req.ID.SaveID << ":" << req.ID.SaveDate << " found, appending." << std::endl;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//Add the current listener to the item already being requested
|
|
||||||
(*iter).SubRequests.push_back(req.SubRequests.front());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if(requested)
|
|
||||||
{
|
|
||||||
//Already requested
|
|
||||||
thumbnailRequests.pop_front();
|
|
||||||
pthread_mutex_unlock(&thumbnailQueueMutex);
|
|
||||||
}
|
|
||||||
else if(currentRequests.size() < IMGCONNS) //If it's not already being requested and we still have more space for a new connection, request it
|
|
||||||
{
|
|
||||||
thumbnailRequests.pop_front();
|
|
||||||
pthread_mutex_unlock(&thumbnailQueueMutex);
|
|
||||||
|
|
||||||
//If it's not already being requested, request it
|
|
||||||
std::stringstream urlStream;
|
|
||||||
urlStream << "http://" << STATICSERVER << "/" << req.ID.SaveID;
|
|
||||||
if(req.ID.SaveDate)
|
|
||||||
{
|
|
||||||
urlStream << "_" << req.ID.SaveDate;
|
|
||||||
}
|
|
||||||
urlStream << "_small.pti";
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
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, 0);
|
|
||||||
req.RequestTime = time(NULL);
|
|
||||||
currentRequests.push_back(req);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Already full of requests
|
|
||||||
pthread_mutex_unlock(&thumbnailQueueMutex);
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
pthread_mutex_unlock(&thumbnailQueueMutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
std::list<ThumbnailRequest>::iterator iter = currentRequests.begin();
|
|
||||||
while (iter != currentRequests.end())
|
|
||||||
{
|
|
||||||
lastAction = time(NULL);
|
|
||||||
|
|
||||||
ThumbnailRequest req = *iter;
|
|
||||||
Thumbnail * thumbnail = NULL;
|
|
||||||
|
|
||||||
if(http_async_req_status(req.HTTPContext))
|
|
||||||
{
|
|
||||||
|
|
||||||
pixel * thumbData;
|
|
||||||
char * data;
|
|
||||||
int status, data_size, imgw, imgh;
|
|
||||||
data = http_async_req_stop(req.HTTPContext, &status, &data_size);
|
|
||||||
|
|
||||||
if (status == 200 && data)
|
|
||||||
{
|
|
||||||
thumbData = Graphics::ptif_unpack(data, data_size, &imgw, &imgh);
|
|
||||||
free(data);
|
|
||||||
|
|
||||||
if(thumbData)
|
|
||||||
{
|
|
||||||
thumbnail = new Thumbnail(req.ID.SaveID, req.ID.SaveID, thumbData, ui::Point(imgw, imgh));
|
|
||||||
free(thumbData);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
//Error thumbnail
|
|
||||||
VideoBuffer errorThumb(128, 128);
|
|
||||||
errorThumb.SetCharacter(64, 64, 'x', 255, 255, 255, 255);
|
|
||||||
|
|
||||||
thumbnail = new Thumbnail(req.ID.SaveID, req.ID.SaveID, errorThumb.Buffer, ui::Point(errorThumb.Width, errorThumb.Height));
|
|
||||||
}
|
|
||||||
|
|
||||||
if(thumbnailCache.size() >= THUMB_CACHE_SIZE)
|
|
||||||
{
|
|
||||||
delete thumbnailCache.front().second;
|
|
||||||
thumbnailCache.pop_front();
|
|
||||||
}
|
|
||||||
thumbnailCache.push_back(std::pair<ThumbnailID, Thumbnail*>(req.ID, thumbnail));
|
|
||||||
|
|
||||||
for(std::vector<ThumbnailSpec>::iterator specIter = req.SubRequests.begin(), specEnd = req.SubRequests.end(); specIter != specEnd; ++specIter)
|
|
||||||
{
|
|
||||||
Thumbnail * tempThumbnail = new Thumbnail(*thumbnail);
|
|
||||||
tempThumbnail->Resize((*specIter).Width, (*specIter).Height);
|
|
||||||
|
|
||||||
pthread_mutex_lock(&thumbnailQueueMutex);
|
|
||||||
thumbnailComplete.push_back(std::pair<ListenerHandle, Thumbnail*>((*specIter).CompletedListener, tempThumbnail));
|
|
||||||
pthread_mutex_unlock(&thumbnailQueueMutex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
#ifdef DEBUG
|
|
||||||
std::cout << typeid(*this).name() << " Request for " << req.ID.SaveID << ":" << req.ID.SaveDate << " failed with status " << status << std::endl;
|
|
||||||
#endif
|
|
||||||
if(data)
|
|
||||||
free(data);
|
|
||||||
}
|
|
||||||
iter = currentRequests.erase(iter);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
++iter;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
pthread_mutex_lock(&runningMutex);
|
pthread_mutex_lock(&runningMutex);
|
||||||
thumbnailQueueRunning = false;
|
thumbnailQueueRunning = false;
|
||||||
pthread_mutex_unlock(&runningMutex);
|
pthread_mutex_unlock(&runningMutex);
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestBroker::RetrieveThumbnail(int saveID, int width, int height, ThumbnailListener * tListener)
|
RequestBroker::ProcessResponse RequestBroker::processThumbnailRender(ThumbRenderRequest & request)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
std::cout << typeid(*this).name() << " Processing render request" << std::endl;
|
||||||
|
#endif
|
||||||
|
Thumbnail * thumbnail = SaveRenderer::Ref().Render(request.Save, request.Decorations, request.Fire);
|
||||||
|
delete request.Save;
|
||||||
|
request.Save = NULL;
|
||||||
|
|
||||||
|
if(thumbnail)
|
||||||
|
{
|
||||||
|
thumbnail->Resize(request.Width, request.Height);
|
||||||
|
request.ResultObject = (void*)thumbnail;
|
||||||
|
requestComplete(&request);
|
||||||
|
return Finished;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return Failed;
|
||||||
|
}
|
||||||
|
return Failed;
|
||||||
|
}
|
||||||
|
|
||||||
|
RequestBroker::ProcessResponse RequestBroker::processImage(ImageRequest & request)
|
||||||
|
{
|
||||||
|
VideoBuffer * image = NULL;
|
||||||
|
|
||||||
|
//Have a look at the thumbnail cache
|
||||||
|
for(std::deque<std::pair<std::string, VideoBuffer*> >::iterator iter = imageCache.begin(), end = imageCache.end(); iter != end; ++iter)
|
||||||
|
{
|
||||||
|
if((*iter).first == request.URL)
|
||||||
|
{
|
||||||
|
image = (*iter).second;
|
||||||
|
#ifdef DEBUG
|
||||||
|
std::cout << typeid(*this).name() << " " << request.URL << " found in cache" << std::endl;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!image)
|
||||||
|
{
|
||||||
|
if(request.HTTPContext)
|
||||||
|
{
|
||||||
|
if(http_async_req_status(request.HTTPContext))
|
||||||
|
{
|
||||||
|
pixel * imageData;
|
||||||
|
char * data;
|
||||||
|
int status, data_size, imgw, imgh;
|
||||||
|
data = http_async_req_stop(request.HTTPContext, &status, &data_size);
|
||||||
|
|
||||||
|
if (status == 200 && data)
|
||||||
|
{
|
||||||
|
imageData = Graphics::ptif_unpack(data, data_size, &imgw, &imgh);
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
if(imageData)
|
||||||
|
{
|
||||||
|
//Success!
|
||||||
|
image = new VideoBuffer(imageData, imgw, imgh);
|
||||||
|
free(imageData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Error thumbnail
|
||||||
|
image = new VideoBuffer(32, 32);
|
||||||
|
image->SetCharacter(14, 14, 'x', 255, 255, 255, 255);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(imageCache.size() >= THUMB_CACHE_SIZE)
|
||||||
|
{
|
||||||
|
//Remove unnecessary from thumbnail cache
|
||||||
|
delete imageCache.front().second;
|
||||||
|
imageCache.pop_front();
|
||||||
|
}
|
||||||
|
imageCache.push_back(std::pair<std::string, VideoBuffer*>(request.URL, image));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
std::cout << typeid(*this).name() << " Request for " << request.URL << " failed with status " << status << std::endl;
|
||||||
|
#endif
|
||||||
|
if(data)
|
||||||
|
free(data);
|
||||||
|
|
||||||
|
return Failed;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
//Check for ongoing requests
|
||||||
|
for(std::vector<Request*>::iterator iter = activeRequests.begin(), end = activeRequests.end(); iter != end; ++iter)
|
||||||
|
{
|
||||||
|
if((*iter)->Type != Request::Image)
|
||||||
|
continue;
|
||||||
|
ImageRequest * otherReq = (ImageRequest*)(*iter);
|
||||||
|
if(otherReq->URL == request.URL && otherReq != &request)
|
||||||
|
{
|
||||||
|
#ifdef DEBUG
|
||||||
|
std::cout << typeid(*this).name() << " Request for " << request.URL << " found, appending." << std::endl;
|
||||||
|
#endif
|
||||||
|
//Add the current listener to the item already being requested
|
||||||
|
(*iter)->Children.push_back(&request);
|
||||||
|
return Duplicate;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//If it's not already being requested, request it
|
||||||
|
#ifdef DEBUG
|
||||||
|
std::cout << typeid(*this).name() << " Creating new request for " << request.URL << std::endl;
|
||||||
|
#endif
|
||||||
|
request.HTTPContext = http_async_req_start(NULL, (char *)request.URL.c_str(), NULL, 0, 0);
|
||||||
|
request.RequestTime = time(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(image)
|
||||||
|
{
|
||||||
|
|
||||||
|
//Create a copy, to seperate from the cache
|
||||||
|
VideoBuffer * myVB = new VideoBuffer(*image);
|
||||||
|
myVB->Resize(request.Width, request.Height, true);
|
||||||
|
request.ResultObject = (void*)myVB;
|
||||||
|
requestComplete(&request);
|
||||||
|
for(std::vector<Request*>::iterator childIter = request.Children.begin(), childEnd = request.Children.end(); childIter != childEnd; ++childIter)
|
||||||
|
{
|
||||||
|
if((*childIter)->Type == Request::Image)
|
||||||
|
{
|
||||||
|
ImageRequest * childReq = (ImageRequest*)*childIter;
|
||||||
|
VideoBuffer * tempImage = new VideoBuffer(*image);
|
||||||
|
tempImage->Resize(childReq->Width, childReq->Height, true);
|
||||||
|
childReq->ResultObject = (void*)tempImage;
|
||||||
|
requestComplete(*childIter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Finished;
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void RequestBroker::requestComplete(Request * completedRequest)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&completeQueueMutex);
|
||||||
|
completeQueue.push(completedRequest);
|
||||||
|
pthread_mutex_unlock(&completeQueueMutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void RequestBroker::RetrieveThumbnail(int saveID, int width, int height, RequestListener * tListener)
|
||||||
{
|
{
|
||||||
RetrieveThumbnail(saveID, 0, width, height, tListener);
|
RetrieveThumbnail(saveID, 0, width, height, tListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RequestBroker::CheckThumbnailListener(ListenerHandle handle)
|
bool RequestBroker::CheckRequestListener(ListenerHandle handle)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&listenersMutex);
|
pthread_mutex_lock(&listenersMutex);
|
||||||
int count = std::count(validListeners.begin(), validListeners.end(), handle);
|
int count = std::count(validListeners.begin(), validListeners.end(), handle);
|
||||||
@@ -368,14 +393,16 @@ bool RequestBroker::CheckThumbnailListener(ListenerHandle handle)
|
|||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestBroker::AttachThumbnailListener(ThumbnailListener * tListener)
|
ListenerHandle RequestBroker::AttachRequestListener(RequestListener * tListener)
|
||||||
{
|
{
|
||||||
|
ListenerHandle handle = ListenerHandle(tListener->ListenerRand, tListener);
|
||||||
pthread_mutex_lock(&listenersMutex);
|
pthread_mutex_lock(&listenersMutex);
|
||||||
validListeners.push_back(ListenerHandle(tListener->ListenerRand, tListener));
|
validListeners.push_back(handle);
|
||||||
pthread_mutex_unlock(&listenersMutex);
|
pthread_mutex_unlock(&listenersMutex);
|
||||||
|
return handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RequestBroker::DetachThumbnailListener(ThumbnailListener * tListener)
|
void RequestBroker::DetachRequestListener(RequestListener * tListener)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&listenersMutex);
|
pthread_mutex_lock(&listenersMutex);
|
||||||
|
|
||||||
|
@@ -9,113 +9,147 @@
|
|||||||
#include "Singleton.h"
|
#include "Singleton.h"
|
||||||
|
|
||||||
class GameSave;
|
class GameSave;
|
||||||
class Thumbnail;
|
class VideoBuffer;
|
||||||
class ThumbnailListener;
|
class RequestListener;
|
||||||
typedef std::pair<int, ThumbnailListener*> ListenerHandle;
|
typedef std::pair<int, RequestListener*> ListenerHandle;
|
||||||
class RequestBroker: public Singleton<RequestBroker>
|
class RequestBroker: public Singleton<RequestBroker>
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
class ThumbnailSpec
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
int Width, Height;
|
|
||||||
ListenerHandle CompletedListener;
|
|
||||||
ThumbnailSpec(int width, int height, ListenerHandle completedListener) :
|
|
||||||
Width(width), Height(height), CompletedListener(completedListener) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ThumbnailID
|
enum ProcessResponse { Finished, OK, Canceled, Failed, Duplicate };
|
||||||
|
|
||||||
|
class Request
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int SaveID, SaveDate;
|
enum RequestType { ThumbnailRender, Image };
|
||||||
bool operator ==(const ThumbnailID & second)
|
RequestType Type;
|
||||||
|
void * ResultObject;
|
||||||
|
ListenerHandle Listener;
|
||||||
|
std::vector<Request*> Children;
|
||||||
|
Request(RequestType type, ListenerHandle listener)
|
||||||
{
|
{
|
||||||
return SaveID == second.SaveID && SaveDate == second.SaveDate;
|
Type = type;
|
||||||
|
Listener = listener;
|
||||||
|
ResultObject = NULL;
|
||||||
}
|
}
|
||||||
ThumbnailID(int saveID, int saveDate) : SaveID(saveID), SaveDate(saveDate) {}
|
virtual ~Request()
|
||||||
ThumbnailID() : SaveID(0), SaveDate(0) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class ThumbnailRequest
|
|
||||||
{
|
{
|
||||||
public:
|
std::vector<Request*>::iterator iter = Children.begin();
|
||||||
bool Complete;
|
while(iter != Children.end())
|
||||||
void * HTTPContext;
|
|
||||||
int RequestTime;
|
|
||||||
|
|
||||||
ThumbnailID ID;
|
|
||||||
std::vector<ThumbnailSpec> SubRequests;
|
|
||||||
|
|
||||||
ThumbnailRequest(int saveID, int saveDate, int width, int height, ListenerHandle completedListener) :
|
|
||||||
ID(saveID, saveDate), Complete(false), HTTPContext(NULL), RequestTime(0)
|
|
||||||
{
|
{
|
||||||
SubRequests.push_back(ThumbnailSpec(width, height, completedListener));
|
delete (*iter);
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
virtual void Cleanup()
|
||||||
|
{
|
||||||
|
std::vector<Request*>::iterator iter = Children.begin();
|
||||||
|
while(iter != Children.end())
|
||||||
|
{
|
||||||
|
(*iter)->Cleanup();
|
||||||
|
iter++;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ThumbnailRequest() : Complete(false), HTTPContext(NULL), RequestTime(0) {}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class ThumbRenderRequest
|
class ThumbRenderRequest: public Request
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
int Width, Height;
|
int Width, Height;
|
||||||
bool Decorations;
|
bool Decorations;
|
||||||
bool Fire;
|
bool Fire;
|
||||||
GameSave * Save;
|
GameSave * Save;
|
||||||
ListenerHandle CompletedListener;
|
ThumbRenderRequest(GameSave * save, bool decorations, bool fire, int width, int height, ListenerHandle listener):
|
||||||
ThumbRenderRequest(GameSave * save, bool decorations, bool fire, int width, int height, ListenerHandle completedListener) :
|
Request(ThumbnailRender, listener)
|
||||||
Save(save), Width(width), Height(height), CompletedListener(completedListener), Decorations(decorations), Fire(fire) {}
|
|
||||||
ThumbRenderRequest() : Save(0), Decorations(true), Fire(true), Width(0), Height(0), CompletedListener(ListenerHandle(0, (ThumbnailListener*)NULL)) {}
|
|
||||||
};
|
|
||||||
|
|
||||||
class Request
|
|
||||||
{
|
{
|
||||||
enum RequestType { Thumbnail, ThumbnailRender, HTTP };
|
Save = save;
|
||||||
public:
|
Width = width;
|
||||||
RequestType Type;
|
Height = height;
|
||||||
void * RequestObject;
|
Decorations = decorations;
|
||||||
ListenerHandle Listener;
|
Fire = fire;
|
||||||
|
}
|
||||||
|
virtual ~ThumbRenderRequest()
|
||||||
|
{
|
||||||
|
if(Save)
|
||||||
|
delete Save;
|
||||||
|
}
|
||||||
|
virtual void Cleanup()
|
||||||
|
{
|
||||||
|
Request::Cleanup();
|
||||||
|
if(ResultObject)
|
||||||
|
{
|
||||||
|
delete ((VideoBuffer*)ResultObject);
|
||||||
|
ResultObject = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//Thumbnail retreival
|
class ImageRequest: public Request
|
||||||
/*int thumbnailCacheNextID;
|
{
|
||||||
Thumbnail * thumbnailCache[THUMB_CACHE_SIZE];
|
public:
|
||||||
void * activeThumbRequests[IMGCONNS];
|
int Width, Height;
|
||||||
int activeThumbRequestTimes[IMGCONNS];
|
std::string URL;
|
||||||
int activeThumbRequestCompleteTimes[IMGCONNS];
|
int RequestTime;
|
||||||
std::string activeThumbRequestIDs[IMGCONNS];*/
|
void * HTTPContext;
|
||||||
|
ImageRequest(std::string url, int width, int height, ListenerHandle listener):
|
||||||
|
Request(Image, listener)
|
||||||
|
{
|
||||||
|
URL = url;
|
||||||
|
HTTPContext = NULL;
|
||||||
|
Width = width;
|
||||||
|
Height = height;
|
||||||
|
}
|
||||||
|
virtual ~ImageRequest() {}
|
||||||
|
virtual void Cleanup()
|
||||||
|
{
|
||||||
|
Request::Cleanup();
|
||||||
|
if(ResultObject)
|
||||||
|
{
|
||||||
|
delete ((VideoBuffer*)ResultObject);
|
||||||
|
ResultObject = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
pthread_mutex_t thumbnailQueueMutex;
|
|
||||||
pthread_mutex_t listenersMutex;
|
pthread_mutex_t listenersMutex;
|
||||||
pthread_mutex_t runningMutex;
|
pthread_mutex_t runningMutex;
|
||||||
|
pthread_mutex_t requestQueueMutex;
|
||||||
|
pthread_mutex_t completeQueueMutex;
|
||||||
|
|
||||||
pthread_t thumbnailQueueThread;
|
pthread_t thumbnailQueueThread;
|
||||||
bool thumbnailQueueRunning;
|
bool thumbnailQueueRunning;
|
||||||
std::deque<ThumbnailRequest> thumbnailRequests;
|
|
||||||
std::deque<ThumbRenderRequest> renderRequests;
|
|
||||||
|
|
||||||
std::deque<std::pair<ListenerHandle, Thumbnail*> > thumbnailComplete;
|
|
||||||
std::list<ThumbnailRequest> currentRequests;
|
|
||||||
std::deque<std::pair<ThumbnailID, Thumbnail*> > thumbnailCache;
|
|
||||||
|
|
||||||
std::vector<ListenerHandle> validListeners;
|
std::vector<ListenerHandle> validListeners;
|
||||||
|
|
||||||
std::deque<Request> requestQueue;
|
std::deque<std::pair<std::string, VideoBuffer*> > imageCache;
|
||||||
|
|
||||||
|
std::queue<Request*> completeQueue;
|
||||||
|
std::vector<Request*> requestQueue;
|
||||||
|
std::vector<Request*> activeRequests;
|
||||||
|
|
||||||
static void * thumbnailQueueProcessHelper(void * ref);
|
static void * thumbnailQueueProcessHelper(void * ref);
|
||||||
void thumbnailQueueProcessTH();
|
void thumbnailQueueProcessTH();
|
||||||
void assureRunning();
|
void assureRunning();
|
||||||
|
|
||||||
|
ProcessResponse processThumbnailRender(ThumbRenderRequest & request);
|
||||||
|
ProcessResponse processImage(ImageRequest & request);
|
||||||
|
|
||||||
|
void requestComplete(Request * completedRequest);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RequestBroker();
|
RequestBroker();
|
||||||
virtual ~RequestBroker();
|
virtual ~RequestBroker();
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
||||||
void FlushThumbQueue();
|
void FlushThumbQueue();
|
||||||
void RenderThumbnail(GameSave * gameSave, bool decorations, bool fire, int width, int height, ThumbnailListener * tListener);
|
void RetrieveImage(std::string imageUrl, int width, int height, RequestListener * tListener);
|
||||||
void RenderThumbnail(GameSave * gameSave, int width, int height, ThumbnailListener * tListener);
|
void RenderThumbnail(GameSave * gameSave, bool decorations, bool fire, int width, int height, RequestListener * tListener);
|
||||||
void RetrieveThumbnail(int saveID, int saveDate, int width, int height, ThumbnailListener * tListener);
|
void RenderThumbnail(GameSave * gameSave, int width, int height, RequestListener * tListener);
|
||||||
void RetrieveThumbnail(int saveID, int width, int height, ThumbnailListener * tListener);
|
void RetrieveThumbnail(int saveID, int saveDate, int width, int height, RequestListener * tListener);
|
||||||
|
void RetrieveThumbnail(int saveID, int width, int height, RequestListener * tListener);
|
||||||
|
void RetrieveAvatar(std::string username, int width, int height, RequestListener * tListener);
|
||||||
|
|
||||||
bool CheckThumbnailListener(ListenerHandle handle);
|
bool CheckRequestListener(ListenerHandle handle);
|
||||||
void AttachThumbnailListener(ThumbnailListener * tListener);
|
ListenerHandle AttachRequestListener(RequestListener * tListener);
|
||||||
void DetachThumbnailListener(ThumbnailListener * tListener);
|
void DetachRequestListener(RequestListener * tListener);
|
||||||
};
|
};
|
11
src/client/RequestListener.h
Normal file
11
src/client/RequestListener.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
class RequestListener
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int ListenerRand;
|
||||||
|
RequestListener() { ListenerRand = rand(); }
|
||||||
|
virtual ~RequestListener() {}
|
||||||
|
|
||||||
|
virtual void OnResponseReady(void * response) {}
|
||||||
|
};
|
@@ -1,12 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
class Thumbnail;
|
|
||||||
class ThumbnailListener
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
int ListenerRand;
|
|
||||||
ThumbnailListener() { ListenerRand = rand(); }
|
|
||||||
virtual ~ThumbnailListener() {}
|
|
||||||
|
|
||||||
virtual void OnThumbnailReady(Thumbnail * thumb) {}
|
|
||||||
};
|
|
@@ -5,6 +5,7 @@
|
|||||||
#include "Format.h"
|
#include "Format.h"
|
||||||
#include "Engine.h"
|
#include "Engine.h"
|
||||||
#include "client/Client.h"
|
#include "client/Client.h"
|
||||||
|
#include "client/RequestBroker.h"
|
||||||
#include "graphics/Graphics.h"
|
#include "graphics/Graphics.h"
|
||||||
#include "ContextMenu.h"
|
#include "ContextMenu.h"
|
||||||
#include "Keys.h"
|
#include "Keys.h"
|
||||||
@@ -23,6 +24,7 @@ AvatarButton::AvatarButton(Point position, Point size, std::string username):
|
|||||||
|
|
||||||
AvatarButton::~AvatarButton()
|
AvatarButton::~AvatarButton()
|
||||||
{
|
{
|
||||||
|
RequestBroker::Ref().DetachRequestListener(this);
|
||||||
if(avatar)
|
if(avatar)
|
||||||
delete avatar;
|
delete avatar;
|
||||||
if(actionCallback)
|
if(actionCallback)
|
||||||
@@ -34,13 +36,18 @@ void AvatarButton::Tick(float dt)
|
|||||||
if(!avatar && !tried && name.size() > 0)
|
if(!avatar && !tried && name.size() > 0)
|
||||||
{
|
{
|
||||||
tried = true;
|
tried = true;
|
||||||
avatar = Client::Ref().GetAvatar(name);
|
RequestBroker::Ref().RetrieveAvatar(name, Size.X, Size.Y, this);
|
||||||
if(avatar) {
|
}
|
||||||
if(avatar->Width != Size.X && avatar->Height != Size.Y)
|
}
|
||||||
|
|
||||||
|
void AvatarButton::OnResponseReady(void * imagePtr)
|
||||||
|
{
|
||||||
|
VideoBuffer * image = (VideoBuffer*)imagePtr;
|
||||||
|
if(image)
|
||||||
{
|
{
|
||||||
avatar->Resize(Size.X, Size.Y, true);
|
if(avatar)
|
||||||
}
|
delete avatar;
|
||||||
}
|
avatar = image;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,6 +6,7 @@
|
|||||||
#include "Component.h"
|
#include "Component.h"
|
||||||
#include "graphics/Graphics.h"
|
#include "graphics/Graphics.h"
|
||||||
#include "interface/Colour.h"
|
#include "interface/Colour.h"
|
||||||
|
#include "client/RequestListener.h"
|
||||||
|
|
||||||
namespace ui
|
namespace ui
|
||||||
{
|
{
|
||||||
@@ -17,7 +18,7 @@ public:
|
|||||||
virtual ~AvatarButtonAction() {}
|
virtual ~AvatarButtonAction() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class AvatarButton : public Component
|
class AvatarButton : public Component, public RequestListener
|
||||||
{
|
{
|
||||||
VideoBuffer * avatar;
|
VideoBuffer * avatar;
|
||||||
std::string name;
|
std::string name;
|
||||||
@@ -37,6 +38,8 @@ public:
|
|||||||
virtual void Draw(const Point& screenPos);
|
virtual void Draw(const Point& screenPos);
|
||||||
virtual void Tick(float dt);
|
virtual void Tick(float dt);
|
||||||
|
|
||||||
|
virtual void OnResponseReady(void * imagePtr);
|
||||||
|
|
||||||
virtual void DoAction();
|
virtual void DoAction();
|
||||||
|
|
||||||
void SetUsername(std::string username) { name = username; }
|
void SetUsername(std::string username) { name = username; }
|
||||||
|
@@ -117,7 +117,7 @@ SaveButton::SaveButton(Point position, Point size, SaveFile * file):
|
|||||||
|
|
||||||
SaveButton::~SaveButton()
|
SaveButton::~SaveButton()
|
||||||
{
|
{
|
||||||
RequestBroker::Ref().DetachThumbnailListener(this);
|
RequestBroker::Ref().DetachRequestListener(this);
|
||||||
|
|
||||||
if(thumbnail)
|
if(thumbnail)
|
||||||
delete thumbnail;
|
delete thumbnail;
|
||||||
@@ -129,13 +129,14 @@ SaveButton::~SaveButton()
|
|||||||
delete file;
|
delete file;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SaveButton::OnThumbnailReady(Thumbnail * thumb)
|
void SaveButton::OnResponseReady(void * imagePtr)
|
||||||
{
|
{
|
||||||
if(thumb)
|
VideoBuffer * image = (VideoBuffer*)imagePtr;
|
||||||
|
if(image)
|
||||||
{
|
{
|
||||||
if(thumbnail)
|
if(thumbnail)
|
||||||
delete thumbnail;
|
delete thumbnail;
|
||||||
thumbnail = thumb;
|
thumbnail = image;
|
||||||
waitingForThumb = false;
|
waitingForThumb = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -144,23 +145,25 @@ void SaveButton::Tick(float dt)
|
|||||||
{
|
{
|
||||||
if(!thumbnail && !waitingForThumb)
|
if(!thumbnail && !waitingForThumb)
|
||||||
{
|
{
|
||||||
|
float scaleFactor = (Size.Y-25)/((float)YRES);
|
||||||
|
ui::Point thumbBoxSize = ui::Point(((float)XRES)*scaleFactor, ((float)YRES)*scaleFactor);
|
||||||
if(save)
|
if(save)
|
||||||
{
|
{
|
||||||
if(save->GetGameSave())
|
if(save->GetGameSave())
|
||||||
{
|
{
|
||||||
waitingForThumb = true;
|
waitingForThumb = true;
|
||||||
RequestBroker::Ref().RenderThumbnail(save->GetGameSave(), Size.X-3, Size.Y-25, this);
|
RequestBroker::Ref().RenderThumbnail(save->GetGameSave(), thumbBoxSize.X, thumbBoxSize.Y, this);
|
||||||
}
|
}
|
||||||
else if(save->GetID())
|
else if(save->GetID())
|
||||||
{
|
{
|
||||||
waitingForThumb = true;
|
waitingForThumb = true;
|
||||||
RequestBroker::Ref().RetrieveThumbnail(save->GetID(), save->GetVersion(), Size.X-3, Size.Y-25, this);
|
RequestBroker::Ref().RetrieveThumbnail(save->GetID(), save->GetVersion(), thumbBoxSize.X, thumbBoxSize.Y, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else if(file && file->GetGameSave())
|
else if(file && file->GetGameSave())
|
||||||
{
|
{
|
||||||
waitingForThumb = true;
|
waitingForThumb = true;
|
||||||
RequestBroker::Ref().RenderThumbnail(file->GetGameSave(), Size.X-3, Size.Y-25, this);
|
RequestBroker::Ref().RenderThumbnail(file->GetGameSave(), thumbBoxSize.X, thumbBoxSize.Y, this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,11 +183,11 @@ void SaveButton::Draw(const Point& screenPos)
|
|||||||
|
|
||||||
if(thumbnail)
|
if(thumbnail)
|
||||||
{
|
{
|
||||||
thumbBoxSize = ui::Point(thumbnail->Size.X, thumbnail->Size.Y);
|
thumbBoxSize = ui::Point(thumbnail->Width, thumbnail->Height);
|
||||||
if(save && save->id)
|
if(save && save->id)
|
||||||
g->draw_image(thumbnail->Data, screenPos.X-3+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, thumbnail->Size.X, thumbnail->Size.Y, 255);
|
g->draw_image(thumbnail, screenPos.X-3+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, 255);
|
||||||
else
|
else
|
||||||
g->draw_image(thumbnail->Data, screenPos.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, thumbnail->Size.X, thumbnail->Size.Y, 255);
|
g->draw_image(thumbnail, screenPos.X+(Size.X-thumbBoxSize.X)/2, screenPos.Y+(Size.Y-21-thumbBoxSize.Y)/2, 255);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@@ -6,9 +6,8 @@
|
|||||||
#include "Component.h"
|
#include "Component.h"
|
||||||
#include "client/SaveFile.h"
|
#include "client/SaveFile.h"
|
||||||
#include "client/SaveInfo.h"
|
#include "client/SaveInfo.h"
|
||||||
#include "client/ThumbnailListener.h"
|
#include "client/RequestListener.h"
|
||||||
#include "graphics/Graphics.h"
|
#include "graphics/Graphics.h"
|
||||||
#include "search/Thumbnail.h"
|
|
||||||
#include "interface/Colour.h"
|
#include "interface/Colour.h"
|
||||||
|
|
||||||
namespace ui
|
namespace ui
|
||||||
@@ -24,11 +23,11 @@ public:
|
|||||||
virtual ~SaveButtonAction() {}
|
virtual ~SaveButtonAction() {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class SaveButton : public Component, public ThumbnailListener
|
class SaveButton : public Component, public RequestListener
|
||||||
{
|
{
|
||||||
SaveFile * file;
|
SaveFile * file;
|
||||||
SaveInfo * save;
|
SaveInfo * save;
|
||||||
Thumbnail * thumbnail;
|
VideoBuffer * thumbnail;
|
||||||
std::string name;
|
std::string name;
|
||||||
std::string votesString;
|
std::string votesString;
|
||||||
std::string votesBackground;
|
std::string votesBackground;
|
||||||
@@ -59,7 +58,7 @@ public:
|
|||||||
virtual void Draw(const Point& screenPos);
|
virtual void Draw(const Point& screenPos);
|
||||||
virtual void Tick(float dt);
|
virtual void Tick(float dt);
|
||||||
|
|
||||||
virtual void OnThumbnailReady(Thumbnail * thumb);
|
virtual void OnResponseReady(void * imagePtr);
|
||||||
|
|
||||||
void SetSelected(bool selected_) { selected = selected_; }
|
void SetSelected(bool selected_) { selected = selected_; }
|
||||||
bool GetSelected() { return selected; }
|
bool GetSelected() { return selected; }
|
||||||
|
@@ -543,15 +543,15 @@ void PreviewView::NotifyCommentsChanged(PreviewModel * sender)
|
|||||||
int usernameY = currentY+5, commentY;
|
int usernameY = currentY+5, commentY;
|
||||||
if(showAvatars)
|
if(showAvatars)
|
||||||
{
|
{
|
||||||
tempAvatar = new ui::AvatarButton(ui::Point(4, currentY+4), ui::Point(26, 26), comments->at(i)->authorName);
|
tempAvatar = new ui::AvatarButton(ui::Point(2, currentY+7), ui::Point(26, 26), comments->at(i)->authorName);
|
||||||
commentComponents.push_back(tempAvatar);
|
commentComponents.push_back(tempAvatar);
|
||||||
commentsPanel->AddChild(tempAvatar);
|
commentsPanel->AddChild(tempAvatar);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(showAvatars)
|
if(showAvatars)
|
||||||
tempUsername = new ui::Label(ui::Point(31, currentY+5), ui::Point(Size.X-((XRES/2) + 13), 16), comments->at(i)->authorName);
|
tempUsername = new ui::Label(ui::Point(31, currentY+3), ui::Point(Size.X-((XRES/2) + 13), 16), comments->at(i)->authorName);
|
||||||
else
|
else
|
||||||
tempUsername = new ui::Label(ui::Point(5, currentY+5), ui::Point(Size.X-((XRES/2) + 13), 16), comments->at(i)->authorName);
|
tempUsername = new ui::Label(ui::Point(5, currentY+3), ui::Point(Size.X-((XRES/2) + 13), 16), comments->at(i)->authorName);
|
||||||
tempUsername->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
tempUsername->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||||
tempUsername->Appearance.VerticalAlign = ui::Appearance::AlignBottom;
|
tempUsername->Appearance.VerticalAlign = ui::Appearance::AlignBottom;
|
||||||
currentY += 16;
|
currentY += 16;
|
||||||
@@ -560,6 +560,9 @@ void PreviewView::NotifyCommentsChanged(PreviewModel * sender)
|
|||||||
commentsPanel->AddChild(tempUsername);
|
commentsPanel->AddChild(tempUsername);
|
||||||
|
|
||||||
commentY = currentY+5;
|
commentY = currentY+5;
|
||||||
|
if(showAvatars)
|
||||||
|
tempComment = new ui::Label(ui::Point(31, currentY+5), ui::Point(Size.X-((XRES/2) + 13 + 26), -1), comments->at(i)->comment);
|
||||||
|
else
|
||||||
tempComment = new ui::Label(ui::Point(5, currentY+5), ui::Point(Size.X-((XRES/2) + 13), -1), comments->at(i)->comment);
|
tempComment = new ui::Label(ui::Point(5, currentY+5), ui::Point(Size.X-((XRES/2) + 13), -1), comments->at(i)->comment);
|
||||||
tempComment->SetMultiline(true);
|
tempComment->SetMultiline(true);
|
||||||
tempComment->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
tempComment->Appearance.HorizontalAlign = ui::Appearance::AlignLeft;
|
||||||
|
@@ -123,14 +123,14 @@ void LocalSaveActivity::OnDraw()
|
|||||||
|
|
||||||
if(thumbnail)
|
if(thumbnail)
|
||||||
{
|
{
|
||||||
g->draw_image(thumbnail->Data, Position.X+(Size.X-thumbnail->Size.X)/2, Position.Y+45, thumbnail->Size.X, thumbnail->Size.Y, 255);
|
g->draw_image(thumbnail, Position.X+(Size.X-thumbnail->Width)/2, Position.Y+45, 255);
|
||||||
g->drawrect(Position.X+(Size.X-thumbnail->Size.X)/2, Position.Y+45, thumbnail->Size.X, thumbnail->Size.Y, 180, 180, 180, 255);
|
g->drawrect(Position.X+(Size.X-thumbnail->Width)/2, Position.Y+45, thumbnail->Width, thumbnail->Height, 180, 180, 180, 255);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LocalSaveActivity::OnThumbnailReady(Thumbnail * thumbnail)
|
void LocalSaveActivity::OnRequestReady(void * imagePtr)
|
||||||
{
|
{
|
||||||
this->thumbnail = thumbnail;
|
this->thumbnail = (VideoBuffer*)imagePtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
LocalSaveActivity::~LocalSaveActivity()
|
LocalSaveActivity::~LocalSaveActivity()
|
||||||
|
@@ -2,14 +2,14 @@
|
|||||||
|
|
||||||
#include "Activity.h"
|
#include "Activity.h"
|
||||||
#include "client/SaveFile.h"
|
#include "client/SaveFile.h"
|
||||||
#include "client/ThumbnailListener.h"
|
#include "client/RequestListener.h"
|
||||||
|
|
||||||
namespace ui
|
namespace ui
|
||||||
{
|
{
|
||||||
class Textbox;
|
class Textbox;
|
||||||
}
|
}
|
||||||
|
|
||||||
class Thumbnail;
|
class VideoBuffer;
|
||||||
|
|
||||||
class FileSavedCallback
|
class FileSavedCallback
|
||||||
{
|
{
|
||||||
@@ -19,10 +19,10 @@ public:
|
|||||||
virtual void FileSaved(SaveFile * file) {}
|
virtual void FileSaved(SaveFile * file) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class LocalSaveActivity: public WindowActivity, public ThumbnailListener
|
class LocalSaveActivity: public WindowActivity, public RequestListener
|
||||||
{
|
{
|
||||||
SaveFile save;
|
SaveFile save;
|
||||||
Thumbnail * thumbnail;
|
VideoBuffer * thumbnail;
|
||||||
ui::Textbox * filenameField;
|
ui::Textbox * filenameField;
|
||||||
class CancelAction;
|
class CancelAction;
|
||||||
class SaveAction;
|
class SaveAction;
|
||||||
@@ -34,6 +34,6 @@ public:
|
|||||||
void saveWrite(std::string finalFilename);
|
void saveWrite(std::string finalFilename);
|
||||||
virtual void Save();
|
virtual void Save();
|
||||||
virtual void OnDraw();
|
virtual void OnDraw();
|
||||||
virtual void OnThumbnailReady(Thumbnail * thumbnail);
|
virtual void OnRequestReady(void * imagePtr);
|
||||||
virtual ~LocalSaveActivity();
|
virtual ~LocalSaveActivity();
|
||||||
};
|
};
|
@@ -3,7 +3,6 @@
|
|||||||
#include "interface/Textbox.h"
|
#include "interface/Textbox.h"
|
||||||
#include "interface/Button.h"
|
#include "interface/Button.h"
|
||||||
#include "interface/Checkbox.h"
|
#include "interface/Checkbox.h"
|
||||||
#include "search/Thumbnail.h"
|
|
||||||
#include "client/RequestBroker.h"
|
#include "client/RequestBroker.h"
|
||||||
#include "dialogues/ErrorMessage.h"
|
#include "dialogues/ErrorMessage.h"
|
||||||
#include "dialogues/ConfirmPrompt.h"
|
#include "dialogues/ConfirmPrompt.h"
|
||||||
@@ -245,14 +244,14 @@ void ServerSaveActivity::OnDraw()
|
|||||||
|
|
||||||
if(thumbnail)
|
if(thumbnail)
|
||||||
{
|
{
|
||||||
g->draw_image(thumbnail->Data, Position.X+(Size.X/2)+((Size.X/2)-thumbnail->Size.X)/2, Position.Y+25, thumbnail->Size.X, thumbnail->Size.Y, 255);
|
g->draw_image(thumbnail, Position.X+(Size.X/2)+((Size.X/2)-thumbnail->Width)/2, Position.Y+25, 255);
|
||||||
g->drawrect(Position.X+(Size.X/2)+((Size.X/2)-thumbnail->Size.X)/2, Position.Y+25, thumbnail->Size.X, thumbnail->Size.Y, 180, 180, 180, 255);
|
g->drawrect(Position.X+(Size.X/2)+((Size.X/2)-thumbnail->Width)/2, Position.Y+25, thumbnail->Width, thumbnail->Height, 180, 180, 180, 255);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ServerSaveActivity::OnThumbnailReady(Thumbnail * thumbnail)
|
void ServerSaveActivity::OnRequestReady(void * imagePtr)
|
||||||
{
|
{
|
||||||
this->thumbnail = thumbnail;
|
this->thumbnail = (VideoBuffer *)imagePtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
ServerSaveActivity::~ServerSaveActivity()
|
ServerSaveActivity::~ServerSaveActivity()
|
||||||
|
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "Activity.h"
|
#include "Activity.h"
|
||||||
#include "client/SaveInfo.h"
|
#include "client/SaveInfo.h"
|
||||||
#include "client/ThumbnailListener.h"
|
#include "client/RequestListener.h"
|
||||||
#include "tasks/TaskListener.h"
|
#include "tasks/TaskListener.h"
|
||||||
|
|
||||||
namespace ui
|
namespace ui
|
||||||
@@ -13,7 +13,7 @@ namespace ui
|
|||||||
|
|
||||||
class Task;
|
class Task;
|
||||||
class Thumbnail;
|
class Thumbnail;
|
||||||
class ServerSaveActivity: public WindowActivity, public ThumbnailListener, public TaskListener
|
class ServerSaveActivity: public WindowActivity, public RequestListener, public TaskListener
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
class SaveUploadedCallback
|
class SaveUploadedCallback
|
||||||
@@ -29,7 +29,7 @@ public:
|
|||||||
virtual void Save();
|
virtual void Save();
|
||||||
virtual void Exit();
|
virtual void Exit();
|
||||||
virtual void OnDraw();
|
virtual void OnDraw();
|
||||||
virtual void OnThumbnailReady(Thumbnail * thumbnail);
|
virtual void OnRequestReady(void * imagePtr);
|
||||||
virtual void OnTick(float dt);
|
virtual void OnTick(float dt);
|
||||||
virtual ~ServerSaveActivity();
|
virtual ~ServerSaveActivity();
|
||||||
protected:
|
protected:
|
||||||
@@ -37,7 +37,7 @@ protected:
|
|||||||
Task * saveUploadTask;
|
Task * saveUploadTask;
|
||||||
SaveUploadedCallback * callback;
|
SaveUploadedCallback * callback;
|
||||||
SaveInfo save;
|
SaveInfo save;
|
||||||
Thumbnail * thumbnail;
|
VideoBuffer * thumbnail;
|
||||||
ui::Textbox * nameField;
|
ui::Textbox * nameField;
|
||||||
ui::Textbox * descriptionField;
|
ui::Textbox * descriptionField;
|
||||||
ui::Checkbox * publishedCheckbox;
|
ui::Checkbox * publishedCheckbox;
|
||||||
|
Reference in New Issue
Block a user