mirror of
https://github.com/Team-Resurgent/PrometheOS-Launcher.git
synced 2026-08-15 11:18:38 -07:00
730 lines
20 KiB
C++
730 lines
20 KiB
C++
#include "drawing.h"
|
|
#include "context.h"
|
|
#include "math.h"
|
|
#include "utils.h"
|
|
#include "meshUtility.h"
|
|
#include "stringUtility.h"
|
|
#include "theme.h"
|
|
#include "pointerMap.h"
|
|
|
|
#include <xgraphics.h>
|
|
|
|
#define SSFN_IMPLEMENTATION
|
|
#define SFFN_MAXLINES 8192
|
|
#define SSFN_memcmp memcmp
|
|
#define SSFN_memset memset
|
|
#define SSFN_realloc realloc
|
|
#define SSFN_free free
|
|
#include "ssfn.h"
|
|
|
|
#define STB_IMAGE_IMPLEMENTATION
|
|
#define STBI_ASSERT(x)
|
|
#include "stb_image.h"
|
|
|
|
#define STB_IMAGE_WRITE_IMPLEMENTATION
|
|
#include "stb_image_write.h"
|
|
|
|
namespace
|
|
{
|
|
ssfn_t* mFontContext = NULL;
|
|
//ssfn_buf_t* mFontBuffer = NULL;
|
|
|
|
//SSFN::Font* mFont = NULL;
|
|
}
|
|
|
|
inline unsigned char lerp(unsigned char a, unsigned char b, float t)
|
|
{
|
|
return (unsigned char)(a + t * (b - a));
|
|
}
|
|
|
|
inline int length(int a, int b)
|
|
{
|
|
return (a * a) + (b * b);
|
|
}
|
|
|
|
void drawing::swizzle(const void *src, const uint32_t& depth, const uint32_t& width, const uint32_t& height, void *dest)
|
|
{
|
|
for (UINT y = 0; y < height; y++)
|
|
{
|
|
UINT sy = 0;
|
|
if (y < width)
|
|
{
|
|
for (int bit = 0; bit < 16; bit++)
|
|
sy |= ((y >> bit) & 1) << (2*bit);
|
|
sy <<= 1; // y counts twice
|
|
}
|
|
else
|
|
{
|
|
UINT y_mask = y % width;
|
|
for (int bit = 0; bit < 16; bit++)
|
|
sy |= ((y_mask >> bit) & 1) << (2*bit);
|
|
sy <<= 1; // y counts twice
|
|
sy += (y / width) * width * width;
|
|
}
|
|
BYTE *s = (BYTE *)src + y * width * depth;
|
|
for (UINT x = 0; x < width; x++)
|
|
{
|
|
UINT sx = 0;
|
|
if (x < height * 2)
|
|
{
|
|
for (int bit = 0; bit < 16; bit++)
|
|
sx |= ((x >> bit) & 1) << (2*bit);
|
|
}
|
|
else
|
|
{
|
|
int x_mask = x % (2*height);
|
|
for (int bit = 0; bit < 16; bit++)
|
|
sx |= ((x_mask >> bit) & 1) << (2*bit);
|
|
sx += (x / (2 * height)) * 2 * height * height;
|
|
}
|
|
BYTE *d = (BYTE *)dest + (sx + sy)*depth;
|
|
for (unsigned int i = 0; i < depth; ++i)
|
|
*d++ = *s++;
|
|
}
|
|
}
|
|
}
|
|
|
|
//uint8_t* pixels = imageData;
|
|
//for (int i = 0; i < width * height * 4; i+=4)
|
|
//{
|
|
// // swap bgra to rgba
|
|
// unsigned char temp = pixels[i + 0];
|
|
// pixels[i + 0] = pixels[i + 2];
|
|
// pixels[i + 2] = temp;
|
|
//}
|
|
|
|
image* drawing::createImage(uint8_t* imageData, D3DFORMAT format, int width, int height)
|
|
{
|
|
image* imageToAdd = new image();
|
|
imageToAdd->width = width;
|
|
imageToAdd->height = height;
|
|
|
|
if (FAILED(D3DXCreateTexture(context::getD3dDevice(), imageToAdd->width, imageToAdd->height, 1, 0, format, D3DPOOL_DEFAULT, &imageToAdd->texture)))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
D3DSURFACE_DESC surfaceDesc;
|
|
imageToAdd->texture->GetLevelDesc(0, &surfaceDesc);
|
|
|
|
imageToAdd->uvRect = math::rectF(0, 0, imageToAdd->width / (float)surfaceDesc.Width, imageToAdd->height / (float)surfaceDesc.Height);
|
|
|
|
D3DLOCKED_RECT lockedRect;
|
|
if (SUCCEEDED(imageToAdd->texture->LockRect(0, &lockedRect, NULL, 0)))
|
|
{
|
|
uint8_t* tempBuffer = (uint8_t*)malloc(surfaceDesc.Size);
|
|
memset(tempBuffer, 0, surfaceDesc.Size);
|
|
uint8_t* src = imageData;
|
|
uint8_t* dst = tempBuffer;
|
|
for (int32_t y = 0; y < imageToAdd->height; y++)
|
|
{
|
|
memcpy(dst, src, imageToAdd->width * 4);
|
|
src += imageToAdd->width * 4;
|
|
dst += surfaceDesc.Width * 4;
|
|
}
|
|
swizzle(tempBuffer, 4, surfaceDesc.Width, surfaceDesc.Height, lockedRect.pBits);
|
|
free(tempBuffer);
|
|
imageToAdd->texture->UnlockRect(0);
|
|
}
|
|
|
|
return imageToAdd;
|
|
}
|
|
|
|
void drawing::addImage(const char* key, uint8_t* imageData, D3DFORMAT format, int width, int height)
|
|
{
|
|
image* imageToAdd = createImage(imageData, format, width, height);
|
|
context::getImageMap()->add(key, imageToAdd);
|
|
}
|
|
|
|
uint64_t drawing::getImageMemUse(const char* key)
|
|
{
|
|
image* imageInfo = context::getImageMap()->get(key);
|
|
if (imageInfo == NULL)
|
|
{
|
|
return 0;
|
|
}
|
|
return utils::roundUpToNextPowerOf2(imageInfo->width) * utils::roundUpToNextPowerOf2(imageInfo->height) * 4;
|
|
}
|
|
|
|
void drawing::removeImage(const char* key)
|
|
{
|
|
image* imageToRemove = context::getImageMap()->get(key);
|
|
if (imageToRemove != NULL)
|
|
{
|
|
context::getImageMap()->removeKey(key);
|
|
}
|
|
}
|
|
|
|
bool drawing::loadImage(const char* buffer, uint32_t length, const char* key)
|
|
{
|
|
int width;
|
|
int height;
|
|
uint8_t* imageData = (uint8_t*)stbi_load_from_memory((const stbi_uc*)buffer, length, &width, &height, NULL, STBI_rgb_alpha);
|
|
if (imageData == NULL)
|
|
{
|
|
return false;
|
|
}
|
|
addImage(key, imageData, D3DFMT_A8B8G8R8, width, height);
|
|
free(imageData);
|
|
return true;
|
|
}
|
|
|
|
bool drawing::loadFont(const uint8_t* data)
|
|
{
|
|
if (mFontContext == NULL)
|
|
{
|
|
mFontContext = (ssfn_t*)malloc(sizeof(ssfn_t));
|
|
memset(mFontContext, 0, sizeof(ssfn_t));
|
|
}
|
|
|
|
int result = ssfn_load(mFontContext, data);
|
|
return result == 0;
|
|
}
|
|
|
|
void drawing::clearBackground(uint32_t index)
|
|
{
|
|
char* backgroundName = stringUtility::formatString("background:%i", index);
|
|
|
|
uint32_t backgroundColor = theme::getBackgroundColor();
|
|
context::getD3dDevice()->Clear(0L, NULL, D3DCLEAR_TARGET|D3DCLEAR_ZBUFFER|D3DCLEAR_STENCIL, (0xff << 24) | backgroundColor, 1.0f, 0L);
|
|
|
|
for (int i = 0; i < 2; i++)
|
|
{
|
|
int index = theme::getBackgroundOverlayAsUnderlay() == true ? (1 - i) : i;
|
|
if (index == 0 && imageExists(backgroundName) == true)
|
|
{
|
|
drawImage(backgroundName, theme::getBackgroundImageTint(), 0, 0, context::getBufferWidth(), context::getBufferHeight());
|
|
}
|
|
if (index == 1 && imageExists("background-overlay") == true)
|
|
{
|
|
drawImage("background-overlay", theme::getBackgroundOverlayImageTint(), 0, 0, context::getBufferWidth(), context::getBufferHeight());
|
|
}
|
|
}
|
|
|
|
free(backgroundName);
|
|
}
|
|
|
|
bool drawing::imageExists(const char* key)
|
|
{
|
|
image* result = context::getImageMap()->get(key);
|
|
return result != NULL;
|
|
}
|
|
|
|
image* drawing::getImage(const char* key)
|
|
{
|
|
image* result = context::getImageMap()->get(key);
|
|
return result;
|
|
}
|
|
|
|
void drawing::setTint(unsigned int color)
|
|
{
|
|
context::getD3dDevice()->SetRenderState(D3DRS_TEXTUREFACTOR, color);
|
|
}
|
|
|
|
void drawing::drawImage(image* image, uint32_t tint, int x, int y, int width, int height)
|
|
{
|
|
if (image == NULL)
|
|
{
|
|
return;
|
|
|
|
}
|
|
context::getD3dDevice()->SetRenderState(D3DRS_TEXTUREFACTOR, tint);
|
|
float newY = (float)context::getBufferHeight() - (y + height);
|
|
context::getD3dDevice()->SetTexture(0, image->texture);
|
|
utils::dataContainer* vertices = meshUtility::createQuadXY(math::vec3F((float)x - 0.5f, newY - 0.5f, 0), math::sizeF((float)width, (float)height), image->uvRect);
|
|
context::getD3dDevice()->DrawPrimitiveUP(D3DPT_TRIANGLELIST, (vertices->size / sizeof(meshUtility::vertex)) / 3, vertices->data, sizeof(meshUtility::vertex));
|
|
delete(vertices);
|
|
}
|
|
|
|
void drawing::drawImage(image* image, uint32_t tint, int x, int y)
|
|
{
|
|
if (image == NULL)
|
|
{
|
|
return;
|
|
|
|
}
|
|
drawImage(image, tint, x, y, image->width, image->height);
|
|
}
|
|
|
|
void drawing::drawImage(const char* imageKey, uint32_t tint, int x, int y, int width, int height)
|
|
{
|
|
image* imageToDraw = getImage(imageKey);
|
|
if (imageToDraw == NULL)
|
|
{
|
|
return;
|
|
}
|
|
drawImage(imageToDraw, tint, x, y, width, height);
|
|
}
|
|
|
|
void drawing::drawImage(const char* imageKey, uint32_t tint, int x, int y)
|
|
{
|
|
image* imageToDraw = getImage(imageKey);
|
|
if (imageToDraw == NULL)
|
|
{
|
|
return;
|
|
}
|
|
drawImage(imageToDraw, tint, x, y);
|
|
}
|
|
|
|
void drawing::drawNinePatch(const char* imageKey, uint32_t tint, int x, int y, int width, int height)
|
|
{
|
|
image* imageToDraw = getImage(imageKey);
|
|
if (imageToDraw == NULL)
|
|
{
|
|
return;
|
|
}
|
|
context::getD3dDevice()->SetRenderState(D3DRS_TEXTUREFACTOR, tint);
|
|
float newY = (float)context::getBufferHeight() - (y + height);
|
|
context::getD3dDevice()->SetTexture(0, imageToDraw->texture);
|
|
utils::dataContainer* vertices = meshUtility::createNinePatchXY(math::vec3F((float)x - 0.5f, newY - 0.5f, 0), math::sizeF((float)width, (float)height), imageToDraw->uvRect);
|
|
context::getD3dDevice()->DrawPrimitiveUP(D3DPT_TRIANGLELIST, (vertices->size / sizeof(meshUtility::vertex)) / 3, vertices->data, sizeof(meshUtility::vertex));
|
|
delete(vertices);
|
|
}
|
|
|
|
image* drawing::renderHorizontalLine(const char* cacheKey, unsigned int color, int width, int height)
|
|
{
|
|
if (imageExists(cacheKey) == false)
|
|
{
|
|
uint32_t* imageData = (uint32_t*)malloc(width * height * 4);
|
|
for (int i = 0; i < width * height; i++)
|
|
{
|
|
imageData[i] = color;
|
|
}
|
|
addImage(cacheKey, (uint8_t*)imageData, D3DFMT_A8R8G8B8, width, height);
|
|
free(imageData);
|
|
}
|
|
return getImage(cacheKey);
|
|
}
|
|
|
|
image* drawing::renderRoundedRect(const char* cacheKey, uint32_t width, uint32_t height, uint32_t cornerRadius, uint32_t fillColor, uint32_t strokeColor, uint32_t strokeWidth)
|
|
{
|
|
if (imageExists(cacheKey) == false)
|
|
{
|
|
uint32_t* imageData = (uint32_t*)malloc(width * height * 4);
|
|
|
|
int widthMinus1 = width - 1;
|
|
int heightMinus1 = height - 1;
|
|
for (unsigned int y = 0; y < height; y++)
|
|
{
|
|
float gradient = (float)y / height;
|
|
for (unsigned int x = 0; x < width; x++)
|
|
{
|
|
unsigned int color = 0x00000000;
|
|
|
|
bool isInsideRect = (y >= cornerRadius && y < height - cornerRadius) || (x >= cornerRadius && x < width - cornerRadius);
|
|
int topLeftCornerLength = length(y - cornerRadius, x - cornerRadius);
|
|
int topRightCornerLength = length(y - cornerRadius, x - (widthMinus1 - cornerRadius));
|
|
int bottomLeftCornerLength = length(y - (heightMinus1 - cornerRadius), x - cornerRadius);
|
|
int bottomRightCornerLength = length(y - (heightMinus1 - cornerRadius), x - (widthMinus1 - cornerRadius));
|
|
int cornerRadiusSquared = cornerRadius * cornerRadius;
|
|
|
|
bool isInsideTopLeftCorner = topLeftCornerLength < cornerRadiusSquared;
|
|
bool isInsideTopRightCorner = topRightCornerLength < cornerRadiusSquared;
|
|
bool isInsideBottomLeftCorner = bottomLeftCornerLength < cornerRadiusSquared;
|
|
bool isInsideBottomRightCorner = bottomRightCornerLength < cornerRadiusSquared;
|
|
if (isInsideRect || isInsideTopLeftCorner || isInsideTopRightCorner || isInsideBottomLeftCorner || isInsideBottomRightCorner)
|
|
{
|
|
color = fillColor;
|
|
}
|
|
imageData[(y * width) + x] = color;
|
|
}
|
|
}
|
|
|
|
if (strokeWidth > 0)
|
|
{
|
|
for (uint32_t y = 0; y < height; y++)
|
|
{
|
|
int count = 0;
|
|
for (uint32_t x = 0; x < width; x++)
|
|
{
|
|
uint32_t color = imageData[(y * width) + x];
|
|
if (count == strokeWidth)
|
|
{
|
|
break;
|
|
}
|
|
if (color > 0)
|
|
{
|
|
imageData[(y * width) + x] = strokeColor;
|
|
imageData[(y * width) + (width - 1) - x] = strokeColor;
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
|
|
for (uint32_t x = 0; x < width; x++)
|
|
{
|
|
int count = 0;
|
|
for (uint32_t y = 0; y < height; y++)
|
|
{
|
|
uint32_t color = imageData[(y * width) + x];
|
|
if (count == strokeWidth)
|
|
{
|
|
break;
|
|
}
|
|
if (color > 0)
|
|
{
|
|
imageData[(y * width) + x] = strokeColor;
|
|
imageData[(((height - 1) - y) * width) + x] = strokeColor;
|
|
count++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//stbi_write_jpg("App:\\test.jpg", width, height, 4, imageData, 100);
|
|
addImage(cacheKey, (uint8_t*)imageData, D3DFMT_A8R8G8B8, width, height);
|
|
free(imageData);
|
|
}
|
|
return getImage(cacheKey);
|
|
}
|
|
|
|
void drawing::drawHorizontalLine(uint32_t color, int x, int y, int width, int height)
|
|
{
|
|
char* cacheKey = stringUtility::formatString("drawHorizontalLine-%02x-%02x", width, height);
|
|
image* image = renderHorizontalLine(cacheKey, color, width, height);
|
|
drawImage(image, color, x, y);
|
|
free(cacheKey);
|
|
}
|
|
//
|
|
//void drawing::measureString(const char* fontName, int fontStyle, int fontSize, const char* message, int* width, int* height)
|
|
//{
|
|
// ssfn_select(mFontContext, SSFN_FAMILY_ANY, fontName, fontStyle, fontSize);
|
|
// ssfn_bbox(mFontContext, message, width, height, NULL, NULL);
|
|
//}
|
|
//
|
|
//image* drawing::renderString(const char* cacheKey, Bounds bounds, const char* message, uint32_t color)
|
|
//{
|
|
// if (imageExists(cacheKey) == false)
|
|
// {
|
|
// int ret;
|
|
//
|
|
// uint32_t* imageData = (uint32_t*)malloc(bounds.width * bounds.height * 4);
|
|
// memset(imageData, 0, bounds.width * bounds.height * 4);
|
|
//
|
|
// ssfn_buf_t buffer;
|
|
// memset(&buffer, 0, sizeof(buffer));
|
|
// buffer.ptr = (uint8_t*)imageData;
|
|
// buffer.x = bounds.left;
|
|
// buffer.y = bounds.top;
|
|
// buffer.w = bounds.width;
|
|
// buffer.h = bounds.height;
|
|
// buffer.p = bounds.width * 4;
|
|
// buffer.bg = color;
|
|
// buffer.fg = color;
|
|
//
|
|
// const char *text = message;
|
|
//
|
|
// while((ret = ssfn_render(mFontContext, &buffer, text)) > 0)
|
|
// {
|
|
// text += ret;
|
|
// }
|
|
//
|
|
// addImage(cacheKey, (uint8_t*)imageData, D3DFMT_A8R8G8B8, bounds.width, bounds.height);
|
|
// free(imageData);
|
|
// }
|
|
// return getImage(cacheKey);
|
|
//}
|
|
//
|
|
//void drawing::drawString(const char* fontName, int fontStyle, int fontSize, const char* message, uint32_t color, int x, int y)
|
|
//{
|
|
// ssfn_select(mFontContext, SSFN_FAMILY_ANY, fontName, fontStyle, fontSize);
|
|
//
|
|
// Bounds bounds;
|
|
// ssfn_bbox(mFontContext, message, &bounds.width, &bounds.height, &bounds.left, &bounds.top);
|
|
//
|
|
// char* cacheKey = stringUtility::formatString("drawString-%s-%02x-%02x-%s-%08x-%08x", fontName, fontStyle, fontSize, message, color);
|
|
// image* image = renderString(cacheKey, bounds, message, color);
|
|
// drawImage(image, 0xffffffff, x, y);
|
|
// free(cacheKey);
|
|
//}
|
|
//
|
|
//void drawing::drawStringAligned(const char* fontName, int fontStyle, int fontSize, const char* message, uint32_t color, horizAlignment hAlign, int x, int y, int width)
|
|
//{
|
|
// ssfn_select(mFontContext, SSFN_FAMILY_ANY, fontName, fontStyle, fontSize);
|
|
//
|
|
// int textWidth = 0;
|
|
// measureString(fontName, fontStyle, fontSize, message, &textWidth, NULL);
|
|
//
|
|
// int xPos = x;
|
|
// if (hAlign == horizAlignmentCenter)
|
|
// {
|
|
// xPos = x + ((width - textWidth) / 2);
|
|
// }
|
|
// else if (hAlign == horizAlignmentRight)
|
|
// {
|
|
// xPos = x + (width - textWidth);
|
|
// }
|
|
//
|
|
// drawString(fontName, fontStyle, fontSize, message, color, xPos, y);
|
|
//}
|
|
|
|
bitmapFont* drawing::generateBitmapFont(const char* fontName, int fontStyle, int fontSize, int lineHeight, int spacing, int textureDimension)
|
|
{
|
|
bitmapFont* font = new bitmapFont();
|
|
font->charMap = new pointerMap<math::rectI*>(true);
|
|
|
|
ssfn_select(mFontContext, SSFN_FAMILY_ANY, fontName, fontStyle, fontSize);
|
|
|
|
int textureWidth = textureDimension;
|
|
int textureHeight = textureDimension;
|
|
|
|
uint32_t* imageData = (uint32_t*)malloc(textureWidth * textureHeight * 4);
|
|
memset(imageData, 0, textureWidth * textureHeight * 4);
|
|
|
|
int x = 2;
|
|
int y = 2;
|
|
|
|
char* charsToEncode = " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~\xC2\xA1\xC2\xA2\xC2\xA3\xC2\xA4\xC2\xA5\xC2\xA6\xC2\xA7\xC2\xA8\xC2\xA9\xC2\xAA\xC2\xAB\xC2\xAC\xC2\xAD\xC2\xAE\xC2\xAF\xC2\xB0\xC2\xB1\xC2\xB2\xC2\xB3\xC2\xB4\xC2\xB5\xC2\xB6";
|
|
char* currentCharPos = charsToEncode;
|
|
while(*currentCharPos)
|
|
{
|
|
char* nextCharPos = currentCharPos;
|
|
uint32_t unicode = ssfn_utf8(&nextCharPos);
|
|
|
|
int32_t length = nextCharPos - currentCharPos;
|
|
char* currentChar = (char*)malloc(length + 1);
|
|
memcpy(currentChar, currentCharPos, length);
|
|
currentChar[length] = 0;
|
|
|
|
currentCharPos = nextCharPos;
|
|
|
|
Bounds bounds;
|
|
int ret = ssfn_bbox(mFontContext, currentChar, &bounds.width, &bounds.height, &bounds.left, &bounds.top);
|
|
if (ret != 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
if ((x + bounds.width + 2) > textureWidth)
|
|
{
|
|
x = 2;
|
|
y = y + bounds.height + 2;
|
|
}
|
|
|
|
math::rectI* rect = new math::rectI();
|
|
rect->x = x;
|
|
rect->y = y;
|
|
rect->width = bounds.width;
|
|
rect->height = bounds.height;
|
|
|
|
char* unicodeString = stringUtility::formatString("%i", unicode);
|
|
font->charMap->add(unicodeString, rect);
|
|
free(unicodeString);
|
|
|
|
ssfn_buf_t buffer;
|
|
memset(&buffer, 0, sizeof(buffer));
|
|
buffer.ptr = (uint8_t*)imageData;
|
|
buffer.x = x + bounds.left;
|
|
buffer.y = y + bounds.top;
|
|
buffer.w = textureWidth;
|
|
buffer.h = textureHeight;
|
|
buffer.p = textureWidth * 4;
|
|
buffer.bg = 0xffffffff;
|
|
buffer.fg = 0xffffffff;
|
|
|
|
ssfn_render(mFontContext, &buffer, currentChar);
|
|
|
|
x = x + bounds.width + 2;
|
|
free(currentChar);
|
|
}
|
|
|
|
font->image = createImage((uint8_t*)imageData, D3DFMT_A8R8G8B8, textureWidth, textureHeight);
|
|
font->lineHeight = lineHeight;
|
|
font->spacing = spacing;
|
|
free(imageData);
|
|
|
|
return font;
|
|
}
|
|
|
|
void drawing::measureBitmapString(bitmapFont* font, const char* message, int* width, int* height)
|
|
{
|
|
image* image = font->image;
|
|
|
|
int xPosMax = 0;
|
|
|
|
int xPos = 0;
|
|
int yPos = 0;
|
|
|
|
char* currentCharPos = (char*)message;
|
|
while(*currentCharPos)
|
|
{
|
|
char* nextCharPos = currentCharPos;
|
|
uint32_t unicode = ssfn_utf8(&nextCharPos);
|
|
|
|
int32_t length = nextCharPos - currentCharPos;
|
|
char* currentChar = (char*)malloc(length + 1);
|
|
memcpy(currentChar, currentCharPos, length);
|
|
currentChar[length] = 0;
|
|
|
|
currentCharPos = nextCharPos;
|
|
|
|
if (stringUtility::equals(currentChar, "\n", false) == true)
|
|
{
|
|
xPos = 0;
|
|
yPos += font->lineHeight;
|
|
continue;
|
|
}
|
|
|
|
char* unicodeString = stringUtility::formatString("%i", unicode);
|
|
math::rectI* rect = font->charMap->get(unicodeString);
|
|
free(unicodeString);
|
|
if (rect == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
xPos = xPos + rect->width + font->spacing;
|
|
xPosMax = max(xPosMax, xPos);
|
|
free(currentChar);
|
|
}
|
|
|
|
if (width != NULL)
|
|
{
|
|
*width = xPosMax - 2;
|
|
}
|
|
|
|
if (height != NULL)
|
|
{
|
|
*height = yPos + font->lineHeight;
|
|
}
|
|
}
|
|
|
|
void drawing::drawBitmapString(bitmapFont* font, const char* message, uint32_t color, int x, int y)
|
|
{
|
|
image* image = font->image;
|
|
|
|
int xPos = x;
|
|
int yPos = y;
|
|
|
|
char* currentCharPos = (char*)message;
|
|
while(*currentCharPos)
|
|
{
|
|
char* nextCharPos = currentCharPos;
|
|
uint32_t unicode = ssfn_utf8(&nextCharPos);
|
|
|
|
int32_t length = nextCharPos - currentCharPos;
|
|
char* currentChar = (char*)malloc(length + 1);
|
|
memcpy(currentChar, currentCharPos, length);
|
|
currentChar[length] = 0;
|
|
|
|
currentCharPos = nextCharPos;
|
|
|
|
if (stringUtility::equals(currentChar, "\n", false) == true)
|
|
{
|
|
xPos = x;
|
|
yPos += font->lineHeight;
|
|
continue;
|
|
}
|
|
|
|
char* unicodeString = stringUtility::formatString("%i", unicode);
|
|
math::rectI* rect = font->charMap->get(unicodeString);
|
|
free(unicodeString);
|
|
if (rect == NULL)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
math::rectF uvRect;
|
|
uvRect.x = rect->x / (float)image->width;
|
|
uvRect.y = rect->y / (float)image->height;
|
|
uvRect.width = rect->width / (float)image->width;
|
|
uvRect.height = rect->height / (float)image->height;
|
|
|
|
uint32_t charColor = color;
|
|
if (unicode == 161)
|
|
{
|
|
charColor = theme::getJoyButtonAColor();
|
|
}
|
|
else if (unicode == 162)
|
|
{
|
|
charColor = theme::getJoyButtonBColor();
|
|
}
|
|
else if (unicode == 163)
|
|
{
|
|
charColor = theme::getJoyButtonXColor();
|
|
}
|
|
else if (unicode == 164)
|
|
{
|
|
charColor = theme::getJoyButtonYColor();
|
|
}
|
|
else if (unicode == 182)
|
|
{
|
|
charColor = theme::getJoyButtonBlackColor();
|
|
}
|
|
else if (unicode == 181)
|
|
{
|
|
charColor = theme::getJoyButtonWhiteColor();
|
|
}
|
|
|
|
context::getD3dDevice()->SetRenderState(D3DRS_TEXTUREFACTOR, charColor);
|
|
float newY = (float)context::getBufferHeight() - (yPos + rect->height);
|
|
context::getD3dDevice()->SetTexture(0, image->texture);
|
|
utils::dataContainer* vertices = meshUtility::createQuadXY(math::vec3F((float)xPos - 0.5f, newY - 0.5f, 0), math::sizeF((float)rect->width, (float)rect->height), uvRect);
|
|
context::getD3dDevice()->DrawPrimitiveUP(D3DPT_TRIANGLELIST, (vertices->size / sizeof(meshUtility::vertex)) / 3, vertices->data, sizeof(meshUtility::vertex));
|
|
delete(vertices);
|
|
|
|
xPos = xPos + rect->width + font->spacing;
|
|
free(currentChar);
|
|
}
|
|
}
|
|
|
|
void drawing::drawBitmapStringAligned(bitmapFont* font, const char* message, uint32_t color, horizAlignment hAlign, int x, int y, int width)
|
|
{
|
|
int textWidth = 0;
|
|
measureBitmapString(font, message, &textWidth, NULL);
|
|
|
|
int xPos = x;
|
|
if (hAlign == horizAlignmentCenter)
|
|
{
|
|
xPos = x + ((width - textWidth) / 2);
|
|
}
|
|
else if (hAlign == horizAlignmentRight)
|
|
{
|
|
xPos = x + (width - textWidth);
|
|
}
|
|
|
|
drawBitmapString(font, message, color, xPos, y);
|
|
}
|
|
|
|
utils::dataContainer* drawing::takeScreenshot()
|
|
{
|
|
utils::dataContainer* result = NULL;
|
|
|
|
IDirect3DSurface8* surface;
|
|
context::getD3dDevice()->GetBackBuffer(-1, D3DBACKBUFFER_TYPE_MONO, &surface);
|
|
|
|
D3DLOCKED_RECT lockedRect;
|
|
if (surface->LockRect(&lockedRect, NULL, D3DLOCK_READONLY) >= 0)
|
|
{
|
|
uint8_t* pBits = (uint8_t*)lockedRect.pBits;
|
|
|
|
D3DSURFACE_DESC desc;
|
|
surface->GetDesc(&desc);
|
|
|
|
uint8_t* buffer = (uint8_t*)malloc(desc.Width * desc.Height * 4);
|
|
uint8_t* bufferOffset = buffer;
|
|
|
|
for (uint32_t y = 0; y < desc.Height; ++y) {
|
|
uint8_t* row = pBits + y * lockedRect.Pitch;
|
|
for (uint32_t x = 0; x < desc.Width; ++x) {
|
|
uint8_t* pixel = row + x * 4;
|
|
bufferOffset[0] = pixel[2];
|
|
bufferOffset[1] = pixel[1];
|
|
bufferOffset[2] = pixel[0];
|
|
bufferOffset[3] = 0xff;
|
|
bufferOffset += 4;
|
|
}
|
|
}
|
|
|
|
int fileSize = 0;
|
|
char *pngData = (char*)stbi_write_png_to_mem(buffer, lockedRect.Pitch, desc.Width, desc.Height, 4, &fileSize);
|
|
result = new utils::dataContainer(pngData, fileSize, fileSize);
|
|
free(buffer);
|
|
free(pngData);
|
|
|
|
surface->UnlockRect();
|
|
}
|
|
surface->Release();
|
|
|
|
return result;
|
|
} |