#include "EterLib/StdAfx.h" #include "UIRenderCommands.h" #include "RenderCommands3D.h" #include "EterLib/StateManager.h" #include namespace { std::vector commands; std::uint64_t frame_id = 0; int canvas_width = 0; int canvas_height = 0; float clip_x1 = 0, clip_y1 = 0, clip_x2 = 0, clip_y2 = 0; float saved_x1 = 0, saved_y1 = 0, saved_x2 = 0, saved_y2 = 0; } void UIRenderSetSize(int width, int height) { canvas_width = width; canvas_height = height; } void UIRenderGetSize(unsigned* width, unsigned* height) { if (width) *width = canvas_width; if (height) *height = canvas_height; } void UIRenderBeginFrame() { ++frame_id; commands.clear(); clip_x1 = clip_y1 = 0; clip_x2 = canvas_width; clip_y2 = canvas_height; } std::uint64_t UIRenderFrameId() { return frame_id; } void UIRenderAdd(UIRenderCommand command) { command.clip_x1 = clip_x1; command.clip_y1 = clip_y1; command.clip_x2 = clip_x2; command.clip_y2 = clip_y2; command.behind_3d = Render3DDraws().empty(); commands.push_back(command); } const std::vector& UIRenderCommands() { return commands; } void UIRenderSetClip(float x, float y, float width, float height) { saved_x1 = clip_x1; saved_y1 = clip_y1; saved_x2 = clip_x2; saved_y2 = clip_y2; clip_x1 = x; clip_y1 = y; clip_x2 = x + width; clip_y2 = y + height; } void UIRenderRestoreClip() { clip_x1 = saved_x1; clip_y1 = saved_y1; clip_x2 = saved_x2; clip_y2 = saved_y2; } void UIRenderAddImage(const CGraphicTexture* texture, const float x[4], const float y[4], float su, float sv, float eu, float ev, std::uint32_t argb, int blend) { // 40250 draws the image quad through the device: the UI pass's world transform places it // (identity except where a caller sets one, e.g. CPythonMiniMap::RenderAtlas's window offset) and a // stage-0 MODULATE with D3DTA_TFACTOR tints it (the atlas's NPC/warp/waypoint marks). D3DXMATRIX world; D3DXMatrixIdentity(&world); if (CStateManager* state = CStateManager::InstancePtr()) { state->GetTransform(D3DTS_WORLD, &world); DWORD op = 0, arg1 = 0, arg2 = 0; state->GetTextureStageState(0, D3DTSS_COLOROP, &op); state->GetTextureStageState(0, D3DTSS_COLORARG1, &arg1); state->GetTextureStageState(0, D3DTSS_COLORARG2, &arg2); if (op == D3DTOP_MODULATE && (arg1 == D3DTA_TFACTOR || arg2 == D3DTA_TFACTOR)) { // TFACTOR x TEXTURE drops the vertex colour; TFACTOR x DIFFUSE scales it. The canvas // multiplies the texture in. const std::uint32_t factor = state->GetRenderState(D3DRS_TEXTUREFACTOR) & 0x00FFFFFFu; const DWORD other = arg1 == D3DTA_TFACTOR ? arg2 : arg1; if (other == D3DTA_DIFFUSE) { std::uint32_t tinted = argb & 0xFF000000u; for (int shift = 0; shift < 24; shift += 8) tinted |= ((((argb >> shift) & 255) * ((factor >> shift) & 255) + 127) / 255) << shift; argb = tinted; } else { argb = (argb & 0xFF000000u) | factor; } } } UIRenderCommand command{UIRenderCommand::Image, 0, 0, 0, 0, argb}; for (int i = 0; i < 4; ++i) { command.qx[i] = x[i] * world._11 + y[i] * world._21 + world._41 + 0.5f; command.qy[i] = x[i] * world._12 + y[i] * world._22 + world._42 + 0.5f; } command.x1 = std::min({command.qx[0], command.qx[1], command.qx[2], command.qx[3]}); command.y1 = std::min({command.qy[0], command.qy[1], command.qy[2], command.qy[3]}); command.x2 = std::max({command.qx[0], command.qx[1], command.qx[2], command.qx[3]}); command.y2 = std::max({command.qy[0], command.qy[1], command.qy[2], command.qy[3]}); command.text = UIRenderTextureName(texture); command.quad = true; command.su = su; command.sv = sv; command.eu = eu; command.ev = ev; command.blend = blend; UIRenderAdd(std::move(command)); }