Skip to content

Commit

Permalink
Fix motion prediction of shadows, rework how MoP is applied to units …
Browse files Browse the repository at this point in the history
…a bit, and clean up.
  • Loading branch information
bolrog committed May 25, 2021
1 parent 42484d5 commit 6fd4c53
Show file tree
Hide file tree
Showing 6 changed files with 119 additions and 41 deletions.
54 changes: 31 additions & 23 deletions src/d2dx/D2DXContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -413,9 +413,7 @@ void D2DXContext::OnBufferSwap()
if (IsFeatureEnabled(Feature::UnitMotionPrediction) &&
_majorGameState == MajorGameState::InGame)
{
const OffsetF offset = _unitMotionPredictor.GetOffset(_gameHelper->GetPlayerUnit());
const OffsetF scaleFactors{ 32.0f / sqrtf(2.0f), 16.0f / sqrtf(2.0f) };
const OffsetF screenOffsetf = scaleFactors * OffsetF{ offset.x - offset.y, offset.x + offset.y } + 0.5f;
const Offset offset = _unitMotionPredictor.GetOffset(_gameHelper->GetPlayerUnit());

for (uint32_t i = 0; i < _batchCount; ++i)
{
Expand All @@ -430,8 +428,8 @@ void D2DXContext::OnBufferSwap()
for (uint32_t j = 0; j < batchVertexCount; ++j)
{
_vertices.items[vertexIndex++].AddOffset(
(int32_t)-screenOffsetf.x,
(int32_t)-screenOffsetf.y);
-offset.x,
-offset.y);
}
}
}
Expand Down Expand Up @@ -898,17 +896,6 @@ void D2DXContext::OnDrawVertexArrayContiguous(
return;
}

Offset screenOffset = { 0,0 };
if (_majorGameState == MajorGameState::InGame)
{
if (currentlyDrawingUnit && currentlyDrawingUnit != _gameHelper->GetPlayerUnit())
{
auto drawOffset = _unitMotionPredictor.GetOffset(currentlyDrawingUnit);
screenOffset.x = (int32_t)(32.0f * (drawOffset.x - drawOffset.y) / sqrt(2.0f) + 0.5f);
screenOffset.y = (int32_t)(16.0f * (drawOffset.x + drawOffset.y) / sqrt(2.0f) + 0.5f);
}
}

Batch batch = PrepareBatchForSubmit(_scratchBatch, PrimitiveType::Triangles, 6, gameContext);

if (!batch.IsValid())
Expand All @@ -929,7 +916,7 @@ void D2DXContext::OnDrawVertexArrayContiguous(

for (int32_t i = 0; i < 4; ++i)
{
v.SetPosition((int32_t)d2Vertices[i].x + screenOffset.x, (int32_t)d2Vertices[i].y + screenOffset.y);
v.SetPosition((int32_t)d2Vertices[i].x, (int32_t)d2Vertices[i].y);
v.SetTexcoord((int32_t)d2Vertices[i].s >> _glideState.stShift, (int32_t)d2Vertices[i].t >> _glideState.stShift);
v.SetColor(maskedConstantColor | (d2Vertices[i].color & iteratedColorMask));
pVertices[i] = v;
Expand Down Expand Up @@ -1326,31 +1313,50 @@ void D2DXContext::EndDrawText()
}

_Use_decl_annotations_
void D2DXContext::BeginDrawImage(
Offset D2DXContext::BeginDrawImage(
const D2::CellContext* cellContext,
uint32_t drawMode,
Offset pos)
Offset pos,
D2Function d2Function)
{
Offset offset{ 0,0 };

if (_isDrawingText)
{
return;
return offset;
}

if (currentlyDrawingUnit)
{
_unitMotionPredictor.SetUnitScreenPos(currentlyDrawingUnit, pos.x, pos.y);

if (currentlyDrawingUnit == _gameHelper->GetPlayerUnit())
{
// The player unit itself.
_scratchBatch.SetTextureCategory(TextureCategory::Player);
_playerScreenPos = pos;
}
else
{
offset = _unitMotionPredictor.GetOffset(currentlyDrawingUnit);
}
}
else
{
const bool isPlayerShadow = _playerScreenPos.x > 0 && max(abs(pos.x - _playerScreenPos.x), abs(pos.y - _playerScreenPos.y)) < 4;
if (isPlayerShadow)
if (d2Function == D2Function::D2Gfx_DrawShadow)
{
_scratchBatch.SetTextureCategory(TextureCategory::Player);
const bool isPlayerShadow =
_playerScreenPos.x > 0 &&
max(abs(pos.x - _playerScreenPos.x), abs(pos.y - _playerScreenPos.y)) < 8;

if (isPlayerShadow)
{
_scratchBatch.SetTextureCategory(TextureCategory::Player);
}
else
{
offset = _unitMotionPredictor.GetOffsetForShadow(pos.x, pos.y);
}
}
else
{
Expand All @@ -1364,6 +1370,8 @@ void D2DXContext::BeginDrawImage(
}
}
}

return offset;
}

void D2DXContext::EndDrawImage()
Expand Down
5 changes: 3 additions & 2 deletions src/d2dx/D2DXContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -194,10 +194,11 @@ namespace d2dx

virtual void EndDrawText() override;

virtual void BeginDrawImage(
virtual Offset BeginDrawImage(
_In_ const D2::CellContext* cellContext,
_In_ uint32_t drawMode,
_In_ Offset pos) override;
_In_ Offset pos,
_In_ D2Function d2Function) override;

virtual void EndDrawImage() override;

Expand Down
20 changes: 12 additions & 8 deletions src/d2dx/Detours.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -315,12 +315,14 @@ void __stdcall D2Gfx_DrawImage_Hooked(

auto d2InterceptionHandler = GetD2InterceptionHandler();

Offset offset{ 0,0 };

if (d2InterceptionHandler)
{
d2InterceptionHandler->BeginDrawImage(cellContext, nDrawMode, { nXpos, nYpos });
offset = d2InterceptionHandler->BeginDrawImage(cellContext, nDrawMode, { nXpos, nYpos }, D2Function::D2Gfx_DrawImage);
}

D2Gfx_DrawImage_Real(cellContext, nXpos, nYpos, dwGamma, nDrawMode, pPalette);
D2Gfx_DrawImage_Real(cellContext, nXpos + offset.x, nYpos + offset.y, dwGamma, nDrawMode, pPalette);

if (d2InterceptionHandler)
{
Expand All @@ -339,7 +341,7 @@ void __stdcall D2Gfx_DrawClippedImage_Hooked(

if (d2InterceptionHandler)
{
d2InterceptionHandler->BeginDrawImage(cellContext, (uint32_t)nDrawMode, { nXpos, nYpos });
d2InterceptionHandler->BeginDrawImage(cellContext, (uint32_t)nDrawMode, { nXpos, nYpos }, D2Function::D2Gfx_DrawClippedImage);
}

D2Gfx_DrawClippedImage_Real(cellContext, nXpos, nYpos, pCropRect, nDrawMode);
Expand Down Expand Up @@ -378,7 +380,7 @@ void __stdcall D2Gfx_DrawShiftedImage_Hooked(

if (d2InterceptionHandler)
{
d2InterceptionHandler->BeginDrawImage(cellContext, (uint32_t)nDrawMode, { nXpos, nYpos });
d2InterceptionHandler->BeginDrawImage(cellContext, (uint32_t)nDrawMode, { nXpos, nYpos }, D2Function::D2Gfx_DrawShiftedImage);
}

D2Gfx_DrawShiftedImage_Real(cellContext, nXpos, nYpos, dwGamma, nDrawMode, nGlobalPaletteShift);
Expand Down Expand Up @@ -410,7 +412,7 @@ void __stdcall D2Gfx_DrawVerticalCropImage_Hooked(

if (d2InterceptionHandler)
{
d2InterceptionHandler->BeginDrawImage(cellContext, (uint32_t)nDrawMode, { nXpos, nYpos });
d2InterceptionHandler->BeginDrawImage(cellContext, (uint32_t)nDrawMode, { nXpos, nYpos }, D2Function::D2Gfx_DrawVerticalCropImage);
}

D2Gfx_DrawVerticalCropImage_Real(cellContext, nXpos, nYpos, nSkipLines, nDrawLines, nDrawMode);
Expand All @@ -431,7 +433,7 @@ void __stdcall D2Gfx_DrawImageFast_Hooked(

if (d2InterceptionHandler)
{
d2InterceptionHandler->BeginDrawImage(cellContext, (uint32_t)-1, { nXpos, nYpos });
d2InterceptionHandler->BeginDrawImage(cellContext, (uint32_t)-1, { nXpos, nYpos }, D2Function::D2Gfx_DrawImageFast);
}

D2Gfx_DrawImageFast_Real(cellContext, nXpos, nYpos, nPaletteIndex);
Expand All @@ -458,12 +460,14 @@ void __stdcall D2Gfx_DrawShadow_Hooked(

auto d2InterceptionHandler = GetD2InterceptionHandler();

Offset offset{ 0,0 };

if (d2InterceptionHandler)
{
d2InterceptionHandler->BeginDrawImage(cellContext, (uint32_t)-1, { nXpos, nYpos });
offset = d2InterceptionHandler->BeginDrawImage(cellContext, (uint32_t)-1, { nXpos, nYpos }, D2Function::D2Gfx_DrawShadow);
}

D2Gfx_DrawShadow_Real(cellContext, nXpos, nYpos);
D2Gfx_DrawShadow_Real(cellContext, nXpos + offset.x, nYpos + offset.y);

if (d2InterceptionHandler)
{
Expand Down
6 changes: 4 additions & 2 deletions src/d2dx/ID2InterceptionHandler.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
#pragma once

#include "IGameHelper.h"
#include "Types.h"
#include "D2Types.h"

Expand All @@ -34,10 +35,11 @@ namespace d2dx

virtual void EndDrawText() = 0;

virtual void BeginDrawImage(
virtual Offset BeginDrawImage(
_In_ const D2::CellContext* cellContext,
_In_ uint32_t drawMode,
_In_ Offset pos) = 0;
_In_ Offset pos,
_In_ D2Function d2Function) = 0;

virtual void EndDrawImage() = 0;
};
Expand Down
61 changes: 56 additions & 5 deletions src/d2dx/UnitMotionPredictor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ UnitMotionPredictor::UnitMotionPredictor(
const std::shared_ptr<IGameHelper>& gameHelper) :
_gameHelper{ gameHelper },
_unitIdAndTypes{ 1024, true },
_unitMotions{ 1024, true }
_unitMotions{ 1024, true },
_unitScreenPositions{ 1024, true }
{
}

Expand Down Expand Up @@ -157,7 +158,7 @@ void UnitMotionPredictor::Update(
}

_Use_decl_annotations_
OffsetF UnitMotionPredictor::GetOffset(
Offset UnitMotionPredictor::GetOffset(
const D2::UnitAny* unit)
{
int32_t unitIndex = -1;
Expand Down Expand Up @@ -194,9 +195,59 @@ OffsetF UnitMotionPredictor::GetOffset(

if (unitIndex < 0)
{
return { 0.0f, 0.0f };
return { 0, 0 };
}

UnitMotion& um = _unitMotions.items[unitIndex];
return { (um.predictedPos.x - um.lastPos.x) / 65536.0f, (um.predictedPos.y - um.lastPos.y) / 65536.0f };
return _unitMotions.items[unitIndex].GetOffset();
}

_Use_decl_annotations_
void UnitMotionPredictor::SetUnitScreenPos(
const D2::UnitAny* unit,
int32_t x,
int32_t y)
{
auto unitId = _gameHelper->GetUnitId(unit);
auto unitType = _gameHelper->GetUnitType(unit);

for (int32_t unitIndex = 0; unitIndex < _unitsCount; ++unitIndex)
{
if (_unitIdAndTypes.items[unitIndex].unitId == (uint16_t)unitId &&
_unitIdAndTypes.items[unitIndex].unitType == (uint16_t)unitType)
{
_unitScreenPositions.items[unitIndex] = { x, y };
break;
}
}
}

_Use_decl_annotations_
Offset UnitMotionPredictor::GetOffsetForShadow(
_In_ int32_t x,
_In_ int32_t y)
{
for (int32_t i = 0; i < _unitsCount; ++i)
{
if (!_unitIdAndTypes.items[i].unitId)
{
continue;
}

const int32_t dist = max(abs(_unitScreenPositions.items[i].x - x), abs(_unitScreenPositions.items[i].y - y));

if (dist < 8)
{
return _unitMotions.items[i].GetOffset();
}
}

return { 0, 0 };
}

Offset UnitMotionPredictor::UnitMotion::GetOffset() const
{
const OffsetF offset{ (predictedPos.x - lastPos.x) / 65536.0f, (predictedPos.y - lastPos.y) / 65536.0f };
const OffsetF scaleFactors{ 32.0f / sqrtf(2.0f), 16.0f / sqrtf(2.0f) };
const OffsetF screenOffset = scaleFactors * OffsetF{ offset.x - offset.y, offset.x + offset.y } + 0.5f;
return { (int32_t)screenOffset.x, (int32_t)screenOffset.y };
}
14 changes: 13 additions & 1 deletion src/d2dx/UnitMotionPredictor.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,9 +32,18 @@ namespace d2dx
void Update(
_In_ IRenderContext* renderContext);

OffsetF GetOffset(
Offset GetOffset(
_In_ const D2::UnitAny* unit);

void SetUnitScreenPos(
_In_ const D2::UnitAny* unit,
_In_ int32_t x,
_In_ int32_t y);

Offset GetOffsetForShadow(
_In_ int32_t x,
_In_ int32_t y);

private:
struct UnitIdAndType final
{
Expand All @@ -44,6 +53,8 @@ namespace d2dx

struct UnitMotion final
{
Offset GetOffset() const;

uint32_t lastUsedFrame = 0;
Offset lastPos = { 0, 0 };
Offset velocity = { 0, 0 };
Expand All @@ -56,6 +67,7 @@ namespace d2dx
uint32_t _frame = 0;
Buffer<UnitIdAndType> _unitIdAndTypes;
Buffer<UnitMotion> _unitMotions;
Buffer<Offset> _unitScreenPositions;
int32_t _unitsCount = 0;
};
}

0 comments on commit 6fd4c53

Please sign in to comment.