mirror of
https://github.com/luksamuk/engine-psx.git
synced 2025-04-28 13:28:02 +03:00
Improve and optimize parallax generation and drawing
This commit is contained in:
parent
09e17d3bbb
commit
774034dce6
5 changed files with 81 additions and 118 deletions
|
@ -41,16 +41,14 @@ single = false
|
|||
|
||||
# =============
|
||||
[island2]
|
||||
width = 256
|
||||
height = 40
|
||||
u0 = 0
|
||||
v0 = 44
|
||||
scrollx = 0.25
|
||||
y0 = 80
|
||||
single = false
|
||||
|
||||
[[island2.parts]]
|
||||
u0 = 0
|
||||
v0 = 44
|
||||
width = 256
|
||||
|
||||
# =============
|
||||
# Water starts at BG1.
|
||||
# Anything with v0 >= 256 is at BG1
|
||||
|
|
|
@ -20,32 +20,18 @@
|
|||
height: u16
|
||||
*/
|
||||
|
||||
// Holds a single parallax strip part.
|
||||
// Parts are a horizontal slice of a single strip.
|
||||
// Holds a single parallax strip for a level.
|
||||
// A strip is a horizontally-repeating quad.
|
||||
typedef struct {
|
||||
uint8_t u0;
|
||||
uint8_t v0;
|
||||
uint8_t bgindex;
|
||||
uint16_t width;
|
||||
uint16_t height;
|
||||
|
||||
// Calculated on load
|
||||
uint16_t offsetx;
|
||||
} ParallaxPart;
|
||||
|
||||
// Holds a single parallax strip for a level.
|
||||
// A strip may be a horizontally-repeating quad, or it
|
||||
// may be composed of more than one quad that forms a bigger strip.
|
||||
typedef struct {
|
||||
uint8_t num_parts;
|
||||
uint8_t bgindex;
|
||||
uint8_t is_single;
|
||||
int32_t scrollx;
|
||||
int32_t speedx;
|
||||
int16_t y0;
|
||||
ParallaxPart *parts;
|
||||
|
||||
// Calculated on load
|
||||
uint16_t width;
|
||||
|
||||
// State
|
||||
int32_t rposx;
|
||||
|
|
110
src/parallax.c
110
src/parallax.c
|
@ -1,4 +1,5 @@
|
|||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#include "parallax.h"
|
||||
#include "util.h"
|
||||
|
@ -9,6 +10,11 @@
|
|||
extern ArenaAllocator _level_arena;
|
||||
extern uint8_t level_fade;
|
||||
|
||||
// Pre-allocated parallax polygons
|
||||
#define PRL_POLYS 200
|
||||
POLY_FT4 prl_polys[2][PRL_POLYS];
|
||||
uint8_t prl_current_buffer = 0;
|
||||
|
||||
void
|
||||
load_parallax(Parallax *parallax, const char *filename)
|
||||
{
|
||||
|
@ -33,40 +39,38 @@ load_parallax(Parallax *parallax, const char *filename)
|
|||
sizeof(ParallaxStrip) * parallax->num_strips);
|
||||
for(uint8_t i = 0; i < parallax->num_strips; i++) {
|
||||
ParallaxStrip *strip = ¶llax->strips[i];
|
||||
strip->width = 0;
|
||||
|
||||
strip->num_parts = get_byte(bytes, &b);
|
||||
strip->u0 = get_byte(bytes, &b);
|
||||
strip->v0 = get_byte(bytes, &b);
|
||||
strip->width = get_short_be(bytes, &b);
|
||||
strip->height = get_short_be(bytes, &b);
|
||||
strip->bgindex = get_byte(bytes, &b);
|
||||
strip->is_single = get_byte(bytes, &b);
|
||||
strip->scrollx = get_long_be(bytes, &b);
|
||||
strip->speedx = get_long_be(bytes, &b);
|
||||
strip->y0 = get_short_be(bytes, &b);
|
||||
|
||||
strip->rposx = 0;
|
||||
|
||||
strip->parts = alloc_arena_malloc(
|
||||
&_level_arena,
|
||||
sizeof(ParallaxPart) * strip->num_parts);
|
||||
for(uint8_t j = 0; j < strip->num_parts; j++) {
|
||||
ParallaxPart *part = &strip->parts[j];
|
||||
|
||||
part->u0 = get_byte(bytes, &b);
|
||||
part->v0 = get_byte(bytes, &b);
|
||||
part->bgindex = get_byte(bytes, &b);
|
||||
part->width = get_short_be(bytes, &b);
|
||||
part->height = get_short_be(bytes, &b);
|
||||
part->offsetx = (j == 0)
|
||||
? 0
|
||||
: (strip->parts[j-1].offsetx + strip->parts[j-1].width);
|
||||
strip->width += part->width;
|
||||
}
|
||||
}
|
||||
|
||||
free(bytes);
|
||||
|
||||
// Pre-allocate polygons
|
||||
prl_current_buffer = 0;
|
||||
for(uint32_t i = 0; i < PRL_POLYS; i++) {
|
||||
for(int j = 0; j < 2; j++) {
|
||||
POLY_FT4 *poly = &prl_polys[j][i];
|
||||
setPolyFT4(poly);
|
||||
setRGB0(poly, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
parallax_draw(Parallax *prl, Camera *camera,
|
||||
uint8_t tx_mode, int32_t px, int32_t py, int32_t cx, int32_t cy)
|
||||
{
|
||||
uint32_t poly_count = 0;
|
||||
|
||||
// Camera left boundary (fixed 20.12 format)
|
||||
int32_t camera_vx = (camera->pos.vx - (CENTERX << 12));
|
||||
|
||||
|
@ -76,46 +80,52 @@ parallax_draw(Parallax *prl, Camera *camera,
|
|||
ParallaxStrip *strip = &prl->strips[si];
|
||||
// Cast multiplication to avoid sign extension on bit shift
|
||||
// This gets the mult. result but also removes the decimal part
|
||||
int32_t stripx = (uint32_t)(camera_vx * strip->scrollx) >> 24;
|
||||
int32_t stripx = (uint32_t)(camera_vx * -strip->scrollx) >> 24;
|
||||
|
||||
// Coordinates currently start drawing at screen center, so
|
||||
// push them back one screem
|
||||
stripx -= SCREEN_XRES;
|
||||
|
||||
// Update strip relative position when there's speed involved
|
||||
strip->rposx -= strip->speedx;
|
||||
if((strip->rposx >> 12) < -((int32_t)strip->width))
|
||||
strip->rposx = 0;
|
||||
|
||||
for(uint8_t pi = 0; pi < strip->num_parts; pi++) {
|
||||
ParallaxPart *part = &strip->parts[pi];
|
||||
// Calculate part X position based on factor and camera (int format)
|
||||
int32_t vx = stripx + (strip->rposx >> 12);
|
||||
|
||||
// Calculate part X position based on factor and camera (int format)
|
||||
int32_t vx = ((int32_t)part->offsetx) - stripx + (strip->rposx >> 12);
|
||||
// Given that each part is a horizontal piece of a strip, we assume
|
||||
// that these parts repeat at every (strip width), so just draw
|
||||
// all equal parts now at once, until we exhaust the screen width
|
||||
for(int32_t wx = vx;
|
||||
wx < (int32_t)(SCREEN_XRES + strip->width);
|
||||
wx += strip->width)
|
||||
{
|
||||
// Don't draw if strip is outside screen
|
||||
if((wx + strip->width) < 0) continue;
|
||||
|
||||
// Given that each part is a horizontal piece of a strip, we assume
|
||||
// that these parts repeat at every (strip width), so just draw
|
||||
// all equal parts now at once, until we exhaust the screen width
|
||||
for(int32_t wx = vx;
|
||||
wx < (int32_t)(SCREEN_XRES + part->width);
|
||||
wx += part->width)
|
||||
{
|
||||
// Don't draw if strip is outside screen
|
||||
if((wx + part->width) < 0) continue;
|
||||
// TODO: 6 or 8 Depends on CLUT!!!
|
||||
uint16_t curr_px = (uint16_t)(px + ((uint32_t)strip->bgindex << 6));
|
||||
uint16_t curr_cy = (uint16_t)(cy + strip->bgindex);
|
||||
|
||||
// TODO: 6 or 8 Depends on CLUT!!!
|
||||
uint16_t curr_px = (uint16_t)(px + ((uint32_t)part->bgindex << 6));
|
||||
uint16_t curr_cy = (uint16_t)(cy + part->bgindex);
|
||||
//POLY_FT4 *poly = (POLY_FT4 *)get_next_prim();
|
||||
//increment_prim(sizeof(POLY_FT4));
|
||||
//setPolyFT4(poly);
|
||||
POLY_FT4 *poly = &prl_polys[prl_current_buffer][poly_count];
|
||||
|
||||
POLY_FT4 *poly = (POLY_FT4 *)get_next_prim();
|
||||
increment_prim(sizeof(POLY_FT4));
|
||||
setPolyFT4(poly);
|
||||
if(poly->r0 != level_fade)
|
||||
setRGB0(poly, level_fade, level_fade, level_fade);
|
||||
poly->tpage = getTPage(tx_mode & 0x3, 0, curr_px, py);
|
||||
poly->clut = getClut(cx, curr_cy);
|
||||
setXYWH(poly, wx, strip->y0, part->width, part->height);
|
||||
setUVWH(poly, part->u0, part->v0, part->width - 1, part->height - 1);
|
||||
sort_prim(poly, OT_LENGTH - 2); // Layer 5: Background
|
||||
poly->tpage = getTPage(tx_mode & 0x3, 0, curr_px, py);
|
||||
poly->clut = getClut(cx, curr_cy);
|
||||
setXYWH(poly, wx, strip->y0, strip->width, strip->height);
|
||||
setUVWH(poly, strip->u0, strip->v0, strip->width - 1, strip->height - 1);
|
||||
sort_prim(poly, OT_LENGTH - 2); // Layer 5: Background
|
||||
|
||||
poly_count++;
|
||||
assert(poly_count < PRL_POLYS);
|
||||
|
||||
// If drawing a single time, stop now
|
||||
if(strip->is_single) break;
|
||||
}
|
||||
// If drawing a single time, stop now
|
||||
if(strip->is_single) break;
|
||||
}
|
||||
}
|
||||
|
||||
prl_current_buffer ^= 1;
|
||||
}
|
||||
|
|
|
@ -21,37 +21,27 @@ def tofixed12(value: float) -> int:
|
|||
|
||||
|
||||
@dataclass
|
||||
class ParallaxPart:
|
||||
class ParallaxStrip:
|
||||
u0: int = 0
|
||||
v0: int = 0
|
||||
bg_index: int = 0
|
||||
width: int = 0
|
||||
height: int = 0
|
||||
|
||||
def write_to(self, f):
|
||||
f.write(c_ubyte(self.u0))
|
||||
f.write(c_ubyte(self.v0))
|
||||
f.write(c_ubyte(self.bg_index))
|
||||
f.write(c_ushort(self.width))
|
||||
f.write(c_ushort(self.height))
|
||||
|
||||
|
||||
@dataclass
|
||||
class ParallaxStrip:
|
||||
bg_index: int = 0
|
||||
single: bool = False
|
||||
scrollx: float = 0
|
||||
speedx: float = 0
|
||||
y0: int = 0
|
||||
parts: [ParallaxPart] = field(default_factory=list)
|
||||
|
||||
def write_to(self, f):
|
||||
f.write(c_ubyte(len(self.parts)))
|
||||
f.write(c_ubyte(self.u0))
|
||||
f.write(c_ubyte(self.v0))
|
||||
f.write(c_ushort(self.width))
|
||||
f.write(c_ushort(self.height))
|
||||
f.write(c_ubyte(self.bg_index))
|
||||
f.write(c_ubyte(int(self.single)))
|
||||
f.write(c_int(tofixed12(self.scrollx)))
|
||||
f.write(c_int(tofixed12(self.speedx)))
|
||||
f.write(c_short(self.y0))
|
||||
for p in self.parts:
|
||||
p.write_to(f)
|
||||
|
||||
|
||||
@dataclass
|
||||
|
@ -73,29 +63,13 @@ def parse(data) -> Parallax:
|
|||
strip.scrollx = strip_data.get("scrollx", 0)
|
||||
strip.speedx = strip_data.get("speedx", 0)
|
||||
strip.y0 = strip_data.get("y0")
|
||||
height = strip_data.get("height") # Reserved
|
||||
parts = strip_data.get("parts")
|
||||
strip.width = strip_data.get("width")
|
||||
strip.height = strip_data.get("height")
|
||||
|
||||
if not parts:
|
||||
# This is a single-piece strip
|
||||
part = ParallaxPart()
|
||||
v0 = strip_data.get("v0")
|
||||
part.bg_index = int(v0 / 256)
|
||||
part.u0 = strip_data.get("u0")
|
||||
part.v0 = v0 % 256
|
||||
part.width = strip_data.get("width")
|
||||
part.height = height
|
||||
strip.parts.append(part)
|
||||
else:
|
||||
for part_data in parts:
|
||||
part = ParallaxPart()
|
||||
v0 = part_data.get("v0")
|
||||
part.bg_index = int(v0 / 256)
|
||||
part.u0 = part_data.get("u0")
|
||||
part.v0 = v0 % 256
|
||||
part.width = part_data.get("width")
|
||||
part.height = height
|
||||
strip.parts.append(part)
|
||||
v0 = strip_data.get("v0")
|
||||
strip.bg_index = int(v0 / 256)
|
||||
strip.u0 = strip_data.get("u0")
|
||||
strip.v0 = v0 % 256
|
||||
|
||||
p.strips.append(strip)
|
||||
return p
|
||||
|
|
|
@ -1,20 +1,15 @@
|
|||
// -*- mode: c; -*-
|
||||
|
||||
struct ParallaxPart {
|
||||
struct ParallaxStrip {
|
||||
u8 u0;
|
||||
u8 v0;
|
||||
u8 tex_idx;
|
||||
be u16 width;
|
||||
be u16 height;
|
||||
};
|
||||
|
||||
struct ParallaxStrip {
|
||||
u8 num_parts;
|
||||
u8 tex_idx;
|
||||
u8 is_single;
|
||||
be s32 scrollx;
|
||||
be s32 speedx;
|
||||
be s16 y0;
|
||||
ParallaxPart parts[num_parts];
|
||||
};
|
||||
|
||||
struct Parallax {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue