fix terrain.png in C client being cached discarding alpha channel

This commit is contained in:
UnknownShadow200 2018-07-20 15:13:07 +10:00
parent 0086f047f8
commit d60472be45
11 changed files with 75 additions and 156 deletions

View File

@ -6,17 +6,7 @@
#include "GameStructs.h"
void ASyncRequest_Free(struct AsyncRequest* request) {
switch (request->RequestType) {
case REQUEST_TYPE_IMAGE:
Platform_MemFree(&request->ResultBitmap.Scan0);
break;
case REQUEST_TYPE_DATA:
Platform_MemFree(&request->ResultData.Ptr);
break;
case REQUEST_TYPE_STRING:
Platform_MemFree(&request->ResultString.buffer);
break;
}
Platform_MemFree(&request->ResultData);
}
#define ASYNCREQUESTLIST_DEFELEMS 10
@ -127,37 +117,25 @@ void AsyncDownloader_GetSkin(STRING_PURE String* id, STRING_PURE String* skinNam
String_AppendConst(&url, ".png");
}
AsyncDownloader_Add(&url, false, id, REQUEST_TYPE_IMAGE, NULL, NULL, NULL);
AsyncDownloader_Add(&url, false, id, REQUEST_TYPE_DATA, NULL, NULL, NULL);
}
void AsyncDownloader_GetData(STRING_PURE String* url, bool priority, STRING_PURE String* id) {
AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_DATA, NULL, NULL, NULL);
}
void AsyncDownloader_GetImage(STRING_PURE String* url, bool priority, STRING_PURE String* id) {
AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_IMAGE, NULL, NULL, NULL);
}
void AsyncDownloader_GetString(STRING_PURE String* url, bool priority, STRING_PURE String* id) {
AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_STRING, NULL, NULL, NULL);
}
void AsyncDownloader_GetContentLength(STRING_PURE String* url, bool priority, STRING_PURE String* id) {
AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_CONTENT_LENGTH, NULL, NULL, NULL);
}
void AsyncDownloader_PostString(STRING_PURE String* url, bool priority, STRING_PURE String* id, STRING_PURE String* contents) {
AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_STRING, NULL, NULL, contents);
AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_DATA, NULL, NULL, contents);
}
void AsyncDownloader_GetDataEx(STRING_PURE String* url, bool priority, STRING_PURE String* id, DateTime* lastModified, STRING_PURE String* etag) {
AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_DATA, lastModified, etag, NULL);
}
void AsyncDownloader_GetImageEx(STRING_PURE String* url, bool priority, STRING_PURE String* id, DateTime* lastModified, STRING_PURE String* etag) {
AsyncDownloader_Add(url, priority, id, REQUEST_TYPE_IMAGE, lastModified, etag, NULL);
}
void AsyncDownloader_PurgeOldEntriesTask(struct ScheduledTask* task) {
Platform_MutexLock(async_processedMutex);
{
@ -247,27 +225,8 @@ static void AsyncDownloader_ProcessRequest(struct AsyncRequest* request) {
UInt64 addr = (UInt64)data;
Platform_Log2("OK I got the DATA! %i bytes at %x", &size, &addr);
struct Stream memStream;
switch (request->RequestType) {
case REQUEST_TYPE_DATA:
request->ResultData.Ptr = data;
request->ResultData.Size = size;
break;
case REQUEST_TYPE_IMAGE:
Stream_ReadonlyMemory(&memStream, data, size, &url);
Bitmap_DecodePng(&request->ResultBitmap, &memStream);
break;
case REQUEST_TYPE_STRING:
request->ResultString = String_Init(data, size, size);
break;
case REQUEST_TYPE_CONTENT_LENGTH:
request->ResultContentLength = size;
break;
}
request->ResultData = data;
request->ResultSize = size;
}
static void AsyncDownloader_CompleteResult(struct AsyncRequest* request) {

View File

@ -9,10 +9,7 @@
struct IGameComponent;
struct ScheduledTask;
enum REQUEST_TYPE {
REQUEST_TYPE_DATA, REQUEST_TYPE_IMAGE,
REQUEST_TYPE_STRING, REQUEST_TYPE_CONTENT_LENGTH,
};
enum REQUEST_TYPE { REQUEST_TYPE_DATA, REQUEST_TYPE_CONTENT_LENGTH };
#define ASYNC_PROGRESS_NOTHING -3
#define ASYNC_PROGRESS_MAKING_REQUEST -2
#define ASYNC_PROGRESS_FETCHING_DATA -1
@ -25,12 +22,8 @@ struct AsyncRequest {
DateTime TimeDownloaded;
UInt16 StatusCode;
union {
struct { void* Ptr; UInt32 Size; } ResultData;
struct Bitmap ResultBitmap;
String ResultString;
UInt32 ResultContentLength;
};
void* ResultData;
UInt32 ResultSize;
DateTime LastModified; /* Time item cached at (if at all) */
UInt8 Etag[String_BufferSize(STRING_SIZE)]; /* ETag of cached item (if any) */
@ -42,13 +35,10 @@ void ASyncRequest_Free(struct AsyncRequest* request);
void AsyncDownloader_MakeComponent(struct IGameComponent* comp);
void AsyncDownloader_GetSkin(STRING_PURE String* id, STRING_PURE String* skinName);
void AsyncDownloader_GetData(STRING_PURE String* url, bool priority, STRING_PURE String* id);
void AsyncDownloader_GetImage(STRING_PURE String* url, bool priority, STRING_PURE String* id);
void AsyncDownloader_GetString(STRING_PURE String* url, bool priority, STRING_PURE String* id);
void AsyncDownloader_GetContentLength(STRING_PURE String* url, bool priority, STRING_PURE String* id);
/* TODO: Implement post */
//void AsyncDownloader_PostString(STRING_PURE String* url, bool priority, STRING_PURE String* id, STRING_PURE String* contents);
void AsyncDownloader_GetDataEx(STRING_PURE String* url, bool priority, STRING_PURE String* id, DateTime* lastModified, STRING_PURE String* etag);
void AsyncDownloader_GetImageEx(STRING_PURE String* url, bool priority, STRING_PURE String* id, DateTime* lastModified, STRING_PURE String* etag);
bool AsyncDownloader_Get(STRING_PURE String* id, struct AsyncRequest* item);
bool AsyncDownloader_GetCurrent(struct AsyncRequest* request, Int32* progress);

View File

@ -63,13 +63,20 @@ enum PNG_FILTER {
typedef void(*Png_RowExpander)(UInt8 bpp, Int32 width, UInt32* palette, UInt8* src, UInt32* dst);
UInt8 png_sig[PNG_SIG_SIZE] = { 137, 80, 78, 71, 13, 10, 26, 10 };
bool Bitmap_DetectPng(UInt8* data, UInt32 len) {
if (len < PNG_SIG_SIZE) return false;
Int32 i;
for (i = 0; i < PNG_SIG_SIZE; i++) {
if (data[i] != png_sig[i]) return false;
}
return true;
}
static void Png_CheckHeader(struct Stream* stream) {
UInt8 header[PNG_SIG_SIZE];
Stream_Read(stream, header, PNG_SIG_SIZE);
Int32 i;
for (i = 0; i < PNG_SIG_SIZE; i++) {
if (header[i] != png_sig[i]) ErrorHandler_Fail("Invalid PNG header");
}
if (!Bitmap_DetectPng(header, PNG_SIG_SIZE)) ErrorHandler_Fail("Invalid PNG header");
}
static void Png_Reconstruct(UInt8 type, UInt8 bytesPerPixel, UInt8* line, UInt8* prior, UInt32 lineLen) {

View File

@ -25,6 +25,7 @@ void Bitmap_Allocate(struct Bitmap* bmp, Int32 width, Int32 height);
/* Allocates a power-of-2 sized bitmap larger or equal to to the given size, and clears it to 0. You are responsible for freeing its memory! */
void Bitmap_AllocateClearedPow2(struct Bitmap* bmp, Int32 width, Int32 height);
bool Bitmap_DetectPng(UInt8* data, UInt32 len);
/*
Partially based off information from
https://handmade.network/forums/wip/t/2363-implementing_a_basic_png_reader_the_handmade_way

View File

@ -697,8 +697,12 @@ static void Player_CheckSkin(struct Player* player) {
struct AsyncRequest item;
if (!AsyncDownloader_Get(&skin, &item)) return;
struct Bitmap bmp = item.ResultBitmap;
if (bmp.Scan0 == NULL) { Player_SetSkinAll(player, true); return; }
if (item.ResultData == NULL) { Player_SetSkinAll(player, true); return; }
String url = String_FromRawArray(item.URL);
struct Stream mem; struct Bitmap bmp;
Stream_ReadonlyMemory(&mem, item.ResultData, item.ResultSize, &url);
Bitmap_DecodePng(&bmp, &mem);
Gfx_DeleteTexture(&entity->TextureId);
Player_SetSkinAll(player, true);

View File

@ -3324,7 +3324,7 @@ static void TexPackOverlay_Render(struct GuiElem* elem, Real64 delta) {
struct AsyncRequest item;
if (!AsyncDownloader_Get(&identifier, &item)) return;
screen->ContentLength = item.ResultContentLength;
screen->ContentLength = item.ResultSize;
if (screen->ContentLength == 0) return;
screen->ContextLost(elem);

View File

@ -200,7 +200,7 @@ static void WoM_CheckMotd(void) {
applied in the new world if the async 'get env request' didn't complete before the old world was unloaded */
wom_counter++;
WoM_UpdateIdentifier();
AsyncDownloader_GetString(&url, true, &wom_identifier);
AsyncDownloader_GetData(&url, true, &wom_identifier);
wom_sendId = true;
}
@ -288,11 +288,13 @@ static void WoM_Reset(void) {
static void WoM_Tick(void) {
struct AsyncRequest item;
bool success = AsyncDownloader_Get(&wom_identifier, &item);
if (success && item.ResultString.length > 0) {
Wom_ParseConfig(&item.ResultString);
ASyncRequest_Free(&item);
if (!AsyncDownloader_Get(&wom_identifier, &item)) return;
if (item.ResultData) {
String str = String_Init(item.ResultData, item.ResultSize, item.ResultSize);
Wom_ParseConfig(&str);
}
ASyncRequest_Free(&item);
}

View File

@ -60,47 +60,27 @@ void ServerConnection_DownloadTexturePack(STRING_PURE String* url) {
TextureCache_GetLastModified(url, &lastModified);
TextureCache_GetETag(url, &etag);
}
TexturePack_ExtractCurrent(url);
String zip = String_FromConst(".zip");
if (String_ContainsString(url, &zip)) {
String texPack = String_FromConst("texturePack");
AsyncDownloader_GetDataEx(url, true, &texPack, &lastModified, &etag);
} else {
String terrain = String_FromConst("terrain");
AsyncDownloader_GetImageEx(url, true, &terrain, &lastModified, &etag);
}
}
void ServerConnection_LogResourceFail(struct AsyncRequest* item) {
Int32 status = item->StatusCode;
if (status == 0 || status == 304) return;
UChar msgBuffer[String_BufferSize(STRING_SIZE)];
String msg = String_InitAndClearArray(msgBuffer);
String_Format1(&msg, "&c%i error when trying to download texture pack", &status);
Chat_Add(&msg);
String texPack = String_FromConst("texturePack");
AsyncDownloader_GetDataEx(url, true, &texPack, &lastModified, &etag);
}
void ServerConnection_CheckAsyncResources(void) {
struct AsyncRequest item;
String terrain = String_FromConst("terrain");
String texPack = String_FromConst("texturePack");
if (!AsyncDownloader_Get(&texPack, &item)) return;
if (AsyncDownloader_Get(&terrain, &item)) {
if (item.ResultBitmap.Scan0 != NULL) {
TexturePack_ExtractTerrainPng_Req(&item);
} else {
ServerConnection_LogResourceFail(&item);
}
}
if (item.ResultData) {
TexturePack_Extract_Req(&item);
} else {
Int32 status = item.StatusCode;
if (status == 0 || status == 304) return;
if (AsyncDownloader_Get(&texPack, &item)) {
if (item.ResultData.Ptr != NULL) {
TexturePack_ExtractTexturePack_Req(&item);
} else {
ServerConnection_LogResourceFail(&item);
}
UChar msgBuffer[String_BufferSize(STRING_SIZE)];
String msg = String_InitAndClearArray(msgBuffer);
String_Format1(&msg, "&c%i error when trying to download texture pack", &status);
Chat_Add(&msg);
}
}

View File

@ -63,7 +63,7 @@ ReturnCode Platform_SocketConnect(SocketPtr socket, STRING_PURE String* ip, Int3
ReturnCode Platform_SocketRead(SocketPtr socket, UInt8* buffer, UInt32 count, UInt32* modified) {
Int32 recvCount = recv(socket, buffer, count, 0);
if (recvCount == -1) { *modified = recvCount; return 0; }
if (recvCount != -1) { *modified = recvCount; return 0; }
*modified = 0; return Socket__Error();
}

View File

@ -354,39 +354,24 @@ void TextureCache_GetETag(STRING_PURE String* url, STRING_PURE String* etag) {
TexturePack_GetFromTags(url, etag, &cache_eTags);
}
static void* TextureCache_CreateFile(STRING_PURE String* path) {
String folder = String_FromConst(TEXCACHE_FOLDER);
if (!Platform_DirectoryExists(&folder)) {
ReturnCode dirResult = Platform_DirectoryCreate(&folder);
ErrorHandler_CheckOrFail(dirResult, "TextureCache_CreateFile - create directory");
}
void* file;
ReturnCode result = Platform_FileCreate(&file, path);
/* TODO: Should we just log failure to save? */
ErrorHandler_CheckOrFail(result, "TextureCache_CreateFile - open file");
return file;
}
void TextureCache_AddImage(STRING_PURE String* url, struct Bitmap* bmp) {
String path; TexCache_InitAndMakePath(url);
void* file = TextureCache_CreateFile(&path);
struct Stream stream; Stream_FromFile(&stream, file, &path);
{
Bitmap_EncodePng(bmp, &stream);
}
ReturnCode result = stream.Close(&stream);
ErrorHandler_CheckOrFail(result, "TextureCache_AddImage - close file");
}
void TextureCache_AddData(STRING_PURE String* url, UInt8* data, UInt32 length) {
String path; TexCache_InitAndMakePath(url);
void* file = TextureCache_CreateFile(&path);
ReturnCode result;
String folder = String_FromConst(TEXCACHE_FOLDER);
if (!Platform_DirectoryExists(&folder)) {
result = Platform_DirectoryCreate(&folder);
ErrorHandler_CheckOrFail(result, "TextureCache_AddData - create directory");
}
void* file; result = Platform_FileCreate(&file, &path);
/* TODO: Should we just log failure to save? */
ErrorHandler_CheckOrFail(result, "TextureCache_AddData - open file");
struct Stream stream; Stream_FromFile(&stream, file, &path);
{
Stream_Write(&stream, data, length);
}
ReturnCode result = stream.Close(&stream);
result = stream.Close(&stream);
ErrorHandler_CheckOrFail(result, "TextureCache_AddData - close file");
}
@ -495,29 +480,15 @@ void TexturePack_ExtractCurrent(STRING_PURE String* url) {
}
ReturnCode result = stream.Close(&stream);
ErrorHandler_CheckOrFail(result, "TexturePack_ExtractCurrent - slow stream");
ErrorHandler_CheckOrFail(result, "TexturePack_ExtractCurrent - close stream");
}
}
void TexturePack_ExtractTerrainPng_Req(struct AsyncRequest* item) {
void TexturePack_Extract_Req(struct AsyncRequest* item) {
String url = String_FromRawArray(item->URL);
String_Set(&World_TextureUrl, &url);
struct Bitmap bmp = item->ResultBitmap;
String etag = String_FromRawArray(item->Etag);
TextureCache_AddImage(&url, &bmp);
TextureCache_AddETag(&url, &etag);
TextureCache_AddLastModified(&url, &item->LastModified);
Event_RaiseVoid(&TextureEvents_PackChanged);
if (!Game_ChangeTerrainAtlas(&bmp)) ASyncRequest_Free(item);
}
void TexturePack_ExtractTexturePack_Req(struct AsyncRequest* item) {
String url = String_FromRawArray(item->URL);
String_Set(&World_TextureUrl, &url);
void* data = item->ResultData.Ptr;
UInt32 len = item->ResultData.Size;
void* data = item->ResultData;
UInt32 len = item->ResultSize;
String etag = String_FromRawArray(item->Etag);
TextureCache_AddData(&url, data, len);
@ -525,7 +496,14 @@ void TexturePack_ExtractTexturePack_Req(struct AsyncRequest* item) {
TextureCache_AddLastModified(&url, &item->LastModified);
String id = String_FromRawArray(item->ID);
struct Stream stream; Stream_ReadonlyMemory(&stream, data, len, &id);
TexturePack_ExtractZip(&stream);
struct Stream mem; Stream_ReadonlyMemory(&mem, data, len, &id);
if (Bitmap_DetectPng(data, len)) {
struct Bitmap bmp; Bitmap_DecodePng(&bmp, &mem);
Event_RaiseVoid(&TextureEvents_PackChanged);
if (!Game_ChangeTerrainAtlas(&bmp)) Platform_MemFree(&bmp.Scan0);
} else {
TexturePack_ExtractZip(&mem);
}
ASyncRequest_Free(item);
}

View File

@ -35,7 +35,6 @@ bool TextureCache_HasUrl(STRING_PURE String* url);
bool TextureCache_GetStream(STRING_PURE String* url, struct Stream* stream);
void TextureCache_GetLastModified(STRING_PURE String* url, DateTime* time);
void TextureCache_GetETag(STRING_PURE String* url, STRING_PURE String* etag);
void TextureCache_AddImage(STRING_PURE String* url, struct Bitmap* bmp);
void TextureCache_AddData(STRING_PURE String* url, UInt8* data, UInt32 length);
void TextureCache_AddETag(STRING_PURE String* url, STRING_PURE String* etag);
void TextureCache_AddLastModified(STRING_PURE String* url, DateTime* lastModified);
@ -43,6 +42,5 @@ void TextureCache_AddLastModified(STRING_PURE String* url, DateTime* lastModifie
void TexturePack_ExtractZip_File(STRING_PURE String* filename);
void TexturePack_ExtractDefault(void);
void TexturePack_ExtractCurrent(STRING_PURE String* url);
void TexturePack_ExtractTerrainPng_Req(struct AsyncRequest* item);
void TexturePack_ExtractTexturePack_Req(struct AsyncRequest* item);
void TexturePack_Extract_Req(struct AsyncRequest* item);
#endif