/* Copyright 2016-2017 sub1to This file is part of subVersion GTA:O SC External Hack. subVersion GTA:O SC External Hack is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. subVersion GTA:O SC External Hack is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with subVersion GTA:O SC External Hack. If not, see . */ #include "stdafx.h" D3D9Render::D3D9Render() : m_nFont(0) { } D3D9Render::~D3D9Render() { this->releaseFont(); m_pVertexBuffer->Release(); //close and release vertex buffer m_pD3dDev->Release(); // close and release the 3D device m_pD3d->Release(); // close and release Direct3D } bool D3D9Render::init(HWND hWnd) { m_pD3d = Direct3DCreate9(D3D_SDK_VERSION); //create d3d9 interface ZeroMemory(&m_d3dParam, sizeof(m_d3dParam)); //clear the struct m_d3dParam.Windowed = true; m_d3dParam.SwapEffect = D3DSWAPEFFECT_DISCARD; m_d3dParam.hDeviceWindow = hWnd; m_d3dParam.BackBufferHeight = m_screen.h; m_d3dParam.BackBufferWidth = m_screen.w; m_d3dParam.MultiSampleQuality = D3DMULTISAMPLE_NONE; m_d3dParam.BackBufferFormat = D3DFMT_A8R8G8B8; m_pD3d->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd, D3DCREATE_HARDWARE_VERTEXPROCESSING, &m_d3dParam, &m_pD3dDev); //create vertex buffer m_pD3dDev->CreateVertexBuffer( 4 * sizeof(Vertex), 0, VERTEX_FORMAT, D3DPOOL_DEFAULT, //managed = video ram; D3DPOOL_DEFAULT = auto &m_pVertexBuffer, //vertex buffer interface NULL); this->createFont("Verdana", 14, true, false); this->createFont("Verdana", 14, false, false); this->createFont("Verdana", 18, true, false); m_pD3dDev->SetFVF(VERTEX_FORMAT);// select which vertex format to use return true; } static std::string floatToString(float val) { auto res = std::to_string(val); const std::string format("$1"); std::regex r("(\\d*)\\.0{6}|"); std::regex r2("(\\d*\\.{1}0*[^0]+)0*"); res = std::regex_replace(res, r2, format); res = std::regex_replace(res, r, format); return res; } bool D3D9Render::render() { m_pD3dDev->Clear(0, nullptr, D3DCLEAR_TARGET, D3DCOLOR_ARGB(0,0,0,0), 1.f, 0); m_pD3dDev->BeginScene(); if(g_pSettings->isMenuActive() && g_pMemMan->getWindow() == GetForegroundWindow()) { //Draw header this->drawBoxBorder(0, 0, LAYOUT_ELEMENT_WIDTH, LAYOUT_ELEMENT_HEIGHT, LAYOUT_BORDER_SIZE, LAYOUT_COLOR_BACKGROUND, LAYOUT_COLOR_BORDER); this->drawText(m_szWindowTitle, 0, 0, LAYOUT_ELEMENT_WIDTH, LAYOUT_ELEMENT_HEIGHT, 2, LAYOUT_COLOR_TEXT, DT_CENTER | DT_VCENTER); if (this->m_bMBShowing) { this->drawBoxBorder(LAYOUT_ELEMENT_WIDTH + 10, 0, LAYOUT_MB_WIDTH, LAYOUT_ELEMENT_HEIGHT, LAYOUT_BORDER_SIZE, LAYOUT_COLOR_BACKGROUND, LAYOUT_COLOR_BORDER); this->drawText(this->m_sTitle, LAYOUT_ELEMENT_WIDTH + 10, 0, LAYOUT_MB_WIDTH, LAYOUT_ELEMENT_HEIGHT, 2, LAYOUT_COLOR_TEXT, DT_CENTER | DT_VCENTER); this->drawBoxBorder(LAYOUT_ELEMENT_WIDTH + 10, LAYOUT_ELEMENT_HEIGHT, LAYOUT_MB_WIDTH, LAYOUT_MB_HEIGHT, LAYOUT_BORDER_SIZE, LAYOUT_COLOR_BACKGROUND, LAYOUT_COLOR_BORDER); this->drawText(this->m_sDetail, LAYOUT_ELEMENT_WIDTH + 10, LAYOUT_ELEMENT_HEIGHT, LAYOUT_MB_WIDTH , LAYOUT_MB_HEIGHT, 0, LAYOUT_COLOR_TEXT, DT_CENTER | DT_VCENTER); } //prevent race conditions while(!g_pSettings->lockFeatureCur()) Sleep(1); //draw tabs for(int i = 0; i < g_pSettings->getFeatureCategoryCount(); i++) { featCat* tab = g_pSettings->getFeatureCategory(i); int x = (LAYOUT_ELEMENT_WIDTH / g_pSettings->getFeatureCategoryCount()) * i, y = LAYOUT_ELEMENT_HEIGHT * 1, w = LAYOUT_ELEMENT_WIDTH / g_pSettings->getFeatureCategoryCount(), h = LAYOUT_ELEMENT_HEIGHT; this->drawBoxBorder( x, y, w, h, LAYOUT_BORDER_SIZE, (i == g_pSettings->getActiveCat()) ? LAYOUT_COLOR_ACTIVE_BG : LAYOUT_COLOR_BACKGROUND, (i == g_pSettings->getActiveCat()) ? LAYOUT_COLOR_ACTIVE_BORDER : LAYOUT_COLOR_BORDER); this->drawText(tab->m_szName, x, y, w - 1, h, 0, LAYOUT_COLOR_TEXT, DT_CENTER | DT_VCENTER); } //draw features int n = g_pSettings->getFeatureCurCount(), active = g_pSettings->getActiveFeature(); this->drawBoxBorder( 0, //draw bg for all features LAYOUT_ELEMENT_HEIGHT * 2, LAYOUT_ELEMENT_WIDTH, (n > MAX_MENU_FEATURES_DISPLAYED) ? MAX_MENU_FEATURES_DISPLAYED * LAYOUT_ELEMENT_HEIGHT : LAYOUT_ELEMENT_HEIGHT * n, LAYOUT_BORDER_SIZE, LAYOUT_COLOR_BACKGROUND, LAYOUT_COLOR_BORDER); for(int i = 0, j = g_pSettings->getDisplayOffset(); i < n && i < MAX_MENU_FEATURES_DISPLAYED; i++, j++) { feat* feature = g_pSettings->getFeatureCur(j); int x = 8, y = LAYOUT_ELEMENT_HEIGHT * (i + 2); //selected box if(j == active) this->drawBoxBorder( x - 6, y + 2, LAYOUT_ELEMENT_WIDTH - (LAYOUT_BORDER_SIZE * 2), LAYOUT_ELEMENT_HEIGHT - (LAYOUT_BORDER_SIZE * 2), LAYOUT_BORDER_SIZE, LAYOUT_COLOR_ACTIVE_BG, LAYOUT_COLOR_SELECTED); //checkbox if(feature->m_type == feat_toggle || feature->m_type == feat_slider) { this->drawBoxBorder( x - 2, y + 5, LAYOUT_ELEMENT_HEIGHT - (LAYOUT_BORDER_SIZE * 5), LAYOUT_ELEMENT_HEIGHT - (LAYOUT_BORDER_SIZE * 5), LAYOUT_BORDER_SIZE, (feature->m_bOn == true) ? LAYOUT_COLOR_SELECTED : LAYOUT_COLOR_BACKGROUND, (feature->m_bOn == true) ? LAYOUT_COLOR_ACTIVE_BORDER : LAYOUT_COLOR_BORDER); x += (LAYOUT_ELEMENT_HEIGHT - (LAYOUT_BORDER_SIZE * 3)); } this->drawText(feature->m_szName, x, y, 0, LAYOUT_ELEMENT_HEIGHT, 1, LAYOUT_COLOR_TEXT, DT_VCENTER); //slider if(feature->m_type == feat_slider) { featSlider* slider = static_cast(feature); int x = (int) (LAYOUT_ELEMENT_WIDTH * .5f), y = (LAYOUT_ELEMENT_HEIGHT * (i + 2)) + 5, w = (int) ((LAYOUT_ELEMENT_WIDTH * .5f) - (LAYOUT_BORDER_SIZE * 2)), h = LAYOUT_ELEMENT_HEIGHT - (LAYOUT_BORDER_SIZE * 5); float mod = (slider->m_fValue - slider->m_fMin) / (slider->m_fMax - slider->m_fMin); this->drawBoxBorder(x, y, w, h, LAYOUT_BORDER_SIZE, LAYOUT_COLOR_SLIDER_BG, LAYOUT_COLOR_BORDER); this->drawBoxBorder(x + (int) (mod * (w - h)), y, h, h, LAYOUT_BORDER_SIZE, LAYOUT_COLOR_SLIDER_BTN, LAYOUT_COLOR_BORDER); //this->drawText(floatToString(slider->m_fValue), x, y, w - 1, h, 0, LAYOUT_COLOR_VALUE_TEXT, DT_CENTER | DT_VCENTER); } } //draw scrollbar int max = n - MAX_MENU_FEATURES_DISPLAYED; //number of features that are not displayed if(max > 0) { int space = LAYOUT_ELEMENT_HEIGHT * (MAX_MENU_FEATURES_DISPLAYED + 2), height = (space / max <= space / 2) ? space / max : space / 2; space -= height; float mod = (g_pSettings->getDisplayOffset() / (float) max); this->drawBoxBorder(LAYOUT_ELEMENT_WIDTH + LAYOUT_BORDER_SIZE , (int) (space * mod), LAYOUT_SCROLLBAR_WIDTH, height, LAYOUT_BORDER_SIZE, LAYOUT_COLOR_BACKGROUND, LAYOUT_COLOR_BORDER); } g_pSettings->unlockFeatureCur(); } m_pD3dDev->EndScene(); m_pD3dDev->Present(nullptr, nullptr, nullptr, nullptr); return true; } bool D3D9Render::createFont(char *name, int size, bool bold, bool italic) { if(m_nFont >= FONT_BUFFER_SIZE) return false; D3DXCreateFont(m_pD3dDev, size, 0, (bold) ? FW_BOLD : FW_NORMAL, 0, (italic) ? 1 : 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, ANTIALIASED_QUALITY, DEFAULT_PITCH, name, &m_pFont[m_nFont]); m_nFont++; return true; } void D3D9Render::releaseFont() { for(int i = 0; i < m_nFont; i++) if(m_pFont[i] != nullptr) m_pFont[i]->Release(); m_nFont = 0; return; } bool D3D9Render::getViewport() { RECT rectWnd; GetWindowRect(g_pMemMan->getWindow(), &rectWnd); m_screen.w = LAYOUT_ELEMENT_WIDTH * 2 + LAYOUT_SCROLLBAR_WIDTH + LAYOUT_BORDER_SIZE; m_screen.h = LAYOUT_ELEMENT_HEIGHT * (MAX_MENU_FEATURES_DISPLAYED + 2); //300 m_screen.x = rectWnd.left + LAYOUT_PADDING_LEFT; m_screen.y = rectWnd.top + LAYOUT_PADDING_TOP; return 1; } void D3D9Render::showMessageBox(std::wstring title,std::wstring detail) { this->m_sTitle = title; this->m_sDetail = detail; std::thread t([this] { m_bMBShowing = true; Sleep(3000); m_bMBShowing = false; }); t.detach(); } void D3D9Render::drawBox(int x, int y, int w, int h, D3DCOLOR color) { /*Vertex vertex[] = { {(float) x, (float) y + h, 1.0f, 1.0f, color}, {(float) x, (float) y, 1.0f, 1.0f, color}, {(float) x + w, (float) y + h, 1.0f, 1.0f, color}, {(float) x + w, (float) y, 1.0f, 1.0f, color} }; void* pvBuffer; //pointer to the buffer m_pVertexBuffer->Lock(0, 0, (void**) &pvBuffer, 0); memcpy(pvBuffer, vertex, sizeof(vertex)); m_pVertexBuffer->Unlock(); // select the vertex buffer to display m_pD3dDev->SetStreamSource(0, m_pVertexBuffer, 0, sizeof(Vertex)); // copy the vertex buffer to the back buffer m_pD3dDev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);*/ D3DRECT rect {x, y, x + w, y + h}; m_pD3dDev->Clear(1, &rect, D3DCLEAR_TARGET, color, 1.f, 0); return; } void D3D9Render::drawBoxInline(int x, int y, int w, int h, int size, D3DCOLOR color) { this->drawBox(x, y, w, size, color); //top this->drawBox(x + w - size, y, size, h, color); //right this->drawBox(x, y + h - size, w, size, color); //bottom this->drawBox(x, y, size, h, color); //left return; } void D3D9Render::drawBoxBorder(int x, int y, int w, int h, int borderSize, D3DCOLOR color, D3DCOLOR borderColor) { this->drawBox(x, y, w, h, borderColor); this->drawBox(x + borderSize, y + borderSize, w - (borderSize * 2), h - (borderSize * 2), color); } void D3D9Render::drawText(std::wstring str, int x, int y, int font, D3DCOLOR color) { LPCWSTR pszStr = str.c_str(); RECT pos; pos.left = x; pos.top = y; m_pFont[font]->DrawTextW(nullptr, pszStr, (int) lstrlenW(pszStr), &pos, DT_NOCLIP, color); } //void drawText (std::string str, float x, float y, float w, float h, int font, D3DCOLOR color, DWORD flags = NULL) void D3D9Render::drawText(std::wstring str, int x, int y, int w, int h, int font, D3DCOLOR color, DWORD flags) { LPCWSTR pszStr = str.c_str(); RECT pos; pos.left = x; pos.right = x + w; pos.top = y; pos.bottom = y + h; m_pFont[font]->DrawTextW(nullptr, pszStr, (int) lstrlenW(pszStr), &pos, flags | DT_NOCLIP, color); }