mirror of
https://github.com/sfall-team/sfall.git
synced 2026-07-27 16:52:34 -07:00
Moved GNW_win_refresh and related functions to new render.cpp
This commit is contained in:
@@ -0,0 +1,188 @@
|
||||
/*
|
||||
* sfall
|
||||
* Copyright (C) 2008-2021 The sfall team
|
||||
*
|
||||
*/
|
||||
|
||||
#include "..\main.h"
|
||||
#include "..\FalloutEngine\Fallout2.h"
|
||||
|
||||
#include "..\Modules\Graphics.h"
|
||||
#include "..\Modules\SubModules\WindowRender.h"
|
||||
|
||||
#include "render.h"
|
||||
|
||||
namespace game
|
||||
{
|
||||
|
||||
namespace sf = sfall;
|
||||
|
||||
static BYTE* GetBuffer() {
|
||||
return (BYTE*)*(DWORD*)FO_VAR_screen_buffer;
|
||||
}
|
||||
|
||||
static void Draw(fo::Window* win, BYTE* surface, long width, long height, long widthFrom, BYTE* toBuffer, long toWidth, RECT &rect, RECT* updateRect) {
|
||||
auto drawFunc = (win->flags & fo::WinFlags::Transparent && win->wID) ? fo::func::trans_buf_to_buf : fo::func::buf_to_buf;
|
||||
if (toBuffer) {
|
||||
drawFunc(surface, width, height, widthFrom, &toBuffer[rect.left - updateRect->left] + ((rect.top - updateRect->top) * toWidth), toWidth);
|
||||
} else {
|
||||
drawFunc(surface, width, height, widthFrom, &GetBuffer()[rect.left] + (rect.top * toWidth), toWidth); // copy to buffer instead of DD surface (buffering)
|
||||
}
|
||||
|
||||
if (!win->randY) return;
|
||||
surface = &sf::WindowRender::GetOverlaySurface(win)[rect.left - win->rect.x] + ((rect.top - win->rect.y) * win->width);
|
||||
|
||||
if (toBuffer) {
|
||||
fo::func::trans_buf_to_buf(surface, width, height, widthFrom, &toBuffer[rect.left - updateRect->left] + ((rect.top - updateRect->top) * toWidth), toWidth);
|
||||
} else {
|
||||
fo::func::trans_buf_to_buf(surface, width, height, widthFrom, &GetBuffer()[rect.left] + (rect.top * toWidth), toWidth);
|
||||
}
|
||||
}
|
||||
|
||||
void __fastcall Render::GNW_win_refresh(fo::Window* win, RECT* updateRect, BYTE* toBuffer) {
|
||||
if (win->flags & fo::WinFlags::Hidden) return;
|
||||
fo::RectList* rects;
|
||||
|
||||
if (win->flags & fo::WinFlags::Transparent && !*(DWORD*)FO_VAR_doing_refresh_all) {
|
||||
__asm {
|
||||
mov eax, updateRect;
|
||||
mov edx, ds:[FO_VAR_screen_buffer];
|
||||
call fo::funcoffs::refresh_all_;
|
||||
}
|
||||
int w = (updateRect->right - updateRect->left) + 1;
|
||||
|
||||
if (fo::var::mouse_is_hidden || !fo::func::mouse_in(updateRect->left, updateRect->top, updateRect->right, updateRect->bottom)) {
|
||||
/*__asm {
|
||||
mov eax, win;
|
||||
mov edx, updateRect;
|
||||
call fo::funcoffs::GNW_button_refresh_;
|
||||
}*/
|
||||
int h = (updateRect->bottom - updateRect->top) + 1;
|
||||
|
||||
sf::Graphics::UpdateDDSurface(GetBuffer(), w, h, w, updateRect); // update the entire rectangle area
|
||||
|
||||
} else {
|
||||
fo::func::mouse_show(); // for updating background cursor area
|
||||
RECT mouseRect;
|
||||
__asm {
|
||||
lea eax, mouseRect;
|
||||
mov edx, eax;
|
||||
call fo::funcoffs::mouse_get_rect_;
|
||||
mov eax, updateRect;
|
||||
call fo::funcoffs::rect_clip_;
|
||||
mov rects, eax;
|
||||
}
|
||||
while (rects) { // updates everything except the cursor area
|
||||
/*__asm {
|
||||
mov eax, win;
|
||||
mov edx, rects;
|
||||
call fo::funcoffs::GNW_button_refresh_;
|
||||
}*/
|
||||
|
||||
int wRect = (rects->wRect.right - rects->wRect.left) + 1;
|
||||
int hRect = (rects->wRect.bottom - rects->wRect.top) + 1;
|
||||
|
||||
sf::Graphics::UpdateDDSurface(&GetBuffer()[rects->wRect.left - updateRect->left] + (rects->wRect.top - updateRect->top) * w, wRect, hRect, w, &rects->wRect);
|
||||
|
||||
fo::RectList* free = rects;
|
||||
rects = rects->nextRect;
|
||||
fo::sf_rect_free(free);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Allocates memory for 10 RectList (if no memory was allocated), returns the first Rect and removes it from the list */
|
||||
__asm call fo::funcoffs::rect_malloc_;
|
||||
__asm mov rects, eax;
|
||||
if (!rects) return;
|
||||
|
||||
rects->rect = updateRect;
|
||||
rects->nextRect = nullptr;
|
||||
|
||||
/*
|
||||
If the border of the updateRect rectangle is located outside the window, then assign to rects->rect the border of the window rectangle
|
||||
Otherwise, rects->rect contains the borders from the update rectangle (updateRect)
|
||||
*/
|
||||
if (rects->wRect.left < win->wRect.left) rects->wRect.left = win->wRect.left;
|
||||
if (rects->wRect.top < win->wRect.top) rects->wRect.top = win->wRect.top;
|
||||
if (rects->wRect.right > win->wRect.right) rects->wRect.right = win->wRect.right;
|
||||
if (rects->wRect.bottom > win->wRect.bottom) rects->wRect.bottom = win->wRect.bottom;
|
||||
|
||||
if (rects->wRect.right < rects->wRect.left || rects->wRect.bottom < rects->wRect.top) {
|
||||
fo::sf_rect_free(rects);
|
||||
return;
|
||||
}
|
||||
|
||||
int widthFrom = win->width;
|
||||
int toWidth = (toBuffer) ? (updateRect->right - updateRect->left) + 1 : sf::Graphics::GetGameWidthRes();
|
||||
|
||||
fo::func::win_clip(win, &rects, toBuffer);
|
||||
|
||||
fo::RectList* currRect = rects;
|
||||
while (currRect) {
|
||||
int width = (currRect->wRect.right - currRect->wRect.left) + 1; // for current rectangle
|
||||
int height = (currRect->wRect.bottom - currRect->wRect.top) + 1;; // for current rectangle
|
||||
|
||||
BYTE* surface;
|
||||
if (win->wID > 0) {
|
||||
__asm {
|
||||
mov eax, win;
|
||||
mov edx, currRect;
|
||||
call fo::funcoffs::GNW_button_refresh_;
|
||||
}
|
||||
surface = &win->surface[currRect->wRect.left - win->rect.x] + ((currRect->wRect.top - win->rect.y) * win->width);
|
||||
} else {
|
||||
surface = new BYTE[height * width](); // black background
|
||||
widthFrom = width; // replace with rectangle
|
||||
}
|
||||
|
||||
Draw(win, surface, width, height, widthFrom, toBuffer, toWidth, currRect->wRect, updateRect);
|
||||
|
||||
if (win->wID == 0) delete[] surface;
|
||||
|
||||
currRect = currRect->nextRect;
|
||||
}
|
||||
|
||||
while (rects) {
|
||||
// copy all rectangles from the buffer to the DD surface (buffering)
|
||||
if (!toBuffer) {
|
||||
int width = (rects->rect.offx - rects->rect.x) + 1;
|
||||
int height = (rects->rect.offy - rects->rect.y) + 1;
|
||||
int widthFrom = toWidth;
|
||||
|
||||
sf::Graphics::UpdateDDSurface(&GetBuffer()[rects->rect.x] + (rects->rect.y * widthFrom), width, height, widthFrom, &rects->wRect);
|
||||
}
|
||||
fo::RectList* next = rects->nextRect;
|
||||
fo::sf_rect_free(rects);
|
||||
rects = next;
|
||||
}
|
||||
|
||||
if (!toBuffer && !*(DWORD*)FO_VAR_doing_refresh_all && !fo::var::mouse_is_hidden && fo::func::mouse_in(updateRect->left, updateRect->top, updateRect->right, updateRect->bottom)) {
|
||||
fo::func::mouse_show();
|
||||
}
|
||||
}
|
||||
|
||||
static __declspec(naked) void GNW_win_refresh_hack() {
|
||||
__asm {
|
||||
push ebx; // toBuffer
|
||||
mov ecx, eax;
|
||||
call Render::GNW_win_refresh;
|
||||
pop ecx;
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
void Render::init() {
|
||||
// Replace the srcCopy_ function with a pure MMX implementation
|
||||
sf::MakeJump(fo::funcoffs::buf_to_buf_, fo::func::buf_to_buf); // 0x4D36D4
|
||||
// Replace the transSrcCopy_ function
|
||||
sf::MakeJump(fo::funcoffs::trans_buf_to_buf_, fo::func::trans_buf_to_buf); // 0x4D3704
|
||||
|
||||
// Custom implementation of the GNW_win_refresh function
|
||||
sf::MakeJump(0x4D6FD9, GNW_win_refresh_hack, 1);
|
||||
// Replace _screendump_buf with _screen_buffer for creating screenshots
|
||||
sf::SafeWriteBatch<DWORD>(FO_VAR_screen_buffer, {0x4C8FD1, 0x4C900D});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* sfall
|
||||
* Copyright (C) 2008-2021 The sfall team
|
||||
*
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace game
|
||||
{
|
||||
|
||||
class Render {
|
||||
public:
|
||||
static void init();
|
||||
|
||||
static void __fastcall GNW_win_refresh(fo::Window* win, RECT* updateRect, BYTE* toBuffer);
|
||||
};
|
||||
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
#include "..\InputFuncs.h"
|
||||
#include "ScriptShaders.h"
|
||||
|
||||
#include "SubModules\GameRender.h"
|
||||
#include "SubModules\WindowRender.h"
|
||||
|
||||
#include "Graphics.h"
|
||||
|
||||
@@ -1209,7 +1209,7 @@ void Graphics::init() {
|
||||
dlogr(" Done", DL_INIT);
|
||||
}
|
||||
|
||||
GameRender::init();
|
||||
WindowRender::init();
|
||||
}
|
||||
|
||||
void Graphics::exit() {
|
||||
|
||||
@@ -29,7 +29,8 @@
|
||||
|
||||
#include "..\..\HookScripts\InventoryHs.h"
|
||||
|
||||
#include "..\..\SubModules\GameRender.h"
|
||||
#include "..\..\SubModules\WindowRender.h"
|
||||
#include "..\..\..\Game\render.h"
|
||||
|
||||
#include "Interface.h"
|
||||
|
||||
@@ -277,7 +278,7 @@ void mf_intface_redraw(OpcodeContext& ctx) {
|
||||
fo::func::RefreshGNW(true);
|
||||
} else {
|
||||
fo::Window* win = Interface::GetWindow(winType);
|
||||
if (win && (int)win != -1) fo::func::GNW_win_refresh(win, &win->rect, 0);
|
||||
if (win && (int)win != -1) game::Render::GNW_win_refresh(win, &win->wRect, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -637,14 +638,14 @@ static long InterfaceDrawImage(OpcodeContext& ctx, fo::Window* ifaceWin) {
|
||||
int width = (w >= 0) ? w : framePtr->width;
|
||||
int height = (h >= 0) ? h : framePtr->height;
|
||||
|
||||
BYTE* surface = (ifaceWin->randY) ? GameRender::GetOverlaySurface(ifaceWin) : ifaceWin->surface;
|
||||
BYTE* surface = (ifaceWin->randY) ? WindowRender::GetOverlaySurface(ifaceWin) : ifaceWin->surface;
|
||||
|
||||
fo::func::trans_cscale(((frmPtr->id == 'PCX') ? frmPtr->pixelData : framePtr->data), framePtr->width, framePtr->height, framePtr->width,
|
||||
surface + (y * ifaceWin->width) + x, width, height, ifaceWin->width
|
||||
);
|
||||
|
||||
if (!(ctx.arg(0).rawValue() & 0x1000000)) { // is set to "Don't redraw"
|
||||
fo::func::GNW_win_refresh(ifaceWin, &ifaceWin->rect, 0);
|
||||
game::Render::GNW_win_refresh(ifaceWin, &ifaceWin->wRect, 0);
|
||||
}
|
||||
|
||||
FreeArtFile(frmPtr);
|
||||
@@ -800,7 +801,7 @@ void mf_interface_print(OpcodeContext& ctx) { // same as vanilla PrintRect
|
||||
BYTE* surface;
|
||||
if (win->randY) { // if a surface was created, the engine will draw on it
|
||||
surface = win->surface;
|
||||
win->surface = GameRender::GetOverlaySurface(win); // replace the surface for the windowWrapLineWithSpacing_ function
|
||||
win->surface = WindowRender::GetOverlaySurface(win); // replace the surface for the windowWrapLineWithSpacing_ function
|
||||
}
|
||||
|
||||
if (color & 0x10000) { // shadow (textshadow)
|
||||
@@ -812,7 +813,7 @@ void mf_interface_print(OpcodeContext& ctx) { // same as vanilla PrintRect
|
||||
if (win->randY) win->surface = surface;
|
||||
|
||||
// no redraw (textdirect)
|
||||
if (!(color & 0x1000000)) fo::func::GNW_win_refresh(win, &win->rect, 0);
|
||||
if (!(color & 0x1000000)) game::Render::GNW_win_refresh(win, &win->wRect, 0);
|
||||
}
|
||||
|
||||
void mf_win_fill_color(OpcodeContext& ctx) {
|
||||
@@ -842,10 +843,10 @@ void mf_interface_overlay(OpcodeContext& ctx) {
|
||||
|
||||
switch (ctx.arg(1).rawValue()) {
|
||||
case 0:
|
||||
GameRender::DestroyOverlaySurface(win);
|
||||
WindowRender::DestroyOverlaySurface(win);
|
||||
break;
|
||||
case 1:
|
||||
GameRender::CreateOverlaySurface(win, winType);
|
||||
WindowRender::CreateOverlaySurface(win, winType);
|
||||
break;
|
||||
case 2: // clear
|
||||
if (ctx.numArgs() > 2) {
|
||||
@@ -858,9 +859,9 @@ void mf_interface_overlay(OpcodeContext& ctx) {
|
||||
if (x < 0 || y < 0) return;
|
||||
|
||||
Rectangle rect = { x, y, w, h };
|
||||
GameRender::ClearOverlay(win, rect);
|
||||
WindowRender::ClearOverlay(win, rect);
|
||||
} else {
|
||||
GameRender::ClearOverlay(win);
|
||||
WindowRender::ClearOverlay(win);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -1,339 +0,0 @@
|
||||
/*
|
||||
* sfall
|
||||
* Copyright (C) 2008-2020 The sfall team
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "..\..\main.h"
|
||||
#include "..\..\FalloutEngine\Fallout2.h"
|
||||
#include "..\Graphics.h"
|
||||
|
||||
#include "GameRender.h"
|
||||
|
||||
namespace sfall
|
||||
{
|
||||
|
||||
static void __fastcall sf_GNW_win_refresh(fo::Window* win, RECT* updateRect, BYTE* toBuffer);
|
||||
|
||||
class OverlaySurface
|
||||
{
|
||||
private:
|
||||
long size = 0;
|
||||
long surfWidth;
|
||||
long allocSize;
|
||||
BYTE* surface = nullptr;
|
||||
|
||||
public:
|
||||
long winType = -1;
|
||||
|
||||
BYTE* Surface() { return surface; }
|
||||
|
||||
void CreateSurface(fo::Window* win, long winType) {
|
||||
this->winType = winType;
|
||||
this->surfWidth = win->width;
|
||||
this->size = win->height * win->width;
|
||||
|
||||
if (surface != nullptr) {
|
||||
if (size <= allocSize) {
|
||||
std::memset(surface, 0, size);
|
||||
return;
|
||||
}
|
||||
delete[] surface;
|
||||
}
|
||||
|
||||
this->allocSize = size;
|
||||
surface = new BYTE[size]();
|
||||
}
|
||||
|
||||
void ClearSurface() {
|
||||
if (surface != nullptr) std::memset(surface, 0, size);
|
||||
}
|
||||
|
||||
void ClearSurface(Rectangle &rect) {
|
||||
if (surface != nullptr) {
|
||||
if (rect.width > surfWidth || rect.height > (size / surfWidth)) return; // going beyond the surface size
|
||||
BYTE* surf = surface + (surfWidth * rect.y) + rect.x;
|
||||
|
||||
size_t sizeD = rect.width >> 2;
|
||||
size_t sizeB = rect.width & 3;
|
||||
size_t strideD = sizeD << 2;
|
||||
size_t stride = surfWidth - rect.width;
|
||||
|
||||
long height = rect.height;
|
||||
while (height--) {
|
||||
if (sizeD) {
|
||||
__stosd((DWORD*)surf, 0, sizeD);
|
||||
surf += strideD;
|
||||
}
|
||||
if (sizeB) {
|
||||
__stosb(surf, 0, sizeB);
|
||||
surf += sizeB;
|
||||
}
|
||||
surf += stride;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void DestroySurface() {
|
||||
delete[] surface;
|
||||
surface = nullptr;
|
||||
}
|
||||
|
||||
~OverlaySurface() {
|
||||
delete[] surface;
|
||||
}
|
||||
} overlaySurfaces[5];
|
||||
|
||||
static long indexPosition = 0;
|
||||
|
||||
void GameRender::CreateOverlaySurface(fo::Window* win, long winType) {
|
||||
if (win->randY) return;
|
||||
if (overlaySurfaces[indexPosition].winType == winType) {
|
||||
overlaySurfaces[indexPosition].ClearSurface();
|
||||
} else {
|
||||
if (++indexPosition == 5) indexPosition = 0;
|
||||
overlaySurfaces[indexPosition].CreateSurface(win, winType);
|
||||
}
|
||||
win->randY = reinterpret_cast<long*>(&overlaySurfaces[indexPosition]);
|
||||
}
|
||||
|
||||
BYTE* GameRender::GetOverlaySurface(fo::Window* win) {
|
||||
return reinterpret_cast<OverlaySurface*>(win->randY)->Surface();
|
||||
}
|
||||
|
||||
void GameRender::ClearOverlay(fo::Window* win) {
|
||||
if (win->randY) reinterpret_cast<OverlaySurface*>(win->randY)->ClearSurface();
|
||||
}
|
||||
|
||||
void GameRender::ClearOverlay(fo::Window* win, Rectangle &rect) {
|
||||
if (win->randY) {
|
||||
reinterpret_cast<OverlaySurface*>(win->randY)->ClearSurface(rect);
|
||||
fo::BoundRect updateRect = rect;
|
||||
updateRect.x += win->rect.x;
|
||||
updateRect.y += win->rect.y;
|
||||
updateRect.offx += win->rect.x;
|
||||
updateRect.offy += win->rect.y;
|
||||
sf_GNW_win_refresh(win, reinterpret_cast<RECT*>(&updateRect), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void GameRender::DestroyOverlaySurface(fo::Window* win) {
|
||||
if (win->randY) {
|
||||
auto overlay = reinterpret_cast<OverlaySurface*>(win->randY);
|
||||
win->randY = nullptr;
|
||||
overlay->winType = -1;
|
||||
overlay->DestroySurface();
|
||||
sf_GNW_win_refresh(win, &win->wRect, 0);
|
||||
}
|
||||
}
|
||||
|
||||
static BYTE* GetBuffer() {
|
||||
return (BYTE*)*(DWORD*)FO_VAR_screen_buffer;
|
||||
}
|
||||
|
||||
static void Draw(fo::Window* win, BYTE* surface, long width, long height, long widthFrom, BYTE* toBuffer, long toWidth, RECT &rect, RECT* updateRect) {
|
||||
auto drawFunc = (win->flags & fo::WinFlags::Transparent && win->wID) ? fo::func::trans_buf_to_buf : fo::func::buf_to_buf;
|
||||
if (toBuffer) {
|
||||
drawFunc(surface, width, height, widthFrom, &toBuffer[rect.left - updateRect->left] + ((rect.top - updateRect->top) * toWidth), toWidth);
|
||||
} else {
|
||||
drawFunc(surface, width, height, widthFrom, &GetBuffer()[rect.left] + (rect.top * toWidth), toWidth); // copy to buffer instead of DD surface (buffering)
|
||||
}
|
||||
|
||||
if (!win->randY) return;
|
||||
surface = &GameRender::GetOverlaySurface(win)[rect.left - win->rect.x] + ((rect.top - win->rect.y) * win->width);
|
||||
|
||||
if (toBuffer) {
|
||||
fo::func::trans_buf_to_buf(surface, width, height, widthFrom, &toBuffer[rect.left - updateRect->left] + ((rect.top - updateRect->top) * toWidth), toWidth);
|
||||
} else {
|
||||
fo::func::trans_buf_to_buf(surface, width, height, widthFrom, &GetBuffer()[rect.left] + (rect.top * toWidth), toWidth);
|
||||
}
|
||||
}
|
||||
|
||||
static void __fastcall sf_GNW_win_refresh(fo::Window* win, RECT* updateRect, BYTE* toBuffer) {
|
||||
if (win->flags & fo::WinFlags::Hidden) return;
|
||||
fo::RectList* rects;
|
||||
|
||||
if (win->flags & fo::WinFlags::Transparent && !*(DWORD*)FO_VAR_doing_refresh_all) {
|
||||
__asm {
|
||||
mov eax, updateRect;
|
||||
mov edx, ds:[FO_VAR_screen_buffer];
|
||||
call fo::funcoffs::refresh_all_;
|
||||
}
|
||||
int w = (updateRect->right - updateRect->left) + 1;
|
||||
|
||||
if (fo::var::mouse_is_hidden || !fo::func::mouse_in(updateRect->left, updateRect->top, updateRect->right, updateRect->bottom)) {
|
||||
/*__asm {
|
||||
mov eax, win;
|
||||
mov edx, updateRect;
|
||||
call fo::funcoffs::GNW_button_refresh_;
|
||||
}*/
|
||||
int h = (updateRect->bottom - updateRect->top) + 1;
|
||||
|
||||
Graphics::UpdateDDSurface(GetBuffer(), w, h, w, updateRect); // update the entire rectangle area
|
||||
|
||||
} else {
|
||||
fo::func::mouse_show(); // for updating background cursor area
|
||||
RECT mouseRect;
|
||||
__asm {
|
||||
lea eax, mouseRect;
|
||||
mov edx, eax;
|
||||
call fo::funcoffs::mouse_get_rect_;
|
||||
mov eax, updateRect;
|
||||
call fo::funcoffs::rect_clip_;
|
||||
mov rects, eax;
|
||||
}
|
||||
while (rects) { // updates everything except the cursor area
|
||||
/*__asm {
|
||||
mov eax, win;
|
||||
mov edx, rects;
|
||||
call fo::funcoffs::GNW_button_refresh_;
|
||||
}*/
|
||||
|
||||
int wRect = (rects->wRect.right - rects->wRect.left) + 1;
|
||||
int hRect = (rects->wRect.bottom - rects->wRect.top) + 1;
|
||||
|
||||
Graphics::UpdateDDSurface(&GetBuffer()[rects->wRect.left - updateRect->left] + (rects->wRect.top - updateRect->top) * w, wRect, hRect, w, &rects->wRect);
|
||||
|
||||
fo::RectList* free = rects;
|
||||
rects = rects->nextRect;
|
||||
fo::sf_rect_free(free);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/* Allocates memory for 10 RectList (if no memory was allocated), returns the first Rect and removes it from the list */
|
||||
__asm call fo::funcoffs::rect_malloc_;
|
||||
__asm mov rects, eax;
|
||||
if (!rects) return;
|
||||
|
||||
rects->rect = updateRect;
|
||||
rects->nextRect = nullptr;
|
||||
|
||||
/*
|
||||
If the border of the updateRect rectangle is located outside the window, then assign to rects->rect the border of the window rectangle
|
||||
Otherwise, rects->rect contains the borders from the update rectangle (updateRect)
|
||||
*/
|
||||
if (rects->wRect.left < win->wRect.left) rects->wRect.left = win->wRect.left;
|
||||
if (rects->wRect.top < win->wRect.top) rects->wRect.top = win->wRect.top;
|
||||
if (rects->wRect.right > win->wRect.right) rects->wRect.right = win->wRect.right;
|
||||
if (rects->wRect.bottom > win->wRect.bottom) rects->wRect.bottom = win->wRect.bottom;
|
||||
|
||||
if (rects->wRect.right < rects->wRect.left || rects->wRect.bottom < rects->wRect.top) {
|
||||
fo::sf_rect_free(rects);
|
||||
return;
|
||||
}
|
||||
|
||||
int widthFrom = win->width;
|
||||
int toWidth = (toBuffer) ? (updateRect->right - updateRect->left) + 1 : Graphics::GetGameWidthRes();
|
||||
|
||||
fo::func::win_clip(win, &rects, toBuffer);
|
||||
|
||||
fo::RectList* currRect = rects;
|
||||
while (currRect) {
|
||||
int width = (currRect->wRect.right - currRect->wRect.left) + 1; // for current rectangle
|
||||
int height = (currRect->wRect.bottom - currRect->wRect.top) + 1;; // for current rectangle
|
||||
|
||||
BYTE* surface;
|
||||
if (win->wID > 0) {
|
||||
__asm {
|
||||
mov eax, win;
|
||||
mov edx, currRect;
|
||||
call fo::funcoffs::GNW_button_refresh_;
|
||||
}
|
||||
surface = &win->surface[currRect->wRect.left - win->rect.x] + ((currRect->wRect.top - win->rect.y) * win->width);
|
||||
} else {
|
||||
surface = new BYTE[height * width](); // black background
|
||||
widthFrom = width; // replace with rectangle
|
||||
}
|
||||
|
||||
Draw(win, surface, width, height, widthFrom, toBuffer, toWidth, currRect->wRect, updateRect);
|
||||
|
||||
if (win->wID == 0) delete[] surface;
|
||||
|
||||
currRect = currRect->nextRect;
|
||||
}
|
||||
|
||||
while (rects) {
|
||||
// copy all rectangles from the buffer to the DD surface (buffering)
|
||||
if (!toBuffer) {
|
||||
int width = (rects->rect.offx - rects->rect.x) + 1;
|
||||
int height = (rects->rect.offy - rects->rect.y) + 1;
|
||||
int widthFrom = toWidth;
|
||||
|
||||
Graphics::UpdateDDSurface(&GetBuffer()[rects->rect.x] + (rects->rect.y * widthFrom), width, height, widthFrom, &rects->wRect);
|
||||
}
|
||||
fo::RectList* next = rects->nextRect;
|
||||
fo::sf_rect_free(rects);
|
||||
rects = next;
|
||||
}
|
||||
|
||||
if (!toBuffer && !*(DWORD*)FO_VAR_doing_refresh_all && !fo::var::mouse_is_hidden && fo::func::mouse_in(updateRect->left, updateRect->top, updateRect->right, updateRect->bottom)) {
|
||||
fo::func::mouse_show();
|
||||
}
|
||||
}
|
||||
|
||||
static __declspec(naked) void GNW_win_refresh_hack() {
|
||||
__asm {
|
||||
push ebx; // toBuffer
|
||||
mov ecx, eax;
|
||||
call sf_GNW_win_refresh;
|
||||
pop ecx;
|
||||
retn;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static double fadeMulti;
|
||||
|
||||
static __declspec(naked) void palette_fade_to_hook() {
|
||||
__asm {
|
||||
push ebx; // _fade_steps
|
||||
fild [esp];
|
||||
fmul fadeMulti;
|
||||
fistp [esp];
|
||||
pop ebx;
|
||||
jmp fo::funcoffs::fadeSystemPalette_;
|
||||
}
|
||||
}
|
||||
|
||||
void GameRender::init() {
|
||||
fadeMulti = GetConfigInt("Graphics", "FadeMultiplier", 100);
|
||||
if (fadeMulti != 100) {
|
||||
dlog("Applying fade patch.", DL_INIT);
|
||||
HookCall(0x493B16, palette_fade_to_hook);
|
||||
fadeMulti = ((double)fadeMulti) / 100.0;
|
||||
dlogr(" Done", DL_INIT);
|
||||
}
|
||||
|
||||
// Replace the srcCopy_ function with a pure MMX implementation
|
||||
MakeJump(0x4D36D4, fo::func::buf_to_buf); // buf_to_buf_
|
||||
// Replace the transSrcCopy_ function
|
||||
MakeJump(0x4D3704, fo::func::trans_buf_to_buf); // trans_buf_to_buf_
|
||||
|
||||
// Enable support for transparent interface windows
|
||||
SafeWriteBatch<WORD>(0x9090, {
|
||||
0x4D5D46, // win_init_ (create screen_buffer)
|
||||
0x4D75E6 // win_clip_ (remove _buffering checking)
|
||||
});
|
||||
|
||||
// Custom implementation of the GNW_win_refresh function
|
||||
MakeJump(0x4D6FD9, GNW_win_refresh_hack, 1);
|
||||
// Replace _screendump_buf with _screen_buffer for creating screenshots
|
||||
SafeWriteBatch<DWORD>(FO_VAR_screen_buffer, {0x4C8FD1, 0x4C900D});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
/*
|
||||
* sfall
|
||||
* Copyright (C) 2008-2020 The sfall team
|
||||
*
|
||||
* This program 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.
|
||||
*
|
||||
* This program 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 this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "..\..\main.h"
|
||||
#include "..\..\FalloutEngine\Fallout2.h"
|
||||
|
||||
#include "..\..\Game\render.h"
|
||||
|
||||
#include "WindowRender.h"
|
||||
|
||||
namespace sfall
|
||||
{
|
||||
|
||||
class OverlaySurface
|
||||
{
|
||||
private:
|
||||
long size = 0;
|
||||
long surfWidth;
|
||||
long allocSize;
|
||||
BYTE* surface = nullptr;
|
||||
|
||||
public:
|
||||
long winType = -1;
|
||||
|
||||
BYTE* Surface() { return surface; }
|
||||
|
||||
void CreateSurface(fo::Window* win, long winType) {
|
||||
this->winType = winType;
|
||||
this->surfWidth = win->width;
|
||||
this->size = win->height * win->width;
|
||||
|
||||
if (surface != nullptr) {
|
||||
if (size <= allocSize) {
|
||||
std::memset(surface, 0, size);
|
||||
return;
|
||||
}
|
||||
delete[] surface;
|
||||
}
|
||||
|
||||
this->allocSize = size;
|
||||
surface = new BYTE[size]();
|
||||
}
|
||||
|
||||
void ClearSurface() {
|
||||
if (surface != nullptr) std::memset(surface, 0, size);
|
||||
}
|
||||
|
||||
void ClearSurface(Rectangle &rect) {
|
||||
if (surface != nullptr) {
|
||||
if (rect.width > surfWidth || rect.height > (size / surfWidth)) return; // going beyond the surface size
|
||||
BYTE* surf = surface + (surfWidth * rect.y) + rect.x;
|
||||
|
||||
size_t sizeD = rect.width >> 2;
|
||||
size_t sizeB = rect.width & 3;
|
||||
size_t strideD = sizeD << 2;
|
||||
size_t stride = surfWidth - rect.width;
|
||||
|
||||
long height = rect.height;
|
||||
while (height--) {
|
||||
if (sizeD) {
|
||||
__stosd((DWORD*)surf, 0, sizeD);
|
||||
surf += strideD;
|
||||
}
|
||||
if (sizeB) {
|
||||
__stosb(surf, 0, sizeB);
|
||||
surf += sizeB;
|
||||
}
|
||||
surf += stride;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
void DestroySurface() {
|
||||
delete[] surface;
|
||||
surface = nullptr;
|
||||
}
|
||||
|
||||
~OverlaySurface() {
|
||||
delete[] surface;
|
||||
}
|
||||
} overlaySurfaces[5];
|
||||
|
||||
static long indexPosition = 0;
|
||||
|
||||
void WindowRender::CreateOverlaySurface(fo::Window* win, long winType) {
|
||||
if (win->randY) return;
|
||||
if (overlaySurfaces[indexPosition].winType == winType) {
|
||||
overlaySurfaces[indexPosition].ClearSurface();
|
||||
} else {
|
||||
if (++indexPosition == 5) indexPosition = 0;
|
||||
overlaySurfaces[indexPosition].CreateSurface(win, winType);
|
||||
}
|
||||
win->randY = reinterpret_cast<long*>(&overlaySurfaces[indexPosition]);
|
||||
}
|
||||
|
||||
BYTE* WindowRender::GetOverlaySurface(fo::Window* win) {
|
||||
return reinterpret_cast<OverlaySurface*>(win->randY)->Surface();
|
||||
}
|
||||
|
||||
void WindowRender::ClearOverlay(fo::Window* win) {
|
||||
if (win->randY) reinterpret_cast<OverlaySurface*>(win->randY)->ClearSurface();
|
||||
}
|
||||
|
||||
void WindowRender::ClearOverlay(fo::Window* win, Rectangle &rect) {
|
||||
if (win->randY) {
|
||||
reinterpret_cast<OverlaySurface*>(win->randY)->ClearSurface(rect);
|
||||
fo::BoundRect updateRect = rect;
|
||||
updateRect.x += win->rect.x;
|
||||
updateRect.y += win->rect.y;
|
||||
updateRect.offx += win->rect.x;
|
||||
updateRect.offy += win->rect.y;
|
||||
game::Render::GNW_win_refresh(win, reinterpret_cast<RECT*>(&updateRect), 0);
|
||||
}
|
||||
}
|
||||
|
||||
void WindowRender::DestroyOverlaySurface(fo::Window* win) {
|
||||
if (win->randY) {
|
||||
auto overlay = reinterpret_cast<OverlaySurface*>(win->randY);
|
||||
win->randY = nullptr;
|
||||
overlay->winType = -1;
|
||||
overlay->DestroySurface();
|
||||
game::Render::GNW_win_refresh(win, &win->wRect, 0);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
static double fadeMulti;
|
||||
|
||||
static __declspec(naked) void palette_fade_to_hook() {
|
||||
__asm {
|
||||
push ebx; // _fade_steps
|
||||
fild [esp];
|
||||
fmul fadeMulti;
|
||||
fistp [esp];
|
||||
pop ebx;
|
||||
jmp fo::funcoffs::fadeSystemPalette_;
|
||||
}
|
||||
}
|
||||
|
||||
void WindowRender::init() {
|
||||
fadeMulti = GetConfigInt("Graphics", "FadeMultiplier", 100);
|
||||
if (fadeMulti != 100) {
|
||||
dlog("Applying fade patch.", DL_INIT);
|
||||
HookCall(0x493B16, palette_fade_to_hook);
|
||||
fadeMulti = ((double)fadeMulti) / 100.0;
|
||||
dlogr(" Done", DL_INIT);
|
||||
}
|
||||
|
||||
// Enable support for transparent interface windows
|
||||
SafeWriteBatch<WORD>(0x9090, {
|
||||
0x4D5D46, // win_init_ (create screen_buffer)
|
||||
0x4D75E6 // win_clip_ (remove _buffering checking)
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -21,7 +21,7 @@
|
||||
namespace sfall
|
||||
{
|
||||
|
||||
class GameRender {
|
||||
class WindowRender {
|
||||
public:
|
||||
static void init();
|
||||
|
||||
@@ -7,5 +7,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "Game\inventory.h"
|
||||
#include "Game\render.h"
|
||||
#include "Game\skills.h"
|
||||
#include "Game\stats.h"
|
||||
|
||||
+4
-2
@@ -292,6 +292,7 @@
|
||||
<ClInclude Include="FalloutEngine\Functions.h" />
|
||||
<ClInclude Include="FalloutEngine\Functions_def.h" />
|
||||
<ClInclude Include="Game\inventory.h" />
|
||||
<ClInclude Include="Game\render.h" />
|
||||
<ClInclude Include="Game\skills.h" />
|
||||
<ClInclude Include="Game\stats.h" />
|
||||
<ClInclude Include="Modules\CritterPoison.h" />
|
||||
@@ -322,7 +323,7 @@
|
||||
<ClInclude Include="Modules\SpeedPatch.h" />
|
||||
<ClInclude Include="Modules\SubModules\CombatBlock.h" />
|
||||
<ClInclude Include="Modules\SubModules\EnginePerks.h" />
|
||||
<ClInclude Include="Modules\SubModules\GameRender.h" />
|
||||
<ClInclude Include="Modules\SubModules\WindowRender.h" />
|
||||
<ClInclude Include="Modules\Worldmap.h" />
|
||||
<ClInclude Include="Modules\ScriptExtender.h" />
|
||||
<ClInclude Include="Modules\BarBoxes.h" />
|
||||
@@ -395,6 +396,7 @@
|
||||
<ClCompile Include="FalloutEngine\Variables.cpp" />
|
||||
<ClCompile Include="FalloutEngine\Functions.cpp" />
|
||||
<ClCompile Include="Game\inventory.cpp" />
|
||||
<ClCompile Include="Game\render.cpp" />
|
||||
<ClCompile Include="Game\skills.cpp" />
|
||||
<ClCompile Include="Game\stats.cpp" />
|
||||
<ClCompile Include="Modules\CritterPoison.cpp" />
|
||||
@@ -424,7 +426,7 @@
|
||||
<ClCompile Include="Modules\SpeedPatch.cpp" />
|
||||
<ClCompile Include="Modules\SubModules\CombatBlock.cpp" />
|
||||
<ClCompile Include="Modules\SubModules\EnginePerks.cpp" />
|
||||
<ClCompile Include="Modules\SubModules\GameRender.cpp" />
|
||||
<ClCompile Include="Modules\SubModules\WindowRender.cpp" />
|
||||
<ClCompile Include="Modules\Worldmap.cpp" />
|
||||
<ClCompile Include="Modules\ScriptExtender.cpp" />
|
||||
<ClCompile Include="Modules\BarBoxes.cpp" />
|
||||
|
||||
@@ -304,7 +304,7 @@
|
||||
<ClInclude Include="Modules\MetaruleExtender.h">
|
||||
<Filter>Modules</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Modules\SubModules\GameRender.h">
|
||||
<ClInclude Include="Modules\SubModules\WindowRender.h">
|
||||
<Filter>Modules\SubModules</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Modules\CritterPoison.h">
|
||||
@@ -322,6 +322,9 @@
|
||||
<ClInclude Include="Game\stats.h">
|
||||
<Filter>Game</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Game\render.h">
|
||||
<Filter>Game</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ReplacementFuncs.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
@@ -578,7 +581,7 @@
|
||||
<ClCompile Include="Modules\MetaruleExtender.cpp">
|
||||
<Filter>Modules</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Modules\SubModules\GameRender.cpp">
|
||||
<ClCompile Include="Modules\SubModules\WindowRender.cpp">
|
||||
<Filter>Modules\SubModules</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Modules\CritterPoison.cpp">
|
||||
@@ -596,6 +599,9 @@
|
||||
<ClCompile Include="Game\stats.cpp">
|
||||
<Filter>Game</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Game\render.cpp">
|
||||
<Filter>Game</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="version.rc" />
|
||||
|
||||
@@ -172,6 +172,7 @@ int SetConfigInt(const char* section, const char* setting, int value) {
|
||||
|
||||
void InitReplacementHacks() {
|
||||
game::Inventory::init();
|
||||
game::Render::init();
|
||||
game::Skills::init();
|
||||
game::Stats::init();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user