mirror of https://github.com/nmlgc/ReC98.git
[Maintenance] Remove the `operator =` overloads for Subpixels
At least we've now documented their negative effects. Part of P0110, funded by [Anonymous] and Blue Bolt.
This commit is contained in:
parent
7c4d31c02b
commit
2ef3db3052
|
@ -130,6 +130,47 @@ case it's part of an arithmetic expression that was promoted to `int`.
|
|||
// Note the opposite order of variables!
|
||||
```
|
||||
|
||||
* For trivially copyable structures, copy assignments are optimized to an
|
||||
equivalent of `memcpy()`:
|
||||
|
||||
| Structure size | (no flags) | -G |
|
||||
|----------------|-------------|----------------------|
|
||||
| 1 | via `AL` | via `AL` |
|
||||
| 2 | via `AX` | via `AX` |
|
||||
| 3 | `SCOPY@` | via `AX` and `AL` |
|
||||
| 4 | via `DX:AX` | via `DX:AX` |
|
||||
| 5, 7, 9 | `SCOPY@` | via `AX` and `AL` |
|
||||
| 6, 8 | `SCOPY@` | via `AX` |
|
||||
| 10, 12, 14, … | `SCOPY@` | `REP MOVSW` |
|
||||
| 11, 13, 15, … | `SCOPY@` | `REP MOVSW`, `MOVSB` |
|
||||
|
||||
(With the `-3` flag, `EAX` is used instead of `DX:AX` in the 4-byte case,
|
||||
but everything else stays the same.)
|
||||
|
||||
Breaking triviality by overloading `operator =` in any of the structure
|
||||
members also breaks this optimization. In some cases, it might be possible
|
||||
to recreate it, by simulating triviality in an overloaded copy assignment
|
||||
operator inside the class in question:
|
||||
|
||||
```c++
|
||||
struct Nontrivial {
|
||||
nontrivial_char_t e[100];
|
||||
// Functions containing local classes aren't expanded inline, so...
|
||||
struct Trivial {
|
||||
char e[100];
|
||||
};
|
||||
|
||||
void operator =(const Nontrivial &other) {
|
||||
reinterpret_cast<Trivial &>(*this) = (
|
||||
reinterpret_cast<const Trivial &>(other)
|
||||
);
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
However, this only generates identical code to the original optimization if
|
||||
passing the `other` parameter can be inlined, which isn't always the case.
|
||||
|
||||
## `switch` statements
|
||||
|
||||
* Sequence of the individual cases is identical in both C and ASM
|
||||
|
|
|
@ -82,7 +82,7 @@ bool16 pattern_velocity_set(
|
|||
switch(pattern) {
|
||||
case PP_1:
|
||||
ret_y.v = speed;
|
||||
ret_x = 0.0f;
|
||||
ret_x.set(0.0f);
|
||||
done = true;
|
||||
break;
|
||||
case PP_1_AIMED:
|
||||
|
@ -179,7 +179,7 @@ inline subpixel_t base_speed_for_rank(void)
|
|||
#define pellet_init(pellet, left, top, pattern) \
|
||||
pellet->decay_frame = 0; \
|
||||
pellet->cur_left.v = TO_SP(left); \
|
||||
pellet->cur_top = top; \
|
||||
pellet->cur_top.v = TO_SP(top); \
|
||||
pellet->cloud_left = left; \
|
||||
pellet->cloud_top = top; \
|
||||
if(spawn_with_cloud) { \
|
||||
|
@ -271,7 +271,7 @@ void CPellets::add_single(
|
|||
p->age = 0;
|
||||
alive_count++;
|
||||
p->spin_center.x.v = TO_SP(spin_center_x);
|
||||
p->spin_center.y = spin_center_y;
|
||||
p->spin_center.y.v = TO_SP(spin_center_y);
|
||||
if(motion_type == PM_SPIN) {
|
||||
vector2(vel_x.v, vel_y.v, speed_for_motion_fixed, angle);
|
||||
p->spin_velocity.x.v = vel_x.v;
|
||||
|
@ -339,27 +339,27 @@ void CPellets::motion_type_apply_for_cur(void)
|
|||
|| (p->cur_top.v <= to_sp(PELLET_BOUNCE_TOP_MIN))
|
||||
) {
|
||||
p->velocity.x.v = -p->velocity.x.v;
|
||||
p->velocity.y = 0.0f;
|
||||
p->velocity.y.set(0.0f);
|
||||
p->motion_type = PM_GRAVITY;
|
||||
// Nope, this doesn't help.
|
||||
if(p->cur_left.v <= to_sp(PELLET_LEFT_MIN)) {
|
||||
p->cur_left = (PELLET_LEFT_MIN + 1.0f);
|
||||
p->cur_left.set(PELLET_LEFT_MIN + 1.0f);
|
||||
}
|
||||
if(p->cur_left.v >= to_sp(PELLET_LEFT_MAX)) {
|
||||
p->cur_left = (PELLET_LEFT_MAX - 1.0f);
|
||||
p->cur_left.set(PELLET_LEFT_MAX - 1.0f);
|
||||
}
|
||||
if(p->cur_top.v <= to_sp(PELLET_TOP_MIN)) {
|
||||
p->cur_top = (PELLET_TOP_MIN + 1.0f);
|
||||
p->cur_top.set(PELLET_TOP_MIN + 1.0f);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case PM_FALL_STRAIGHT_FROM_TOP_THEN_NORMAL:
|
||||
if(p->cur_top.to_screen() <= PELLET_BOUNCE_TOP_MIN) {
|
||||
p->velocity.x = 0.0f;
|
||||
p->velocity.x.set(0.0f);
|
||||
p->velocity.y.v = p->speed.v;
|
||||
p->motion_type = PM_NORMAL;
|
||||
if(p->cur_top.to_screen() <= PLAYFIELD_TOP) {
|
||||
p->cur_top = (PLAYFIELD_TOP + 1.0f);
|
||||
p->cur_top.set(PLAYFIELD_TOP + 1.0f);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -370,8 +370,7 @@ void CPellets::motion_type_apply_for_cur(void)
|
|||
p->cur_top.v = (to_spin_circle(Sin8(p->angle)) + p->spin_center.y.v);
|
||||
p->spin_center.x.v += p->spin_velocity.x.v;
|
||||
p->spin_center.y.v += p->spin_velocity.y.v;
|
||||
p->velocity.x = 0.0f;
|
||||
p->velocity.y = 0.0f;
|
||||
p->velocity.set(0.0f, 0.0f);
|
||||
p->angle += PELLET_SPIN_DELTA_ANGLE;
|
||||
#undef to_spin_circle
|
||||
break;
|
||||
|
|
|
@ -30,11 +30,13 @@ public:
|
|||
this->v -= static_cast<T>(to_sp(screen_v));
|
||||
}
|
||||
|
||||
void operator =(float screen_v) {
|
||||
// No overloads of `operator =()`, since the class needs to be trivially
|
||||
// copyable.
|
||||
void set(float screen_v) {
|
||||
v = static_cast<T>(to_sp(screen_v));
|
||||
}
|
||||
|
||||
void operator =(const T &screen_v) {
|
||||
void set(const T &screen_v) {
|
||||
v = TO_SP(screen_v);
|
||||
}
|
||||
|
||||
|
@ -55,13 +57,8 @@ template <class T> struct SPPointBase {
|
|||
T x, y;
|
||||
|
||||
void set(float screen_x, float screen_y) {
|
||||
x = screen_x;
|
||||
y = screen_y;
|
||||
}
|
||||
|
||||
void set(const T &screen_x, const T &screen_y) {
|
||||
x = screen_x;
|
||||
y = screen_y;
|
||||
x.set(screen_x);
|
||||
y.set(screen_y);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -4,9 +4,9 @@ typedef struct {
|
|||
SPPoint velocity;
|
||||
|
||||
void init(float screen_x, float screen_y) {
|
||||
cur.x = screen_x;
|
||||
prev.x = screen_x;
|
||||
cur.y = screen_y;
|
||||
prev.y = screen_y;
|
||||
cur.x.set(screen_x);
|
||||
prev.x.set(screen_x);
|
||||
cur.y.set(screen_y);
|
||||
prev.y.set(screen_y);
|
||||
}
|
||||
} motion_t;
|
||||
|
|
|
@ -66,8 +66,8 @@ struct ShotAddIterator {
|
|||
#define MISSILE_R shot->type = ST_MISSILE_RIGHT
|
||||
#define MISSILE_S shot->type = ST_MISSILE_STRAIGHT
|
||||
|
||||
#define VELOCITY_X(screen_x) shot->pos.velocity.x = screen_x;
|
||||
#define VELOCITY_Y(screen_y) shot->pos.velocity.y = screen_y;
|
||||
#define VELOCITY_X(screen_x) shot->pos.velocity.x.set(screen_x);
|
||||
#define VELOCITY_Y(screen_y) shot->pos.velocity.y.set(screen_y);
|
||||
|
||||
#define VELOCITY_XY(screen_x, screen_y) \
|
||||
VELOCITY_X(screen_x); \
|
||||
|
|
|
@ -40,7 +40,7 @@ void pascal near stage2_setup(void)
|
|||
midboss_render_func = midboss2_render;
|
||||
midboss.frames_until = 2750;
|
||||
midboss.pos.init(192, -32);
|
||||
midboss.pos.velocity.set(0, 0.5f);
|
||||
midboss.pos.velocity.set(0.0f, 0.5f);
|
||||
midboss.hp = 1400;
|
||||
midboss.sprite = 202;
|
||||
|
||||
|
@ -67,7 +67,7 @@ void pascal near stage3_setup(void)
|
|||
midboss_render_func = midboss3_render;
|
||||
midboss.frames_until = 5750;
|
||||
midboss.pos.init(192, -32);
|
||||
midboss.pos.velocity.set(0, 0.5f);
|
||||
midboss.pos.velocity.set(0.0f, 0.5f);
|
||||
midboss.hp = 1400;
|
||||
midboss.sprite = 208;
|
||||
|
||||
|
@ -97,7 +97,7 @@ void pascal near stage4_setup(void)
|
|||
midboss_render_func = midboss4_render;
|
||||
midboss.frames_until = 3900;
|
||||
midboss.pos.init(192, -32);
|
||||
midboss.pos.velocity.set(0, 0.5f);
|
||||
midboss.pos.velocity.set(0.0f, 0.5f);
|
||||
midboss.hp = 1100;
|
||||
midboss.sprite = 208;
|
||||
|
||||
|
@ -126,7 +126,7 @@ void pascal near stage5_setup(void)
|
|||
midboss_render_func = midboss5_render;
|
||||
midboss.frames_until = 4800;
|
||||
midboss.pos.init(192, -32);
|
||||
midboss.pos.velocity.set(0, 0.5f);
|
||||
midboss.pos.velocity.set(0.0f, 0.5f);
|
||||
midboss.hp = 1550;
|
||||
midboss.sprite = 212;
|
||||
|
||||
|
|
|
@ -18,7 +18,7 @@ void pascal near shot_mima_l2(void)
|
|||
if(sai.i <= 2) {
|
||||
if(sai.i == 2) { shot->from_option_l(); }
|
||||
else/*i == 1*/ { shot->from_option_r(); }
|
||||
shot->pos.velocity.y = -20.0f;
|
||||
shot->pos.velocity.y.set(-20.0f);
|
||||
shot->set_option_sprite_and_damage(5);
|
||||
} else {
|
||||
shot->set_random_angle_forwards();
|
||||
|
@ -37,12 +37,12 @@ void pascal near shot_mima_l3(void)
|
|||
if(sai.i <= 2) {
|
||||
if(sai.i == 2) { shot->from_option_l(); }
|
||||
else/*i == 1*/ { shot->from_option_r(); }
|
||||
shot->pos.velocity.y = -20.0f;
|
||||
shot->pos.velocity.y.set(-20.0f);
|
||||
shot->set_option_sprite_and_damage(5);
|
||||
} else {
|
||||
if(sai.i == 4) { shot->pos.cur.x -= 8.0f; }
|
||||
else/*i == 3*/ { shot->pos.cur.x += 8.0f; }
|
||||
shot->pos.velocity.y = -12.0f;
|
||||
shot->pos.velocity.y.set(-12.0f);
|
||||
shot->damage = 7;
|
||||
}
|
||||
if(sai.next() <= 0) {
|
||||
|
@ -63,12 +63,12 @@ void pascal near shot_mima_l4(void)
|
|||
case 3: shot->from_option_l(); break;
|
||||
case 2: shot->from_option_r(); break;
|
||||
}
|
||||
shot->pos.velocity.y = -20.0f;
|
||||
shot->pos.velocity.y.set(-20.0f);
|
||||
shot->set_option_sprite_and_damage(4);
|
||||
} else {
|
||||
if(sai.i == 6) { shot->pos.cur.x -= 8.0f; }
|
||||
else/* i== 5*/ { shot->pos.cur.x += 8.0f; }
|
||||
shot->pos.velocity.y = -12.0f;
|
||||
shot->pos.velocity.y.set(-12.0f);
|
||||
shot->damage = 7;
|
||||
}
|
||||
if(sai.next() <= 0) {
|
||||
|
@ -90,7 +90,7 @@ void pascal near shot_mima_l5(void)
|
|||
case 1: VELOCITY_X(-1.0f); shot->from_option_r(); break;
|
||||
case 2: shot->from_option_r(); break;
|
||||
}
|
||||
shot->pos.velocity.y = -20.0f;
|
||||
shot->pos.velocity.y.set(-20.0f);
|
||||
shot->set_option_sprite_and_damage(4);
|
||||
} else {
|
||||
shot_velocity_set(&shot->pos.velocity, sai.angle);
|
||||
|
@ -115,7 +115,7 @@ void pascal near shot_mima_l6(void)
|
|||
case 2: VELOCITY_X(-0.5f); shot->from_option_r(); break;
|
||||
case 3: VELOCITY_X( 0.5f); shot->from_option_l(); break;
|
||||
}
|
||||
shot->pos.velocity.y = -20.0f;
|
||||
shot->pos.velocity.y.set(-20.0f);
|
||||
shot->set_option_sprite_and_damage(4);
|
||||
} else {
|
||||
shot_velocity_set(&shot->pos.velocity, sai.angle);
|
||||
|
@ -143,7 +143,7 @@ void pascal near shot_mima_l7(void)
|
|||
case 3: VELOCITY_X( 0.5f); shot->from_option_l(); break;
|
||||
case 5: shot->from_option_l(); break;
|
||||
}
|
||||
shot->pos.velocity.y = -20.0f;
|
||||
shot->pos.velocity.y.set(-20.0f);
|
||||
shot->set_option_sprite_and_damage(4);
|
||||
} else {
|
||||
shot_velocity_set(&shot->pos.velocity, sai.angle);
|
||||
|
@ -162,7 +162,7 @@ void pascal near shot_mima_l8(void)
|
|||
sai.angle = 186;
|
||||
while(( shot = shots_add() ) != NULL) {
|
||||
if(sai.i <= 6) {
|
||||
shot->pos.velocity.y = -20.0f;
|
||||
shot->pos.velocity.y.set(-20.0f);
|
||||
switch(sai.i - 1) {
|
||||
// Beware, non-sequential case order!
|
||||
case 0: VELOCITY_XY( 1.75f, -18.0f); shot->from_option_r(8.0f); break;
|
||||
|
@ -172,7 +172,7 @@ void pascal near shot_mima_l8(void)
|
|||
case 3: VELOCITY_X ( 0.5f); shot->from_option_l(); break;
|
||||
case 5: shot->from_option_l(); break;
|
||||
}
|
||||
shot->pos.velocity.y = -20.0f;
|
||||
shot->pos.velocity.y.set(-20.0f);
|
||||
shot->set_option_sprite_and_damage(4);
|
||||
} else {
|
||||
shot_velocity_set(&shot->pos.velocity, sai.angle);
|
||||
|
@ -190,7 +190,7 @@ void pascal near shot_mima_l9(void)
|
|||
SHOT_FUNC_INIT(6, SC_6X, SC_3X, i += 4);
|
||||
while(( shot = shots_add() ) != NULL) {
|
||||
if(sai.i <= 6) {
|
||||
shot->pos.velocity.y = -20.0f;
|
||||
shot->pos.velocity.y.set(-20.0f);
|
||||
switch(sai.i - 1) {
|
||||
case 0: VELOCITY_XY( 2.625f, -18.0f); shot->from_option_r(8.0f); break;
|
||||
case 1: VELOCITY_XY(-2.625f, -18.0f); shot->from_option_l(8.0f); break;
|
||||
|
|
|
@ -102,7 +102,7 @@ void pascal near shot_yuuka_l4(void)
|
|||
sai.i = 1;
|
||||
}
|
||||
}
|
||||
shot->pos.velocity.y = 2.0f;
|
||||
shot->pos.velocity.y.set(2.0f);
|
||||
shot->set_option_sprite_and_damage(6);
|
||||
}
|
||||
shot_velocity_set(&shot->pos.velocity, sai.angle);
|
||||
|
|
Loading…
Reference in New Issue