splitscreen hack
parent
72ee35ada2
commit
2e6bbcbce8
|
@ -40,7 +40,7 @@ struct SharedRenderState {
|
|||
u32 offset_of_s7;
|
||||
|
||||
bool use_sky_cpu = true;
|
||||
bool use_occlusion_culling = true;
|
||||
bool use_occlusion_culling = false; // bad for multi
|
||||
math::Vector<u8, 4> fog_color = math::Vector<u8, 4>{0, 0, 0, 0};
|
||||
float fog_intensity = 1.f;
|
||||
bool no_multidraw = false;
|
||||
|
@ -87,6 +87,23 @@ struct SharedRenderState {
|
|||
u64 frame_idx = 0;
|
||||
|
||||
bool stencil_dirty = false;
|
||||
|
||||
// camera matrices from GOAL:
|
||||
struct MultiCameraGoalMatrices {
|
||||
// the inv-rot matrix from GOAL. (pose of the primary camera in the world)
|
||||
math::Matrix4f w_T_cpri;
|
||||
// the inv-rot matrix of extra cameras from GOAL. (pose of extra camera in the world)
|
||||
math::Matrix4f w_T_cextra[3];
|
||||
} multi_camera_goal;
|
||||
|
||||
// per-camera info for multi-camera rendering.
|
||||
struct Cam {
|
||||
math::Matrix4f w_T_wprime; // for non merc
|
||||
math::Matrix4f pri_cam_T_cam;
|
||||
};
|
||||
|
||||
Cam cameras[4];
|
||||
int camera_idx = 0;
|
||||
};
|
||||
|
||||
/*!
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "common/goal_constants.h"
|
||||
#include "common/log/log.h"
|
||||
#include "common/math/geometry.h"
|
||||
#include "common/util/FileUtil.h"
|
||||
|
||||
#include "game/graphics/opengl_renderer/BlitDisplays.h"
|
||||
|
@ -66,12 +67,61 @@ void GLAPIENTRY opengl_error_callback(GLenum source,
|
|||
}
|
||||
}
|
||||
|
||||
class MultiCameraMatrixGrabber : public BucketRenderer {
|
||||
public:
|
||||
MultiCameraMatrixGrabber(const std::string& name, int my_id) : BucketRenderer(name, my_id) {}
|
||||
void draw_debug_window() override {}
|
||||
void render(DmaFollower& dma, SharedRenderState* render_state, ScopedProfilerNode&) override {
|
||||
while (dma.current_tag_offset() != render_state->next_bucket) {
|
||||
auto xfer = dma.read_and_advance();
|
||||
if (xfer.size_bytes == sizeof(SharedRenderState::MultiCameraGoalMatrices) &&
|
||||
render_state->camera_idx == 0) {
|
||||
// grab camera data from GOAL:
|
||||
memcpy(&render_state->multi_camera_goal, xfer.data,
|
||||
sizeof(SharedRenderState::MultiCameraGoalMatrices));
|
||||
|
||||
math::Matrix4f cpri_T_w = inverse(render_state->multi_camera_goal.w_T_cpri);
|
||||
// set up some helpful matrices:
|
||||
for (int i = 0; i < 4; i++) {
|
||||
auto& cam = render_state->cameras[i];
|
||||
|
||||
// what GOAL calls "inverse camera rot", but is really w_T_c
|
||||
const auto& w_T_c = i == 0 ? render_state->multi_camera_goal.w_T_cpri
|
||||
: render_state->multi_camera_goal.w_T_cextra[i - 1];
|
||||
cam.w_T_wprime = render_state->multi_camera_goal.w_T_cpri * inverse(w_T_c);
|
||||
cam.pri_cam_T_cam = cpri_T_w * w_T_c;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
OpenGLRenderer::OpenGLRenderer(std::shared_ptr<TexturePool> texture_pool,
|
||||
std::shared_ptr<Loader> loader,
|
||||
GameVersion version)
|
||||
: m_render_state(texture_pool, loader, version),
|
||||
m_collide_renderer(version),
|
||||
m_version(version) {
|
||||
m_version(version),
|
||||
m_skip_multi_buckets((int)jak2::BucketId::MAX_BUCKETS) {
|
||||
for (auto bucket : {
|
||||
jak1::BucketId::OCEAN_MID_AND_FAR, // too lazy to fix
|
||||
jak1::BucketId::OCEAN_NEAR, // too lazy to fix
|
||||
jak1::BucketId::SKY_DRAW, // needs goal fix
|
||||
jak1::BucketId::TFRAG_TEX_LEVEL0, // texture
|
||||
jak1::BucketId::TFRAG_TEX_LEVEL1, // texture
|
||||
jak1::BucketId::SHRUB_TEX_LEVEL0, // texture
|
||||
jak1::BucketId::SHRUB_TEX_LEVEL1, // texture
|
||||
jak1::BucketId::ALPHA_TEX_LEVEL0, // texture
|
||||
jak1::BucketId::ALPHA_TEX_LEVEL1, // texture
|
||||
jak1::BucketId::PRIS_TEX_LEVEL0, // texture
|
||||
jak1::BucketId::PRIS_TEX_LEVEL1, // texture
|
||||
jak1::BucketId::WATER_TEX_LEVEL0, // texture
|
||||
jak1::BucketId::WATER_TEX_LEVEL1, // texture
|
||||
jak1::BucketId::PRE_SPRITE_TEX, // texture
|
||||
}) {
|
||||
m_skip_multi_buckets[(int)bucket] = true;
|
||||
}
|
||||
|
||||
// requires OpenGL 4.3
|
||||
#ifndef __APPLE__
|
||||
// setup OpenGL errors
|
||||
|
@ -341,6 +391,8 @@ void OpenGLRenderer::init_bucket_renderers_jak1() {
|
|||
// 0 : ??
|
||||
// 1 : ??
|
||||
// 2 : ??
|
||||
init_bucket_renderer<MultiCameraMatrixGrabber>("multicam", BucketCategory::OTHER,
|
||||
BucketId::BUCKET2);
|
||||
// 3 : SKY_DRAW
|
||||
init_bucket_renderer<SkyRenderer>("sky", BucketCategory::OTHER, BucketId::SKY_DRAW);
|
||||
// 4 : OCEAN_MID_AND_FAR
|
||||
|
@ -983,13 +1035,28 @@ void OpenGLRenderer::dispatch_buckets_jak1(DmaFollower dma,
|
|||
ASSERT(dma.current_tag_offset() == m_render_state.next_bucket);
|
||||
m_render_state.next_bucket += 16;
|
||||
|
||||
GLint old_viewport[4];
|
||||
glGetIntegerv(GL_VIEWPORT, old_viewport);
|
||||
|
||||
// loop over the buckets!
|
||||
for (size_t bucket_id = 0; bucket_id < m_bucket_renderers.size(); bucket_id++) {
|
||||
auto& renderer = m_bucket_renderers[bucket_id];
|
||||
auto bucket_prof = prof.make_scoped_child(renderer->name_and_id());
|
||||
g_current_renderer = renderer->name_and_id();
|
||||
// lg::info("Render: {} start", g_current_renderer);
|
||||
|
||||
// render primary camera:
|
||||
m_render_state.camera_idx = 0;
|
||||
auto dma_copy = dma;
|
||||
glViewport(old_viewport[0], old_viewport[1], old_viewport[2] / 2, old_viewport[3] / 2);
|
||||
renderer->render(dma, &m_render_state, bucket_prof);
|
||||
if (!m_skip_multi_buckets[bucket_id]) {
|
||||
m_render_state.camera_idx = 1;
|
||||
glViewport(old_viewport[0] + old_viewport[2] / 2, old_viewport[1] + old_viewport[3] / 2,
|
||||
old_viewport[2] / 2, old_viewport[3] / 2);
|
||||
renderer->render(dma_copy, &m_render_state, bucket_prof);
|
||||
}
|
||||
|
||||
if (sync_after_buckets) {
|
||||
auto pp = scoped_prof("finish");
|
||||
glFinish();
|
||||
|
@ -1009,6 +1076,8 @@ void OpenGLRenderer::dispatch_buckets_jak1(DmaFollower dma,
|
|||
}
|
||||
}
|
||||
|
||||
glViewport(old_viewport[0], old_viewport[1], old_viewport[2], old_viewport[3]);
|
||||
|
||||
// TODO ending data.
|
||||
}
|
||||
|
||||
|
|
|
@ -103,6 +103,7 @@ class OpenGLRenderer {
|
|||
}
|
||||
|
||||
SharedRenderState m_render_state;
|
||||
std::vector<bool> m_skip_multi_buckets;
|
||||
Profiler m_profiler;
|
||||
SmallProfiler m_small_profiler;
|
||||
SubtitleEditor* m_subtitle_editor = nullptr;
|
||||
|
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
#include <cfloat>
|
||||
|
||||
#include "common/math/geometry.h"
|
||||
|
||||
#include "third-party/imgui/imgui.h"
|
||||
|
||||
ShadowRenderer::ShadowRenderer(const std::string& name, int my_id) : BucketRenderer(name, my_id) {
|
||||
|
@ -237,7 +239,15 @@ void ShadowRenderer::render(DmaFollower& dma,
|
|||
ASSERT(v1.kind == VifCode::Kind::UNPACK_V4_32);
|
||||
ASSERT(v1.immediate == Vu1Data::MATRIX);
|
||||
ASSERT(v1.num == 4);
|
||||
memcpy(m_vu_data + v1.immediate, constants.data, v1.num * 16);
|
||||
|
||||
// such disgusting hacks
|
||||
math::Matrix4f p;
|
||||
memcpy(p.data(), constants.data, v1.num * 16);
|
||||
auto& this_cam = render_state->cameras[render_state->camera_idx];
|
||||
auto new_cam = (p * inverse(this_cam.pri_cam_T_cam));
|
||||
memcpy(m_vu_data + v1.immediate, new_cam.data(), 16 * 4);
|
||||
|
||||
// memcpy(m_vu_data + v1.immediate, constants.data, v1.num * 16);
|
||||
}
|
||||
|
||||
{
|
||||
|
|
|
@ -447,8 +447,11 @@ void TFragment::render_tree(int geom,
|
|||
glEnable(GL_PRIMITIVE_RESTART);
|
||||
glPrimitiveRestartIndex(UINT32_MAX);
|
||||
|
||||
cull_check_all_slow(settings.camera.planes, tree.vis->vis_nodes, settings.occlusion_culling,
|
||||
m_cache.vis_temp.data());
|
||||
// cull_check_all_slow(settings.camera.planes, tree.vis->vis_nodes, settings.occlusion_culling,
|
||||
// m_cache.vis_temp.data());
|
||||
for (size_t i = 0; i < tree.vis->vis_nodes.size(); i++) {
|
||||
m_cache.vis_temp.data()[i] = 1;
|
||||
}
|
||||
|
||||
u32 total_tris;
|
||||
if (render_state->no_multidraw) {
|
||||
|
|
|
@ -448,9 +448,12 @@ void Tie3::setup_tree(int idx,
|
|||
}
|
||||
|
||||
if (!m_debug_all_visible) {
|
||||
// need culling data
|
||||
cull_check_all_slow(settings.camera.planes, tree.vis->vis_nodes, settings.occlusion_culling,
|
||||
tree.vis_temp.data());
|
||||
for (size_t i = 0; i < tree.vis->vis_nodes.size(); i++) {
|
||||
tree.vis_temp.data()[i] = 1;
|
||||
}
|
||||
// cull_check_all_slow(settings.camera.planes, tree.vis->vis_nodes,
|
||||
// settings.occlusion_culling,
|
||||
// tree.vis_temp.data());
|
||||
}
|
||||
|
||||
u32 num_tris = 0;
|
||||
|
@ -504,8 +507,24 @@ void set_uniform(GLuint uniform, const math::Vector4f& val) {
|
|||
}
|
||||
} // namespace
|
||||
|
||||
void init_etie_cam_uniforms(const EtieUniforms& uniforms, const GoalBackgroundCameraData& data) {
|
||||
glUniformMatrix4fv(uniforms.cam_no_persp, 1, GL_FALSE, data.rot[0].data());
|
||||
namespace {
|
||||
math::Matrix4f matrix_from_col_vectors(const math::Vector4f* vectors) {
|
||||
math::Matrix4f ret;
|
||||
for (int c = 0; c < 4; c++) {
|
||||
for (int r = 0; r < 4; r++) {
|
||||
ret(r, c) = vectors[c][r];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void init_etie_cam_uniforms(const EtieUniforms& uniforms,
|
||||
const GoalBackgroundCameraData& data,
|
||||
SharedRenderState* render_state) {
|
||||
auto& this_cam = render_state->cameras[render_state->camera_idx];
|
||||
math::Matrix4f s_T_w = matrix_from_col_vectors(data.rot);
|
||||
glUniformMatrix4fv(uniforms.cam_no_persp, 1, GL_FALSE, (s_T_w * this_cam.w_T_wprime).data());
|
||||
|
||||
math::Vector4f perspective[2];
|
||||
float inv_fog = 1.f / data.fog[0];
|
||||
|
@ -550,7 +569,7 @@ void Tie3::draw_matching_draws_for_tree(int idx,
|
|||
|
||||
if (use_envmap) {
|
||||
// if we use envmap, use the envmap-style math for the base draw to avoid rounding issue.
|
||||
init_etie_cam_uniforms(m_etie_base_uniforms, m_common_data.settings.camera);
|
||||
init_etie_cam_uniforms(m_etie_base_uniforms, m_common_data.settings.camera, render_state);
|
||||
}
|
||||
|
||||
glBindVertexArray(tree.vao);
|
||||
|
@ -654,7 +673,7 @@ void Tie3::envmap_second_pass_draw(const Tree& tree,
|
|||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER,
|
||||
render_state->no_multidraw ? tree.single_draw_index_buffer : tree.index_buffer);
|
||||
|
||||
init_etie_cam_uniforms(m_etie_uniforms, m_common_data.settings.camera);
|
||||
init_etie_cam_uniforms(m_etie_uniforms, m_common_data.settings.camera, render_state);
|
||||
set_uniform(m_etie_uniforms.envmap_tod_tint, m_common_data.envmap_color);
|
||||
|
||||
int last_texture = -1;
|
||||
|
@ -874,6 +893,8 @@ void do_wind_math(u16 wind_idx,
|
|||
// sd s2, 0(s5)
|
||||
}
|
||||
|
||||
namespace {} // namespace
|
||||
|
||||
void Tie3::render_tree_wind(int idx,
|
||||
int geom,
|
||||
const TfragRenderSettings& settings,
|
||||
|
@ -887,10 +908,17 @@ void Tie3::render_tree_wind(int idx,
|
|||
// note: this isn't the most efficient because we might compute wind matrices for invisible
|
||||
// instances. TODO: add vis ids to the instance info to avoid this
|
||||
memset(tree.wind_matrix_cache.data(), 0, sizeof(float) * 16 * tree.wind_matrix_cache.size());
|
||||
auto& cam_bad = settings.camera.camera;
|
||||
|
||||
auto& this_cam = render_state->cameras[render_state->camera_idx];
|
||||
math::Matrix4f s_T_w = matrix_from_col_vectors(settings.camera.camera);
|
||||
auto hacked_cam = s_T_w * this_cam.w_T_wprime;
|
||||
|
||||
// auto& cam_bad = settings.camera.camera;
|
||||
std::array<math::Vector4f, 4> cam;
|
||||
for (int i = 0; i < 4; i++) {
|
||||
cam[i] = cam_bad[i];
|
||||
for (int c = 0; c < 4; c++) {
|
||||
for (int r = 0; r < 4; r++) {
|
||||
cam[c][r] = hacked_cam(r, c);
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t inst_id = 0; inst_id < tree.instance_info->size(); inst_id++) {
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
|
||||
|
||||
#include "background_common.h"
|
||||
#include "common/math/geometry.h"
|
||||
|
||||
#ifdef __aarch64__
|
||||
#include "third-party/sse2neon/sse2neon.h"
|
||||
|
@ -171,6 +172,18 @@ DoubleDraw setup_tfrag_shader(SharedRenderState* render_state, DrawMode mode, Sh
|
|||
return draw_settings;
|
||||
}
|
||||
|
||||
namespace {
|
||||
math::Matrix4f matrix_from_col_vectors(const math::Vector4f* vectors) {
|
||||
math::Matrix4f ret;
|
||||
for (int c = 0; c < 4; c++) {
|
||||
for (int r = 0; r < 4; r++) {
|
||||
ret(r, c) = vectors[c][r];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
void first_tfrag_draw_setup(const TfragRenderSettings& settings,
|
||||
SharedRenderState* render_state,
|
||||
ShaderId shader) {
|
||||
|
@ -180,8 +193,10 @@ void first_tfrag_draw_setup(const TfragRenderSettings& settings,
|
|||
glUniform1i(glGetUniformLocation(id, "gfx_hack_no_tex"), Gfx::g_global_settings.hack_no_tex);
|
||||
glUniform1i(glGetUniformLocation(id, "decal"), false);
|
||||
glUniform1i(glGetUniformLocation(id, "tex_T0"), 0);
|
||||
auto& this_cam = render_state->cameras[render_state->camera_idx];
|
||||
math::Matrix4f s_T_w = matrix_from_col_vectors(settings.camera.camera);
|
||||
glUniformMatrix4fv(glGetUniformLocation(id, "camera"), 1, GL_FALSE,
|
||||
settings.camera.camera[0].data());
|
||||
(s_T_w * this_cam.w_T_wprime).data());
|
||||
glUniform4f(glGetUniformLocation(id, "hvdf_offset"), settings.camera.hvdf_off[0],
|
||||
settings.camera.hvdf_off[1], settings.camera.hvdf_off[2],
|
||||
settings.camera.hvdf_off[3]);
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace jak1 {
|
|||
enum class BucketId {
|
||||
BUCKET0 = 0,
|
||||
BUCKET1 = 1,
|
||||
// 2
|
||||
BUCKET2 = 2,
|
||||
SKY_DRAW = 3,
|
||||
OCEAN_MID_AND_FAR = 4,
|
||||
TFRAG_TEX_LEVEL0 = 5,
|
||||
|
|
|
@ -1,5 +1,8 @@
|
|||
#include "Merc2.h"
|
||||
|
||||
#include "common/math/geometry.h"
|
||||
|
||||
|
||||
#ifdef __aarch64__
|
||||
#include "third-party/sse2neon/sse2neon.h"
|
||||
#else
|
||||
|
@ -840,6 +843,18 @@ void set_uniform(GLuint uniform, const math::Vector4f& val) {
|
|||
}
|
||||
} // namespace
|
||||
|
||||
namespace {
|
||||
math::Matrix4f matrix_from_col_vectors(const math::Vector4f* vectors) {
|
||||
math::Matrix4f ret;
|
||||
for (int c = 0; c < 4; c++) {
|
||||
for (int r = 0; r < 4; r++) {
|
||||
ret(r, c) = vectors[c][r];
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void Merc2::handle_setup_dma(DmaFollower& dma, SharedRenderState* render_state) {
|
||||
auto first = dma.read_and_advance();
|
||||
|
||||
|
@ -882,16 +897,18 @@ void Merc2::handle_setup_dma(DmaFollower& dma, SharedRenderState* render_state)
|
|||
// 8 qw's of low memory data
|
||||
memcpy(&m_low_memory, first.data + 16, sizeof(LowMemory));
|
||||
|
||||
auto& this_cam = render_state->cameras[render_state->camera_idx];
|
||||
math::Matrix4f p = matrix_from_col_vectors(m_low_memory.perspective);
|
||||
auto new_cam = (p * inverse(this_cam.pri_cam_T_cam));
|
||||
|
||||
switch_to_merc2(render_state);
|
||||
set_uniform(m_merc_uniforms.hvdf_offset, m_low_memory.hvdf_offset);
|
||||
set_uniform(m_merc_uniforms.fog, m_low_memory.fog);
|
||||
glUniformMatrix4fv(m_merc_uniforms.perspective_matrix, 1, GL_FALSE,
|
||||
&m_low_memory.perspective[0].x());
|
||||
glUniformMatrix4fv(m_merc_uniforms.perspective_matrix, 1, GL_FALSE, new_cam.data());
|
||||
switch_to_emerc(render_state);
|
||||
set_uniform(m_emerc_uniforms.hvdf_offset, m_low_memory.hvdf_offset);
|
||||
set_uniform(m_emerc_uniforms.fog, m_low_memory.fog);
|
||||
glUniformMatrix4fv(m_emerc_uniforms.perspective_matrix, 1, GL_FALSE,
|
||||
&m_low_memory.perspective[0].x());
|
||||
glUniformMatrix4fv(m_emerc_uniforms.perspective_matrix, 1, GL_FALSE, new_cam.data());
|
||||
|
||||
// 1 qw with another 4 vifcodes.
|
||||
u32 vifcode_final_data[4];
|
||||
|
|
|
@ -232,8 +232,12 @@ void Sprite3::render_2d_group0(DmaFollower& dma,
|
|||
// glUniform4fv(glGetUniformLocation(shid, "hmge_scale"), 1, m_frame_data.hmge_scale.data());
|
||||
glUniform1f(glGetUniformLocation(shid, "deg_to_rad"), m_frame_data.deg_to_rad);
|
||||
glUniform1f(glGetUniformLocation(shid, "inv_area"), m_frame_data.inv_area);
|
||||
auto& this_cam = render_state->cameras[render_state->camera_idx];
|
||||
|
||||
glUniformMatrix4fv(glGetUniformLocation(shid, "camera"), 1, GL_FALSE,
|
||||
m_3d_matrix_data.camera.data());
|
||||
// m_3d_matrix_data.camera
|
||||
(m_3d_matrix_data.camera * this_cam.w_T_wprime)
|
||||
.data());
|
||||
glUniform4fv(glGetUniformLocation(shid, "xy_array"), 8, m_frame_data.xy_array[0].data());
|
||||
glUniform4fv(glGetUniformLocation(shid, "xyz_array"), 4, m_frame_data.xyz_array[0].data());
|
||||
glUniform4fv(glGetUniformLocation(shid, "st_array"), 4, m_frame_data.st_array[0].data());
|
||||
|
|
|
@ -904,6 +904,16 @@
|
|||
|
||||
(define *generic-effect-mode* 0)
|
||||
|
||||
|
||||
;; This contains the camera matrices. There must be one "primary camera" that matches *math-camera*. But the rest of the cameras are up to you.
|
||||
(deftype multi-camera (structure)
|
||||
((primary-camera matrix :inline)
|
||||
(extra-cameras matrix 3 :inline)
|
||||
)
|
||||
)
|
||||
|
||||
(define *multi-camera* (new 'global 'multi-camera))
|
||||
|
||||
(defun real-main-draw-hook ()
|
||||
"The main drawing function. This dispatches all renderers and is called directly from the display-loop
|
||||
in main.gc"
|
||||
|
@ -937,6 +947,60 @@
|
|||
(reset! *dma-mem-usage*)
|
||||
)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Multi-camera mode: camera placement.
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
;; set primary camera to the normal camera.
|
||||
(matrix-copy! (-> *multi-camera* primary-camera)
|
||||
(-> *math-camera* inv-camera-rot)
|
||||
)
|
||||
|
||||
;; set secondary camera to some example different camera. This puts a camera 10 meters above the default, and
|
||||
;; point it at jak directly:
|
||||
(let ((cam-pos (vector-copy! (new-stack-vector0) (-> *math-camera* inv-camera-rot vector 3))))
|
||||
;; shift up by 10 meters
|
||||
(+! (-> cam-pos y) (meters 5))
|
||||
;; dir from camera to jak
|
||||
(let* ((jak-dir (vector-! (new-stack-vector0)
|
||||
(if *target* (-> *target* root trans)
|
||||
(new-stack-vector0))
|
||||
cam-pos
|
||||
))
|
||||
(mat (-> *multi-camera* extra-cameras 0))
|
||||
)
|
||||
;; create rotation matrix to point camera at jak
|
||||
(forward-down->inv-matrix
|
||||
mat
|
||||
jak-dir
|
||||
(new 'static 'vector :y -1.))
|
||||
;; set position.
|
||||
(vector-copy! (-> mat vector 3) cam-pos)
|
||||
)
|
||||
)
|
||||
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
;; Multi-camera mode: send data to C++
|
||||
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
|
||||
|
||||
(with-dma-buffer-add-bucket ((buf (-> (current-frame) global-buf))
|
||||
(the bucket-id 2))
|
||||
(dma-buffer-add-cnt-vif2
|
||||
buf
|
||||
(/ (size-of multi-camera) 16)
|
||||
(the vif-tag 0)
|
||||
(the vif-tag 0)
|
||||
)
|
||||
;(&+! (-> buf base) 16)
|
||||
|
||||
(mem-copy! (-> buf base)
|
||||
(the pointer *multi-camera*)
|
||||
(size-of multi-camera)
|
||||
)
|
||||
(&+! (-> buf base) (size-of multi-camera))
|
||||
)
|
||||
|
||||
|
||||
;; todo shrub matrix
|
||||
|
||||
;; initialize dma buckets that are generic sinks.
|
||||
|
|
Loading…
Reference in New Issue