mirror of
https://github.com/beefytech/Beef.git
synced 2025-06-08 11:38:21 +02:00
BMP loading, show workspace icon files on startup panel
This commit is contained in:
parent
c8394bef26
commit
05cda98c85
11 changed files with 725 additions and 4 deletions
|
@ -463,6 +463,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
|
||||||
<ClCompile Include="gfx\Texture.cpp" />
|
<ClCompile Include="gfx\Texture.cpp" />
|
||||||
<ClCompile Include="HeadlessApp.cpp" />
|
<ClCompile Include="HeadlessApp.cpp" />
|
||||||
<ClCompile Include="img\BFIData.cpp" />
|
<ClCompile Include="img\BFIData.cpp" />
|
||||||
|
<ClCompile Include="img\BMPData.cpp" />
|
||||||
<ClCompile Include="img\ImageAdjustments.cpp" />
|
<ClCompile Include="img\ImageAdjustments.cpp" />
|
||||||
<ClCompile Include="img\ImageData.cpp" />
|
<ClCompile Include="img\ImageData.cpp" />
|
||||||
<ClCompile Include="img\ImageUtils.cpp" />
|
<ClCompile Include="img\ImageUtils.cpp" />
|
||||||
|
@ -1985,6 +1986,7 @@ copy /y "$(OutDir)$(TargetName).lib" "$(SolutionDir)\BeefLibs\Beefy2D\dist\"</Co
|
||||||
<ClInclude Include="gfx\Texture.h" />
|
<ClInclude Include="gfx\Texture.h" />
|
||||||
<ClInclude Include="HeadlessApp.h" />
|
<ClInclude Include="HeadlessApp.h" />
|
||||||
<ClInclude Include="img\BFIData.h" />
|
<ClInclude Include="img\BFIData.h" />
|
||||||
|
<ClInclude Include="img\BMPData.h" />
|
||||||
<ClInclude Include="img\ImageAdjustments.h" />
|
<ClInclude Include="img\ImageAdjustments.h" />
|
||||||
<ClInclude Include="img\ImageData.h" />
|
<ClInclude Include="img\ImageData.h" />
|
||||||
<ClInclude Include="img\ImageUtils.h" />
|
<ClInclude Include="img\ImageUtils.h" />
|
||||||
|
|
|
@ -740,6 +740,9 @@
|
||||||
<ClCompile Include="util\MTRand.cpp">
|
<ClCompile Include="util\MTRand.cpp">
|
||||||
<Filter>src\util</Filter>
|
<Filter>src\util</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="img\BMPData.cpp">
|
||||||
|
<Filter>src\img</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Common.h">
|
<ClInclude Include="Common.h">
|
||||||
|
@ -1141,6 +1144,9 @@
|
||||||
<ClInclude Include="util\MTRand.h">
|
<ClInclude Include="util\MTRand.h">
|
||||||
<Filter>src\util</Filter>
|
<Filter>src\util</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="img\BMPData.h">
|
||||||
|
<Filter>src\img</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<CustomBuild Include="third_party\libffi\i686-pc-cygwin\src\x86\win32.asm">
|
<CustomBuild Include="third_party\libffi\i686-pc-cygwin\src\x86\win32.asm">
|
||||||
|
|
|
@ -199,6 +199,7 @@
|
||||||
<ClCompile Include="gfx\Shader.cpp" />
|
<ClCompile Include="gfx\Shader.cpp" />
|
||||||
<ClCompile Include="gfx\Texture.cpp" />
|
<ClCompile Include="gfx\Texture.cpp" />
|
||||||
<ClCompile Include="img\BFIData.cpp" />
|
<ClCompile Include="img\BFIData.cpp" />
|
||||||
|
<ClCompile Include="img\BMPData.cpp" />
|
||||||
<ClCompile Include="img\ImageAdjustments.cpp" />
|
<ClCompile Include="img\ImageAdjustments.cpp" />
|
||||||
<ClCompile Include="img\ImageData.cpp" />
|
<ClCompile Include="img\ImageData.cpp" />
|
||||||
<ClCompile Include="img\ImageUtils.cpp" />
|
<ClCompile Include="img\ImageUtils.cpp" />
|
||||||
|
@ -908,6 +909,7 @@
|
||||||
<ClInclude Include="gfx\Shader.h" />
|
<ClInclude Include="gfx\Shader.h" />
|
||||||
<ClInclude Include="gfx\Texture.h" />
|
<ClInclude Include="gfx\Texture.h" />
|
||||||
<ClInclude Include="img\BFIData.h" />
|
<ClInclude Include="img\BFIData.h" />
|
||||||
|
<ClInclude Include="img\BMPData.h" />
|
||||||
<ClInclude Include="img\ImageAdjustments.h" />
|
<ClInclude Include="img\ImageAdjustments.h" />
|
||||||
<ClInclude Include="img\ImageData.h" />
|
<ClInclude Include="img\ImageData.h" />
|
||||||
<ClInclude Include="img\ImageUtils.h" />
|
<ClInclude Include="img\ImageUtils.h" />
|
||||||
|
|
|
@ -590,6 +590,9 @@
|
||||||
<ClCompile Include="third_party\putty\wildcard.c">
|
<ClCompile Include="third_party\putty\wildcard.c">
|
||||||
<Filter>src\third_party\putty</Filter>
|
<Filter>src\third_party\putty</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="img\BMPData.cpp">
|
||||||
|
<Filter>src\img</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="Common.h">
|
<ClInclude Include="Common.h">
|
||||||
|
@ -907,6 +910,9 @@
|
||||||
<ClInclude Include="third_party\putty\wildcard.h">
|
<ClInclude Include="third_party\putty\wildcard.h">
|
||||||
<Filter>src\third_party\putty</Filter>
|
<Filter>src\third_party\putty</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="img\BMPData.h">
|
||||||
|
<Filter>src\img</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<CustomBuild Include="third_party\libffi\i686-pc-cygwin\src\x86\win32.asm">
|
<CustomBuild Include="third_party\libffi\i686-pc-cygwin\src\x86\win32.asm">
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include "img/TGAData.h"
|
#include "img/TGAData.h"
|
||||||
#include "img/PNGData.h"
|
#include "img/PNGData.h"
|
||||||
#include "img/PVRData.h"
|
#include "img/PVRData.h"
|
||||||
|
#include "img/BMPData.h"
|
||||||
#include "img/BFIData.h"
|
#include "img/BFIData.h"
|
||||||
#include "img/JPEGData.h"
|
#include "img/JPEGData.h"
|
||||||
#include "util/PerfTimer.h"
|
#include "util/PerfTimer.h"
|
||||||
|
@ -142,6 +143,12 @@ Texture* RenderDevice::LoadTexture(const StringImpl& fileName, int flags)
|
||||||
imageData = new JPEGData();
|
imageData = new JPEGData();
|
||||||
else if (ext == ".pvr")
|
else if (ext == ".pvr")
|
||||||
imageData = new PVRData();
|
imageData = new PVRData();
|
||||||
|
else if (ext == ".bmp")
|
||||||
|
{
|
||||||
|
BMPData* bmpData = new BMPData();
|
||||||
|
bmpData->mHasTransFollowing = (flags & TextureFlag_HasTransFollowing) == 0;;
|
||||||
|
imageData = bmpData;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
return NULL; // Unknown format
|
return NULL; // Unknown format
|
||||||
|
|
|
@ -156,6 +156,7 @@ enum TextureFlag : int8
|
||||||
TextureFlag_Additive = 1,
|
TextureFlag_Additive = 1,
|
||||||
TextureFlag_NoPremult = 2,
|
TextureFlag_NoPremult = 2,
|
||||||
TextureFlag_AllowRead = 4,
|
TextureFlag_AllowRead = 4,
|
||||||
|
TextureFlag_HasTransFollowing = 8
|
||||||
};
|
};
|
||||||
|
|
||||||
struct VertexDefData
|
struct VertexDefData
|
||||||
|
|
531
BeefySysLib/img/BMPData.cpp
Normal file
531
BeefySysLib/img/BMPData.cpp
Normal file
|
@ -0,0 +1,531 @@
|
||||||
|
#include "BMPData.h"
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
USING_NS_BF;
|
||||||
|
|
||||||
|
#pragma warning(disable:4996)
|
||||||
|
|
||||||
|
int BMPData::Read(void* ptr, int elemSize, int elemCount)
|
||||||
|
{
|
||||||
|
int maxReadCount = (mSrcDataLen - mReadPos) / elemSize;
|
||||||
|
if (elemCount > maxReadCount)
|
||||||
|
elemCount = maxReadCount;
|
||||||
|
memcpy(ptr, mSrcData + mReadPos, elemCount * elemSize);
|
||||||
|
mReadPos += elemCount * elemSize;
|
||||||
|
return elemCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char BMPData::ReadC()
|
||||||
|
{
|
||||||
|
if (mReadPos >= mSrcDataLen)
|
||||||
|
return 0;
|
||||||
|
return mSrcData[mReadPos++];
|
||||||
|
}
|
||||||
|
|
||||||
|
BMPData::BMPData()
|
||||||
|
{
|
||||||
|
mHasTransFollowing = false;
|
||||||
|
mReadPos = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#define BITMAP_MAGIC_NUMBER 19778
|
||||||
|
|
||||||
|
typedef struct bmp_file_header_s bmp_file_header_t;
|
||||||
|
struct bmp_file_header_s
|
||||||
|
{
|
||||||
|
/* int16_t magic_number; */ /* because of padding, we don't put it into the struct */
|
||||||
|
int32_t size;
|
||||||
|
int32_t app_id;
|
||||||
|
int32_t offset;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct bmp_bitmap_info_header_s bmp_bitmap_info_header_t;
|
||||||
|
struct bmp_bitmap_info_header_s
|
||||||
|
{
|
||||||
|
int32_t header_size;
|
||||||
|
int32_t width;
|
||||||
|
int32_t height;
|
||||||
|
int16_t num_planes;
|
||||||
|
int16_t bpp;
|
||||||
|
int32_t compression;
|
||||||
|
int32_t image_size;
|
||||||
|
int32_t horizontal_resolution;
|
||||||
|
int32_t vertical_resolution;
|
||||||
|
int32_t colors_used;
|
||||||
|
int32_t colors_important;
|
||||||
|
};
|
||||||
|
|
||||||
|
//typedef struct bmp_palette_element_s bmp_palette_element_t;
|
||||||
|
|
||||||
|
|
||||||
|
bool BMPData::ReadPixelsRLE8(bmp_palette_element_t* palette)
|
||||||
|
{
|
||||||
|
unsigned char byte, index, i, * p;
|
||||||
|
unsigned char x_ofs, y_ofs;
|
||||||
|
char keepreading = 1;
|
||||||
|
int current_line = 0;
|
||||||
|
unsigned char* dest = (unsigned char*)mBits;
|
||||||
|
|
||||||
|
p = dest;
|
||||||
|
while (keepreading) { /* in each loop, we read a pair of bytes */
|
||||||
|
byte = ReadC(); /* read the first byte */
|
||||||
|
if (byte) {
|
||||||
|
index = ReadC(); /* read the second byte */
|
||||||
|
for (i = 0; i < byte; i++) {
|
||||||
|
*p = palette[index].red; p++; /* unindex pixels on the fly */
|
||||||
|
*p = palette[index].green; p++;
|
||||||
|
*p = palette[index].blue; p++;
|
||||||
|
*p = 0xFF; p++; /* add alpha */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
byte = ReadC(); /* read the second byte */
|
||||||
|
switch (byte)
|
||||||
|
{
|
||||||
|
case 0: /* skip the end of the current line and go to the next line */
|
||||||
|
current_line++;
|
||||||
|
p = dest + current_line * mWidth * 4;
|
||||||
|
break;
|
||||||
|
case 1: /* stop reading */
|
||||||
|
keepreading = 0;
|
||||||
|
break;
|
||||||
|
case 2: /* skip y_ofs lines and x_ofs columns. This means that the ignored pixels will be
|
||||||
|
filled with black (Or maybe i didn't understand the spec ?). This has already be done :
|
||||||
|
before starting to load pixel data, we filled all the dest[] array with 0x00 by a memset() */
|
||||||
|
x_ofs = ReadC();
|
||||||
|
y_ofs = ReadC();
|
||||||
|
current_line += y_ofs;
|
||||||
|
p += y_ofs * mWidth * 4 + x_ofs * 4;
|
||||||
|
break;
|
||||||
|
default: /* get the next n pixels, where n = byte */
|
||||||
|
for (i = 0; i < byte; i++) {
|
||||||
|
index = ReadC();
|
||||||
|
*p = palette[index].red; p++; /* unindex pixels on the fly */
|
||||||
|
*p = palette[index].green; p++;
|
||||||
|
*p = palette[index].blue; p++;
|
||||||
|
*p = 0xFF; p++; /* add alpha */
|
||||||
|
}
|
||||||
|
/* if n is not a multiple of 2, then skip one byte in the file, to respect int16_t alignment */
|
||||||
|
if (byte % 2) mReadPos++;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* the place to which p is pointing is guided by the content of the file. A corrupted file could make p point to a wrong localization.
|
||||||
|
Hence, we must check that we don't point outside of the dest[] array. This may prevent an error of segmentation */
|
||||||
|
if (p >= dest + mWidth * mHeight * 4) keepreading = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BMPData::ReadPixelsRLE4(bmp_palette_element_t* palette)
|
||||||
|
{
|
||||||
|
unsigned char byte1, byte2, index1, index2, * p;
|
||||||
|
unsigned char x_ofs, y_ofs;
|
||||||
|
unsigned char bitmask = 0x0F; /* bit mask : 00001111 */
|
||||||
|
char keepreading = 1;
|
||||||
|
int current_line = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
unsigned char* dest = (unsigned char*)mBits;
|
||||||
|
|
||||||
|
p = dest;
|
||||||
|
while (keepreading) {
|
||||||
|
byte1 = ReadC();
|
||||||
|
if (byte1) { /* encoded mode */
|
||||||
|
byte2 = ReadC();
|
||||||
|
index1 = byte2 >> 4; /* get the first 4 bits of byte2 */
|
||||||
|
index2 = byte2 & bitmask; /* get the next 4 bits of byte2 */
|
||||||
|
for (i = 0; i < (byte1 / 2); i++) {
|
||||||
|
*p = palette[index1].red; p++;
|
||||||
|
*p = palette[index1].green; p++;
|
||||||
|
*p = palette[index1].blue; p++;
|
||||||
|
*p = 0x0F; p++;
|
||||||
|
*p = palette[index2].red; p++;
|
||||||
|
*p = palette[index2].green; p++;
|
||||||
|
*p = palette[index2].blue; p++;
|
||||||
|
*p = 0x0F; p++;
|
||||||
|
}
|
||||||
|
if (byte1 % 2) {
|
||||||
|
*p = palette[index1].red; p++;
|
||||||
|
*p = palette[index1].green; p++;
|
||||||
|
*p = palette[index1].blue; p++;
|
||||||
|
*p = 0x0F; p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else { /* absolute mode */
|
||||||
|
byte2 = ReadC();
|
||||||
|
switch (byte2)
|
||||||
|
{
|
||||||
|
case 0: /* skip the end of the current line and go to the next line */
|
||||||
|
current_line++;
|
||||||
|
p = dest + current_line * mWidth * 4;
|
||||||
|
break;
|
||||||
|
case 1: /* stop reading */
|
||||||
|
keepreading = 0;
|
||||||
|
break;
|
||||||
|
case 2: /* skip y_ofs lines and x_ofs column */
|
||||||
|
x_ofs = ReadC();
|
||||||
|
y_ofs = ReadC();
|
||||||
|
current_line += y_ofs;
|
||||||
|
p += y_ofs * mWidth * 4 + x_ofs * 4;
|
||||||
|
break;
|
||||||
|
default: /* get the next n pixels, where n = byte2 */
|
||||||
|
for (i = 0; i < (byte2 / 2); i++) {
|
||||||
|
byte1 = ReadC();
|
||||||
|
index1 = byte1 >> 4;
|
||||||
|
*p = palette[index1].red; p++;
|
||||||
|
*p = palette[index1].green; p++;
|
||||||
|
*p = palette[index1].blue; p++;
|
||||||
|
*p = 0x0F; p++;
|
||||||
|
index2 = byte1 & bitmask;
|
||||||
|
*p = palette[index2].red; p++;
|
||||||
|
*p = palette[index2].green; p++;
|
||||||
|
*p = palette[index2].blue; p++;
|
||||||
|
*p = 0x0F; p++;
|
||||||
|
}
|
||||||
|
if (byte2 % 2) {
|
||||||
|
byte1 = ReadC();
|
||||||
|
index1 = byte1 >> 4;
|
||||||
|
*p = palette[index1].red; p++;
|
||||||
|
*p = palette[index1].green; p++;
|
||||||
|
*p = palette[index1].blue; p++;
|
||||||
|
*p = 0x0F; p++;
|
||||||
|
}
|
||||||
|
if (((byte2 + 1) / 2) % 2) /* int16_t alignment */
|
||||||
|
mReadPos += 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* the place to which p is pointing is guided by the content of the file. A corrupted file could make p point to a wrong localization.
|
||||||
|
Hence, we must check that we don't point outside of the dest[] array. This may prevent an error of segmentation */
|
||||||
|
if (p >= dest + mWidth * mHeight * 4) keepreading = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BMPData::ReadPixels32()
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
unsigned char px[4], * p;
|
||||||
|
|
||||||
|
unsigned char* dest = (unsigned char*)mBits;
|
||||||
|
|
||||||
|
for (i = 0; i < mHeight; i++)
|
||||||
|
{
|
||||||
|
p = dest + (mHeight - i - 1) * mWidth * 4;
|
||||||
|
for (j = 0; j < mWidth; j++)
|
||||||
|
{
|
||||||
|
Read(px, 4, 1); /* convert BGRX to RGBA */
|
||||||
|
*p = px[2]; p++; // R
|
||||||
|
*p = px[1]; p++;
|
||||||
|
*p = px[0]; p++;
|
||||||
|
*p = px[3]; p++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BMPData::ReadPixels24()
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
unsigned char px[3], * p;
|
||||||
|
|
||||||
|
unsigned char* dest = (unsigned char*)mBits;
|
||||||
|
|
||||||
|
for (i = 0; i < mHeight; i++)
|
||||||
|
{
|
||||||
|
p = dest + (mHeight - i - 1) * mWidth * 4;
|
||||||
|
for (j = 0; j < mWidth; j++)
|
||||||
|
{
|
||||||
|
Read(px, 3, 1);
|
||||||
|
*p = px[2]; p++; /* convert BGR to RGBA */
|
||||||
|
*p = px[1]; p++;
|
||||||
|
*p = px[0]; p++;
|
||||||
|
*p = 0xFF; p++; /* add alpha component */
|
||||||
|
}
|
||||||
|
if (mWidth * 3 % 4 != 0)
|
||||||
|
mReadPos += 4 - (mWidth * 3 % 4); /* if the width is not a multiple of 4, skip the end of the line */
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Expected format : XBGR 0 11111 11111 11111 */
|
||||||
|
bool BMPData::ReadPixels16()
|
||||||
|
{
|
||||||
|
uint16_t pxl, r, g, b;
|
||||||
|
uint16_t bitmask = 0x1F;
|
||||||
|
unsigned char* p;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
unsigned char* dest = (unsigned char*)mBits;
|
||||||
|
|
||||||
|
p = dest;
|
||||||
|
for (i = 0; i < mHeight; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < mWidth; j++)
|
||||||
|
{
|
||||||
|
Read(&pxl, 2, 1);
|
||||||
|
b = (pxl >> 10) & bitmask;
|
||||||
|
g = (pxl >> 5) & bitmask;
|
||||||
|
r = pxl & bitmask;
|
||||||
|
*p = r * 8; p++; /* fix me */
|
||||||
|
*p = g * 8; p++;
|
||||||
|
*p = b * 8; p++;
|
||||||
|
*p = 0xFF; p++;
|
||||||
|
}
|
||||||
|
if ((2 * mWidth) % 4 != 0)
|
||||||
|
mReadPos += 4 - ((2 * mWidth) % 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BMPData::ReadPixels8(bmp_palette_element_t* palette)
|
||||||
|
{
|
||||||
|
int i, j;
|
||||||
|
unsigned char px, * p;
|
||||||
|
|
||||||
|
unsigned char* dest = (unsigned char*)mBits;
|
||||||
|
|
||||||
|
p = dest;
|
||||||
|
for (i = 0; i < mHeight; i++) {
|
||||||
|
for (j = 0; j < mWidth; j++) {
|
||||||
|
Read(&px, 1, 1);
|
||||||
|
*p = palette[px].red; p++;
|
||||||
|
*p = palette[px].green; p++;
|
||||||
|
*p = palette[px].blue; p++;
|
||||||
|
*p = 0xFF; p++;
|
||||||
|
}
|
||||||
|
if (mWidth % 4 != 0)
|
||||||
|
mReadPos += 4 - (mWidth % 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BMPData::ReadPixels4(bmp_palette_element_t* palette)
|
||||||
|
{
|
||||||
|
int size = (mWidth + 1) / 2; /* byte alignment */
|
||||||
|
unsigned char* row_stride = new unsigned char[size]; /* not C90 but convenient here */
|
||||||
|
defer({ delete row_stride; });
|
||||||
|
|
||||||
|
unsigned char index, byte, * p;
|
||||||
|
unsigned char bitmask = 0x0F; /* bit mask : 00001111 */
|
||||||
|
|
||||||
|
unsigned char* dest = (unsigned char*)mBits;
|
||||||
|
|
||||||
|
p = dest;
|
||||||
|
for (int i = 0; i < mHeight; i++)
|
||||||
|
{
|
||||||
|
Read(row_stride, size, 1);
|
||||||
|
for (int j = 0; j < mWidth; j++)
|
||||||
|
{
|
||||||
|
byte = row_stride[j / 2];
|
||||||
|
index = (j % 2) ? bitmask & byte : byte >> 4;
|
||||||
|
*p = palette[index].red; p++;
|
||||||
|
*p = palette[index].green; p++;
|
||||||
|
*p = palette[index].blue; p++;
|
||||||
|
*p = 0xFF; p++;
|
||||||
|
}
|
||||||
|
if (size % 4 != 0)
|
||||||
|
mReadPos += 4 - (size % 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BMPData::ReadPixels1(bmp_palette_element_t* palette)
|
||||||
|
{
|
||||||
|
int size = (mWidth + 7) / 8; /* byte alignment */
|
||||||
|
unsigned char* row_stride = new unsigned char[size]; /* not C90 but convenient here */
|
||||||
|
defer({ delete row_stride; });
|
||||||
|
|
||||||
|
unsigned char index, byte, * p;
|
||||||
|
unsigned char bitmask = 0x01; /* bit mask : 00000001 */
|
||||||
|
int bit;
|
||||||
|
|
||||||
|
unsigned char* dest = (unsigned char*)mBits;
|
||||||
|
|
||||||
|
p = dest;
|
||||||
|
for (int i = 0; i < mHeight; i++) {
|
||||||
|
Read(row_stride, size, 1);
|
||||||
|
for (int j = 0; j < mWidth; j++) {
|
||||||
|
bit = (j % 8) + 1;
|
||||||
|
byte = row_stride[j / 8];
|
||||||
|
index = byte >> (8 - bit);
|
||||||
|
index &= bitmask;
|
||||||
|
*p = palette[index].red; p++;
|
||||||
|
*p = palette[index].green; p++;
|
||||||
|
*p = palette[index].blue; p++;
|
||||||
|
*p = 0xFF; p++;
|
||||||
|
}
|
||||||
|
if (size % 4 != 0)
|
||||||
|
mReadPos += 4 - (size % 4);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BMPData::ReadData()
|
||||||
|
{
|
||||||
|
int16_t magic_number;
|
||||||
|
bmp_file_header_t file_header;
|
||||||
|
bmp_bitmap_info_header_t info_header;
|
||||||
|
bmp_palette_element_t* palette = NULL;
|
||||||
|
|
||||||
|
Read(&magic_number, 2, 1);
|
||||||
|
if (magic_number == BITMAP_MAGIC_NUMBER)
|
||||||
|
{
|
||||||
|
Read((void*)&file_header, 12, 1);
|
||||||
|
Read((void*)&info_header, 40, 1);
|
||||||
|
mReadPos = file_header.offset;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mReadPos = 0;
|
||||||
|
Read((void*)&info_header, 40, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* info_header sanity checks */
|
||||||
|
/* accepted headers : bitmapinfoheader, bitmapv4header, bitmapv5header */
|
||||||
|
if (!(info_header.header_size == 40 || info_header.header_size == 108 || info_header.header_size == 124)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (info_header.num_planes != 1) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (info_header.compression == 4 || info_header.compression == 5) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (info_header.height < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* load palette, if present */
|
||||||
|
if (info_header.bpp <= 8) {
|
||||||
|
mReadPos = 14 + info_header.header_size;
|
||||||
|
if ((info_header.bpp == 1) && (info_header.colors_used == 0)) info_header.colors_used = 2;
|
||||||
|
if ((info_header.bpp == 4) && (info_header.colors_used == 0)) info_header.colors_used = 16;
|
||||||
|
if ((info_header.bpp == 8) && (info_header.colors_used == 0)) info_header.colors_used = 256;
|
||||||
|
palette = (bmp_palette_element_t*)malloc(info_header.colors_used * sizeof(bmp_palette_element_t));
|
||||||
|
if (!palette) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
Read((void*)palette, sizeof(bmp_palette_element_t), info_header.colors_used);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* memory allocation */
|
||||||
|
//buf = malloc(info_header.width * info_header.height * 4);
|
||||||
|
mWidth = info_header.width;
|
||||||
|
mHeight = info_header.height;
|
||||||
|
mBits = new uint32[mWidth * mHeight];
|
||||||
|
|
||||||
|
memset(mBits, 0x00, info_header.width * info_header.height * 4);
|
||||||
|
|
||||||
|
/* load image data */
|
||||||
|
switch (info_header.bpp)
|
||||||
|
{
|
||||||
|
case 32:
|
||||||
|
ReadPixels32();
|
||||||
|
break;
|
||||||
|
case 24:
|
||||||
|
ReadPixels24();
|
||||||
|
break;
|
||||||
|
case 16:
|
||||||
|
ReadPixels16();
|
||||||
|
break;
|
||||||
|
case 8:
|
||||||
|
if (info_header.compression == 1)
|
||||||
|
ReadPixelsRLE8(palette);
|
||||||
|
else
|
||||||
|
ReadPixels8(palette);
|
||||||
|
break;
|
||||||
|
case 4:
|
||||||
|
if (info_header.compression == 2)
|
||||||
|
ReadPixelsRLE4(palette);
|
||||||
|
else
|
||||||
|
ReadPixels4(palette);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
ReadPixels1(palette);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info_header.colors_used) free(palette);
|
||||||
|
|
||||||
|
if (mHasTransFollowing)
|
||||||
|
{
|
||||||
|
mHeight /= 2;
|
||||||
|
auto newBits = new uint32[mWidth * mHeight];
|
||||||
|
memcpy(newBits, mBits + mHeight * mWidth, mWidth * mHeight * 4);
|
||||||
|
delete mBits;
|
||||||
|
mBits = newBits;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool BMPData::WriteToFile(const StringImpl& path)
|
||||||
|
{
|
||||||
|
FILE* file;
|
||||||
|
int16_t magic_number;
|
||||||
|
bmp_file_header_t file_header;
|
||||||
|
bmp_bitmap_info_header_t info_header;
|
||||||
|
unsigned char sample[3], * p;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
file = fopen(path.c_str(), "wb");
|
||||||
|
if (!file)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
magic_number = BITMAP_MAGIC_NUMBER;
|
||||||
|
|
||||||
|
file_header.size = mWidth * mHeight * 4 + 54;
|
||||||
|
file_header.app_id = 0;
|
||||||
|
file_header.offset = 54;
|
||||||
|
|
||||||
|
info_header.header_size = 40;
|
||||||
|
info_header.width = mWidth;
|
||||||
|
info_header.height = mHeight;
|
||||||
|
info_header.num_planes = 1;
|
||||||
|
info_header.bpp = 24;
|
||||||
|
info_header.compression = 0;
|
||||||
|
info_header.image_size = mWidth * mHeight * 4;
|
||||||
|
info_header.horizontal_resolution = 0;
|
||||||
|
info_header.vertical_resolution = 0;
|
||||||
|
info_header.colors_used = 0;
|
||||||
|
info_header.colors_important = 0;
|
||||||
|
|
||||||
|
fwrite(&magic_number, sizeof(magic_number), 1, file);
|
||||||
|
fwrite(&file_header, sizeof(bmp_file_header_t), 1, file);
|
||||||
|
fwrite(&info_header, sizeof(bmp_bitmap_info_header_t), 1, file);
|
||||||
|
|
||||||
|
p = (unsigned char*)mBits;
|
||||||
|
for (i = 0; i < mHeight; i++)
|
||||||
|
{
|
||||||
|
for (j = 0; j < mWidth; j++)
|
||||||
|
{
|
||||||
|
/* convert RGBA to BGR */
|
||||||
|
sample[2] = *p; p++;
|
||||||
|
sample[1] = *p; p++;
|
||||||
|
sample[0] = *p; p++;
|
||||||
|
p++;
|
||||||
|
|
||||||
|
fwrite(sample, 3, 1, file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
41
BeefySysLib/img/BMPData.h
Normal file
41
BeefySysLib/img/BMPData.h
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ImageData.h"
|
||||||
|
|
||||||
|
NS_BF_BEGIN;
|
||||||
|
|
||||||
|
struct bmp_palette_element_s
|
||||||
|
{
|
||||||
|
unsigned char blue;
|
||||||
|
unsigned char green;
|
||||||
|
unsigned char red;
|
||||||
|
unsigned char reserved; /* alpha ? */
|
||||||
|
};
|
||||||
|
typedef struct bmp_palette_element_s bmp_palette_element_t;
|
||||||
|
|
||||||
|
class BMPData : public ImageData
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
int mReadPos;
|
||||||
|
bool mHasTransFollowing;
|
||||||
|
|
||||||
|
int Read(void* ptr, int elemSize, int elemCount);
|
||||||
|
unsigned char ReadC();
|
||||||
|
|
||||||
|
bool ReadPixelsRLE8(bmp_palette_element_t* palette);
|
||||||
|
bool ReadPixelsRLE4(bmp_palette_element_t* palette);
|
||||||
|
bool ReadPixels32();
|
||||||
|
bool ReadPixels24();
|
||||||
|
bool ReadPixels16();
|
||||||
|
bool ReadPixels8(bmp_palette_element_t* palette);
|
||||||
|
bool ReadPixels4(bmp_palette_element_t* palette);
|
||||||
|
bool ReadPixels1(bmp_palette_element_t* palette);
|
||||||
|
|
||||||
|
public:
|
||||||
|
BMPData();
|
||||||
|
|
||||||
|
bool ReadData();
|
||||||
|
bool WriteToFile(const StringImpl& path);
|
||||||
|
};
|
||||||
|
|
||||||
|
NS_BF_END;
|
|
@ -692,6 +692,9 @@ void DXTexture::SetBits(int destX, int destY, int destWidth, int destHeight, int
|
||||||
|
|
||||||
void DXTexture::GetBits(int srcX, int srcY, int srcWidth, int srcHeight, int destPitch, uint32* bits)
|
void DXTexture::GetBits(int srcX, int srcY, int srcWidth, int srcHeight, int destPitch, uint32* bits)
|
||||||
{
|
{
|
||||||
|
if ((srcWidth <= 0) || (srcHeight <= 0))
|
||||||
|
return;
|
||||||
|
|
||||||
D3D11_TEXTURE2D_DESC texDesc;
|
D3D11_TEXTURE2D_DESC texDesc;
|
||||||
texDesc.ArraySize = 1;
|
texDesc.ArraySize = 1;
|
||||||
texDesc.BindFlags = 0;
|
texDesc.BindFlags = 0;
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
#pragma warning disable 168
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
|
@ -9,6 +11,7 @@ using IDE.util;
|
||||||
using Beefy.events;
|
using Beefy.events;
|
||||||
using Beefy.theme;
|
using Beefy.theme;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using Beefy.utils;
|
||||||
|
|
||||||
namespace IDE.ui
|
namespace IDE.ui
|
||||||
{
|
{
|
||||||
|
@ -17,6 +20,7 @@ namespace IDE.ui
|
||||||
class RecentWorkspacesScrollWidget : ScrollableWidget
|
class RecentWorkspacesScrollWidget : ScrollableWidget
|
||||||
{
|
{
|
||||||
public Font mTitleFont;
|
public Font mTitleFont;
|
||||||
|
public bool mHasIcons;
|
||||||
|
|
||||||
public this()
|
public this()
|
||||||
{
|
{
|
||||||
|
@ -31,7 +35,7 @@ namespace IDE.ui
|
||||||
|
|
||||||
public override void Resize(float x, float y, float width, float height)
|
public override void Resize(float x, float y, float width, float height)
|
||||||
{
|
{
|
||||||
const float MARGIN = 3;
|
const float MARGIN = 0;
|
||||||
float currentY = 0;
|
float currentY = 0;
|
||||||
|
|
||||||
float fillWidth = width - (mVertScrollbar?.Width).GetValueOrDefault();
|
float fillWidth = width - (mVertScrollbar?.Width).GetValueOrDefault();
|
||||||
|
@ -40,7 +44,7 @@ namespace IDE.ui
|
||||||
{
|
{
|
||||||
for (let widget in mScrollContent.mChildWidgets)
|
for (let widget in mScrollContent.mChildWidgets)
|
||||||
{
|
{
|
||||||
widget.Resize(0, currentY, fillWidth, GS!(30));
|
widget.Resize(0, currentY, fillWidth, GS!(33));
|
||||||
currentY += widget.Height + MARGIN;
|
currentY += widget.Height + MARGIN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -60,7 +64,7 @@ namespace IDE.ui
|
||||||
g.SetFont(mTitleFont);
|
g.SetFont(mTitleFont);
|
||||||
|
|
||||||
using (g.PushColor(gApp.mSettings.mUISettings.mColors.mText))
|
using (g.PushColor(gApp.mSettings.mUISettings.mColors.mText))
|
||||||
g.DrawString("Recent Workspaces", 0, GS!(-30), .Centered, mWidth, .Ellipsis);
|
g.DrawString("Recent Workspaces", GS!(2), GS!(-30), .Centered, mWidth - GS!(4), .Ellipsis);
|
||||||
|
|
||||||
base.Draw(g);
|
base.Draw(g);
|
||||||
}
|
}
|
||||||
|
@ -70,6 +74,8 @@ namespace IDE.ui
|
||||||
{
|
{
|
||||||
public static Font s_Font;
|
public static Font s_Font;
|
||||||
append String mPath;
|
append String mPath;
|
||||||
|
public bool mTriedLoadIcon;
|
||||||
|
public Image mIcon ~ delete _;
|
||||||
|
|
||||||
public bool mPinned;
|
public bool mPinned;
|
||||||
public RecentWorkspacesScrollWidget mRecentsParent;
|
public RecentWorkspacesScrollWidget mRecentsParent;
|
||||||
|
@ -91,9 +97,67 @@ namespace IDE.ui
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!mTriedLoadIcon)
|
||||||
|
{
|
||||||
|
mTriedLoadIcon = true;
|
||||||
|
|
||||||
|
StructuredData sd = scope .();
|
||||||
|
if (sd.Load(scope $"{mPath}/BeefProj.toml") case .Ok)
|
||||||
|
{
|
||||||
|
using (sd.Open("Platform"))
|
||||||
|
{
|
||||||
|
using (sd.Open("Windows"))
|
||||||
|
{
|
||||||
|
var iconFileName = sd.GetString("IconFile", .. scope .());
|
||||||
|
iconFileName.Replace("$(ProjectDir)", mPath);
|
||||||
|
iconFileName.Replace("$(WorkspaceDir)", mPath);
|
||||||
|
var iconFilePath = IO.Path.GetAbsolutePath(iconFileName, mPath, .. scope .());
|
||||||
|
|
||||||
|
if (File.Exists(iconFilePath))
|
||||||
|
{
|
||||||
|
int wantSize = 32;
|
||||||
|
if (var image = ResourceGen.LoadIcon(iconFilePath, wantSize))
|
||||||
|
{
|
||||||
|
if ((image.mWidth != wantSize) || (image.mHeight != wantSize))
|
||||||
|
{
|
||||||
|
image.Scale(wantSize / Math.Max(image.mWidth, image.mHeight));
|
||||||
|
}
|
||||||
|
mIcon = image;
|
||||||
|
mRecentsParent.mHasIcons = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
g.SetFont(s_Font);
|
g.SetFont(s_Font);
|
||||||
using (g.PushColor(gApp.mSettings.mUISettings.mColors.mText))
|
using (g.PushColor(gApp.mSettings.mUISettings.mColors.mText))
|
||||||
g.DrawString(mPath, 10, 0, .Left, mWidth - 10);
|
{
|
||||||
|
String drawStr = scope String();
|
||||||
|
int lastSlash = Math.Max(mPath.LastIndexOf('\\'), mPath.LastIndexOf('/'));
|
||||||
|
if (lastSlash != -1)
|
||||||
|
{
|
||||||
|
drawStr.Append(Font.EncodeColor(0x80FFFFFF));
|
||||||
|
drawStr.Append(mPath.Substring(0, lastSlash + 1));
|
||||||
|
drawStr.Append(Font.EncodePopColor());
|
||||||
|
drawStr.Append(mPath.Substring(lastSlash + 1));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
drawStr.Append(mPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
float drawX = GS!(50);
|
||||||
|
g.DrawString(drawStr, drawX, GS!(3), .Left, mWidth - drawX - GS!(2), .Ellipsis);
|
||||||
|
}
|
||||||
|
if (mIcon != null)
|
||||||
|
g.DrawCentered(mIcon, GS!(24), mHeight / 2);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
using (g.PushColor(0x80FFFFFF))
|
||||||
|
g.DrawCentered(DarkTheme.sDarkTheme.GetImage(.Workspace), GS!(24), mHeight / 2);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void MouseEnter()
|
public override void MouseEnter()
|
||||||
|
|
|
@ -1,8 +1,12 @@
|
||||||
|
#pragma warning disable 168
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Collections;
|
using System.Collections;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using Beefy.gfx;
|
||||||
|
|
||||||
namespace IDE.util
|
namespace IDE.util
|
||||||
{
|
{
|
||||||
class ResourceGen
|
class ResourceGen
|
||||||
|
@ -62,6 +66,60 @@ namespace IDE.util
|
||||||
|
|
||||||
FileStream mOutStream = new FileStream() ~ delete _;
|
FileStream mOutStream = new FileStream() ~ delete _;
|
||||||
|
|
||||||
|
public static Result<Image> LoadIcon(String iconFile, int wantSize = -1)
|
||||||
|
{
|
||||||
|
FileStream stream = scope FileStream();
|
||||||
|
if (stream.Open(iconFile, .Read) case .Err)
|
||||||
|
{
|
||||||
|
return .Err;
|
||||||
|
}
|
||||||
|
|
||||||
|
let iconDir = Try!(stream.Read<IconDir>());
|
||||||
|
if ((iconDir.mReserved != 0) || (iconDir.mType != 1) || (iconDir.mCount > 0x100))
|
||||||
|
{
|
||||||
|
return .Err;
|
||||||
|
}
|
||||||
|
|
||||||
|
var entries = scope List<IconDirectoryEntry>();
|
||||||
|
|
||||||
|
for (int idx < iconDir.mCount)
|
||||||
|
{
|
||||||
|
entries.Add(Try!(stream.Read<IconDirectoryEntry>()));
|
||||||
|
}
|
||||||
|
|
||||||
|
int bestIdx = iconDir.mCount - 1;
|
||||||
|
for (int idx < iconDir.mCount)
|
||||||
|
{
|
||||||
|
let iconEntry = ref entries[idx];
|
||||||
|
if (iconEntry.mWidth >= wantSize)
|
||||||
|
{
|
||||||
|
bestIdx = idx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let iconEntry = ref entries[bestIdx];
|
||||||
|
|
||||||
|
Try!(stream.Seek(iconEntry.mImageOffset));
|
||||||
|
|
||||||
|
if (iconEntry.mBytesInRes > 1024*1024)
|
||||||
|
{
|
||||||
|
return .Err;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8* data = new:ScopedAlloc! uint8[iconEntry.mBytesInRes]*;
|
||||||
|
|
||||||
|
Try!(stream.TryRead(.(data, iconEntry.mBytesInRes)));
|
||||||
|
|
||||||
|
String bmpPath = scope $"@{(int)(void*)data:X}:{iconEntry.mBytesInRes}.bmp";
|
||||||
|
|
||||||
|
var image = Image.LoadFromFile(bmpPath);
|
||||||
|
if (image != null)
|
||||||
|
return image;
|
||||||
|
|
||||||
|
return .Err;
|
||||||
|
}
|
||||||
|
|
||||||
public Result<void> AddIcon(String iconFile)
|
public Result<void> AddIcon(String iconFile)
|
||||||
{
|
{
|
||||||
if (!iconFile.EndsWith(".ico", .OrdinalIgnoreCase))
|
if (!iconFile.EndsWith(".ico", .OrdinalIgnoreCase))
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue