diff --git a/src/Animations.c b/src/Animations.c index 80ad23c7c..0ae87fea3 100644 --- a/src/Animations.c +++ b/src/Animations.c @@ -23,10 +23,9 @@ static float L_flameHeat[LIQUID_ANIM_MAX * LIQUID_ANIM_MAX]; static RNGState L_rnd; static bool L_rndInitalised; -static void LavaAnimation_Tick(uint32_t* ptr, int size) { +static void LavaAnimation_Tick(BitmapCol* ptr, int size) { int mask = size - 1, shift = Math_Log2(size); float soupHeat, potHeat, col; - uint8_t r, g, b; int x, y, i = 0; if (!L_rndInitalised) { @@ -74,10 +73,10 @@ static void LavaAnimation_Tick(uint32_t* ptr, int size) { col = 2.0f * L_soupHeat[i]; Math_Clamp(col, 0.0f, 1.0f); - r = (uint8_t)(col * 100.0f + 155.0f); - g = (uint8_t)(col * col * 255.0f); - b = (uint8_t)(col * col * col * col * 128.0f); - *ptr = PackedCol_ARGB(r, g, b, 255); + ptr->R = (uint8_t)(col * 100.0f + 155.0f); + ptr->G = (uint8_t)(col * col * 255.0f); + ptr->B = (uint8_t)(col * col * col * col * 128.0f); + ptr->A = 255; ptr++; i++; } @@ -94,10 +93,9 @@ static float W_flameHeat[LIQUID_ANIM_MAX * LIQUID_ANIM_MAX]; static RNGState W_rnd; static bool W_rndInitalised; -static void WaterAnimation_Tick(uint32_t* ptr, int size) { +static void WaterAnimation_Tick(BitmapCol* ptr, int size) { int mask = size - 1, shift = Math_Log2(size); float soupHeat, col; - uint8_t r, g, a; int x, y, i = 0; if (!W_rndInitalised) { @@ -126,10 +124,10 @@ static void WaterAnimation_Tick(uint32_t* ptr, int size) { Math_Clamp(col, 0.0f, 1.0f); col = col * col; - r = (uint8_t)(32.0f + col * 32.0f); - g = (uint8_t)(50.0f + col * 64.0f); - a = (uint8_t)(146.0f + col * 50.0f); - *ptr = PackedCol_ARGB(r, g, 255, a); + ptr->R = (uint8_t)(32.0f + col * 32.0f); + ptr->G = (uint8_t)(50.0f + col * 64.0f); + ptr->A = (uint8_t)(146.0f + col * 50.0f); + ptr->B = 255; ptr++; i++; } @@ -230,9 +228,9 @@ static void Animations_Draw(struct AnimationData* data, TextureLoc texLoc, int s if (!data) { if (texLoc == 30) { - LavaAnimation_Tick((uint32_t*)frame.Scan0, size); + LavaAnimation_Tick((BitmapCol*)frame.Scan0, size); } else if (texLoc == 14) { - WaterAnimation_Tick((uint32_t*)frame.Scan0, size); + WaterAnimation_Tick((BitmapCol*)frame.Scan0, size); } } else { srcX = data->FrameX + data->State * size; diff --git a/src/AxisLinesRenderer.c b/src/AxisLinesRenderer.c index daf3a0174..b4209fc4c 100644 --- a/src/AxisLinesRenderer.c +++ b/src/AxisLinesRenderer.c @@ -37,7 +37,11 @@ void AxisLinesRenderer_Render(double delta) { 1,2,2, 1,2,4, 3,2,4, 3,2,2, /* Z arrow */ 1,2,3, 1,4,3, 3,4,1, 3,2,1, /* Y arrow */ }; - static PackedCol cols[3] = { PACKEDCOL_RED, PACKEDCOL_BLUE, PACKEDCOL_GREEN }; + static PackedCol cols[3] = { + PACKEDCOL_CONST(255, 0, 0, 255), /* Red */ + PACKEDCOL_CONST( 0, 255, 0, 255), /* Green */ + PACKEDCOL_CONST( 0, 0, 255, 255), /* Blue */ + }; Vector3 coords[5], pos; VertexP3fC4b vertices[AXISLINES_NUM_VERTICES]; diff --git a/src/Bitmap.c b/src/Bitmap.c index a4dd3afa9..9169885a0 100644 --- a/src/Bitmap.c +++ b/src/Bitmap.c @@ -7,6 +7,13 @@ #include "Stream.h" #include "Errors.h" +BitmapCol BitmapCol_Scale(BitmapCol value, float t) { + value.R = (uint8_t)(value.R * t); + value.G = (uint8_t)(value.G * t); + value.B = (uint8_t)(value.B * t); + return value; +} + void Bitmap_Create(Bitmap* bmp, int width, int height, uint8_t* scan0) { bmp->Width = width; bmp->Height = height; bmp->Scan0 = scan0; } @@ -14,11 +21,9 @@ void Bitmap_Create(Bitmap* bmp, int width, int height, uint8_t* scan0) { void Bitmap_CopyBlock(int srcX, int srcY, int dstX, int dstY, Bitmap* src, Bitmap* dst, int size) { int x, y; for (y = 0; y < size; y++) { - uint32_t* srcRow = Bitmap_GetRow(src, srcY + y); - uint32_t* dstRow = Bitmap_GetRow(dst, dstY + y); - for (x = 0; x < size; x++) { - dstRow[dstX + x] = srcRow[srcX + x]; - } + BitmapCol* srcRow = Bitmap_GetRow(src, srcY + y) + srcX; + BitmapCol* dstRow = Bitmap_GetRow(dst, dstY + y) + dstX; + for (x = 0; x < size; x++) { dstRow[x] = srcRow[x]; } } } @@ -54,7 +59,7 @@ enum PngFilter { PNG_FILTER_NONE, PNG_FILTER_SUB, PNG_FILTER_UP, PNG_FILTER_AVERAGE, PNG_FILTER_PAETH }; -typedef void (*Png_RowExpander)(int width, uint32_t* palette, uint8_t* src, uint32_t* dst); +typedef void (*Png_RowExpander)(int width, BitmapCol* palette, uint8_t* src, BitmapCol* dst); static uint8_t png_sig[PNG_SIG_SIZE] = { 137, 80, 78, 71, 13, 10, 26, 10 }; bool Png_Detect(const uint8_t* data, uint32_t len) { @@ -118,58 +123,60 @@ static void Png_Reconstruct(uint8_t type, uint8_t bytesPerPixel, uint8_t* line, } } -static void Png_Expand_GRAYSCALE_1(int width, uint32_t* palette, uint8_t* src, uint32_t* dst) { - int i; /* NOTE: not optimised*/ -#define PNG_Do_Grayscale(tmp, dstI, srcI, scale) tmp = src[srcI] * scale; dst[dstI] = PackedCol_ARGB(tmp, tmp, tmp, 255); - for (i = 0; i < width; i++) { - int mask = (7 - (i & 7)); uint8_t rgb; - PNG_Do_Grayscale(rgb, i, (src[i >> 3] >> mask) & 1, 255); - } +#define Bitmap_Set(dst, r,g,b,a) dst.B = b; dst.G = g; dst.R = r; dst.A = a; + +#define PNG_Do_Grayscale(dstI, srcI, scale) rgb = src[srcI] * scale; Bitmap_Set(dst[dstI], rgb, rgb, rgb, 255); +#define PNG_Do_Grayscale_8(dstI, srcI) rgb = src[srcI]; Bitmap_Set(dst[dstI], rgb, rgb, rgb, 255); +#define PNG_Do_Grayscale_A__8(dstI, srcI) rgb = src[srcI]; Bitmap_Set(dst[dstI], rgb, rgb, rgb, src[srcI + 1]); +#define PNG_Do_RGB__8(dstI, srcI) Bitmap_Set(dst[dstI], src[srcI], src[srcI + 1], src[srcI + 2], 255); +#define PNG_Do_RGB_A__8(dstI, srcI) Bitmap_Set(dst[dstI], src[srcI], src[srcI + 1], src[srcI + 2], src[srcI + 3]); + +#define PNG_Mask_1(i) (7 - (i & 7)) +#define PNG_Mask_2(i) ((3 - (i & 3)) * 2) +#define PNG_Mask_4(i) ((1 - (i & 1)) * 4) +#define PNG_Get__1(i) ((src[i >> 3] >> PNG_Mask_1(i)) & 1) +#define PNG_Get__2(i) ((src[i >> 2] >> PNG_Mask_2(i)) & 3) + +static void Png_Expand_GRAYSCALE_1(int width, BitmapCol* palette, uint8_t* src, BitmapCol* dst) { + int i; uint8_t rgb; /* NOTE: not optimised*/ + for (i = 0; i < width; i++) { PNG_Do_Grayscale(i, PNG_Get__1(i), 255); } } -static void Png_Expand_GRAYSCALE_2(int width, uint32_t* palette, uint8_t* src, uint32_t* dst) { - int i; /* NOTE: not optimised */ - for (i = 0; i < width; i++) { - int mask = (3 - (i & 3)) * 2; uint8_t rgb; - PNG_Do_Grayscale(rgb, i, (src[i >> 3] >> mask) & 3, 85); - } +static void Png_Expand_GRAYSCALE_2(int width, BitmapCol* palette, uint8_t* src, BitmapCol* dst) { + int i; uint8_t rgb; /* NOTE: not optimised */ + for (i = 0; i < width; i++) { PNG_Do_Grayscale(i, PNG_Get__2(i), 85); } } -static void Png_Expand_GRAYSCALE_4(int width, uint32_t* palette, uint8_t* src, uint32_t* dst) { - int i, j, mask; uint8_t cur, rgb1, rgb2; +static void Png_Expand_GRAYSCALE_4(int width, BitmapCol* palette, uint8_t* src, BitmapCol* dst) { + int i, j; uint8_t rgb; for (i = 0, j = 0; i < (width & ~0x1); i += 2, j++) { - cur = src[j]; - PNG_Do_Grayscale(rgb1, i, cur >> 4, 17); PNG_Do_Grayscale(rgb2, i + 1, cur & 0x0F, 17); + PNG_Do_Grayscale(i, src[j] >> 4, 17); PNG_Do_Grayscale(i + 1, src[j] & 0x0F, 17); } for (; i < width; i++) { - mask = (1 - (i & 1)) * 4; - PNG_Do_Grayscale(rgb1, i, (src[j] >> mask) & 15, 17); + PNG_Do_Grayscale(i, (src[j] >> PNG_Mask_4(i)) & 15, 17); } } -static void Png_Expand_GRAYSCALE_8(int width, uint32_t* palette, uint8_t* src, uint32_t* dst) { - int i; uint8_t rgb1, rgb2, rgb3, rgb4; -#define PNG_Do_Grayscale_8(tmp, dstI, srcI) tmp = src[srcI]; dst[dstI] = PackedCol_ARGB(tmp, tmp, tmp, 255); +static void Png_Expand_GRAYSCALE_8(int width, BitmapCol* palette, uint8_t* src, BitmapCol* dst) { + int i; uint8_t rgb; for (i = 0; i < (width & ~0x3); i += 4) { - PNG_Do_Grayscale_8(rgb1, i , i ); PNG_Do_Grayscale_8(rgb2, i + 1, i + 1); - PNG_Do_Grayscale_8(rgb3, i + 2, i + 2); PNG_Do_Grayscale_8(rgb4, i + 3, i + 3); + PNG_Do_Grayscale_8(i , i ); PNG_Do_Grayscale_8(i + 1, i + 1); + PNG_Do_Grayscale_8(i + 2, i + 2); PNG_Do_Grayscale_8(i + 3, i + 3); } - for (; i < width; i++) { PNG_Do_Grayscale_8(rgb1, i, i); } + for (; i < width; i++) { PNG_Do_Grayscale_8(i, i); } } -static void Png_Expand_GRAYSCALE_16(int width, uint32_t* palette, uint8_t* src, uint32_t* dst) { - int i; +static void Png_Expand_GRAYSCALE_16(int width, BitmapCol* palette, uint8_t* src, BitmapCol* dst) { + int i; uint8_t rgb; /* NOTE: not optimised */ for (i = 0; i < width; i++) { - uint8_t rgb = src[i * 2]; - dst[i] = PackedCol_ARGB(rgb, rgb, rgb, 255); + rgb = src[i * 2]; Bitmap_Set(dst[i], rgb, rgb, rgb, 255); } } -static void Png_Expand_RGB_8(int width, uint32_t* palette, uint8_t* src, uint32_t* dst) { +static void Png_Expand_RGB_8(int width, BitmapCol* palette, uint8_t* src, BitmapCol* dst) { int i, j; -#define PNG_Do_RGB__8(dstI, srcI) dst[dstI] = PackedCol_ARGB(src[srcI], src[srcI + 1], src[srcI + 2], 255); for (i = 0, j = 0; i < (width & ~0x03); i += 4, j += 12) { PNG_Do_RGB__8(i , j ); PNG_Do_RGB__8(i + 1, j + 3); @@ -178,75 +185,64 @@ static void Png_Expand_RGB_8(int width, uint32_t* palette, uint8_t* src, uint32_ for (; i < width; i++, j += 3) { PNG_Do_RGB__8(i, j); } } -static void Png_Expand_RGB_16(int width, uint32_t* palette, uint8_t* src, uint32_t* dst) { - int i, j; +static void Png_Expand_RGB_16(int width, BitmapCol* palette, uint8_t* src, BitmapCol* dst) { + int i, j; /* NOTE: not optimised */ for (i = 0, j = 0; i < width; i++, j += 6) { - dst[i] = PackedCol_ARGB(src[j], src[j + 2], src[j + 4], 255); + Bitmap_Set(dst[i], src[j], src[j + 2], src[j + 4], 255); } } -static void Png_Expand_INDEXED_1(int width, uint32_t* palette, uint8_t* src, uint32_t* dst) { - int i; /* NOTE: not optimised*/ - for (i = 0; i < width; i++) { - int mask = (7 - (i & 7)); - dst[i] = palette[(src[i >> 3] >> mask) & 1]; - } +static void Png_Expand_INDEXED_1(int width, BitmapCol* palette, uint8_t* src, BitmapCol* dst) { + int i; /* NOTE: not optimised */ + for (i = 0; i < width; i++) { dst[i] = palette[PNG_Get__1(i)]; } } -static void Png_Expand_INDEXED_2(int width, uint32_t* palette, uint8_t* src, uint32_t* dst) { - int i; /* NOTE: not optimised*/ - for (i = 0; i < width; i++) { - int mask = (3 - (i & 3)) * 2; - dst[i] = palette[(src[i >> 3] >> mask) & 3]; - } +static void Png_Expand_INDEXED_2(int width, BitmapCol* palette, uint8_t* src, BitmapCol* dst) { + int i; /* NOTE: not optimised */ + for (i = 0; i < width; i++) { dst[i] = palette[PNG_Get__2(i)]; } } -static void Png_Expand_INDEXED_4(int width, uint32_t* palette, uint8_t* src, uint32_t* dst) { - int i, j, mask; uint8_t cur; -#define PNG_Do_Indexed(dstI, srcI) dst[dstI] = palette[srcI]; +static void Png_Expand_INDEXED_4(int width, BitmapCol* palette, uint8_t* src, BitmapCol* dst) { + int i, j; uint8_t cur; for (i = 0, j = 0; i < (width & ~0x1); i += 2, j++) { cur = src[j]; - PNG_Do_Indexed(i, cur >> 4); PNG_Do_Indexed(i + 1, cur & 0x0F); + dst[i] = palette[cur >> 4]; dst[i + 1] = palette[cur & 0x0F]; } for (; i < width; i++) { - mask = (1 - (i & 1)) * 4; - PNG_Do_Indexed(i, (src[j] >> mask) & 15); + dst[i] = palette[(src[j] >> PNG_Mask_4(i)) & 15]; } } -static void Png_Expand_INDEXED_8(int width, uint32_t* palette, uint8_t* src, uint32_t* dst) { +static void Png_Expand_INDEXED_8(int width, BitmapCol* palette, uint8_t* src, BitmapCol* dst) { int i; for (i = 0; i < (width & ~0x3); i += 4) { - PNG_Do_Indexed(i , src[i] ); PNG_Do_Indexed(i + 1, src[i + 1]); - PNG_Do_Indexed(i + 2, src[i + 2]); PNG_Do_Indexed(i + 3, src[i + 3]); + dst[i] = palette[src[i]]; dst[i + 1] = palette[src[i + 1]]; + dst[i + 2] = palette[src[i + 2]]; dst[i + 3] = palette[src[i + 3]]; } - for (; i < width; i++) { PNG_Do_Indexed(i, src[i]); } + for (; i < width; i++) { dst[i] = palette[src[i]]; } } -static void Png_Expand_GRAYSCALE_A_8(int width, uint32_t* palette, uint8_t* src, uint32_t* dst) { - int i, j; uint8_t rgb1, rgb2, rgb3, rgb4; -#define PNG_Do_Grayscale_A__8(tmp, dstI, srcI) tmp = src[srcI]; dst[dstI] = PackedCol_ARGB(tmp, tmp, tmp, src[srcI + 1]); +static void Png_Expand_GRAYSCALE_A_8(int width, BitmapCol* palette, uint8_t* src, BitmapCol* dst) { + int i, j; uint8_t rgb; for (i = 0, j = 0; i < (width & ~0x3); i += 4, j += 8) { - PNG_Do_Grayscale_A__8(rgb1, i , j ); PNG_Do_Grayscale_A__8(rgb2, i + 1, j + 2); - PNG_Do_Grayscale_A__8(rgb3, i + 2, j + 4); PNG_Do_Grayscale_A__8(rgb4, i + 3, j + 6); + PNG_Do_Grayscale_A__8(i , j ); PNG_Do_Grayscale_A__8(i + 1, j + 2); + PNG_Do_Grayscale_A__8(i + 2, j + 4); PNG_Do_Grayscale_A__8(i + 3, j + 6); } - for (; i < width; i++, j += 2) { PNG_Do_Grayscale_A__8(rgb1, i, j); } + for (; i < width; i++, j += 2) { PNG_Do_Grayscale_A__8(i, j); } } -static void Png_Expand_GRAYSCALE_A_16(int width, uint32_t* palette, uint8_t* src, uint32_t* dst) { - int i, j; /* NOTE: not optimised*/ - for (i = 0, j = 0; i < width; i++, j += 4) { - uint8_t rgb = src[j]; - dst[i] = PackedCol_ARGB(rgb, rgb, rgb, src[j + 2]); +static void Png_Expand_GRAYSCALE_A_16(int width, BitmapCol* palette, uint8_t* src, BitmapCol* dst) { + int i; uint8_t rgb; /* NOTE: not optimised*/ + for (i = 0; i < width; i++) { + rgb = src[i * 4]; Bitmap_Set(dst[i], rgb, rgb, rgb, src[i * 4 + 2]); } } -static void Png_Expand_RGB_A_8(int width, uint32_t* palette, uint8_t* src, uint32_t* dst) { +static void Png_Expand_RGB_A_8(int width, BitmapCol* palette, uint8_t* src, BitmapCol* dst) { int i, j; -#define PNG_Do_RGB_A__8(dstI, srcI) dst[dstI] = PackedCol_ARGB(src[srcI], src[srcI + 1], src[srcI + 2], src[srcI + 3]); for (i = 0, j = 0; i < (width & ~0x3); i += 4, j += 16) { PNG_Do_RGB_A__8(i , j ); PNG_Do_RGB_A__8(i + 1, j + 4 ); @@ -255,10 +251,10 @@ static void Png_Expand_RGB_A_8(int width, uint32_t* palette, uint8_t* src, uint3 for (; i < width; i++, j += 4) { PNG_Do_RGB_A__8(i, j); } } -static void Png_Expand_RGB_A_16(int width, uint32_t* palette, uint8_t* src, uint32_t* dst) { +static void Png_Expand_RGB_A_16(int width, BitmapCol* palette, uint8_t* src, BitmapCol* dst) { int i, j; /* NOTE: not optimised*/ for (i = 0, j = 0; i < width; i++, j += 8) { - dst[i] = PackedCol_ARGB(src[j], src[j + 2], src[j + 4], src[j + 6]); + Bitmap_Set(dst[i], src[j], src[j + 2], src[j + 4], src[j + 6]); } } @@ -307,12 +303,12 @@ Png_RowExpander Png_GetExpander(uint8_t col, uint8_t bitsPerSample) { return NULL; } -static void Png_ComputeTransparency(Bitmap* bmp, uint32_t transparentCol) { - uint32_t trnsRGB = transparentCol & PNG_RGB_MASK; +static void Png_ComputeTransparency(Bitmap* bmp, BitmapCol col) { + uint32_t trnsRGB = col.B | (col.G << 8) | (col.R << 16); /* TODO: Remove this!! */ int x, y, width = bmp->Width, height = bmp->Height; for (y = 0; y < height; y++) { - uint32_t* row = Bitmap_GetRow(bmp, y); + uint32_t* row = Bitmap_RawRow(bmp, y); for (x = 0; x < width; x++) { uint32_t rgb = row[x] & PNG_RGB_MASK; row[x] = (rgb == trnsRGB) ? trnsRGB : row[x]; @@ -335,8 +331,9 @@ ReturnCode Png_Decode(Bitmap* bmp, struct Stream* stream) { uint32_t scanlineSize, scanlineBytes; /* palette data */ - uint32_t transparentCol = PackedCol_ARGB(0, 0, 0, 255); - uint32_t palette[PNG_PALETTE]; + BitmapCol black = BITMAPCOL_CONST(0, 0, 0, 255); + BitmapCol transparentCol; + BitmapCol palette[PNG_PALETTE]; uint32_t i; /* idat state */ @@ -355,15 +352,13 @@ ReturnCode Png_Decode(Bitmap* bmp, struct Stream* stream) { if (res) return res; if (!Png_Detect(tmp, PNG_SIG_SIZE)) return PNG_ERR_INVALID_SIG; - for (i = 0; i < PNG_PALETTE; i++) { - palette[i] = PackedCol_ARGB(0, 0, 0, 255); - } - bool readingChunks = true; + transparentCol = black; + for (i = 0; i < PNG_PALETTE; i++) { palette[i] = black; } Inflate_MakeStream(&compStream, &inflate, stream); ZLibHeader_Init(&zlibHeader); - while (readingChunks) { + for (;;) { res = Stream_Read(stream, tmp, 8); if (res) return res; dataSize = Stream_GetU32_BE(&tmp[0]); @@ -407,7 +402,9 @@ ReturnCode Png_Decode(Bitmap* bmp, struct Stream* stream) { if (res) return res; for (i = 0; i < dataSize; i += 3) { - palette[i / 3] = PackedCol_ARGB(tmp[i], tmp[i + 1], tmp[i + 2], 255); + palette[i / 3].R = tmp[i]; + palette[i / 3].G = tmp[i + 1]; + palette[i / 3].B = tmp[i + 2]; } } break; @@ -418,8 +415,8 @@ ReturnCode Png_Decode(Bitmap* bmp, struct Stream* stream) { if (res) return res; /* RGB is 16 bits big endian, ignore least significant 8 bits */ - uint8_t palRGB = tmp[0]; - transparentCol = PackedCol_ARGB(palRGB, palRGB, palRGB, 0); + transparentCol.B = tmp[0]; transparentCol.G = tmp[0]; + transparentCol.R = tmp[0]; transparentCol.A = 0; } else if (col == PNG_COL_INDEXED) { if (dataSize > PNG_PALETTE) return PNG_ERR_TRANS_COUNT; res = Stream_Read(stream, tmp, dataSize); @@ -427,8 +424,7 @@ ReturnCode Png_Decode(Bitmap* bmp, struct Stream* stream) { /* set alpha component of palette*/ for (i = 0; i < dataSize; i++) { - palette[i] &= PNG_RGB_MASK; - palette[i] |= (uint32_t)tmp[i] << 24; + palette[i].A = tmp[i]; } } else if (col == PNG_COL_RGB) { if (dataSize != 6) return PNG_ERR_TRANS_COUNT; @@ -436,8 +432,8 @@ ReturnCode Png_Decode(Bitmap* bmp, struct Stream* stream) { if (res) return res; /* R,G,B is 16 bits big endian, ignore least significant 8 bits */ - uint8_t palR = tmp[0], palG = tmp[2], palB = tmp[4]; - transparentCol = PackedCol_ARGB(palR, palG, palB, 0); + transparentCol.B = tmp[4]; transparentCol.G = tmp[2]; + transparentCol.R = tmp[0]; transparentCol.A = 0; } else { return PNG_ERR_TRANS_INVALID; } @@ -491,8 +487,9 @@ ReturnCode Png_Decode(Bitmap* bmp, struct Stream* stream) { } break; case PNG_FourCC('I','E','N','D'): { - readingChunks = false; if (dataSize) return PNG_ERR_INVALID_END_SIZE; + if (!transparentCol.A) Png_ComputeTransparency(bmp, transparentCol); + return bmp->Scan0 ? 0 : PNG_ERR_NO_DATA; } break; default: @@ -502,11 +499,6 @@ ReturnCode Png_Decode(Bitmap* bmp, struct Stream* stream) { if ((res = stream->Skip(stream, 4))) return res; /* Skip CRC32 */ } - - if (transparentCol <= PNG_RGB_MASK) { - Png_ComputeTransparency(bmp, transparentCol); - } - return bmp->Scan0 ? 0 : PNG_ERR_NO_DATA; } @@ -589,14 +581,14 @@ static void Png_Filter(uint8_t filter, uint8_t* cur, uint8_t* prior, uint8_t* be } } -static void Png_EncodeRow(const uint8_t* src, uint8_t* cur, uint8_t* prior, uint8_t* best, int lineLen) { +static void Png_EncodeRow(const BitmapCol* src, uint8_t* cur, uint8_t* prior, uint8_t* best, int lineLen) { uint8_t* dst = cur; int bestFilter, bestEstimate = Int32_MaxValue; int x, filter, estimate; for (x = 0; x < lineLen; x += 3) { - dst[0] = src[2]; dst[1] = src[1]; dst[2] = src[0]; - src += 4; dst += 3; + dst[0] = src->R; dst[1] = src->G; dst[2] = src->B; + src++; dst += 3; } dst = best + 1; @@ -665,9 +657,9 @@ ReturnCode Png_Encode(Bitmap* bmp, struct Stream* stream, Png_RowSelector select for (y = 0; y < bmp->Height; 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; + BitmapCol* src = Bitmap_GetRow(bmp, row); + uint8_t* prev = (y & 1) == 0 ? prevLine : curLine; + uint8_t* cur = (y & 1) == 0 ? curLine : prevLine; Png_EncodeRow(src, cur, prev, bestLine, lineSize); /* +1 for filter byte */ diff --git a/src/Bitmap.h b/src/Bitmap.h index 3176a140b..1de8558c9 100644 --- a/src/Bitmap.h +++ b/src/Bitmap.h @@ -6,12 +6,26 @@ */ struct Stream; +/* Represents an ARGB colour, suitable for native graphics API texture pixels. */ +typedef CC_ALIGN_HINT(4) struct BitmapCol_ { + uint8_t B, G, R, A; +} BitmapCol; +/* Represents an ARGB colour, suitable for native graphics API texture pixels. */ +/* Unioned with Packed member for efficient equality comparison */ +typedef union BitmapColUnion_ { BitmapCol C; uint32_t Raw; } BitmapColUnion; + +typedef struct Bitmap_ { uint8_t* Scan0; int Width, Height; } Bitmap; + #define PNG_MAX_DIMS 0x8000 +#define BITMAPCOL_CONST(r, g, b, a) { b, g, r, a } #define BITMAP_SIZEOF_PIXEL 4 /* 32 bit ARGB */ + #define Bitmap_DataSize(width, height) ((uint32_t)(width) * (uint32_t)(height) * (uint32_t)BITMAP_SIZEOF_PIXEL) -#define Bitmap_GetRow(bmp, y) ((uint32_t*)((bmp)->Scan0 + ((y) * ((bmp)->Width << 2)))) +#define Bitmap_RawRow(bmp, y) ((uint32_t*)((bmp)->Scan0 + ((y) * ((bmp)->Width << 2)))) +#define Bitmap_GetRow(bmp, y) ((BitmapCol*)((bmp)->Scan0 + ((y) * ((bmp)->Width << 2)))) #define Bitmap_GetPixel(bmp, x, y) (Bitmap_GetRow(bmp, y)[x]) +BitmapCol BitmapCol_Scale(BitmapCol value, float t); void Bitmap_Create(Bitmap* bmp, int width, int height, uint8_t* scan0); void Bitmap_CopyBlock(int srcX, int srcY, int dstX, int dstY, Bitmap* src, Bitmap* dst, int size); /* Allocates a new bitmap of the given dimensions. You are responsible for freeing its memory! */ diff --git a/src/Block.c b/src/Block.c index 25fac130d..3c77c3c18 100644 --- a/src/Block.c +++ b/src/Block.c @@ -89,7 +89,7 @@ void Block_SetCustomDefined(BlockID block, bool defined) { } void Block_DefineCustom(BlockID block) { - PackedCol black = PACKEDCOL_BLACK; + PackedCol black = PACKEDCOL_CONST(0, 0, 0, 255); String name = Block_UNSAFE_GetName(block); Block_Tinted[block] = !PackedCol_Equals(Block_FogCol[block], black) && String_IndexOf(&name, '#', 0) >= 0; @@ -283,60 +283,52 @@ void Block_RecalculateSpriteBB(void) { } static float Block_GetSpriteBB_MinX(int size, int tileX, int tileY, Bitmap* bmp) { - uint32_t* row; + BitmapCol* row; int x, y; + for (x = 0; x < size; x++) { for (y = 0; y < size; y++) { row = Bitmap_GetRow(bmp, tileY * size + y) + (tileX * size); - - if (PackedCol_ARGB_A(row[x]) != 0) { - return (float)x / size; - } + if (row[x].A) { return (float)x / size; } } } return 1.0f; } static float Block_GetSpriteBB_MinY(int size, int tileX, int tileY, Bitmap* bmp) { - uint32_t* row; + BitmapCol* row; int x, y; + for (y = size - 1; y >= 0; y--) { row = Bitmap_GetRow(bmp, tileY * size + y) + (tileX * size); - for (x = 0; x < size; x++) { - if (PackedCol_ARGB_A(row[x]) != 0) { - return 1.0f - (float)(y + 1) / size; - } + if (row[x].A) { return 1.0f - (float)(y + 1) / size; } } } return 1.0f; } static float Block_GetSpriteBB_MaxX(int size, int tileX, int tileY, Bitmap* bmp) { - uint32_t* row; + BitmapCol* row; int x, y; + for (x = size - 1; x >= 0; x--) { for (y = 0; y < size; y++) { row = Bitmap_GetRow(bmp, tileY * size + y) + (tileX * size); - - if (PackedCol_ARGB_A(row[x]) != 0) { - return (float)(x + 1) / size; - } + if (row[x].A) { return (float)(x + 1) / size; } } } return 0.0f; } static float Block_GetSpriteBB_MaxY(int size, int tileX, int tileY, Bitmap* bmp) { - uint32_t* row; + BitmapCol* row; int x, y; + for (y = 0; y < size; y++) { row = Bitmap_GetRow(bmp, tileY * size + y) + (tileX * size); - for (x = 0; x < size; x++) { - if (PackedCol_ARGB_A(row[x]) != 0) { - return 1.0f - (float)y / size; - } + if (row[x].A) { return 1.0f - (float)y / size; } } } return 0.0f; diff --git a/src/Builder.c b/src/Builder.c index 0e55862bb..05855dff3 100644 --- a/src/Builder.c +++ b/src/Builder.c @@ -508,7 +508,7 @@ static PackedCol Normal_LightCol(int x, int y, int z, Face face, BlockID block) return y >= World_MaxY ? Env_SunCol : Lighting_Col_YMax_Fast(x, (y + 1) - offset, z); } - PackedCol black = PACKEDCOL_BLACK; return black; + PackedCol invalid = PACKEDCOL_CONST(0, 0, 0, 0); return invalid; } static bool Normal_CanStretch(BlockID initial, int chunkIndex, int x, int y, int z, Face face) { diff --git a/src/ChunkUpdater.c b/src/ChunkUpdater.c index b9898766a..9da9ca6f1 100644 --- a/src/ChunkUpdater.c +++ b/src/ChunkUpdater.c @@ -270,25 +270,28 @@ static int ChunkUpdater_UpdateChunksStill(int* chunkUpdates) { return j; } -void ChunkUpdater_UpdateChunks(double delta) { +static void ChunkUpdater_UpdateChunks(double delta) { + struct LocalPlayer* p; + bool samePos; int chunkUpdates = 0; - cu_chunksTarget += delta < cu_targetTime ? 1 : -1; /* build more chunks if 30 FPS or over, otherwise slowdown. */ + + /* Build more chunks if 30 FPS or over, otherwise slowdown */ + cu_chunksTarget += delta < cu_targetTime ? 1 : -1; Math_Clamp(cu_chunksTarget, 4, Game_MaxChunkUpdates); - struct LocalPlayer* p = &LocalPlayer_Instance; - Vector3 pos = Camera_CurrentPos; - float headX = p->Base.HeadX; - float headY = p->Base.HeadY; + p = &LocalPlayer_Instance; + samePos = Vector3_Equals(&Camera_CurrentPos, &cu_lastCamPos) + && p->Base.HeadX == cu_lastHeadX && p->Base.HeadY == cu_lastHeadY; - bool samePos = Vector3_Equals(&pos, &cu_lastCamPos) && headX == cu_lastHeadX && headY == cu_lastHeadY; MapRenderer_RenderChunksCount = samePos ? ChunkUpdater_UpdateChunksStill(&chunkUpdates) : ChunkUpdater_UpdateChunksAndVisibility(&chunkUpdates); - cu_lastCamPos = pos; - cu_lastHeadX = headX; cu_lastHeadY = headY; + cu_lastCamPos = Camera_CurrentPos; + cu_lastHeadX = p->Base.HeadX; + cu_lastHeadY = p->Base.HeadY; - if (!samePos || chunkUpdates != 0) { + if (!samePos || chunkUpdates) { ChunkUpdater_ResetPartFlags(); } } diff --git a/src/Core.h b/src/Core.h index 250221b9d..7e64a4a7a 100644 --- a/src/Core.h +++ b/src/Core.h @@ -72,7 +72,6 @@ typedef struct Point2D_ { int X, Y; } Point2D; typedef struct Size2D_ { int Width, Height; } Size2D; typedef struct FontDesc_ { void* Handle; uint16_t Size, Style; } FontDesc; typedef struct TextureRec_ { float U1, V1, U2, V2; } TextureRec; -typedef struct Bitmap_ { uint8_t* Scan0; int Width, Height; } Bitmap; /*#define CC_BUILD_GL11*/ /*#define CC_BUILD_SOLARIS*/ diff --git a/src/Drawer2D.c b/src/Drawer2D.c index 558530fbd..c87ac83c6 100644 --- a/src/Drawer2D.c +++ b/src/Drawer2D.c @@ -38,7 +38,7 @@ static int Drawer2D_Widths[256]; static void Drawer2D_CalculateTextWidths(void) { int width = Drawer2D_FontBitmap.Width, height = Drawer2D_FontBitmap.Height; - uint32_t* row; + BitmapCol* row; int i, x, y, xx, tileX, tileY; for (i = 0; i < Array_Elems(Drawer2D_Widths); i++) { @@ -55,9 +55,7 @@ static void Drawer2D_CalculateTextWidths(void) { /* Iterate through each pixel of the given character, on the current scanline */ for (xx = Drawer2D_TileSize - 1; xx >= 0; xx--) { - uint32_t pixel = row[x + xx]; - uint8_t a = PackedCol_ARGB_A(pixel); - if (a < 127) continue; + if (row[x + xx].A < 127) continue; /* Check if this is the pixel furthest to the right, for the current character */ Drawer2D_Widths[i] = max(Drawer2D_Widths[i], xx + 1); @@ -82,15 +80,14 @@ void Drawer2D_SetFontBitmap(Bitmap* bmp) { void Drawer2D_HexEncodedCol(int i, int hex, uint8_t lo, uint8_t hi) { - PackedCol* col = &Drawer2D_Cols[i]; - col->R = (uint8_t)(lo * ((hex >> 2) & 1) + hi * (hex >> 3)); - col->G = (uint8_t)(lo * ((hex >> 1) & 1) + hi * (hex >> 3)); - col->B = (uint8_t)(lo * ((hex >> 0) & 1) + hi * (hex >> 3)); - col->A = UInt8_MaxValue; + Drawer2D_Cols[i].R = (uint8_t)(lo * ((hex >> 2) & 1) + hi * (hex >> 3)); + Drawer2D_Cols[i].G = (uint8_t)(lo * ((hex >> 1) & 1) + hi * (hex >> 3)); + Drawer2D_Cols[i].B = (uint8_t)(lo * ((hex >> 0) & 1) + hi * (hex >> 3)); + Drawer2D_Cols[i].A = 255; } void Drawer2D_Init(void) { - PackedCol col = PACKEDCOL_CONST(0, 0, 0, 0); + BitmapCol col = BITMAPCOL_CONST(0, 0, 0, 0); int i; for (i = 0; i < DRAWER2D_MAX_COLS; i++) { @@ -109,11 +106,10 @@ void Drawer2D_Init(void) { void Drawer2D_Free(void) { Drawer2D_FreeFontBitmap(); } /* Draws a 2D flat rectangle. */ -void Drawer2D_Rect(Bitmap* bmp, PackedCol col, int x, int y, int width, int height); +void Drawer2D_Rect(Bitmap* bmp, BitmapCol col, int x, int y, int width, int height); -void Drawer2D_Clear(Bitmap* bmp, PackedCol col, int x, int y, int width, int height) { - uint32_t argb = PackedCol_ToARGB(col); - uint32_t* row; +void Drawer2D_Clear(Bitmap* bmp, BitmapCol col, int x, int y, int width, int height) { + BitmapCol* row; int xx, yy; if (x < 0 || y < 0 || (x + width) > bmp->Width || (y + height) > bmp->Height) { @@ -122,7 +118,7 @@ void Drawer2D_Clear(Bitmap* bmp, PackedCol col, int x, int y, int width, int hei for (yy = 0; yy < height; yy++) { row = Bitmap_GetRow(bmp, y + yy) + x; - for (xx = 0; xx < width; xx++) { row[xx] = argb; } + for (xx = 0; xx < width; xx++) { row[xx] = col; } } } @@ -233,9 +229,8 @@ static int Drawer2D_NextPart(int i, STRING_REF String* value, String* part, char return i; } -void Drawer2D_Underline(Bitmap* bmp, int x, int y, int width, int height, PackedCol col) { - uint32_t argb = PackedCol_ToARGB(col); - uint32_t* row; +void Drawer2D_Underline(Bitmap* bmp, int x, int y, int width, int height, BitmapCol col) { + BitmapCol* row; int xx, yy; for (yy = y; yy < y + height; yy++) { @@ -244,14 +239,14 @@ void Drawer2D_Underline(Bitmap* bmp, int x, int y, int width, int height, Packed for (xx = x; xx < x + width; xx++) { if (xx >= bmp->Width) break; - row[xx] = argb; + row[xx] = col; } } } static void Drawer2D_DrawCore(Bitmap* bmp, struct DrawTextArgs* args, int x, int y, bool shadow) { - PackedCol black = PACKEDCOL_BLACK; - PackedColUnion col; + BitmapCol black = BITMAPCOL_CONST(0, 0, 0, 255); + BitmapColUnion col; String text = args->Text; int i, point = args->Font.Size, count = 0; @@ -262,13 +257,16 @@ static void Drawer2D_DrawCore(Bitmap* bmp, struct DrawTextArgs* args, int x, int int dstHeight, begX, xx, yy; int cellY, underlineY, underlineHeight; + BitmapCol* srcRow, src; + BitmapCol* dstRow, dst; + uint8_t coords[256]; - PackedColUnion cols[256]; + BitmapColUnion cols[256]; uint16_t dstWidths[256]; col.C = Drawer2D_Cols['f']; if (shadow) { - col.C = Drawer2D_BlackTextShadows ? black : PackedCol_Scale(col.C, 0.25f); + col.C = Drawer2D_BlackTextShadows ? black : BitmapCol_Scale(col.C, 0.25f); } for (i = 0; i < text.length; i++) { @@ -276,7 +274,7 @@ static void Drawer2D_DrawCore(Bitmap* bmp, struct DrawTextArgs* args, int x, int if (c == '&' && Drawer2D_ValidColCodeAt(&text, i + 1)) { col.C = Drawer2D_GetCol(text.buffer[i + 1]); if (shadow) { - col.C = Drawer2D_BlackTextShadows ? black : PackedCol_Scale(col.C, 0.25f); + col.C = Drawer2D_BlackTextShadows ? black : BitmapCol_Scale(col.C, 0.25f); } i++; continue; /* skip over the colour code */ } @@ -296,13 +294,13 @@ static void Drawer2D_DrawCore(Bitmap* bmp, struct DrawTextArgs* args, int x, int dstY = y + (yy + yPadding); if (dstY >= bmp->Height) break; - fontY = 0 + yy * Drawer2D_TileSize / dstHeight; - uint32_t* dstRow = Bitmap_GetRow(bmp, dstY); + fontY = 0 + yy * Drawer2D_TileSize / dstHeight; + dstRow = Bitmap_GetRow(bmp, dstY); for (i = 0; i < count; i++) { - srcX = (coords[i] & 0x0F) * Drawer2D_TileSize; - srcY = (coords[i] >> 4) * Drawer2D_TileSize; - uint32_t* fontRow = Bitmap_GetRow(&Drawer2D_FontBitmap, fontY + srcY); + srcX = (coords[i] & 0x0F) * Drawer2D_TileSize; + srcY = (coords[i] >> 4) * Drawer2D_TileSize; + srcRow = Bitmap_GetRow(&Drawer2D_FontBitmap, fontY + srcY); srcWidth = Drawer2D_Widths[coords[i]]; dstWidth = dstWidths[i]; @@ -310,17 +308,17 @@ static void Drawer2D_DrawCore(Bitmap* bmp, struct DrawTextArgs* args, int x, int for (xx = 0; xx < dstWidth; xx++) { fontX = srcX + xx * srcWidth / dstWidth; - uint32_t src = fontRow[fontX]; - if (PackedCol_ARGB_A(src) == 0) continue; + src = srcRow[fontX]; + if (!src.A) continue; dstX = x + xx; if (dstX >= bmp->Width) break; - uint32_t pixel = src & ~0xFFFFFF; - pixel |= ((src & 0xFF) * col.C.B / 255); - pixel |= (((src >> 8) & 0xFF) * col.C.G / 255) << 8; - pixel |= (((src >> 16) & 0xFF) * col.C.R / 255) << 16; - dstRow[dstX] = pixel; + dst.B = src.B * col.C.B / 255; + dst.G = src.G * col.C.G / 255; + dst.R = src.R * col.C.R / 255; + dst.A = src.A; + dstRow[dstX] = dst; } x += dstWidth + xPadding; } @@ -382,7 +380,7 @@ static Size2D Drawer2D_MeasureBitmapText(struct DrawTextArgs* args) { } void Drawer2D_DrawText(Bitmap* bmp, struct DrawTextArgs* args, int x, int y) { - PackedCol col, backCol, black = PACKEDCOL_BLACK; + BitmapCol col, backCol, black = BITMAPCOL_CONST(0, 0, 0, 255); Size2D partSize; String value = args->Text; char colCode, nextCol = 'f'; @@ -398,7 +396,7 @@ void Drawer2D_DrawText(Bitmap* bmp, struct DrawTextArgs* args, int x, int y) { col = Drawer2D_GetCol(colCode); if (args->UseShadow) { - backCol = Drawer2D_BlackTextShadows ? black : PackedCol_Scale(col, 0.25f); + backCol = Drawer2D_BlackTextShadows ? black : BitmapCol_Scale(col, 0.25f); Platform_TextDraw(args, bmp, x + DRAWER2D_OFFSET, y + DRAWER2D_OFFSET, backCol); } diff --git a/src/Drawer2D.h b/src/Drawer2D.h index 16e442d81..cfc8be395 100644 --- a/src/Drawer2D.h +++ b/src/Drawer2D.h @@ -2,6 +2,7 @@ #define CC_DRAWER2D_H #include "PackedCol.h" #include "Constants.h" +#include "Bitmap.h" /* Responsible for performing drawing operations on bitmaps, and for converting bitmaps into textures. Copyright 2017 ClassicalSharp | Licensed under BSD-3 */ @@ -18,7 +19,7 @@ CC_NOINLINE void Drawer2D_MakeFont(FontDesc* desc, int size, int style); bool Drawer2D_BitmappedText; /* Whether the shadows behind text (that uses shadows) is fully black. */ bool Drawer2D_BlackTextShadows; -PackedCol Drawer2D_Cols[DRAWER2D_MAX_COLS]; +BitmapCol Drawer2D_Cols[DRAWER2D_MAX_COLS]; #define DRAWER2D_OFFSET 1 #define Drawer2D_GetCol(c) Drawer2D_Cols[(uint8_t)c] @@ -26,11 +27,11 @@ void Drawer2D_Init(void); void Drawer2D_Free(void); /* Draws a 2D flat rectangle. */ -void Drawer2D_Rect(Bitmap* bmp, PackedCol col, int x, int y, int width, int height); +void Drawer2D_Rect(Bitmap* bmp, BitmapCol col, int x, int y, int width, int height); /* Clears the entire given area to the specified colour. */ -void Drawer2D_Clear(Bitmap* bmp, PackedCol col, int x, int y, int width, int height); +void Drawer2D_Clear(Bitmap* bmp, BitmapCol col, int x, int y, int width, int height); -void Drawer2D_Underline(Bitmap* bmp, int x, int y, int width, int height, PackedCol col); +void Drawer2D_Underline(Bitmap* bmp, int x, int y, int width, int height, BitmapCol col); void Drawer2D_DrawText(Bitmap* bmp, struct DrawTextArgs* args, int x, int y); Size2D Drawer2D_MeasureText(struct DrawTextArgs* args); int Drawer2D_FontHeight(const FontDesc* font, bool useShadow); diff --git a/src/Entity.c b/src/Entity.c index c7441b53d..12e4b8e13 100644 --- a/src/Entity.c +++ b/src/Entity.c @@ -477,6 +477,9 @@ void TabList_MakeComponent(struct IGameComponent* comp) { static void Player_MakeNameTexture(struct Player* player) { String colorlessName; char colorlessBuffer[STRING_SIZE]; + BitmapCol shadowCol = BITMAPCOL_CONST(80, 80, 80, 255); + BitmapCol origWhiteCol; + struct DrawTextArgs args; bool bitmapped; String name; @@ -501,9 +504,9 @@ static void Player_MakeNameTexture(struct Player* player) { Bitmap_AllocateClearedPow2(&bmp, size.Width, size.Height); { - PackedCol origWhiteCol = Drawer2D_Cols['f']; + origWhiteCol = Drawer2D_Cols['f']; - Drawer2D_Cols['f'] = PackedCol_Create3(80, 80, 80); + Drawer2D_Cols['f'] = shadowCol; String_AppendColorless(&colorlessName, &name); args.Text = colorlessName; Drawer2D_DrawText(&bmp, &args, NAME_OFFSET, NAME_OFFSET); @@ -653,11 +656,9 @@ static void Player_ClearHat(Bitmap* bmp, uint8_t skinType) { /* determine if we actually need filtering */ for (y = 0; y < sizeY; y++) { - uint32_t* row = Bitmap_GetRow(bmp, y); - row += sizeX; + BitmapCol* row = Bitmap_GetRow(bmp, y) + sizeX; for (x = 0; x < sizeX; x++) { - uint8_t alpha = PackedCol_ARGB_A(row[x]); - if (alpha != 255) return; + if (row[x].A != 255) return; } } @@ -665,8 +666,7 @@ static void Player_ClearHat(Bitmap* bmp, uint8_t skinType) { uint32_t fullWhite = PackedCol_ARGB(255, 255, 255, 255); uint32_t fullBlack = PackedCol_ARGB(0, 0, 0, 255); for (y = 0; y < sizeY; y++) { - uint32_t* row = Bitmap_GetRow(bmp, y); - row += sizeX; + uint32_t* row = Bitmap_RawRow(bmp, y) + sizeX; for (x = 0; x < sizeX; x++) { uint32_t pixel = row[x]; if (pixel == fullWhite || pixel == fullBlack) row[x] = 0; @@ -690,8 +690,8 @@ static void Player_EnsurePow2(struct Player* p, Bitmap* bmp) { stride = bmp->Width * BITMAP_SIZEOF_PIXEL; for (y = 0; y < bmp->Height; y++) { - uint32_t* src = Bitmap_GetRow(bmp, y); - uint32_t* dst = Bitmap_GetRow(&scaled, y); + BitmapCol* src = Bitmap_GetRow(bmp, y); + BitmapCol* dst = Bitmap_GetRow(&scaled, y); Mem_Copy(dst, src, stride); } diff --git a/src/EntityComponents.c b/src/EntityComponents.c index 99404a62b..1745cfc32 100644 --- a/src/EntityComponents.c +++ b/src/EntityComponents.c @@ -602,14 +602,14 @@ static bool ShadowComponent_GetBlocks(struct Entity* e, int x, int y, int z, str #define sh_half (sh_size / 2) static void ShadowComponent_MakeTex(void) { uint8_t pixels[Bitmap_DataSize(sh_size, sh_size)]; - Bitmap bmp; Bitmap_Create(&bmp, sh_size, sh_size, pixels); - - uint32_t inPix = PackedCol_ARGB(0, 0, 0, 200); - uint32_t outPix = PackedCol_ARGB(0, 0, 0, 0); - + BitmapCol inPix = BITMAPCOL_CONST(0, 0, 0, 200); + BitmapCol outPix = BITMAPCOL_CONST(0, 0, 0, 0); + Bitmap bmp; uint32_t x, y; + Bitmap_Create(&bmp, sh_size, sh_size, pixels); + for (y = 0; y < sh_size; y++) { - uint32_t* row = Bitmap_GetRow(&bmp, y); + BitmapCol* row = Bitmap_GetRow(&bmp, y); for (x = 0; x < sh_size; x++) { double dist = (sh_half - (x + 0.5)) * (sh_half - (x + 0.5)) + diff --git a/src/EnvRenderer.c b/src/EnvRenderer.c index d6da57ea8..629ed1a5e 100644 --- a/src/EnvRenderer.c +++ b/src/EnvRenderer.c @@ -215,18 +215,21 @@ static GfxResourceID sky_vb; static int sky_vertices; void EnvRenderer_RenderSky(double deltaTime) { + struct Matrix m; + float skyY, normY, dy; if (!sky_vb || EnvRenderer_ShouldRenderSkybox()) return; - Vector3 pos = Camera_CurrentPos; - float normalY = (float)World_Height + 8.0f; - float skyY = max(pos.Y + 8.0f, normalY); + + normY = (float)World_Height + 8.0f; + skyY = max(Camera_CurrentPos.Y + 8.0f, normY); Gfx_SetBatchFormat(VERTEX_FORMAT_P3FC4B); Gfx_BindVb(sky_vb); - if (skyY == normalY) { + if (skyY == normY) { Gfx_DrawVb_IndexedTris(sky_vertices); } else { - struct Matrix m = Gfx_View; - float dy = skyY - normalY; /* inlined Y translation matrix multiply */ + m = Gfx_View; + dy = skyY - normY; + /* inlined Y translation matrix multiply */ m.Row3.X += dy * m.Row1.X; m.Row3.Y += dy * m.Row1.Y; m.Row3.Z += dy * m.Row1.Z; m.Row3.W += dy * m.Row1.W; @@ -445,12 +448,19 @@ static float EnvRenderer_RainAlphaAt(float x) { } void EnvRenderer_RenderWeather(double deltaTime) { - int weather = Env_Weather; + VertexP3fT2fC4b vertices[WEATHER_VERTS_COUNT]; + VertexP3fT2fC4b* ptr, v; + int weather, vCount; Vector3I pos; bool moved, particles; float speed, vOffset; - float dist, alpha; + int dist, dx, dz, x, z; + float alpha, y, height; + float worldV, v1, v2; + float x1,y1,z1, x2,y2,z2; + + weather = Env_Weather; if (weather == WEATHER_SUNNY) return; if (!Weather_Heightmap) EnvRenderer_InitWeatherHeightmap(); Gfx_BindTexture(weather == WEATHER_RAINY ? rain_tex : snow_tex); @@ -468,16 +478,15 @@ void EnvRenderer_RenderWeather(double deltaTime) { particles = weather == WEATHER_RAINY; weather_accumulator += deltaTime; - VertexP3fT2fC4b v; v.Col = Env_SunCol; - VertexP3fT2fC4b vertices[WEATHER_VERTS_COUNT]; - VertexP3fT2fC4b* ptr = vertices; + ptr = vertices; + v.Col = Env_SunCol; - int dx, dz; for (dx = -WEATHER_EXTENT; dx <= WEATHER_EXTENT; dx++) { for (dz = -WEATHER_EXTENT; dz <= WEATHER_EXTENT; dz++) { - int x = pos.X + dx, z = pos.Z + dz; - float y = EnvRenderer_RainHeight(x, z); - float height = pos.Y - y; + x = pos.X + dx; z = pos.Z + dz; + + y = EnvRenderer_RainHeight(x, z); + height = pos.Y - y; if (height <= 0) continue; if (particles && (weather_accumulator >= 0.25 || moved)) { @@ -485,16 +494,17 @@ void EnvRenderer_RenderWeather(double deltaTime) { Particles_RainSnowEffect(particlePos); } - dist = (float)dx * (float)dx + (float)dz * (float)dz; - alpha = EnvRenderer_RainAlphaAt(dist); + dist = dx * dx + dz * dz; + alpha = EnvRenderer_RainAlphaAt((float)dist); Math_Clamp(alpha, 0.0f, 255.0f); v.Col.A = (uint8_t)alpha; /* NOTE: Making vertex is inlined since this is called millions of times. */ - float worldV = vOffset + (z & 1) / 2.0f - (x & 0x0F) / 16.0f; - float v1 = y / 6.0f + worldV, v2 = (y + height) / 6.0f + worldV; - float x1 = (float)x, y1 = (float)y, z1 = (float)z; - float x2 = (float)(x + 1), y2 = (float)(y + height), z2 = (float)(z + 1); + worldV = vOffset + (z & 1) / 2.0f - (x & 0x0F) / 16.0f; + v1 = y / 6.0f + worldV; + v2 = (y + height) / 6.0f + worldV; + x1 = (float)x; y1 = (float)y; z1 = (float)z; + x2 = (float)(x + 1); y2 = (float)(y + height); z2 = (float)(z + 1); v.X = x1; v.Y = y1; v.Z = z1; v.U = 0.0f; v.V = v1; *ptr++ = v; v.Y = y2; v.V = v2; *ptr++ = v; @@ -518,7 +528,7 @@ void EnvRenderer_RenderWeather(double deltaTime) { Gfx_SetAlphaArgBlend(true); Gfx_SetBatchFormat(VERTEX_FORMAT_P3FT2FC4B); - int vCount = (int)(ptr - vertices); + vCount = (int)(ptr - vertices); GfxCommon_UpdateDynamicVb_IndexedTris(weather_vb, vertices, vCount); Gfx_SetAlphaArgBlend(false); diff --git a/src/ErrorHandler.c b/src/ErrorHandler.c index 6b95b88df..23975bff1 100644 --- a/src/ErrorHandler.c +++ b/src/ErrorHandler.c @@ -445,13 +445,16 @@ typedef struct { } X11Button; static void X11Button_Draw(X11Button* b, X11Window* w) { + X11Textbox* t; + int begX, endX, begY, endY; + XSetForeground(dpy, w->gc, w->btnBorder); XDrawRectangle(dpy, w->win, w->gc, b->X, b->Y, b->Width, b->Height); - X11Textbox* t = &b->Text; - int begX = b->X + 1, endX = b->X + b->Width - 1; - int begY = b->Y + 1, endY = b->Y + b->Height - 1; + t = &b->Text; + begX = b->X + 1; endX = b->X + b->Width - 1; + begY = b->Y + 1; endY = b->Y + b->Height - 1; if (b->Clicked) { XSetForeground(dpy, w->gc, w->highlight); diff --git a/src/Game.h b/src/Game.h index 14f461885..561aeaecc 100644 --- a/src/Game.h +++ b/src/Game.h @@ -2,6 +2,7 @@ #define CC_GAME_H #include "Picking.h" #include "Options.h" +#include "Bitmap.h" /* Represents the game. Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 */ diff --git a/src/Graphics.h b/src/Graphics.h index 766ff3ad9..db9e2bfe6 100644 --- a/src/Graphics.h +++ b/src/Graphics.h @@ -3,6 +3,7 @@ #include "PackedCol.h" #include "Vectors.h" #include "GameStructs.h" +#include "Bitmap.h" /* Abstracts a 3D graphics rendering API. Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 diff --git a/src/GraphicsCommon.c b/src/GraphicsCommon.c index c335408e2..5fb4f7d04 100644 --- a/src/GraphicsCommon.c +++ b/src/GraphicsCommon.c @@ -167,52 +167,54 @@ void GfxCommon_RestoreAlphaState(uint8_t draw) { } -#define alphaMask ((uint32_t)0xFF000000UL) /* Quoted from http://www.realtimerendering.com/blog/gpus-prefer-premultiplication/ The short version: if you want your renderer to properly handle textures with alphas when using bilinear interpolation or mipmapping, you need to premultiply your PNG color data by their (unassociated) alphas. */ -static uint32_t GfxCommon_Average(uint32_t p1, uint32_t p2) { - uint32_t a1 = ((p1 & alphaMask) >> 24) & 0xFF; - uint32_t a2 = ((p2 & alphaMask) >> 24) & 0xFF; - uint32_t aSum = (a1 + a2); +static BitmapCol GfxCommon_Average(BitmapCol p1, BitmapCol p2) { + uint32_t a1, a2, aSum; + uint32_t b1, g1, r1; + uint32_t b2, g2, r2; + BitmapCol ave; + + a1 = p1.A; a2 = p2.A; + aSum = (a1 + a2); aSum = aSum > 0 ? aSum : 1; /* avoid divide by 0 below */ /* Convert RGB to pre-multiplied form */ - uint32_t r1 = ((p1 >> 16) & 0xFF) * a1, g1 = ((p1 >> 8) & 0xFF) * a1, b1 = (p1 & 0xFF) * a1; - uint32_t r2 = ((p2 >> 16) & 0xFF) * a2, g2 = ((p2 >> 8) & 0xFF) * a2, b2 = (p2 & 0xFF) * a2; + b1 = p1.B * a1; g1 = p1.G * a1; r1 = p1.R * a1; + b2 = p1.B * a2; g2 = p2.G * a2; r2 = p2.R * a2; /* https://stackoverflow.com/a/347376 We need to convert RGB back from the pre-multiplied average into normal form ((r1 + r2) / 2) / ((a1 + a2) / 2) but we just cancel out the / 2*/ - uint32_t aAve = aSum >> 1; - uint32_t rAve = (r1 + r2) / aSum; - uint32_t gAve = (g1 + g2) / aSum; - uint32_t bAve = (b1 + b2) / aSum; - - return (aAve << 24) | (rAve << 16) | (gAve << 8) | bAve; + ave.B = (b1 + b2) / aSum; + ave.G = (g1 + g2) / aSum; + ave.R = (r1 + r2) / aSum; + ave.A = aSum >> 1; + return ave; } void GfxCommon_GenMipmaps(int width, int height, uint8_t* lvlScan0, uint8_t* scan0) { - uint32_t* baseSrc = (uint32_t*)scan0; - uint32_t* baseDst = (uint32_t*)lvlScan0; + BitmapCol* baseSrc = (BitmapCol*)scan0; + BitmapCol* baseDst = (BitmapCol*)lvlScan0; int srcWidth = width << 1; int x, y; for (y = 0; y < height; y++) { int srcY = (y << 1); - uint32_t* src0 = baseSrc + srcY * srcWidth; - uint32_t* src1 = src0 + srcWidth; - uint32_t* dst = baseDst + y * width; + BitmapCol* src0 = baseSrc + srcY * srcWidth; + BitmapCol* src1 = src0 + srcWidth; + BitmapCol* dst = baseDst + y * width; for (x = 0; x < width; x++) { int srcX = (x << 1); - uint32_t src00 = src0[srcX], src01 = src0[srcX + 1]; - uint32_t src10 = src1[srcX], src11 = src1[srcX + 1]; + BitmapCol src00 = src0[srcX], src01 = src0[srcX + 1]; + BitmapCol src10 = src1[srcX], src11 = src1[srcX + 1]; /* bilinear filter this mipmap */ - uint32_t ave0 = GfxCommon_Average(src00, src01); - uint32_t ave1 = GfxCommon_Average(src10, src11); + BitmapCol ave0 = GfxCommon_Average(src00, src01); + BitmapCol ave1 = GfxCommon_Average(src10, src11); dst[x] = GfxCommon_Average(ave0, ave1); } } diff --git a/src/PackedCol.c b/src/PackedCol.c index b071d3851..e96483cd4 100644 --- a/src/PackedCol.c +++ b/src/PackedCol.c @@ -13,10 +13,6 @@ bool PackedCol_Equals(PackedCol a, PackedCol b) { return a.R == b.R && a.G == b.G && a.B == b.B && a.A == b.A; } -uint32_t PackedCol_ToARGB(PackedCol col) { - return PackedCol_ARGB(col.R, col.G, col.B, col.A); -} - PackedCol PackedCol_Scale(PackedCol value, float t) { value.R = (uint8_t)(value.R * t); value.G = (uint8_t)(value.G * t); diff --git a/src/PackedCol.h b/src/PackedCol.h index 8627931e7..7efa551b8 100644 --- a/src/PackedCol.h +++ b/src/PackedCol.h @@ -1,11 +1,11 @@ #ifndef CC_PACKEDCOL_H #define CC_PACKEDCOL_H #include "String.h" -/* Manipulates an ARGB colour, in a format suitable for the native 3d graphics api. +/* Manipulates an ARGB colour, in a format suitable for the native 3D graphics API. Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 */ -/* Represents an ARGB colour, in a format suitable for the native graphics api. */ +/* Represents an ARGB colour, suitable for native graphics API colours. */ typedef CC_ALIGN_HINT(4) struct PackedCol_ { #ifdef CC_BUILD_D3D9 uint8_t B, G, R, A; @@ -14,25 +14,22 @@ #endif } PackedCol; -/* Represents an ARGB colour, in a format suitable for the native graphics api. */ +/* Represents an ARGB colour, suitable for native graphics API colours. */ /* Unioned with Packed member for efficient equality comparison */ typedef union PackedColUnion_ { PackedCol C; uint32_t Raw; } PackedColUnion; -/* NOTE: can't just use "struct { uint8_t B, G, R, A; };" here, - because unnamed members aren't supported on all compilers) */ #ifdef CC_BUILD_D3D9 #define PACKEDCOL_CONST(r, g, b, a) { b, g, r, a } #else #define PACKEDCOL_CONST(r, g, b, a) { r, g, b, a } #endif +#define PACKEDCOL_WHITE PACKEDCOL_CONST(255, 255, 255, 255) PackedCol PackedCol_Create4(uint8_t r, uint8_t g, uint8_t b, uint8_t a); PackedCol PackedCol_Create3(uint8_t r, uint8_t g, uint8_t b); bool PackedCol_Equals(PackedCol a, PackedCol b); #define PackedCol_ARGB(r, g, b, a) (((uint32_t)(r) << 16) | ((uint32_t)(g) << 8) | ((uint32_t)(b)) | ((uint32_t)(a) << 24)) -#define PackedCol_ARGB_A(col) ((uint8_t)((col) >> 24)) -uint32_t PackedCol_ToARGB(PackedCol col); PackedCol PackedCol_Scale(PackedCol value, float t); PackedCol PackedCol_Lerp(PackedCol a, PackedCol b, float t); CC_NOINLINE bool PackedCol_Unhex(char hex, int* value); @@ -44,13 +41,4 @@ CC_NOINLINE bool PackedCol_TryParseHex(const String* str, PackedCol* value); #define PACKEDCOL_SHADE_YMIN 0.5f /* Retrieves shaded colours for ambient block face lighting */ void PackedCol_GetShaded(PackedCol normal, PackedCol* xSide, PackedCol* zSide, PackedCol* yMin); - -#define PACKEDCOL_WHITE PACKEDCOL_CONST(255, 255, 255, 255) -#define PACKEDCOL_BLACK PACKEDCOL_CONST( 0, 0, 0, 255) -#define PACKEDCOL_RED PACKEDCOL_CONST(255, 0, 0, 255) -#define PACKEDCOL_GREEN PACKEDCOL_CONST( 0, 255, 0, 255) -#define PACKEDCOL_BLUE PACKEDCOL_CONST( 0, 0, 255, 255) -#define PACKEDCOL_YELLOW PACKEDCOL_CONST(255, 255, 0, 255) -#define PACKEDCOL_MAGENTA PACKEDCOL_CONST(255, 0, 255, 255) -#define PACKEDCOL_CYAN PACKEDCOL_CONST( 0, 255, 255, 255) #endif diff --git a/src/PacketHandlers.c b/src/PacketHandlers.c index 442a96c7a..ae9d23e23 100644 --- a/src/PacketHandlers.c +++ b/src/PacketHandlers.c @@ -1212,7 +1212,7 @@ static void CPE_BulkBlockUpdate(uint8_t* data) { } static void CPE_SetTextColor(uint8_t* data) { - PackedCol c; + BitmapCol c; uint8_t code; c.R = *data++; c.G = *data++; c.B = *data++; c.A = *data++; diff --git a/src/Platform.c b/src/Platform.c index 6a30b52be..bf46c7f5f 100644 --- a/src/Platform.c +++ b/src/Platform.c @@ -1007,7 +1007,7 @@ Size2D Platform_TextMeasure(struct DrawTextArgs* args) { return s; } -Size2D Platform_TextDraw(struct DrawTextArgs* args, Bitmap* bmp, int x, int y, PackedCol col) { +Size2D Platform_TextDraw(struct DrawTextArgs* args, Bitmap* bmp, int x, int y, BitmapCol col) { FT_Face face = args->Font.Handle; String text = args->Text; Size2D s = { x, TEXT_CEIL(face->size->metrics.height) }; @@ -1023,19 +1023,19 @@ Size2D Platform_TextDraw(struct DrawTextArgs* args, Bitmap* bmp, int x, int y, P for (yy = 0; yy < img->rows; yy++) { if ((y + yy) < 0 || (y + yy) >= bmp->Height) continue; - uint8_t* src = img->buffer + (yy * img->width); - uint8_t* dst = (uint8_t*)Bitmap_GetRow(bmp, y + yy) + (x * BITMAP_SIZEOF_PIXEL); + uint8_t* src = img->buffer + (yy * img->width); + BitmapCol* dst = Bitmap_GetRow(bmp, y + yy) + x; for (xx = 0; xx < img->width; xx++) { if ((x + xx) < 0 || (x + xx) >= bmp->Width) continue; uint8_t intensity = *src, invIntensity = UInt8_MaxValue - intensity; - dst[0] = ((col.B * intensity) >> 8) + ((dst[0] * invIntensity) >> 8); - dst[1] = ((col.G * intensity) >> 8) + ((dst[1] * invIntensity) >> 8); - dst[2] = ((col.R * intensity) >> 8) + ((dst[2] * invIntensity) >> 8); - //dst[3] = ((col.A * intensity) >> 8) + ((dst[3] * invIntensity) >> 8); - dst[3] = intensity + ((dst[3] * invIntensity) >> 8); - src++; dst += BITMAP_SIZEOF_PIXEL; + dst->B = ((col.B * intensity) >> 8) + ((dst->B * invIntensity) >> 8); + dst->G = ((col.G * intensity) >> 8) + ((dst->G * invIntensity) >> 8); + dst->R = ((col.R * intensity) >> 8) + ((dst->R * invIntensity) >> 8); + //dst[3] = ((col.A * intensity) >> 8) + ((dst->A * invIntensity) >> 8); + dst->A = intensity + ((dst->A * invIntensity) >> 8); + src++; dst++; } } diff --git a/src/Platform.h b/src/Platform.h index 67989224a..9d7804cc3 100644 --- a/src/Platform.h +++ b/src/Platform.h @@ -2,6 +2,7 @@ #define CC_PLATFORM_H #include "Utils.h" #include "PackedCol.h" +#include "Bitmap.h" /* Abstracts platform specific memory management, I/O, etc. Copyright 2017 ClassicalSharp | Licensed under BSD-3 */ @@ -176,7 +177,7 @@ CC_EXPORT void Font_Free(FontDesc* desc); /* Measures dimensions of the given text, if it was drawn with the given font. */ CC_EXPORT Size2D Platform_TextMeasure(struct DrawTextArgs* args); /* Draws the given text with the given font onto the given bitmap. */ -CC_EXPORT Size2D Platform_TextDraw(struct DrawTextArgs* args, Bitmap* bmp, int x, int y, PackedCol col); +CC_EXPORT Size2D Platform_TextDraw(struct DrawTextArgs* args, Bitmap* bmp, int x, int y, BitmapCol col); /* Allocates a new socket. */ void Socket_Create(SocketPtr* socket); diff --git a/src/TerrainAtlas.c b/src/TerrainAtlas.c index 76227840f..f87468c41 100644 --- a/src/TerrainAtlas.c +++ b/src/TerrainAtlas.c @@ -1,5 +1,4 @@ #include "TerrainAtlas.h" -#include "Bitmap.h" #include "Block.h" #include "ExtMath.h" #include "Funcs.h" diff --git a/src/TerrainAtlas.h b/src/TerrainAtlas.h index 22cc31a23..bb4cd3679 100644 --- a/src/TerrainAtlas.h +++ b/src/TerrainAtlas.h @@ -1,6 +1,6 @@ #ifndef CC_TERRAINATLAS_H #define CC_TERRAINATLAS_H -#include "Core.h" +#include "Bitmap.h" /* Represents the 2D texture atlas of terrain.png, and converted into an array of 1D textures. Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 */ diff --git a/src/Utils.c b/src/Utils.c index 3df303a6b..0af78d087 100644 --- a/src/Utils.c +++ b/src/Utils.c @@ -154,14 +154,13 @@ int Utils_AccumulateWheelDelta(float* accumulator, float delta) { } uint8_t Utils_GetSkinType(const Bitmap* bmp) { + int scale; if (bmp->Width == bmp->Height * 2) return SKIN_64x32; if (bmp->Width != bmp->Height) return SKIN_INVALID; /* Minecraft alex skins have this particular pixel with alpha of 0 */ - int scale = bmp->Width / 64; - uint32_t pixel = Bitmap_GetPixel(bmp, 54 * scale, 20 * scale); - uint8_t alpha = PackedCol_ARGB_A(pixel); - return alpha >= 127 ? SKIN_64x64 : SKIN_64x64_SLIM; + scale = bmp->Width / 64; + return Bitmap_GetPixel(bmp, 54 * scale, 20 * scale).A >= 127 ? SKIN_64x64 : SKIN_64x64_SLIM; } uint32_t Utils_CRC32(const uint8_t* data, uint32_t length) { diff --git a/src/Utils.h b/src/Utils.h index a20dd059d..d0f196ae9 100644 --- a/src/Utils.h +++ b/src/Utils.h @@ -1,6 +1,7 @@ #ifndef CC_UTILS_H #define CC_UTILS_H #include "String.h" +#include "Bitmap.h" /* Implements various utility functions. Copyright 2014-2017 ClassicalSharp | Licensed under BSD-3 */ diff --git a/src/Widgets.c b/src/Widgets.c index 1b6ff8643..91b4ccaf8 100644 --- a/src/Widgets.c +++ b/src/Widgets.c @@ -925,6 +925,7 @@ static char InputWidget_GetLastCol(struct InputWidget* w, int x, int y) { } static void InputWidget_UpdateCaret(struct InputWidget* w) { + BitmapCol col; String line; char lineBuffer[STRING_SIZE]; struct DrawTextArgs args; int maxChars, lineWidth; @@ -961,7 +962,9 @@ static void InputWidget_UpdateCaret(struct InputWidget* w) { colCode = InputWidget_GetLastCol(w, w->CaretX, w->CaretY); if (colCode) { - w->CaretCol = Drawer2D_GetCol(colCode); + col = Drawer2D_GetCol(colCode); + w->CaretCol.B = col.B; w->CaretCol.G = col.G; + w->CaretCol.R = col.R; w->CaretCol.A = col.A; } else { PackedCol white = PACKEDCOL_WHITE; w->CaretCol = PackedCol_Scale(white, 0.8f); @@ -2725,9 +2728,9 @@ static Size2D SpecialInputWidget_MeasureTitles(struct SpecialInputWidget* w) { } static void SpecialInputWidget_DrawTitles(struct SpecialInputWidget* w, Bitmap* bmp) { - PackedCol col_selected = PACKEDCOL_CONST(30, 30, 30, 200); - PackedCol col_inactive = PACKEDCOL_CONST( 0, 0, 0, 127); - PackedCol col; + BitmapCol col_selected = BITMAPCOL_CONST(30, 30, 30, 200); + BitmapCol col_inactive = BITMAPCOL_CONST( 0, 0, 0, 127); + BitmapCol col; struct DrawTextArgs args; Size2D size; @@ -2788,7 +2791,7 @@ static void SpecialInputWidget_DrawContent(struct SpecialInputWidget* w, struct } static void SpecialInputWidget_Make(struct SpecialInputWidget* w, struct SpecialInputTab* tab) { - PackedCol col = PACKEDCOL_CONST(30, 30, 30, 200); + BitmapCol col = PACKEDCOL_CONST(30, 30, 30, 200); Size2D size, titles, content; Bitmap bmp;