This commit is contained in:
1 parent
f1b253e842
commit
039dcaa381
3 files changed
+300
-1
No files matched your search
@@ -28,7 +28,8 @@
|
|||||||
"src/utils/KromOGLUtils.pas",
|
"src/utils/KromOGLUtils.pas",
|
||||||
"src/render/KM_RenderPool.pas",
|
"src/render/KM_RenderPool.pas",
|
||||||
"src/gui/KM_InterfaceGame.pas",
|
"src/gui/KM_InterfaceGame.pas",
|
||||||
"src/render/KM_RenderTerrain.pas"
|
"src/render/KM_RenderTerrain.pas",
|
||||||
|
"src/res/KM_ResInterpolation.pas"
|
||||||
],
|
],
|
||||||
"source_paths": [
|
"source_paths": [
|
||||||
"code/resource"
|
"code/resource"
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
{"kind": "file", "path": "data/Sprites/Tileset.rxx"},
|
{"kind": "file", "path": "data/Sprites/Tileset.rxx"},
|
||||||
{"kind": "file", "path": "data/defines/unit.dat"},
|
{"kind": "file", "path": "data/defines/unit.dat"},
|
||||||
{"kind": "file", "path": "data/defines/houses.dat"},
|
{"kind": "file", "path": "data/defines/houses.dat"},
|
||||||
|
{"kind": "file", "path": "data/defines/interp.dat"},
|
||||||
{"kind": "file", "path": "data/defines/tiles.json"},
|
{"kind": "file", "path": "data/defines/tiles.json"},
|
||||||
{"kind": "file", "path": "data/gfx/pal0.bbm"},
|
{"kind": "file", "path": "data/gfx/pal0.bbm"},
|
||||||
{"kind": "file", "path": "data/defines/mapelem.dat"},
|
{"kind": "file", "path": "data/defines/mapelem.dat"},
|
||||||
|
|||||||
@@ -0,0 +1,297 @@
|
|||||||
|
unit KM_ResInterpolation;
|
||||||
|
{$I KaM_Remake.inc}
|
||||||
|
interface
|
||||||
|
uses
|
||||||
|
Classes, SysUtils, Math,
|
||||||
|
KM_Defaults, KM_Points, KM_ResTypes, KM_ResMapElements, KM_ResHouses;
|
||||||
|
|
||||||
|
const
|
||||||
|
INTERP_LEVEL = 8;
|
||||||
|
|
||||||
|
type
|
||||||
|
TKMInterpolation = array[1..30, 0..INTERP_LEVEL-1] of Integer;
|
||||||
|
TKMUnitActionInterp = array[UNIT_MIN..UNIT_MAX, UNIT_ACT_MIN..UNIT_ACT_MAX, dirN..dirNW] of TKMInterpolation;
|
||||||
|
TKMSerfCarryInterp = array[WARE_MIN..WARE_MAX, dirN..dirNW] of TKMInterpolation;
|
||||||
|
TKMUnitThoughtInterp = array[TKMUnitThought] of TKMInterpolation;
|
||||||
|
TKMTreeInterp = array[0..OBJECTS_CNT] of TKMInterpolation;
|
||||||
|
TKMHouseInterp = array[HOUSE_MIN..HOUSE_MAX, TKMHouseActionType] of TKMInterpolation;
|
||||||
|
TKMBeastInterp = array[1..3,1..5,1..3] of TKMInterpolation;
|
||||||
|
|
||||||
|
TKMResInterpolation = class
|
||||||
|
private
|
||||||
|
fUnitActions: TKMUnitActionInterp;
|
||||||
|
fSerfCarry: TKMSerfCarryInterp;
|
||||||
|
fUnitThoughts: TKMUnitThoughtInterp;
|
||||||
|
fTrees: TKMTreeInterp;
|
||||||
|
fHouses: TKMHouseInterp;
|
||||||
|
fBeasts: TKMBeastInterp;
|
||||||
|
fInterpolationDataEligible: Boolean;
|
||||||
|
public
|
||||||
|
procedure LoadFromFile(const FileName: string);
|
||||||
|
|
||||||
|
function UnitAction(aUnit: TKMUnitType; aAct: TKMUnitActionType; aDir: TKMDirection; aStep: Integer; aStepFrac: Single): Integer;
|
||||||
|
function UnitActionByPercent(aUnit: TKMUnitType; aAct: TKMUnitActionType; aDir: TKMDirection; aPercent: Single): Integer;
|
||||||
|
function SerfCarry(aWare: TKMWareType; aDir: TKMDirection; aStep: Integer; aStepFrac: Single): Integer;
|
||||||
|
function UnitThought(aTh: TKMUnitThought; aStep: Integer; aStepFrac: Single): Integer;
|
||||||
|
function Tree(aObject: Integer; aStep: Integer; aStepFrac: Single; aLoop: Boolean): Integer;
|
||||||
|
function House(aHT: TKMHouseType; aAct: TKMHouseActionType; aStep: Integer; aStepFrac: Single): Integer;
|
||||||
|
function Beast(aHT: TKMHouseType; BeastId, BeastAge, aStep: Integer; aStepFrac: Single): Integer;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
implementation
|
||||||
|
uses
|
||||||
|
KM_CommonClasses, KM_Resource, KM_CommonTypes, KM_Pics, KM_ResUnits, KM_GameSettings,
|
||||||
|
KaMResourceInput;
|
||||||
|
|
||||||
|
|
||||||
|
type
|
||||||
|
EInterpolationDataFormatError = class(Exception);
|
||||||
|
|
||||||
|
TInterpolationStaging = record
|
||||||
|
UnitActions: TKMUnitActionInterp;
|
||||||
|
SerfCarry: TKMSerfCarryInterp;
|
||||||
|
UnitThoughts: TKMUnitThoughtInterp;
|
||||||
|
Trees: TKMTreeInterp;
|
||||||
|
Houses: TKMHouseInterp;
|
||||||
|
Beasts: TKMBeastInterp;
|
||||||
|
end;
|
||||||
|
PInterpolationStaging = ^TInterpolationStaging;
|
||||||
|
|
||||||
|
|
||||||
|
procedure CheckInterpolationMarker(aStream: TKMemoryStreamBinary; const aExpected: string);
|
||||||
|
var
|
||||||
|
markerLength: Word;
|
||||||
|
markerBytes: array[0..13] of Byte;
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
aStream.ReadBuffer(markerLength, SizeOf(Word));
|
||||||
|
if markerLength <> Length(aExpected) then
|
||||||
|
raise EInterpolationDataFormatError.Create('Invalid interpolation data marker');
|
||||||
|
|
||||||
|
aStream.ReadBuffer(markerBytes[0], markerLength);
|
||||||
|
for i := 1 to Length(aExpected) do
|
||||||
|
if markerBytes[i - 1] <> Ord(aExpected[i]) then
|
||||||
|
raise EInterpolationDataFormatError.Create('Invalid interpolation data marker');
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
{ TKMResInterpolation }
|
||||||
|
procedure TKMResInterpolation.LoadFromFile(const FileName: string);
|
||||||
|
var
|
||||||
|
S: TKMemoryStreamBinary;
|
||||||
|
stagingPtr: PInterpolationStaging;
|
||||||
|
effectiveReference: string;
|
||||||
|
begin
|
||||||
|
fInterpolationDataEligible := False;
|
||||||
|
|
||||||
|
if FileName = ExeDir + 'data' + PathDelim + 'defines' + PathDelim + 'interp.dat' then
|
||||||
|
effectiveReference := KaMResolvePackagedResource('data/defines/interp.dat')
|
||||||
|
else
|
||||||
|
effectiveReference := FileName;
|
||||||
|
|
||||||
|
S := TKMemoryStreamBinary.Create;
|
||||||
|
try
|
||||||
|
S.LoadFromFile(effectiveReference);
|
||||||
|
New(stagingPtr);
|
||||||
|
try
|
||||||
|
CheckInterpolationMarker(S, 'UnitAction');
|
||||||
|
S.ReadBuffer(stagingPtr^.UnitActions, SizeOf(TKMUnitActionInterp));
|
||||||
|
|
||||||
|
CheckInterpolationMarker(S, 'SerfCarry ');
|
||||||
|
S.ReadBuffer(stagingPtr^.SerfCarry, SizeOf(TKMSerfCarryInterp));
|
||||||
|
|
||||||
|
CheckInterpolationMarker(S, 'UnitThoughts ');
|
||||||
|
S.ReadBuffer(stagingPtr^.UnitThoughts, SizeOf(TKMUnitThoughtInterp));
|
||||||
|
|
||||||
|
CheckInterpolationMarker(S, 'Trees ');
|
||||||
|
S.ReadBuffer(stagingPtr^.Trees, SizeOf(TKMTreeInterp));
|
||||||
|
|
||||||
|
CheckInterpolationMarker(S, 'Houses');
|
||||||
|
S.ReadBuffer(stagingPtr^.Houses, SizeOf(TKMHouseInterp));
|
||||||
|
|
||||||
|
CheckInterpolationMarker(S, 'Beasts');
|
||||||
|
S.ReadBuffer(stagingPtr^.Beasts, SizeOf(TKMBeastInterp));
|
||||||
|
|
||||||
|
System.Move(stagingPtr^.UnitActions, fUnitActions, SizeOf(TKMUnitActionInterp));
|
||||||
|
System.Move(stagingPtr^.SerfCarry, fSerfCarry, SizeOf(TKMSerfCarryInterp));
|
||||||
|
System.Move(stagingPtr^.UnitThoughts, fUnitThoughts, SizeOf(TKMUnitThoughtInterp));
|
||||||
|
System.Move(stagingPtr^.Trees, fTrees, SizeOf(TKMTreeInterp));
|
||||||
|
System.Move(stagingPtr^.Houses, fHouses, SizeOf(TKMHouseInterp));
|
||||||
|
System.Move(stagingPtr^.Beasts, fBeasts, SizeOf(TKMBeastInterp));
|
||||||
|
fInterpolationDataEligible := True;
|
||||||
|
finally
|
||||||
|
Dispose(stagingPtr);
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
S.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TKMResInterpolation.UnitAction(aUnit: TKMUnitType; aAct: TKMUnitActionType; aDir: TKMDirection; aStep: Integer;
|
||||||
|
aStepFrac: Single): Integer;
|
||||||
|
var
|
||||||
|
A: TKMAnimLoop;
|
||||||
|
step, subStep, baseFrame, candidate: Integer;
|
||||||
|
begin
|
||||||
|
A := gRes.Units[aUnit].UnitAnim[aAct, aDir];
|
||||||
|
|
||||||
|
step := aStep mod Byte(A.Count) + 1;
|
||||||
|
subStep := EnsureRange(Floor(INTERP_LEVEL*aStepFrac), 0, INTERP_LEVEL-1);
|
||||||
|
baseFrame := A.Step[step] + 1;
|
||||||
|
|
||||||
|
if not fInterpolationDataEligible then
|
||||||
|
Exit(baseFrame);
|
||||||
|
if not gGameSettings.GFX.InterpolatedAnimations then
|
||||||
|
Exit(baseFrame);
|
||||||
|
|
||||||
|
candidate := fUnitActions[aUnit, aAct, aDir, step, subStep];
|
||||||
|
if candidate <= 0 then Exit(baseFrame);
|
||||||
|
if candidate > gRes.Sprites[rxUnits].RXData.Count then Exit(baseFrame);
|
||||||
|
if gRes.Sprites[rxUnits].RXData.Size[candidate].X = 0 then Exit(baseFrame);
|
||||||
|
Result := candidate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TKMResInterpolation.UnitActionByPercent(aUnit: TKMUnitType; aAct: TKMUnitActionType; aDir: TKMDirection; aPercent: Single): Integer;
|
||||||
|
var
|
||||||
|
count: Integer;
|
||||||
|
fracStep: Single;
|
||||||
|
begin
|
||||||
|
count := gRes.Units[aUnit].UnitAnim[aAct, aDir].Count;
|
||||||
|
fracStep := Min(aPercent, 1.0) * (count-1);
|
||||||
|
Result := UnitAction(aUnit, aAct, aDir, Trunc(fracStep), Frac(fracStep));
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TKMResInterpolation.UnitThought(aTh: TKMUnitThought; aStep: Integer; aStepFrac: Single): Integer;
|
||||||
|
var
|
||||||
|
animCount, step, subStep: Integer;
|
||||||
|
baseFrame, candidate: Integer;
|
||||||
|
begin
|
||||||
|
animCount := UNIT_THOUGHT_BOUNDS[aTh, 2] - UNIT_THOUGHT_BOUNDS[aTh, 1];
|
||||||
|
step := aStep mod Byte(animCount) + 1;
|
||||||
|
subStep := EnsureRange(Floor(INTERP_LEVEL*aStepFrac), 0, INTERP_LEVEL-1);
|
||||||
|
baseFrame := UNIT_THOUGHT_BOUNDS[aTh, 2] + 1 - step;
|
||||||
|
|
||||||
|
if not fInterpolationDataEligible then
|
||||||
|
Exit(baseFrame);
|
||||||
|
if not gGameSettings.GFX.InterpolatedAnimations then
|
||||||
|
Exit(baseFrame);
|
||||||
|
|
||||||
|
candidate := fUnitThoughts[aTh, step, subStep];
|
||||||
|
if candidate <= 0 then Exit(baseFrame);
|
||||||
|
if candidate > gRes.Sprites[rxUnits].RXData.Count then Exit(baseFrame);
|
||||||
|
if gRes.Sprites[rxUnits].RXData.Size[candidate].X = 0 then Exit(baseFrame);
|
||||||
|
Result := candidate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TKMResInterpolation.SerfCarry(aWare: TKMWareType; aDir: TKMDirection; aStep: Integer; aStepFrac: Single): Integer;
|
||||||
|
var
|
||||||
|
A: TKMAnimLoop;
|
||||||
|
step, subStep, baseFrame, candidate: Integer;
|
||||||
|
begin
|
||||||
|
A := gRes.Units.SerfCarry[aWare, aDir];
|
||||||
|
|
||||||
|
step := aStep mod Byte(A.Count) + 1;
|
||||||
|
subStep := EnsureRange(Floor(INTERP_LEVEL*aStepFrac), 0, INTERP_LEVEL-1);
|
||||||
|
baseFrame := A.Step[step] + 1;
|
||||||
|
|
||||||
|
if not fInterpolationDataEligible then
|
||||||
|
Exit(baseFrame);
|
||||||
|
if not gGameSettings.GFX.InterpolatedAnimations then
|
||||||
|
Exit(baseFrame);
|
||||||
|
|
||||||
|
candidate := fSerfCarry[aWare, aDir, step, subStep];
|
||||||
|
if candidate <= 0 then Exit(baseFrame);
|
||||||
|
if candidate > gRes.Sprites[rxUnits].RXData.Count then Exit(baseFrame);
|
||||||
|
if gRes.Sprites[rxUnits].RXData.Size[candidate].X = 0 then Exit(baseFrame);
|
||||||
|
Result := candidate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TKMResInterpolation.Tree(aObject, aStep: Integer; aStepFrac: Single; aLoop: Boolean): Integer;
|
||||||
|
var
|
||||||
|
A: TKMAnimLoop;
|
||||||
|
step, subStep, baseFrame, candidate: Integer;
|
||||||
|
begin
|
||||||
|
A := gMapElements[aObject].Anim;
|
||||||
|
|
||||||
|
step := aStep mod Byte(A.Count) + 1;
|
||||||
|
|
||||||
|
if aLoop or (step < A.Count) then
|
||||||
|
subStep := EnsureRange(Floor(INTERP_LEVEL*aStepFrac), 0, INTERP_LEVEL-1)
|
||||||
|
else
|
||||||
|
subStep := 0;
|
||||||
|
baseFrame := A.Step[step] + 1;
|
||||||
|
|
||||||
|
if not fInterpolationDataEligible then
|
||||||
|
Exit(baseFrame);
|
||||||
|
if not gGameSettings.GFX.InterpolatedAnimations then
|
||||||
|
Exit(baseFrame);
|
||||||
|
|
||||||
|
candidate := fTrees[aObject, step, subStep];
|
||||||
|
if candidate <= 0 then Exit(baseFrame);
|
||||||
|
if candidate > gRes.Sprites[rxTrees].RXData.Count then Exit(baseFrame);
|
||||||
|
if gRes.Sprites[rxTrees].RXData.Size[candidate].X = 0 then Exit(baseFrame);
|
||||||
|
Result := candidate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TKMResInterpolation.House(aHT: TKMHouseType; aAct: TKMHouseActionType; aStep: Integer; aStepFrac: Single): Integer;
|
||||||
|
var
|
||||||
|
A: TKMAnimLoop;
|
||||||
|
step, subStep, baseFrame, candidate: Integer;
|
||||||
|
begin
|
||||||
|
A := gRes.Houses[aHT].Anim[aAct];
|
||||||
|
|
||||||
|
step := aStep mod Byte(A.Count) + 1;
|
||||||
|
subStep := EnsureRange(Floor(INTERP_LEVEL*aStepFrac), 0, INTERP_LEVEL-1);
|
||||||
|
baseFrame := A.Step[step] + 1;
|
||||||
|
|
||||||
|
if not fInterpolationDataEligible then
|
||||||
|
Exit(baseFrame);
|
||||||
|
if not gGameSettings.GFX.InterpolatedAnimations then
|
||||||
|
Exit(baseFrame);
|
||||||
|
|
||||||
|
candidate := fHouses[aHT, aAct, step, subStep];
|
||||||
|
if candidate <= 0 then Exit(baseFrame);
|
||||||
|
if candidate > gRes.Sprites[rxHouses].RXData.Count then Exit(baseFrame);
|
||||||
|
if gRes.Sprites[rxHouses].RXData.Size[candidate].X = 0 then Exit(baseFrame);
|
||||||
|
Result := candidate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
function TKMResInterpolation.Beast(aHT: TKMHouseType; BeastId, BeastAge, aStep: Integer; aStepFrac: Single): Integer;
|
||||||
|
var
|
||||||
|
A: TKMAnimLoop;
|
||||||
|
step, subStep, baseFrame, candidate: Integer;
|
||||||
|
begin
|
||||||
|
A := gRes.Houses.BeastAnim[aHT, BeastId, BeastAge];
|
||||||
|
|
||||||
|
step := aStep mod Byte(A.Count) + 1;
|
||||||
|
subStep := EnsureRange(Floor(INTERP_LEVEL*aStepFrac), 0, INTERP_LEVEL-1);
|
||||||
|
baseFrame := A.Step[step] + 1;
|
||||||
|
|
||||||
|
if not fInterpolationDataEligible then
|
||||||
|
Exit(baseFrame);
|
||||||
|
if not gGameSettings.GFX.InterpolatedAnimations then
|
||||||
|
Exit(baseFrame);
|
||||||
|
|
||||||
|
case aHT of
|
||||||
|
htSwine: candidate := fBeasts[1, BeastId, BeastAge, step, subStep];
|
||||||
|
htStables: candidate := fBeasts[2, BeastId, BeastAge, step, subStep];
|
||||||
|
htMarket: candidate := fBeasts[3, BeastId, 1, step, subStep];
|
||||||
|
else candidate := -1;
|
||||||
|
end;
|
||||||
|
|
||||||
|
if candidate <= 0 then Exit(baseFrame);
|
||||||
|
if candidate > gRes.Sprites[rxHouses].RXData.Count then Exit(baseFrame);
|
||||||
|
if gRes.Sprites[rxHouses].RXData.Size[candidate].X = 0 then Exit(baseFrame);
|
||||||
|
Result := candidate;
|
||||||
|
end;
|
||||||
|
|
||||||
|
|
||||||
|
end.
|
||||||
Reference in new issue
Block a user