Licar/mods/ribbon.diff
2025-06-29 23:48:01 +02:00

176 lines
5.4 KiB
Diff

Licar mod that adds a simple visual effect, a kind of ribbon light trail.
diff --git a/game.h b/game.h
index b1db32c..e9db9be 100644
--- a/game.h
+++ b/game.h
@@ -335,6 +335,7 @@ struct
uint32_t frame; ///< Current frame number.
uint32_t nextRenderFrameTime; ///< At which frame to render next frame.
uint32_t nextRacingTickTime; ///< When to simulate next physics tick.
+ uint32_t nextRibbonTime;
uint8_t cameraMode;
uint8_t musicOn;
uint8_t keyStates[LCR_KEYS_TOTAL]; /**< Assures unchanging key states
@@ -1102,6 +1103,7 @@ void LCR_gameInit(int argc, const char **argv)
LCR_game.musicOn = LCR_SETTING_MUSIC;
LCR_game.nextRenderFrameTime = 0;
LCR_game.nextRacingTickTime = 0;
+ LCR_game.nextRibbonTime = 0;
LCR_game.cameraMode = LCR_CAMERA_MODE_DRIVE;
LCR_currentMap.blockCount = 0; // means no map loaded
@@ -1771,6 +1773,9 @@ uint8_t LCR_gameStep(uint32_t time)
uint32_t events = paused ? 0 : LCR_racingStep(input);
+ if (LCR_racing.tick % LCR_SETTING_RIBBON_INTERVAL == 0)
+ LCR_rendererRibbonUpdate();
+
#if LCR_SETTING_PARTICLES
LCR_rendererSetParticles(0);
diff --git a/renderer.h b/renderer.h
index 735644e..6941398 100644
--- a/renderer.h
+++ b/renderer.h
@@ -153,6 +153,9 @@ struct
#if LCR_SETTING_PARTICLES
uint_fast16_t particleColor; ///< 0x0000 means no particles active.
#endif
+
+ int16_t ribbonPoints[LCR_SETTING_RIBBON_SEGMENTS * 3];
+ uint8_t ribbonLastSegment;
} LCR_renderer;
/**
@@ -200,6 +203,23 @@ void LCR_rendererSetGhostTransform(LCR_GameUnit position[3],
_LCR_rendererSetModelTransform(LCR_renderer.ghostModel,position,rotation);
}
+void LCR_rendererRibbonUpdate(void)
+{
+ LCR_renderer.ribbonLastSegment =
+ (LCR_renderer.ribbonLastSegment + 1) % LCR_SETTING_RIBBON_SEGMENTS;
+
+ unsigned int n = 3 * LCR_renderer.ribbonLastSegment;
+
+ LCR_renderer.ribbonPoints[n] =
+ LCR_renderer.carModel->transform.translation.x / 2;
+ n++;
+ LCR_renderer.ribbonPoints[n] =
+ LCR_renderer.carModel->transform.translation.y / 2;
+ n++;
+ LCR_renderer.ribbonPoints[n] =
+ LCR_renderer.carModel->transform.translation.z / 2;
+}
+
void LCR_rendererSetCarVisibility(uint8_t visible)
{
LCR_renderer.carModel->config.visible = visible;
@@ -2154,6 +2174,59 @@ void LCR_rendererSetWheelState(LCR_GameUnit rotation, LCR_GameUnit steer)
#endif
}
+void LCR_rendererDrawRibbon(void)
+{
+ S3L_Vec4 p, r;
+ int16_t *s = // this will go backwards
+ LCR_renderer.ribbonPoints + 3 * LCR_renderer.ribbonLastSegment + 2;
+ int16_t prev[3]; // previous values for interpolation: screen x, y and size
+
+ p.x = LCR_renderer.carModel->transform.translation.x;
+ p.y = LCR_renderer.carModel->transform.translation.y;
+ p.z = LCR_renderer.carModel->transform.translation.z;
+ p.w = (LCR_SETTING_RIBBON_SIZE * LCR_SETTING_RESOLUTION_X) / 100;
+
+ S3L_project3DPointToScreen(p,LCR_renderer.scene.camera,&r);
+
+ prev[0] = r.x;
+ prev[1] = r.y;
+ prev[2] = r.w;
+
+ for (int i = 0; i < LCR_SETTING_RIBBON_SEGMENTS; ++i)
+ {
+ p.z = *s * 2; s--;
+ p.y = *s * 2; s--;
+ p.x = *s * 2; s--;
+ p.w = (LCR_SETTING_RIBBON_SIZE * LCR_SETTING_RESOLUTION_X) / 100;
+
+ // reducing size towards the tail:
+ p.w = (p.w * (LCR_SETTING_RIBBON_SEGMENTS - 1 - i))
+ / LCR_SETTING_RIBBON_SEGMENTS;
+
+ if (s <= LCR_renderer.ribbonPoints) // wrap to the end
+ s = LCR_renderer.ribbonPoints + (LCR_SETTING_RIBBON_SEGMENTS - 1) * 3 + 2;
+
+ S3L_project3DPointToScreen(p,LCR_renderer.scene.camera,&r);
+
+ for (int j = 0; j < LCR_SETTING_RIBBON_SUBDIV; ++j)
+ {
+ int w = prev[2] + (j * (r.w - prev[2])) / LCR_SETTING_RIBBON_SUBDIV;
+ int x = prev[0] + (j * (r.x - prev[0])) / LCR_SETTING_RIBBON_SUBDIV
+ - w / 2;
+ int y = prev[1] + (j * (r.y - prev[1])) / LCR_SETTING_RIBBON_SUBDIV
+ - w / 2;
+
+ if (w > 0 && x > 0 && y > 0 &&
+ x < LCR_EFFECTIVE_RESOLUTION_X && y < LCR_EFFECTIVE_RESOLUTION_Y)
+ LCR_rendererDrawRect(x,y,w,w,LCR_SETTING_RIBBON_COLOR,1);
+ }
+
+ prev[0] = r.x;
+ prev[1] = r.y;
+ prev[2] = r.w;
+ }
+}
+
void LCR_rendererDraw3D(void)
{
LCR_LOG2("rendering frame (start)");
@@ -2304,6 +2377,8 @@ void LCR_rendererDraw3D(void)
#endif
+ LCR_rendererDrawRibbon();
+
LCR_LOG2("3D rendering (end)");
LCR_LOG2("rendering frame (end)");
}
diff --git a/settings.h b/settings.h
index 332df45..47e27f8 100644
--- a/settings.h
+++ b/settings.h
@@ -200,6 +200,32 @@
#define LCR_SETTING_COUNTDOWN_MS 2200
#endif
+#ifndef LCR_SETTING_RIBBON_SEGMENTS
+ /** Ribbon mod: how many points to spawn. */
+ #define LCR_SETTING_RIBBON_SEGMENTS 10
+#endif
+
+#ifndef LCR_SETTING_RIBBON_SUBDIV
+ /** Ribbon mod: number of splats to draw per segment, it's good to keep this a
+ power of 2. */
+ #define LCR_SETTING_RIBBON_SUBDIV 16
+#endif
+
+#ifndef LCR_SETTING_RIBBON_INTERVAL
+ /** Ribbon mod: how often to spawn a new ribbon point (in physics ticks). */
+ #define LCR_SETTING_RIBBON_INTERVAL 4
+#endif
+
+#ifndef LCR_SETTING_RIBBON_SIZE
+ /** Ribbon mod: ribbon splat size (in percents of screen width). */
+ #define LCR_SETTING_RIBBON_SIZE 6
+#endif
+
+#ifndef LCR_SETTING_RIBBON_COLOR
+ /** Ribbon mod: ribbon color. */
+ #define LCR_SETTING_RIBBON_COLOR 0xffe6
+#endif
+
#ifndef LCR_SETTING_MAP_CHUNK_RELOAD_INTERVAL
/** Interval in rendering frames of reloading map chunks, should ideally be
kept a power of two, can't be 0. */