|
@@ -74,6 +74,9 @@ using Render::GL::Humanoid::saturate_color;
|
|
|
|
|
|
|
|
class BuilderRenderer : public HumanoidRendererBase {
|
|
class BuilderRenderer : public HumanoidRendererBase {
|
|
|
public:
|
|
public:
|
|
|
|
|
+ friend void
|
|
|
|
|
+ register_builder_renderer(Render::GL::EntityRendererRegistry ®istry);
|
|
|
|
|
+
|
|
|
auto get_proportion_scaling() const -> QVector3D override {
|
|
auto get_proportion_scaling() const -> QVector3D override {
|
|
|
return {0.98F, 1.01F, 0.96F};
|
|
return {0.98F, 1.01F, 0.96F};
|
|
|
}
|
|
}
|
|
@@ -123,60 +126,26 @@ public:
|
|
|
|
|
|
|
|
if (anim.is_constructing) {
|
|
if (anim.is_constructing) {
|
|
|
|
|
|
|
|
|
|
+ uint32_t const pose_selector = seed % 100;
|
|
|
|
|
+
|
|
|
float const phase_offset = float(seed % 100) * 0.0628F;
|
|
float const phase_offset = float(seed % 100) * 0.0628F;
|
|
|
float const cycle_speed = 2.0F + float(seed % 50) * 0.02F;
|
|
float const cycle_speed = 2.0F + float(seed % 50) * 0.02F;
|
|
|
float const swing_cycle =
|
|
float const swing_cycle =
|
|
|
std::fmod(anim.time * cycle_speed + phase_offset, 1.0F);
|
|
std::fmod(anim.time * cycle_speed + phase_offset, 1.0F);
|
|
|
|
|
|
|
|
- float swing_angle;
|
|
|
|
|
- float body_lean;
|
|
|
|
|
- float crouch_amount;
|
|
|
|
|
-
|
|
|
|
|
- if (swing_cycle < 0.3F) {
|
|
|
|
|
|
|
+ if (pose_selector < 40) {
|
|
|
|
|
|
|
|
- float const t = swing_cycle / 0.3F;
|
|
|
|
|
- swing_angle = t * 0.85F;
|
|
|
|
|
- body_lean = -t * 0.08F;
|
|
|
|
|
- crouch_amount = 0.0F;
|
|
|
|
|
- } else if (swing_cycle < 0.5F) {
|
|
|
|
|
|
|
+ apply_hammering_pose(controller, swing_cycle, asym, seed);
|
|
|
|
|
+ } else if (pose_selector < 70) {
|
|
|
|
|
|
|
|
- float const t = (swing_cycle - 0.3F) / 0.2F;
|
|
|
|
|
- swing_angle = 0.85F - t * 1.3F;
|
|
|
|
|
- body_lean = -0.08F + t * 0.22F;
|
|
|
|
|
- crouch_amount = t * 0.06F;
|
|
|
|
|
- } else if (swing_cycle < 0.6F) {
|
|
|
|
|
|
|
+ apply_kneeling_work_pose(controller, swing_cycle, asym, seed);
|
|
|
|
|
+ } else if (pose_selector < 90) {
|
|
|
|
|
|
|
|
- float const t = (swing_cycle - 0.5F) / 0.1F;
|
|
|
|
|
- swing_angle = -0.45F + t * 0.15F;
|
|
|
|
|
- body_lean = 0.14F - t * 0.04F;
|
|
|
|
|
- crouch_amount = 0.06F - t * 0.02F;
|
|
|
|
|
|
|
+ apply_sawing_pose(controller, swing_cycle, asym, seed);
|
|
|
} else {
|
|
} else {
|
|
|
|
|
|
|
|
- float const t = (swing_cycle - 0.6F) / 0.4F;
|
|
|
|
|
- swing_angle = -0.30F + t * 0.30F;
|
|
|
|
|
- body_lean = 0.10F * (1.0F - t);
|
|
|
|
|
- crouch_amount = 0.04F * (1.0F - t);
|
|
|
|
|
|
|
+ apply_lifting_pose(controller, swing_cycle, asym, seed);
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
- float const torso_y_offset = -crouch_amount;
|
|
|
|
|
-
|
|
|
|
|
- float const hammer_y = HP::SHOULDER_Y + 0.10F + swing_angle * 0.20F;
|
|
|
|
|
- float const hammer_forward =
|
|
|
|
|
- 0.18F + std::abs(swing_angle) * 0.15F + body_lean * 0.5F;
|
|
|
|
|
- float const hammer_down =
|
|
|
|
|
- swing_cycle > 0.4F && swing_cycle < 0.65F ? 0.08F : 0.0F;
|
|
|
|
|
-
|
|
|
|
|
- QVector3D const hammer_hand(-0.06F + asym,
|
|
|
|
|
- hammer_y - hammer_down + torso_y_offset,
|
|
|
|
|
- hammer_forward);
|
|
|
|
|
-
|
|
|
|
|
- float const brace_y =
|
|
|
|
|
- HP::WAIST_Y + 0.12F + torso_y_offset - crouch_amount * 0.5F;
|
|
|
|
|
- float const brace_forward = 0.15F + body_lean * 0.3F;
|
|
|
|
|
- QVector3D const brace_hand(0.14F - asym * 0.5F, brace_y, brace_forward);
|
|
|
|
|
-
|
|
|
|
|
- controller.placeHandAt(true, hammer_hand);
|
|
|
|
|
- controller.placeHandAt(false, brace_hand);
|
|
|
|
|
return;
|
|
return;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
@@ -196,11 +165,164 @@ public:
|
|
|
const HumanoidAnimationContext &anim_ctx,
|
|
const HumanoidAnimationContext &anim_ctx,
|
|
|
ISubmitter &out) const override {
|
|
ISubmitter &out) const override {
|
|
|
|
|
|
|
|
- draw_stone_hammer(ctx, v, pose, out);
|
|
|
|
|
|
|
+ draw_stone_hammer(ctx, v, pose, anim_ctx, out);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void draw_helmet(const DrawContext &ctx, const HumanoidVariant &v,
|
|
|
|
|
+ const HumanoidPose &pose, ISubmitter &out) const override {
|
|
|
|
|
+
|
|
|
|
|
+ draw_headwrap(ctx, v, pose, out);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void draw_armor(const DrawContext &ctx, const HumanoidVariant &v,
|
|
|
|
|
+ const HumanoidPose &pose,
|
|
|
|
|
+ const HumanoidAnimationContext &anim,
|
|
|
|
|
+ ISubmitter &out) const override {
|
|
|
|
|
+ uint32_t const seed = reinterpret_cast<uintptr_t>(ctx.entity) & 0xFFFFFFFFU;
|
|
|
|
|
+ draw_craftsman_robes(ctx, v, pose, seed, out);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+private:
|
|
|
|
|
+ static constexpr uint32_t KNEEL_SEED_OFFSET = 0x5678U;
|
|
|
|
|
+
|
|
|
|
|
+ void apply_hammering_pose(HumanoidPoseController &controller,
|
|
|
|
|
+ float swing_cycle, float asym,
|
|
|
|
|
+ uint32_t seed) const {
|
|
|
|
|
+ using HP = HumanProportions;
|
|
|
|
|
+
|
|
|
|
|
+ float swing_angle;
|
|
|
|
|
+ float body_lean;
|
|
|
|
|
+ float crouch_amount;
|
|
|
|
|
+
|
|
|
|
|
+ if (swing_cycle < 0.3F) {
|
|
|
|
|
+
|
|
|
|
|
+ float const t = swing_cycle / 0.3F;
|
|
|
|
|
+ swing_angle = t * 0.92F;
|
|
|
|
|
+ body_lean = -t * 0.09F;
|
|
|
|
|
+ crouch_amount = 0.0F;
|
|
|
|
|
+ } else if (swing_cycle < 0.5F) {
|
|
|
|
|
+
|
|
|
|
|
+ float const t = (swing_cycle - 0.3F) / 0.2F;
|
|
|
|
|
+ swing_angle = 0.92F - t * 1.45F;
|
|
|
|
|
+ body_lean = -0.09F + t * 0.26F;
|
|
|
|
|
+ crouch_amount = t * 0.07F;
|
|
|
|
|
+ } else if (swing_cycle < 0.6F) {
|
|
|
|
|
+
|
|
|
|
|
+ float const t = (swing_cycle - 0.5F) / 0.1F;
|
|
|
|
|
+ swing_angle = -0.53F + t * 0.16F;
|
|
|
|
|
+ body_lean = 0.17F - t * 0.05F;
|
|
|
|
|
+ crouch_amount = 0.07F - t * 0.02F;
|
|
|
|
|
+ } else {
|
|
|
|
|
+
|
|
|
|
|
+ float const t = (swing_cycle - 0.6F) / 0.4F;
|
|
|
|
|
+ swing_angle = -0.37F + t * 0.37F;
|
|
|
|
|
+ body_lean = 0.12F * (1.0F - t);
|
|
|
|
|
+ crouch_amount = 0.05F * (1.0F - t);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ float const torso_y_offset = -crouch_amount;
|
|
|
|
|
+ float const hammer_y = HP::SHOULDER_Y + 0.10F + swing_angle * 0.20F;
|
|
|
|
|
+ float const hammer_forward =
|
|
|
|
|
+ 0.18F + std::abs(swing_angle) * 0.15F + body_lean * 0.5F;
|
|
|
|
|
+ float const hammer_down =
|
|
|
|
|
+ swing_cycle > 0.4F && swing_cycle < 0.65F ? 0.08F : 0.0F;
|
|
|
|
|
+
|
|
|
|
|
+ QVector3D const hammer_hand(
|
|
|
|
|
+ -0.06F + asym, hammer_y - hammer_down + torso_y_offset, hammer_forward);
|
|
|
|
|
+
|
|
|
|
|
+ float const brace_y =
|
|
|
|
|
+ HP::WAIST_Y + 0.12F + torso_y_offset - crouch_amount * 0.5F;
|
|
|
|
|
+ float const brace_forward = 0.15F + body_lean * 0.3F;
|
|
|
|
|
+ QVector3D const brace_hand(0.14F - asym * 0.5F, brace_y, brace_forward);
|
|
|
|
|
+
|
|
|
|
|
+ controller.placeHandAt(true, hammer_hand);
|
|
|
|
|
+ controller.placeHandAt(false, brace_hand);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void apply_kneeling_work_pose(HumanoidPoseController &controller, float cycle,
|
|
|
|
|
+ float asym, uint32_t seed) const {
|
|
|
|
|
+ using HP = HumanProportions;
|
|
|
|
|
+
|
|
|
|
|
+ float const kneel_depth =
|
|
|
|
|
+ 0.50F + (hash_01(seed ^ KNEEL_SEED_OFFSET) * 0.12F);
|
|
|
|
|
+ controller.kneel(kneel_depth);
|
|
|
|
|
+
|
|
|
|
|
+ float const work_cycle = std::sin(cycle * std::numbers::pi_v<float> * 2.0F);
|
|
|
|
|
+
|
|
|
|
|
+ float const tool_y = HP::WAIST_Y * 0.32F + work_cycle * 0.07F;
|
|
|
|
|
+ float const tool_x_offset = 0.06F + work_cycle * 0.05F;
|
|
|
|
|
+ QVector3D const tool_hand(-tool_x_offset + asym, tool_y, 0.24F);
|
|
|
|
|
+
|
|
|
|
|
+ float const brace_x = 0.20F - asym * 0.5F;
|
|
|
|
|
+ QVector3D const brace_hand(brace_x, HP::WAIST_Y * 0.28F, 0.22F);
|
|
|
|
|
+
|
|
|
|
|
+ controller.placeHandAt(true, tool_hand);
|
|
|
|
|
+ controller.placeHandAt(false, brace_hand);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void apply_sawing_pose(HumanoidPoseController &controller, float cycle,
|
|
|
|
|
+ float asym, uint32_t seed) const {
|
|
|
|
|
+ using HP = HumanProportions;
|
|
|
|
|
+
|
|
|
|
|
+ controller.lean(QVector3D(0.0F, 0.0F, 1.0F), 0.14F);
|
|
|
|
|
+
|
|
|
|
|
+ float const saw_offset =
|
|
|
|
|
+ std::sin(cycle * std::numbers::pi_v<float> * 4.0F) * 0.14F;
|
|
|
|
|
+
|
|
|
|
|
+ float const saw_y = HP::WAIST_Y + 0.18F;
|
|
|
|
|
+ float const saw_z = 0.22F + saw_offset;
|
|
|
|
|
+
|
|
|
|
|
+ QVector3D const left_hand(-0.10F + asym, saw_y, saw_z);
|
|
|
|
|
+ QVector3D const right_hand(0.10F - asym, saw_y + 0.03F, saw_z);
|
|
|
|
|
+
|
|
|
|
|
+ controller.placeHandAt(true, left_hand);
|
|
|
|
|
+ controller.placeHandAt(false, right_hand);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ void apply_lifting_pose(HumanoidPoseController &controller, float cycle,
|
|
|
|
|
+ float asym, uint32_t seed) const {
|
|
|
|
|
+ using HP = HumanProportions;
|
|
|
|
|
+
|
|
|
|
|
+ float lift_height;
|
|
|
|
|
+ float crouch;
|
|
|
|
|
+
|
|
|
|
|
+ if (cycle < 0.3F) {
|
|
|
|
|
+
|
|
|
|
|
+ float const t = cycle / 0.3F;
|
|
|
|
|
+ lift_height = HP::WAIST_Y * (1.0F - t * 0.5F);
|
|
|
|
|
+ crouch = t * 0.22F;
|
|
|
|
|
+ } else if (cycle < 0.6F) {
|
|
|
|
|
+
|
|
|
|
|
+ float const t = (cycle - 0.3F) / 0.3F;
|
|
|
|
|
+ lift_height =
|
|
|
|
|
+ HP::WAIST_Y * 0.5F + t * (HP::SHOULDER_Y - HP::WAIST_Y * 0.5F);
|
|
|
|
|
+ crouch = 0.22F * (1.0F - t);
|
|
|
|
|
+ } else if (cycle < 0.8F) {
|
|
|
|
|
+
|
|
|
|
|
+ lift_height = HP::SHOULDER_Y;
|
|
|
|
|
+ crouch = 0.0F;
|
|
|
|
|
+ } else {
|
|
|
|
|
+
|
|
|
|
|
+ float const t = (cycle - 0.8F) / 0.2F;
|
|
|
|
|
+ lift_height = HP::SHOULDER_Y * (1.0F - t * 0.35F);
|
|
|
|
|
+ crouch = 0.0F;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ QVector3D const left_hand(-0.14F + asym, lift_height, 0.18F);
|
|
|
|
|
+ QVector3D const right_hand(0.14F - asym, lift_height, 0.18F);
|
|
|
|
|
+
|
|
|
|
|
+ controller.placeHandAt(true, left_hand);
|
|
|
|
|
+ controller.placeHandAt(false, right_hand);
|
|
|
|
|
+
|
|
|
|
|
+ if (crouch > 0.0F) {
|
|
|
|
|
+ controller.kneel(crouch);
|
|
|
|
|
+ }
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
void draw_stone_hammer(const DrawContext &ctx, const HumanoidVariant &v,
|
|
void draw_stone_hammer(const DrawContext &ctx, const HumanoidVariant &v,
|
|
|
- const HumanoidPose &pose, ISubmitter &out) const {
|
|
|
|
|
|
|
+ const HumanoidPose &pose,
|
|
|
|
|
+ const HumanoidAnimationContext &anim_ctx,
|
|
|
|
|
+ ISubmitter &out) const {
|
|
|
QVector3D const wood = v.palette.wood;
|
|
QVector3D const wood = v.palette.wood;
|
|
|
|
|
|
|
|
QVector3D const stone_color(0.52F, 0.50F, 0.46F);
|
|
QVector3D const stone_color(0.52F, 0.50F, 0.46F);
|
|
@@ -208,11 +330,29 @@ public:
|
|
|
|
|
|
|
|
QVector3D const hand = pose.hand_l;
|
|
QVector3D const hand = pose.hand_l;
|
|
|
QVector3D const up(0.0F, 1.0F, 0.0F);
|
|
QVector3D const up(0.0F, 1.0F, 0.0F);
|
|
|
|
|
+ QVector3D const forward(0.0F, 0.0F, 1.0F);
|
|
|
QVector3D const right(1.0F, 0.0F, 0.0F);
|
|
QVector3D const right(1.0F, 0.0F, 0.0F);
|
|
|
|
|
|
|
|
|
|
+ const AnimationInputs &anim = anim_ctx.inputs;
|
|
|
|
|
+ QVector3D handle_axis;
|
|
|
|
|
+ QVector3D head_axis;
|
|
|
|
|
+
|
|
|
|
|
+ if (anim.is_constructing) {
|
|
|
|
|
+
|
|
|
|
|
+ handle_axis = forward;
|
|
|
|
|
+ head_axis = up;
|
|
|
|
|
+ } else {
|
|
|
|
|
+
|
|
|
|
|
+ handle_axis = up;
|
|
|
|
|
+ head_axis = right;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
float const h_len = 0.30F;
|
|
float const h_len = 0.30F;
|
|
|
- QVector3D const h_top = hand + up * 0.11F;
|
|
|
|
|
- QVector3D const h_bot = h_top - up * h_len;
|
|
|
|
|
|
|
+ QVector3D const handle_offset = anim.is_constructing
|
|
|
|
|
+ ? (forward * 0.11F + up * 0.02F)
|
|
|
|
|
+ : (up * 0.11F + forward * 0.02F);
|
|
|
|
|
+ QVector3D const h_top = hand + handle_offset;
|
|
|
|
|
+ QVector3D const h_bot = h_top - handle_axis * h_len;
|
|
|
|
|
|
|
|
out.mesh(get_unit_cylinder(),
|
|
out.mesh(get_unit_cylinder(),
|
|
|
cylinder_between(ctx.model, h_bot, h_top, 0.015F), wood, nullptr,
|
|
cylinder_between(ctx.model, h_bot, h_top, 0.015F), wood, nullptr,
|
|
@@ -220,31 +360,25 @@ public:
|
|
|
|
|
|
|
|
float const head_len = 0.09F;
|
|
float const head_len = 0.09F;
|
|
|
float const head_r = 0.028F;
|
|
float const head_r = 0.028F;
|
|
|
- QVector3D const head_center = h_top + up * 0.03F;
|
|
|
|
|
|
|
+ QVector3D const head_center = h_top + handle_axis * 0.03F;
|
|
|
|
|
|
|
|
- out.mesh(get_unit_cylinder(),
|
|
|
|
|
- cylinder_between(ctx.model,
|
|
|
|
|
- head_center - right * (head_len * 0.5F),
|
|
|
|
|
- head_center + right * (head_len * 0.5F), head_r),
|
|
|
|
|
- stone_color, nullptr, 1.0F);
|
|
|
|
|
|
|
+ out.mesh(
|
|
|
|
|
+ get_unit_cylinder(),
|
|
|
|
|
+ cylinder_between(ctx.model, head_center - head_axis * (head_len * 0.5F),
|
|
|
|
|
+ head_center + head_axis * (head_len * 0.5F), head_r),
|
|
|
|
|
+ stone_color, nullptr, 1.0F);
|
|
|
|
|
|
|
|
out.mesh(get_unit_sphere(),
|
|
out.mesh(get_unit_sphere(),
|
|
|
- sphere_at(ctx.model, head_center + right * (head_len * 0.5F),
|
|
|
|
|
|
|
+ sphere_at(ctx.model, head_center + head_axis * (head_len * 0.5F),
|
|
|
head_r * 1.1F),
|
|
head_r * 1.1F),
|
|
|
stone_dark, nullptr, 1.0F);
|
|
stone_dark, nullptr, 1.0F);
|
|
|
|
|
|
|
|
out.mesh(get_unit_sphere(),
|
|
out.mesh(get_unit_sphere(),
|
|
|
- sphere_at(ctx.model, head_center - right * (head_len * 0.5F),
|
|
|
|
|
|
|
+ sphere_at(ctx.model, head_center - head_axis * (head_len * 0.5F),
|
|
|
head_r * 0.85F),
|
|
head_r * 0.85F),
|
|
|
stone_color * 0.92F, nullptr, 1.0F);
|
|
stone_color * 0.92F, nullptr, 1.0F);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void draw_helmet(const DrawContext &ctx, const HumanoidVariant &v,
|
|
|
|
|
- const HumanoidPose &pose, ISubmitter &out) const override {
|
|
|
|
|
-
|
|
|
|
|
- draw_headwrap(ctx, v, pose, out);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
void draw_headwrap(const DrawContext &ctx, const HumanoidVariant &v,
|
|
void draw_headwrap(const DrawContext &ctx, const HumanoidVariant &v,
|
|
|
const HumanoidPose &pose, ISubmitter &out) const {
|
|
const HumanoidPose &pose, ISubmitter &out) const {
|
|
|
const BodyFrames &frames = pose.body_frames;
|
|
const BodyFrames &frames = pose.body_frames;
|
|
@@ -261,14 +395,6 @@ public:
|
|
|
wrap_color * 0.95F, nullptr, 1.0F);
|
|
wrap_color * 0.95F, nullptr, 1.0F);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- void draw_armor(const DrawContext &ctx, const HumanoidVariant &v,
|
|
|
|
|
- const HumanoidPose &pose,
|
|
|
|
|
- const HumanoidAnimationContext &anim,
|
|
|
|
|
- ISubmitter &out) const override {
|
|
|
|
|
- uint32_t const seed = reinterpret_cast<uintptr_t>(ctx.entity) & 0xFFFFFFFFU;
|
|
|
|
|
- draw_craftsman_robes(ctx, v, pose, seed, out);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
void draw_craftsman_robes(const DrawContext &ctx, const HumanoidVariant &v,
|
|
void draw_craftsman_robes(const DrawContext &ctx, const HumanoidVariant &v,
|
|
|
const HumanoidPose &pose, uint32_t seed,
|
|
const HumanoidPose &pose, uint32_t seed,
|
|
|
ISubmitter &out) const {
|
|
ISubmitter &out) const {
|
|
@@ -403,7 +529,6 @@ private:
|
|
|
return def;
|
|
return def;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-public:
|
|
|
|
|
auto resolve_shader_key(const DrawContext &ctx) const -> QString {
|
|
auto resolve_shader_key(const DrawContext &ctx) const -> QString {
|
|
|
const BuilderStyleConfig &s = resolve_style(ctx);
|
|
const BuilderStyleConfig &s = resolve_style(ctx);
|
|
|
if (!s.shader_id.empty()) {
|
|
if (!s.shader_id.empty()) {
|
|
@@ -412,7 +537,6 @@ public:
|
|
|
return QStringLiteral("builder");
|
|
return QStringLiteral("builder");
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-private:
|
|
|
|
|
void apply_palette_overrides(const BuilderStyleConfig &style,
|
|
void apply_palette_overrides(const BuilderStyleConfig &style,
|
|
|
const QVector3D &team_tint,
|
|
const QVector3D &team_tint,
|
|
|
HumanoidVariant &v) const {
|
|
HumanoidVariant &v) const {
|