void UIEnd() { ui_draw2d.End(); ui_draw2d_front.End(); ui_draw2d.Flush(); ui_draw2d_front.Flush(); }
void UIEnd() { for (int i = 0; i < MAX_POINTERS; i++) { if (uistate.mousedown[i] == 0) { uistate.activeitem[i] = 0; } else { if (uistate.activeitem[i] == 0) { uistate.activeitem[i] = -1; } } } ui_draw2d.End(); ui_draw2d_front.End(); if (uistate.ui_tick > 0) uistate.ui_tick--; ui_draw2d.Flush(); ui_draw2d_front.Flush(); }
void UIFlush() { ui_draw2d.Flush(); ui_draw2d_front.Flush(); }
int UITextureButton(UIContext *ctx, int id, const LayoutManager &layout, float w, float h, Texture *texture, int button_align, uint32_t color, int drop_shadow) // uses current UI atlas for fetching images. { float x, y; layout.GetPos(&w, &h, &x, &y); if (button_align & ALIGN_HCENTER) x -= w / 2; if (button_align & ALIGN_VCENTER) y -= h / 2; if (button_align & ALIGN_RIGHT) x -= w; if (button_align & ALIGN_BOTTOMRIGHT) y -= h; int txOffset = 0; int clicked = 0; for (int i = 0; i < MAX_POINTERS; i++) { // Check whether the button should be hot, use a generous margin for touch ease if (UIRegionHit(i, x, y, w, h, 8)) { uistate.hotitem[i] = id; if (uistate.activeitem[i] == 0 && uistate.mousedown[i]) uistate.activeitem[i] = id; } if (uistate.hotitem[i] == id) { if (uistate.activeitem[i] == id) { // Button is both 'hot' and 'active' txOffset = 2; } else { // Button is merely 'hot' } } else { // button is not hot, but it may be active } // If button is hot and active, but mouse button is not // down, the user must have clicked the button. if (uistate.mousedown[i] == 0 && uistate.hotitem[i] == id && uistate.activeitem[i] == id) { clicked = 1; } } if (texture) { float tw = texture->Width(); float th = texture->Height(); // Adjust position so we don't stretch the image vertically or horizontally. // TODO: Add a param to specify fit? The below assumes it's never too wide. float nw = h * tw / th; x += (w - nw) / 2.0f; w = nw; } // Render button int dropsize = 10; if (drop_shadow && texture) { if (txOffset) { dropsize = 3; y += txOffset * 2; } ui_draw2d.DrawImage4Grid(drop_shadow, x - dropsize, y, x+w + dropsize, y+h+dropsize*1.5, blackAlpha(0.5f), 1.0f); ui_draw2d.Flush(true); } if (texture) { texture->Bind(0); } else { ui_draw2d.DrawImage2GridH(theme.buttonImage, x, y, x + w, color); ui_draw2d.Flush(); Texture::Unbind(); } ui_draw2d.DrawTexRect(x, y, x+w, y+h, 0, 0, 1, 1, color); ui_draw2d.Flush(); ctx->RebindTexture(); uistate.lastwidget = id; return clicked; }
void TextDrawerWin32::DrawString(DrawBuffer &target, const char *str, float x, float y, uint32_t color, int align) { using namespace Draw; if (!strlen(str)) return; uint32_t stringHash = hash::Adler32((const uint8_t *)str, strlen(str)); uint32_t entryHash = stringHash ^ fontHash_ ^ (align << 24); target.Flush(true); TextStringEntry *entry; auto iter = cache_.find(entryHash); if (iter != cache_.end()) { entry = iter->second.get(); entry->lastUsedFrame = frameCount_; } else { // Render the string to our bitmap and save to a GL texture. std::wstring wstr = ConvertUTF8ToWString(ReplaceAll(str, "\n", "\r\n")); SIZE size; auto iter = fontMap_.find(fontHash_); if (iter != fontMap_.end()) { SelectObject(ctx_->hDC, iter->second->hFont); } // Set text properties SetTextColor(ctx_->hDC, 0xFFFFFF); SetBkColor(ctx_->hDC, 0); SetTextAlign(ctx_->hDC, TA_TOP); // This matters for multi-line text - DT_CENTER is horizontal only. UINT dtAlign = (align & ALIGN_HCENTER) == 0 ? DT_LEFT : DT_CENTER; RECT textRect = { 0 }; DrawTextExW(ctx_->hDC, (LPWSTR)wstr.c_str(), (int)wstr.size(), &textRect, DT_HIDEPREFIX | DT_TOP | dtAlign | DT_CALCRECT, 0); size.cx = textRect.right; size.cy = textRect.bottom; // GetTextExtentPoint32(ctx_->hDC, wstr.c_str(), (int)wstr.size(), &size); RECT rc = { 0 }; rc.right = size.cx + 4; rc.bottom = size.cy + 4; FillRect(ctx_->hDC, &rc, (HBRUSH)GetStockObject(BLACK_BRUSH)); //ExtTextOut(ctx_->hDC, 0, 0, ETO_OPAQUE | ETO_CLIPPED, NULL, wstr.c_str(), (int)wstr.size(), NULL); DrawTextExW(ctx_->hDC, (LPWSTR)wstr.c_str(), (int)wstr.size(), &rc, DT_HIDEPREFIX | DT_TOP | dtAlign, 0); if (size.cx > MAX_TEXT_WIDTH) size.cx = MAX_TEXT_WIDTH; if (size.cy > MAX_TEXT_HEIGHT) size.cy = MAX_TEXT_HEIGHT; entry = new TextStringEntry(); entry->width = size.cx; entry->height = size.cy; entry->bmWidth = (size.cx + 3) & ~3; entry->bmHeight = (size.cy + 3) & ~3; entry->lastUsedFrame = frameCount_; DataFormat texFormat; // For our purposes these are equivalent, so just choose the supported one. D3D can emulate them. if (draw_->GetDataFormatSupport(Draw::DataFormat::A4R4G4B4_UNORM_PACK16) & FMT_TEXTURE) texFormat = Draw::DataFormat::A4R4G4B4_UNORM_PACK16; else if (draw_->GetDataFormatSupport(Draw::DataFormat::B4G4R4A4_UNORM_PACK16) & FMT_TEXTURE) texFormat = Draw::DataFormat::B4G4R4A4_UNORM_PACK16; else texFormat = Draw::DataFormat::R8G8B8A8_UNORM; // Convert the bitmap to a Thin3D compatible array of 16-bit pixels. Can't use a single channel format // because we need white. Well, we could using swizzle, but not all our backends support that. TextureDesc desc{}; uint32_t *bitmapData32 = nullptr; uint16_t *bitmapData16 = nullptr; if (texFormat == Draw::DataFormat::R8G8B8A8_UNORM || texFormat == Draw::DataFormat::B8G8R8A8_UNORM) { bitmapData32 = new uint32_t[entry->bmWidth * entry->bmHeight]; for (int y = 0; y < entry->bmHeight; y++) { for (int x = 0; x < entry->bmWidth; x++) { uint8_t bAlpha = (uint8_t)(ctx_->pBitmapBits[MAX_TEXT_WIDTH * y + x] & 0xff); bitmapData32[entry->bmWidth * y + x] = (bAlpha << 24) | 0x00ffffff; } } desc.initData.push_back((uint8_t *)bitmapData32); } else if (texFormat == Draw::DataFormat::B4G4R4A4_UNORM_PACK16) { bitmapData16 = new uint16_t[entry->bmWidth * entry->bmHeight]; for (int y = 0; y < entry->bmHeight; y++) { for (int x = 0; x < entry->bmWidth; x++) { uint8_t bAlpha = (uint8_t)((ctx_->pBitmapBits[MAX_TEXT_WIDTH * y + x] & 0xff) >> 4); bitmapData16[entry->bmWidth * y + x] = (bAlpha) | 0xfff0; } } desc.initData.push_back((uint8_t *)bitmapData16); } else if (texFormat == Draw::DataFormat::A4R4G4B4_UNORM_PACK16) {