Add animation smoothing

This commit is contained in:
Miloslav Ciz 2024-09-09 19:16:51 +02:00
parent e3d0b3219f
commit 03b703d454
5 changed files with 326 additions and 182 deletions

View file

@ -6194,7 +6194,7 @@ void LCR_imageChangeBrightness(int up)
{ {
if (up) if (up)
for (int i = 0; i < 256; ++i) for (int i = 0; i < 256; ++i)
_LCR_currentImagePalette[i] |= 0x1042; _LCR_currentImagePalette[i] |= 0x18e3;
else else
for (int i = 0; i < 256; ++i) for (int i = 0; i < 256; ++i)
_LCR_currentImagePalette[i] = _LCR_currentImagePalette[i] =

106
game.h
View file

@ -12,10 +12,10 @@
square is LCR_GAME_UNITs long, a full angle is also LCR_GAME_UNITs. square is LCR_GAME_UNITs long, a full angle is also LCR_GAME_UNITs.
- LCR_GAME_UNIT: Size of one game square and full angle in LCR_GameUnits. - LCR_GAME_UNIT: Size of one game square and full angle in LCR_GameUnits.
- S3L_Unit: data type, small3dlib's unit. May change with renderer change. - S3L_Unit: data type, small3dlib's unit. May change with renderer change.
- S3L_FRACTIONS_PER_UNIT: small3dlib's value representing 1.0. - S3L_F: small3dlib's value representing 1.0.
- LCR_RENDERER_UNIT: for the renderer one map square is this many S3L_Units. - LCR_RENDERER_UNIT: for the renderer one map square is this many S3L_Units.
- TPE_Unit: tinyphysicsengine's unit. May change with phys. engine change. - TPE_Unit: tinyphysicsengine's unit. May change with phys. engine change.
- TPE_FRACTIONS_PER_UNIT: tinyphysicsengine's value representing value 1.0. - TPE_F: tinyphysicsengine's value representing value 1.0.
- LCR_PHYSICS_UNIT: for the phys. eng. one map square is this many TPE_Units. - LCR_PHYSICS_UNIT: for the phys. eng. one map square is this many TPE_Units.
COORDINATE SYSTEM AND ROTATIONS: The game itself (racing module) is COORDINATE SYSTEM AND ROTATIONS: The game itself (racing module) is
@ -96,10 +96,15 @@ uint8_t LCR_gameStep(uint32_t timeMs);
//------------------------------------------------------------------------------ //------------------------------------------------------------------------------
#define LCR_CONTROL_MODE_FREECAM 0x00
#define LCR_CONTROL_MODE_DRIVE 0x01
struct struct
{ {
uint32_t nextRenderFrameTime; uint32_t nextRenderFrameTime;
uint32_t nextRacingTickTime; uint32_t nextRacingTickTime;
uint8_t controlMode;
uint8_t debugDraw;
} LCR_game; } LCR_game;
void LCR_drawPixelXYUnsafe(unsigned int x, unsigned int y, void LCR_drawPixelXYUnsafe(unsigned int x, unsigned int y,
@ -118,7 +123,9 @@ static inline void LCR_drawPixelXYSafe(unsigned int x, unsigned int y,
#include "renderer.h" #include "renderer.h"
uint8_t LCR_keyStates[LCR_KEYS_TOTAL]; /**< Assures unchanging key states uint8_t LCR_keyStates[LCR_KEYS_TOTAL]; /**< Assures unchanging key states
during a single frame. */ during a single frame, holds
number of frames for which the key
has been continuously held. */
void LCR_drawPixelXYUnsafe(unsigned int x, unsigned int y, void LCR_drawPixelXYUnsafe(unsigned int x, unsigned int y,
uint16_t color) uint16_t color)
@ -150,6 +157,9 @@ void LCR_gameInit(void)
LCR_game.nextRenderFrameTime = 0; LCR_game.nextRenderFrameTime = 0;
LCR_game.nextRacingTickTime = 0; LCR_game.nextRacingTickTime = 0;
LCR_game.controlMode = LCR_CONTROL_MODE_FREECAM;
LCR_game.debugDraw = 0;
} }
void LCR_gameEnd(void) void LCR_gameEnd(void)
@ -159,15 +169,22 @@ void LCR_gameEnd(void)
uint8_t LCR_gameStep(uint32_t time) uint8_t LCR_gameStep(uint32_t time)
{ {
for (int i = 0; i < LCR_KEYS_TOTAL; ++i) for (int i = 0; i < LCR_KEYS_TOTAL; ++i)
LCR_keyStates[i] = LCR_keyPressed(i); LCR_keyStates[i] = LCR_keyPressed(i) ?
(LCR_keyStates[i] < 255 ? LCR_keyStates[i] + 1 : 255) : 0;
uint32_t sleep = 0; uint32_t sleep = 0;
if (LCR_keyStates[LCR_KEY_B] == 1)
LCR_game.controlMode = LCR_game.controlMode == LCR_CONTROL_MODE_FREECAM ?
LCR_CONTROL_MODE_DRIVE : LCR_CONTROL_MODE_FREECAM;
else if (LCR_keyStates[LCR_KEY_B] == 30)
LCR_game.debugDraw = !LCR_game.debugDraw;
while (time >= LCR_game.nextRacingTickTime) while (time >= LCR_game.nextRacingTickTime)
{ {
unsigned int input = 0; unsigned int input = 0;
if (LCR_keyStates[LCR_KEY_B]) if (LCR_game.controlMode != LCR_CONTROL_MODE_FREECAM)
input = input =
(LCR_keyStates[LCR_KEY_UP] ? LCR_RACING_INPUT_FORW : 0) | (LCR_keyStates[LCR_KEY_UP] ? LCR_RACING_INPUT_FORW : 0) |
(LCR_keyStates[LCR_KEY_RIGHT] ? LCR_RACING_INPUT_RIGHT : 0) | (LCR_keyStates[LCR_KEY_RIGHT] ? LCR_RACING_INPUT_RIGHT : 0) |
@ -178,56 +195,67 @@ uint8_t LCR_gameStep(uint32_t time)
LCR_game.nextRacingTickTime += LCR_RACING_TICK_MS; LCR_game.nextRacingTickTime += LCR_RACING_TICK_MS;
} }
if (time >= LCR_game.nextRenderFrameTime) if (time >= LCR_game.nextRenderFrameTime)
{ {
LCR_GameUnit physicsInterpolationParam = LCR_GAME_UNIT -
((LCR_game.nextRacingTickTime - time) * LCR_GAME_UNIT) /
LCR_RACING_TICK_MS;
LCR_GameUnit carTransform[6]; LCR_GameUnit carTransform[6];
LCR_racingGetCarTransform(carTransform,carTransform + 3); LCR_racingGetCarTransform(carTransform,carTransform + 3,
physicsInterpolationParam);
LCR_rendererSetCarTransform(carTransform,carTransform + 3); LCR_rendererSetCarTransform(carTransform,carTransform + 3);
while (time >= LCR_game.nextRenderFrameTime)
LCR_game.nextRenderFrameTime += 1000 / LCR_SETTING_FPS;
LCR_rendererDraw();
LCR_GameUnit sss[7];
LCR_rendererGetCameraTransform(sss,sss + 3,sss + 6);
LCR_physicsDebugDraw(sss,sss + 3,sss[6]);
LCR_game.nextRenderFrameTime += 1000 / LCR_SETTING_FPS;
LCR_GameUnit offsets[5]; LCR_GameUnit offsets[5];
for (int i = 0; i < 5; ++i) for (int i = 0; i < 5; ++i)
offsets[i] = 0; offsets[i] = 0;
if (LCR_keyStates[LCR_KEY_A]) if (LCR_game.controlMode == LCR_CONTROL_MODE_FREECAM)
{ {
if (LCR_keyStates[LCR_KEY_UP]) if (LCR_keyStates[LCR_KEY_A])
offsets[4] = LCR_FREE_CAMERA_TURN_STEP; {
else if (LCR_keyStates[LCR_KEY_DOWN]) if (LCR_keyStates[LCR_KEY_UP])
offsets[4] -= LCR_FREE_CAMERA_TURN_STEP; offsets[4] = LCR_FREE_CAMERA_TURN_STEP;
else if (LCR_keyStates[LCR_KEY_DOWN])
offsets[4] -= LCR_FREE_CAMERA_TURN_STEP;
if (LCR_keyStates[LCR_KEY_RIGHT]) if (LCR_keyStates[LCR_KEY_RIGHT])
offsets[3] -= LCR_FREE_CAMERA_TURN_STEP; offsets[3] -= LCR_FREE_CAMERA_TURN_STEP;
else if (LCR_keyStates[LCR_KEY_LEFT]) else if (LCR_keyStates[LCR_KEY_LEFT])
offsets[3] = LCR_FREE_CAMERA_TURN_STEP; offsets[3] = LCR_FREE_CAMERA_TURN_STEP;
}
else
{
if (LCR_keyStates[LCR_KEY_UP])
offsets[0] = LCR_FREE_CAMERA_STEP;
else if (LCR_keyStates[LCR_KEY_DOWN])
offsets[0] -= LCR_FREE_CAMERA_STEP;
if (LCR_keyStates[LCR_KEY_RIGHT])
offsets[1] = LCR_FREE_CAMERA_STEP;
else if (LCR_keyStates[LCR_KEY_LEFT])
offsets[1] -= LCR_FREE_CAMERA_STEP;
}
LCR_rendererMoveCamera(offsets,offsets + 3);
} }
else if (!LCR_keyStates[LCR_KEY_B]) else
LCR_rendererCameraFollow();
LCR_rendererDraw();
if (LCR_game.debugDraw)
{ {
if (LCR_keyStates[LCR_KEY_UP]) LCR_GameUnit camTr[7];
offsets[0] = LCR_FREE_CAMERA_STEP; LCR_rendererGetCameraTransform(camTr,camTr + 3,camTr + 6);
else if (LCR_keyStates[LCR_KEY_DOWN]) LCR_physicsDebugDraw(camTr,camTr + 3,camTr[6]);
offsets[0] -= LCR_FREE_CAMERA_STEP;
if (LCR_keyStates[LCR_KEY_RIGHT])
offsets[1] = LCR_FREE_CAMERA_STEP;
else if (LCR_keyStates[LCR_KEY_LEFT])
offsets[1] -= LCR_FREE_CAMERA_STEP;
} }
LCR_rendererMoveCamera(offsets,offsets + 3);
} }
else else
sleep = LCR_game.nextRenderFrameTime - time; sleep = LCR_game.nextRenderFrameTime - time;

170
racing.h
View file

@ -5,16 +5,16 @@
#ifndef _LCR_RACING_H #ifndef _LCR_RACING_H
#define _LCR_RACING_H #define _LCR_RACING_H
typedef int32_t LCR_GameUnit; ///< abstract game unit typedef int32_t LCR_GameUnit; ///< abstract game unit
#define LCR_GAME_UNIT 1024 ///< length of map square in LCR_GameUnits #define LCR_GAME_UNIT 1024 ///< length of map square in LCR_GameUnits
#define LCR_RACING_INPUT_FORW 0x01 #define LCR_RACING_INPUT_FORW 0x01
#define LCR_RACING_INPUT_RIGHT 0x02 #define LCR_RACING_INPUT_RIGHT 0x02
#define LCR_RACING_INPUT_BACK 0x04 #define LCR_RACING_INPUT_BACK 0x04
#define LCR_RACING_INPUT_LEFT 0x08 #define LCR_RACING_INPUT_LEFT 0x08
#define LCR_PHYSICS_UNIT 1024 ///< length of map square for physics engine #define LCR_PHYSICS_UNIT 512 ///< length of map square for physics engine
#include "map.h" #include "map.h"
#include "tinyphysicsengine.h" #include "tinyphysicsengine.h"
@ -22,15 +22,35 @@ typedef int32_t LCR_GameUnit; ///< abstract game unit
#define LCR_CAR_JOINTS 5 #define LCR_CAR_JOINTS 5
#define LCR_CAR_CONNECTIONS 10 #define LCR_CAR_CONNECTIONS 10
#define LCR_CAR_FORWARD_FRICTION (TPE_F / 14)
#define LCR_CAR_TURN_FRICTION (3 * TPE_F / 4)
#define LCR_CAR_ELASTICITY (TPE_F / 100)
struct struct
{ {
TPE_World physicsWorld; TPE_World physicsWorld;
TPE_Body carBody; TPE_Body carBody;
TPE_Joint carJoints[LCR_CAR_JOINTS]; TPE_Joint carJoints[LCR_CAR_JOINTS];
TPE_Connection carConnections[LCR_CAR_CONNECTIONS]; TPE_Connection carConnections[LCR_CAR_CONNECTIONS];
uint8_t wheelCollisions; /**< In individual bits records for each car wheel
whether it's currently touching the ground.
Lower bits record current collisions, higher
bits the previous state (for averaging). */
TPE_Vec3 carPositions[2]; ///* Current and previous position.
} LCR_racing; } LCR_racing;
TPE_Vec3 LCR_racingEnvironmentFunction(TPE_Vec3 point, TPE_Unit maxDist) TPE_Vec3 _LCR_TPE_vec3DividePlain(TPE_Vec3 v, TPE_Unit d)
{
v.x /= d;
v.y /= d;
v.z /= d;
return v;
}
TPE_Vec3 _LCR_racingEnvironmentFunction(TPE_Vec3 point, TPE_Unit maxDist)
{ {
return TPE_envAABoxInside(point,TPE_vec3(0,0,0),TPE_vec3( return TPE_envAABoxInside(point,TPE_vec3(0,0,0),TPE_vec3(
LCR_PHYSICS_UNIT * LCR_MAP_SIZE_BLOCKS, LCR_PHYSICS_UNIT * LCR_MAP_SIZE_BLOCKS,
@ -38,6 +58,31 @@ TPE_Vec3 LCR_racingEnvironmentFunction(TPE_Vec3 point, TPE_Unit maxDist)
LCR_PHYSICS_UNIT * LCR_MAP_SIZE_BLOCKS)); LCR_PHYSICS_UNIT * LCR_MAP_SIZE_BLOCKS));
} }
uint8_t _LCR_racingCollisionHandler(uint16_t b1, uint16_t j1, uint16_t b2,
uint16_t j2, TPE_Vec3 p)
{
// check which wheels are touching the ground.
if (j1 < 4) // wheel joint?
LCR_racing.wheelCollisions |= 0x01 << j1;
return 1;
}
/**
Initializes new run.
*/
void LCR_racingRestart(void)
{
LCR_racing.wheelCollisions = 0;
TPE_bodyDeactivate(&(LCR_racing.carBody));
// TODO
}
/**
Initializes the racing module, only call once.
*/
void LCR_racingInit(void) void LCR_racingInit(void)
{ {
LCR_log("initializing racing engine"); LCR_log("initializing racing engine");
@ -49,42 +94,57 @@ void LCR_racingInit(void)
(LCR_PHYSICS_UNIT * 3) / 4, (LCR_PHYSICS_UNIT * 3) / 4,
LCR_PHYSICS_UNIT / 8); LCR_PHYSICS_UNIT / 8);
LCR_racing.carJoints[4].position.y += LCR_PHYSICS_UNIT / 8; LCR_racing.carJoints[4].position.y += LCR_PHYSICS_UNIT / 6;
LCR_racing.carJoints[4].sizeDivided *= 3; LCR_racing.carJoints[4].sizeDivided *= 3;
LCR_racing.carJoints[4].sizeDivided /= 2; LCR_racing.carJoints[4].sizeDivided /= 2;
TPE_bodyInit(&(LCR_racing.carBody), TPE_bodyInit(&(LCR_racing.carBody),
LCR_racing.carJoints,LCR_CAR_JOINTS, LCR_racing.carJoints,LCR_CAR_JOINTS,
LCR_racing.carConnections,LCR_CAR_CONNECTIONS, LCR_racing.carConnections,LCR_CAR_CONNECTIONS,
TPE_FRACTIONS_PER_UNIT); TPE_F);
LCR_racing.carBody.friction = LCR_CAR_FORWARD_FRICTION;
LCR_racing.carBody.elasticity = LCR_CAR_ELASTICITY;
TPE_worldInit(&(LCR_racing.physicsWorld), TPE_worldInit(&(LCR_racing.physicsWorld),
&(LCR_racing.carBody),1,LCR_racingEnvironmentFunction); &(LCR_racing.carBody),1,_LCR_racingEnvironmentFunction);
TPE_bodyDeactivate(&(LCR_racing.carBody)); LCR_racing.physicsWorld.collisionCallback = _LCR_racingCollisionHandler;
LCR_racingRestart();
} }
void LCR_racingGetCarTransform(LCR_GameUnit position[3], void LCR_racingGetCarTransform(LCR_GameUnit position[3],
LCR_GameUnit rotation[3]) LCR_GameUnit rotation[3], LCR_GameUnit interpolationParam)
{ {
#define AVERAGE(c) \
(((((LCR_racing.carBody.joints[0].position.c + \
LCR_racing.carBody.joints[1].position.c + \
LCR_racing.carBody.joints[2].position.c + \
LCR_racing.carBody.joints[3].position.c) / 4) + \
LCR_racing.carBody.joints[4].position.c) / 2) * \
LCR_GAME_UNIT) / LCR_PHYSICS_UNIT
position[0] = AVERAGE(x); #if LCR_SETTING_SMOOTH_ANIMATIONS
position[1] = AVERAGE(y); TPE_Vec3 v = TPE_vec3Plus(
position[2] = AVERAGE(z); LCR_racing.carPositions[1],
#undef AVERAGE _LCR_TPE_vec3DividePlain(
TPE_vec3TimesPlain(
TPE_vec3Minus(
LCR_racing.carPositions[0],LCR_racing.carPositions[1]),
interpolationParam),LCR_GAME_UNIT));
TPE_Vec3 rot = TPE_bodyGetRotation(&(LCR_racing.carBody),0,2,1); position[0] = v.x;
position[1] = v.y;
position[2] = v.z;
#else
TPE_Vec3 v;
rotation[0] = (rot.x * LCR_GAME_UNIT) / TPE_FRACTIONS_PER_UNIT; position[0] = LCR_racing.carPositions[0].x;
rotation[1] = (rot.y * LCR_GAME_UNIT) / TPE_FRACTIONS_PER_UNIT; position[1] = LCR_racing.carPositions[0].y;
rotation[2] = (rot.z * LCR_GAME_UNIT) / TPE_FRACTIONS_PER_UNIT; position[2] = LCR_racing.carPositions[0].z;
#endif
v = TPE_bodyGetRotation(&(LCR_racing.carBody),0,2,1);
rotation[0] = (v.x * LCR_GAME_UNIT) / TPE_F;
rotation[1] = (v.y * LCR_GAME_UNIT) / TPE_F;
rotation[2] = (v.z * LCR_GAME_UNIT) / TPE_F;
// TODO: also smooth out rotation?
} }
void _LCR_drawPhysicsDebugPixel(uint16_t x, uint16_t y, uint8_t color) void _LCR_drawPhysicsDebugPixel(uint16_t x, uint16_t y, uint8_t color)
@ -100,18 +160,24 @@ void _LCR_drawPhysicsDebugPixel(uint16_t x, uint16_t y, uint8_t color)
} }
} }
// TODO: input int LCR_racingCarWheelTouchesGround(int wheel)
{
return ((LCR_racing.wheelCollisions & (LCR_racing.wheelCollisions >> 4))
>> wheel) & 0x01;
}
void LCR_racingStep(unsigned int input) void LCR_racingStep(unsigned int input)
{ {
TPE_Vec3 carForw, carRight, carUp;
TPE_Vec3 vel = TPE_vec3(0,0,0); TPE_Vec3 vel = TPE_vec3(0,0,0);
if (input) if (input)
{ {
if (input & LCR_RACING_INPUT_FORW) if (input & LCR_RACING_INPUT_FORW)
vel.z = LCR_PHYSICS_UNIT / 32; vel.y = LCR_PHYSICS_UNIT / 8;
if (input & LCR_RACING_INPUT_BACK) if (input & LCR_RACING_INPUT_BACK)
vel.y = LCR_PHYSICS_UNIT / 32; vel.z = LCR_PHYSICS_UNIT / 32;
if (input & LCR_RACING_INPUT_RIGHT) if (input & LCR_RACING_INPUT_RIGHT)
vel.x = LCR_PHYSICS_UNIT / 32; vel.x = LCR_PHYSICS_UNIT / 32;
@ -123,10 +189,52 @@ void LCR_racingStep(unsigned int input)
} }
TPE_bodyApplyGravity(&(LCR_racing.carBody), TPE_bodyApplyGravity(&(LCR_racing.carBody),
TPE_FRACTIONS_PER_UNIT / 32 TPE_F / 32
); );
LCR_racing.wheelCollisions <<= 4;
TPE_worldStep(&(LCR_racing.physicsWorld)); TPE_worldStep(&(LCR_racing.physicsWorld));
carForw = TPE_vec3Normalized(TPE_vec3Plus(
TPE_vec3Minus(LCR_racing.carBody.joints[2].position,
LCR_racing.carBody.joints[0].position),
TPE_vec3Minus(LCR_racing.carBody.joints[3].position,
LCR_racing.carBody.joints[1].position)));
carRight = TPE_vec3Normalized(TPE_vec3Plus(
TPE_vec3Minus(LCR_racing.carBody.joints[1].position,
LCR_racing.carBody.joints[0].position),
TPE_vec3Minus(LCR_racing.carBody.joints[3].position,
LCR_racing.carBody.joints[2].position)));
carUp = TPE_vec3Cross(carForw,carRight);
if (TPE_vec3Dot(carUp,TPE_vec3Minus(LCR_racing.carBody.joints[4].position,
LCR_racing.carBody.joints[0].position)) < 0)
{
/* if the car falls on its roof the center joint may flip to the other
side, here we fix it */
// LCR_log("car flipped over, fixing");
LCR_racing.carBody.joints[4].position = TPE_vec3Plus(TPE_vec3Times(carUp,
LCR_GAME_UNIT / 4),LCR_racing.carBody.joints[4].position);
}
LCR_racing.carPositions[1] = LCR_racing.carPositions[0];
#define AVERAGE(c) \
(((((LCR_racing.carBody.joints[0].position.c + \
LCR_racing.carBody.joints[1].position.c + \
LCR_racing.carBody.joints[2].position.c + \
LCR_racing.carBody.joints[3].position.c) / 4) + \
LCR_racing.carBody.joints[4].position.c) / 2) * \
LCR_GAME_UNIT) / LCR_PHYSICS_UNIT
LCR_racing.carPositions[0].x = AVERAGE(x);
LCR_racing.carPositions[0].y = AVERAGE(y);
LCR_racing.carPositions[0].z = AVERAGE(z);
#undef AVERAGE
} }
void LCR_physicsDebugDraw(LCR_GameUnit camPos[3], LCR_GameUnit camRot[2], void LCR_physicsDebugDraw(LCR_GameUnit camPos[3], LCR_GameUnit camRot[2],
@ -138,13 +246,13 @@ void LCR_physicsDebugDraw(LCR_GameUnit camPos[3], LCR_GameUnit camRot[2],
cPos.y = (camPos[1] * LCR_PHYSICS_UNIT) / LCR_GAME_UNIT; cPos.y = (camPos[1] * LCR_PHYSICS_UNIT) / LCR_GAME_UNIT;
cPos.z = (camPos[2] * LCR_PHYSICS_UNIT) / LCR_GAME_UNIT; cPos.z = (camPos[2] * LCR_PHYSICS_UNIT) / LCR_GAME_UNIT;
cRot.x = (camRot[0] * TPE_FRACTIONS_PER_UNIT) / LCR_GAME_UNIT; cRot.x = (camRot[0] * TPE_F) / LCR_GAME_UNIT;
cRot.y = (camRot[1] * TPE_FRACTIONS_PER_UNIT) / LCR_GAME_UNIT; cRot.y = (camRot[1] * TPE_F) / LCR_GAME_UNIT;
cRot.z = 0; cRot.z = 0;
cView.x = LCR_EFFECTIVE_RESOLUTION_X; cView.x = LCR_EFFECTIVE_RESOLUTION_X;
cView.y = LCR_EFFECTIVE_RESOLUTION_Y; cView.y = LCR_EFFECTIVE_RESOLUTION_Y;
cView.z = (camFov * TPE_FRACTIONS_PER_UNIT) / LCR_GAME_UNIT; cView.z = (camFov * TPE_F) / LCR_GAME_UNIT;
TPE_worldDebugDraw(&(LCR_racing.physicsWorld),_LCR_drawPhysicsDebugPixel, TPE_worldDebugDraw(&(LCR_racing.physicsWorld),_LCR_drawPhysicsDebugPixel,
cPos,cRot,cView,16,2 * LCR_PHYSICS_UNIT); cPos,cRot,cView,16,2 * LCR_PHYSICS_UNIT);

View file

@ -17,8 +17,8 @@
#include "small3dlib.h" #include "small3dlib.h"
/// Renderer specific unit, length of one map square. /// Renderer specific unit, length of one map square.
#define LCR_RENDERER_UNIT (S3L_FRACTIONS_PER_UNIT / 2) #define LCR_RENDERER_UNIT (S3L_F / 2)
// ^ just S3L_FRACTIONS_PER_UNIT leaves some tris bugging // ^ just S3L_F leaves some tris bugging
#define LCR_RENDERER_CHUNK_RESOLUTION 4 // do not change #define LCR_RENDERER_CHUNK_RESOLUTION 4 // do not change
#define LCR_RENDERER_LOD_BLOCKS 64 // do not change #define LCR_RENDERER_LOD_BLOCKS 64 // do not change
@ -29,7 +29,7 @@
#define LCR_RENDERER_CHUNKS_TOTAL (LCR_RENDERER_CHUNK_RESOLUTION * \ #define LCR_RENDERER_CHUNKS_TOTAL (LCR_RENDERER_CHUNK_RESOLUTION * \
LCR_RENDERER_CHUNK_RESOLUTION * LCR_RENDERER_CHUNK_RESOLUTION) LCR_RENDERER_CHUNK_RESOLUTION * LCR_RENDERER_CHUNK_RESOLUTION)
#define LCR_RENDERER_MODEL_COUNT 9 #define LCR_RENDERER_MODEL_COUNT 10
#define LCR_RENDERER_CAR_SCALE (LCR_RENDERER_UNIT / 4) #define LCR_RENDERER_CAR_SCALE (LCR_RENDERER_UNIT / 4)
@ -37,7 +37,8 @@ struct
{ {
S3L_Scene scene; S3L_Scene scene;
S3L_Model3D mapModel; ///< whole map model S3L_Model3D mapModel; ///< whole map model
S3L_Model3D *carModel; S3L_Model3D *carModel;
S3L_Model3D *ghostModel;
// TODO: ghostModel // TODO: ghostModel
@ -45,6 +46,7 @@ struct
The scene model array. The scene model array.
0, 1, 2, 3, 4, 5, 6, 7: nearest map chunk models 0, 1, 2, 3, 4, 5, 6, 7: nearest map chunk models
8: car model 8: car model
9: ghost model
*/ */
S3L_Model3D models[LCR_RENDERER_MODEL_COUNT]; S3L_Model3D models[LCR_RENDERER_MODEL_COUNT];
@ -70,11 +72,6 @@ struct
*/ */
uint8_t gridOfLODs[LCR_RENDERER_LOD_BLOCKS]; uint8_t gridOfLODs[LCR_RENDERER_LOD_BLOCKS];
// pixel function precomputed values:
uint32_t previousTriID;
int triUVs[6];
uint8_t texSubsampleCount;
#if LCR_ANIMATE_CAR #if LCR_ANIMATE_CAR
S3L_Unit wheelRotation; S3L_Unit wheelRotation;
S3L_Unit wheelTurn; S3L_Unit wheelTurn;
@ -82,6 +79,13 @@ struct
S3L_Unit animatedCarVerts[LCR_CAR_VERTEX_COUNT * 3]; S3L_Unit animatedCarVerts[LCR_CAR_VERTEX_COUNT * 3];
#endif #endif
// pixel function precomputed values:
uint32_t previousTriID;
int triUVs[6];
int texSubsampleCount;
unsigned int flatAndTransparent; /**< If non-zero, transparent (dithered)
polygons will be drawn without texture,
with color stored in this variable. */
} LCR_renderer; } LCR_renderer;
void LCR_rendererSetCarTransform(LCR_GameUnit position[3], void LCR_rendererSetCarTransform(LCR_GameUnit position[3],
@ -95,11 +99,11 @@ void LCR_rendererSetCarTransform(LCR_GameUnit position[3],
(position[2] * LCR_RENDERER_UNIT) / LCR_GAME_UNIT; (position[2] * LCR_RENDERER_UNIT) / LCR_GAME_UNIT;
LCR_renderer.carModel->transform.rotation.x = S3L_wrap((rotation[0] * LCR_renderer.carModel->transform.rotation.x = S3L_wrap((rotation[0] *
S3L_FRACTIONS_PER_UNIT) / LCR_GAME_UNIT,S3L_FRACTIONS_PER_UNIT); S3L_F) / LCR_GAME_UNIT,S3L_F);
LCR_renderer.carModel->transform.rotation.y = S3L_wrap((rotation[1] * LCR_renderer.carModel->transform.rotation.y = S3L_wrap((rotation[1] *
S3L_FRACTIONS_PER_UNIT) / LCR_GAME_UNIT,S3L_FRACTIONS_PER_UNIT); S3L_F) / LCR_GAME_UNIT,S3L_F);
LCR_renderer.carModel->transform.rotation.z = S3L_wrap((rotation[2] * LCR_renderer.carModel->transform.rotation.z = S3L_wrap((rotation[2] *
S3L_FRACTIONS_PER_UNIT) / LCR_GAME_UNIT,S3L_FRACTIONS_PER_UNIT); S3L_F) / LCR_GAME_UNIT,S3L_F);
} }
void _LCR_pixelFuncc3D(S3L_PixelInfo *pixel) void _LCR_pixelFuncc3D(S3L_PixelInfo *pixel)
@ -108,12 +112,18 @@ void _LCR_pixelFuncc3D(S3L_PixelInfo *pixel)
if (pixel->triangleID != LCR_renderer.previousTriID) if (pixel->triangleID != LCR_renderer.previousTriID)
{ {
LCR_renderer.previousTriID = pixel->triangleID; LCR_renderer.previousTriID = pixel->triangleID;
LCR_renderer.flatAndTransparent = 0;
#if LCR_SETTING_TEXTURE_SUBSAMPLE != 0 #if LCR_SETTING_TEXTURE_SUBSAMPLE != 0
LCR_renderer.texSubsampleCount = 0; LCR_renderer.texSubsampleCount = 0;
#endif #endif
if (pixel->modelIndex == 8) if (pixel->modelIndex == 9)
{
// car ghost model
LCR_renderer.flatAndTransparent = LCR_SETTING_GHOST_COLOR;
}
else if (pixel->modelIndex == 8)
{ {
// car model // car model
@ -197,8 +207,15 @@ void _LCR_pixelFuncc3D(S3L_PixelInfo *pixel)
} }
} }
uint16_t color; if (LCR_renderer.flatAndTransparent)
{
if (pixel->x % 2 == pixel->y % 2)
LCR_drawPixelXYUnsafe(pixel->x,pixel->y,LCR_renderer.flatAndTransparent);
return;
}
uint16_t color;
#if LCR_SETTING_TEXTURE_SUBSAMPLE != 0 #if LCR_SETTING_TEXTURE_SUBSAMPLE != 0
if (LCR_renderer.texSubsampleCount == 0) if (LCR_renderer.texSubsampleCount == 0)
@ -214,11 +231,11 @@ void _LCR_pixelFuncc3D(S3L_PixelInfo *pixel)
(barycentric[0] * LCR_renderer.triUVs[0] + (barycentric[0] * LCR_renderer.triUVs[0] +
barycentric[1] * LCR_renderer.triUVs[2] + barycentric[1] * LCR_renderer.triUVs[2] +
barycentric[2] * LCR_renderer.triUVs[4]) barycentric[2] * LCR_renderer.triUVs[4])
/ (S3L_FRACTIONS_PER_UNIT / 8), / (S3L_F / 8),
(barycentric[0] * LCR_renderer.triUVs[1] + (barycentric[0] * LCR_renderer.triUVs[1] +
barycentric[1] * LCR_renderer.triUVs[3] + barycentric[1] * LCR_renderer.triUVs[3] +
barycentric[2] * LCR_renderer.triUVs[5]) barycentric[2] * LCR_renderer.triUVs[5])
/ (S3L_FRACTIONS_PER_UNIT / 8)); / (S3L_F / 8));
#if LCR_SETTING_TEXTURE_SUBSAMPLE != 0 #if LCR_SETTING_TEXTURE_SUBSAMPLE != 0
LCR_renderer.texSubsampleCount = LCR_SETTING_TEXTURE_SUBSAMPLE; LCR_renderer.texSubsampleCount = LCR_SETTING_TEXTURE_SUBSAMPLE;
@ -755,6 +772,7 @@ uint8_t LCR_rendererInit(void)
_LCR_rendererComputeLOD(); _LCR_rendererComputeLOD();
LCR_renderer.carModel = LCR_renderer.models + 8; LCR_renderer.carModel = LCR_renderer.models + 8;
LCR_renderer.ghostModel = LCR_renderer.models + 9;
S3L_model3DInit( S3L_model3DInit(
#if LCR_ANIMATE_CAR #if LCR_ANIMATE_CAR
@ -766,6 +784,20 @@ uint8_t LCR_rendererInit(void)
LCR_carTriangles,LCR_CAR_TRIANGLE_COUNT, LCR_carTriangles,LCR_CAR_TRIANGLE_COUNT,
LCR_renderer.carModel); LCR_renderer.carModel);
S3L_vec4Set(&(LCR_renderer.carModel->transform.scale),
LCR_RENDERER_CAR_SCALE,LCR_RENDERER_CAR_SCALE,LCR_RENDERER_CAR_SCALE,0);
S3L_model3DInit(
LCR_carVertices
,LCR_CAR_VERTEX_COUNT,
LCR_carTriangles,LCR_CAR_TRIANGLE_COUNT,
LCR_renderer.ghostModel);
LCR_renderer.ghostModel->transform.scale =
LCR_renderer.carModel->transform.scale;
LCR_renderer.ghostModel->transform.translation.x -= LCR_GAME_UNIT / 4;
#if LCR_ANIMATE_CAR #if LCR_ANIMATE_CAR
for (int i = 0; i < LCR_CAR_VERTEX_COUNT * 3; ++i) for (int i = 0; i < LCR_CAR_VERTEX_COUNT * 3; ++i)
LCR_renderer.animatedCarVerts[i] = LCR_carVertices[i]; LCR_renderer.animatedCarVerts[i] = LCR_carVertices[i];
@ -799,10 +831,6 @@ uint8_t LCR_rendererInit(void)
LCR_renderer.wheelTurn = 0; LCR_renderer.wheelTurn = 0;
#endif #endif
LCR_renderer.carModel->transform.scale.x = LCR_RENDERER_CAR_SCALE;
LCR_renderer.carModel->transform.scale.y = LCR_RENDERER_CAR_SCALE;
LCR_renderer.carModel->transform.scale.z = LCR_RENDERER_CAR_SCALE;
S3L_sceneInit( S3L_sceneInit(
LCR_renderer.models,LCR_RENDERER_MODEL_COUNT,&LCR_renderer.scene); LCR_renderer.models,LCR_RENDERER_MODEL_COUNT,&LCR_renderer.scene);
@ -820,14 +848,14 @@ void LCR_rendererGetCameraTransform(LCR_GameUnit position[3],
LCR_GAME_UNIT) / LCR_RENDERER_UNIT; LCR_GAME_UNIT) / LCR_RENDERER_UNIT;
rotation[0] = (LCR_renderer.scene.camera.transform.rotation.x * rotation[0] = (LCR_renderer.scene.camera.transform.rotation.x *
LCR_GAME_UNIT) / S3L_FRACTIONS_PER_UNIT; LCR_GAME_UNIT) / S3L_F;
rotation[1] = (LCR_renderer.scene.camera.transform.rotation.y * rotation[1] = (LCR_renderer.scene.camera.transform.rotation.y *
LCR_GAME_UNIT) / S3L_FRACTIONS_PER_UNIT; LCR_GAME_UNIT) / S3L_F;
rotation[2] = (LCR_renderer.scene.camera.transform.rotation.z * rotation[2] = (LCR_renderer.scene.camera.transform.rotation.z *
LCR_GAME_UNIT) / S3L_FRACTIONS_PER_UNIT; LCR_GAME_UNIT) / S3L_F;
*fov = (LCR_renderer.scene.camera.focalLength * LCR_GAME_UNIT) *fov = (LCR_renderer.scene.camera.focalLength * LCR_GAME_UNIT)
/ S3L_FRACTIONS_PER_UNIT; / S3L_F;
} }
void LCR_rendererMoveCamera(LCR_GameUnit forwRightUpOffset[3], void LCR_rendererMoveCamera(LCR_GameUnit forwRightUpOffset[3],
@ -836,29 +864,29 @@ void LCR_rendererMoveCamera(LCR_GameUnit forwRightUpOffset[3],
S3L_Vec4 f, r, u; S3L_Vec4 f, r, u;
S3L_rotationToDirections(LCR_renderer.scene.camera.transform.rotation, S3L_rotationToDirections(LCR_renderer.scene.camera.transform.rotation,
S3L_FRACTIONS_PER_UNIT,&f,&r,&u); S3L_F,&f,&r,&u);
LCR_renderer.scene.camera.transform.translation.x += LCR_renderer.scene.camera.transform.translation.x +=
((f.x * forwRightUpOffset[0] + r.x * forwRightUpOffset[1] + ((f.x * forwRightUpOffset[0] + r.x * forwRightUpOffset[1] +
u.x * forwRightUpOffset[2]) * S3L_FRACTIONS_PER_UNIT) / LCR_GAME_UNIT; u.x * forwRightUpOffset[2]) * S3L_F) / LCR_GAME_UNIT;
LCR_renderer.scene.camera.transform.translation.y += LCR_renderer.scene.camera.transform.translation.y +=
((f.y * forwRightUpOffset[0] + r.y * forwRightUpOffset[1] + ((f.y * forwRightUpOffset[0] + r.y * forwRightUpOffset[1] +
u.y * forwRightUpOffset[2]) * S3L_FRACTIONS_PER_UNIT) / LCR_GAME_UNIT; u.y * forwRightUpOffset[2]) * S3L_F) / LCR_GAME_UNIT;
LCR_renderer.scene.camera.transform.translation.z += LCR_renderer.scene.camera.transform.translation.z +=
((f.z * forwRightUpOffset[0] + r.z * forwRightUpOffset[1] + ((f.z * forwRightUpOffset[0] + r.z * forwRightUpOffset[1] +
u.z * forwRightUpOffset[2]) * S3L_FRACTIONS_PER_UNIT) / LCR_GAME_UNIT; u.z * forwRightUpOffset[2]) * S3L_F) / LCR_GAME_UNIT;
LCR_renderer.scene.camera.transform.rotation.y = S3L_wrap( LCR_renderer.scene.camera.transform.rotation.y = S3L_wrap(
LCR_renderer.scene.camera.transform.rotation.y + LCR_renderer.scene.camera.transform.rotation.y +
(yawPitchOffset[0] * S3L_FRACTIONS_PER_UNIT) / LCR_GAME_UNIT, (yawPitchOffset[0] * S3L_F) / LCR_GAME_UNIT,
S3L_FRACTIONS_PER_UNIT); S3L_F);
LCR_renderer.scene.camera.transform.rotation.x = S3L_clamp( LCR_renderer.scene.camera.transform.rotation.x = S3L_clamp(
LCR_renderer.scene.camera.transform.rotation.x + LCR_renderer.scene.camera.transform.rotation.x +
(yawPitchOffset[1] * S3L_FRACTIONS_PER_UNIT) / LCR_GAME_UNIT, (yawPitchOffset[1] * S3L_F) / LCR_GAME_UNIT,
-1 * S3L_FRACTIONS_PER_UNIT / 4,S3L_FRACTIONS_PER_UNIT / 4); -1 * S3L_F / 4,S3L_F / 4);
#define chk(o,c,l) \ #define chk(o,c,l) \
if (LCR_renderer.scene.camera.transform.translation.c o l) \ if (LCR_renderer.scene.camera.transform.translation.c o l) \
@ -976,7 +1004,7 @@ void _LCR_rendererDrawLODBlock(int blockX, int blockY, int blockZ, unsigned int
/** /**
Draws background sky, offsets are in multiples of screen dimensions Draws background sky, offsets are in multiples of screen dimensions
(e.g. S3L_FRACTIONS_PER_UNIT / 2 for offsetH means half the screen width). (e.g. S3L_F / 2 for offsetH means half the screen width).
*/ */
void LCR_rendererDrawSky(int sky, S3L_Unit offsetH, S3L_Unit offsetV) void LCR_rendererDrawSky(int sky, S3L_Unit offsetH, S3L_Unit offsetV)
{ {
@ -993,7 +1021,7 @@ void LCR_rendererDrawSky(int sky, S3L_Unit offsetH, S3L_Unit offsetV)
bottomColor = LCR_sampleImage(LCR_IMAGE_SIZE - 1,LCR_IMAGE_SIZE - 1); bottomColor = LCR_sampleImage(LCR_IMAGE_SIZE - 1,LCR_IMAGE_SIZE - 1);
anchorPoint[0] = ((LCR_EFFECTIVE_RESOLUTION_X * offsetH) anchorPoint[0] = ((LCR_EFFECTIVE_RESOLUTION_X * offsetH)
/ S3L_FRACTIONS_PER_UNIT) % / S3L_F) %
(2 * LCR_IMAGE_SIZE * LCR_SETTING_SKY_SIZE); (2 * LCR_IMAGE_SIZE * LCR_SETTING_SKY_SIZE);
if (anchorPoint[0] < 0) if (anchorPoint[0] < 0)
@ -1001,7 +1029,7 @@ void LCR_rendererDrawSky(int sky, S3L_Unit offsetH, S3L_Unit offsetV)
anchorPoint[1] = anchorPoint[1] =
(LCR_EFFECTIVE_RESOLUTION_Y) / 3 - // 3: we place the center a bit more up (LCR_EFFECTIVE_RESOLUTION_Y) / 3 - // 3: we place the center a bit more up
(LCR_EFFECTIVE_RESOLUTION_Y * offsetV) / S3L_FRACTIONS_PER_UNIT (LCR_EFFECTIVE_RESOLUTION_Y * offsetV) / S3L_F
- LCR_IMAGE_SIZE * LCR_SETTING_SKY_SIZE; - LCR_IMAGE_SIZE * LCR_SETTING_SKY_SIZE;
pixelIndex = 0; pixelIndex = 0;
@ -1266,8 +1294,8 @@ void _LCR_rendererAnimateCar(void)
LCR_renderer.wheelRotationCenters[offset + 1]; LCR_renderer.wheelRotationCenters[offset + 1];
tmp = v[0]; tmp = v[0];
v[0] = (v[0] * c - v[1] * s) / S3L_FRACTIONS_PER_UNIT; v[0] = (v[0] * c - v[1] * s) / S3L_F;
v[1] = (tmp * s + v[1] * c) / S3L_FRACTIONS_PER_UNIT; v[1] = (tmp * s + v[1] * c) / S3L_F;
LCR_renderer.animatedCarVerts[index + 2] = LCR_renderer.animatedCarVerts[index + 2] =
v[0] + LCR_renderer.wheelRotationCenters[offset]; v[0] + LCR_renderer.wheelRotationCenters[offset];
@ -1282,12 +1310,12 @@ void _LCR_rendererAnimateCar(void)
LCR_renderer.animatedCarVerts[index + 2] -= LCR_renderer.animatedCarVerts[index + 2] -=
(LCR_renderer.animatedCarVerts[index] * LCR_renderer.wheelTurn) (LCR_renderer.animatedCarVerts[index] * LCR_renderer.wheelTurn)
/ (8 * S3L_FRACTIONS_PER_UNIT); / (8 * S3L_F);
LCR_renderer.animatedCarVerts[index] += LCR_renderer.animatedCarVerts[index] +=
((LCR_renderer.animatedCarVerts[index + 2] - ((LCR_renderer.animatedCarVerts[index + 2] -
LCR_renderer.wheelRotationCenters[0]) * LCR_renderer.wheelTurn) LCR_renderer.wheelRotationCenters[0]) * LCR_renderer.wheelTurn)
/ (2 * S3L_FRACTIONS_PER_UNIT); / (2 * S3L_F);
} }
} }
} }
@ -1296,86 +1324,57 @@ void _LCR_rendererAnimateCar(void)
void LCR_rendererCameraFollow(void) void LCR_rendererCameraFollow(void)
{ {
S3L_Transform3D transPrev =
LCR_renderer.scene.camera.transform;
/*
LCR_renderer.scene.camera.transform.translation.y = LCR_renderer.scene.camera.transform.translation.y =
LCR_renderer.carModel->transform.translation.y + LCR_RENDERER_UNIT; S3L_clamp(
*/ LCR_renderer.scene.camera.transform.translation.y,
LCR_renderer.carModel->transform.translation.y +
/* (LCR_SETTING_CAMERA_HEIGHT - LCR_SETTING_CAMERA_HEIGHT_BAND) *
TPE_Vec3 cPos = TPE_vec3KeepWithinDistanceBand( LCR_RENDERER_UNIT / 8,
TPE_vec3( LCR_renderer.carModel->transform.translation.y +
s3l_scene.camera.transform.translation.x, (LCR_SETTING_CAMERA_HEIGHT + LCR_SETTING_CAMERA_HEIGHT_BAND) *
s3l_scene.camera.transform.translation.y, LCR_RENDERER_UNIT / 8);
s3l_scene.camera.transform.translation.z
),carBody->joints[4].position,4 * TPE_F,6 * TPE_F);
s3l_scene.camera.transform.translation.x = cPos.x;
s3l_scene.camera.transform.translation.y = cPos.y;
s3l_scene.camera.transform.translation.z = cPos.z;
*/
/*
S3L_Unit tmp =
LCR_renderer.scene.camera.transform.translation.y -
LCR_renderer.carModel->transform.translation.y;
tmp -= S3L_clamp(tmp,
(LCR_SETTING_CAMERA_HEIGHT -
LCR_SETTING_CAMERA_HEIGHT_BAND) * LCR_GAME_UNIT / 8,
(LCR_SETTING_CAMERA_HEIGHT +
LCR_SETTING_CAMERA_HEIGHT_BAND) * LCR_GAME_UNIT / 8);
LCR_renderer.scene.camera.transform.translation.y -= tmp;
*/
LCR_renderer.scene.camera.transform.translation.y =
S3L_clamp(
LCR_renderer.scene.camera.transform.translation.y,
LCR_renderer.carModel->transform.translation.y +
(LCR_SETTING_CAMERA_HEIGHT - LCR_SETTING_CAMERA_HEIGHT_BAND) *
LCR_GAME_UNIT / 8,
LCR_renderer.carModel->transform.translation.y +
(LCR_SETTING_CAMERA_HEIGHT + LCR_SETTING_CAMERA_HEIGHT_BAND) *
LCR_GAME_UNIT / 8);
LCR_renderer.scene.camera.transform.translation.x =
S3L_clamp(
LCR_renderer.scene.camera.transform.translation.x,
LCR_renderer.carModel->transform.translation.x -
LCR_SETTING_CAMERA_MAX_DISTANCE * LCR_GAME_UNIT / 4,
LCR_renderer.carModel->transform.translation.x +
LCR_SETTING_CAMERA_MAX_DISTANCE * LCR_GAME_UNIT / 4);
LCR_renderer.scene.camera.transform.translation.z =
S3L_clamp(
LCR_renderer.scene.camera.transform.translation.z,
LCR_renderer.carModel->transform.translation.z -
LCR_SETTING_CAMERA_MAX_DISTANCE * LCR_GAME_UNIT / 4,
LCR_renderer.carModel->transform.translation.z +
LCR_SETTING_CAMERA_MAX_DISTANCE * LCR_GAME_UNIT / 4);
LCR_renderer.scene.camera.transform.translation.x =
S3L_clamp(
LCR_renderer.scene.camera.transform.translation.x,
LCR_renderer.carModel->transform.translation.x -
LCR_SETTING_CAMERA_MAX_DISTANCE * LCR_RENDERER_UNIT / 4,
LCR_renderer.carModel->transform.translation.x +
LCR_SETTING_CAMERA_MAX_DISTANCE * LCR_RENDERER_UNIT / 4);
LCR_renderer.scene.camera.transform.translation.z =
S3L_clamp(
LCR_renderer.scene.camera.transform.translation.z,
LCR_renderer.carModel->transform.translation.z -
LCR_SETTING_CAMERA_MAX_DISTANCE * LCR_RENDERER_UNIT / 4,
LCR_renderer.carModel->transform.translation.z +
LCR_SETTING_CAMERA_MAX_DISTANCE * LCR_RENDERER_UNIT / 4);
S3L_lookAt(LCR_renderer.carModel->transform.translation, S3L_lookAt(LCR_renderer.carModel->transform.translation,
&(LCR_renderer.scene.camera.transform)); &(LCR_renderer.scene.camera.transform));
#if LCR_SETTING_SMOOTH_ANIMATIONS
// now average with previous transform to smooth the animation out:
S3L_vec3Add(&(LCR_renderer.scene.camera.transform.translation),
transPrev.translation);
/* LCR_renderer.scene.camera.transform.translation.x /= 2;
TPE_Unit angleDiff = s3l_scene.camera.transform.rotation.y - LCR_renderer.scene.camera.transform.translation.y /= 2;
(TPE_vec2Angle(toCar.x,toCar.z) - 128); LCR_renderer.scene.camera.transform.translation.z /= 2;
s3l_scene.camera.transform.rotation.y -= transPrev.rotation.x -= LCR_renderer.scene.camera.transform.rotation.x;
(angleDiff < 100 && angleDiff > -100) ? angleDiff / 2 : angleDiff; transPrev.rotation.y -= LCR_renderer.scene.camera.transform.rotation.y;
*/
if (S3L_abs(transPrev.rotation.x) < S3L_F / 4)
LCR_renderer.scene.camera.transform.rotation.x += transPrev.rotation.x / 2;
LCR_renderer.scene.camera.transform.rotation.y += transPrev.rotation.y / 2;
#endif
} }
void LCR_rendererDraw(void) void LCR_rendererDraw(void)
{ {
LCR_renderer.previousTriID = -1; LCR_renderer.previousTriID = -1;
@ -1394,12 +1393,11 @@ LCR_renderer.wheelTurn = S3L_sin(LCR_renderer.frame * 4);
_LCR_rendererAnimateCar(); _LCR_rendererAnimateCar();
#endif #endif
LCR_rendererCameraFollow();
LCR_drawLevelFloor(); LCR_drawLevelFloor();
LCR_rendererDrawLOD(); LCR_rendererDrawLOD();
S3L_drawScene(LCR_renderer.scene); S3L_drawScene(LCR_renderer.scene);
LCR_renderer.frame++; LCR_renderer.frame++;
} }

View file

@ -102,18 +102,28 @@
#ifndef LCR_SETTING_CAMERA_HEIGHT #ifndef LCR_SETTING_CAMERA_HEIGHT
/** Base height of the car follow camera, in 4ths of map block height. */ /** Base height of the car follow camera, in 4ths of map block height. */
#define LCR_SETTING_CAMERA_HEIGHT 2 #define LCR_SETTING_CAMERA_HEIGHT 4
#endif #endif
#ifndef LCR_SETTING_CAMERA_HEIGHT_BAND #ifndef LCR_SETTING_CAMERA_HEIGHT_BAND
/** Size of height band of the follow camera, in same units as base height. */ /** Size of height band of the follow camera, in same units as base height. */
#define LCR_SETTING_CAMERA_HEIGHT_BAND 1 #define LCR_SETTING_CAMERA_HEIGHT_BAND 2
#endif #endif
#ifndef LCR_SETTING_CAMERA_MAX_DISTANCE #ifndef LCR_SETTING_CAMERA_MAX_DISTANCE
/** Maximum horizontal distance of the car follow camera, in 4ths of map block /** Maximum horizontal distance of the car follow camera, in 4ths of map block
width. */ width. */
#define LCR_SETTING_CAMERA_MAX_DISTANCE 2 #define LCR_SETTING_CAMERA_MAX_DISTANCE 6
#endif
#ifndef LCR_SETTING_GHOST_COLOR
/** Color of the ghost car (in RGB565). */
#define LCR_SETTING_GHOST_COLOR 0xff00
#endif
#ifndef LCR_SETTING_SMOOTH_ANIMATIONS
/** Whether to smooth out animations (car physics, camera movement etc.). */
#define LCR_SETTING_SMOOTH_ANIMATIONS 1
#endif #endif
#endif // guard #endif // guard