Continue ghost

This commit is contained in:
Miloslav Ciz 2025-01-22 15:35:58 +01:00
parent 1753e3237b
commit dc66182afb
3 changed files with 111 additions and 10 deletions

View file

@ -1,5 +1,6 @@
=========== GENERAL ============== =========== GENERAL ==============
- test if the replay stretching works
- replay validation - replay validation
- ghosts: if the replay for the ghost is too long (too many samples for the - ghosts: if the replay for the ghost is too long (too many samples for the
preallocated array), we can subdivide the sample resolution (i.e. "stretch" preallocated array), we can subdivide the sample resolution (i.e. "stretch"

2
data Normal file
View file

@ -0,0 +1,2 @@
#Mmap2;4321 1 :*H1k0J :,s0s0 :fd190
#Rrep2;testmap;482f70f9 00000843:0173:0081:0029:0111:0039:0071:00a3:0061:0169:0051:00b3:0041:0073:0081:0033:0041:0033:0231:0030:0098:0029:0011:0163:00f1:0053:0081:0033:0051:0023:0031:00f0:0032:0023:0131:00b9:0081:0023:00a1:0119:00e1:00c9:0071:0039:00a1:00d3:0021:01f9:0091:0079:0091:0039:0051:0049:0021:0083:0031:0083:0031:0083:0061:0089:0121:00a0:0058:002c:0048:0061:0013:0150:0052:00c0:00a1:0053:0041:0043:0031:0020:0092:0063:0181:0010:00a2:0013:0071:00e0:0028:00e9:0078:00a9:0043:0032:0123:0042:0080:0038:004c:01a8:0050:0032:0033:0101

118
game.h
View file

@ -278,7 +278,7 @@ struct
{ {
uint8_t active; uint8_t active;
uint8_t samples[LCR_SETTING_GHOST_MAX_SAMPLES * LCR_GHOST_SAMPLE_SIZE]; uint8_t samples[LCR_SETTING_GHOST_MAX_SAMPLES * LCR_GHOST_SAMPLE_SIZE];
/**< Samples, each 5 bytes: 9 bits for X and Z, 10 for Z, /**< Samples, each 5 bytes: 9 bits for X and Z, 10 for Y,
4 for each rotation component. */ 4 for each rotation component. */
uint8_t stretch; /**< Stretch of the base sample step, as a bit shift uint8_t stretch; /**< Stretch of the base sample step, as a bit shift
(i.e. 1 means the step will be 2x as long etc.). This (i.e. 1 means the step will be 2x as long etc.). This
@ -350,19 +350,90 @@ void LCR_gameResetRun(uint8_t replay, uint8_t ghost)
LCR_game.runTimeMS = 0; LCR_game.runTimeMS = 0;
} }
void _LCR_gameGetNthGhostSample(unsigned int n,
LCR_GameUnit position[3], LCR_GameUnit rotation[3])
{
n *= LCR_GHOST_SAMPLE_SIZE;
position[0] = LCR_game.ghost.samples[n];
n++;
position[0] |=
((LCR_GameUnit) (LCR_game.ghost.samples[n] & 0x01)) << 8;
position[1] = LCR_game.ghost.samples[n] >> 1;
n++;
position[1] |=
((LCR_GameUnit) (LCR_game.ghost.samples[n] & 0x07)) << 7;
position[2] = LCR_game.ghost.samples[n] >> 3;
n++;
position[2] |=
((LCR_GameUnit) (LCR_game.ghost.samples[n] & 0x0f)) << 5;
rotation[0] = LCR_game.ghost.samples[n] >> 4;
n++;
rotation[1] = LCR_game.ghost.samples[n] & 0x0f;
rotation[2] = LCR_game.ghost.samples[n] >> 4;
for (int i = 0; i < 3; ++i)
{
if (i != 2)
position[i] <<= 1;
position[i] = (position[i] * LCR_GAME_UNIT) / 16;
position[i] -=
(LCR_MAP_SIZE_BLOCKS / 2) *
(i == 1 ? LCR_GAME_UNIT / 2 : LCR_GAME_UNIT);
rotation[i] = (rotation[i] * LCR_GAME_UNIT) / 16;
}
}
void LCR_gameGhostGetTransform(uint32_t frame, void LCR_gameGhostGetTransform(uint32_t frame,
LCR_GameUnit position[3], LCR_GameUnit rotation[3]) LCR_GameUnit position[3], LCR_GameUnit rotation[3])
{ {
unsigned int n = ((frame >> LCR_game.ghost.stretch) / LCR_SETTING_GHOST_STEP);
LCR_racingGetCarTransform(position,rotation,0);
_LCR_gameGetNthGhostSample(n % 64,position,rotation);
if (n < LCR_SETTING_GHOST_MAX_SAMPLES - 1)
{
LCR_GameUnit carTransform[6];
// interpolate
_LCR_gameGetNthGhostSample((n % 64) + 1,carTransform,carTransform + 3);
n = (frame >> LCR_game.ghost.stretch) % LCR_SETTING_GHOST_STEP;
for (int i = 0; i < 3; ++i)
{
position[i] = position[i] +
((carTransform[i] - position[i]) * n) /
LCR_SETTING_GHOST_STEP;
}
}
} }
void _LCR_gamePrepareGhost(void) void _LCR_gamePrepareGhost(void)
{ {
LCR_GameUnit carTransform[6]; LCR_GameUnit carTransform[6];
LCR_LOG1("preparing ghost"); LCR_LOG1("preparing ghost");
LCR_gameResetRun(1,0); LCR_gameResetRun(1,0);
uint8_t *currentSample = LCR_game.ghost.samples; uint8_t *currentSample = LCR_game.ghost.samples;
@ -384,18 +455,36 @@ void _LCR_gamePrepareGhost(void)
{ {
LCR_racingGetCarTransform(carTransform,carTransform + 3,0); LCR_racingGetCarTransform(carTransform,carTransform + 3,0);
currentSample[0] = carTransform[0];
for (int i = 0; i < 3; ++i)
{
// convert positions to unsigned 10 bit values
carTransform[i] += // make non-negative
(LCR_MAP_SIZE_BLOCKS / 2) * (i == 1 ? LCR_GAME_UNIT / 2 : LCR_GAME_UNIT);
// convert to 10 bit value
carTransform[i] = (carTransform[i] * 16) / LCR_GAME_UNIT;
// conv. rots to 4 bits, we rely on them being non-negative!
carTransform[3 + i] =
(carTransform[3 + i] * 16) / LCR_GAME_UNIT;
}
// format: XXXXXXXX YYYYYYYX ZZZZZYYY AAAAZZZZ CCCCBBBB
currentSample[0] = carTransform[0] >> 1;
currentSample[1] = currentSample[1] =
((carTransform[0] >> 8) & 0x01) | ((carTransform[0] >> 9) & 0x01) |
(carTransform[1] << 1); (carTransform[1] << 1);
currentSample[2] = currentSample[2] =
((carTransform[1] >> 7) & 0x03) | ((carTransform[1] >> 7) & 0x07) |
(carTransform[2] << 2); ((carTransform[2] << 2) & 0xf8);
currentSample[3] = currentSample[3] =
((carTransform[2] >> 6) & 0x0f) | ((carTransform[2] >> 5) & 0x0f) |
(carTransform[3] << 4); (carTransform[3] << 4);
currentSample[4] = currentSample[4] =
(carTransform[4] >> 4) | (carTransform[4] & 0x0f) |
(carTransform[5] << 4); (carTransform[5] << 4);
currentSample += LCR_GHOST_SAMPLE_SIZE; currentSample += LCR_GHOST_SAMPLE_SIZE;
@ -403,6 +492,15 @@ void _LCR_gamePrepareGhost(void)
LCR_racingStep(0); LCR_racingStep(0);
} }
while ( // fill the rest with the last sample
currentSample >= LCR_game.ghost.samples + LCR_GHOST_SAMPLE_SIZE &&
currentSample < LCR_game.ghost.samples +
LCR_SETTING_GHOST_MAX_SAMPLES * LCR_GHOST_SAMPLE_SIZE)
{
*currentSample = *(currentSample - LCR_GHOST_SAMPLE_SIZE);
currentSample++;
}
} }
LCR_GameUnit LCR_carSpeedKMH(void) LCR_GameUnit LCR_carSpeedKMH(void)