diff --git a/custom_levels/test-zone/test-zone.jsonc b/custom_levels/test-zone/test-zone.jsonc index db2e1dd05f..4a6fb08661 100644 --- a/custom_levels/test-zone/test-zone.jsonc +++ b/custom_levels/test-zone/test-zone.jsonc @@ -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 diff --git a/goalc/CMakeLists.txt b/goalc/CMakeLists.txt index c113fbc87d..2c61857bf1 100644 --- a/goalc/CMakeLists.txt +++ b/goalc/CMakeLists.txt @@ -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 diff --git a/goalc/build_level/Entity.cpp b/goalc/build_level/Entity.cpp index afd10ad445..0b32e4e5f6 100644 --- a/goalc/build_level/Entity.cpp +++ b/goalc/build_level/Entity.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& actors) { std::vector 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& ambients) { + std::vector 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_from_json_array(const std::string& name, } } // namespace +void add_ambients_from_json(const nlohmann::json& json, + std::vector& 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(); + if (value_string.size() > 0 && value_string[0] == '\'') { + ambient.res_lump.add_res( + std::make_unique(key, value_string.substr(1), -1000000000.0000)); + } else { + ambient.res_lump.add_res( + std::make_unique(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& actor_list, u32 base_aid) { diff --git a/goalc/build_level/Entity.h b/goalc/build_level/Entity.h index ea84dc5322..15df5a2631 100644 --- a/goalc/build_level/Entity.h +++ b/goalc/build_level/Entity.h @@ -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& actors); +size_t generate_inline_array_ambients(DataObjectGenerator& gen, + const std::vector& ambients); +void add_ambients_from_json(const nlohmann::json& json, + std::vector& ambient_list, + u32 base_aid); + void add_actors_from_json(const nlohmann::json& json, std::vector& actor_list, u32 base_aid); \ No newline at end of file diff --git a/goalc/build_level/LevelFile.cpp b/goalc/build_level/LevelFile.cpp index 4195fb4718..c87346694b 100644 --- a/goalc/build_level/LevelFile.cpp +++ b/goalc/build_level/LevelFile.cpp @@ -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 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 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) diff --git a/goalc/build_level/LevelFile.h b/goalc/build_level/LevelFile.h index 312b9a17e3..8fba983d82 100644 --- a/goalc/build_level/LevelFile.h +++ b/goalc/build_level/LevelFile.h @@ -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 bytes; @@ -22,8 +23,6 @@ struct DrawableTreeInstanceTie {}; struct DrawableTreeActor {}; -struct DrawableTreeAmbient {}; - struct DrawableTreeInstanceShrub {}; struct DrawableTreeArray { @@ -33,7 +32,9 @@ struct DrawableTreeArray { std::vector collides; std::vector ambients; std::vector 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 ambients; +}; struct AdgifShaderArray {}; @@ -115,7 +116,7 @@ struct LevelFile { // zero // (ambients drawable-inline-array-ambient :offset-assert 156) - DrawableInlineArrayAmbient ambients; + std::vector ambients; // (unk-data-4 float :offset-assert 160) float close_subdiv = 0; diff --git a/goalc/build_level/build_level.cpp b/goalc/build_level/build_level.cpp index bb5f7e6a6f..6475215333 100644 --- a/goalc/build_level/build_level.cpp +++ b/goalc/build_level/build_level.cpp @@ -72,6 +72,11 @@ bool run_build_level(const std::string& input_file, std::vector actors; add_actors_from_json(level_json.at("actors"), actors, level_json.value("base_id", 1234)); file.actors = std::move(actors); + // ambients + std::vector 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 diff --git a/goalc/build_level/drawable_ambient.cpp b/goalc/build_level/drawable_ambient.cpp new file mode 100644 index 0000000000..a89dc38a44 --- /dev/null +++ b/goalc/build_level/drawable_ambient.cpp @@ -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; +} \ No newline at end of file diff --git a/goalc/build_level/drawable_ambient.h b/goalc/build_level/drawable_ambient.h new file mode 100644 index 0000000000..a83c328ee3 --- /dev/null +++ b/goalc/build_level/drawable_ambient.h @@ -0,0 +1,17 @@ +#pragma once + +#include + +#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; +}; \ No newline at end of file