mirror of
https://github.com/open-goal/jak-project.git
synced 2024-11-23 06:09:57 +00:00
[custom levels] A few bug fixes (#3736)
Some checks failed
Build / 🖥️ Windows (push) Waiting to run
Build / 🐧 Linux (push) Waiting to run
Build / 🍎 MacOS (push) Waiting to run
Lint / 📝 Formatting (push) Waiting to run
Lint / 📝 Required Checks (push) Waiting to run
Lint / 📝 Optional Checks (push) Waiting to run
Update Controller Database / update-controller-db (push) Has been cancelled
Some checks failed
Build / 🖥️ Windows (push) Waiting to run
Build / 🐧 Linux (push) Waiting to run
Build / 🍎 MacOS (push) Waiting to run
Lint / 📝 Formatting (push) Waiting to run
Lint / 📝 Required Checks (push) Waiting to run
Lint / 📝 Optional Checks (push) Waiting to run
Update Controller Database / update-controller-db (push) Has been cancelled
- Bug fix to KD tree splitting, should fix cases with bad vertex colors/alphas. - Normalize normals instead of asserting if they are the wrong length. **the fact that blender exports normals incorrectly is a bug and I doubt their implementation is correct if you've scaled things on only on axis.** - Automatically resize metallic texture (envmap strength) if it doesn't match the size of the rgb texture instead of asserting Co-authored-by: water111 <awaterford1111445@gmail.com>
This commit is contained in:
parent
1962fbfb51
commit
dff9ac163a
@ -95,6 +95,7 @@ add_library(common
|
||||
util/Timer.cpp
|
||||
util/unicode_util.cpp
|
||||
util/gltf_util.cpp
|
||||
util/image_resize.cpp
|
||||
versions/versions.cpp
|
||||
)
|
||||
|
||||
|
@ -323,7 +323,8 @@ ExtractedVertices gltf_vertices(const tinygltf::Model& model,
|
||||
normals = extract_vec3f(data_ptr, count, byte_stride);
|
||||
for (auto& nrm : normals) {
|
||||
math::Vector4f nrm4(nrm.x(), nrm.y(), nrm.z(), 0.f);
|
||||
nrm = (w_T_local * nrm4).xyz();
|
||||
// we found that normals aren't normalized if an object is scaled in blender.
|
||||
nrm = (w_T_local * nrm4).xyz().normalized();
|
||||
}
|
||||
ASSERT(normals.size() == result.size());
|
||||
} else {
|
||||
|
101
common/util/image_resize.cpp
Normal file
101
common/util/image_resize.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
#include "image_resize.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
#include "common/math/Vector.h"
|
||||
|
||||
namespace {
|
||||
struct BilinearSample {
|
||||
int i0, i1;
|
||||
double w0, w1;
|
||||
};
|
||||
|
||||
BilinearSample bilinear(int src_i, double sample, bool wrap) {
|
||||
BilinearSample result;
|
||||
|
||||
const double px_size = 1. / double(src_i);
|
||||
const double px_center_f = (sample - 0.5 * px_size) / px_size;
|
||||
const int px_floor = std::floor(px_center_f);
|
||||
const double frac = px_center_f - double(px_floor);
|
||||
|
||||
if (px_center_f < 0) { // off the bottom
|
||||
if (wrap) {
|
||||
// wrap around!
|
||||
result.i0 = 0;
|
||||
result.i1 = src_i - 1;
|
||||
result.w1 = -px_center_f;
|
||||
result.w0 = 1. - result.w1;
|
||||
} else {
|
||||
// clamp to edge
|
||||
result.i0 = 0;
|
||||
result.i1 = 0;
|
||||
result.w0 = 1;
|
||||
result.w1 = 0;
|
||||
}
|
||||
} else if (px_floor >= (src_i - 1)) { // off the top
|
||||
if (wrap) {
|
||||
result.i0 = src_i - 1;
|
||||
result.i1 = 0;
|
||||
result.w0 = 1. - frac;
|
||||
result.w1 = frac;
|
||||
} else {
|
||||
// clamp
|
||||
result.i0 = src_i - 1;
|
||||
result.i1 = src_i - 1;
|
||||
result.w0 = 1;
|
||||
result.w1 = 0;
|
||||
}
|
||||
} else {
|
||||
result.i0 = px_floor;
|
||||
result.i1 = px_floor + 1;
|
||||
result.w0 = 1. - frac;
|
||||
result.w1 = frac;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
math::Vector4<u8> sample1(const u8* src, int w, int h, int x, int y) {
|
||||
(void)h;
|
||||
int offset = 4 * (y * w + x);
|
||||
return math::Vector4<u8>(src[offset], src[offset + 1], src[offset + 2], src[offset + 3]);
|
||||
}
|
||||
|
||||
math::Vector4<u8> sample_bilinear(const u8* src,
|
||||
int w,
|
||||
int h,
|
||||
const BilinearSample& x,
|
||||
const BilinearSample& y) {
|
||||
auto p00 = sample1(src, w, h, x.i0, y.i0).cast<double>();
|
||||
auto p01 = sample1(src, w, h, x.i0, y.i1).cast<double>();
|
||||
auto p10 = sample1(src, w, h, x.i1, y.i0).cast<double>();
|
||||
auto p11 = sample1(src, w, h, x.i1, y.i1).cast<double>();
|
||||
auto p_interp = (p00 * x.w0 * y.w0 + p01 * x.w0 * y.w1 + p10 * x.w1 * y.w0 + p11 * x.w1 * y.w1);
|
||||
return p_interp.cast<u8>();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void resize_rgba_image(u8* dst,
|
||||
int dst_w,
|
||||
int dst_h,
|
||||
const u8* src,
|
||||
int src_w,
|
||||
int src_h,
|
||||
bool wrap_w,
|
||||
bool wrap_h) {
|
||||
const double dst_px_h = 1. / dst_h;
|
||||
const double dst_px_w = 1. / dst_w;
|
||||
for (int h = 0; h < dst_h; h++) {
|
||||
const float h_pos = (double(h) + 0.5) * dst_px_h;
|
||||
const auto h_sample = bilinear(src_h, h_pos, wrap_h);
|
||||
for (int w = 0; w < dst_w; w++) {
|
||||
const float w_pos = (double(w) + 0.5) * dst_px_w;
|
||||
const auto w_sample = bilinear(src_w, w_pos, wrap_w);
|
||||
auto result = sample_bilinear(src, src_w, src_h, w_sample, h_sample);
|
||||
for (int i = 0; i < 4; i++) {
|
||||
*dst = result[i];
|
||||
dst++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
12
common/util/image_resize.h
Normal file
12
common/util/image_resize.h
Normal file
@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
void resize_rgba_image(u8* dst,
|
||||
int dst_w,
|
||||
int dst_h,
|
||||
const u8* src,
|
||||
int src_w,
|
||||
int src_h,
|
||||
bool wrap_w,
|
||||
bool wrap_h);
|
@ -237,6 +237,24 @@ void split_kd(KdNode* in, u32 depth, int next_split_dim) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!in->colors.empty()) {
|
||||
for (int i = 0; i < 4; i++) {
|
||||
bool all_same = true;
|
||||
u8 same = in->colors[0][next_split_dim];
|
||||
for (auto& color : in->colors) {
|
||||
if (color[next_split_dim] != same) {
|
||||
all_same = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (all_same) {
|
||||
next_split_dim = (next_split_dim + 1) % 4;
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// sort by split dimension
|
||||
std::stable_sort(in->colors.begin(), in->colors.end(), [=](const Color& a, const Color& b) {
|
||||
return a[next_split_dim] < b[next_split_dim];
|
||||
@ -248,11 +266,12 @@ void split_kd(KdNode* in, u32 depth, int next_split_dim) {
|
||||
size_t i = 0;
|
||||
size_t mid = in->colors.size() / 2;
|
||||
if (depth & 1) {
|
||||
while (mid > 1 && in->colors[mid] == in->colors[mid - 1]) {
|
||||
while (mid > 1 && in->colors[mid][next_split_dim] == in->colors[mid - 1][next_split_dim]) {
|
||||
mid--;
|
||||
}
|
||||
} else {
|
||||
while (mid + 2 < in->colors.size() && in->colors[mid] == in->colors[mid + 1]) {
|
||||
while (mid + 2 < in->colors.size() &&
|
||||
in->colors[mid][next_split_dim] == in->colors[mid + 1][next_split_dim]) {
|
||||
mid++;
|
||||
}
|
||||
}
|
||||
|
@ -12,6 +12,7 @@
|
||||
#include "common/math/geometry.h"
|
||||
#include "common/util/Timer.h"
|
||||
#include "common/util/gltf_util.h"
|
||||
#include <common/util/image_resize.h>
|
||||
|
||||
using namespace gltf_util;
|
||||
namespace gltf_mesh_extract {
|
||||
@ -262,7 +263,9 @@ void add_to_packed_verts(std::vector<tfrag3::PackedTieVertices::Vertex>* out,
|
||||
int texture_pool_add_envmap_control_texture(TexturePool* pool,
|
||||
const tinygltf::Model& model,
|
||||
int rgb_image_id,
|
||||
int mr_image_id) {
|
||||
int mr_image_id,
|
||||
bool wrap_w,
|
||||
bool wrap_h) {
|
||||
const auto& existing = pool->envmap_textures_by_gltf_id.find({rgb_image_id, mr_image_id});
|
||||
if (existing != pool->envmap_textures_by_gltf_id.end()) {
|
||||
lg::info("Reusing envmap textures");
|
||||
@ -279,8 +282,16 @@ int texture_pool_add_envmap_control_texture(TexturePool* pool,
|
||||
ASSERT(mr_tex.pixel_type == TINYGLTF_TEXTURE_TYPE_UNSIGNED_BYTE);
|
||||
ASSERT(mr_tex.component == 4);
|
||||
|
||||
ASSERT(rgb_tex.width == mr_tex.width);
|
||||
ASSERT(rgb_tex.height == mr_tex.height);
|
||||
std::vector<u8> resized_mr_tex;
|
||||
const u8* mr_src;
|
||||
if (rgb_tex.width == mr_tex.width && rgb_tex.height == mr_tex.height) {
|
||||
mr_src = mr_tex.image.data();
|
||||
} else {
|
||||
resized_mr_tex.resize(rgb_tex.width * rgb_tex.height * 4);
|
||||
resize_rgba_image(resized_mr_tex.data(), rgb_tex.width, rgb_tex.height, mr_tex.image.data(),
|
||||
mr_tex.width, mr_tex.height, wrap_w, wrap_h);
|
||||
mr_src = resized_mr_tex.data();
|
||||
}
|
||||
|
||||
size_t idx = pool->textures_by_idx.size();
|
||||
pool->envmap_textures_by_gltf_id[{rgb_image_id, mr_image_id}] = idx;
|
||||
@ -298,7 +309,7 @@ int texture_pool_add_envmap_control_texture(TexturePool* pool,
|
||||
// adjust alpha from metallic channel
|
||||
for (size_t i = 0; i < tt.data.size(); i++) {
|
||||
u32 rgb = tt.data[i];
|
||||
u32 metal = mr_tex.image[4 * i + 2] / 4;
|
||||
u32 metal = mr_src[4 * i + 2] / 4;
|
||||
rgb &= 0xff'ff'ff;
|
||||
rgb |= (metal << 24);
|
||||
tt.data[i] = rgb;
|
||||
@ -404,8 +415,9 @@ void extract(const Input& in,
|
||||
ASSERT(roughness_tex.source >= 0);
|
||||
|
||||
// draw.tree_tex_id = texture_pool_add_texture(in.tex_pool, model.images[base_tex.source]);
|
||||
draw.tree_tex_id = texture_pool_add_envmap_control_texture(in.tex_pool, model, base_tex.source,
|
||||
roughness_tex.source);
|
||||
draw.tree_tex_id = texture_pool_add_envmap_control_texture(
|
||||
in.tex_pool, model, base_tex.source, roughness_tex.source, !draw.mode.get_clamp_s_enable(),
|
||||
!draw.mode.get_clamp_t_enable());
|
||||
out.base_draws.push_back(draw);
|
||||
|
||||
// now, setup envmap draw:
|
||||
|
@ -39,6 +39,9 @@ add_executable(goalc-test
|
||||
|
||||
target_link_libraries(goalc-test common runtime compiler gtest decomp Zydis libzstd_static tree-sitter)
|
||||
|
||||
add_executable(test_image_resize ${CMAKE_CURRENT_LIST_DIR}/common/test_image_resize.cpp)
|
||||
target_link_libraries(test_image_resize common)
|
||||
|
||||
if(WIN32)
|
||||
target_link_libraries(goalc-test mman)
|
||||
endif()
|
||||
|
37
test/common/test_image_resize.cpp
Normal file
37
test/common/test_image_resize.cpp
Normal file
@ -0,0 +1,37 @@
|
||||
#include <cstdio>
|
||||
#include <vector>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "common/util/FileUtil.h"
|
||||
#include "common/util/Timer.h"
|
||||
#include "common/util/image_resize.h"
|
||||
|
||||
int main() {
|
||||
int src_h = 30;
|
||||
int src_w = 30;
|
||||
int check_divide = 3;
|
||||
int dst_sz = 300;
|
||||
|
||||
std::vector<u8> src;
|
||||
for (int h = 0; h < src_h; h++) {
|
||||
for (int w = 0; w < src_w; w++) {
|
||||
u8 color = (((h / check_divide) & 1) ^ ((w / check_divide) & 1)) ? 0x10 : 0xd0;
|
||||
src.push_back(color);
|
||||
src.push_back(color);
|
||||
src.push_back(color);
|
||||
src.push_back(255);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<u8> dst(dst_sz * dst_sz * 4);
|
||||
Timer timer;
|
||||
resize_rgba_image(dst.data(), dst_sz, dst_sz, src.data(), src_w, src_h, true, true);
|
||||
printf("resized in %.3f ms\n", timer.getMs());
|
||||
file_util::write_rgba_png("test_wrap.png", dst.data(), dst_sz, dst_sz);
|
||||
resize_rgba_image(dst.data(), dst_sz, dst_sz, src.data(), src_w, src_h, false, false);
|
||||
printf("resized in %.3f ms\n", timer.getMs());
|
||||
file_util::write_rgba_png("test_unwrap.png", dst.data(), dst_sz, dst_sz);
|
||||
file_util::write_rgba_png("src.png", src.data(), src_w, src_h);
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in New Issue
Block a user