Skip to content

Commit

Permalink
C client: Optimise screenshot saving with OpenGL
Browse files Browse the repository at this point in the history
  • Loading branch information
UnknownShadow200 committed Oct 10, 2018
1 parent 8782d25 commit c8c2225
Show file tree
Hide file tree
Showing 9 changed files with 33 additions and 46 deletions.
2 changes: 1 addition & 1 deletion src/Animations.c
Expand Up @@ -324,7 +324,7 @@ static void Animations_PackChanged(void* obj) {

static void Animations_FileChanged(void* obj, struct Stream* stream, const String* name) {
if (String_CaselessEqualsConst(name, "animations.png")) {
ReturnCode res = Bitmap_DecodePng(&anims_bmp, stream);
ReturnCode res = Png_Decode(&anims_bmp, stream);
if (!res) return;

Chat_LogError2(res, "decoding", name);
Expand Down
14 changes: 8 additions & 6 deletions src/Bitmap.c
Expand Up @@ -58,7 +58,7 @@ enum PNG_FILTER {
typedef void (*Png_RowExpander)(int width, uint32_t* palette, uint8_t* src, uint32_t* dst);
uint8_t png_sig[PNG_SIG_SIZE] = { 137, 80, 78, 71, 13, 10, 26, 10 };

bool Bitmap_DetectPng(uint8_t* data, uint32_t len) {
bool Png_Detect(uint8_t* data, uint32_t len) {
if (len < PNG_SIG_SIZE) return false;
int i;

Expand Down Expand Up @@ -324,14 +324,14 @@ static void Png_ComputeTransparency(Bitmap* bmp, uint32_t transparentCol) {
/* Most bits per sample is 16. Most samples per pixel is 4. Add 1 for filter byte. */
#define PNG_BUFFER_SIZE ((PNG_MAX_DIMS * 2 * 4 + 1) * 2)
/* TODO: Test a lot of .png files and ensure output is right */
ReturnCode Bitmap_DecodePng(Bitmap* bmp, struct Stream* stream) {
ReturnCode Png_Decode(Bitmap* bmp, struct Stream* stream) {
Bitmap_Create(bmp, 0, 0, NULL);
uint8_t tmp[PNG_PALETTE * 3];
ReturnCode res;

res = Stream_Read(stream, tmp, PNG_SIG_SIZE);
if (res) return res;
if (!Bitmap_DetectPng(tmp, PNG_SIG_SIZE)) return PNG_ERR_INVALID_SIG;
if (!Png_Detect(tmp, PNG_SIG_SIZE)) return PNG_ERR_INVALID_SIG;

uint32_t transparentCol = PackedCol_ARGB(0, 0, 0, 255);
uint8_t col, bitsPerSample, bytesPerPixel;
Expand Down Expand Up @@ -607,7 +607,7 @@ static void Png_EncodeRow(uint8_t* src, uint8_t* cur, uint8_t* prior, uint8_t* b
best[0] = bestFilter;
}

ReturnCode Bitmap_EncodePng(Bitmap* bmp, struct Stream* stream) {
ReturnCode Png_Encode(Bitmap* bmp, struct Stream* stream, Png_RowSelector selectRow) {
ReturnCode res;
uint8_t tmp[32];
if ((res = Stream_Write(stream, png_sig, PNG_SIG_SIZE))) return res;
Expand Down Expand Up @@ -649,9 +649,11 @@ ReturnCode Bitmap_EncodePng(Bitmap* bmp, struct Stream* stream) {
ZLib_MakeStream(&zlStream, &zlState, stream);

for (y = 0; y < bmp->Height; y++) {
uint8_t* src = (uint8_t*)Bitmap_GetRow(bmp, y);
int row = selectRow(bmp, y);
uint8_t* src = (uint8_t*)Bitmap_GetRow(bmp, row);
uint8_t* prev = (y & 1) == 0 ? prevLine : curLine;
uint8_t* cur = (y & 1) == 0 ? curLine : prevLine;
uint8_t* cur = (y & 1) == 0 ? curLine : prevLine;

Png_EncodeRow(src, cur, prev, bestLine, lineSize);
/* +1 for filter byte */
if ((res = Stream_Write(&zlStream, bestLine, lineSize + 1))) return res;
Expand Down
7 changes: 4 additions & 3 deletions src/Bitmap.h
Expand Up @@ -19,12 +19,13 @@ void Bitmap_Allocate(Bitmap* bmp, int width, int 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(Bitmap* bmp, int width, int height);

bool Bitmap_DetectPng(uint8_t* data, uint32_t len);
bool Png_Detect(uint8_t* data, uint32_t len);
typedef int (*Png_RowSelector)(Bitmap* bmp, int row);
/*
Partially based off information from
https://handmade.network/forums/wip/t/2363-implementing_a_basic_png_reader_the_handmade_way
https://github.com/nothings/stb/blob/master/stb_image.h
*/
ReturnCode Bitmap_DecodePng(Bitmap* bmp, struct Stream* stream);
ReturnCode Bitmap_EncodePng(Bitmap* bmp, struct Stream* stream);
ReturnCode Png_Decode(Bitmap* bmp, struct Stream* stream);
ReturnCode Png_Encode(Bitmap* bmp, struct Stream* stream, Png_RowSelector selectRow);
#endif
2 changes: 1 addition & 1 deletion src/Entity.c
Expand Up @@ -697,7 +697,7 @@ static void Player_CheckSkin(struct Player* p) {
struct Stream mem; Bitmap bmp;
Stream_ReadonlyMemory(&mem, item.ResultData, item.ResultSize);

ReturnCode res = Bitmap_DecodePng(&bmp, &mem);
ReturnCode res = Png_Decode(&bmp, &mem);
if (res) {
Chat_LogError2(res, "decoding", &url);
Mem_Free(bmp.Scan0); return;
Expand Down
6 changes: 3 additions & 3 deletions src/Game.c
Expand Up @@ -209,7 +209,7 @@ bool Game_CanPick(BlockID block) {

bool Game_UpdateTexture(GfxResourceID* texId, struct Stream* src, const String* file, uint8_t* skinType) {
Bitmap bmp;
ReturnCode res = Bitmap_DecodePng(&bmp, src);
ReturnCode res = Png_Decode(&bmp, src);
if (res) { Chat_LogError2(res, "decoding", file); }

bool success = !res && Game_ValidateBitmap(file, &bmp);
Expand Down Expand Up @@ -287,7 +287,7 @@ static void Game_OnNewMapLoadedCore(void* obj) {
static void Game_TextureChangedCore(void* obj, struct Stream* src, const String* name) {
Bitmap bmp;
if (String_CaselessEqualsConst(name, "terrain.png")) {
ReturnCode res = Bitmap_DecodePng(&bmp, src);
ReturnCode res = Png_Decode(&bmp, src);

if (res) {
Chat_LogError2(res, "decoding", name);
Expand All @@ -296,7 +296,7 @@ static void Game_TextureChangedCore(void* obj, struct Stream* src, const String*
Mem_Free(bmp.Scan0);
}
} else if (String_CaselessEqualsConst(name, "default.png")) {
ReturnCode res = Bitmap_DecodePng(&bmp, src);
ReturnCode res = Png_Decode(&bmp, src);

if (res) {
Chat_LogError2(res, "decoding", name);
Expand Down
26 changes: 6 additions & 20 deletions src/Graphics.c
Expand Up @@ -393,7 +393,7 @@ void Gfx_SetAlphaArgBlend(bool enabled) {
}

void Gfx_ClearCol(PackedCol col) { d3d9_clearCol = col.Packed; }
void Gfx_SetColourWriteMask(bool r, bool g, bool b, bool a) {
void Gfx_SetColWriteMask(bool r, bool g, bool b, bool a) {
DWORD channels = (r ? 1u : 0u) | (g ? 2u : 0u) | (b ? 4u : 0u) | (a ? 8u : 0u);
D3D9_SetRenderState(D3DRS_COLORWRITEENABLE, channels, "D3D9_SetColourWrite");
}
Expand Down Expand Up @@ -608,6 +608,7 @@ void Gfx_CalcPerspectiveMatrix(float fov, float aspect, float zNear, float zFar,
/*########################################################################################################################*
*-----------------------------------------------------------Misc----------------------------------------------------------*
*#########################################################################################################################*/
static int D3D9_SelectRow(Bitmap* bmp, int y) { return y; }
ReturnCode Gfx_TakeScreenshot(struct Stream* output, int width, int height) {
IDirect3DSurface9* backbuffer = NULL;
IDirect3DSurface9* temp = NULL;
Expand All @@ -625,7 +626,7 @@ ReturnCode Gfx_TakeScreenshot(struct Stream* output, int width, int height) {
if (res) goto finished;
{
Bitmap bmp; Bitmap_Create(&bmp, width, height, rect.pBits);
res = Bitmap_EncodePng(&bmp, output);
res = Png_Encode(&bmp, output, D3D9_SelectRow);
if (res) { IDirect3DSurface9_UnlockRect(temp); goto finished; }
}
res = IDirect3DSurface9_UnlockRect(temp);
Expand Down Expand Up @@ -954,7 +955,7 @@ void Gfx_ClearCol(PackedCol col) {
gl_lastClearCol = col;
}

void Gfx_SetColourWriteMask(bool r, bool g, bool b, bool a) {
void Gfx_SetColWriteMask(bool r, bool g, bool b, bool a) {
glColorMask(r, g, b, a);
}

Expand Down Expand Up @@ -1219,27 +1220,12 @@ void Gfx_CalcPerspectiveMatrix(float fov, float aspect, float zNear, float zFar,
/*########################################################################################################################*
*-----------------------------------------------------------Misc----------------------------------------------------------*
*#########################################################################################################################*/
static int GL_SelectRow(Bitmap* bmp, int y) { return (bmp->Height - 1) - y; }
ReturnCode Gfx_TakeScreenshot(struct Stream* output, int width, int height) {
Bitmap bmp; Bitmap_Allocate(&bmp, width, height);
glReadPixels(0, 0, width, height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, bmp.Scan0);
uint8_t tmp[PNG_MAX_DIMS * BITMAP_SIZEOF_PIXEL];

/* flip vertically around y */
int x, y;
uint32_t stride = (uint32_t)(bmp.Width) * BITMAP_SIZEOF_PIXEL;
for (y = 0; y < height / 2; y++) {
uint32_t* src = Bitmap_GetRow(&bmp, y);
uint32_t* dst = Bitmap_GetRow(&bmp, (height - 1) - y);

Mem_Copy(tmp, src, stride);
Mem_Copy(src, dst, stride);
Mem_Copy(dst, tmp, stride);
/*for (x = 0; x < bmp.Width; x++) {
uint32_t temp = dst[x]; dst[x] = src[x]; src[x] = temp;
}*/
}

ReturnCode res = Bitmap_EncodePng(&bmp, output);
ReturnCode res = Png_Encode(&bmp, output, GL_SelectRow);
Mem_Free(bmp.Scan0);
return res;
}
Expand Down
14 changes: 6 additions & 8 deletions src/Graphics.h
Expand Up @@ -9,10 +9,6 @@
*/
struct Stream;

#define ICOUNT(verticesCount) (((verticesCount) >> 2) * 6)
#define VERTEX_FORMAT_P3FC4B 0
#define VERTEX_FORMAT_P3FT2FC4B 1

enum COMPARE_FUNC {
COMPARE_FUNC_ALWAYS, COMPARE_FUNC_NOTEQUAL, COMPARE_FUNC_NEVER,
COMPARE_FUNC_LESS, COMPARE_FUNC_LESSEQUAL, COMPARE_FUNC_EQUAL,
Expand All @@ -23,8 +19,9 @@ enum BLEND_FUNC {
BLEND_FUNC_INV_SRC_ALPHA, BLEND_FUNC_DST_ALPHA, BLEND_FUNC_INV_DST_ALPHA,
};

enum FOG_FUNC { FOG_LINEAR, FOG_EXP, FOG_EXP2, };
enum MATRIX_TYPE { MATRIX_TYPE_PROJECTION, MATRIX_TYPE_VIEW, MATRIX_TYPE_TEXTURE };
enum VERTEX_FORMAT { VERTEX_FORMAT_P3FC4B, VERTEX_FORMAT_P3FT2FC4B };
enum FOG_FUNC { FOG_LINEAR, FOG_EXP, FOG_EXP2 };
enum MATRIX_TYPE { MATRIX_TYPE_PROJECTION, MATRIX_TYPE_VIEW, MATRIX_TYPE_TEXTURE };

void Gfx_Init(void);
void Gfx_Free(void);
Expand All @@ -36,10 +33,11 @@ bool Gfx_Mipmaps;
bool Gfx_CustomMipmapsLevels;
struct Matrix Gfx_View, Gfx_Projection;

#define ICOUNT(verticesCount) (((verticesCount) >> 2) * 6)
#define GFX_MAX_INDICES (65536 / 4 * 6)
#define GFX_MAX_VERTICES 65536

/* Callback invoked when the current context is lost, and is repeatedly invoked until the context can be retrieved. */
/* Callback invoked when the context is lost. Repeatedly invoked until a context can be retrieved. */
ScheduledTaskCallback Gfx_LostContextFunction;

GfxResourceID Gfx_CreateTexture(Bitmap* bmp, bool managedPool, bool mipmaps);
Expand Down Expand Up @@ -69,7 +67,7 @@ void Gfx_Clear(void);
void Gfx_ClearCol(PackedCol col);
void Gfx_SetDepthTest(bool enabled);
void Gfx_SetDepthTestFunc(int compareFunc);
void Gfx_SetColourWriteMask(bool r, bool g, bool b, bool a);
void Gfx_SetColWriteMask(bool r, bool g, bool b, bool a);
void Gfx_SetDepthWrite(bool enabled);

GfxResourceID Gfx_CreateDynamicVb(int vertexFormat, int maxVertices);
Expand Down
4 changes: 2 additions & 2 deletions src/MapRenderer.c
Expand Up @@ -220,7 +220,7 @@ void MapRenderer_RenderTranslucent(double delta) {
Gfx_SetBatchFormat(VERTEX_FORMAT_P3FT2FC4B);
Gfx_SetTexturing(false);
Gfx_SetAlphaBlending(false);
Gfx_SetColourWriteMask(false, false, false, false);
Gfx_SetColWriteMask(false, false, false, false);

int batch;
for (batch = 0; batch < MapRenderer_1DUsedCount; batch++) {
Expand All @@ -235,7 +235,7 @@ void MapRenderer_RenderTranslucent(double delta) {
/* Then actually draw the transluscent blocks */
Gfx_SetAlphaBlending(true);
Gfx_SetTexturing(true);
Gfx_SetColourWriteMask(true, true, true, true);
Gfx_SetColWriteMask(true, true, true, true);
Gfx_SetDepthWrite(false); /* we already calculated depth values in depth pass */

Gfx_EnableMipmaps();
Expand Down
4 changes: 2 additions & 2 deletions src/TexturePack.c
Expand Up @@ -440,7 +440,7 @@ void TexturePack_ExtractZip_File(const String* filename) {

ReturnCode TexturePack_ExtractTerrainPng(struct Stream* stream) {
Bitmap bmp;
ReturnCode res = Bitmap_DecodePng(&bmp, stream);
ReturnCode res = Png_Decode(&bmp, stream);

if (!res) {
Event_RaiseVoid(&TextureEvents_PackChanged);
Expand Down Expand Up @@ -499,7 +499,7 @@ void TexturePack_Extract_Req(struct AsyncRequest* item) {
TextureCache_AddLastModified(&url, &item->LastModified);

struct Stream mem; Stream_ReadonlyMemory(&mem, data, len);
bool png = Bitmap_DetectPng(data, len);
bool png = Png_Detect(data, len);
ReturnCode res = png ? TexturePack_ExtractTerrainPng(&mem)
: TexturePack_ExtractZip(&mem);
const char* operation = png ? "decoding" : "extracting";
Expand Down

0 comments on commit c8c2225

Please sign in to comment.