[graphics] Ocean Mid (in progress) (#1232)

* first pass at ocean mid

* fix some bugs

* fix seams

* cleanup

* temp

* fix mipmap
This commit is contained in:
water111 2022-03-14 19:47:29 -04:00 committed by GitHub
parent b2131d43e3
commit ef0f7635d3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 5136 additions and 1162 deletions

View File

@ -5,7 +5,7 @@
namespace colors {
// some reasonable colors that are different from each other
constexpr int COLOR_COUNT = 131;
u32 common_colors[COLOR_COUNT] = {
constexpr u32 common_colors[COLOR_COUNT] = {
0xF0F8FE, 0xFAEBD7, 0x00FFFF, 0x70DB93, 0xF0FFFF, 0xF5F5DC, 0x000000, 0x0000FF, 0x9F5F9F,
0xB5A642, 0xD9D919, 0x8C7853, 0xA52A2A, 0x5F9EA0, 0xD2691E, 0xB87333, 0xFF7F50, 0xDC143C,
0x00FFFF, 0x00008B, 0x5C4033, 0x008B8B, 0xB8860B, 0xA9A9A9, 0x006400, 0xBDB76B, 0x8B008B,

View File

@ -830,18 +830,25 @@ std::string VuDisassembler::to_cpp(const VuInstruction& instr, bool mips2c_forma
vi_src(instr.src.at(1).to_string(m_label_names), mips2c_format));
case VuInstrK::IOR:
if (instr.src.at(1).is_int_reg(0)) {
ASSERT(!instr.dst->is_int_reg(0));
ASSERT(!instr.src.at(0).is_int_reg(0));
if (mips2c_format) {
return fmt::format("vis[{}] = vis[{}];", instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names));
fmt::print("instr: {}\n", to_string(instr));
if (instr.src.at(0).is_int_reg(0) && instr.src.at(1).is_int_reg(0)) {
return fmt::format("vu.{} = 0;", instr.dst->to_string(m_label_names));
} else {
return fmt::format("vu.{} = vu.{};", instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names));
ASSERT(!instr.dst->is_int_reg(0));
ASSERT(!instr.src.at(0).is_int_reg(0));
if (mips2c_format) {
return fmt::format("vis[{}] = vis[{}];", instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names));
} else {
return fmt::format("vu.{} = vu.{};", instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names));
}
}
} else {
goto unknown;
return fmt::format("vu.{} = vu.{} | vu.{};", instr.dst->to_string(m_label_names),
instr.src.at(0).to_string(m_label_names),
instr.src.at(1).to_string(m_label_names));
}
case VuInstrK::MFP:
@ -865,8 +872,7 @@ std::string VuDisassembler::to_cpp(const VuInstruction& instr, bool mips2c_forma
bc_to_part(*instr.second_src_field));
case VuInstrK::ERLENG:
return fmt::format("vu.P = erleng(Mask::{}, vu.{}); /* TODO erleng */",
mask_to_string(*instr.mask), instr.src.at(0).to_string(m_label_names));
return fmt::format("vu.P = erleng(vu.{});", instr.src.at(0).to_string(m_label_names));
case VuInstrK::RSQRT:
return fmt::format(
"c->Q = c->vf_src({}).vf.{}() / std::sqrt(c->vf_src({}).vf.{}());",
@ -891,8 +897,11 @@ std::string VuDisassembler::to_cpp(const VuInstruction& instr, bool mips2c_forma
vf_src(instr.src.at(0).to_string(m_label_names), mips2c_format),
vf_src(instr.src.at(1).to_string(m_label_names), mips2c_format));
case VuInstrK::FCAND:
return fmt::format("ASSERT(false); vu.vi01 = cf & 0x{:x};\n", instr.src.at(0).value());
return fmt::format("fcand(vu.vi01, 0x{:x}, cf);\n", instr.src.at(0).value());
case VuInstrK::FCOR:
return fmt::format("fcor(vu.vi01, 0x{:x}, cf);\n", instr.src.at(0).value());
case VuInstrK::FCSET:
return fmt::format("cf = 0x{:x};\n", instr.src.at(0).value());
case VuInstrK::ADDbc:
case VuInstrK::SUBbc:
case VuInstrK::MULbc:
@ -971,6 +980,9 @@ std::string VuDisassembler::to_cpp(const VuInstruction& instr, bool mips2c_forma
return fmt::format("vu.acc.mula(Mask::{}, vu.{}, vu.{});", mask_to_string(*instr.mask),
instr.src.at(0).to_string(m_label_names),
instr.src.at(1).to_string(m_label_names));
case VuInstrK::MULAq:
return fmt::format("vu.acc.mula(Mask::{}, vu.{}, vu.Q);", mask_to_string(*instr.mask),
instr.src.at(0).to_string(m_label_names));
case VuInstrK::MULAbc:
return fmt::format(mips2c_format
? "c->acc.vf.mula(Mask::{}, c->vf_src({}).vf, c->vf_src({}).vf.{}());"
@ -985,13 +997,17 @@ std::string VuDisassembler::to_cpp(const VuInstruction& instr, bool mips2c_forma
return fmt::format("vu.{} = xtop();", instr.src.at(0).to_string(m_label_names));
default:
unk++;
fmt::print("unknown 0 is {}\n", to_string(instr));
return "ASSERT(false);"; //"???";
}
unknown:
unk++;
return "???";
fmt::print("unknown 1 is {}\n", to_string(instr));
return "ASSERT(false);";
}
std::string VuDisassembler::to_string(const VuInstruction& instr) const {

View File

@ -84,6 +84,8 @@ set(RUNTIME_SOURCE
graphics/opengl_renderer/foreground/Generic2_DMA.cpp
graphics/opengl_renderer/foreground/Generic2_Build.cpp
graphics/opengl_renderer/foreground/Generic2_OpenGL.cpp
graphics/opengl_renderer/ocean/OceanMid.cpp
graphics/opengl_renderer/ocean/OceanMid_PS2.cpp
graphics/opengl_renderer/ocean/OceanMidAndFar.cpp
graphics/opengl_renderer/ocean/OceanTexture.cpp
graphics/opengl_renderer/ocean/OceanTexture_PC.cpp

View File

@ -64,6 +64,8 @@ class DirectRenderer : public BucketRenderer {
m_blend_state.d = GsAlpha::BlendMode::SOURCE;
}
void set_mipmap(bool en) { m_debug_state.disable_mipmap = !en; }
private:
void handle_ad(const u8* data, SharedRenderState* render_state, ScopedProfilerNode& prof);
void handle_zbuf1(u64 val, SharedRenderState* render_state, ScopedProfilerNode& prof);

View File

@ -79,4 +79,5 @@ ShaderLibrary::ShaderLibrary() {
at(ShaderId::EYE) = {"eye"};
at(ShaderId::GENERIC) = {"generic"};
at(ShaderId::OCEAN_TEXTURE) = {"ocean_texture"};
at(ShaderId::OCEAN_TEXTURE_MIPMAP) = {"ocean_texture_mipmap"};
}

View File

@ -36,6 +36,7 @@ enum class ShaderId {
EYE = 11,
GENERIC = 12,
OCEAN_TEXTURE = 13,
OCEAN_TEXTURE_MIPMAP = 14,
MAX_SHADERS
};

View File

@ -0,0 +1,145 @@
#include "OceanMid.h"
static bool is_end_tag(const DmaTag& tag, const VifCode& v0, const VifCode& v1) {
return tag.qwc == 2 && tag.kind == DmaTag::Kind::CNT && v0.kind == VifCode::Kind::NOP &&
v1.kind == VifCode::Kind::DIRECT;
}
OceanMid::OceanMid() {
for (auto& x : m_vu_data) {
x.fill(999.);
}
vu.vf25 = Vf(1, 1, 1, 1);
}
void OceanMid::run(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof,
DirectRenderer& direct) {
// first is setting base and offset
{
auto base_offset_tag = dma.read_and_advance();
ASSERT(base_offset_tag.size_bytes == 0);
auto base = base_offset_tag.vifcode0();
ASSERT(base.kind == VifCode::Kind::BASE);
ASSERT(base.immediate == VU1_INPUT_BUFFER_BASE);
auto offset = base_offset_tag.vifcode1();
ASSERT(offset.kind == VifCode::Kind::OFFSET);
ASSERT(offset.immediate == VU1_INPUT_BUFFER_OFFSET);
}
// next is constants
{
auto constants = dma.read_and_advance();
ASSERT(constants.size_bytes == sizeof(Constants));
ASSERT(constants.vifcode0().kind == VifCode::Kind::STCYCL); // for whatever reason they do this
auto unpack = constants.vifcode1();
ASSERT(VifCodeUnpack(unpack).addr_qw == Vu1Data::CONSTANTS);
memcpy(&m_constants, constants.data, sizeof(Constants));
memcpy(m_vu_data + Vu1Data::CONSTANTS, &m_constants, sizeof(Constants));
}
// next is call 0
{
auto call0 = dma.read_and_advance();
ASSERT(call0.vifcode0().kind == VifCode::Kind::STCYCL);
auto c = call0.vifcode1();
ASSERT(c.kind == VifCode::Kind::MSCALF);
ASSERT(c.immediate == 0);
run_call0();
}
while (!is_end_tag(dma.current_tag(), dma.current_tag_vif0(), dma.current_tag_vif1())) {
auto data = dma.read_and_advance();
auto v0 = data.vifcode0();
auto v1 = data.vifcode1();
if (v0.kind == VifCode::Kind::STCYCL && v0.immediate == 0x404 &&
v1.kind == VifCode::Kind::UNPACK_V4_32) {
auto up = VifCodeUnpack(v1);
// ASSERT(up.use_tops_flag);
u16 addr = up.addr_qw + (up.use_tops_flag ? get_upload_buffer() : 0);
ASSERT(addr + v1.num <= 1024);
memcpy(m_vu_data + addr, data.data, 16 * v1.num);
ASSERT(16 * v1.num == data.size_bytes);
} else if (v0.kind == VifCode::Kind::STCYCL && v0.immediate == 0x404 &&
v1.kind == VifCode::Kind::UNPACK_V4_8) {
auto up = VifCodeUnpack(v1);
ASSERT(up.use_tops_flag);
ASSERT(up.is_unsigned);
u16 addr = up.addr_qw + get_upload_buffer();
ASSERT(addr + v1.num <= 1024);
u32 temp[4];
for (u32 i = 0; i < v1.num; i++) {
for (u32 j = 0; j < 4; j++) {
temp[j] = data.data[4 * i + j];
}
memcpy(m_vu_data + addr + i, temp, 16);
}
ASSERT(4 * v1.num == data.size_bytes);
} else if (v0.kind == VifCode::Kind::STCYCL && v0.immediate == 0x204 &&
v1.kind == VifCode::Kind::UNPACK_V4_8) {
auto up = VifCodeUnpack(v1);
ASSERT(up.use_tops_flag);
ASSERT(up.is_unsigned);
u16 addr = up.addr_qw + get_upload_buffer();
ASSERT(addr + v1.num <= 1024);
u32 temp[4];
for (u32 i = 0; i < v1.num; i++) {
for (u32 j = 0; j < 4; j++) {
temp[j] = data.data[4 * i + j];
}
// cl = 4
// wl = 2
u32 addr_off = 4 * (i / 2) + i % 2;
memcpy(m_vu_data + addr + addr_off, temp, 16);
}
ASSERT(8 * v1.num == data.size_bytes);
// TODO
} else if (v0.kind == VifCode::Kind::STCYCL && v0.immediate == 0x404 &&
v1.kind == VifCode::Kind::MSCALF) {
switch (v1.immediate) {
case 46:
run_call46_vu2c(render_state, prof, direct);
break;
case 73:
run_call73_vu2c(render_state, prof, direct);
break;
case 107:
run_call107_vu2c(render_state, prof, direct);
break;
case 275:
run_call275_vu2c(render_state, prof, direct);
break;
default:
fmt::print("unknown call1: {}\n", v1.immediate);
}
// TODO
} else if (v0.kind == VifCode::Kind::MSCALF && v1.kind == VifCode::Kind::FLUSHA) {
switch (v0.immediate) {
case 41:
run_call41_vu2c();
break;
case 43:
run_call43_vu2c();
break;
default:
fmt::print("unknown call2: {}\n", v0.immediate);
ASSERT(false);
}
// TODO
}
else {
fmt::print("{} {}\n", data.vifcode0().print(), data.vifcode1().print());
ASSERT(false);
}
}
}
void OceanMid::run_call0() {
run_call0_vu2c();
}

View File

@ -0,0 +1,203 @@
#pragma once
#include "game/graphics/opengl_renderer/BucketRenderer.h"
#include "game/graphics/opengl_renderer/DirectRenderer.h"
#include "game/common/vu.h"
class OceanMid {
public:
OceanMid();
void run(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof,
DirectRenderer& direct);
private:
void run_call0();
void run_call0_vu2c();
void run_call41_vu2c();
void run_call43_vu2c();
void run_call46_vu2c(SharedRenderState* render_state,
ScopedProfilerNode& prof,
DirectRenderer& direct);
void run_call73_vu2c(SharedRenderState* render_state,
ScopedProfilerNode& prof,
DirectRenderer& direct);
void run_call107_vu2c(SharedRenderState* render_state,
ScopedProfilerNode& prof,
DirectRenderer& direct);
void run_call275_vu2c(SharedRenderState* render_state,
ScopedProfilerNode& prof,
DirectRenderer& direct);
void xgkick(u16 addr,
SharedRenderState* render_state,
ScopedProfilerNode& prof,
DirectRenderer& direct);
void run_L26_vu2c();
void run_L32_vu2c();
void run_L38_vu2c(SharedRenderState* render_state,
ScopedProfilerNode& prof,
DirectRenderer& direct);
void run_L43_vu2c(SharedRenderState* render_state,
ScopedProfilerNode& prof,
DirectRenderer& direct);
void run_L45_vu2c();
bool m_buffer_toggle = false;
static constexpr int VU1_INPUT_BUFFER_BASE = 0;
static constexpr int VU1_INPUT_BUFFER_OFFSET = 0x76;
u16 xtop() {
m_buffer_toggle = !m_buffer_toggle;
return get_vu_buffer();
}
u16 get_upload_buffer() {
if (m_buffer_toggle) {
return VU1_INPUT_BUFFER_OFFSET;
} else {
return VU1_INPUT_BUFFER_BASE;
}
}
u16 get_vu_buffer() {
if (!m_buffer_toggle) {
return VU1_INPUT_BUFFER_OFFSET;
} else {
return VU1_INPUT_BUFFER_BASE;
}
}
// (deftype ocean-mid-constants (structure)
struct Constants {
// ((hmge-scale vector :inline :offset-assert 0)
math::Vector4f hmge_scale;
// (inv-hmge-scale vector :inline :offset-assert 16)
math::Vector4f inv_hmge_scale;
// (hvdf-offset vector :inline :offset-assert 32)
math::Vector4f hvdf_offset;
// (fog vector :inline :offset-assert 48)
math::Vector4f fog;
// (constants vector :inline :offset-assert 64)
math::Vector4f constants;
// (constants2 vector :inline :offset-assert 80)
math::Vector4f constants2;
// (drw-fan gs-gif-tag :inline :offset-assert 96) ;; was qword
u8 drw_fan[16];
// (env-fan gs-gif-tag :inline :offset-assert 112) ;; was qword
u8 env_fan[16];
// (drw-adgif gs-gif-tag :inline :offset-assert 128);; was qword
AdGifData drw_adgif;
// (drw-texture adgif-shader :inline :offset-assert 144)
u8 drw_texture[16];
// (drw-strip-0 gs-gif-tag :inline :offset-assert 224) ;; was qword
u8 drw_strip_0[16];
// (drw-strip-1 gs-gif-tag :inline :offset-assert 240) ;; was qword
u8 drw_strip_1[16];
// (env-adgif gs-gif-tag :inline :offset-assert 256) ;; was qword
u8 env_adgif[16];
// (env-texture adgif-shader :inline :offset-assert 272)
AdGifData env_texture;
// (env-strip gs-gif-tag :inline :offset-assert 352) ;; was qword
u8 env_strip[16];
// (env-color vector :inline :offset-assert 368)
math::Vector4f env_color;
// (index-table vector4w 8 :inline :offset-assert 384)
math::Vector<u32, 4> index_table[8];
// (pos0 vector :inline :offset-assert 512)
math::Vector4f pos0;
// (pos1 vector :inline :offset-assert 528)
math::Vector4f pos1;
// (pos2 vector :inline :offset-assert 544)
math::Vector4f pos2;
// (pos3 vector :inline :offset-assert 560)
math::Vector4f pos3;
// )
// :method-count-assert 9
// :size-assert #x240
// :flag-assert #x900000240
// )
} m_constants;
static_assert(sizeof(Constants) == 0x240);
enum Vu1Data {
IN_BUFFER_0 = VU1_INPUT_BUFFER_BASE, // 0
IN_BUFFER_1 = VU1_INPUT_BUFFER_OFFSET, // 0x76
CONSTANTS = 0x2dd,
};
Vf m_vu_data[1024];
void sq_buffer(Mask mask, const Vf& val, u16 addr) {
ASSERT(addr < 1024);
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
m_vu_data[addr].data[i] = val[i];
}
}
}
void ilw_buffer(Mask mask, u16& dest, u16 addr) {
ASSERT(addr < 1024);
switch (mask) {
case Mask::x:
dest = m_vu_data[addr].x_as_u16();
break;
case Mask::y:
dest = m_vu_data[addr].y_as_u16();
break;
case Mask::z:
dest = m_vu_data[addr].z_as_u16();
break;
case Mask::w:
dest = m_vu_data[addr].w_as_u16();
break;
default:
ASSERT(false);
}
}
void isw_buffer(Mask mask, u16 src, u16 addr) {
ASSERT(addr < 1024);
u32 val32 = src;
switch (mask) {
case Mask::x:
memcpy(&m_vu_data[addr].data[0], &val32, 4);
break;
case Mask::y:
memcpy(&m_vu_data[addr].data[1], &val32, 4);
break;
case Mask::z:
memcpy(&m_vu_data[addr].data[2], &val32, 4);
break;
case Mask::w:
memcpy(&m_vu_data[addr].data[3], &val32, 4);
break;
default:
ASSERT(false);
}
}
void lq_buffer(Mask mask, Vf& dest, u16 addr) {
ASSERT(addr < 1024);
for (int i = 0; i < 4; i++) {
if ((u64)mask & (1 << i)) {
dest[i] = m_vu_data[addr].data[i];
}
}
}
struct Vu {
const Vf vf00;
Accumulator acc;
Vf vf01, vf02, vf03, vf04, vf05, vf06, vf07, vf08, vf09, vf10, vf11, vf12, vf13, vf14, vf15,
vf16, vf17, vf18, vf19, vf20, vf21, vf22, vf23, vf24, vf25, vf26, vf27, vf28, vf29, vf30,
vf31;
u16 vi01, vi02, vi03, vi04, vi05, vi06, vi07, vi08, vi09, vi10, vi11, vi12, vi13, vi14, vi15;
float Q, P;
Vu() : vf00(0, 0, 0, 1) {}
} vu;
};

View File

@ -47,7 +47,9 @@ void OceanMidAndFar::render(DmaFollower& dma,
}
handle_ocean_far(dma, render_state, prof);
m_direct.flush_pending(render_state, prof);
m_direct.set_mipmap(true);
handle_ocean_mid(dma, render_state, prof);
auto final_next = dma.read_and_advance();
@ -59,6 +61,7 @@ void OceanMidAndFar::render(DmaFollower& dma,
ASSERT(dma.current_tag_offset() == render_state->next_bucket);
m_direct.flush_pending(render_state, prof);
m_direct.set_mipmap(false);
}
void OceanMidAndFar::handle_ocean_far(DmaFollower& dma,
@ -93,6 +96,13 @@ bool is_end_tag(const DmaTag& tag, const VifCode& v0, const VifCode& v1) {
void OceanMidAndFar::handle_ocean_mid(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
if (dma.current_tag_vifcode0().kind == VifCode::Kind::BASE) {
m_mid_renderer.run(dma, render_state, prof, m_direct);
} else {
// not drawing
return;
}
while (!is_end_tag(dma.current_tag(), dma.current_tag_vifcode0(), dma.current_tag_vifcode1())) {
dma.read_and_advance();
}

View File

@ -4,10 +4,14 @@
#include "game/graphics/opengl_renderer/DirectRenderer.h"
#include "game/graphics/opengl_renderer/opengl_utils.h"
#include "game/graphics/opengl_renderer/ocean/OceanTexture.h"
#include "game/graphics/opengl_renderer/ocean/OceanMid.h"
/*!
* OceanMidAndFar is the handler for the first ocean bucket.
*
* This bucket runs three renderers:
* - ocean-texture (handled by the OceanTexture C++ class)
* - ocean-far (handled by this class, it's very simple)
* - ocean-mid (handled by the C++ OceanMid class)
*/
class OceanMidAndFar : public BucketRenderer {
public:
@ -26,4 +30,5 @@ class OceanMidAndFar : public BucketRenderer {
DirectRenderer m_direct;
OceanTexture m_texture_renderer;
OceanMid m_mid_renderer;
};

File diff suppressed because it is too large Load Diff

View File

@ -4,7 +4,8 @@
constexpr int OCEAN_TEX_TBP = 8160; // todo
OceanTexture::OceanTexture()
: m_tex0(TEX0_SIZE, TEX0_SIZE, GL_UNSIGNED_INT_8_8_8_8_REV),
: m_result_texture(TEX0_SIZE, TEX0_SIZE, GL_UNSIGNED_INT_8_8_8_8_REV, 8),
m_temp_texture(TEX0_SIZE, TEX0_SIZE, GL_UNSIGNED_INT_8_8_8_8_REV),
m_hack_renderer("burp", BucketId::BUCKET0, 0x8000) {
m_dbuf_x = m_dbuf_a;
m_dbuf_y = m_dbuf_b;
@ -13,6 +14,34 @@ OceanTexture::OceanTexture()
m_tbuf_y = m_tbuf_b;
init_pc();
// initialize the mipmap drawing
glGenVertexArrays(1, &m_mipmap.vao);
glBindVertexArray(m_mipmap.vao);
glGenBuffers(1, &m_mipmap.vtx_buffer);
glBindBuffer(GL_ARRAY_BUFFER, m_mipmap.vtx_buffer);
std::vector<MipMap::Vertex> vertices = {
{-1, -1, 0, 0}, {-1, 1, 0, 1}, {1, -1, 1, 0}, {1, 1, 1, 1}};
glBufferData(GL_ARRAY_BUFFER, sizeof(MipMap::Vertex) * 4, vertices.data(), GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(
0, // location 0 in the shader
2, // 4 color components
GL_FLOAT, // floats
GL_FALSE, // normalized, ignored,
sizeof(MipMap::Vertex), //
(void*)offsetof(MipMap::Vertex, x) // offset in array (why is this a pointer...)
);
glVertexAttribPointer(
1, // location 0 in the shader
2, // 4 color components
GL_FLOAT, // floats
GL_FALSE, // normalized, ignored,
sizeof(MipMap::Vertex), //
(void*)offsetof(MipMap::Vertex, s) // offset in array (why is this a pointer...)
);
glBindVertexArray(0);
}
OceanTexture::~OceanTexture() {
@ -21,10 +50,9 @@ OceanTexture::~OceanTexture() {
void OceanTexture::init_textures(TexturePool& pool) {
TextureInput in;
in.gpu_texture = m_tex0.texture();
constexpr int boost = 2;
in.w = 128 * boost;
in.h = 128 * boost;
in.gpu_texture = m_result_texture.texture();
in.w = TEX0_SIZE;
in.h = TEX0_SIZE;
in.page_name = "PC-OCEAN";
in.name = "pc-ocean";
m_tex0_gpu = pool.give_texture_and_load_to_vram(in, OCEAN_TEX_TBP);
@ -73,7 +101,7 @@ void OceanTexture::handle_tex_call_rest(SharedRenderState* render_state, ScopedP
void OceanTexture::handle_ocean_texture(DmaFollower& dma,
SharedRenderState* render_state,
ScopedProfilerNode& prof) {
FramebufferTexturePairContext ctxt(m_tex0);
FramebufferTexturePairContext ctxt(m_temp_texture);
// render to the first texture
{
// (set-display-gs-state arg0 ocean-tex-page-0 128 128 0 0)
@ -234,5 +262,43 @@ void OceanTexture::handle_ocean_texture(DmaFollower& dma,
}
flush(render_state, prof);
render_state->texture_pool->move_existing_to_vram(m_tex0_gpu, 8160);
make_mipmaps(render_state, prof);
}
/*!
* Generate mipmaps for the ocean texture.
* There's a trick here - we reduce the intensity of alpha on the lower lods. This lets texture
* filtering slowly fade the alpha value out to 0 with distance.
*/
void OceanTexture::make_mipmaps(SharedRenderState* render_state, ScopedProfilerNode& prof) {
glBindVertexArray(m_mipmap.vao);
render_state->shaders[ShaderId::OCEAN_TEXTURE_MIPMAP].activate();
glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::OCEAN_TEXTURE_MIPMAP].id(),
"alpha_intensity"),
1.0);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, m_temp_texture.texture());
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glDisable(GL_DEPTH_TEST);
glDisable(GL_BLEND);
glUniform1i(
glGetUniformLocation(render_state->shaders[ShaderId::OCEAN_TEXTURE_MIPMAP].id(), "tex_T0"),
0);
glBindBuffer(GL_ARRAY_BUFFER, m_mipmap.vtx_buffer);
for (int i = 0; i < 8; i++) {
FramebufferTexturePairContext ctxt(m_result_texture, i);
glUniform1f(glGetUniformLocation(render_state->shaders[ShaderId::OCEAN_TEXTURE_MIPMAP].id(),
"alpha_intensity"),
std::max(0.f, 1.f - 0.5f * i));
glUniform1f(
glGetUniformLocation(render_state->shaders[ShaderId::OCEAN_TEXTURE_MIPMAP].id(), "scale"),
1.f / (1 << i));
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
prof.add_draw_call();
prof.add_tri(2);
}
render_state->texture_pool->move_existing_to_vram(m_tex0_gpu, OCEAN_TEX_TBP);
glBindVertexArray(0);
}

View File

@ -39,10 +39,13 @@ class OceanTexture {
void init_pc();
void destroy_pc();
void make_mipmaps(SharedRenderState* render_state, ScopedProfilerNode& prof);
bool m_use_ocean_specific = true;
static constexpr int TEX0_SIZE = 256; // TODO actually 128
FramebufferTexturePair m_tex0;
static constexpr int TEX0_SIZE = 128;
FramebufferTexturePair m_result_texture;
FramebufferTexturePair m_temp_texture;
GpuTexture* m_tex0_gpu = nullptr;
// (deftype ocean-texture-constants (structure)
@ -136,6 +139,15 @@ class OceanTexture {
GLuint vao, static_vertex_buffer, dynamic_vertex_buffer, gl_index_buffer;
} m_pc;
struct MipMap {
GLuint vao, vtx_buffer;
struct Vertex {
float x, y;
float s, t;
};
static_assert(sizeof(Vertex) == 16);
} m_mipmap;
enum TexVu1Data {
BUF0 = 384,
BUF1 = 583,

View File

@ -1,51 +1,89 @@
#include "opengl_utils.h"
#include "common/util/Assert.h"
#include <cstdio>
FramebufferTexturePair::FramebufferTexturePair(int w, int h, u64 texture_format) : m_w(w), m_h(h) {
glGenFramebuffers(1, &m_framebuffer);
FramebufferTexturePair::FramebufferTexturePair(int w, int h, u64 texture_format, int num_levels)
: m_w(w), m_h(h) {
m_framebuffers.resize(num_levels);
glGenFramebuffers(num_levels, m_framebuffers.data());
glGenTextures(1, &m_texture);
GLint old_framebuffer;
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &old_framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffer);
glBindTexture(GL_TEXTURE_2D, m_texture);
for (int i = 0; i < num_levels; i++) {
glBindTexture(GL_TEXTURE_2D, m_texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, num_levels);
glTexImage2D(GL_TEXTURE_2D, i, GL_RGBA, w >> i, h >> i, 0, GL_RGBA, texture_format, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
}
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, w, h, 0, GL_RGBA, texture_format, nullptr);
for (int i = 0; i < num_levels; i++) {
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebuffer(GL_FRAMEBUFFER, m_framebuffers[i]);
glBindTexture(GL_TEXTURE_2D, m_texture);
// I don't know if we really need to do this. whatever uses this texture should figure it out.
// I don't know if we really need to do this. whatever uses this texture should figure it out.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + i, m_texture, i);
GLenum draw_buffers[1] = {GLenum(GL_COLOR_ATTACHMENT0 + i)};
glDrawBuffers(1, draw_buffers);
auto status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
switch (status) {
case GL_FRAMEBUFFER_UNDEFINED:
printf("GL_FRAMEBUFFER_UNDEFINED\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT:
printf("GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT:
printf("GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER:
printf("GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER:
printf("GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER\n");
break;
case GL_FRAMEBUFFER_UNSUPPORTED:
printf("GL_FRAMEBUFFER_UNSUPPORTED\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE:
printf("GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE\n");
break;
case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS:
printf("GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS\n");
break;
}
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_texture, 0);
GLenum draw_buffers[1] = {GL_COLOR_ATTACHMENT0};
glDrawBuffers(1, draw_buffers);
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
ASSERT(false);
ASSERT(false);
}
glBindFramebuffer(GL_FRAMEBUFFER, old_framebuffer);
}
glBindFramebuffer(GL_FRAMEBUFFER, old_framebuffer);
}
FramebufferTexturePair::~FramebufferTexturePair() {
glDeleteFramebuffers(1, &m_framebuffer);
glDeleteFramebuffers(m_framebuffers.size(), m_framebuffers.data());
glDeleteTextures(1, &m_texture);
}
FramebufferTexturePairContext::FramebufferTexturePairContext(FramebufferTexturePair& fb)
FramebufferTexturePairContext::FramebufferTexturePairContext(FramebufferTexturePair& fb, int level)
: m_fb(&fb) {
glGetIntegerv(GL_VIEWPORT, m_old_viewport);
glGetIntegerv(GL_FRAMEBUFFER_BINDING, &m_old_framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, m_fb->m_framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, m_fb->m_framebuffers[level]);
glViewport(0, 0, m_fb->m_w, m_fb->m_h);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_fb->m_texture, 0);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_fb->m_texture, level);
}
void FramebufferTexturePairContext::switch_to(FramebufferTexturePair& fb) {
if (&fb != m_fb) {
m_fb = &fb;
glBindFramebuffer(GL_FRAMEBUFFER, m_fb->m_framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, m_fb->m_framebuffers[0]);
glViewport(0, 0, m_fb->m_w, m_fb->m_h);
glFramebufferTexture(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, m_fb->m_texture, 0);
}

View File

@ -7,7 +7,7 @@
*/
class FramebufferTexturePair {
public:
FramebufferTexturePair(int w, int h, u64 texture_format);
FramebufferTexturePair(int w, int h, u64 texture_format, int num_levels = 1);
~FramebufferTexturePair();
GLuint texture() const { return m_texture; }
@ -17,14 +17,14 @@ class FramebufferTexturePair {
private:
friend class FramebufferTexturePairContext;
GLuint m_framebuffer;
std::vector<GLuint> m_framebuffers;
GLuint m_texture;
int m_w, m_h;
};
class FramebufferTexturePairContext {
public:
FramebufferTexturePairContext(FramebufferTexturePair& fb);
FramebufferTexturePairContext(FramebufferTexturePair& fb, int level = 0);
~FramebufferTexturePairContext();
void switch_to(FramebufferTexturePair& fb);

View File

@ -8,5 +8,6 @@ uniform sampler2D tex_T0;
void main() {
vec4 tex = texture(tex_T0, tex_coord);
color = fragment_color * tex * 2;
tex.xyz *= 2;
color = fragment_color * tex;
}

View File

@ -0,0 +1,13 @@
#version 430 core
out vec4 color;
in vec2 tex_coord;
uniform float alpha_intensity;
uniform sampler2D tex_T0;
void main() {
vec4 tex = texture(tex_T0, tex_coord);
tex.w *= alpha_intensity;
color = tex;
}

View File

@ -0,0 +1,11 @@
#version 430 core
layout (location = 0) in vec2 position_in;
layout (location = 1) in vec2 tex_coord_in;
out vec2 tex_coord;
uniform float scale;
void main() {
gl_Position = vec4(position_in.x * scale - (1 - scale), position_in.y * scale - (1 - scale), 0.5, 1.0);
tex_coord = tex_coord_in;
}

View File

@ -9,14 +9,21 @@
(defun ocean-mid-setup-constants ((arg0 ocean-mid-constants))
"Generate the ocean VU1 renderer constants in-place."
;; the usual camera math
(let ((v1-0 *math-camera*))
(set! (-> arg0 hmge-scale quad) (-> v1-0 hmge-scale quad))
(set! (-> arg0 inv-hmge-scale quad) (-> v1-0 inv-hmge-scale quad))
(set! (-> arg0 hvdf-offset quad) (-> v1-0 hvdf-off quad))
(set-vector! (-> arg0 fog) (-> v1-0 pfog0) (-> v1-0 fog-min) (-> v1-0 fog-max) 3072.0)
)
;; is this 393216 the size of a triangle? (96 meters)
(set-vector! (-> arg0 constants) 0.5 0.5 0.0 393216.0)
(set-vector! (-> arg0 constants2) 0.5 0.5 1.0 0.0)
(let ((v1-3 *ocean-subdivide-draw-mode*))
(cond
((zero? v1-3)
@ -258,6 +265,8 @@
(set-vector! (-> arg0 index-table 5) 18 24 21 0)
(set-vector! (-> arg0 index-table 6) 9 12 12 0)
(set-vector! (-> arg0 index-table 7) 0 0 3 0)
(set-vector! (-> arg0 pos0) 0.0 0.0 0.0 1.0)
(set-vector! (-> arg0 pos1) 393216.0 0.0 0.0 1.0)
(set-vector! (-> arg0 pos2) 0.0 0.0 393216.0 1.0)
@ -265,9 +274,8 @@
(none)
)
;; definition for function ocean-mid-add-constants
;; INFO: Return type mismatch pointer vs none.
(defun ocean-mid-add-constants ((arg0 dma-buffer))
"Generate DMA for loading ocean-mid constants to VU1 data memory."
(let* ((a1-0 36)
(v1-0 arg0)
(a0-1 (the-as object (-> v1-0 base)))
@ -279,6 +287,7 @@
)
(set! (-> v1-0 base) (&+ (the-as pointer a0-1) 16))
)
;; generate the constants in place.
(ocean-mid-setup-constants (the-as ocean-mid-constants (-> arg0 base)))
(&+! (-> arg0 base) 576)
(none)
@ -509,9 +518,10 @@
(none)
)
;; definition for function ocean-mid-add-upload
;; Used lq/sq
(defun ocean-mid-add-upload ((arg0 dma-buffer) (arg1 int) (arg2 int) (arg3 int) (arg4 int) (arg5 float))
"Add DMA data to upload data needed to draw an ocean tile."
;; calculate the location of the tile.
(let ((gp-0 (new-stack-vector0)))
(let ((v1-1 (-> *ocean-map* start-corner)))
(set! (-> gp-0 x) (+ (-> v1-1 x) (* 3145728.0 (the float arg2))))
@ -519,7 +529,11 @@
(set! (-> gp-0 z) (+ (-> v1-1 z) (* 3145728.0 (the float arg1))))
)
(set! (-> gp-0 w) 1.0)
;; compute combined matrix
(ocean-mid-add-matrices arg0 gp-0)
;; upload color.
(let ((v1-4 (+ (the-as uint (-> *ocean-map* ocean-colors)) (* (+ (* 416 arg1) (* arg2 8)) 4))))
(dotimes (a0-6 9)
(let* ((a1-3 arg0)
@ -538,6 +552,10 @@
(+! v1-4 208)
)
)
;; upload "mid masks".
;; these allow some zones to be skipped.
;; using 0 will draw, using 1 willl skip.
(let* ((a2-3 1)
(v1-7 arg0)
(a0-7 (the-as object (-> v1-7 base)))
@ -553,10 +571,15 @@
(let ((a0-12 (-> *ocean-map* ocean-mid-masks data arg3)))
(set! (-> *ocean-work* mid-mask-ptrs arg4) (the-as (pointer int64) v1-8))
(set! (-> (the-as (pointer uint64) v1-8)) (-> a0-12 dword))
;; (set! (-> (the-as (pointer uint64) v1-8)) #xffffffffffffffff)
)
(set! (-> (the-as (pointer uint64) v1-8) 1) (the-as uint 0))
)
(&+! (-> arg0 base) 16)
;; when the camera is very close, we need to do additional checking.
;; I believe this checks which subtiles will be skipped by the renderer
;; and adds them to the camera masks.
(when (< arg5 556091.4)
(let* ((v1-12 (-> *math-camera* trans))
(s5-1 (&-> *ocean-work* mid-camera-masks arg4))
@ -694,6 +717,7 @@
(set! (-> a1-2 z) (+ (-> v1-1 z) (* 393216.0 (the float arg1))))
)
(set! (-> a1-2 w) 1.0)
;; (format 0 "~`vector`P~%" (-> *ocean-map* start-corner))
(ocean-mid-add-matrices arg0 a1-2)
)
(let* ((a1-3 9)
@ -982,6 +1006,41 @@
(none)
)
(defun sphere-cull-for-ocean ((arg0 vector))
"NOTE: added in PC port"
(local-vars (v1-0 uint128) (v1-1 uint128) (v1-2 uint128))
(rlet ((acc :class vf)
(vf0 :class vf)
(vf10 :class vf)
(vf16 :class vf)
(vf17 :class vf)
(vf18 :class vf)
(vf19 :class vf)
(vf9 :class vf)
)
(init-vf0-vector)
(let ((v1-5 *math-camera*))
;; note: these are for sphere cull.
(.lvf vf16 (&-> v1-5 plane 0 quad))
(.lvf vf17 (&-> v1-5 plane 1 quad))
(.lvf vf18 (&-> v1-5 plane 2 quad))
(.lvf vf19 (&-> v1-5 plane 3 quad))
)
(.lvf vf10 (&-> arg0 quad))
(.mul.x.vf acc vf16 vf10)
(.add.mul.y.vf acc vf17 vf10 acc)
(.add.mul.z.vf acc vf18 vf10 acc)
(.sub.mul.w.vf vf9 vf19 vf0 acc)
(.add.w.vf vf9 vf9 vf10)
(.mov v1-0 vf9)
(.pcgtw v1-1 0 v1-0)
(.ppach v1-2 (the-as uint128 0) v1-1)
(zero? (the-as int v1-2))
)
)
;; definition for function draw-ocean-mid-seams
;; INFO: Return type mismatch symbol vs none.
(defun draw-ocean-mid-seams ((arg0 dma-buffer))
@ -1004,7 +1063,7 @@
(while (>= s2-0 s3-0)
(set! (-> sv-36 x) (+ 196608.0 (* 393216.0 (the float s3-0)) (-> *ocean-map* start-corner x)))
(set! (-> sv-36 z) (+ 196608.0 (* 393216.0 (the float s5-0)) (-> *ocean-map* start-corner z)))
(when (sphere-cull sv-36)
(when (sphere-cull-for-ocean sv-36)
(cond
((= s5-0 sv-34)
(ocean-mid-add-upload-top arg0 s5-0 s3-0)
@ -1031,10 +1090,60 @@
(none)
)
;; definition for function draw-ocean-mid
;; INFO: Return type mismatch int vs none.
;; Used lq/sq
;; ADDED for PC Port
(defun debug-draw-ocean-tile ((y int) (x int) (color0 rgba) (color1 rgba) (masks int))
;;3145728.0
(let* ((ps (-> *ocean-map* start-corner))
(p0 (vector-copy! (new-stack-vector0) ps))
(p1 (vector-copy! (new-stack-vector0) ps))
(p2 (vector-copy! (new-stack-vector0) ps))
(p1s (vector-copy! (new-stack-vector0) ps))
(p2s (vector-copy! (new-stack-vector0) ps))
(p3 (vector-copy! (new-stack-vector0) ps))
(x0 (* 3145728.0 (the float x)))
(y0 (* 3145728.0 (the float y)))
)
(+! (-> p0 x) x0)
(+! (-> p0 z) y0)
(+! (-> p1 x) (+ x0 3145728.0))
(+! (-> p1 z) y0)
(+! (-> p2 x) x0)
(+! (-> p2 z) (+ y0 3145728.0))
(+! (-> p1s x) (+ x0 314572.0))
(+! (-> p1s z) y0)
(+! (-> p2s x) x0)
(+! (-> p2s z) (+ y0 314572.0))
(+! (-> p3 x) (+ x0 3145728.0))
(+! (-> p3 z) (+ y0 3145728.0))
(add-debug-flat-triangle #t (bucket-id debug-draw1) p0 p1s p2s color0)
;; (add-debug-flat-triangle #t (bucket-id debug-draw1) p3 p1 p2 color0)
(add-debug-outline-triangle #t (bucket-id debug-draw1) p0 p1 p2 color1)
(add-debug-outline-triangle #t (bucket-id debug-draw1) p3 p1 p2 color1)
(format (clear *temp-string*) "o: ~d ~d ~d ~b" x y (+ (* 6 y) x) masks)
(add-debug-text-3d
#t
(bucket-id debug-draw1)
*temp-string*
p0
(font-color orange-red)
(the vector2h #f)
)
)
)
(defun draw-ocean-mid ((arg0 dma-buffer))
"Main function to draw the 'mid' ocean
The mid ocean is used to draw the non-transparent ocean parts.
There is a large 6x6 grid of tiles.
Tiles that are closer to the camera have an environment mapping effect applied."
(rlet ((vf16 :class vf)
(vf17 :class vf)
(vf18 :class vf)
@ -1044,11 +1153,16 @@
(vf22 :class vf)
(vf23 :class vf)
)
;; first, reset all masks to 0
(dotimes (v1-0 36)
(set! (-> *ocean-work* mid-mask-ptrs v1-0) (the-as (pointer int64) #f))
(set! (-> *ocean-work* mid-camera-masks v1-0) (the-as uint 0))
)
;; upload VU1 program
(dma-buffer-add-vu-function arg0 ocean-mid-block 1)
;; set up base+offset for the VU1 program uploads
(let* ((v1-3 arg0)
(a0-6 (the-as object (-> v1-3 base)))
)
@ -1057,8 +1171,14 @@
(set! (-> (the-as dma-packet a0-6) vif1) (new 'static 'vif-tag :imm #x76 :cmd (vif-cmd offset)))
(set! (-> v1-3 base) (&+ (the-as pointer a0-6) 16))
)
;; upload ocean constants
(ocean-mid-add-constants arg0)
;; run program to initialize VU1 renderer
(ocean-mid-add-call arg0 0)
;; set up VF registers for sphere culling.
(let ((v1-5 *math-camera*))
(.lvf vf16 (&-> v1-5 plane 0 quad))
(.lvf vf17 (&-> v1-5 plane 1 quad))
@ -1070,21 +1190,30 @@
(.lvf vf23 (&-> v1-5 guard-plane 3 quad))
)
(set! (-> (new 'stack-no-clear 'vector) quad) (the-as uint128 0))
;; draw tiles!
(let ((s5-0 (-> *math-camera* trans)))
(dotimes (s4-0 6)
(dotimes (s3-0 6)
(let* ((s2-0 (+ (* 6 s4-0) s3-0))
(s1-0 (-> *ocean-map* ocean-spheres spheres s2-0))
(dotimes (s4-0 6) ;; x?
(dotimes (s3-0 6) ;; y?
(let* ((s2-0 (+ (* 6 s4-0) s3-0)) ;; tile index
(s1-0 (-> *ocean-map* ocean-spheres spheres s2-0)) ;; vis sphere of ocean
(s0-0 (-> (the-as (pointer int16) (+ (* s2-0 2) (the-as int (-> *ocean-map* ocean-mid-indices))))))
)
(when (sphere-cull s1-0)
;; (format 0 "draw ocean tile: ~d x ~d = ~d index ~d~%" s4-0 s3-0 s2-0 s0-0)
;; (debug-draw-ocean-tile s4-0 s3-0 (new 'static 'rgba :r #x80 :a #x80) (new 'static 'rgba :g #x80 :a #x80) s0-0)
(when (sphere-cull-for-ocean s1-0)
;;(format 0 " vis!~%")
(cond
((< s0-0 0)
;; (format 0 " skip tile.~%")
)
((let ((f30-0 (- (vector-vector-distance s1-0 s5-0) (-> s1-0 w))))
(ocean-mid-add-upload arg0 s4-0 s3-0 s0-0 s2-0 f30-0)
(< f30-0 786432.0)
;; HACK
;; #t
)
;; (format 0 " draw env map~%")
(ocean-mid-add-call arg0 73)
(+! (-> *terrain-stats* ocean-mid fragments) 1)
(+! (-> *terrain-stats* ocean-mid tris) 256)
@ -1102,6 +1231,13 @@
)
)
)
; (dotimes (i 36)
; (format 0 "tidx: ~d ~X~%" i (-> *ocean-work* mid-camera-masks i))
; )
;; for now, skip seams.
;; when it's both on and cam is low
(when (not (or *ocean-near-off* (< 196608.0 (fabs (-> *math-camera* trans y)))))
(let ((a1-11 48)
(a2-2 0)

File diff suppressed because it is too large Load Diff

View File

@ -667,7 +667,8 @@
)
)
)
; (when (not (or *ocean-near-off* (or *ocean-mid-off* (< 196608.0 (fabs (-> *math-camera* trans y))))))
(when (not (or *ocean-near-off* (or *ocean-mid-off* (< 196608.0 (fabs (-> *math-camera* trans y))))))
; (format *stdcon* "draw near~%")
; (let* ((s5-1 (-> *display* frames (-> *display* on-screen) frame global-buf))
; (gp-2 (-> s5-1 base))
; )
@ -689,7 +690,7 @@
; )
; )
; )
; )
)
)
)
)