mirror of
https://github.com/open-goal/jak-project
synced 2026-08-02 00:34:13 -04:00
[gfx] sprite 3d hack and fix graphics dumps (#1057)
* add sprite 3d * cleanup
This commit is contained in:
@@ -298,6 +298,10 @@ void DirectRenderer::update_gl_prim(SharedRenderState* render_state) {
|
||||
void DirectRenderer::update_gl_texture(SharedRenderState* render_state, int unit) {
|
||||
TextureRecord* tex = nullptr;
|
||||
auto& state = m_texture_state[unit];
|
||||
if (!state.used) {
|
||||
// nothing used this state, don't bother binding the texture.
|
||||
return;
|
||||
}
|
||||
if (state.using_mt4hh) {
|
||||
tex = render_state->texture_pool->lookup_mt4hh(state.texture_base_ptr);
|
||||
} else {
|
||||
@@ -659,8 +663,7 @@ void DirectRenderer::handle_tex1_1(u64 val,
|
||||
if (needs_state_flush()) {
|
||||
flush_pending(render_state, prof);
|
||||
m_texture_state[0] = *current_texture_state();
|
||||
m_texture_state[0].used = false;
|
||||
m_current_texture_state = 0;
|
||||
reset_texture_states();
|
||||
m_stats.flush_from_state_exhaust++;
|
||||
} else {
|
||||
push_texture_state();
|
||||
@@ -697,8 +700,7 @@ void DirectRenderer::handle_tex0_1(u64 val,
|
||||
if (needs_state_flush()) {
|
||||
flush_pending(render_state, prof);
|
||||
m_texture_state[0] = *current_texture_state();
|
||||
m_texture_state[0].used = false;
|
||||
m_current_texture_state = 0;
|
||||
reset_texture_states();
|
||||
m_stats.flush_from_state_exhaust++;
|
||||
} else {
|
||||
push_texture_state();
|
||||
@@ -833,8 +835,9 @@ void DirectRenderer::handle_clamp1(u64 val,
|
||||
if (needs_state_flush()) {
|
||||
flush_pending(render_state, prof);
|
||||
m_texture_state[0] = *current_texture_state();
|
||||
m_texture_state[0].used = false;
|
||||
m_current_texture_state = 0;
|
||||
reset_texture_states();
|
||||
// m_texture_state[0].used = false;
|
||||
// m_current_texture_state = 0;
|
||||
m_stats.flush_from_state_exhaust++;
|
||||
} else {
|
||||
push_texture_state();
|
||||
@@ -1046,6 +1049,7 @@ void DirectRenderer::reset_state() {
|
||||
m_texture_state[i] = TextureState();
|
||||
}
|
||||
m_global_texture_state = TextureGlobalState();
|
||||
m_current_texture_state = 0;
|
||||
|
||||
m_prim_building = PrimBuildState();
|
||||
|
||||
|
||||
@@ -167,6 +167,14 @@ class DirectRenderer : public BucketRenderer {
|
||||
bool used = false;
|
||||
} m_texture_state[TEXTURE_STATE_COUNT];
|
||||
|
||||
void reset_texture_states() {
|
||||
m_current_texture_state = 0;
|
||||
m_texture_state[0].used = false;
|
||||
for (auto& ts : m_texture_state) {
|
||||
ts.used = false;
|
||||
}
|
||||
}
|
||||
|
||||
struct TextureGlobalState {
|
||||
bool needs_gl_update = true;
|
||||
} m_global_texture_state;
|
||||
|
||||
@@ -137,6 +137,9 @@ SkyBlendStats SkyBlendCPU::do_sky_blends(DmaFollower& dma,
|
||||
}
|
||||
|
||||
// put in pool.
|
||||
if (render_state->dump_playback) {
|
||||
return stats;
|
||||
}
|
||||
for (int i = 0; i < 2; i++) {
|
||||
// todo - these are hardcoded and rely on the vram layout.
|
||||
u32 tbp = i == 0 ? 8064 : 8096;
|
||||
|
||||
@@ -163,7 +163,15 @@ void SpriteRenderer::render_2d_group0(DmaFollower& dma,
|
||||
// HACK: this renderers 3D sprites with the 2D renderer. amazingly, it almost works.
|
||||
// assert(run.vifcode1().immediate == SpriteProgMem::Sprites2dGrp0);
|
||||
if (m_enabled) {
|
||||
do_2d_group0_block_cpu(sprite_count, render_state, prof);
|
||||
if (run.vifcode1().immediate == SpriteProgMem::Sprites2dGrp0) {
|
||||
if (m_2d_enable) {
|
||||
do_2d_group0_block_cpu(sprite_count, render_state, prof);
|
||||
}
|
||||
} else {
|
||||
if (m_3d_enable) {
|
||||
do_3d_block_cpu(sprite_count, render_state, prof);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -218,7 +226,7 @@ void SpriteRenderer::render_2d_group1(DmaFollower& dma,
|
||||
assert(run.vifcode0().kind == VifCode::Kind::NOP);
|
||||
assert(run.vifcode1().kind == VifCode::Kind::MSCAL);
|
||||
assert(run.vifcode1().immediate == SpriteProgMem::Sprites2dHud);
|
||||
if (m_enabled) {
|
||||
if (m_enabled && m_2d_enable) {
|
||||
do_2d_group1_block_cpu(sprite_count, render_state, prof);
|
||||
}
|
||||
}
|
||||
@@ -293,6 +301,11 @@ void SpriteRenderer::draw_debug_window() {
|
||||
ImGui::Text("2D Group 1 (HUD) blocks: %d sprites: %d", m_debug_stats.blocks_2d_grp1,
|
||||
m_debug_stats.count_2d_grp1);
|
||||
ImGui::Checkbox("Extra Debug", &m_extra_debug);
|
||||
ImGui::Checkbox("2d", &m_2d_enable);
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("3d", &m_3d_enable);
|
||||
ImGui::SameLine();
|
||||
ImGui::Checkbox("3d-debug", &m_3d_debug);
|
||||
if (ImGui::TreeNode("direct")) {
|
||||
m_sprite_renderer.draw_debug_window();
|
||||
ImGui::TreePop();
|
||||
@@ -718,6 +731,251 @@ void SpriteRenderer::do_2d_group1_block_cpu(u32 count,
|
||||
}
|
||||
}
|
||||
|
||||
std::array<math::Vector3f, 3> sprite_quat_to_rot(float qi, float qj, float qk) {
|
||||
std::array<math::Vector3f, 3> result;
|
||||
float qr = std::sqrt(std::abs(1.f - (qi * qi + qj * qj + qk * qk)));
|
||||
// fmt::print("q: {} {} {} {}\n", qi, qj, qk, qr);
|
||||
result[0][0] = 1.f - 2.f * (qj * qj + qk * qk);
|
||||
result[1][0] = 2.f * (qi * qj - qk * qr);
|
||||
result[2][0] = 2.f * (qi * qk + qj * qr);
|
||||
result[0][1] = 2.f * (qi * qj + qk * qr);
|
||||
result[1][1] = 1.f - 2.f * (qi * qi + qk * qk);
|
||||
result[2][1] = 2.f * (qj * qk - qi * qr);
|
||||
result[0][2] = 2.f * (qi * qk - qj * qr);
|
||||
result[1][2] = 2.f * (qj * qk + qi * qr);
|
||||
result[2][2] = 1.f - 2.f * (qi * qi + qj * qj);
|
||||
return result;
|
||||
}
|
||||
|
||||
Vector4f sprite_transform2(const Vector4f& root,
|
||||
const Vector4f& off,
|
||||
const Matrix4f& cam,
|
||||
const std::array<math::Vector3f, 3>& sprite_rot,
|
||||
float sx,
|
||||
float sy,
|
||||
const Vector4f& hvdf_off,
|
||||
float pfog0,
|
||||
float fog_min,
|
||||
float fog_max) {
|
||||
Vector4f pos = root;
|
||||
// fmt::print("root : {}\n", root.to_string_aligned());
|
||||
// fmt::print("off : {} s {} {}\n", off.to_string_aligned(), sx, sy);
|
||||
|
||||
math::Vector3f offset =
|
||||
sprite_rot[0] * off.x() * sx + sprite_rot[1] * off.y() + sprite_rot[2] * off.z() * sy;
|
||||
// fmt::print("off (r): {}\n", offset.to_string_aligned());
|
||||
|
||||
pos.x() += offset.x();
|
||||
pos.y() += offset.y();
|
||||
pos.z() += offset.z();
|
||||
Vector4f transformed_pos = matrix_transform(cam, pos);
|
||||
float Q = pfog0 / transformed_pos.w();
|
||||
transformed_pos.x() *= Q;
|
||||
transformed_pos.y() *= Q;
|
||||
transformed_pos.z() *= Q;
|
||||
Vector4f offset_pos = transformed_pos + hvdf_off;
|
||||
offset_pos.w() = std::max(offset_pos.w(), fog_max);
|
||||
offset_pos.w() = std::min(offset_pos.w(), fog_min);
|
||||
|
||||
return offset_pos;
|
||||
}
|
||||
|
||||
void SpriteRenderer::do_3d_block_cpu(u32 count,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof) {
|
||||
Matrix4f camera_matrix = m_3d_matrix_data.camera; // vf25, vf26, vf27, vf28
|
||||
for (u32 sprite_idx = 0; sprite_idx < count; sprite_idx++) {
|
||||
SpriteHud2DPacket packet;
|
||||
memset(&packet, 0, sizeof(packet));
|
||||
// ilw.y vi08, 1(vi02) | nop vi08 = matrix
|
||||
u32 offset_selector = m_vec_data_2d[sprite_idx].matrix();
|
||||
// assert(offset_selector == 0 || offset_selector == 1);
|
||||
// moved this out of the loop.
|
||||
// lq.xyzw vf25, 900(vi00) | nop vf25 = cam_mat
|
||||
// lq.xyzw vf26, 901(vi00) | nop
|
||||
// lq.xyzw vf27, 902(vi00) | nop
|
||||
// lq.xyzw vf28, 903(vi00) | nop
|
||||
// lq.xyzw vf30, 904(vi00) | nop vf30 = hvdf_offset
|
||||
// vf30
|
||||
Vector4f hvdf_offset = m_3d_matrix_data.hvdf_offset;
|
||||
|
||||
// lqi.xyzw vf01, vi02 | nop
|
||||
Vector4f pos_vf01 = m_vec_data_2d[sprite_idx].xyz_sx;
|
||||
// lqi.xyzw vf05, vi02 | nop
|
||||
Vector4f flags_vf05 = m_vec_data_2d[sprite_idx].flag_rot_sy;
|
||||
// lqi.xyzw vf11, vi02 | nop
|
||||
Vector4f color_vf11 = m_vec_data_2d[sprite_idx].rgba;
|
||||
|
||||
// multiplications from the right column
|
||||
Vector4f transformed_pos_vf02 = matrix_transform(camera_matrix, pos_vf01);
|
||||
|
||||
Vector4f scales_vf01 = pos_vf01; // now used for something else.
|
||||
// lq.xyzw vf12, 1020(vi00) | mulaw.xyzw ACC, vf28, vf00
|
||||
// vf12 is fog consts
|
||||
Vector4f fog_consts_vf12(m_frame_data.fog_min, m_frame_data.fog_max, m_frame_data.max_scale,
|
||||
m_frame_data.bonus);
|
||||
// ilw.y vi08, 1(vi02) | maddax.xyzw ACC, vf25, vf01
|
||||
// load offset selector for the next round.
|
||||
// nop | madday.xyzw ACC, vf26, vf01
|
||||
// nop | maddz.xyzw vf02, vf27, vf01
|
||||
|
||||
// move.w vf05, vf00 | addw.z vf01, vf00, vf05
|
||||
// scales_vf01.z = sy
|
||||
scales_vf01.z() = flags_vf05.w(); // start building the scale vector
|
||||
flags_vf05.w() = 1.f; // what are we building in flags right now??
|
||||
|
||||
// nop | nop
|
||||
// div Q, vf31.x, vf02.w | muly.z vf05, vf05, vf31
|
||||
float Q = m_frame_data.pfog0 / transformed_pos_vf02.w();
|
||||
flags_vf05.z() *= m_frame_data.deg_to_rad;
|
||||
// nop | mul.xyzw vf03, vf02, vf29
|
||||
Vector4f scaled_pos_vf03 = transformed_pos_vf02.elementwise_multiply(m_frame_data.hmge_scale);
|
||||
// nop | nop
|
||||
// nop | nop
|
||||
// nop | mulz.z vf04, vf05, vf05 (ts)
|
||||
// fmt::print("rot is {} degrees\n", flags_vf05.z() * 360.0 / (2.0 * M_PI));
|
||||
|
||||
// the load is for rotation stuff,
|
||||
// lq.xyzw vf14, 1001(vi00) | clipw.xyz vf03, vf03 (used for fcand)
|
||||
// iaddi vi06, vi00, 0x1 | adda.xyzw ACC, vf11, vf11 (used for fmand)
|
||||
|
||||
// upcoming fcand with 0x3f, that checks all of them.
|
||||
bool fcand_result = clip_xyz_plus_minus(scaled_pos_vf03);
|
||||
bool fmand_result = color_vf11.w() == 0; // (really w+w, but I don't think it matters?)
|
||||
|
||||
// L8:
|
||||
// xgkick double buffer setup
|
||||
// ior vi05, vi15, vi00 | mul.zw vf01, vf01, Q
|
||||
scales_vf01.z() *= Q; // sy
|
||||
scales_vf01.w() *= Q; // sx
|
||||
|
||||
// lq.xyzw vf06, 998(vi00) | mulz.xyzw vf15, vf05, vf04 (ts)
|
||||
auto adgif_vf06 = m_frame_data.adgif_giftag;
|
||||
|
||||
// lq.xyzw vf14, 1002(vi00) ts| mula.xyzw ACC, vf05, vf14 (ts)
|
||||
|
||||
// fmand vi01, vi06 | mul.xyz vf02, vf02, Q
|
||||
transformed_pos_vf02.x() *= Q;
|
||||
transformed_pos_vf02.y() *= Q;
|
||||
transformed_pos_vf02.z() *= Q;
|
||||
|
||||
// ibne vi00, vi01, L10 | addz.x vf01, vf00, vf01
|
||||
scales_vf01.x() = scales_vf01.z(); // = sy
|
||||
if (fmand_result) {
|
||||
continue; // reject!
|
||||
}
|
||||
|
||||
// lqi.xyzw vf07, vi03 | mulz.xyzw vf16, vf15, vf04 (ts)
|
||||
// vf07 is first use adgif
|
||||
|
||||
// lq.xyzw vf14, 1003(vi00) | madda.xyzw ACC, vf15, vf14 (ts both)
|
||||
|
||||
// lqi.xyzw vf08, vi03 | add.xyzw vf10, vf02, vf30
|
||||
// vf08 is second user adgif
|
||||
Vector4f offset_pos_vf10 = transformed_pos_vf02 + hvdf_offset;
|
||||
// if (m_extra_debug) {
|
||||
// ImGui::Text("sel %d", offset_selector);
|
||||
// //ImGui::Text("hvdf off z: %f tf/w z: %f", hvdf_offset.z(), transformed_pos_vf02.z());
|
||||
// imgui_vec(hvdf_offset, "hvdf");
|
||||
// imgui_vec(transformed_pos_vf02, "tf'd");
|
||||
// }
|
||||
|
||||
// lqi.xyzw vf09, vi03 | mulw.x vf01, vf01, vf01
|
||||
// vf09 is third user adgif
|
||||
scales_vf01.x() *= scales_vf01.w(); // x = sx * sy
|
||||
|
||||
// sqi.xyzw vf06, vi05 | mulz.xyzw vf15, vf16, vf04 (ts)
|
||||
// FIRST ADGIF IS adgif_vf06
|
||||
packet.adgif_giftag = adgif_vf06;
|
||||
|
||||
// just do all 5 now.
|
||||
packet.user_adgif = m_adgif[sprite_idx];
|
||||
|
||||
offset_pos_vf10.w() = std::max(offset_pos_vf10.w(), m_frame_data.fog_max);
|
||||
|
||||
scales_vf01.z() = std::max(scales_vf01.z(), m_frame_data.min_scale);
|
||||
scales_vf01.w() = std::max(scales_vf01.w(), m_frame_data.min_scale);
|
||||
|
||||
scales_vf01.x() *= m_frame_data.inv_area; // x = sx * sy * inv_area (area ratio)
|
||||
|
||||
offset_pos_vf10.w() = std::min(offset_pos_vf10.w(), m_frame_data.fog_min);
|
||||
|
||||
scales_vf01.z() = std::min(scales_vf01.z(), fog_consts_vf12.z());
|
||||
scales_vf01.w() = std::min(scales_vf01.w(), fog_consts_vf12.z());
|
||||
bool use_first_giftag = offset_selector == 0;
|
||||
|
||||
auto flag_vi07 = m_vec_data_2d[sprite_idx].flag();
|
||||
|
||||
scales_vf01.x() = std::min(scales_vf01.x(), 1.f);
|
||||
|
||||
transformed_pos_vf02.w() = offset_pos_vf10.w() - fog_consts_vf12.y();
|
||||
|
||||
color_vf11.w() *= scales_vf01.x(); // is this right? doesn't this stall??
|
||||
|
||||
// ibne vi00, vi09, L6 | nop
|
||||
if (transformed_pos_vf02.w() != 0) {
|
||||
use_first_giftag = false;
|
||||
}
|
||||
|
||||
flag_vi07 = 0; // todo hack
|
||||
Vector4f* xy_array = m_frame_data.xyz_array + flag_vi07;
|
||||
math::Vector<s32, 4> color_integer_vf11 = color_vf11.cast<s32>();
|
||||
|
||||
packet.color = color_integer_vf11;
|
||||
|
||||
if (fcand_result) {
|
||||
continue; // reject (could move earlier)
|
||||
}
|
||||
|
||||
Vector4f transformed[4];
|
||||
|
||||
flags_vf05 = m_vec_data_2d[sprite_idx].flag_rot_sy;
|
||||
// do rot
|
||||
auto rot = sprite_quat_to_rot(flags_vf05.x(), flags_vf05.y(), flags_vf05.z());
|
||||
// fmt::print("root: {}\n", offset_pos_vf10.to_string_aligned());
|
||||
|
||||
// for (int i = 0; i < 3; i++) {
|
||||
// fmt::print("M{}: {}\n", i, rot[i].to_string_aligned());
|
||||
// }
|
||||
for (int i = 0; i < 4; i++) {
|
||||
transformed[i] =
|
||||
sprite_transform2(m_vec_data_2d[sprite_idx].xyz_sx, xy_array[i], camera_matrix, rot,
|
||||
m_vec_data_2d[sprite_idx].sx(), m_vec_data_2d[sprite_idx].sy(),
|
||||
m_3d_matrix_data.hvdf_offset, m_frame_data.pfog0, m_frame_data.fog_min,
|
||||
m_frame_data.fog_max);
|
||||
}
|
||||
Vector4f xy0_vf19 = transformed[0];
|
||||
Vector4f xy1_vf20 = transformed[1];
|
||||
Vector4f xy2_vf21 = transformed[2];
|
||||
Vector4f xy3_vf22 = transformed[3];
|
||||
|
||||
packet.sprite_giftag =
|
||||
use_first_giftag ? m_frame_data.sprite_2d_giftag : m_frame_data.sprite_2d_giftag2;
|
||||
|
||||
Vector4f st0_vf06 = m_frame_data.st_array[0];
|
||||
Vector4f st1_vf07 = m_frame_data.st_array[1];
|
||||
Vector4f st2_vf08 = m_frame_data.st_array[2];
|
||||
Vector4f st3_vf09 = m_frame_data.st_array[3];
|
||||
|
||||
packet.st0 = st0_vf06;
|
||||
packet.st1 = st1_vf07;
|
||||
packet.st2 = st2_vf08;
|
||||
packet.st3 = st3_vf09;
|
||||
|
||||
auto xy0_vf19_int = (xy0_vf19 * 16.f).cast<s32>();
|
||||
auto xy1_vf20_int = (xy1_vf20 * 16.f).cast<s32>();
|
||||
auto xy2_vf21_int = (xy2_vf21 * 16.f).cast<s32>();
|
||||
auto xy3_vf22_int = (xy3_vf22 * 16.f).cast<s32>();
|
||||
|
||||
packet.xy0 = xy0_vf19_int;
|
||||
packet.xy1 = xy1_vf20_int;
|
||||
packet.xy2 = xy2_vf21_int;
|
||||
packet.xy3 = xy3_vf22_int;
|
||||
|
||||
m_sprite_renderer.render_gif((const u8*)&packet, sizeof(packet), render_state, prof);
|
||||
}
|
||||
}
|
||||
|
||||
void SpriteRenderer::do_2d_group0_block_cpu(u32 count,
|
||||
SharedRenderState* render_state,
|
||||
ScopedProfilerNode& prof) {
|
||||
|
||||
@@ -165,6 +165,7 @@ class SpriteRenderer : public BucketRenderer {
|
||||
ScopedProfilerNode& prof);
|
||||
void do_2d_group1_block_cpu(u32 count, SharedRenderState* render_state, ScopedProfilerNode& prof);
|
||||
void do_2d_group0_block_cpu(u32 count, SharedRenderState* render_state, ScopedProfilerNode& prof);
|
||||
void do_3d_block_cpu(u32 count, SharedRenderState* render_state, ScopedProfilerNode& prof);
|
||||
|
||||
u8 m_sprite_distorter_setup[7 * 16]; // direct data
|
||||
u8 m_sprite_direct_setup[3 * 16];
|
||||
@@ -183,6 +184,10 @@ class SpriteRenderer : public BucketRenderer {
|
||||
} m_debug_stats;
|
||||
|
||||
bool m_extra_debug = false;
|
||||
bool m_3d_debug = false;
|
||||
|
||||
bool m_2d_enable = true;
|
||||
bool m_3d_enable = true;
|
||||
|
||||
DirectRenderer m_sprite_renderer;
|
||||
DirectRenderer m_direct_renderer;
|
||||
|
||||
@@ -397,7 +397,8 @@ static void gl_render_display(GfxDisplay* display) {
|
||||
int lbox_h = (fbuf_h - height) / 2;
|
||||
|
||||
if (g_gfx_data->debug_gui.want_dump_replay()) {
|
||||
render_dump_frame(width, height, lbox_w, lbox_h);
|
||||
// hack: no letterbox for dump frames, for now.
|
||||
render_dump_frame(fbuf_w, fbuf_h, 0, 0);
|
||||
} else if (g_gfx_data->debug_gui.should_advance_frame()) {
|
||||
render_game_frame(width, height, lbox_w, lbox_h);
|
||||
}
|
||||
|
||||
@@ -393,13 +393,17 @@ void TexturePool::upload_to_gpu(TextureRecord* tex) {
|
||||
GLuint tex_id;
|
||||
glGenTextures(1, &tex_id);
|
||||
tex->gpu_texture = tex_id;
|
||||
GLint old_tex;
|
||||
glGetIntegerv(GL_ACTIVE_TEXTURE, &old_tex);
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, tex_id);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex->w, tex->h, 0, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV,
|
||||
tex->data.data());
|
||||
glBindTexture(GL_TEXTURE_2D, 0);
|
||||
|
||||
// we have to set these, imgui won't do it automatically
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, tex->gpu_texture);
|
||||
glGenerateMipmap(GL_TEXTURE_2D);
|
||||
|
||||
@@ -412,6 +416,7 @@ void TexturePool::upload_to_gpu(TextureRecord* tex) {
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||
|
||||
glActiveTexture(old_tex);
|
||||
tex->on_gpu = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -810,6 +810,18 @@
|
||||
)
|
||||
)
|
||||
|
||||
(defmacro quaternion-vompula-hack (vf-out vf-in)
|
||||
`(let ((in-vec (new 'stack-no-clear 'vector))
|
||||
(out-vec (new 'stack-no-clear 'vector)))
|
||||
(.svf (&-> in-vec quad) ,vf-in)
|
||||
(set! (-> out-vec x) (* (-> in-vec y) (-> in-vec z)))
|
||||
(set! (-> out-vec y) (* (-> in-vec z) (-> in-vec x)))
|
||||
(set! (-> out-vec z) (* (-> in-vec x) (-> in-vec y)))
|
||||
;;(set! (-> out-vec w) (-> in-vec w))
|
||||
(.lvf ,vf-out (&-> out-vec quad))
|
||||
)
|
||||
)
|
||||
|
||||
(defun quaternion-zxy! ((arg0 quaternion) (arg1 vector))
|
||||
(rlet ((acc :class vf)
|
||||
(vf0 :class vf)
|
||||
@@ -836,8 +848,10 @@
|
||||
(.sub.vf vf4 vf0 vf4 :mask #b110)
|
||||
(.add.vf vf3 vf0 vf1 :mask #b111)
|
||||
(.mul.x.vf vf3 vf0 vf2 :mask #b1000)
|
||||
(.outer.product.vf vf6 vf0 vf0)
|
||||
(.outer.product.vf vf5 vf0 vf0)
|
||||
; (.outer.product.vf vf6 vf0 vf0)
|
||||
(quaternion-vompula-hack vf6 vf1)
|
||||
(quaternion-vompula-hack vf5 vf2)
|
||||
; (.outer.product.vf vf5 vf0 vf0)
|
||||
(.mul.x.vf vf6 vf0 vf6 :mask #b1000)
|
||||
(.mul.x.vf vf5 vf0 vf5 :mask #b1000)
|
||||
(.mul.vf acc vf6 vf4)
|
||||
|
||||
Reference in New Issue
Block a user