initial commit
This commit is contained in:
Executable
+426
@@ -0,0 +1,426 @@
|
||||
#include "chatwnd.h"
|
||||
#include <stdbool.h>
|
||||
#include <windows.h>
|
||||
#include "snoctrl.h"
|
||||
#include "../discordtypes.h"
|
||||
#include "../hmap/hashmap.h"
|
||||
#include <libpng18/png.h>
|
||||
#include <wingdi.h>
|
||||
#include "pnghlp.h"
|
||||
ChatWnd *chatwnds = NULL;
|
||||
int chatwndcount = 0;
|
||||
|
||||
HFONT regfont;
|
||||
HFONT boldfont;
|
||||
HFONT h1font;
|
||||
HFONT h2font;
|
||||
HFONT h3font;
|
||||
hmap pfp_map;
|
||||
ChatWnd *GetChatControlDetails(HWND hwnd) {
|
||||
for (int i = 0; i < chatwndcount; i++) {
|
||||
if (chatwnds[i].hWnd == hwnd) {
|
||||
return &chatwnds[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
void ChatView_SetUserPfp(char *path, char *user) {
|
||||
HANDLE f = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (f == INVALID_HANDLE_VALUE) {
|
||||
MessageBoxA(NULL, "Error accessing the path for the pfp set!",
|
||||
"Snow's Controls - ChatView", 0);
|
||||
return;
|
||||
}
|
||||
LARGE_INTEGER size;
|
||||
GetFileSizeEx(f, &size);
|
||||
|
||||
size_t file_size = (size_t)size.QuadPart;
|
||||
|
||||
uint8_t *buf = malloc(file_size);
|
||||
|
||||
DWORD read = 0;
|
||||
|
||||
ReadFile(f, buf, file_size, &read, NULL);
|
||||
|
||||
png_structp png =
|
||||
png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
png_infop info = png_create_info_struct(png);
|
||||
PngBuffer pngbuf = {buf, file_size, 0};
|
||||
|
||||
png_set_read_fn(png, &pngbuf, PngReadBufCB);
|
||||
png_read_info(png, info);
|
||||
|
||||
BITMAPINFO bmi = {0};
|
||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.bmiHeader.biWidth = png_get_image_width(png, info);
|
||||
bmi.bmiHeader.biHeight = -png_get_image_height(png, info); // top-down
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biBitCount = 32;
|
||||
bmi.bmiHeader.biCompression = BI_RGB; // THIS IS RAW - gordon ramsey
|
||||
if (setjmp(png_jmpbuf(png))) {
|
||||
png_destroy_read_struct(&png, &info, NULL);
|
||||
// err
|
||||
MessageBoxA(NULL, "zzzzzzzz", "zzzzzzzzz", 0);
|
||||
}
|
||||
png_set_expand(png);
|
||||
png_set_strip_16(png);
|
||||
png_set_filler(png, 0xFF,
|
||||
PNG_FILLER_AFTER); // ensures RGBA or RGBX cause winblows
|
||||
png_read_update_info(png, info);
|
||||
int width = png_get_image_width(png, info);
|
||||
int height = png_get_image_height(png, info);
|
||||
png_bytep *rows = malloc(height * sizeof(png_bytep));
|
||||
for (int y = 0; y < height; y++)
|
||||
rows[y] = malloc(png_get_rowbytes(png, info));
|
||||
// flat BGRA buffer for GDI
|
||||
uint8_t *fbuf = malloc(width * height * 4);
|
||||
png_read_image(png, rows);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
png_bytep src = rows[y];
|
||||
uint8_t *dst = fbuf + y * width * 4;
|
||||
|
||||
for (int x = 0; x < width; x++) {
|
||||
dst[x * 4 + 0] = src[x * 4 + 2]; // B
|
||||
dst[x * 4 + 1] = src[x * 4 + 1]; // G
|
||||
dst[x * 4 + 2] = src[x * 4 + 0]; // R
|
||||
dst[x * 4 + 3] = src[x * 4 + 3]; // A
|
||||
}
|
||||
}
|
||||
void *gdibuf = NULL;
|
||||
HBITMAP bmp =
|
||||
CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, &gdibuf, NULL, 0);
|
||||
// GDI allocates its own dumbahh buffer so we just memcpy to it
|
||||
memcpy(gdibuf, fbuf, width * height * 4);
|
||||
free(fbuf);
|
||||
HDC memdc = CreateCompatibleDC(NULL);
|
||||
SelectObject(memdc, bmp);
|
||||
|
||||
IntPfpTableItem it;
|
||||
it.key = user;
|
||||
it.bmp = memdc;
|
||||
|
||||
hashmap_set(pfp_map, &it);
|
||||
|
||||
CloseHandle(f);
|
||||
}
|
||||
void InsertChatMessage(DiscordMessage msg, HWND hwnd) {
|
||||
ChatWnd *cwnd = GetChatControlDetails(hwnd);
|
||||
cwnd->uimsgs =
|
||||
realloc(cwnd->uimsgs, (cwnd->uimsgcnt + 1) * sizeof(GUIMessage));
|
||||
cwnd->uimsgs[cwnd->uimsgcnt].msg = msg;
|
||||
cwnd->uimsgs[cwnd->uimsgcnt].vw = hwnd;
|
||||
cwnd->uimsgcnt++;
|
||||
|
||||
InvalidateRect(hwnd, NULL, FALSE);
|
||||
UpdateWindow(hwnd); // forces WM_PAINT now, contentHeight is fresh
|
||||
|
||||
RECT clientRect;
|
||||
GetClientRect(hwnd, &clientRect);
|
||||
int viewHeight = clientRect.bottom - clientRect.top;
|
||||
|
||||
cwnd->scrollOffset = max(0, cwnd->contentHeight - viewHeight);
|
||||
|
||||
SCROLLINFO si = {sizeof(SCROLLINFO)};
|
||||
si.fMask = SIF_POS;
|
||||
si.nPos = cwnd->scrollOffset;
|
||||
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
|
||||
|
||||
InvalidateRect(hwnd, NULL, FALSE); // repaint with correct offset
|
||||
}
|
||||
void ClearChatControl(HWND hwnd) {
|
||||
ChatWnd *cwnd = GetChatControlDetails(hwnd);
|
||||
int count = cwnd->uimsgcnt;
|
||||
cwnd->uimsgcnt = 0;
|
||||
for (int i = 0; i < count; i++) {
|
||||
DiscordMessage hmsg = (DiscordMessage)cwnd->uimsgs[i].msg;
|
||||
free(hmsg.content);
|
||||
free(hmsg.channelID);
|
||||
free(hmsg.id);
|
||||
free(hmsg.author.Username);
|
||||
free(hmsg.author.DisplayName);
|
||||
free(hmsg.author.id);
|
||||
free(hmsg.author.avatar);
|
||||
}
|
||||
cwnd->uimsgs = realloc(cwnd->uimsgs, sizeof(GUIMessage));
|
||||
}
|
||||
LONG MeasureTotalMessageHeight(HWND hwnd) {}
|
||||
static uint64_t pfp_hash(const void *item, uint64_t seed0, uint64_t seed1) {
|
||||
const IntPfpTableItem *e = item;
|
||||
return hashmap_sip(e->key, strlen(e->key), seed0, seed1);
|
||||
}
|
||||
static int pfp_compare(const void *a, const void *b, void *udata) {
|
||||
return strcmp(((IntPfpTableItem *)a)->key, ((IntPfpTableItem *)b)->key);
|
||||
}
|
||||
static void pfp_free(void *pfpitem) {
|
||||
IntPfpTableItem *item = pfpitem;
|
||||
free(item->bmp);
|
||||
free(item->key);
|
||||
}
|
||||
#define UsernameFieldHeight 15
|
||||
#define PfpPadding 6
|
||||
#define YPadding 4
|
||||
#define PfpSize 40
|
||||
#define MinMsgH PfpSize + 10
|
||||
/*
|
||||
| X
|
||||
+------------+--------------------------------------------------------+
|
||||
| |
|
||||
| |
|
||||
-X | |
|
||||
| |
|
||||
| |
|
||||
+------------+
|
||||
|
|
||||
|
||||
|
||||
|
||||
|
||||
*/
|
||||
BOOL IsStartMsg(ChatWnd *cwnd, int i) {
|
||||
if (i > 0) {
|
||||
return (strcmp(cwnd->uimsgs[i].msg.author.id,
|
||||
cwnd->uimsgs[i - 1].msg.author.id) == 0)
|
||||
? FALSE
|
||||
: TRUE;
|
||||
} else {
|
||||
return TRUE;
|
||||
}
|
||||
}
|
||||
BOOL ShouldGoUp(ChatWnd *cwnd, int i) {
|
||||
if (i > 0) {
|
||||
return (IsStartMsg(cwnd, i - 1) && !IsStartMsg(cwnd, i));
|
||||
} else {
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
LRESULT CALLBACK ChatWndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
||||
LPARAM lParam) {
|
||||
switch (uMsg) {
|
||||
case WM_CREATE: {
|
||||
chatwnds = realloc(chatwnds, (chatwndcount + 1) * sizeof(ChatWnd));
|
||||
chatwnds[chatwndcount].hWnd = hwnd;
|
||||
chatwnds[chatwndcount].uimsgcnt = 0;
|
||||
chatwnds[chatwndcount].uimsgs = malloc(sizeof(GUIMessage));
|
||||
chatwnds[chatwndcount].scrollOffset = 0;
|
||||
chatwnds[chatwndcount].contentHeight = 0;
|
||||
chatwnds[chatwndcount].pfpmap = pfp_map =
|
||||
hashmap_new(sizeof(IntPfpTableItem), 256, 0, 0, pfp_hash,
|
||||
pfp_compare, pfp_free, NULL);
|
||||
chatwndcount++;
|
||||
break;
|
||||
}
|
||||
case WM_PAINT: {
|
||||
ChatWnd *cwnd = GetChatControlDetails(hwnd);
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc = BeginPaint(hwnd, &ps);
|
||||
|
||||
RECT clientRect;
|
||||
GetClientRect(hwnd, &clientRect);
|
||||
int viewHeight = clientRect.bottom - clientRect.top;
|
||||
|
||||
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
|
||||
SetStretchBltMode(hdc, HALFTONE);
|
||||
SetBrushOrgEx(hdc, 0, 0, NULL);
|
||||
|
||||
typedef struct {
|
||||
int TextContentHeight;
|
||||
int UnpaddedMessageHeight;
|
||||
int ClampedUnpaddedMessageHeight;
|
||||
int UnclampedTotalMessageHeight;
|
||||
int TotalMessageHeight;
|
||||
int MessageHeightForUse;
|
||||
BOOL StartMsg;
|
||||
BOOL PushBack;
|
||||
} MessageDetails;
|
||||
cwnd->contentHeight = 0;
|
||||
MessageDetails msgdet[cwnd->uimsgcnt];
|
||||
for (int i = 0; i < cwnd->uimsgcnt; i++) {
|
||||
RECT contr = {0, 0, clientRect.right - clientRect.left - 6 - 6 - 40,
|
||||
0};
|
||||
DrawTextA(hdc, cwnd->uimsgs[i].msg.content,
|
||||
strlen(cwnd->uimsgs[i].msg.content), &contr,
|
||||
DT_CALCRECT | DT_WORDBREAK);
|
||||
// printf("%i | %i\n", i, contr.bottom - contr.top);
|
||||
msgdet[i].TextContentHeight = contr.bottom - contr.top;
|
||||
msgdet[i].StartMsg = IsStartMsg(cwnd, i);
|
||||
if (msgdet[i].StartMsg) {
|
||||
|
||||
if (i + 1 < cwnd->uimsgcnt) {
|
||||
if (!IsStartMsg(cwnd, i + 1)) {
|
||||
msgdet[i].PushBack = TRUE;
|
||||
} else {
|
||||
msgdet[i].PushBack = FALSE;
|
||||
}
|
||||
} else {
|
||||
msgdet[i].PushBack = FALSE;
|
||||
}
|
||||
|
||||
if (msgdet[i].PushBack) {
|
||||
|
||||
msgdet[i].UnpaddedMessageHeight =
|
||||
15 + msgdet[i].TextContentHeight;
|
||||
|
||||
msgdet[i].TotalMessageHeight =
|
||||
15 + msgdet[i].TextContentHeight;
|
||||
} else {
|
||||
|
||||
msgdet[i].UnpaddedMessageHeight =
|
||||
max(40, 15 + msgdet[i].TextContentHeight);
|
||||
|
||||
msgdet[i].TotalMessageHeight =
|
||||
max(40, 15 + msgdet[i].TextContentHeight)+6;
|
||||
}
|
||||
|
||||
} else {
|
||||
msgdet[i].TotalMessageHeight = msgdet[i].TextContentHeight ;
|
||||
|
||||
msgdet[i].PushBack = FALSE;
|
||||
}
|
||||
cwnd->contentHeight += msgdet[i].TotalMessageHeight;
|
||||
}
|
||||
|
||||
RECT msgrect;
|
||||
msgrect = clientRect;
|
||||
msgrect.top -= cwnd->scrollOffset;
|
||||
for (int i = 0; i < cwnd->uimsgcnt; i++) {
|
||||
|
||||
if (msgrect.top + msgdet[i].TotalMessageHeight < 0) {
|
||||
msgrect.top += msgdet[i].TotalMessageHeight;
|
||||
continue;
|
||||
}
|
||||
if (msgrect.top > clientRect.bottom) {
|
||||
break;
|
||||
}
|
||||
DiscordMessage msg = cwnd->uimsgs[i].msg;
|
||||
if (msgdet[i].StartMsg) {
|
||||
RECT pfprect = msgrect;
|
||||
pfprect.left += 6;
|
||||
// pfprect.top += 6;
|
||||
pfprect.bottom = pfprect.top + 40;
|
||||
pfprect.right = pfprect.left + 40;
|
||||
|
||||
IntPfpTableItem searchfilters;
|
||||
searchfilters.key = msg.author.id;
|
||||
IntPfpTableItem *pfplookup =
|
||||
hashmap_get(pfp_map, &searchfilters);
|
||||
if (pfplookup) {
|
||||
HBITMAP hBitmap =
|
||||
(HBITMAP)GetCurrentObject(hdc, OBJ_BITMAP);
|
||||
|
||||
BITMAP bmp;
|
||||
GetObject(hBitmap, sizeof(BITMAP), &bmp);
|
||||
|
||||
int width = bmp.bmWidth;
|
||||
int height = bmp.bmHeight;
|
||||
|
||||
BITMAP bmpInfo;
|
||||
HBITMAP hSrcBmp =
|
||||
(HBITMAP)GetCurrentObject(pfplookup->bmp, OBJ_BITMAP);
|
||||
GetObject(hSrcBmp, sizeof(BITMAP), &bmpInfo);
|
||||
|
||||
StretchBlt(hdc, pfprect.left, pfprect.top, 40, 40,
|
||||
pfplookup->bmp, 0, 0, bmpInfo.bmWidth,
|
||||
bmpInfo.bmHeight, SRCCOPY);
|
||||
} else {
|
||||
FillRect(hdc, &pfprect, (HBRUSH)BLACK_BRUSH);
|
||||
}
|
||||
|
||||
RECT usernamerect = msgrect;
|
||||
usernamerect.left += (6 + 40 + 6);
|
||||
// usernamerect.top += 6;
|
||||
char *rndname = cwnd->uimsgs[i].msg.author.DisplayName
|
||||
? cwnd->uimsgs[i].msg.author.DisplayName
|
||||
: cwnd->uimsgs[i].msg.author.Username;
|
||||
SelectObject(hdc, boldfont);
|
||||
DrawTextA(hdc, rndname, strlen(rndname), &usernamerect, 0);
|
||||
RECT contentrect = msgrect;
|
||||
contentrect.left += (6 + 40 + 6);
|
||||
contentrect.top += 15;
|
||||
contentrect.bottom =
|
||||
contentrect.top + msgdet[i].TextContentHeight;
|
||||
SelectObject(hdc, regfont);
|
||||
DrawTextA(hdc, cwnd->uimsgs[i].msg.content,
|
||||
strlen(cwnd->uimsgs[i].msg.content), &contentrect,
|
||||
DT_WORDBREAK);
|
||||
} else {
|
||||
|
||||
RECT contentrect = msgrect;
|
||||
contentrect.left += (6 + 40 + 6);
|
||||
// contentrect.top += 6;
|
||||
contentrect.bottom =
|
||||
contentrect.top + msgdet[i].TextContentHeight;
|
||||
SelectObject(hdc, regfont);
|
||||
DrawTextA(hdc, cwnd->uimsgs[i].msg.content,
|
||||
strlen(cwnd->uimsgs[i].msg.content), &contentrect,
|
||||
DT_WORDBREAK);
|
||||
}
|
||||
msgrect.top += msgdet[i].TotalMessageHeight;
|
||||
}
|
||||
|
||||
/* ── 4. SYNC SCROLL BAR ───────────────────────────────────────────────
|
||||
*/
|
||||
SCROLLINFO si = {sizeof(SCROLLINFO)};
|
||||
si.fMask = SIF_RANGE | SIF_PAGE | SIF_POS;
|
||||
si.nMin = 0;
|
||||
si.nMax = cwnd->contentHeight - 1;
|
||||
si.nPage = viewHeight;
|
||||
si.nPos = cwnd->scrollOffset;
|
||||
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
|
||||
|
||||
EndPaint(hwnd, &ps);
|
||||
break;
|
||||
}
|
||||
case WM_VSCROLL: {
|
||||
ChatWnd *cwnd = GetChatControlDetails(hwnd);
|
||||
RECT clientRect;
|
||||
GetClientRect(hwnd, &clientRect);
|
||||
int viewHeight = clientRect.bottom - clientRect.top;
|
||||
int maxScroll = max(0, cwnd->contentHeight - viewHeight);
|
||||
|
||||
SCROLLINFO si = {sizeof(SCROLLINFO)};
|
||||
si.fMask = SIF_ALL;
|
||||
GetScrollInfo(hwnd, SB_VERT, &si);
|
||||
|
||||
switch (LOWORD(wParam)) {
|
||||
case SB_LINEUP:
|
||||
cwnd->scrollOffset -= 20;
|
||||
break;
|
||||
case SB_LINEDOWN:
|
||||
cwnd->scrollOffset += 20;
|
||||
break;
|
||||
case SB_PAGEUP:
|
||||
cwnd->scrollOffset -= viewHeight;
|
||||
break;
|
||||
case SB_PAGEDOWN:
|
||||
cwnd->scrollOffset += viewHeight;
|
||||
break;
|
||||
case SB_THUMBTRACK:
|
||||
cwnd->scrollOffset = si.nTrackPos;
|
||||
break;
|
||||
case SB_THUMBPOSITION:
|
||||
cwnd->scrollOffset = si.nPos;
|
||||
break;
|
||||
case SB_TOP:
|
||||
cwnd->scrollOffset = 0;
|
||||
break;
|
||||
case SB_BOTTOM:
|
||||
cwnd->scrollOffset = maxScroll;
|
||||
break;
|
||||
}
|
||||
|
||||
cwnd->scrollOffset = max(0, min(cwnd->scrollOffset, maxScroll));
|
||||
|
||||
si.fMask = SIF_POS;
|
||||
si.nPos = cwnd->scrollOffset;
|
||||
SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
|
||||
|
||||
InvalidateRect(hwnd, NULL, FALSE);
|
||||
break;
|
||||
}
|
||||
case WM_DESTROY:
|
||||
break;
|
||||
}
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
Executable
+30
@@ -0,0 +1,30 @@
|
||||
#pragma once
|
||||
#include <windows.h>
|
||||
#include <wingdi.h>
|
||||
#include "snoctrl.h"
|
||||
#include "../discordtypes.h"
|
||||
#include "../hmap/hashmap.h"
|
||||
typedef struct {
|
||||
DiscordMessage msg;
|
||||
HWND vw;
|
||||
} GUIMessage;
|
||||
typedef struct {
|
||||
GUIMessage* uimsgs;
|
||||
int uimsgcnt;
|
||||
HWND hWnd;
|
||||
int scrollOffset;
|
||||
int contentHeight;
|
||||
hmap pfpmap;
|
||||
} ChatWnd;
|
||||
|
||||
typedef struct{
|
||||
char *key;
|
||||
HDC bmp;
|
||||
} IntPfpTableItem;
|
||||
|
||||
ChatWnd* GetChatControlDetails(HWND hwnd);
|
||||
void InsertChatMessage(DiscordMessage msg, HWND hwnd);
|
||||
void ClearChatControl(HWND hwnd);
|
||||
LRESULT CALLBACK ChatWndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
||||
LPARAM lParam);
|
||||
void ChatView_SetUserPfp(char *path, char *user);
|
||||
Executable
+203
@@ -0,0 +1,203 @@
|
||||
#include "guildwnd.h"
|
||||
#include <libpng18/png.h>
|
||||
#include <stdbool.h>
|
||||
#include "pnghlp.h"
|
||||
#include <windows.h>
|
||||
#include <windowsx.h>
|
||||
#include <wingdi.h>
|
||||
int guildwndcount = 0;
|
||||
GuildWnd *guildwnds = NULL;
|
||||
GuildWnd *GetGuildControlDetails(HWND hwnd) {
|
||||
for (int i = 0; i < guildwndcount; i++) {
|
||||
if (guildwnds[i].hWnd == hwnd) {
|
||||
return &guildwnds[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
void GuildView_InsertGuild(HWND hwnd, GUIGuild gld) {
|
||||
GuildWnd *guildwnd = GetGuildControlDetails(hwnd);
|
||||
guildwnd->uigldcnt++;
|
||||
guildwnd->uiglds =
|
||||
realloc(guildwnd->uiglds, guildwnd->uigldcnt * sizeof(GUIGuild));
|
||||
GUIGuild toins = gld;
|
||||
toins.title = strdup(toins.title);
|
||||
toins.id = strdup(toins.id);
|
||||
guildwnd->uiglds[guildwnd->uigldcnt - 1] = toins;
|
||||
InvalidateRect(hwnd, NULL, TRUE);
|
||||
}
|
||||
|
||||
void GuildView_SetIcon(HWND hwnd, HDC icon, char *id) {
|
||||
GuildWnd *guildwnd = GetGuildControlDetails(hwnd);
|
||||
for (int i = 0; i < guildwnd->uigldcnt; i++) {
|
||||
if (strcmp(guildwnd->uiglds[i].id, id) == 0) {
|
||||
guildwnds->uiglds[i].icon = icon;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
void GuildView_SetMentionCount(HWND hwnd, char *id, int cnt) {
|
||||
GuildWnd *guildwnd = GetGuildControlDetails(hwnd);
|
||||
for (int i = 0; i < guildwnd->uigldcnt; i++) {
|
||||
if (strcmp(guildwnd->uiglds[i].id, id) == 0) {
|
||||
guildwnds->uiglds[i].MentionCount = cnt;
|
||||
break;
|
||||
}
|
||||
}
|
||||
InvalidateRect(hwnd, NULL, FALSE);
|
||||
}
|
||||
void GuildView_SetDMsIcon(HWND hwnd, HDC icon) {
|
||||
GuildWnd *guildwnd = GetGuildControlDetails(hwnd);
|
||||
guildwnds->dmsicon = icon;
|
||||
}
|
||||
|
||||
LRESULT CALLBACK GuildWndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
||||
LPARAM lParam) {
|
||||
switch (uMsg) {
|
||||
case WM_CREATE:
|
||||
guildwndcount++;
|
||||
guildwnds = realloc(guildwnds, guildwndcount * sizeof(GuildWnd));
|
||||
guildwnds[guildwndcount - 1].uigldcnt = 0;
|
||||
guildwnds[guildwndcount - 1].uiglds = NULL;
|
||||
guildwnds[guildwndcount - 1].hWnd = hwnd;
|
||||
guildwnds[guildwndcount - 1].scrollOffset = 0;
|
||||
return 0;
|
||||
break;
|
||||
case WM_PAINT: {
|
||||
RECT ctlrect;
|
||||
GetClientRect(hwnd, &ctlrect);
|
||||
GuildWnd *gwnd = GetGuildControlDetails(hwnd);
|
||||
PAINTSTRUCT ps;
|
||||
HDC hdc = BeginPaint(hwnd, &ps);
|
||||
FillRect(hdc, &ctlrect, (HBRUSH)(COLOR_3DFACE + 1));
|
||||
SetStretchBltMode(hdc, HALFTONE);
|
||||
RECT rc = ctlrect;
|
||||
int ctlw = ctlrect.right - ctlrect.left;
|
||||
int guildsize = ctlw - 16;
|
||||
|
||||
rc.left += 8;
|
||||
rc.right = rc.left + guildsize;
|
||||
rc.top += 8;
|
||||
rc.bottom = rc.top + guildsize;
|
||||
|
||||
if (gwnd->dmsicon) {
|
||||
|
||||
BITMAP bmpInfo;
|
||||
HBITMAP hSrcBmp =
|
||||
(HBITMAP)GetCurrentObject(gwnd->dmsicon, OBJ_BITMAP);
|
||||
GetObject(hSrcBmp, sizeof(BITMAP), &bmpInfo);
|
||||
|
||||
StretchBlt(hdc, rc.left, rc.top, guildsize, guildsize,
|
||||
gwnd->dmsicon, 0, 0, bmpInfo.bmWidth, bmpInfo.bmHeight,
|
||||
SRCCOPY);
|
||||
} else {
|
||||
FillRect(hdc, &rc, (HBRUSH)(COLOR_3DSHADOW + 1));
|
||||
}
|
||||
HPEN hPenDark = CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNSHADOW));
|
||||
HPEN hPenLight =
|
||||
CreatePen(PS_SOLID, 1, GetSysColor(COLOR_BTNHIGHLIGHT));
|
||||
HPEN hOldPen;
|
||||
|
||||
hOldPen = SelectObject(hdc, hPenDark);
|
||||
MoveToEx(hdc, rc.left, rc.top + guildsize + 8, NULL);
|
||||
LineTo(hdc, rc.right, rc.top + guildsize + 8);
|
||||
|
||||
SelectObject(hdc, hPenLight);
|
||||
MoveToEx(hdc, rc.left, rc.top + guildsize + 1 + 8, NULL);
|
||||
LineTo(hdc, rc.right, rc.top + guildsize + 1 + 8);
|
||||
|
||||
SelectObject(hdc, hOldPen);
|
||||
DeleteObject(hPenDark);
|
||||
DeleteObject(hPenLight);
|
||||
|
||||
for (int i = 0; i < gwnd->uigldcnt; i++) {
|
||||
RECT rc = ctlrect;
|
||||
rc.left += 8;
|
||||
rc.right = rc.left + guildsize;
|
||||
rc.top += i * (guildsize + 8) + 8 + guildsize + 10 + 8;
|
||||
rc.bottom = rc.top + guildsize;
|
||||
if (i == gwnd->selIndex) {
|
||||
RECT rcs = rc;
|
||||
rcs.left = ctlrect.left;
|
||||
rcs.right = ctlrect.right;
|
||||
rcs.top -= 4;
|
||||
rcs.bottom += 4;
|
||||
FillRect(hdc, &rcs, (HBRUSH)(COLOR_HIGHLIGHT + 1));
|
||||
}
|
||||
if (gwnd->uiglds[i].icon) {
|
||||
|
||||
BITMAP bmpInfo;
|
||||
HBITMAP hSrcBmp =
|
||||
(HBITMAP)GetCurrentObject(gwnd->uiglds[i].icon, OBJ_BITMAP);
|
||||
GetObject(hSrcBmp, sizeof(BITMAP), &bmpInfo);
|
||||
|
||||
StretchBlt(hdc, rc.left, rc.top, guildsize, guildsize,
|
||||
gwnd->uiglds[i].icon, 0, 0, bmpInfo.bmWidth,
|
||||
bmpInfo.bmHeight, SRCCOPY);
|
||||
} else {
|
||||
FillRect(hdc, &rc, (HBRUSH)(COLOR_3DSHADOW + 1));
|
||||
}
|
||||
if (gwnd->uiglds[i].MentionCount) {
|
||||
HBRUSH indicatorbrush = CreateSolidBrush((COLORREF)0x000000FF);
|
||||
|
||||
RECT rc = ctlrect;
|
||||
rc.left += 8;
|
||||
rc.right = rc.left + guildsize;
|
||||
rc.top += i * (guildsize + 8) + 8 + guildsize + 10 + 8;
|
||||
rc.bottom = rc.top + guildsize;
|
||||
|
||||
rc.top = i * (guildsize + 8) + 8 + guildsize + 10 + 8 + guildsize - 16;
|
||||
rc.left = rc.left + guildsize - 16;
|
||||
FillRect(hdc, &rc, indicatorbrush);
|
||||
char unreadtxt[16];
|
||||
wsprintf(unreadtxt,"%i",gwnd->uiglds[i].MentionCount);
|
||||
DrawText(hdc,unreadtxt,strlen(unreadtxt),&rc,DT_SINGLELINE | DT_CENTER | DT_VCENTER);
|
||||
}
|
||||
}
|
||||
EndPaint(hwnd, &ps);
|
||||
return 0;
|
||||
}
|
||||
case WM_LBUTTONUP: {
|
||||
GuildWnd *gwnd = GetGuildControlDetails(hwnd);
|
||||
RECT ctlrect;
|
||||
GetClientRect(hwnd, &ctlrect);
|
||||
int ctlw = ctlrect.right - ctlrect.left;
|
||||
int guildsize = ctlw - 16;
|
||||
if (GET_Y_LPARAM(lParam) < guildsize + 10 + 8) {
|
||||
if (gwnd->selIndex != 1) {
|
||||
gwnd->selIndex = -1;
|
||||
|
||||
NMGUILDVIEW nm = {0};
|
||||
nm.hdr.hwndFrom = hwnd;
|
||||
nm.hdr.idFrom = GetDlgCtrlID(hwnd);
|
||||
nm.hdr.code = GVN_ITEMCLICK;
|
||||
nm.index = GUILDVIEW_DMS;
|
||||
nm.guild = (GUIGuild){NULL};
|
||||
nm.pt = (POINT){GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
|
||||
|
||||
SendMessage(GetParent(hwnd), WM_NOTIFY, (WPARAM)nm.hdr.idFrom,
|
||||
(LPARAM)&nm);
|
||||
InvalidateRect(hwnd, NULL, FALSE);
|
||||
}
|
||||
} else {
|
||||
int index = (GET_Y_LPARAM(lParam) - 8 - guildsize - 10 - 8) /
|
||||
(guildsize + 8);
|
||||
if (index != gwnd->selIndex) {
|
||||
NMGUILDVIEW nm = {0};
|
||||
nm.hdr.hwndFrom = hwnd;
|
||||
nm.hdr.idFrom = GetDlgCtrlID(hwnd);
|
||||
nm.hdr.code = GVN_ITEMCLICK;
|
||||
nm.index = index;
|
||||
nm.guild = gwnd->uiglds[index];
|
||||
nm.pt = (POINT){GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam)};
|
||||
gwnd->selIndex = index;
|
||||
SendMessage(GetParent(hwnd), WM_NOTIFY, (WPARAM)nm.hdr.idFrom,
|
||||
(LPARAM)&nm);
|
||||
InvalidateRect(hwnd, NULL, FALSE);
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, uMsg, wParam, lParam);
|
||||
}
|
||||
Executable
+37
@@ -0,0 +1,37 @@
|
||||
#include <windows.h>
|
||||
#include "../hmap/hashmap.h"
|
||||
|
||||
#define GVN_ITEMCLICK (0U - 1800U)
|
||||
#define GUILDVIEW_MAGIC 0xACC0
|
||||
#define GUILDVIEW_DMS -1
|
||||
typedef struct {
|
||||
char *title;
|
||||
char *id;
|
||||
HDC icon;
|
||||
int MentionCount;
|
||||
void* data;
|
||||
} GUIGuild;
|
||||
typedef struct {
|
||||
NMHDR hdr;
|
||||
int index;
|
||||
GUIGuild guild;
|
||||
POINT pt;
|
||||
} NMGUILDVIEW;
|
||||
typedef NMGUILDVIEW* LPNMGUILDVIEW;
|
||||
typedef struct {
|
||||
GUIGuild* uiglds;
|
||||
int uigldcnt;
|
||||
HWND hWnd;
|
||||
int scrollOffset;
|
||||
int contentHeight;
|
||||
HDC dmsicon;
|
||||
int selIndex;
|
||||
} GuildWnd;
|
||||
|
||||
LRESULT CALLBACK GuildWndProc(HWND hwnd, UINT uMsg, WPARAM wParam,
|
||||
LPARAM lParam);
|
||||
|
||||
void GuildView_InsertGuild(HWND hwnd, GUIGuild gld);
|
||||
void GuildView_SetIcon(HWND hwnd, HDC icon, char *id);
|
||||
void GuildView_SetDMsIcon(HWND hwnd, HDC icon);
|
||||
void GuildView_SetMentionCount(HWND hwnd, char *id, int cnt);
|
||||
Executable
+36
@@ -0,0 +1,36 @@
|
||||
#include <windows.h>
|
||||
#include "snoctrl.h"
|
||||
void InitSnowsControls() {
|
||||
|
||||
NONCLIENTMETRICS ncm = { sizeof(NONCLIENTMETRICS) };
|
||||
SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(ncm), &ncm, 0);
|
||||
regfont=CreateFontIndirect(&ncm.lfMessageFont);
|
||||
ncm.lfMessageFont.lfWeight=FW_BOLD;
|
||||
boldfont=CreateFontIndirect(&ncm.lfMessageFont);
|
||||
ncm.lfMessageFont.lfHeight=-32;
|
||||
h1font=CreateFontIndirect(&ncm.lfMessageFont);
|
||||
ncm.lfMessageFont.lfHeight=-24;
|
||||
h2font=CreateFontIndirect(&ncm.lfMessageFont);
|
||||
h3font = boldfont;
|
||||
|
||||
const char CLASS_NAME_CHAT[] = "BackcordChat";
|
||||
|
||||
WNDCLASS wcc = {};
|
||||
|
||||
wcc.lpfnWndProc = ChatWndProc;
|
||||
wcc.hInstance = GetModuleHandle(NULL);
|
||||
wcc.lpszClassName = CLASS_NAME_CHAT;
|
||||
wcc.hCursor = LoadCursorA(NULL, IDC_ARROW);
|
||||
RegisterClass(&wcc);
|
||||
|
||||
const char CLASS_NAME_GUILD[] = "BackcordGuild";
|
||||
|
||||
WNDCLASS wcg = {};
|
||||
|
||||
wcg.lpfnWndProc = GuildWndProc;
|
||||
wcg.hInstance = GetModuleHandle(NULL);
|
||||
wcg.lpszClassName = CLASS_NAME_GUILD;
|
||||
wcg.hCursor = LoadCursorA(NULL, IDC_ARROW);
|
||||
RegisterClass(&wcg);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,275 @@
|
||||
#include "pnghlp.h"
|
||||
#include <libloaderapi.h>
|
||||
#include <string.h>
|
||||
#include <windows.h>
|
||||
void PngReadBufCB(png_structp png, png_bytep out, png_size_t length) {
|
||||
PngBuffer *buf = png_get_io_ptr(png);
|
||||
memcpy(out, buf->data + buf->pos, length);
|
||||
buf->pos += length;
|
||||
}
|
||||
HDC LoadPNGImage(char *path) {
|
||||
HANDLE f = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (f == INVALID_HANDLE_VALUE) {
|
||||
MessageBoxA(NULL, "Error accessing the path!", "PNG Helper", 0);
|
||||
return NULL;
|
||||
}
|
||||
LARGE_INTEGER size;
|
||||
GetFileSizeEx(f, &size);
|
||||
|
||||
size_t file_size = (size_t)size.QuadPart;
|
||||
|
||||
uint8_t *buf = malloc(file_size);
|
||||
|
||||
DWORD read = 0;
|
||||
|
||||
ReadFile(f, buf, file_size, &read, NULL);
|
||||
|
||||
png_structp png =
|
||||
png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
png_infop info = png_create_info_struct(png);
|
||||
PngBuffer pngbuf = {buf, file_size, 0};
|
||||
|
||||
png_set_read_fn(png, &pngbuf, PngReadBufCB);
|
||||
png_read_info(png, info);
|
||||
|
||||
BITMAPINFO bmi = {0};
|
||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.bmiHeader.biWidth = png_get_image_width(png, info);
|
||||
bmi.bmiHeader.biHeight = -png_get_image_height(png, info); // top-down
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biBitCount = 32;
|
||||
bmi.bmiHeader.biCompression = BI_RGB; // THIS IS RAW - gordon ramsey
|
||||
if (setjmp(png_jmpbuf(png))) {
|
||||
png_destroy_read_struct(&png, &info, NULL);
|
||||
// err
|
||||
MessageBoxA(NULL, "zzzzzzzz", "zzzzzzzzz", 0);
|
||||
return NULL;
|
||||
}
|
||||
png_set_expand(png);
|
||||
png_set_strip_16(png);
|
||||
png_set_filler(png, 0xFF,
|
||||
PNG_FILLER_AFTER); // ensures RGBA or RGBX cause winblows
|
||||
png_read_update_info(png, info);
|
||||
int width = png_get_image_width(png, info);
|
||||
int height = png_get_image_height(png, info);
|
||||
png_bytep *rows = malloc(height * sizeof(png_bytep));
|
||||
for (int y = 0; y < height; y++)
|
||||
rows[y] = malloc(png_get_rowbytes(png, info));
|
||||
// flat BGRA buffer for GDI
|
||||
uint8_t *fbuf = malloc(width * height * 4);
|
||||
png_read_image(png, rows);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
png_bytep src = rows[y];
|
||||
uint8_t *dst = fbuf + y * width * 4;
|
||||
|
||||
for (int x = 0; x < width; x++) {
|
||||
dst[x * 4 + 0] = src[x * 4 + 2]; // B
|
||||
dst[x * 4 + 1] = src[x * 4 + 1]; // G
|
||||
dst[x * 4 + 2] = src[x * 4 + 0]; // R
|
||||
dst[x * 4 + 3] = src[x * 4 + 3]; // A
|
||||
}
|
||||
}
|
||||
void *gdibuf = NULL;
|
||||
HBITMAP bmp =
|
||||
CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, &gdibuf, NULL, 0);
|
||||
// GDI allocates its own dumbahh buffer so we just memcpy to it
|
||||
memcpy(gdibuf, fbuf, width * height * 4);
|
||||
free(fbuf);
|
||||
HDC memdc = CreateCompatibleDC(NULL);
|
||||
SelectObject(memdc, bmp);
|
||||
CloseHandle(f);
|
||||
return memdc;
|
||||
}
|
||||
HBITMAP LoadPNGBitmap(char *path) {
|
||||
HANDLE f = CreateFileA(path, GENERIC_READ, FILE_SHARE_READ, NULL,
|
||||
OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
|
||||
if (f == INVALID_HANDLE_VALUE) {
|
||||
MessageBoxA(NULL, "Error accessing the path!", "PNG Helper", 0);
|
||||
return NULL;
|
||||
}
|
||||
LARGE_INTEGER size;
|
||||
GetFileSizeEx(f, &size);
|
||||
|
||||
size_t file_size = (size_t)size.QuadPart;
|
||||
|
||||
uint8_t *buf = malloc(file_size);
|
||||
|
||||
DWORD read = 0;
|
||||
|
||||
ReadFile(f, buf, file_size, &read, NULL);
|
||||
|
||||
png_structp png =
|
||||
png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
png_infop info = png_create_info_struct(png);
|
||||
PngBuffer pngbuf = {buf, file_size, 0};
|
||||
|
||||
png_set_read_fn(png, &pngbuf, PngReadBufCB);
|
||||
png_read_info(png, info);
|
||||
|
||||
BITMAPINFO bmi = {0};
|
||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.bmiHeader.biWidth = png_get_image_width(png, info);
|
||||
bmi.bmiHeader.biHeight = -png_get_image_height(png, info); // top-down
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biBitCount = 32;
|
||||
bmi.bmiHeader.biCompression = BI_RGB; // THIS IS RAW - gordon ramsey
|
||||
if (setjmp(png_jmpbuf(png))) {
|
||||
png_destroy_read_struct(&png, &info, NULL);
|
||||
// err
|
||||
MessageBoxA(NULL, "zzzzzzzz", "zzzzzzzzz", 0);
|
||||
return NULL;
|
||||
}
|
||||
png_set_expand(png);
|
||||
png_set_strip_16(png);
|
||||
png_set_filler(png, 0xFF,
|
||||
PNG_FILLER_AFTER); // ensures RGBA or RGBX cause winblows
|
||||
png_read_update_info(png, info);
|
||||
int width = png_get_image_width(png, info);
|
||||
int height = png_get_image_height(png, info);
|
||||
png_bytep *rows = malloc(height * sizeof(png_bytep));
|
||||
for (int y = 0; y < height; y++)
|
||||
rows[y] = malloc(png_get_rowbytes(png, info));
|
||||
// flat BGRA buffer for GDI
|
||||
uint8_t *fbuf = malloc(width * height * 4);
|
||||
png_read_image(png, rows);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
png_bytep src = rows[y];
|
||||
uint8_t *dst = fbuf + y * width * 4;
|
||||
|
||||
for (int x = 0; x < width; x++) {
|
||||
dst[x * 4 + 0] = src[x * 4 + 2]; // B
|
||||
dst[x * 4 + 1] = src[x * 4 + 1]; // G
|
||||
dst[x * 4 + 2] = src[x * 4 + 0]; // R
|
||||
dst[x * 4 + 3] = src[x * 4 + 3]; // A
|
||||
}
|
||||
}
|
||||
void *gdibuf = NULL;
|
||||
HBITMAP bmp =
|
||||
CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, &gdibuf, NULL, 0);
|
||||
// GDI allocates its own dumbahh buffer so we just memcpy to it
|
||||
memcpy(gdibuf, fbuf, width * height * 4);
|
||||
free(fbuf);
|
||||
return bmp;
|
||||
}
|
||||
HDC LoadPNGImageFromBytes(char *bytes, int buflen) {
|
||||
png_structp png =
|
||||
png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
png_infop info = png_create_info_struct(png);
|
||||
PngBuffer pngbuf = {bytes, buflen, 0};
|
||||
|
||||
png_set_read_fn(png, &pngbuf, PngReadBufCB);
|
||||
png_read_info(png, info);
|
||||
|
||||
BITMAPINFO bmi = {0};
|
||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.bmiHeader.biWidth = png_get_image_width(png, info);
|
||||
bmi.bmiHeader.biHeight = -png_get_image_height(png, info); // top-down
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biBitCount = 32;
|
||||
bmi.bmiHeader.biCompression = BI_RGB; // THIS IS RAW - gordon ramsey
|
||||
if (setjmp(png_jmpbuf(png))) {
|
||||
png_destroy_read_struct(&png, &info, NULL);
|
||||
// err
|
||||
MessageBoxA(NULL, "zzzzzzzz", "zzzzzzzzz", 0);
|
||||
return NULL;
|
||||
}
|
||||
png_set_expand(png);
|
||||
png_set_strip_16(png);
|
||||
png_set_filler(png, 0xFF,
|
||||
PNG_FILLER_AFTER); // ensures RGBA or RGBX cause winblows
|
||||
png_read_update_info(png, info);
|
||||
int width = png_get_image_width(png, info);
|
||||
int height = png_get_image_height(png, info);
|
||||
png_bytep *rows = malloc(height * sizeof(png_bytep));
|
||||
for (int y = 0; y < height; y++)
|
||||
rows[y] = malloc(png_get_rowbytes(png, info));
|
||||
// flat BGRA buffer for GDI
|
||||
uint8_t *fbuf = malloc(width * height * 4);
|
||||
png_read_image(png, rows);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
png_bytep src = rows[y];
|
||||
uint8_t *dst = fbuf + y * width * 4;
|
||||
|
||||
for (int x = 0; x < width; x++) {
|
||||
dst[x * 4 + 0] = src[x * 4 + 2]; // B
|
||||
dst[x * 4 + 1] = src[x * 4 + 1]; // G
|
||||
dst[x * 4 + 2] = src[x * 4 + 0]; // R
|
||||
dst[x * 4 + 3] = src[x * 4 + 3]; // A
|
||||
}
|
||||
}
|
||||
void *gdibuf = NULL;
|
||||
HBITMAP bmp =
|
||||
CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, &gdibuf, NULL, 0);
|
||||
// GDI allocates its own dumbahh buffer so we just memcpy to it
|
||||
memcpy(gdibuf, fbuf, width * height * 4);
|
||||
free(fbuf);
|
||||
HDC memdc = CreateCompatibleDC(NULL);
|
||||
SelectObject(memdc, bmp);
|
||||
return memdc;
|
||||
}
|
||||
|
||||
HDC LoadPNGImageFromResource(HMODULE hModule, int res) {
|
||||
HRSRC resf = FindResource(hModule, MAKEINTRESOURCE(res), RT_RCDATA);
|
||||
DWORD len = SizeofResource(hModule, resf);
|
||||
HGLOBAL resl = LoadResource(hModule, resf);
|
||||
void* resbuf = LockResource(resl);
|
||||
png_structp png =
|
||||
png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||
png_infop info = png_create_info_struct(png);
|
||||
PngBuffer pngbuf = {resbuf, len, 0};
|
||||
|
||||
png_set_read_fn(png, &pngbuf, PngReadBufCB);
|
||||
png_read_info(png, info);
|
||||
|
||||
BITMAPINFO bmi = {0};
|
||||
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
|
||||
bmi.bmiHeader.biWidth = png_get_image_width(png, info);
|
||||
bmi.bmiHeader.biHeight = -png_get_image_height(png, info); // top-down
|
||||
bmi.bmiHeader.biPlanes = 1;
|
||||
bmi.bmiHeader.biBitCount = 32;
|
||||
bmi.bmiHeader.biCompression = BI_RGB; // THIS IS RAW - gordon ramsey
|
||||
if (setjmp(png_jmpbuf(png))) {
|
||||
png_destroy_read_struct(&png, &info, NULL);
|
||||
// err
|
||||
MessageBoxA(NULL, "zzzzzzzz", "zzzzzzzzz", 0);
|
||||
return NULL;
|
||||
}
|
||||
png_set_expand(png);
|
||||
png_set_strip_16(png);
|
||||
png_set_filler(png, 0xFF,
|
||||
PNG_FILLER_AFTER); // ensures RGBA or RGBX cause winblows
|
||||
png_read_update_info(png, info);
|
||||
int width = png_get_image_width(png, info);
|
||||
int height = png_get_image_height(png, info);
|
||||
png_bytep *rows = malloc(height * sizeof(png_bytep));
|
||||
for (int y = 0; y < height; y++)
|
||||
rows[y] = malloc(png_get_rowbytes(png, info));
|
||||
// flat BGRA buffer for GDI
|
||||
uint8_t *fbuf = malloc(width * height * 4);
|
||||
png_read_image(png, rows);
|
||||
|
||||
for (int y = 0; y < height; y++) {
|
||||
png_bytep src = rows[y];
|
||||
uint8_t *dst = fbuf + y * width * 4;
|
||||
|
||||
for (int x = 0; x < width; x++) {
|
||||
dst[x * 4 + 0] = src[x * 4 + 2]; // B
|
||||
dst[x * 4 + 1] = src[x * 4 + 1]; // G
|
||||
dst[x * 4 + 2] = src[x * 4 + 0]; // R
|
||||
dst[x * 4 + 3] = src[x * 4 + 3]; // A
|
||||
}
|
||||
}
|
||||
void *gdibuf = NULL;
|
||||
HBITMAP bmp =
|
||||
CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, &gdibuf, NULL, 0);
|
||||
// GDI allocates its own dumbahh buffer so we just memcpy to it
|
||||
memcpy(gdibuf, fbuf, width * height * 4);
|
||||
free(fbuf);
|
||||
HDC memdc = CreateCompatibleDC(NULL);
|
||||
SelectObject(memdc, bmp);
|
||||
return memdc;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
#include <libpng18/png.h>
|
||||
#include <stdint.h>
|
||||
#include <windows.h>
|
||||
typedef struct {
|
||||
const uint8_t *data;
|
||||
size_t size;
|
||||
size_t pos;
|
||||
} PngBuffer;
|
||||
void PngReadBufCB(png_structp png, png_bytep out, png_size_t length);
|
||||
HDC LoadPNGImage(char *path);
|
||||
HDC LoadPNGImageFromBytes(char *bytes, int buflen);
|
||||
HDC LoadPNGImageFromResource(HMODULE hModule, int res);
|
||||
HBITMAP LoadPNGBitmap(char *path);
|
||||
Executable
+11
@@ -0,0 +1,11 @@
|
||||
#pragma once
|
||||
#include "chatwnd.h"
|
||||
#include "guildwnd.h"
|
||||
|
||||
extern HFONT regfont;
|
||||
extern HFONT boldfont;
|
||||
extern HFONT h1font;
|
||||
extern HFONT h2font;
|
||||
extern HFONT h3font;
|
||||
|
||||
void InitSnowsControls();
|
||||
Reference in New Issue
Block a user