mirror of
https://github.com/open-goal/jak-project
synced 2026-08-21 23:00:45 -04:00
custom levels: add initial support for ambients (#2173)
This commit is contained in:
@@ -33,7 +33,9 @@
|
||||
|
||||
// The base actor id for your custom level. If you have multiple levels this should be unique!
|
||||
"base_id": 100,
|
||||
|
||||
|
||||
"ambients": [],
|
||||
|
||||
"actors" : [
|
||||
{
|
||||
"trans": [-21.6238, 20.0496, 17.1191], // translation
|
||||
|
||||
@@ -16,6 +16,7 @@ add_library(compiler
|
||||
build_level/LevelFile.cpp
|
||||
build_level/ResLump.cpp
|
||||
build_level/Tfrag.cpp
|
||||
build_level/drawable_ambient.cpp
|
||||
compiler/Compiler.cpp
|
||||
compiler/Env.cpp
|
||||
compiler/Val.cpp
|
||||
|
||||
@@ -30,6 +30,18 @@ size_t EntityActor::generate(DataObjectGenerator& gen) const {
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t EntityAmbient::generate(DataObjectGenerator& gen) const {
|
||||
size_t result = res_lump.generate_header(gen, "entity-ambient");
|
||||
for (size_t i = 0; i < 4; i++) {
|
||||
gen.add_word_float(trans[i]);
|
||||
}
|
||||
ASSERT(vis_id < UINT16_MAX);
|
||||
gen.add_word(aid);
|
||||
gen.add_word(vis_id);
|
||||
res_lump.generate_tag_list_and_data(gen, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t generate_drawable_actor(DataObjectGenerator& gen,
|
||||
const EntityActor& actor,
|
||||
size_t actor_loc) {
|
||||
@@ -46,6 +58,21 @@ size_t generate_drawable_actor(DataObjectGenerator& gen,
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t generate_drawable_ambient(DataObjectGenerator& gen,
|
||||
const EntityAmbient& ambient,
|
||||
size_t ambient_loc) {
|
||||
gen.align_to_basic();
|
||||
gen.add_type_tag("drawable-ambient"); // 0
|
||||
size_t result = gen.current_offset_bytes();
|
||||
gen.add_word(ambient.vis_id); // 4
|
||||
gen.link_word_to_byte(gen.add_word(0), ambient_loc); // 8
|
||||
gen.add_word(0); // 12
|
||||
for (int i = 0; i < 4; i++) {
|
||||
gen.add_word_float(ambient.bsphere[i]); // 16, 20, 24, 28
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t generate_inline_array_actors(DataObjectGenerator& gen,
|
||||
const std::vector<EntityActor>& actors) {
|
||||
std::vector<size_t> actor_locs;
|
||||
@@ -74,6 +101,30 @@ size_t generate_inline_array_actors(DataObjectGenerator& gen,
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t generate_inline_array_ambients(DataObjectGenerator& gen,
|
||||
const std::vector<EntityAmbient>& ambients) {
|
||||
std::vector<size_t> ambient_locs;
|
||||
for (auto& ambient : ambients) {
|
||||
ambient_locs.push_back(ambient.generate(gen));
|
||||
}
|
||||
gen.align_to_basic();
|
||||
gen.add_type_tag("drawable-inline-array-ambient"); // 0
|
||||
size_t result = gen.current_offset_bytes();
|
||||
ASSERT(ambients.size() < UINT16_MAX);
|
||||
gen.add_word(ambients.size() << 16); // 4
|
||||
gen.add_word(0);
|
||||
gen.add_word(0);
|
||||
gen.add_word(0);
|
||||
gen.add_word(0);
|
||||
gen.add_word(0);
|
||||
gen.add_word(0);
|
||||
ASSERT((gen.current_offset_bytes() % 16) == 0);
|
||||
for (size_t i = 0; i < ambients.size(); i++) {
|
||||
generate_drawable_ambient(gen, ambients[i], ambient_locs[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
namespace {
|
||||
math::Vector4f vectorm3_from_json(const nlohmann::json& json) {
|
||||
ASSERT(json.size() == 3);
|
||||
@@ -143,6 +194,36 @@ std::unique_ptr<Res> res_from_json_array(const std::string& name,
|
||||
}
|
||||
} // namespace
|
||||
|
||||
void add_ambients_from_json(const nlohmann::json& json,
|
||||
std::vector<EntityAmbient>& ambient_list,
|
||||
u32 base_aid) {
|
||||
for (const auto& ambient_json : json) {
|
||||
auto& ambient = ambient_list.emplace_back();
|
||||
ambient.aid = ambient_json.value("aid", base_aid + ambient_list.size());
|
||||
ambient.trans = vectorm4_from_json(ambient_json.at("trans"));
|
||||
ambient.bsphere = vectorm4_from_json(ambient_json.at("bsphere"));
|
||||
if (ambient_json.find("lump") != ambient_json.end()) {
|
||||
for (auto [key, value] : ambient_json.at("lump").items()) {
|
||||
if (value.is_string()) {
|
||||
std::string value_string = value.get<std::string>();
|
||||
if (value_string.size() > 0 && value_string[0] == '\'') {
|
||||
ambient.res_lump.add_res(
|
||||
std::make_unique<ResSymbol>(key, value_string.substr(1), -1000000000.0000));
|
||||
} else {
|
||||
ambient.res_lump.add_res(
|
||||
std::make_unique<ResString>(key, value_string, -1000000000.0000));
|
||||
}
|
||||
continue;
|
||||
}
|
||||
if (value.is_array()) {
|
||||
ambient.res_lump.add_res(res_from_json_array(key, value));
|
||||
}
|
||||
}
|
||||
}
|
||||
ambient.res_lump.sort_res();
|
||||
}
|
||||
}
|
||||
|
||||
void add_actors_from_json(const nlohmann::json& json,
|
||||
std::vector<EntityActor>& actor_list,
|
||||
u32 base_aid) {
|
||||
|
||||
@@ -28,9 +28,24 @@ struct EntityActor {
|
||||
size_t generate(DataObjectGenerator& gen) const;
|
||||
};
|
||||
|
||||
struct EntityAmbient {
|
||||
ResLump res_lump;
|
||||
u32 aid = 0;
|
||||
math::Vector4f trans;
|
||||
u32 vis_id = 0;
|
||||
math::Vector4f bsphere;
|
||||
size_t generate(DataObjectGenerator& gen) const;
|
||||
};
|
||||
|
||||
size_t generate_inline_array_actors(DataObjectGenerator& gen,
|
||||
const std::vector<EntityActor>& actors);
|
||||
|
||||
size_t generate_inline_array_ambients(DataObjectGenerator& gen,
|
||||
const std::vector<EntityAmbient>& ambients);
|
||||
void add_ambients_from_json(const nlohmann::json& json,
|
||||
std::vector<EntityAmbient>& ambient_list,
|
||||
u32 base_aid);
|
||||
|
||||
void add_actors_from_json(const nlohmann::json& json,
|
||||
std::vector<EntityActor>& actor_list,
|
||||
u32 base_aid);
|
||||
@@ -2,7 +2,10 @@
|
||||
|
||||
#include "goalc/data_compiler/DataObjectGenerator.h"
|
||||
|
||||
size_t DrawableTreeArray::add_to_object_file(DataObjectGenerator& gen) const {
|
||||
// TODO find better way to pass the ambient array
|
||||
size_t DrawableTreeArray::add_to_object_file(DataObjectGenerator& gen,
|
||||
size_t ambient_count,
|
||||
size_t ambient_arr_slot) const {
|
||||
/*
|
||||
(deftype drawable-tree-array (drawable-group)
|
||||
((trees drawable-tree 1 :offset 32 :score 100))
|
||||
@@ -24,6 +27,7 @@ size_t DrawableTreeArray::add_to_object_file(DataObjectGenerator& gen) const {
|
||||
int num_trees = 0;
|
||||
num_trees += tfrags.size();
|
||||
num_trees += collides.size();
|
||||
num_trees += ambients.size();
|
||||
gen.add_word(num_trees << 16);
|
||||
gen.add_word(0);
|
||||
gen.add_word(0);
|
||||
@@ -51,6 +55,11 @@ size_t DrawableTreeArray::add_to_object_file(DataObjectGenerator& gen) const {
|
||||
for (auto& collide : collides) {
|
||||
gen.link_word_to_byte(tree_word++, collide.add_to_object_file(gen));
|
||||
}
|
||||
|
||||
for (auto& ambients : ambients) {
|
||||
gen.link_word_to_byte(tree_word++,
|
||||
ambients.add_to_object_file(gen, ambient_count, ambient_arr_slot));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
@@ -78,11 +87,14 @@ std::vector<u8> LevelFile::save_object_file() const {
|
||||
auto file_info_slot = info.add_to_object_file(gen);
|
||||
gen.link_word_to_byte(1, file_info_slot);
|
||||
|
||||
auto ambient_arr_slot = generate_inline_array_ambients(gen, ambients);
|
||||
|
||||
//(bsphere vector :inline :offset-assert 16)
|
||||
//(all-visible-list (pointer uint16) :offset-assert 32)
|
||||
//(visible-list-length int32 :offset-assert 36)
|
||||
//(drawable-trees drawable-tree-array :offset-assert 40)
|
||||
gen.link_word_to_byte(40 / 4, drawable_trees.add_to_object_file(gen));
|
||||
gen.link_word_to_byte(40 / 4,
|
||||
drawable_trees.add_to_object_file(gen, ambients.size(), ambient_arr_slot));
|
||||
//(pat pointer :offset-assert 44)
|
||||
//(pat-length int32 :offset-assert 48)
|
||||
//(texture-remap-table (pointer uint64) :offset-assert 52)
|
||||
@@ -105,6 +117,7 @@ std::vector<u8> LevelFile::save_object_file() const {
|
||||
//(boxes box8s-array :offset-assert 148)
|
||||
//(current-bsp-back-flags uint32 :offset-assert 152)
|
||||
//(ambients drawable-inline-array-ambient :offset-assert 156)
|
||||
gen.link_word_to_byte(156 / 4, ambient_arr_slot);
|
||||
//(unk-data-4 float :offset-assert 160)
|
||||
//(unk-data-5 float :offset-assert 164)
|
||||
//(adgifs adgif-shader-array :offset-assert 168)
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
#include "goalc/build_level/collide_common.h"
|
||||
#include "goalc/build_level/collide_drawable.h"
|
||||
#include "goalc/build_level/collide_pack.h"
|
||||
#include "goalc/build_level/drawable_ambient.h"
|
||||
|
||||
struct VisibilityString {
|
||||
std::vector<u8> bytes;
|
||||
@@ -22,8 +23,6 @@ struct DrawableTreeInstanceTie {};
|
||||
|
||||
struct DrawableTreeActor {};
|
||||
|
||||
struct DrawableTreeAmbient {};
|
||||
|
||||
struct DrawableTreeInstanceShrub {};
|
||||
|
||||
struct DrawableTreeArray {
|
||||
@@ -33,7 +32,9 @@ struct DrawableTreeArray {
|
||||
std::vector<DrawableTreeCollideFragment> collides;
|
||||
std::vector<DrawableTreeAmbient> ambients;
|
||||
std::vector<DrawableTreeInstanceShrub> shrubs;
|
||||
size_t add_to_object_file(DataObjectGenerator& gen) const;
|
||||
size_t add_to_object_file(DataObjectGenerator& gen,
|
||||
size_t ambient_count,
|
||||
size_t ambient_arr_slot) const;
|
||||
};
|
||||
|
||||
struct TextureRemap {};
|
||||
@@ -48,9 +49,9 @@ struct BspNode {};
|
||||
|
||||
struct Box8s {};
|
||||
|
||||
struct DrawableAmbient {};
|
||||
|
||||
struct DrawableInlineArrayAmbient {};
|
||||
struct DrawableInlineArrayAmbient {
|
||||
std::vector<EntityAmbient> ambients;
|
||||
};
|
||||
|
||||
struct AdgifShaderArray {};
|
||||
|
||||
@@ -115,7 +116,7 @@ struct LevelFile {
|
||||
// zero
|
||||
|
||||
// (ambients drawable-inline-array-ambient :offset-assert 156)
|
||||
DrawableInlineArrayAmbient ambients;
|
||||
std::vector<EntityAmbient> ambients;
|
||||
|
||||
// (unk-data-4 float :offset-assert 160)
|
||||
float close_subdiv = 0;
|
||||
|
||||
@@ -72,6 +72,11 @@ bool run_build_level(const std::string& input_file,
|
||||
std::vector<EntityActor> actors;
|
||||
add_actors_from_json(level_json.at("actors"), actors, level_json.value("base_id", 1234));
|
||||
file.actors = std::move(actors);
|
||||
// ambients
|
||||
std::vector<EntityAmbient> ambients;
|
||||
add_ambients_from_json(level_json.at("ambients"), ambients, level_json.value("base_id", 12345));
|
||||
file.ambients = std::move(ambients);
|
||||
auto& ambient_drawable_tree = file.drawable_trees.ambients.emplace_back();
|
||||
// cameras
|
||||
// nodes
|
||||
// boxes
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
#include "drawable_ambient.h"
|
||||
|
||||
#include "goalc/data_compiler/DataObjectGenerator.h"
|
||||
/*
|
||||
(deftype drawable-group (drawable)
|
||||
((length int16 :offset 6)
|
||||
(data drawable 1 :offset-assert 32)
|
||||
)
|
||||
(:methods
|
||||
(new (symbol type int) _type_)
|
||||
)
|
||||
:flag-assert #x1200000024
|
||||
)
|
||||
(deftype drawable-tree (drawable-group)
|
||||
()
|
||||
:flag-assert #x1200000024
|
||||
)
|
||||
(deftype drawable-inline-array (drawable)
|
||||
((length int16 :offset 6) ;; this is kinda weird.
|
||||
)
|
||||
:method-count-assert 18
|
||||
:size-assert #x20
|
||||
:flag-assert #x1200000020
|
||||
)
|
||||
*/
|
||||
size_t DrawableTreeAmbient::add_to_object_file(DataObjectGenerator& gen,
|
||||
size_t ambient_count,
|
||||
size_t ambient_arr_slot) const {
|
||||
gen.align_to_basic();
|
||||
gen.add_type_tag("drawable-tree-ambient");
|
||||
size_t result = gen.current_offset_bytes();
|
||||
gen.add_word(ambient_count << 16); // 4, 6
|
||||
gen.add_word(0); // 8
|
||||
gen.add_word(0); // 12
|
||||
gen.add_word(0); // 16
|
||||
gen.add_word(0); // 20
|
||||
gen.add_word(0); // 24
|
||||
gen.add_word(0); // 28
|
||||
gen.link_word_to_byte(gen.add_word(0), ambient_arr_slot);
|
||||
return result;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "goalc/build_level/Entity.h"
|
||||
|
||||
class DataObjectGenerator;
|
||||
|
||||
struct DrawableAmbient {
|
||||
EntityAmbient ambient;
|
||||
};
|
||||
|
||||
struct DrawableTreeAmbient {
|
||||
size_t add_to_object_file(DataObjectGenerator& gen,
|
||||
size_t ambient_count,
|
||||
size_t ambient_arr_slot) const;
|
||||
};
|
||||
Reference in New Issue
Block a user