diff --git a/binding/discord-binding.cpp b/binding/discord-binding.cpp index d94a991d..83a88d64 100644 --- a/binding/discord-binding.cpp +++ b/binding/discord-binding.cpp @@ -3,6 +3,7 @@ #include "discordstate.h" #include "sharedstate.h" #include "binding-util.h" +#include "binding-types.h" //NYI void discordResultCb(void *callback_data, enum EDiscordResult result) @@ -44,6 +45,22 @@ RB_METHOD(DiscordGetUserId) return LL2NUM(shState->discord().userId()); } +void bitmapInitProps(Bitmap *b, VALUE self); + +RB_METHOD(DiscordGetUserAvatar) +{ + RB_UNUSED_PARAM; + + Bitmap *result = shState->discord().userAvatar(); + if (!result) return RUBY_Qnil; + + VALUE ret = wrapObject(result, BitmapType); + bitmapInitProps(result, ret); + + return ret; + +} + RB_METHOD(DiscordActivitySend) { RB_UNUSED_PARAM; @@ -236,6 +253,7 @@ void DiscordBindingInit() _rb_define_module_function(mod, "user_name", DiscordGetUsername); _rb_define_module_function(mod, "user_discriminator", DiscordGetDiscriminator); _rb_define_module_function(mod, "user_id", DiscordGetUserId); + _rb_define_module_function(mod, "user_avatar", DiscordGetUserAvatar); VALUE activityClass = rb_define_class_under(mod, "Activity", rb_cObject); #ifndef OLD_RUBY diff --git a/src/bitmap.cpp b/src/bitmap.cpp index 96cd968a..dd907259 100644 --- a/src/bitmap.cpp +++ b/src/bitmap.cpp @@ -307,6 +307,52 @@ Bitmap::Bitmap(int width, int height) clear(); } +Bitmap::Bitmap(void *pixeldata, int width, int height) +{ + SDL_Surface *surface = SDL_CreateRGBSurface(0, width, height, p->format->BitsPerPixel, + p->format->Rmask, + p->format->Gmask, + p->format->Bmask, + p->format->Amask); + + if (!surface) + throw Exception(Exception::SDLError, "Error creating Bitmap: %s", + SDL_GetError()); + + memcpy(surface->pixels, pixeldata, width*height*(p->format->BitsPerPixel/8)); + + if (surface->w > glState.caps.maxTexSize || surface->h > glState.caps.maxTexSize) + { + p = new BitmapPrivate(this); + p->megaSurface = surface; + SDL_SetSurfaceBlendMode(p->megaSurface, SDL_BLENDMODE_NONE); + } + else + { + TEXFBO tex; + + try + { + tex = shState->texPool().request(surface->w, surface->h); + } + catch (const Exception &e) + { + SDL_FreeSurface(surface); + throw e; + } + + p = new BitmapPrivate(this); + p->gl = tex; + + TEX::bind(p->gl.tex); + TEX::uploadImage(p->gl.width, p->gl.height, surface->pixels, GL_RGBA); + + SDL_FreeSurface(surface); + } + + p->addTaintedArea(rect()); +} + Bitmap::Bitmap(const Bitmap &other) { other.ensureNonMega(); @@ -837,6 +883,26 @@ void Bitmap::setPixel(int x, int y, const Color &color) p->onModified(false); } +void Bitmap::replaceRaw(void *pixel_data, int w, int h) +{ + guardDisposed(); + if (w != width() || h != height()) return; + + GUARD_MEGA; + + TEXFBO buf = shState->texPool().request(w, h); + TEX::bind(buf.tex); + TEX::uploadImage(w, h, pixel_data, GL_RGBA); + + GLMeta::blitBegin(p->gl); + GLMeta::blitSource(buf); + GLMeta::blitRectangle(IntRect(0,0,w,h), Vec2i()); + GLMeta::blitEnd(); + + taintArea(IntRect(0,0,w,h)); + +} + void Bitmap::hueChange(int hue) { guardDisposed(); diff --git a/src/bitmap.h b/src/bitmap.h index 732e9c6e..a044b05d 100644 --- a/src/bitmap.h +++ b/src/bitmap.h @@ -40,6 +40,7 @@ class Bitmap : public Disposable public: Bitmap(const char *filename); Bitmap(int width, int height); + Bitmap(void *pixeldata, int width, int height); /* Clone constructor */ Bitmap(const Bitmap &other); ~Bitmap(); @@ -80,6 +81,8 @@ public: Color getPixel(int x, int y) const; void setPixel(int x, int y, const Color &color); + + void replaceRaw(void *pixel_data, int width, int height); void hueChange(int hue); diff --git a/src/discordstate.cpp b/src/discordstate.cpp index 084a4f48..f48f1aa7 100644 --- a/src/discordstate.cpp +++ b/src/discordstate.cpp @@ -15,12 +15,9 @@ void defaultActivityCb(void *callback_data, enum EDiscordResult result) struct Application { struct IDiscordCore* core; + struct IDiscordImageManager* images; struct IDiscordUserManager* users; - struct IDiscordAchievementManager* achievements; struct IDiscordActivityManager* activities; - struct IDiscordRelationshipManager* relationships; - struct IDiscordApplicationManager* application; - struct IDiscordLobbyManager* lobbies; DiscordUserId user_id; }; @@ -118,6 +115,7 @@ int discordTryConnect(DiscordStatePrivate *p) p->app.activities = p->core->get_activity_manager(p->core); p->app.users = p->core->get_user_manager(p->core); + p->app.images = p->core->get_image_manager(p->core); p->connected = true; @@ -160,6 +158,11 @@ IDiscordUserManager *DiscordState::userManager() return p->app.users; } +IDiscordImageManager *DiscordState::imageManager() +{ + return p->app.images; +} + int DiscordState::update() { if (!p->discordInstalled) return DiscordResult_NotInstalled; @@ -205,10 +208,33 @@ DiscordUserId DiscordState::userId() return (p->userPresent) ? p->currentUser.id : 0; } -// NYI -Bitmap *userAvatar() +typedef struct { DiscordStatePrivate *pri; Bitmap *bmp; } AvatarCbData; +Bitmap *DiscordState::getAvatar(DiscordUserId userId, int size) { - Bitmap *ret = new Bitmap(256, 256); + if (!isConnected()) return 0; + AvatarCbData cbData{}; + cbData.bmp = new Bitmap(size, size); + cbData.pri = p; + DiscordImageHandle handle{}; + handle.id = userId; + handle.size = size; - return ret; + p->app.images->fetch(p->app.images, handle, true, &cbData, + [](void *callback_data, enum EDiscordResult result, struct DiscordImageHandle handle_result){ + if (result == DiscordResult_Ok) + { + AvatarCbData *data = (AvatarCbData*)callback_data; + int sz = data->bmp->width()*data->bmp->height()*4; + uint8_t *buf = new uint8_t[sz]; + data->pri->app.images->get_data(data->pri->app.images, handle_result, buf, sz); + data->bmp->replaceRaw(buf, data->bmp->width(), data->bmp->height()); + delete[] buf; + } + }); + return cbData.bmp; +} + +Bitmap *DiscordState::userAvatar() +{ + return (p->userPresent) ? getAvatar(p->currentUser.id, 256) : 0; } diff --git a/src/discordstate.h b/src/discordstate.h index e22abc9f..0e127aa2 100644 --- a/src/discordstate.h +++ b/src/discordstate.h @@ -17,6 +17,7 @@ public: IDiscordActivityManager *activityManager(); IDiscordUserManager *userManager(); + IDiscordImageManager *imageManager(); int update(); bool isConnected(); @@ -24,6 +25,8 @@ public: std::string userName(); std::string userDiscrim(); DiscordUserId userId(); + + Bitmap *getAvatar(DiscordUserId userId, int size); Bitmap *userAvatar(); private: