diff --git a/assets/sprites/earth.png b/assets/sprites/earth.png new file mode 100644 index 0000000..58d1b19 Binary files /dev/null and b/assets/sprites/earth.png differ diff --git a/src/engine/parallax.c b/src/engine/parallax.c index 0e048e5..27f885a 100644 --- a/src/engine/parallax.c +++ b/src/engine/parallax.c @@ -1,4 +1,5 @@ #include "engine/parallax.h" +#include "engine/assets.h" #include "engine/camera.h" #include #include @@ -795,6 +796,21 @@ static void generate_moon_far(Parallax *p, SDL_Renderer *renderer) { p->far_layer.scroll_y = 0.03f; p->far_layer.active = true; p->far_layer.owns_texture = true; + + /* Earth in the sky — non-tiling feature sprite */ + SDL_Texture *earth_tex = assets_get_texture("assets/sprites/earth.png"); + if (earth_tex) { + int ew, eh; + SDL_QueryTexture(earth_tex, NULL, NULL, &ew, &eh); + p->feature.texture = earth_tex; + p->feature.tex_w = ew; + p->feature.tex_h = eh; + p->feature.x = (float)(w / 4); + p->feature.y = (float)(h * 0.08f); + p->feature.scroll_x = 0.03f; /* same as far layer */ + p->feature.scroll_y = 0.03f; + p->feature.active = true; + } } static void generate_moon_near(Parallax *p, SDL_Renderer *renderer) { @@ -953,9 +969,25 @@ static void render_layer(const ParallaxLayer *layer, const Camera *cam, } } +static void render_feature(const ParallaxFeature *f, const Camera *cam, + SDL_Renderer *renderer) { + if (!f->active || !f->texture) return; + + /* Scroll with camera but do not tile */ + int draw_x = (int)(f->x - cam->pos.x * f->scroll_x); + int draw_y = (int)(f->y - cam->pos.y * f->scroll_y); + + SDL_Rect dst = {draw_x, draw_y, f->tex_w, f->tex_h}; + if (dst.x + dst.w < 0 || dst.x >= SCREEN_WIDTH) return; + if (dst.y + dst.h < 0 || dst.y >= SCREEN_HEIGHT) return; + + SDL_RenderCopy(renderer, f->texture, NULL, &dst); +} + void parallax_render(const Parallax *p, const Camera *cam, SDL_Renderer *renderer) { if (!p || !cam) return; render_layer(&p->far_layer, cam, renderer); + render_feature(&p->feature, cam, renderer); render_layer(&p->near_layer, cam, renderer); } @@ -974,4 +1006,8 @@ void parallax_free(Parallax *p) { } p->near_layer.texture = NULL; p->near_layer.active = false; + + /* Feature sprite is asset-manager-owned — just clear the reference */ + p->feature.texture = NULL; + p->feature.active = false; } diff --git a/src/engine/parallax.h b/src/engine/parallax.h index 11c3de2..35f7d8f 100644 --- a/src/engine/parallax.h +++ b/src/engine/parallax.h @@ -18,10 +18,21 @@ typedef struct ParallaxLayer { bool owns_texture; /* true if we generated it (must free) */ } ParallaxLayer; -/* Parallax background system — up to two layers */ +/* A non-tiling sprite drawn once in the background (e.g. Earth from moon) */ +typedef struct ParallaxFeature { + SDL_Texture *texture; /* sprite image */ + int tex_w, tex_h; /* sprite dimensions */ + float x, y; /* base position (pixels, screen) */ + float scroll_x; /* horizontal scroll factor */ + float scroll_y; /* vertical scroll factor */ + bool active; +} ParallaxFeature; + +/* Parallax background system — two tiling layers + optional feature sprite */ typedef struct Parallax { - ParallaxLayer far_layer; /* distant background (stars) */ - ParallaxLayer near_layer; /* mid-ground background (nebula) */ + ParallaxLayer far_layer; /* distant background (stars) */ + ParallaxLayer near_layer; /* mid-ground background (nebula) */ + ParallaxFeature feature; /* non-tiling overlay (planet, etc.) */ } Parallax; /* Initialize parallax (zeroes everything) */