/* by korenkonder GitHub/GitLab: korenkonder */ #include "disp_manager.hpp" #include "../../KKdLib/hash.hpp" #include "../../AFTModsShared/camera.hpp" #include "../../AFTModsShared/uniform.hpp" #include "../Glitter/glitter.hpp" #include "../rob/rob.hpp" #include "../gl_rend_state.hpp" #include "../gl_state.hpp" #include "../object.hpp" #include "../render_manager.hpp" #include "../shader_ft.hpp" #include "../sprite.hpp" #include "../stage.hpp" #include "../wrap.hpp" #include "draw_object.hpp" #include mdl::DispManager* disp_manager = (mdl::DispManager*)0x00000001411A27F0; static mat4* matrix_buffer = (mat4*)0x000000014CC587D0; static BOOL* matrix_buffer_init = (BOOL*)0x000000014CC5D7D0; static const GLuint POSITION_INDEX = 0; static const GLuint BONE_WEIGHT_INDEX = 1; static const GLuint NORMAL_INDEX = 2; static const GLuint COLOR0_INDEX = 3; static const GLuint COLOR1_INDEX = 4; static const GLuint MORPH_COLOR_INDEX = 5; static const GLuint TANGENT_INDEX = 6; static const GLuint UNKNOWN_INDEX = 7; static const GLuint TEXCOORD0_INDEX = 8; static const GLuint TEXCOORD1_INDEX = 9; static const GLuint MORPH_POSITION_INDEX = 10; static const GLuint MORPH_NORMAL_INDEX = 11; static const GLuint MORPH_TANGENT_INDEX = 12; static const GLuint MORPH_TEXCOORD0_INDEX = 13; static const GLuint MORPH_TEXCOORD1_INDEX = 14; static const GLuint BONE_INDEX_INDEX = 15; static void object_data_get_vertex_attrib_buffer_bindings(const mdl::ObjSubMeshArgs* args, int32_t texcoord_array[2], GLuint vertex_attrib_buffer_binding[16]); static void rob_chara_item_cos_data_disp_item(rob_chara_item_cos_data* item_cos_data, const mat4& mat, int32_t item_no); static void rob_chara_item_cos_data_disp_item_object(rob_chara_item_cos_data* item_cos_data, object_info obj_info, const mat4& mat, int32_t item_no); static void rob_chara_item_cos_data_set_chara_index(rob_chara_item_cos_data* item_cos_data, ::chara_index chara_index); static void sub_140436760(const cam_data& cam); extern bool reflect_draw; extern mat4 reflect_mat; material_list_struct::material_list_struct() : blend_color(), has_blend_color(), emission(), has_emission() { hash = (uint64_t)-1; } material_list_struct::material_list_struct(uint64_t hash, vec4& blend_color, vec4u8& has_blend_color, vec4& emission, vec4u8& has_emission) : hash(hash), blend_color(blend_color), has_blend_color(has_blend_color), emission(emission), has_emission(has_emission) { } namespace mdl { prj::vector vertex_array_cache; prj::vector etc_vertex_array_cache; int32_t material_list_count; material_list_struct material_list_array[MATERIAL_LIST_COUNT]; bool obj_reflect_enable; ObjSubMeshArgs::ObjSubMeshArgs() : sub_mesh(), mesh(), material(), textures(), mat_count(), mats(), vertex_buffer(), vertex_buffer_offset(), index_buffer(), set_blend_color(), chara_color(), self_shadow(), shadow(), morph_vertex_buffer(), morph_vertex_buffer_offset(), morph_weight(), texture_pattern_count(), texture_transform_count(), field_7C4(), field_7C8(), instances_count(), instances_mat(), func(), func_data() { } EtcObjTeapot::EtcObjTeapot() { size = 1.0f; } EtcObjGrid::EtcObjGrid() { w = 10; h = 10; ws = 20; hs = 20; } EtcObjCube::EtcObjCube() : wire() { } EtcObjSphere::EtcObjSphere() : wire() { radius = 1.0f; slices = 8; stacks = 8; } EtcObjPlane::EtcObjPlane() { w = 10; h = 10; } EtcObjCone::EtcObjCone() : wire() { base = 1.0f; height = 1.0f; slices = 8; stacks = 8; } EtcObjLine::EtcObjLine() { pos[0] = { 0.0f, 0.0f, 0.0f }; pos[1] = { 0.0f, 0.0f, 1.0f }; } EtcObjCross::EtcObjCross() { size = 0.1f; } EtcObjCapsule::EtcObjCapsule() : wire() { radius = 1.0f; slices = 8; stacks = 8; pos[0] = { 0.0f, 0.0f, 0.0f }; pos[1] = { 0.0f, 0.0f, 1.0f }; } EtcObjCylinder::EtcObjCylinder() : wire() { base = 1.0f; height = 1.0f; slices = 8; stacks = 8; } EtcObj::Data::Data() : line() { } EtcObj::EtcObj(EtcObjType type) : count(), offset() { this->type = type; color = 0xFFFFFFFF; fog = false; constant = false; switch (type) { case ETC_OBJ_TEAPOT: data.teapot = {}; break; case ETC_OBJ_GRID: data.grid = {}; break; case ETC_OBJ_CUBE: data.cube = {}; break; case ETC_OBJ_SPHERE: data.sphere = {}; break; case ETC_OBJ_PLANE: data.plane = {}; break; case ETC_OBJ_CONE: data.cone = {}; break; case ETC_OBJ_LINE: data.line = {}; break; case ETC_OBJ_CROSS: data.cross = {}; break; case ETC_OBJ_CAPSULE: // Added data.capsule = {}; break; case ETC_OBJ_CYLINDER: // Added data.cylinder = {}; } } EtcObj::~EtcObj() { } UserArgs::UserArgs() : func(), data(){ } ObjTranslucentArgs::ObjTranslucentArgs() : count(), sub_mesh() { } ObjData::Args::Args() : sub_mesh() { } ObjData::Args::~Args() { } ObjData::ObjData() : kind(), view_z(), radius() { } ObjData::~ObjData() { } void ObjData::init_etc(const mat4& mat, const mdl::EtcObj& etc) { kind = mdl::OBJ_KIND_ETC; mat4_transpose(&mat, &this->mat); args.etc = etc; disp_manager->add_vertex_array(&args.etc, this->mat); } void ObjData::init_sub_mesh(const mat4& mat, float_t radius, const obj_sub_mesh* sub_mesh, const obj_mesh* mesh, const obj_material_data* material, const prj::vector* textures, int32_t mat_count, const mat4* mats, GLuint vertex_buffer, size_t vertex_buffer_offset, GLuint index_buffer, const vec4& blend_color, const vec4& emission, GLuint morph_vertex_buffer, size_t morph_vertex_buffer_offset, int32_t instances_count, const mat4* instances_mat, draw_func func, const ObjSubMeshArgs* func_data) { kind = mdl::OBJ_KIND_NORMAL; mat4_transpose(&mat, &this->mat); this->radius = radius; mdl::ObjSubMeshArgs* args = &this->args.sub_mesh; args->mesh = mesh; args->morph_weight = disp_manager->morph.weight; args->material = material; args->sub_mesh = sub_mesh; args->textures = textures; args->mat_count = mat_count; args->mats = mats; args->vertex_buffer = vertex_buffer; args->vertex_buffer_offset = vertex_buffer_offset; args->index_buffer = index_buffer; args->morph_vertex_buffer = morph_vertex_buffer; args->morph_vertex_buffer_offset = morph_vertex_buffer_offset; args->texture_pattern_count = disp_manager->texture_pattern_count; for (int32_t i = 0; i < disp_manager->texture_pattern_count && i < TEXTURE_PATTERN_COUNT; i++) args->texture_pattern_array[i] = disp_manager->texture_pattern_array[i]; args->texture_transform_count = disp_manager->texture_transform_count; for (int32_t i = 0; i < disp_manager->texture_transform_count && i < TEXTURE_TRANSFORM_COUNT; i++) { args->texture_transform_array[i].id = disp_manager->texture_transform_array[i].id; mat4_transpose(&disp_manager->texture_transform_array[i].mat, &args->texture_transform_array[i].mat); } if (blend_color != 1.0f) { args->set_blend_color = true; args->blend_color = blend_color; } else { args->set_blend_color = false; args->blend_color = 1.0f; } args->emission = emission; args->chara_color = disp_manager->chara_color; args->self_shadow = !!(disp_manager->obj_flags & (mdl::OBJ_8 | mdl::OBJ_4)); args->shadow = disp_manager->shadow_type; args->texture_color_coefficients = disp_manager->texture_color_coefficients; args->texture_color_coefficients.w = disp_manager->wet_param; args->texture_color_offset = disp_manager->texture_color_offset; args->texture_specular_coefficients = disp_manager->texture_specular_coefficients; args->texture_specular_offset = disp_manager->texture_specular_offset; args->instances_count = instances_count; args->instances_mat = instances_mat; args->func = func; args->func_data = func_data; disp_manager->add_vertex_array(args); } void ObjData::init_translucent(const mat4& mat, const ObjTranslucentArgs& translucent) { kind = mdl::OBJ_KIND_TRANSLUCENT; mat4_transpose(&mat, &this->mat); args.translucent = translucent; } void ObjData::init_user(const mat4& mat, UserArgsFunc func, void* data) { kind = OBJ_KIND_USER; mat4_transpose(&mat, &this->mat); args.user.func = func; args.user.data = data; } void DispManager::vertex_array::reset_vertex_attrib() { alive_time = 0; vertex_buffer = 0; vertex_buffer_offset = 0; morph_vertex_buffer = 0; morph_vertex_buffer_offset = 0; gl_state.bind_vertex_array(vertex_array); for (int32_t i = 0; i < 16; i++) if (vertex_attrib_array[i]) { glDisableVertexAttribArray(i); vertex_attrib_array[i] = false; } gl_state.bind_array_buffer(0, true); gl_state.bind_element_array_buffer(0, true); gl_state.bind_vertex_array(0); } void DispManager::add_vertex_array(ObjSubMeshArgs* args) { const obj_mesh* mesh = args->mesh; const obj_sub_mesh* sub_mesh = args->sub_mesh; const obj_material_data* material = args->material; GLuint vertex_buffer = args->vertex_buffer; size_t vertex_buffer_offset = args->vertex_buffer_offset; GLuint morph_vertex_buffer = args->morph_vertex_buffer; size_t morph_vertex_buffer_offset = args->morph_vertex_buffer_offset; GLuint index_buffer = args->index_buffer; int32_t texcoord_array[2] = { -1, -1 }; int32_t color_tex_index = 0; for (const obj_material_texture_data& i : material->material.texdata) { if (i.tex_index == -1) continue; int32_t texcoord_index = obj_material_texture_type_get_texcoord_index( i.shader_info.m.tex_type, color_tex_index); if (texcoord_index < 0) continue; texcoord_array[texcoord_index] = sub_mesh->uv_index[&i - material->material.texdata]; if (i.shader_info.m.tex_type == OBJ_MATERIAL_TEXTURE_COLOR) color_tex_index++; } GLuint vertex_attrib_buffer_binding[16] = {}; object_data_get_vertex_attrib_buffer_bindings(args, texcoord_array, vertex_attrib_buffer_binding); uint32_t compression = mesh->attrib.m.compression; GLsizei size_vertex = (GLsizei)mesh->size_vertex; obj_vertex_format vertex_format = mesh->vertex_format; DispManager::vertex_array* vertex_array = 0; for (DispManager::vertex_array& i : vertex_array_cache) if (i.alive_time >= 0 && i.vertex_buffer == vertex_buffer && i.vertex_buffer_offset == vertex_buffer_offset && i.morph_vertex_buffer == morph_vertex_buffer && i.morph_vertex_buffer_offset == morph_vertex_buffer_offset && i.index_buffer == index_buffer && i.vertex_format == vertex_format && i.size_vertex == size_vertex && i.compression == compression && !memcmp(i.vertex_attrib_buffer_binding, vertex_attrib_buffer_binding, sizeof(vertex_attrib_buffer_binding)) && !memcmp(i.texcoord_array, texcoord_array, sizeof(texcoord_array))) if (i.vertex_array) { i.alive_time = 60; return; } else { vertex_array = &i; break; } if (!vertex_array) for (DispManager::vertex_array& i : vertex_array_cache) if (i.alive_time <= 0) { vertex_array = &i; break; } if (!vertex_array) { vertex_array_cache.push_back({}); vertex_array = &vertex_array_cache.back(); } bool new_vertex_array = false; if (!vertex_array->vertex_array) { glGenVertexArrays(1, &vertex_array->vertex_array); gl_state.bind_vertex_array(vertex_array->vertex_array); glVertexAttrib4f( POSITION_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f( BONE_WEIGHT_INDEX, 0.0f, 0.0f, 0.0f, 0.0f); glVertexAttrib4f( NORMAL_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f( COLOR0_INDEX, 1.0f, 1.0f, 1.0f, 1.0f); glVertexAttrib4f( COLOR1_INDEX, 1.0f, 1.0f, 1.0f, 1.0f); glVertexAttrib4f( MORPH_COLOR_INDEX, 1.0f, 1.0f, 1.0f, 1.0f); glVertexAttrib4f( TANGENT_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f( UNKNOWN_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f( TEXCOORD0_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f( TEXCOORD1_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f( MORPH_POSITION_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f( MORPH_NORMAL_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f( MORPH_TANGENT_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f(MORPH_TEXCOORD0_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f(MORPH_TEXCOORD1_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f( BONE_INDEX_INDEX, 0.0f, 0.0f, 0.0f, 0.0f); new_vertex_array = true; } vertex_array->vertex_buffer = vertex_buffer; vertex_array->vertex_buffer_offset = vertex_buffer_offset; vertex_array->morph_vertex_buffer = morph_vertex_buffer; vertex_array->morph_vertex_buffer_offset = morph_vertex_buffer_offset; vertex_array->index_buffer = index_buffer; vertex_array->alive_time = 60; vertex_array->vertex_format = vertex_format; vertex_array->size_vertex = size_vertex; vertex_array->compression = compression; memcpy(&vertex_array->texcoord_array, texcoord_array, sizeof(texcoord_array)); memcpy(&vertex_array->vertex_attrib_buffer_binding, vertex_attrib_buffer_binding, sizeof(vertex_attrib_buffer_binding)); if (!new_vertex_array) gl_state.bind_vertex_array(vertex_array->vertex_array); gl_state.bind_array_buffer(vertex_buffer, true); if (index_buffer) gl_state.bind_element_array_buffer(index_buffer, true); size_t offset = vertex_buffer_offset; if (vertex_format & OBJ_VERTEX_POSITION) { if (!vertex_array->vertex_attrib_array[POSITION_INDEX]) { glEnableVertexAttribArray(POSITION_INDEX); vertex_array->vertex_attrib_array[POSITION_INDEX] = true; } glVertexAttribPointer(POSITION_INDEX, 3, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 12; } else if (vertex_array->vertex_attrib_array[POSITION_INDEX]) { glDisableVertexAttribArray(POSITION_INDEX); vertex_array->vertex_attrib_array[POSITION_INDEX] = false; } if (vertex_format & OBJ_VERTEX_NORMAL) { if (!vertex_array->vertex_attrib_array[NORMAL_INDEX]) { glEnableVertexAttribArray(NORMAL_INDEX); vertex_array->vertex_attrib_array[NORMAL_INDEX] = true; } switch (compression) { case 0: default: glVertexAttribPointer(NORMAL_INDEX, 3, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 12; break; case 1: glVertexAttribPointer(NORMAL_INDEX, 3, GL_SHORT, GL_TRUE, size_vertex, (void*)offset); offset += 8; break; case 2: glVertexAttribPointer(NORMAL_INDEX, 4, GL_INT_2_10_10_10_REV, GL_TRUE, size_vertex, (void*)offset); offset += 4; break; } } else if (vertex_array->vertex_attrib_array[NORMAL_INDEX]) { glDisableVertexAttribArray(NORMAL_INDEX); vertex_array->vertex_attrib_array[NORMAL_INDEX] = false; } if (vertex_format & OBJ_VERTEX_TANGENT) { if (!vertex_array->vertex_attrib_array[TANGENT_INDEX]) { glEnableVertexAttribArray(TANGENT_INDEX); vertex_array->vertex_attrib_array[TANGENT_INDEX] = true; } switch (compression) { case 0: default: glVertexAttribPointer(TANGENT_INDEX, 4, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 16; break; case 1: glVertexAttribPointer(TANGENT_INDEX, 4, GL_SHORT, GL_TRUE, size_vertex, (void*)offset); offset += 8; break; case 2: glVertexAttribPointer(TANGENT_INDEX, 4, GL_INT_2_10_10_10_REV, GL_TRUE, size_vertex, (void*)offset); offset += 4; break; } } else if (vertex_array->vertex_attrib_array[TANGENT_INDEX]) { glDisableVertexAttribArray(TANGENT_INDEX); vertex_array->vertex_attrib_array[TANGENT_INDEX] = false; } if (!compression && (vertex_format & OBJ_VERTEX_BINORMAL)) offset += 12; for (int32_t i = 0; i < 2; i++) { int32_t texcoord_index = texcoord_array[i]; if (texcoord_index < 0) { if (vertex_array->vertex_attrib_array[TEXCOORD0_INDEX + i]) { glDisableVertexAttribArray(TEXCOORD0_INDEX + i); vertex_array->vertex_attrib_array[TEXCOORD0_INDEX + i] = false; } continue; } if (vertex_format & (OBJ_VERTEX_TEXCOORD0 << texcoord_index)) { if (!vertex_array->vertex_attrib_array[TEXCOORD0_INDEX + i]) { glEnableVertexAttribArray(TEXCOORD0_INDEX + i); vertex_array->vertex_attrib_array[TEXCOORD0_INDEX + i] = true; } switch (compression) { case 0: default: glVertexAttribPointer(TEXCOORD0_INDEX + i, 2, GL_FLOAT, GL_FALSE, size_vertex, (void*)(offset + 8ULL * texcoord_index)); break; case 1: case 2: glVertexAttribPointer(TEXCOORD0_INDEX + i, 2, GL_HALF_FLOAT, GL_FALSE, size_vertex, (void*)(offset + 4ULL * texcoord_index)); break; } } } switch (compression) { case 0: default: if (vertex_format & OBJ_VERTEX_TEXCOORD0) offset += 8; if (vertex_format & OBJ_VERTEX_TEXCOORD1) offset += 8; if (vertex_format & OBJ_VERTEX_TEXCOORD2) offset += 8; if (vertex_format & OBJ_VERTEX_TEXCOORD3) offset += 8; break; case 1: case 2: if (vertex_format & OBJ_VERTEX_TEXCOORD0) offset += 4; if (vertex_format & OBJ_VERTEX_TEXCOORD1) offset += 4; if (vertex_format & OBJ_VERTEX_TEXCOORD2) offset += 4; if (vertex_format & OBJ_VERTEX_TEXCOORD3) offset += 4; break; } if (vertex_format & OBJ_VERTEX_COLOR0) { if (!vertex_array->vertex_attrib_array[COLOR0_INDEX]) { glEnableVertexAttribArray(COLOR0_INDEX); vertex_array->vertex_attrib_array[COLOR0_INDEX] = true; } switch (compression) { case 0: default: glVertexAttribPointer(COLOR0_INDEX, 4, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 16; break; case 1: case 2: glVertexAttribPointer(COLOR0_INDEX, 4, GL_HALF_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 8; break; } } else if (vertex_array->vertex_attrib_array[COLOR0_INDEX]) { glDisableVertexAttribArray(COLOR0_INDEX); vertex_array->vertex_attrib_array[COLOR0_INDEX] = false; } if (!compression && (vertex_format & OBJ_VERTEX_COLOR1)) offset += 16; if ((vertex_format & OBJ_VERTEX_BONE_DATA) == OBJ_VERTEX_BONE_DATA) { if (!vertex_array->vertex_attrib_array[BONE_WEIGHT_INDEX]) { glEnableVertexAttribArray(BONE_WEIGHT_INDEX); vertex_array->vertex_attrib_array[BONE_WEIGHT_INDEX] = true; } switch (compression) { case 0: default: glVertexAttribPointer(BONE_WEIGHT_INDEX, 4, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 16; break; case 1: glVertexAttribPointer(BONE_WEIGHT_INDEX, 4, GL_UNSIGNED_SHORT, GL_TRUE, size_vertex, (void*)offset); offset += 8; break; case 2: glVertexAttribPointer(BONE_WEIGHT_INDEX, 4, GL_UNSIGNED_INT_2_10_10_10_REV, GL_TRUE, size_vertex, (void*)offset); offset += 4; break; } if (!vertex_array->vertex_attrib_array[BONE_INDEX_INDEX]) { glEnableVertexAttribArray(BONE_INDEX_INDEX); vertex_array->vertex_attrib_array[BONE_INDEX_INDEX] = true; } switch (compression) { case 0: case 1: default: glVertexAttribIPointer(BONE_INDEX_INDEX, 4, GL_UNSIGNED_SHORT, size_vertex, (void*)offset); offset += 8; break; case 2: glVertexAttribIPointer(BONE_INDEX_INDEX, 4, GL_UNSIGNED_BYTE, size_vertex, (void*)offset); offset += 4; break; } } else { if (vertex_array->vertex_attrib_array[BONE_WEIGHT_INDEX]) { glDisableVertexAttribArray(BONE_WEIGHT_INDEX); vertex_array->vertex_attrib_array[BONE_WEIGHT_INDEX] = false; } if (vertex_array->vertex_attrib_array[BONE_INDEX_INDEX]) { glDisableVertexAttribArray(BONE_INDEX_INDEX); vertex_array->vertex_attrib_array[BONE_INDEX_INDEX] = false; } } if (!compression && (vertex_format & OBJ_VERTEX_UNKNOWN)) { if (!vertex_array->vertex_attrib_array[UNKNOWN_INDEX]) { glEnableVertexAttribArray(UNKNOWN_INDEX); vertex_array->vertex_attrib_array[UNKNOWN_INDEX] = true; } glVertexAttribPointer(UNKNOWN_INDEX, 4, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 16; } else if (vertex_array->vertex_attrib_array[UNKNOWN_INDEX]) { glDisableVertexAttribArray(UNKNOWN_INDEX); vertex_array->vertex_attrib_array[UNKNOWN_INDEX] = false; } if (morph_vertex_buffer) { gl_state.bind_array_buffer(morph_vertex_buffer, true); size_t offset = morph_vertex_buffer_offset; if (vertex_format & OBJ_VERTEX_POSITION) { if (!vertex_array->vertex_attrib_array[MORPH_POSITION_INDEX]) { glEnableVertexAttribArray(MORPH_POSITION_INDEX); vertex_array->vertex_attrib_array[MORPH_POSITION_INDEX] = true; } glVertexAttribPointer(MORPH_POSITION_INDEX, 3, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 12; } else if (vertex_array->vertex_attrib_array[MORPH_POSITION_INDEX]) { glDisableVertexAttribArray(MORPH_POSITION_INDEX); vertex_array->vertex_attrib_array[MORPH_POSITION_INDEX] = false; } if (vertex_format & OBJ_VERTEX_NORMAL) { if (!vertex_array->vertex_attrib_array[MORPH_NORMAL_INDEX]) { glEnableVertexAttribArray(MORPH_NORMAL_INDEX); vertex_array->vertex_attrib_array[MORPH_NORMAL_INDEX] = true; } switch (compression) { case 0: default: glVertexAttribPointer(MORPH_NORMAL_INDEX, 3, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 12; break; case 1: glVertexAttribPointer(MORPH_NORMAL_INDEX, 3, GL_SHORT, GL_TRUE, size_vertex, (void*)offset); offset += 8; break; case 2: glVertexAttribPointer(MORPH_NORMAL_INDEX, 3, GL_INT_2_10_10_10_REV, GL_TRUE, size_vertex, (void*)offset); offset += 4; break; } } else if (vertex_array->vertex_attrib_array[MORPH_NORMAL_INDEX]) { glDisableVertexAttribArray(MORPH_NORMAL_INDEX); vertex_array->vertex_attrib_array[MORPH_NORMAL_INDEX] = false; } if (vertex_format & OBJ_VERTEX_TANGENT) { if (!vertex_array->vertex_attrib_array[MORPH_TANGENT_INDEX]) { glEnableVertexAttribArray(MORPH_TANGENT_INDEX); vertex_array->vertex_attrib_array[MORPH_TANGENT_INDEX] = true; } switch (compression) { case 0: default: glVertexAttribPointer(MORPH_TANGENT_INDEX, 4, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 16; break; case 1: glVertexAttribPointer(MORPH_TANGENT_INDEX, 4, GL_SHORT, GL_TRUE, size_vertex, (void*)offset); offset += 8; break; case 2: glVertexAttribPointer(MORPH_TANGENT_INDEX, 4, GL_INT_2_10_10_10_REV, GL_TRUE, size_vertex, (void*)offset); offset += 4; break; } } else if (vertex_array->vertex_attrib_array[MORPH_TANGENT_INDEX]) { glDisableVertexAttribArray(MORPH_TANGENT_INDEX); vertex_array->vertex_attrib_array[MORPH_TANGENT_INDEX] = false; } if (vertex_format & OBJ_VERTEX_BINORMAL) offset += 12; if (vertex_format & OBJ_VERTEX_TEXCOORD0) { if (!vertex_array->vertex_attrib_array[MORPH_TEXCOORD0_INDEX]) { glEnableVertexAttribArray(MORPH_TEXCOORD0_INDEX); vertex_array->vertex_attrib_array[MORPH_TEXCOORD0_INDEX] = true; } switch (compression) { case 0: default: glVertexAttribPointer(MORPH_TEXCOORD0_INDEX, 2, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 8; break; case 1: case 2: glVertexAttribPointer(MORPH_TEXCOORD0_INDEX, 2, GL_HALF_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 4; break; } } else if (vertex_array->vertex_attrib_array[MORPH_TEXCOORD0_INDEX]) { glDisableVertexAttribArray(MORPH_TEXCOORD0_INDEX); vertex_array->vertex_attrib_array[MORPH_TEXCOORD0_INDEX] = false; } if (vertex_format & OBJ_VERTEX_TEXCOORD1) { if (!vertex_array->vertex_attrib_array[MORPH_TEXCOORD1_INDEX]) { glEnableVertexAttribArray(MORPH_TEXCOORD1_INDEX); vertex_array->vertex_attrib_array[MORPH_TEXCOORD1_INDEX] = true; } switch (compression) { case 0: default: glVertexAttribPointer(MORPH_TEXCOORD1_INDEX, 2, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 8; break; case 1: case 2: glVertexAttribPointer(MORPH_TEXCOORD1_INDEX, 2, GL_HALF_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 4; break; } } else if (vertex_array->vertex_attrib_array[MORPH_TEXCOORD1_INDEX]) { glDisableVertexAttribArray(MORPH_TEXCOORD1_INDEX); vertex_array->vertex_attrib_array[MORPH_TEXCOORD1_INDEX] = false; } switch (compression) { case 0: default: if (vertex_format & OBJ_VERTEX_TEXCOORD2) offset += 8; if (vertex_format & OBJ_VERTEX_TEXCOORD3) offset += 8; break; case 1: case 2: if (vertex_format & OBJ_VERTEX_TEXCOORD2) offset += 4; if (vertex_format & OBJ_VERTEX_TEXCOORD3) offset += 4; break; } if (vertex_format & OBJ_VERTEX_COLOR0) { if (!vertex_array->vertex_attrib_array[MORPH_COLOR_INDEX]) { glEnableVertexAttribArray(MORPH_COLOR_INDEX); vertex_array->vertex_attrib_array[MORPH_COLOR_INDEX] = true; } switch (compression) { case 0: default: glVertexAttribPointer(MORPH_COLOR_INDEX, 4, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 16; break; case 1: case 2: glVertexAttribPointer(MORPH_COLOR_INDEX, 4, GL_HALF_FLOAT, GL_FALSE, size_vertex, (void*)offset); offset += 8; break; } } else if (vertex_array->vertex_attrib_array[MORPH_COLOR_INDEX]) { glDisableVertexAttribArray(MORPH_COLOR_INDEX); vertex_array->vertex_attrib_array[MORPH_COLOR_INDEX] = false; } switch (compression) { case 0: default: if (vertex_format & OBJ_VERTEX_COLOR1) offset += 16; if ((vertex_format & OBJ_VERTEX_BONE_DATA) == OBJ_VERTEX_BONE_DATA) offset += 24; if (vertex_format & OBJ_VERTEX_UNKNOWN) offset += 16; break; case 1: if ((vertex_format & OBJ_VERTEX_BONE_DATA) == OBJ_VERTEX_BONE_DATA) offset += 16; break; case 2: if ((vertex_format & OBJ_VERTEX_BONE_DATA) == OBJ_VERTEX_BONE_DATA) offset += 8; break; } } else { if (vertex_array->vertex_attrib_array[MORPH_POSITION_INDEX]) { glDisableVertexAttribArray(MORPH_POSITION_INDEX); vertex_array->vertex_attrib_array[MORPH_POSITION_INDEX] = false; } if (vertex_array->vertex_attrib_array[MORPH_NORMAL_INDEX]) { glDisableVertexAttribArray(MORPH_NORMAL_INDEX); vertex_array->vertex_attrib_array[MORPH_NORMAL_INDEX] = false; } if (vertex_array->vertex_attrib_array[MORPH_TANGENT_INDEX]) { glDisableVertexAttribArray(MORPH_TANGENT_INDEX); vertex_array->vertex_attrib_array[MORPH_TANGENT_INDEX] = false; } if (vertex_array->vertex_attrib_array[MORPH_TEXCOORD0_INDEX]) { glDisableVertexAttribArray(MORPH_TEXCOORD0_INDEX); vertex_array->vertex_attrib_array[MORPH_TEXCOORD0_INDEX] = false; } if (vertex_array->vertex_attrib_array[MORPH_TEXCOORD1_INDEX]) { glDisableVertexAttribArray(MORPH_TEXCOORD1_INDEX); vertex_array->vertex_attrib_array[MORPH_TEXCOORD1_INDEX] = false; } if (vertex_array->vertex_attrib_array[MORPH_COLOR_INDEX]) { glDisableVertexAttribArray(MORPH_COLOR_INDEX); vertex_array->vertex_attrib_array[MORPH_COLOR_INDEX] = false; } } gl_state.bind_array_buffer(0); gl_state.bind_vertex_array(0); if (index_buffer) gl_state.bind_element_array_buffer(0); } static size_t gen_grid_vertices(prj::vector>& data, int32_t w, int32_t h, int32_t ws, int32_t hs) { const int32_t ws_half = ws / 2; const int32_t hs_half = hs / 2; const float_t w_flt = (float_t)w; const float_t h_flt = (float_t)h; const float_t width = w_flt * 0.5f; const float_t height = h_flt * 0.5f; data.reserve(ws * 2ULL); for (int32_t i = 0; i <= ws; i++) { if (i == ws_half) continue; const float_t w = (float_t)i * (w_flt / ((float_t)ws_half * 2.0f)) - width; data.push_back({ { w, 0.0f, -height }, { 0.0f } }); data.push_back({ { w, 0.0f, height }, { 0.0f } }); } data.reserve(hs * 2ULL); for (int32_t i = 0; i <= hs; i++) { if (i == hs_half) continue; const float_t h = (float_t)i * (h_flt / ((float_t)hs_half * 2.0f)) - height; data.push_back({ { -width, 0.0f, h }, { 0.0f } }); data.push_back({ { width, 0.0f, h }, { 0.0f } }); } size_t center_offset = data.size(); data.reserve(2 * 2ULL); data.push_back({ { 0.0f, 0.0f, -height }, { 0.0f } }); data.push_back({ { 0.0f, 0.0f, height }, { 0.0f } }); data.push_back({ { -width, 0.0f, 0.0f }, { 0.0f } }); data.push_back({ { width, 0.0f, 0.0f }, { 0.0f } }); return center_offset; } static void gen_cube_vertices(prj::vector>& data, vec3 size) { size *= 0.5f; data.reserve(4 * 6ULL); data.push_back({ { -size.x, -size.y, -size.z }, { 0.0f, 0.0f, -1.0f } }); data.push_back({ { size.x, size.y, -size.z }, { 0.0f, 0.0f, -1.0f } }); data.push_back({ { size.x, -size.y, -size.z }, { 0.0f, 0.0f, -1.0f } }); data.push_back({ { -size.x, size.y, -size.z }, { 0.0f, 0.0f, -1.0f } }); data.push_back({ { -size.x, -size.y, size.z }, { 0.0f, 0.0f, 1.0f } }); data.push_back({ { size.x, -size.y, size.z }, { 0.0f, 0.0f, 1.0f } }); data.push_back({ { size.x, size.y, size.z }, { 0.0f, 0.0f, 1.0f } }); data.push_back({ { -size.x, size.y, size.z }, { 0.0f, 0.0f, 1.0f } }); data.push_back({ { -size.x, size.y, size.z }, { -1.0f, 0.0f, 0.0f } }); data.push_back({ { -size.x, size.y, -size.z }, { -1.0f, 0.0f, 0.0f } }); data.push_back({ { -size.x, -size.y, -size.z }, { -1.0f, 0.0f, 0.0f } }); data.push_back({ { -size.x, -size.y, size.z }, { -1.0f, 0.0f, 0.0f } }); data.push_back({ { size.x, size.y, -size.z }, { 1.0f, 0.0f, 0.0f } }); data.push_back({ { size.x, size.y, size.z }, { 1.0f, 0.0f, 0.0f } }); data.push_back({ { size.x, -size.y, -size.z }, { 1.0f, 0.0f, 0.0f } }); data.push_back({ { size.x, -size.y, size.z }, { 1.0f, 0.0f, 0.0f } }); data.push_back({ { -size.x, -size.y, -size.z }, { 0.0f, -1.0f, 0.0f } }); data.push_back({ { size.x, -size.y, -size.z }, { 0.0f, -1.0f, 0.0f } }); data.push_back({ { size.x, -size.y, size.z }, { 0.0f, -1.0f, 0.0f } }); data.push_back({ { -size.x, -size.y, size.z }, { 0.0f, -1.0f, 0.0f } }); data.push_back({ { -size.x, size.y, -size.z }, { 0.0f, 1.0f, 0.0f } }); data.push_back({ { size.x, size.y, size.z }, { 0.0f, 1.0f, 0.0f } }); data.push_back({ { size.x, size.y, -size.z }, { 0.0f, 1.0f, 0.0f } }); data.push_back({ { -size.x, size.y, size.z }, { 0.0f, 1.0f, 0.0f } }); } static size_t gen_cube_indices(prj::vector& indices) { const uint32_t sides_indices[] = { 0, 1, 2, 0, 3, 1, 4, 5, 6, 6, 7, 4, 8, 9, 10, 10, 11, 8, 12, 13, 14, 15, 14, 13, 16, 17, 18, 18, 19, 16, 20, 21, 22, 20, 23, 21, }; const uint32_t edges_indices[] = { 0, 2, 1, 2, 0, 3, 1, 3, 4, 5, 6, 5, 4, 7, 6, 7, 0, 4, 1, 6, 2, 5, 3, 7, }; indices.insert(indices.end(), sides_indices, sides_indices + sizeof(sides_indices) / sizeof(uint32_t)); size_t wire_offset = indices.size(); indices.insert(indices.end(), edges_indices, edges_indices + sizeof(edges_indices) / sizeof(uint32_t)); return wire_offset; } static void gen_sphere_vertices(prj::vector>& data, int32_t slices, int32_t stacks, float_t radius) { if (slices < 2 || stacks < 2) return; data.push_back({ { 0.0f, radius, 0.0f }, { 0.0f, -1.0f, 0.0f} }); double_t slice_step = (M_PI * 2.0) / (double_t)slices; double_t stack_step = M_PI / (double_t)stacks; for (int32_t i = 1; i < stacks; i++) { float_t stack_angle = (float_t)((M_PI / 2.0) - (double_t)i * stack_step); float_t xz = cosf(stack_angle); float_t y = sinf(stack_angle); data.reserve(slices); for (int32_t j = 0; j < slices; j++) { float_t slice_angle = (float_t)((double_t)j * slice_step); float_t x = xz * cosf(slice_angle); float_t z = xz * sinf(slice_angle); data.push_back({ { x * radius, y * radius, z * radius }, { x, y, z } }); } } data.push_back({ { 0.0f, -radius, 0.0f }, { 0.0f, -1.0f, 0.0f} }); } static size_t gen_sphere_indices(prj::vector& indices, int32_t slices, int32_t stacks) { if (slices < 2 || stacks < 2) return 0; // Top stack vertices { int32_t m1 = 0; int32_t m2 = 1; indices.reserve(3LL * slices); for (int32_t j = 0, k = 1; j < slices; j++) { indices.push_back(m1); indices.push_back(k + m2); indices.push_back(j + m2); if (++k >= slices) k = 0; } } // Middle stacks vertices for (int32_t i = 1; i < stacks - 1; i++) { int32_t m1 = (i - 1) * slices + 1; int32_t m2 = m1 + slices; indices.reserve(6LL * slices); for (int32_t j = 0, k = 1; j < slices; j++) { indices.push_back(j + m1); indices.push_back(k + m1); indices.push_back(j + m2); indices.push_back(k + m1); indices.push_back(k + m2); indices.push_back(j + m2); if (++k >= slices) k = 0; } } // Bottom stack vertices { int32_t m1 = (stacks - 2) * slices + 1; int32_t m2 = m1 + slices; indices.reserve(3LL * slices); for (int32_t j = 0, k = 1; j < slices; j++) { indices.push_back(j + m1); indices.push_back(k + m1); indices.push_back(m2); if (++k >= slices) k = 0; } } size_t wire_offset = indices.size(); // Top stack wireframe { int32_t m1 = 0; int32_t m2 = 1; indices.reserve(2LL * slices); for (int32_t j = 0; j < slices; j++) { indices.push_back(m1); indices.push_back(j + m2); } } // Middle stacks wireframe for (int32_t i = 1; i < stacks - 1; i++) { int32_t m1 = (i - 1) * slices + 1; int32_t m2 = m1 + slices; indices.reserve(2LL * slices); for (int32_t j = 0; j < slices; j++) { indices.push_back(j + m1); indices.push_back(j + m2); } } // Bottom stack wireframe { int32_t m1 = (stacks - 2) * slices + 1; int32_t m2 = m1 + slices; indices.reserve(2LL * slices); for (int32_t j = 0; j < slices; j++) { indices.push_back(j + m1); indices.push_back(m2); } } // Slices wireframe for (int32_t i = 1; i < stacks; i++) { int32_t m = (i - 1) * slices + 1; indices.reserve(2LL * slices); for (int32_t j = 0, k = 1; j < slices; j++) { indices.push_back(j + m); indices.push_back(k + m); if (++k >= slices) k = 0; } } return wire_offset; } static void gen_plane_vertices(prj::vector>& data, int32_t w, int32_t h) { float_t width = (float_t)w * 0.5f; float_t height = (float_t)h * 0.5f; data.reserve(4); data.push_back({ { width, 0.0f, height }, { 0.0f, 1.0f, 0.0f } }); data.push_back({ { width, 0.0f, -height }, { 0.0f, 1.0f, 0.0f } }); data.push_back({ { -width, 0.0f, height }, { 0.0f, 1.0f, 0.0f } }); data.push_back({ { -width, 0.0f, -height }, { 0.0f, 1.0f, 0.0f } }); } static void gen_line_vertices(prj::vector>& data, float_t length) { length *= 0.5f; data.reserve(2); data.push_back({ { 0.0f, length, 0.0f }, { 0.0f } }); data.push_back({ { 0.0f, -length, 0.0f }, { 0.0f } }); } static void gen_cross_vertices(prj::vector>& data, float_t size) { data.reserve(6); data.push_back({ { -size, 0.0f, 0.0f }, { 0.0f } }); data.push_back({ { size, 0.0f, 0.0f }, { 0.0f } }); data.push_back({ { 0.0f, -size, 0.0f }, { 0.0f } }); data.push_back({ { 0.0f, size, 0.0f }, { 0.0f }}); data.push_back({ { 0.0f, 0.0f, -size }, { 0.0f } }); data.push_back({ { 0.0f, 0.0f, size }, { 0.0f } }); } static void gen_capsule_vertices(prj::vector>& data, int32_t slices, int32_t stacks, float_t length, float_t radius) { if (slices < 2 || stacks < 2) return; stacks = ((stacks + 1) >> 1) << 1; if (length < 0.00001f) { gen_sphere_vertices(data, slices, stacks, radius); return; } length *= 0.5f; data.push_back({ { 0.0f, radius + length, 0.0f }, { 0.0f, 1.0f, 0.0f } }); double_t slice_step = (M_PI * 2.0) / (double_t)slices; double_t stack_step = M_PI / (double_t)stacks; for (int32_t i = 1; i <= stacks / 2; i++) { float_t stack_angle = (float_t)((M_PI / 2.0) - (double_t)i * stack_step); float_t xz = cosf(stack_angle); float_t y = sinf(stack_angle); y *= radius; data.reserve(slices); for (int32_t j = 0; j < slices; j++) { float_t slice_angle = (float_t)((double_t)j * slice_step); float_t x = xz * cosf(slice_angle); float_t z = xz * sinf(slice_angle); data.push_back({ { x * radius, y + length, z * radius }, { x, y, z } }); } } for (int32_t i = stacks / 2; i < stacks; i++) { float_t stack_angle = (float_t)((M_PI / 2.0) - (double_t)i * stack_step); float_t xz = cosf(stack_angle); float_t y = sinf(stack_angle); y *= radius; data.reserve(slices); for (int32_t j = 0; j < slices; j++) { float_t slice_angle = (float_t)((double_t)j * slice_step); float_t x = xz * cosf(slice_angle); float_t z = xz * sinf(slice_angle); data.push_back({ { x * radius, y - length, z * radius }, { x, y, z } }); } } data.push_back({ { 0.0f, -radius - length, 0.0f }, { 0.0f, -1.0f, 0.0f } }); } static size_t gen_capsule_indices(prj::vector& indices, int32_t slices, int32_t stacks, float_t length) { if (slices < 2 || stacks < 2) return 0; stacks = ((stacks + 1) >> 1) << 1; if (length < 0.00001f) return gen_sphere_indices(indices, slices, stacks); // Top stack vertices { int32_t m1 = 0; int32_t m2 = 1; indices.reserve(3LL * slices); for (int32_t j = 0, k = 1; j < slices; j++) { indices.push_back(m1); indices.push_back(k + m2); indices.push_back(j + m2); if (++k >= slices) k = 0; } } // Middle stacks vertices for (int32_t i = 1; i < stacks; i++) { int32_t m1 = (i - 1) * slices + 1; int32_t m2 = m1 + slices; indices.reserve(6LL * slices); for (int32_t j = 0, k = 1; j < slices; j++) { indices.push_back(j + m1); indices.push_back(k + m1); indices.push_back(j + m2); indices.push_back(k + m1); indices.push_back(k + m2); indices.push_back(j + m2); if (++k >= slices) k = 0; } } // Bottom stack vertices { int32_t m1 = (stacks - 1) * slices + 1; int32_t m2 = m1 + slices; indices.reserve(3LL * slices); for (int32_t j = 0, k = 1; j < slices; j++) { indices.push_back(j + m1); indices.push_back(k + m1); indices.push_back(m2); if (++k >= slices) k = 0; } } size_t wire_offset = indices.size(); // Top stack wireframe { int32_t m1 = 0; int32_t m2 = 1; indices.reserve(2LL * slices); for (int32_t j = 0; j < slices; j++) { indices.push_back(m1); indices.push_back(j + m2); } } // Middle stacks wireframe for (int32_t i = 1; i < stacks; i++) { int32_t m1 = (i - 1) * slices + 1; int32_t m2 = m1 + slices; indices.reserve(2LL * slices); for (int32_t j = 0; j < slices; j++) { indices.push_back(j + m1); indices.push_back(j + m2); } } // Bottom stack wireframe { int32_t m1 = (stacks - 1) * slices + 1; int32_t m2 = m1 + slices; indices.reserve(2LL * slices); for (int32_t j = 0; j < slices; j++) { indices.push_back(j + m1); indices.push_back(m2); } } // Slices wireframe for (int32_t i = 1; i <= stacks; i++) { int32_t m = (i - 1) * slices + 1; indices.reserve(2LL * slices); for (int32_t j = 0, k = 1; j < slices; j++) { indices.push_back(j + m); indices.push_back(k + m); if (k++ >= slices) k = 0; } } return wire_offset; } static void gen_cylinder_vertices(prj::vector>& data, int32_t slices, int32_t stacks, float_t base, float_t height) { float_t half_height = height * 0.5f; if (slices < 2 || stacks < 0) return; data.push_back({ { 0.0f, stacks ? half_height : 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f } }); double_t slice_step = (M_PI * 2.0) / (double_t)slices; double_t stack_step = M_PI / (double_t)stacks; for (int32_t i = 0; i <= stacks; i++) { float_t y = stacks ? lerp_def(half_height, -half_height, (float_t)i / (float_t)stacks) : 0.0f; data.reserve(slices); for (int32_t j = 0; j < slices; j++) { float_t slice_angle = (float_t)((double_t)j * slice_step); float_t x = cosf(slice_angle); float_t z = sinf(slice_angle); data.push_back({ { x * base, y, z * base }, { x, 0.0f, z } }); } } data.push_back({ { 0.0f, stacks ? -half_height : 0.0f, 0.0f }, { 0.0f, -1.0f, 0.0f } }); } static size_t gen_cylinder_indices(prj::vector& indices, int32_t slices, int32_t stacks) { if (slices < 2 || stacks < 0) return 0; // Top cap vertices { int32_t m1 = 0; int32_t m2 = 1; indices.reserve(3LL * slices); for (int32_t j = 0, k = 1; j < slices; j++) { indices.push_back(m1); indices.push_back(k + m2); indices.push_back(j + m2); if (++k >= slices) k = 0; } } // Stacks vertices for (int32_t i = 0; i < stacks; i++) { int32_t m1 = i * slices + 1; int32_t m2 = m1 + slices; indices.reserve(6LL * slices); for (int32_t j = 0, k = 1; j < slices; j++) { indices.push_back(j + m1); indices.push_back(k + m1); indices.push_back(j + m2); indices.push_back(k + m1); indices.push_back(k + m2); indices.push_back(j + m2); if (++k >= slices) k = 0; } } // Bottom cap vertices { int32_t m1 = stacks * slices + 1; int32_t m2 = m1 + slices; indices.reserve(3LL * slices); for (int32_t j = 0, k = 1; j < slices; j++) { indices.push_back(j + m1); indices.push_back(k + m1); indices.push_back(m2); if (++k >= slices) k = 0; } } size_t wire_offset = indices.size(); // Stacks wireframe for (int32_t i = 0; i < stacks; i++) { int32_t m1 = i * slices + 1; int32_t m2 = m1 + slices; indices.reserve(2LL * slices); for (int32_t j = 0; j < slices; j++) { indices.push_back(j + m1); indices.push_back(j + m2); } } // Slices wireframe for (int32_t i = 0; i <= stacks; i++) { int32_t m = i * slices + 1; indices.reserve(2LL * slices); for (int32_t j = 0, k = 1; j < slices; j++) { indices.push_back(j + m); indices.push_back(k + m); if (k++ >= slices) k = 0; } } return wire_offset; } void DispManager::add_vertex_array(EtcObj* etc, mat4& mat) { EtcObjType type = etc->type; switch (type) { case mdl::ETC_OBJ_TEAPOT: case mdl::ETC_OBJ_GRID: case mdl::ETC_OBJ_CUBE: case mdl::ETC_OBJ_SPHERE: case mdl::ETC_OBJ_PLANE: case mdl::ETC_OBJ_CONE: case mdl::ETC_OBJ_LINE: case mdl::ETC_OBJ_CROSS: case mdl::ETC_OBJ_CAPSULE: // Added case mdl::ETC_OBJ_CYLINDER: // Added break; default: return; } bool indexed = false; bool wire = false; float_t length = 0.0f; switch (type) { case mdl::ETC_OBJ_TEAPOT: { EtcObjTeapot& teapot = etc->data.teapot; indexed = true; } break; case mdl::ETC_OBJ_GRID: { EtcObjGrid& grid = etc->data.grid; } break; case mdl::ETC_OBJ_CUBE: { EtcObjCube& cube = etc->data.cube; indexed = true; wire = cube.wire; } break; case mdl::ETC_OBJ_SPHERE: { EtcObjSphere& sphere = etc->data.sphere; indexed = true; wire = sphere.wire; } break; case mdl::ETC_OBJ_PLANE: { EtcObjPlane& plane = etc->data.plane; } break; case mdl::ETC_OBJ_CONE: { EtcObjCone& cone = etc->data.cone; indexed = true; wire = cone.wire; } break; case mdl::ETC_OBJ_LINE: { EtcObjLine& line = etc->data.line; vec3 origin = (line.pos[0] + line.pos[1]) * 0.5f; mat4_add_translate(&mat, &origin, &mat); const vec3 dir = vec3::normalize(line.pos[1] - line.pos[0]); const vec3 up = { 0.0f, 1.0f, 0.0f }; vec3 axis; float_t angle; vec3::axis_angle_from_vectors(axis, angle, up, dir); mat4 m = mat4_identity; mat4_mul_rotation(&m, &axis, angle, &m); mat4_mul(&m, &mat, &mat); length = vec3::distance(line.pos[0], line.pos[1]); } break; case mdl::ETC_OBJ_CROSS: { EtcObjCross& cross = etc->data.cross; } break; case mdl::ETC_OBJ_CAPSULE: { // Added EtcObjCapsule& capsule = etc->data.capsule; vec3 origin = (capsule.pos[0] + capsule.pos[1]) * 0.5f; mat4_add_translate(&mat, &origin, &mat); const vec3 dir = vec3::normalize(capsule.pos[1] - capsule.pos[0]); const vec3 up = { 0.0f, 1.0f, 0.0f }; vec3 axis; float_t angle; vec3::axis_angle_from_vectors(axis, angle, up, dir); mat4 m = mat4_identity; mat4_mul_rotation(&m, &axis, angle, &m); mat4_mul(&m, &mat, &mat); indexed = true; wire = capsule.wire; length = vec3::distance(capsule.pos[0], capsule.pos[1]); } break; case mdl::ETC_OBJ_CYLINDER: { // Added EtcObjCylinder& cylinder = etc->data.cylinder; indexed = true; wire = cylinder.wire; } break; } DispManager::etc_vertex_array* etc_vertex_array = 0; for (DispManager::etc_vertex_array& i : etc_vertex_array_cache) { if (i.alive_time <= 0 || i.type != type || i.vertex_buffer.IsNull()) continue; if (type == mdl::ETC_OBJ_TEAPOT || type == mdl::ETC_OBJ_GRID && !memcmp(&i.data.grid, &etc->data.grid, sizeof(EtcObjGrid)) || type == mdl::ETC_OBJ_CUBE && vec3::dot(vec3::abs(i.data.cube.size - etc->data.cube.size), 1.0f) < 0.00001f || type == mdl::ETC_OBJ_SPHERE && i.data.sphere.slices == etc->data.sphere.slices && i.data.sphere.stacks == etc->data.sphere.stacks && fabsf(i.data.sphere.radius - etc->data.sphere.radius) < 0.00001f || type == mdl::ETC_OBJ_PLANE && i.data.plane.w == etc->data.plane.w && i.data.plane.h == etc->data.plane.h || type == mdl::ETC_OBJ_CONE && i.data.cone.slices == etc->data.cone.slices && i.data.cone.stacks == etc->data.cone.stacks && fabsf(i.data.cone.base - etc->data.cone.base) < 0.00001f && fabsf(i.data.cone.height - etc->data.cone.height) < 0.00001f || type == mdl::ETC_OBJ_LINE && fabsf(vec3::distance(i.data.line.pos[0], i.data.line.pos[1]) - length) < 0.00001f || type == mdl::ETC_OBJ_CROSS && fabsf(i.data.cross.size - etc->data.cross.size) < 0.00001f || type == mdl::ETC_OBJ_CAPSULE // Added && i.data.capsule.slices == etc->data.capsule.slices && ((i.data.capsule.stacks + 1)) >> 1 == ((etc->data.capsule.stacks + 1) >> 1) && fabsf(i.data.capsule.radius - etc->data.capsule.radius) < 0.00001f && fabsf(vec3::distance(i.data.capsule.pos[0], i.data.capsule.pos[1]) - length) < 0.00001f || type == mdl::ETC_OBJ_CYLINDER // Added && i.data.cylinder.slices == etc->data.cylinder.slices && i.data.cylinder.stacks == etc->data.cylinder.stacks && fabsf(i.data.cylinder.base - etc->data.cylinder.base) < 0.00001f && fabsf(i.data.cylinder.height - etc->data.cylinder.height) < 0.00001f) if (i.vertex_array) { i.alive_time = 2; if (!wire) { etc->count = i.count; etc->offset = i.offset; } else { etc->count = i.wire_count; etc->offset = i.wire_offset; } return; } else { etc_vertex_array = &i; break; } } if (!etc_vertex_array) for (DispManager::etc_vertex_array& i : etc_vertex_array_cache) if (i.alive_time <= 0) { etc_vertex_array = &i; break; } if (!etc_vertex_array) { etc_vertex_array_cache.push_back({}); etc_vertex_array = &etc_vertex_array_cache.back(); } bool new_vertex_array = false; if (!etc_vertex_array->vertex_array) { glGenVertexArrays(1, &etc_vertex_array->vertex_array); gl_state.bind_vertex_array(etc_vertex_array->vertex_array); glVertexAttrib4f( POSITION_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f( BONE_WEIGHT_INDEX, 0.0f, 0.0f, 0.0f, 0.0f); glVertexAttrib4f( NORMAL_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f( COLOR0_INDEX, 1.0f, 1.0f, 1.0f, 1.0f); glVertexAttrib4f( COLOR1_INDEX, 1.0f, 1.0f, 1.0f, 1.0f); glVertexAttrib4f( MORPH_COLOR_INDEX, 1.0f, 1.0f, 1.0f, 1.0f); glVertexAttrib4f( TANGENT_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f( UNKNOWN_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f( TEXCOORD0_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f( TEXCOORD1_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f( MORPH_POSITION_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f( MORPH_NORMAL_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f( MORPH_TANGENT_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f(MORPH_TEXCOORD0_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f(MORPH_TEXCOORD1_INDEX, 0.0f, 0.0f, 0.0f, 1.0f); glVertexAttrib4f( BONE_INDEX_INDEX, 0.0f, 0.0f, 0.0f, 0.0f); new_vertex_array = true; } etc_vertex_array->alive_time = 2; etc_vertex_array->data = etc->data; etc_vertex_array->type = type; etc_vertex_array->indexed = indexed; prj::vector> vtx_data; prj::vector vtx_indices; switch (type) { case mdl::ETC_OBJ_TEAPOT: { EtcObjTeapot& teapot = etc->data.teapot; etc_vertex_array->count = (GLsizei)vtx_indices.size(); } break; case mdl::ETC_OBJ_GRID: { EtcObjGrid& grid = etc->data.grid; size_t center_offset = gen_grid_vertices(vtx_data, grid.w, grid.h, grid.ws, grid.hs); etc_vertex_array->offset = 0; etc_vertex_array->count = (GLsizei)center_offset; } break; case mdl::ETC_OBJ_CUBE: { EtcObjCube& cube = etc->data.cube; gen_cube_vertices(vtx_data, cube.size); size_t wire_offset = gen_cube_indices(vtx_indices); etc_vertex_array->offset = 0; etc_vertex_array->count = (GLsizei)wire_offset; etc_vertex_array->wire_offset = wire_offset * sizeof(uint32_t); etc_vertex_array->wire_count = (GLsizei)(vtx_indices.size() - wire_offset); } break; case mdl::ETC_OBJ_SPHERE: { EtcObjSphere& sphere = etc->data.sphere; gen_sphere_vertices(vtx_data, sphere.slices, sphere.stacks, sphere.radius); size_t wire_offset = gen_sphere_indices(vtx_indices, sphere.slices, sphere.stacks); etc_vertex_array->offset = 0; etc_vertex_array->count = (GLsizei)wire_offset; etc_vertex_array->wire_offset = wire_offset * sizeof(uint32_t); etc_vertex_array->wire_count = (GLsizei)(vtx_indices.size() - wire_offset); } break; case mdl::ETC_OBJ_PLANE: { EtcObjPlane& plane = etc->data.plane; gen_plane_vertices(vtx_data, plane.w, plane.h); etc_vertex_array->count = (GLsizei)vtx_data.size(); } break; case mdl::ETC_OBJ_CONE: { EtcObjCone& cone = etc->data.cone; etc_vertex_array->count = (GLsizei)vtx_indices.size(); } break; case mdl::ETC_OBJ_LINE: { EtcObjLine& line = etc->data.line; gen_line_vertices(vtx_data, length); etc_vertex_array->count = (GLsizei)vtx_data.size(); } break; case mdl::ETC_OBJ_CROSS: { EtcObjCross& cross = etc->data.cross; gen_cross_vertices(vtx_data, cross.size); etc_vertex_array->count = (GLsizei)vtx_data.size(); } break; case mdl::ETC_OBJ_CAPSULE: { // Added EtcObjCapsule& capsule = etc->data.capsule; gen_capsule_vertices(vtx_data, capsule.slices, capsule.stacks, length, capsule.radius); size_t wire_offset = gen_capsule_indices(vtx_indices, capsule.slices, capsule.stacks, length); etc_vertex_array->offset = 0; etc_vertex_array->count = (GLsizei)wire_offset; etc_vertex_array->wire_offset = wire_offset * sizeof(uint32_t); etc_vertex_array->wire_count = (GLsizei)(vtx_indices.size() - wire_offset); } break; case mdl::ETC_OBJ_CYLINDER: { // Added EtcObjCylinder& cylinder = etc->data.cylinder; gen_cylinder_vertices(vtx_data, cylinder.slices, cylinder.stacks, cylinder.base, cylinder.height); size_t wire_offset = gen_cylinder_indices(vtx_indices, cylinder.slices, cylinder.stacks); etc_vertex_array->offset = 0; etc_vertex_array->count = (GLsizei)wire_offset; etc_vertex_array->wire_offset = wire_offset * sizeof(uint32_t); etc_vertex_array->wire_count = (GLsizei)(vtx_indices.size() - wire_offset); } break; } if (!wire) { etc->count = etc_vertex_array->count; etc->offset = etc_vertex_array->offset; } else { etc->count = etc_vertex_array->wire_count; etc->offset = etc_vertex_array->wire_offset; } if (!etc_vertex_array->count) return; if (etc_vertex_array->max_vtx < vtx_data.size()) { etc_vertex_array->max_vtx = vtx_data.size(); etc_vertex_array->vertex_buffer.Destroy(); } if (etc_vertex_array->max_idx < vtx_indices.size()) { etc_vertex_array->max_idx = vtx_indices.size(); etc_vertex_array->index_buffer.Destroy(); } GLsizei size_vertex = sizeof(vec3) * 2; if (!new_vertex_array) gl_state.bind_vertex_array(etc_vertex_array->vertex_array); if (etc_vertex_array->vertex_buffer.IsNull()) etc_vertex_array->vertex_buffer.Create(gl_state, sizeof(vec3) * 2 * vtx_data.size()); gl_state.bind_array_buffer(etc_vertex_array->vertex_buffer, true); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vec3) * 2 * vtx_data.size(), vtx_data.data()); if (indexed) { if (etc_vertex_array->index_buffer.IsNull()) etc_vertex_array->index_buffer.Create(gl_state, sizeof(uint32_t) * vtx_indices.size()); gl_state.bind_element_array_buffer(etc_vertex_array->index_buffer, true); glBufferSubData(GL_ELEMENT_ARRAY_BUFFER, 0, sizeof(uint32_t) * vtx_indices.size(), vtx_indices.data()); } glEnableVertexAttribArray(POSITION_INDEX); glVertexAttribPointer(POSITION_INDEX, 3, GL_FLOAT, GL_FALSE, size_vertex, (void*)0); glEnableVertexAttribArray(NORMAL_INDEX); glVertexAttribPointer(NORMAL_INDEX, 3, GL_FLOAT, GL_FALSE, size_vertex, (void*)sizeof(vec3)); gl_state.bind_array_buffer(0); gl_state.bind_vertex_array(0); if (indexed) gl_state.bind_element_array_buffer(0); } void* DispManager::alloc_data(int32_t size) { if (!buff || buff_offset + size > buff_size) return 0; void* data = (void*)((size_t)buff + buff_offset); buff_offset += size; buff_max = max_def(buff_max, buff_offset); return data; } ObjData* DispManager::alloc_obj_data(ObjKind kind) { int32_t size = (int32_t)align_val(sizeof(ObjKind) + sizeof(mat4) + sizeof(float_t) * 2, 0x08); switch (kind) { case OBJ_KIND_NORMAL: return (ObjData*)alloc_data(size + sizeof(ObjSubMeshArgs)); case OBJ_KIND_ETC: return (ObjData*)alloc_data(size + sizeof(EtcObj)); case OBJ_KIND_USER: return (ObjData*)alloc_data(size + sizeof(UserArgs)); case OBJ_KIND_TRANSLUCENT: return (ObjData*)alloc_data(size + sizeof(ObjTranslucentArgs)); default: return 0; } } mat4* DispManager::alloc_mat4_array(int32_t count) { return (mat4*)alloc_data(sizeof(mat4) * count); } void DispManager::buffer_reset() { buff_offset = 0; } void DispManager::calc_obj_radius(const cam_data& cam, ObjType type) { prj::vector alpha_center; prj::vector mat_center; for (ObjData*& i : get_obj_list(type)) { vec3 center = 0.0f; bool v50 = false; switch (i->kind) { case OBJ_KIND_NORMAL: { mat4 mat = i->mat; if (i->args.sub_mesh.mesh->attrib.m.billboard) model_mat_face_camera_view(cam, &mat, &mat); else if (i->args.sub_mesh.mesh->attrib.m.billboard_y_axis) model_mat_face_camera_position(cam, &mat, &mat); get_obj_center(mat, &i->args.sub_mesh, center); v50 = !!i->args.sub_mesh.material->material.attrib.m.flag_30; i->radius = i->args.sub_mesh.mesh->bounding_sphere.radius; } break; case OBJ_KIND_ETC: case OBJ_KIND_USER: mat4_get_translation(&i->mat, ¢er); break; case OBJ_KIND_TRANSLUCENT: vec3 center_sum = 0.0f; for (int32_t j = 0; j < i->args.translucent.count; j++) { vec3 _center = 0.0f; get_obj_center(i->mat, i->args.translucent.sub_mesh[j], _center); if (i->args.translucent.sub_mesh[j]->material->material.attrib.m.flag_30) { v50 = true; break; } center_sum += _center; } if (!v50) center = center_sum * (1.0f / (float_t)i->args.translucent.count); break; } if (show_alpha_center && type == OBJ_TYPE_TRANSLUCENT) alpha_center.push_back(center); if (show_mat_center && type == OBJ_TYPE_TRANSLUCENT && v50) mat_center.push_back(center); mat4_transform_point(&cam.get_view_mat(), ¢er, ¢er); i->view_z = center.z; } if (show_alpha_center && type == OBJ_TYPE_TRANSLUCENT) for (vec3& i : alpha_center) { mdl::EtcObj etc(ETC_OBJ_SPHERE); etc.color = { 0xFF, 0x00, 0x00, 0xFF }; etc.data.sphere.radius = 0.05f; etc.data.sphere.slices = 8; etc.data.sphere.stacks = 8; etc.data.sphere.wire = false; mat4 mat; mat4_translate(&i, &mat); mat4_transpose(&mat, &mat); entry_obj_etc(mat, etc); } if (show_mat_center && type == OBJ_TYPE_TRANSLUCENT) for (vec3& i : alpha_center) { mdl::EtcObj etc(ETC_OBJ_SPHERE); etc.color = { 0x00, 0x00, 0xFF, 0xFF }; etc.data.sphere.radius = 0.05f; etc.data.sphere.slices = 8; etc.data.sphere.stacks = 8; etc.data.sphere.wire = false; mat4 mat; mat4_translate(&i, &mat); mat4_transpose(&mat, &mat); entry_obj_etc(mat, etc); } } void DispManager::calc_obj_radius(const cam_data& cam, ObjTypeLocal type) { for (ObjData*& i : get_obj_list(type)) { vec3 center = 0.0f; bool v50 = false; switch (i->kind) { case OBJ_KIND_NORMAL: { mat4 mat = i->mat; if (i->args.sub_mesh.mesh->attrib.m.billboard) model_mat_face_camera_view(cam, &mat, &mat); else if (i->args.sub_mesh.mesh->attrib.m.billboard_y_axis) model_mat_face_camera_position(cam, &mat, &mat); get_obj_center(mat, &i->args.sub_mesh, center); v50 = !!i->args.sub_mesh.material->material.attrib.m.flag_30; i->radius = i->args.sub_mesh.mesh->bounding_sphere.radius; } break; case OBJ_KIND_TRANSLUCENT: vec3 center_sum = 0.0f; for (int32_t j = 0; j < i->args.translucent.count; j++) { vec3 _center = 0.0f; get_obj_center(i->mat, i->args.translucent.sub_mesh[j], _center); if (i->args.translucent.sub_mesh[j]->material->material.attrib.m.flag_30) { v50 = true; break; } center_sum += _center; } if (!v50) center = center_sum * (1.0f / (float_t)i->args.translucent.count); break; } mat4_transform_point(&cam.get_view_mat(), ¢er, ¢er); i->view_z = center.z; } } void DispManager::calc_obj_radius(const cam_data& cam, ObjTypeReflect type) { for (ObjData*& i : get_obj_list(type)) { vec3 center = 0.0f; bool v50 = false; switch (i->kind) { case OBJ_KIND_NORMAL: { mat4 mat = i->mat; if (i->args.sub_mesh.mesh->attrib.m.billboard) model_mat_face_camera_view(cam, &mat, &mat); else if (i->args.sub_mesh.mesh->attrib.m.billboard_y_axis) model_mat_face_camera_position(cam, &mat, &mat); get_obj_center(mat, &i->args.sub_mesh, center); v50 = !!i->args.sub_mesh.material->material.attrib.m.flag_30; i->radius = i->args.sub_mesh.mesh->bounding_sphere.radius; } break; case OBJ_KIND_TRANSLUCENT: vec3 center_sum = 0.0f; for (int32_t j = 0; j < i->args.translucent.count; j++) { vec3 _center = 0.0f; get_obj_center(i->mat, i->args.translucent.sub_mesh[j], _center); if (i->args.translucent.sub_mesh[j]->material->material.attrib.m.flag_30) { v50 = true; break; } center_sum += _center; } if (!v50) center = center_sum * (1.0f / (float_t)i->args.translucent.count); break; } mat4_transform_point(&cam.get_view_mat(), ¢er, ¢er); i->view_z = center.z; } } void DispManager::check_index_buffer(GLuint buffer) { for (DispManager::vertex_array& i : vertex_array_cache) if (i.alive_time > 0 && i.index_buffer == buffer) i.reset_vertex_attrib(); } void DispManager::check_vertex_arrays() { for (DispManager::vertex_array& i : vertex_array_cache) if (i.alive_time > 0 && --i.alive_time <= 0) i.reset_vertex_attrib(); for (DispManager::etc_vertex_array& i : etc_vertex_array_cache) if (i.alive_time > 0 && --i.alive_time <= 0) { gl_state.bind_vertex_array(i.vertex_array); glDisableVertexAttribArray(POSITION_INDEX); glDisableVertexAttribArray(NORMAL_INDEX); gl_state.bind_array_buffer(0); if (i.indexed) gl_state.bind_element_array_buffer(0); gl_state.bind_vertex_array(0); } } void DispManager::check_vertex_buffer(GLuint buffer) { for (DispManager::vertex_array& i : vertex_array_cache) if (i.alive_time > 0 && (i.vertex_buffer == buffer || i.morph_vertex_buffer == buffer)) i.reset_vertex_attrib(); } void DispManager::draw(render_data_context& rend_data_ctx, ObjType type, const cam_data& cam, int32_t depth_mask, bool reflect_texture_mask, int32_t alpha) { if (type < 0 || type >= OBJ_TYPE_MAX || get_obj_count(type) < 1) return; int32_t alpha_test = 0; float_t min_alpha = 1.0f; float_t alpha_threshold = 0.0f; bool reflect = rend_data_ctx.shader_flags.arr[U_REFLECT] == 1; void(*func)(render_data_context & rend_data_ctx, const ObjSubMeshArgs * args, const cam_data & cam, const mat4 * mat) = draw_sub_mesh_default; for (int32_t i = 0; i < 5; i++) rend_data_ctx.state.active_bind_texture_2d(i, rctx->empty_texture_2d->glid); rend_data_ctx.state.active_bind_texture_cube_map(5, rctx->empty_texture_cube_map->glid); rend_data_ctx.state.active_texture(0); rend_data_ctx.state.set_blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); rend_data_ctx.reset_shader_flags(); switch (type) { case OBJ_TYPE_TRANSLUCENT: case OBJ_TYPE_TRANSLUCENT_SORT_BY_RADIUS: if (depth_mask) func = draw_sub_mesh_no_mat; else rend_data_ctx.state.set_depth_mask(GL_FALSE); alpha_test = 1; min_alpha = 0.0f; alpha_threshold = 0.0f; break; case OBJ_TYPE_TRANSPARENT: alpha_test = 1; min_alpha = 0.1f; alpha_threshold = 0.5f; break; case OBJ_TYPE_SHADOW_CHARA: case OBJ_TYPE_SHADOW_STAGE: case OBJ_TYPE_SHADOW_OBJECT_CHARA: case OBJ_TYPE_SHADOW_OBJECT_STAGE: func = draw_sub_mesh_shadow; break; case OBJ_TYPE_TYPE_6: func = draw_sub_mesh_no_mat; rend_data_ctx.state.set_color_mask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); rctx->draw_state_rend_data[rend_data_ctx.index].shader_index = SHADER_FT_SIL; break; case OBJ_TYPE_TYPE_7: func = draw_sub_mesh_no_mat; rend_data_ctx.state.set_color_mask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); rctx->draw_state_rend_data[rend_data_ctx.index].shader_index = SHADER_FT_SIL; alpha_test = 1; min_alpha = 0.0f; alpha_threshold = 0.99999994f; break; case OBJ_TYPE_REFLECT_CHARA_OPAQUE: rend_data_ctx.state.set_cull_face_mode(GL_FRONT); if (!reflect_draw) { if (reflect) func = draw_sub_mesh_cheap; else if (render_manager.reflect_type == STAGE_DATA_REFLECT_REFLECT_MAP) func = draw_sub_mesh_cheap_reflect_map; } break; case OBJ_TYPE_REFLECT_CHARA_TRANSLUCENT: rend_data_ctx.state.set_cull_face_mode(GL_FRONT); min_alpha = 0.0f; if (!reflect_draw) { if (reflect) func = draw_sub_mesh_cheap; else if (render_manager.reflect_type == STAGE_DATA_REFLECT_REFLECT_MAP) func = draw_sub_mesh_cheap_reflect_map; } break; case OBJ_TYPE_REFLECT_CHARA_TRANSPARENT: rend_data_ctx.state.set_cull_face_mode(GL_FRONT); alpha_test = 1; min_alpha = 0.1f; alpha_threshold = 0.5f; if (!reflect_draw) { if (reflect) func = draw_sub_mesh_cheap; else if (render_manager.reflect_type == STAGE_DATA_REFLECT_REFLECT_MAP) func = draw_sub_mesh_cheap_reflect_map; } break; case OBJ_TYPE_REFLECT_OPAQUE: alpha_test = 1; alpha_threshold = 0.5f; if (reflect_draw) rend_data_ctx.state.set_cull_face_mode(GL_FRONT); else if (!reflect_texture_mask) func = draw_sub_mesh_cheap_reflect_map; break; case OBJ_TYPE_REFLECT_TRANSLUCENT: rend_data_ctx.state.set_depth_mask(GL_FALSE); min_alpha = 0.0f; alpha_threshold = 0.0f; if (reflect_draw) rend_data_ctx.state.set_cull_face_mode(GL_FRONT); break; case OBJ_TYPE_REFLECT_TRANSPARENT: alpha_test = 1; min_alpha = 0.1f; alpha_threshold = 0.5f; if (reflect_draw) rend_data_ctx.state.set_cull_face_mode(GL_FRONT); break; case OBJ_TYPE_REFRACT_TRANSLUCENT: rend_data_ctx.state.set_depth_mask(GL_FALSE); min_alpha = 0.0f; alpha_threshold = 0.0f; break; case OBJ_TYPE_REFRACT_TRANSPARENT: alpha_test = 1; min_alpha = 0.1f; alpha_threshold = 0.5f; break; case OBJ_TYPE_SSS: func = draw_sub_mesh_sss; if (reflect_draw) rend_data_ctx.state.set_cull_face_mode(GL_FRONT); break; case OBJ_TYPE_OPAQUE_ALPHA_ORDER_POST_GLITTER: case OBJ_TYPE_OPAQUE_ALPHA_ORDER_POST_TRANSLUCENT: case OBJ_TYPE_OPAQUE_ALPHA_ORDER_POST_OPAQUE: if (reflect_draw) rend_data_ctx.state.set_cull_face_mode(GL_FRONT); break; case OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_POST_GLITTER: case OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_POST_TRANSLUCENT: case OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_POST_OPAQUE: alpha_test = 1; min_alpha = 0.1f; alpha_threshold = 0.5f; if (reflect_draw) rend_data_ctx.state.set_cull_face_mode(GL_FRONT); break; case OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_POST_GLITTER: case OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_POST_TRANSLUCENT: case OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_POST_OPAQUE: rend_data_ctx.state.set_depth_mask(GL_FALSE); alpha_test = 1; min_alpha = 0.0f; alpha_threshold = 0.0f; if (reflect_draw) rend_data_ctx.state.set_cull_face_mode(GL_FRONT); break; case OBJ_TYPE_USER: func = draw_sub_mesh_no_mat; break; } rend_data_ctx.set_batch_alpha_threshold(alpha_threshold); rend_data_ctx.set_batch_min_alpha(min_alpha); rend_data_ctx.shader_flags.arr[U_ALPHA_TEST] = alpha_test; if (alpha < 0) for (ObjData*& i : get_obj_list(type)) { switch (i->kind) { case OBJ_KIND_NORMAL: { draw_sub_mesh(rend_data_ctx, &i->args.sub_mesh, &i->mat, func, cam); } break; case OBJ_KIND_ETC: { draw_etc_obj(rend_data_ctx, &i->args.etc, &i->mat); } break; case OBJ_KIND_USER: { i->args.user.func(rend_data_ctx, i->args.user.data, cam, &i->mat); } break; case OBJ_KIND_TRANSLUCENT: { for (int32_t j = 0; j < i->args.translucent.count; j++) draw_sub_mesh(rend_data_ctx, i->args.translucent.sub_mesh[j], &i->mat, func, cam); } break; } } else for (ObjData*& i : get_obj_list(type)) { switch (i->kind) { case OBJ_KIND_NORMAL: { int32_t a = (int32_t)(i->args.sub_mesh.blend_color.w * 255.0f); a = clamp_def(a, 0, 255); if (a == alpha) draw_sub_mesh(rend_data_ctx, &i->args.sub_mesh, &i->mat, func, cam); } break; case OBJ_KIND_TRANSLUCENT: { for (int32_t j = 0; j < i->args.translucent.count; j++) { ObjSubMeshArgs* args = i->args.translucent.sub_mesh[j]; int32_t a = (int32_t)(args->blend_color.w * 255.0f); a = clamp_def(a, 0, 255); if (a == alpha) draw_sub_mesh(rend_data_ctx, args, &i->mat, func, cam); } } break; } } switch (type) { case OBJ_TYPE_TRANSLUCENT: case OBJ_TYPE_TRANSLUCENT_SORT_BY_RADIUS: if (!depth_mask) rend_data_ctx.state.set_depth_mask(GL_TRUE); break; case OBJ_TYPE_TYPE_6: case OBJ_TYPE_TYPE_7: rctx->draw_state_rend_data[rend_data_ctx.index].shader_index = -1; rend_data_ctx.state.set_color_mask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE); break; case OBJ_TYPE_REFLECT_CHARA_OPAQUE: case OBJ_TYPE_REFLECT_CHARA_TRANSLUCENT: case OBJ_TYPE_REFLECT_CHARA_TRANSPARENT: rend_data_ctx.state.set_cull_face_mode(GL_BACK); break; case OBJ_TYPE_REFLECT_OPAQUE: if (reflect_draw) rend_data_ctx.state.set_cull_face_mode(GL_BACK); break; case OBJ_TYPE_REFLECT_TRANSLUCENT: if (reflect_draw) rend_data_ctx.state.set_cull_face_mode(GL_BACK); rend_data_ctx.state.set_depth_mask(GL_TRUE); break; case OBJ_TYPE_REFLECT_TRANSPARENT: if (reflect_draw) rend_data_ctx.state.set_cull_face_mode(GL_BACK); break; case OBJ_TYPE_REFRACT_TRANSLUCENT: if (reflect_draw) rend_data_ctx.state.set_cull_face_mode(GL_BACK); rend_data_ctx.state.set_depth_mask(GL_TRUE); break; case OBJ_TYPE_SSS: if (reflect_draw) rend_data_ctx.state.set_cull_face_mode(GL_BACK); break; case OBJ_TYPE_OPAQUE_ALPHA_ORDER_POST_GLITTER: case OBJ_TYPE_OPAQUE_ALPHA_ORDER_POST_TRANSLUCENT: case OBJ_TYPE_OPAQUE_ALPHA_ORDER_POST_OPAQUE: if (reflect_draw) rend_data_ctx.state.set_cull_face_mode(GL_BACK); break; case OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_POST_GLITTER: case OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_POST_TRANSLUCENT: case OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_POST_OPAQUE: if (reflect_draw) rend_data_ctx.state.set_cull_face_mode(GL_BACK); break; case OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_POST_GLITTER: case OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_POST_TRANSLUCENT: case OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_POST_OPAQUE: rend_data_ctx.state.set_depth_mask(GL_TRUE); if (reflect_draw) rend_data_ctx.state.set_cull_face_mode(GL_BACK); break; } rend_data_ctx.reset_shader_flags(); rend_data_ctx.state.bind_vertex_array(0); shader::unbind(rend_data_ctx.state); rend_data_ctx.state.set_blend_func(GL_ONE, GL_ZERO); for (int32_t i = 0; i < 5; i++) rend_data_ctx.state.bind_sampler(i, 0); } void DispManager::draw(render_data_context& rend_data_ctx, mdl::ObjTypeLocal type, const cam_data& cam, int32_t depth_mask, bool reflect_texture_mask, int32_t alpha) { if (type < 0 || type >= OBJ_TYPE_LOCAL_MAX || get_obj_count(type) < 1) return; int32_t alpha_test = 0; float_t min_alpha = 1.0f; float_t alpha_threshold = 0.0f; void(*func)(render_data_context & rend_data_ctx, const ObjSubMeshArgs * args, const cam_data & cam, const mat4 * mat) = draw_sub_mesh_default; for (int32_t i = 0; i < 5; i++) rend_data_ctx.state.active_bind_texture_2d(i, rctx->empty_texture_2d->glid); rend_data_ctx.state.active_bind_texture_cube_map(5, rctx->empty_texture_cube_map->glid); rend_data_ctx.state.active_texture(0); rend_data_ctx.state.set_blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); rend_data_ctx.reset_shader_flags(); switch (type) { case OBJ_TYPE_LOCAL_TRANSLUCENT: if (depth_mask) func = draw_sub_mesh_no_mat; else rend_data_ctx.state.set_depth_mask(GL_FALSE); alpha_test = 1; min_alpha = 0.0f; alpha_threshold = 0.0f; break; case OBJ_TYPE_LOCAL_TRANSPARENT: alpha_test = 1; min_alpha = 0.1f; alpha_threshold = 0.5f; break; case OBJ_TYPE_LOCAL_TRANSPARENT_ALPHA_ORDER_POST_TRANSLUCENT: alpha_test = 1; min_alpha = 0.1f; alpha_threshold = 0.5f; if (reflect_draw) rend_data_ctx.state.set_cull_face_mode(GL_FRONT); break; case OBJ_TYPE_LOCAL_TRANSLUCENT_ALPHA_ORDER_POST_TRANSLUCENT: rend_data_ctx.state.set_depth_mask(GL_FALSE); alpha_test = 1; min_alpha = 0.0f; alpha_threshold = 0.0f; if (reflect_draw) rend_data_ctx.state.set_cull_face_mode(GL_FRONT); break; } rend_data_ctx.set_batch_alpha_threshold(alpha_threshold); rend_data_ctx.set_batch_min_alpha(min_alpha); rend_data_ctx.shader_flags.arr[U_ALPHA_TEST] = alpha_test; if (alpha < 0) for (ObjData*& i : get_obj_list(type)) { switch (i->kind) { case OBJ_KIND_NORMAL: { draw_sub_mesh(rend_data_ctx, &i->args.sub_mesh, &i->mat, func, cam); } break; case OBJ_KIND_TRANSLUCENT: { for (int32_t j = 0; j < i->args.translucent.count; j++) draw_sub_mesh(rend_data_ctx, i->args.translucent.sub_mesh[j], &i->mat, func, cam); } break; } } else for (ObjData*& i : get_obj_list(type)) { switch (i->kind) { case OBJ_KIND_NORMAL: { int32_t a = (int32_t)(i->args.sub_mesh.blend_color.w * 255.0f); a = clamp_def(a, 0, 255); if (a == alpha) draw_sub_mesh(rend_data_ctx, &i->args.sub_mesh, &i->mat, func, cam); } break; case OBJ_KIND_TRANSLUCENT: { for (int32_t j = 0; j < i->args.translucent.count; j++) { ObjSubMeshArgs* args = i->args.translucent.sub_mesh[j]; int32_t a = (int32_t)(args->blend_color.w * 255.0f); a = clamp_def(a, 0, 255); if (a == alpha) draw_sub_mesh(rend_data_ctx, args, &i->mat, func, cam); } } break; } } switch (type) { case OBJ_TYPE_LOCAL_TRANSLUCENT: if (!depth_mask) rend_data_ctx.state.set_depth_mask(GL_TRUE); break; case OBJ_TYPE_LOCAL_TRANSPARENT_ALPHA_ORDER_POST_TRANSLUCENT: if (reflect_draw) rend_data_ctx.state.set_cull_face_mode(GL_BACK); break; case OBJ_TYPE_LOCAL_TRANSLUCENT_ALPHA_ORDER_POST_TRANSLUCENT: rend_data_ctx.state.set_depth_mask(GL_TRUE); if (reflect_draw) rend_data_ctx.state.set_cull_face_mode(GL_BACK); break; } rend_data_ctx.reset_shader_flags(); rend_data_ctx.state.bind_vertex_array(0); shader::unbind(rend_data_ctx.state); rend_data_ctx.state.set_blend_func(GL_ONE, GL_ZERO); for (int32_t i = 0; i < 5; i++) rend_data_ctx.state.bind_sampler(i, 0); } void DispManager::draw(render_data_context& rend_data_ctx, mdl::ObjTypeReflect type, const cam_data& cam, int32_t depth_mask, bool reflect_texture_mask) { if (type < 0 || type >= OBJ_TYPE_REFLECT_MAX || get_obj_count(type) < 1) return; int32_t alpha_test = 0; float_t min_alpha = 1.0f; float_t alpha_threshold = 0.0f; bool reflect = rend_data_ctx.shader_flags.arr[U_REFLECT] == 1; void(*func)(render_data_context & rend_data_ctx, const ObjSubMeshArgs * args, const cam_data & cam, const mat4 * mat) = draw_sub_mesh_default; for (int32_t i = 0; i < 5; i++) rend_data_ctx.state.active_bind_texture_2d(i, rctx->empty_texture_2d->glid); rend_data_ctx.state.active_bind_texture_cube_map(5, rctx->empty_texture_cube_map->glid); rend_data_ctx.state.active_texture(0); rend_data_ctx.state.set_blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); rend_data_ctx.reset_shader_flags(); switch (type) { case OBJ_TYPE_REFLECT_TRANSLUCENT_SORT_BY_RADIUS: if (depth_mask) func = draw_sub_mesh_no_mat; else rend_data_ctx.state.set_depth_mask(GL_FALSE); alpha_test = 1; min_alpha = 0.0f; alpha_threshold = 0.0f; rend_data_ctx.state.set_cull_face_mode(GL_FRONT); break; } rend_data_ctx.set_batch_alpha_threshold(alpha_threshold); rend_data_ctx.set_batch_min_alpha(min_alpha); rend_data_ctx.shader_flags.arr[U_ALPHA_TEST] = alpha_test; for (ObjData*& i : get_obj_list(type)) { switch (i->kind) { case OBJ_KIND_NORMAL: { draw_sub_mesh(rend_data_ctx, &i->args.sub_mesh, &i->mat, func, cam); } break; case OBJ_KIND_TRANSLUCENT: { for (int32_t j = 0; j < i->args.translucent.count; j++) draw_sub_mesh(rend_data_ctx, i->args.translucent.sub_mesh[j], &i->mat, func, cam); } break; } } switch (type) { case OBJ_TYPE_REFLECT_TRANSLUCENT_SORT_BY_RADIUS: if (!depth_mask) rend_data_ctx.state.set_cull_face_mode(GL_BACK); break; } rend_data_ctx.reset_shader_flags(); rend_data_ctx.state.bind_vertex_array(0); shader::unbind(rend_data_ctx.state); rend_data_ctx.state.set_blend_func(GL_ONE, GL_ZERO); for (int32_t i = 0; i < 5; i++) rend_data_ctx.state.bind_sampler(i, 0); } /*void DispManager::draw_show_vector(ObjType type, int32_t show_vector) { if (get_obj_count(type) < 1) return; render_context* rctx = rctx_ptr; for (int32_t i = 0; i < 5; i++) rend_data_ctx.state.active_bind_texture_2d(i, rctx->empty_texture_2d->glid); rend_data_ctx.state.active_bind_texture_cube_map(5, rctx->empty_texture_cube_map->glid); rend_data_ctx.state.active_texture(0); rend_data_ctx.state.set_blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); rend_data_ctx.reset_shader_flags(); rend_data_ctx.state.get(); for (ObjData*& i : get_obj_list(type)) { switch (i->type) { case OBJ_KIND_NORMAL: { draw_sub_mesh_show_vector(&i->args.sub_mesh, &i->mat, show_vector); } break; case OBJ_KIND_TRANSLUCENT: { for (int32_t j = 0; j < i->args.translucent.count; j++) draw_sub_mesh_show_vector(i->args.translucent.sub_mesh[j], &i->mat, show_vector); } break; } } rend_data_ctx.state.set_blend_func(GL_ONE, GL_ZERO); }*/ void DispManager::entry_list(ObjType type, ObjData* data) { get_obj_list(type).push_back(data); } void DispManager::entry_list(ObjTypeLocal type, ObjData* data) { get_obj_list(type).push_back(data); } void DispManager::entry_list(ObjTypeReflect type, ObjData* data) { get_obj_list(type).push_back(data); } static int32_t obj_bounding_sphere_check_visibility_default(const vec3& center, float_t radius) { mat4 view_mat; mat4_transpose(&camera_data.view, &view_mat); vec3 _center; mat4_transform_point(&view_mat, ¢er, &_center); double_t min_depth = (double_t)_center.z - (double_t)radius; double_t max_depth = (double_t)_center.z + (double_t)radius; if (-camera_data.min_distance < min_depth || -camera_data.max_distance > max_depth) return 0; float_t v5 = vec3::dot(camera_data.field_1E4, _center); if (v5 < -radius) return 0; float_t v6 = vec3::dot(camera_data.field_1F0, _center); if (v6 < -radius) return 0; float_t v7 = vec3::dot(camera_data.field_1FC, _center); if (v7 < -radius) return 0; float_t v8 = vec3::dot(camera_data.field_208, _center); if (v8 < -radius) return 0; if (-camera_data.min_distance >= max_depth && -camera_data.max_distance <= min_depth && v5 >= radius && v6 >= radius && v7 >= radius && v8 >= radius) return 1; return 2; } static int32_t obj_bounding_sphere_check_visibility(const obj_bounding_sphere& sphere, const mat4& mat) { if (disp_manager->culling_func) return disp_manager->culling_func(&sphere); vec3 center; mat4 _mat; mat4_transpose(&mat, &_mat); mat4_transform_point(&_mat, &sphere.center, ¢er); return obj_bounding_sphere_check_visibility_default(center, mat4_get_max_scale(&_mat) * sphere.radius); } static int32_t obj_axis_aligned_bounding_box_check_visibility_default( const obj_axis_aligned_bounding_box* aabb, const mat4& mat) { vec3 points[8]; points[0] = aabb->center + (aabb->size ^ vec3( 0.0f, 0.0f, 0.0f)); points[1] = aabb->center + (aabb->size ^ vec3(-0.0f, -0.0f, -0.0f)); points[2] = aabb->center + (aabb->size ^ vec3(-0.0f, 0.0f, 0.0f)); points[3] = aabb->center + (aabb->size ^ vec3( 0.0f, -0.0f, -0.0f)); points[4] = aabb->center + (aabb->size ^ vec3( 0.0f, -0.0f, 0.0f)); points[5] = aabb->center + (aabb->size ^ vec3(-0.0f, 0.0f, -0.0f)); points[6] = aabb->center + (aabb->size ^ vec3( 0.0f, 0.0f, -0.0f)); points[7] = aabb->center + (aabb->size ^ vec3(-0.0f, -0.0f, 0.0f)); mat4 view_mat; mat4_mul(&camera_data.view, &mat, &view_mat); mat4_transpose(&view_mat, &view_mat); for (int32_t i = 0; i < 8; i++) mat4_transform_point(&view_mat, &points[i], &points[i]); vec4 v2[6]; *(vec3*)&v2[0] = { 0.0f, 0.0f, -1.0f }; v2[0].w = -camera_data.min_distance; *(vec3*)&v2[1] = camera_data.field_1E4; v2[1].w = 0.0f; *(vec3*)&v2[2] = camera_data.field_1F0; v2[2].w = 0.0f; *(vec3*)&v2[3] = camera_data.field_1FC; v2[3].w = 0.0f; *(vec3*)&v2[4] = camera_data.field_208; v2[4].w = 0.0f; *(vec3*)&v2[5] = { 0.0f, 0.0f, 1.0f }; v2[5].w = camera_data.max_distance; for (int32_t i = 0; i < 6; i++) for (int32_t j = 0; j < 8; j++) { float_t v34 = vec3::dot(*(vec3*)&v2[i], points[j]) + v2[i].w; if (v34 > 0.0f) break; if (j == 7) return 0; } return 1; } static int32_t obj_axis_aligned_bounding_box_check_visibility( const obj_axis_aligned_bounding_box* aabb, const mat4& mat) { if (disp_manager->culling_func) return 1; return obj_axis_aligned_bounding_box_check_visibility_default(aabb, mat); } bool DispManager::entry_obj(const ::obj* obj, const mat4& mat, obj_mesh_vertex_buffer_divagl* obj_vert_buf, obj_mesh_index_buffer* obj_index_buf, const prj::vector* textures, const vec4* blend_color, const mat4* bone_mat, const ::obj* obj_morph, obj_mesh_vertex_buffer_divagl* obj_morph_vert_buf, int32_t instances_count, const mat4* instances_mat, draw_func func, const ObjSubMeshArgs* func_data, bool enable_bone_mat) { if (!obj_vert_buf || !obj_index_buf) return false; mat4 _mat; if (mdl::obj_reflect_enable) { mat4_transpose(&mat, &_mat); mat4_mul(&_mat, &reflect_mat, &_mat); mat4_transpose(&_mat, &_mat); } if (object_culling && !instances_count && !bone_mat && (!obj || !obj_bounding_sphere_check_visibility(obj->bounding_sphere, mat) && !(mdl::obj_reflect_enable && obj_bounding_sphere_check_visibility(obj->bounding_sphere, _mat)))) { culling.culled.objects++; return false; } culling.passed.objects++; for (int32_t i = 0; i < obj->num_mesh; i++) { const obj_mesh* mesh = &obj->mesh_array[i]; const obj_mesh* mesh_morph = 0; if (obj_vert_buf && obj_morph_vert_buf) { if (obj_vert_buf[i].get_size() != obj_morph_vert_buf[i].get_size()) continue; if (obj_morph && i < obj_morph->num_mesh) mesh_morph = &obj_morph->mesh_array[i]; } if (object_culling && !instances_count && !bone_mat && !obj_bounding_sphere_check_visibility(mesh->bounding_sphere, mat) && (!mesh_morph || !obj_bounding_sphere_check_visibility(mesh_morph->bounding_sphere, mat))) { culling.culled.meshes++; continue; } culling.passed.meshes++; ObjSubMeshArgs* translucent_priority[40]; int32_t translucent_priority_count = 0; for (int32_t j = 0; j < mesh->num_submesh; j++) { const obj_sub_mesh* sub_mesh = &mesh->submesh_array[j]; const obj_sub_mesh* sub_mesh_morph = 0; if (sub_mesh->attrib.m.cloth) continue; if (object_culling && !instances_count && !bone_mat) { int32_t v32 = obj_bounding_sphere_check_visibility(sub_mesh->bounding_sphere, mat); if (v32 != 2 || (!mesh->attrib.m.billboard && !mesh->attrib.m.billboard_y_axis && !mesh->attrib.m.disable_aabb_culling)) { if (v32 == 2) v32 = obj_axis_aligned_bounding_box_check_visibility( sub_mesh->axis_aligned_bounding_box, mat); if (!v32) { if (!mesh_morph || j >= mesh_morph->num_submesh) { culling.culled.sub_meshes++; continue; } sub_mesh_morph = &mesh_morph->submesh_array[j]; if (!sub_mesh_morph) { culling.culled.sub_meshes++; continue; } int32_t v32 = obj_bounding_sphere_check_visibility(sub_mesh_morph->bounding_sphere, mat); if (v32 == 2) v32 = obj_axis_aligned_bounding_box_check_visibility( sub_mesh_morph->axis_aligned_bounding_box, mat); if (!v32) { culling.culled.sub_meshes++; continue; } } } } culling.passed.sub_meshes++; int32_t num_bone_index = sub_mesh->num_bone_index; const uint16_t* bone_index = sub_mesh->bone_index_array; mat4* mats; if (num_bone_index && enable_bone_mat) { mats = alloc_mat4_array(num_bone_index); if (bone_mat) for (int32_t k = 0; k < num_bone_index; k++, bone_index++) mat4_transpose(&bone_mat[*bone_index], &mats[k]); else for (int32_t k = 0; k < num_bone_index; k++) mats[k] = mat4_identity; } else { mats = 0; num_bone_index = 0; } obj_material_data* material = &obj->material_array[sub_mesh->material_index]; ObjData* data = alloc_obj_data(OBJ_KIND_NORMAL); if (!data) continue; GLuint morph_vertex_buffer = 0; size_t morph_vertex_buffer_offset = 0; if (obj_morph_vert_buf) { morph_vertex_buffer = obj_morph_vert_buf[i].get_buffer(); morph_vertex_buffer_offset = obj_morph_vert_buf[i].get_offset(); } GLuint index_buffer = 0; if (obj_index_buf) index_buffer = obj_index_buf[i].buffer; GLuint vertex_buffer = 0; size_t vertex_buffer_offset = 0; if (obj_vert_buf) { vertex_buffer = obj_vert_buf[i].get_buffer(); vertex_buffer_offset = obj_vert_buf[i].get_offset(); } if (!vertex_buffer || !index_buffer || obj_morph_vert_buf && !morph_vertex_buffer) continue; const uint64_t material_hash = hash_utf8_fnv1a64m(material->material.name); material_list_struct* mat_list = 0; for (int32_t k = 0; k < material_list_count; k++) if (material_list_array[k].hash == material_hash) { mat_list = &material_list_array[k]; break; } vec4 _blend_color = 1.0f; vec4 _emission = { 0.0f, 0.0f, 0.0f, 1.0f }; if (mat_list) { bool has_blend_color = false; if (mat_list->has_blend_color.x) { _blend_color.x = mat_list->blend_color.x; has_blend_color = true; } if (mat_list->has_blend_color.y) { _blend_color.y = mat_list->blend_color.y; has_blend_color = true; } if (mat_list->has_blend_color.z) { _blend_color.z = mat_list->blend_color.z; has_blend_color = true; } if (mat_list->has_blend_color.w) { _blend_color.w = mat_list->blend_color.w; has_blend_color = true; } if (blend_color) { if (!has_blend_color) _blend_color = *blend_color; else _blend_color *= *blend_color; } bool has_emission = false; if (mat_list->has_emission.x) { _emission.x = mat_list->emission.x; has_emission = true; } if (mat_list->has_emission.y) { _emission.y = mat_list->emission.y; has_emission = true; } if (mat_list->has_emission.z) { _emission.z = mat_list->emission.z; has_emission = true; } if (mat_list->has_emission.w) { _emission.w = mat_list->emission.w; has_emission = true; } if (!has_emission) _emission = material->material.color.emission; } else { if (blend_color) _blend_color = *blend_color; _emission = material->material.color.emission; } data->init_sub_mesh(mat, obj->bounding_sphere.radius, sub_mesh, mesh, material, textures, num_bone_index, mats, vertex_buffer, vertex_buffer_offset, index_buffer, _blend_color, _emission, morph_vertex_buffer, morph_vertex_buffer_offset, instances_count, instances_mat, func, func_data); if (obj_flags & mdl::OBJ_SHADOW_OBJECT) { entry_list((ObjType)(OBJ_TYPE_SHADOW_OBJECT_CHARA + shadow_type), data); if (obj_flags & mdl::OBJ_USER) entry_list(OBJ_TYPE_USER, data); continue; } const obj_material_attrib_member attrib = material->material.attrib.m; if ((obj_flags & mdl::OBJ_ALPHA_ORDER) && data->args.sub_mesh.blend_color.w < 1.0f) { if (!(obj_flags & mdl::OBJ_NO_TRANSLUCENCY)) { if (attrib.flag_28 || (attrib.punch_through || !(attrib.alpha_texture | attrib.alpha_material)) && !sub_mesh->attrib.m.translucent) { if (!attrib.punch_through) { if (obj_flags & mdl::OBJ_ALPHA_ORDER_POST_GLITTER) entry_list(OBJ_TYPE_OPAQUE_ALPHA_ORDER_POST_GLITTER, data); else if (obj_flags & mdl::OBJ_ALPHA_ORDER_POST_TRANSLUCENT) entry_list(OBJ_TYPE_OPAQUE_ALPHA_ORDER_POST_TRANSLUCENT, data); else entry_list(OBJ_TYPE_OPAQUE_ALPHA_ORDER_POST_OPAQUE, data); } else { if (obj_flags & mdl::OBJ_ALPHA_ORDER_POST_GLITTER) entry_list(OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_POST_GLITTER, data); else if (obj_flags & mdl::OBJ_ALPHA_ORDER_POST_TRANSLUCENT) entry_list(OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_POST_TRANSLUCENT, data); else entry_list(OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_POST_OPAQUE, data); } if (obj_flags & mdl::OBJ_SSS) entry_list(OBJ_TYPE_SSS, data); } else { if (!attrib.translucent_priority) { if (obj_flags & mdl::OBJ_ALPHA_ORDER_POST_GLITTER) entry_list(OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_POST_GLITTER, data); else if (obj_flags & mdl::OBJ_ALPHA_ORDER_POST_TRANSLUCENT) entry_list(OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_POST_TRANSLUCENT, data); else entry_list(OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_POST_OPAQUE, data); } else if (translucent_priority_count < 40) translucent_priority[translucent_priority_count++] = &data->args.sub_mesh; } } } else { if (attrib.flag_28 || data->args.sub_mesh.blend_color.w >= 1.0f && (attrib.punch_through || !(attrib.alpha_texture | attrib.alpha_material)) && !sub_mesh->attrib.m.translucent) { if (obj_flags & mdl::OBJ_SHADOW) entry_list((ObjType)(OBJ_TYPE_SHADOW_CHARA + shadow_type), data); if (obj_flags & mdl::OBJ_SSS) entry_list(OBJ_TYPE_SSS, data); if (attrib.punch_through) { if (!(obj_flags & mdl::OBJ_NO_TRANSLUCENCY)) entry_list(OBJ_TYPE_TRANSPARENT, data); if (obj_flags & mdl::OBJ_CHARA_REFLECT) entry_list(OBJ_TYPE_REFLECT_CHARA_OPAQUE, data); if (obj_flags & mdl::OBJ_REFLECT) entry_list(OBJ_TYPE_REFLECT_OPAQUE, data); if (obj_flags & mdl::OBJ_REFRACT) entry_list(OBJ_TYPE_REFRACT_TRANSPARENT, data); } else { if (!(obj_flags & mdl::OBJ_NO_TRANSLUCENCY)) entry_list(OBJ_TYPE_OPAQUE, data); if (obj_flags & mdl::OBJ_20) entry_list(OBJ_TYPE_TYPE_6, data); if (obj_flags & mdl::OBJ_CHARA_REFLECT) entry_list(OBJ_TYPE_REFLECT_CHARA_OPAQUE, data); if (obj_flags & mdl::OBJ_REFLECT) entry_list(OBJ_TYPE_REFLECT_OPAQUE, data); if (obj_flags & mdl::OBJ_REFRACT) entry_list(OBJ_TYPE_REFRACT_OPAQUE, data); } if (obj_flags & mdl::OBJ_USER) entry_list(OBJ_TYPE_USER, data); continue; } else if (!(obj_flags & mdl::OBJ_NO_TRANSLUCENCY)) { if (!attrib.translucent_priority) if (mesh->attrib.m.translucent_sort_by_radius || obj_flags & mdl::OBJ_TRANSLUCENT_SORT_BY_RADIUS) { entry_list(OBJ_TYPE_TRANSLUCENT_SORT_BY_RADIUS, data); } else entry_list(OBJ_TYPE_TRANSLUCENT, data); else if (translucent_priority_count < 40) translucent_priority[translucent_priority_count++] = &data->args.sub_mesh; } } if (obj_flags & mdl::OBJ_SHADOW) entry_list((ObjType)(OBJ_TYPE_SHADOW_CHARA + shadow_type), data); if (obj_flags & mdl::OBJ_40) entry_list(OBJ_TYPE_TYPE_7, data); if (obj_flags & mdl::OBJ_CHARA_REFLECT) entry_list(OBJ_TYPE_REFLECT_CHARA_OPAQUE, data); if (obj_flags & mdl::OBJ_REFLECT) { if (render_manager.reflect_type != STAGE_DATA_REFLECT_REFLECT_MAP) entry_list(OBJ_TYPE_REFLECT_OPAQUE, data); else entry_list(OBJ_TYPE_REFLECT_TRANSLUCENT, data); } if (obj_flags & mdl::OBJ_REFRACT) entry_list(OBJ_TYPE_REFRACT_TRANSLUCENT, data); if (obj_flags & mdl::OBJ_USER) entry_list(OBJ_TYPE_USER, data); } if (!translucent_priority_count) continue; ObjTranslucentArgs translucent_args; translucent_args.count = 0; for (int32_t j = 62; j; j--) for (int32_t k = 0; k < translucent_priority_count; k++) { ObjSubMeshArgs* sub_mesh = translucent_priority[k]; if (sub_mesh->material->material.attrib.m.translucent_priority != j) continue; translucent_args.sub_mesh[translucent_args.count] = sub_mesh; translucent_args.count++; } ObjData* data = alloc_obj_data(OBJ_KIND_TRANSLUCENT); if (!data) continue; data->init_translucent(mat, translucent_args); if (obj_flags & mdl::OBJ_ALPHA_ORDER_POST_GLITTER) entry_list(OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_POST_GLITTER, data); else if (obj_flags & mdl::OBJ_ALPHA_ORDER_POST_TRANSLUCENT) entry_list(OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_POST_TRANSLUCENT, data); else if (obj_flags & mdl::OBJ_ALPHA_ORDER_POST_OPAQUE) entry_list(OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_POST_OPAQUE, data); else entry_list(OBJ_TYPE_TRANSLUCENT, data); } if ((obj_flags & mdl::OBJ_SHADOW_OBJECT) || ((obj_flags & mdl::OBJ_ALPHA_ORDER) && blend_color && blend_color->w < 1.0f)) return true; mat4_transpose(&mat, &_mat); mat4_mul(&_mat, &reflect_mat, &_mat); mat4_transpose(&_mat, &_mat); bool camera_front = vec3::normalize(camera_data.view_point - camera_data.interest).z >= 0.0f; for (int32_t i = 0; i < obj->num_mesh; i++) { const obj_mesh* mesh = &obj->mesh_array[i]; const obj_mesh* mesh_morph = 0; if (mesh->attrib.m.no_reflect || !mdl::obj_reflect_enable && !mesh->attrib.m.reflect || camera_front && mesh->attrib.m.reflect_cam_back) continue; if (obj_vert_buf && obj_morph_vert_buf) { if (obj_vert_buf[i].get_size() != obj_morph_vert_buf[i].get_size()) continue; if (obj_morph && i < obj_morph->num_mesh) mesh_morph = &obj_morph->mesh_array[i]; } if (object_culling && !instances_count && !bone_mat && !obj_bounding_sphere_check_visibility(mesh->bounding_sphere, _mat) && (!mesh_morph || !obj_bounding_sphere_check_visibility(mesh_morph->bounding_sphere, _mat))) { culling.culled.meshes++; continue; } culling.passed.meshes++; ObjSubMeshArgs* translucent_priority[40]; int32_t translucent_priority_count = 0; for (int32_t j = 0; j < mesh->num_submesh; j++) { const obj_sub_mesh* sub_mesh = &mesh->submesh_array[j]; const obj_sub_mesh* sub_mesh_morph = 0; if (sub_mesh->attrib.m.cloth || sub_mesh->attrib.m.no_reflect || !mdl::obj_reflect_enable && !sub_mesh->attrib.m.reflect || camera_front && sub_mesh->attrib.m.reflect_cam_back) continue; if (object_culling && !instances_count && !bone_mat) { int32_t v32 = obj_bounding_sphere_check_visibility(sub_mesh->bounding_sphere, _mat); if (v32 != 2 || (!mesh->attrib.m.billboard && !mesh->attrib.m.billboard_y_axis && !mesh->attrib.m.disable_aabb_culling)) { if (v32 == 2) v32 = obj_axis_aligned_bounding_box_check_visibility( sub_mesh->axis_aligned_bounding_box, _mat); if (!v32) { if (!mesh_morph || j >= mesh_morph->num_submesh) { culling.culled.sub_meshes++; continue; } sub_mesh_morph = &mesh_morph->submesh_array[j]; if (!sub_mesh_morph) { culling.culled.sub_meshes++; continue; } int32_t v32 = obj_bounding_sphere_check_visibility(sub_mesh_morph->bounding_sphere, _mat); if (v32 == 2) v32 = obj_axis_aligned_bounding_box_check_visibility( sub_mesh_morph->axis_aligned_bounding_box, mat); if (!v32) { culling.culled.sub_meshes++; continue; } } } } culling.passed.sub_meshes++; int32_t num_bone_index = sub_mesh->num_bone_index; const uint16_t* bone_index = sub_mesh->bone_index_array; mat4* mats; if (num_bone_index && enable_bone_mat) { mats = alloc_mat4_array(num_bone_index); if (bone_mat) for (int32_t k = 0; k < num_bone_index; k++, bone_index++) mat4_transpose(&bone_mat[*bone_index], &mats[k]); else for (int32_t k = 0; k < num_bone_index; k++) mats[k] = mat4_identity; } else { mats = 0; num_bone_index = 0; } obj_material_data* material = &obj->material_array[sub_mesh->material_index]; ObjData* data = alloc_obj_data(OBJ_KIND_NORMAL); if (!data) continue; GLuint morph_vertex_buffer = 0; size_t morph_vertex_buffer_offset = 0; if (obj_morph_vert_buf) { morph_vertex_buffer = obj_morph_vert_buf[i].get_buffer(); morph_vertex_buffer_offset = obj_morph_vert_buf[i].get_offset(); } GLuint index_buffer = 0; if (obj_index_buf) index_buffer = obj_index_buf[i].buffer; GLuint vertex_buffer = 0; size_t vertex_buffer_offset = 0; if (obj_vert_buf) { vertex_buffer = obj_vert_buf[i].get_buffer(); vertex_buffer_offset = obj_vert_buf[i].get_offset(); } if (!vertex_buffer || !index_buffer || obj_morph_vert_buf && !morph_vertex_buffer) continue; const uint64_t material_hash = hash_utf8_fnv1a64m(material->material.name); const material_list_struct* mat_list = 0; for (int32_t k = 0; k < material_list_count; k++) if (material_list_array[k].hash == material_hash) { mat_list = &material_list_array[k]; break; } vec4 _blend_color = 1.0f; vec4 _emission = { 0.0f, 0.0f, 0.0f, 1.0f }; if (mat_list) { bool has_blend_color = false; if (mat_list->has_blend_color.x) { _blend_color.x = mat_list->blend_color.x; has_blend_color = true; } if (mat_list->has_blend_color.y) { _blend_color.y = mat_list->blend_color.y; has_blend_color = true; } if (mat_list->has_blend_color.z) { _blend_color.z = mat_list->blend_color.z; has_blend_color = true; } if (mat_list->has_blend_color.w) { _blend_color.w = mat_list->blend_color.w; has_blend_color = true; } if (blend_color) { if (!has_blend_color) _blend_color = *blend_color; else _blend_color *= *blend_color; } bool has_emission = false; if (mat_list->has_emission.x) { _emission.x = mat_list->emission.x; has_emission = true; } if (mat_list->has_emission.y) { _emission.y = mat_list->emission.y; has_emission = true; } if (mat_list->has_emission.z) { _emission.z = mat_list->emission.z; has_emission = true; } if (mat_list->has_emission.w) { _emission.w = mat_list->emission.w; has_emission = true; } if (!has_emission) _emission = material->material.color.emission; } else { if (blend_color) _blend_color = *blend_color; _emission = material->material.color.emission; } data->init_sub_mesh(mat, obj->bounding_sphere.radius, sub_mesh, mesh, material, textures, num_bone_index, mats, vertex_buffer, vertex_buffer_offset, index_buffer, _blend_color, _emission, morph_vertex_buffer, morph_vertex_buffer_offset, instances_count, instances_mat, func, func_data); const obj_material_attrib_member attrib = material->material.attrib.m; if (!attrib.flag_28 && (data->args.sub_mesh.blend_color.w < 1.0f || !attrib.punch_through && attrib.alpha_texture | attrib.alpha_material || sub_mesh->attrib.m.translucent)) { if (!attrib.translucent_priority) if (mesh->attrib.m.translucent_sort_by_radius || obj_flags & mdl::OBJ_TRANSLUCENT_SORT_BY_RADIUS) { DispManager::entry_list(OBJ_TYPE_REFLECT_TRANSLUCENT_SORT_BY_RADIUS, data); } else DispManager::entry_list(OBJ_TYPE_REFLECT_TRANSLUCENT, data); else if (translucent_priority_count < 40) translucent_priority[translucent_priority_count++] = &data->args.sub_mesh; } else { if (!(obj_flags & mdl::OBJ_NO_TRANSLUCENCY)) if (attrib.punch_through) DispManager::entry_list(OBJ_TYPE_REFLECT_TRANSPARENT, data); else DispManager::entry_list(OBJ_TYPE_REFLECT_OPAQUE, data); continue; } } if (translucent_priority_count <= 0) continue; ObjTranslucentArgs translucent_args; translucent_args.count = 0; for (int32_t j = 62; j; j--) for (int32_t k = 0; k < translucent_priority_count; k++) { ObjSubMeshArgs* sub_mesh = translucent_priority[k]; if (sub_mesh->material->material.attrib.m.translucent_priority != j) continue; translucent_args.sub_mesh[translucent_args.count] = sub_mesh; translucent_args.count++; } ObjData* data = alloc_obj_data(OBJ_KIND_TRANSLUCENT); if (data) { data->init_translucent(mat, translucent_args); DispManager::entry_list(OBJ_TYPE_TRANSLUCENT, data); } } return true; } bool DispManager::entry_obj_local(const ::obj* obj, const mat4& mat, obj_mesh_vertex_buffer_divagl* obj_vert_buf, obj_mesh_index_buffer* obj_index_buf, const prj::vector* textures, const vec4* blend_color) { if (!obj_vert_buf || !obj_index_buf) return false; culling.passed.objects++; for (int32_t i = 0; i < obj->num_mesh; i++) { const obj_mesh* mesh = &obj->mesh_array[i]; culling.passed.meshes++; ObjSubMeshArgs* translucent_priority[40]; int32_t translucent_priority_count = 0; for (int32_t j = 0; j < mesh->num_submesh; j++) { const obj_sub_mesh* sub_mesh = &mesh->submesh_array[j]; if (sub_mesh->attrib.m.cloth) continue; culling.passed.sub_meshes++; obj_material_data* material = &obj->material_array[sub_mesh->material_index]; ObjData* data = alloc_obj_data(OBJ_KIND_NORMAL); if (!data) continue; GLuint index_buffer = 0; if (obj_index_buf) index_buffer = obj_index_buf[i].buffer; GLuint vertex_buffer = 0; size_t vertex_buffer_offset = 0; if (obj_vert_buf) { vertex_buffer = obj_vert_buf[i].get_buffer(); vertex_buffer_offset = obj_vert_buf[i].get_offset(); } if (!vertex_buffer || !index_buffer) continue; vec4 _blend_color = 1.0f; if (blend_color) _blend_color = *blend_color; vec4 _emission = material->material.color.emission; data->init_sub_mesh(mat, obj->bounding_sphere.radius, sub_mesh, mesh, material, textures, 0, 0, vertex_buffer, vertex_buffer_offset, index_buffer, _blend_color, _emission, 0, 0, 0, 0, 0, 0); const obj_material_attrib_member attrib = material->material.attrib.m; if ((obj_flags & mdl::OBJ_ALPHA_ORDER) && data->args.sub_mesh.blend_color.w < 1.0f) { if (!(obj_flags & mdl::OBJ_NO_TRANSLUCENCY)) { bool translucent = false; if (!attrib.flag_28 && (!attrib.punch_through && (attrib.alpha_texture || attrib.alpha_material) || sub_mesh->attrib.m.translucent)) translucent = true; if (translucent) { if (obj_flags & mdl::OBJ_ALPHA_ORDER_POST_GLITTER); else if (obj_flags & mdl::OBJ_ALPHA_ORDER_POST_TRANSLUCENT) entry_list(OBJ_TYPE_LOCAL_TRANSLUCENT_ALPHA_ORDER_POST_TRANSLUCENT, data); else; } else { if (!attrib.punch_through) { if (obj_flags & mdl::OBJ_ALPHA_ORDER_POST_GLITTER); else if (obj_flags & mdl::OBJ_ALPHA_ORDER_POST_TRANSLUCENT) entry_list(OBJ_TYPE_LOCAL_OPAQUE_ALPHA_ORDER_POST_TRANSLUCENT, data); else; } else { if (obj_flags & mdl::OBJ_ALPHA_ORDER_POST_GLITTER); else if (obj_flags & mdl::OBJ_ALPHA_ORDER_POST_TRANSLUCENT) entry_list(OBJ_TYPE_LOCAL_TRANSPARENT_ALPHA_ORDER_POST_TRANSLUCENT, data); else; } } } } else if (!attrib.flag_28 && (data->args.sub_mesh.blend_color.w < 1.0f || !attrib.punch_through && attrib.alpha_texture | attrib.alpha_material || sub_mesh->attrib.m.translucent)) { if (!(obj_flags & mdl::OBJ_NO_TRANSLUCENCY)) { if (!attrib.translucent_priority) if (mesh->attrib.m.translucent_sort_by_radius || obj_flags & mdl::OBJ_TRANSLUCENT_SORT_BY_RADIUS); else entry_list(OBJ_TYPE_LOCAL_TRANSLUCENT, data); else if (translucent_priority_count < 40) translucent_priority[translucent_priority_count++] = &data->args.sub_mesh; } } else { if (attrib.punch_through) { if (!(obj_flags & mdl::OBJ_NO_TRANSLUCENCY)) entry_list(OBJ_TYPE_LOCAL_TRANSPARENT, data); } else { if (!(obj_flags & mdl::OBJ_NO_TRANSLUCENCY)) entry_list(OBJ_TYPE_LOCAL_OPAQUE, data); } continue; } } if (translucent_priority_count <= 0) continue; ObjTranslucentArgs translucent_args; translucent_args.count = 0; for (int32_t j = 62; j; j--) for (int32_t k = 0; k < translucent_priority_count; k++) { ObjSubMeshArgs* sub_mesh = translucent_priority[k]; if (sub_mesh->material->material.attrib.m.translucent_priority != j) continue; translucent_args.sub_mesh[translucent_args.count] = sub_mesh; translucent_args.count++; } ObjData* data = alloc_obj_data(OBJ_KIND_TRANSLUCENT); if (data) { data->init_translucent(mat, translucent_args); if (obj_flags & mdl::OBJ_ALPHA_ORDER_POST_GLITTER); else if (obj_flags & mdl::OBJ_ALPHA_ORDER_POST_TRANSLUCENT) entry_list(OBJ_TYPE_LOCAL_TRANSLUCENT_ALPHA_ORDER_POST_TRANSLUCENT, data); else if (obj_flags & mdl::OBJ_ALPHA_ORDER_POST_OPAQUE); else entry_list(OBJ_TYPE_LOCAL_TRANSLUCENT, data); } } return true; } #pragma warning(push) #pragma warning(disable: 6385) #pragma warning(disable: 6386) void DispManager::entry_obj_by_obj(const mat4& mat, const ::obj* obj, prj::vector* textures, obj_mesh_vertex_buffer* obj_vert_buf, obj_mesh_index_buffer* obj_index_buf, const mat4* bone_mat, float_t alpha) { if (!obj) return; const int32_t num_mesh = obj->num_mesh; obj_mesh_vertex_buffer_divagl* _obj_vert_buf = new (_operator_new( sizeof(obj_mesh_vertex_buffer_divagl) * num_mesh)) obj_mesh_vertex_buffer_divagl[num_mesh]; if (!_obj_vert_buf) return; for (int32_t i = 0; i < num_mesh; i++) { obj_mesh_vertex_buffer& src_buf = obj_vert_buf[i]; obj_mesh_vertex_buffer_divagl& dst_buf = _obj_vert_buf[i]; dst_buf = src_buf; #if SHARED_OBJECT_BUFFER if (src_buf.buffers[0]) { GLint buffer; GLint size; glGetIntegervDLL(GL_ARRAY_BUFFER_BINDING, &buffer); glBindBuffer(src_buf.target, src_buf.buffers[0]); glGetBufferParameteriv(src_buf.target, GL_BUFFER_SIZE, &size); glBindBuffer(src_buf.target, buffer); dst_buf.size = size; } else dst_buf.size = 0; dst_buf.offset = 0; #endif } vec4 blend_color = 1.0f; blend_color.w = alpha; vec4* blend_color_ptr = alpha < 1.0f ? &blend_color : 0; entry_obj(obj, mat, _obj_vert_buf, obj_index_buf, textures, blend_color_ptr, bone_mat, 0, 0, 0, 0, 0, 0, !!bone_mat); _operator_delete(_obj_vert_buf); } #pragma warning(pop) void DispManager::entry_obj_by_obj(const mat4& mat, const ::obj* obj, prj::vector* textures, obj_mesh_vertex_buffer_divagl* obj_vert_buf, obj_mesh_index_buffer* obj_index_buf, const mat4* bone_mat, float_t alpha) { if (!obj) return; const vec4 blend_color(1.0f, 1.0f, 1.0f, alpha); entry_obj(obj, mat, obj_vert_buf, obj_index_buf, textures, alpha < 1.0f ? &blend_color : 0, bone_mat, 0, 0, 0, 0, 0, 0, !!bone_mat); } bool DispManager::entry_obj_by_object_info(const mat4& mat, object_info obj_info) { return entry_obj_by_object_info(mat, obj_info, 0, 0, 0, 0, 0, 0, false); } bool DispManager::entry_obj_by_object_info(const mat4& mat, object_info obj_info, const mat4* bone_mat) { vec4 blend_color = 1.0f; return entry_obj_by_object_info(mat, obj_info, &blend_color, bone_mat, 0, 0, 0, 0, true); } bool DispManager::entry_obj_by_object_info(const mat4& mat, object_info obj_info, const vec4* blend_color, const mat4* bone_mat, int32_t instances_count, const mat4* instances_mat, void(*func)(const ObjSubMeshArgs*), const ObjSubMeshArgs* func_data, bool enable_bone_mat) { if (obj_info.id == (uint16_t)-1 && obj_info.set_id == (uint16_t)-1) return false; ::obj* obj = objset_info_storage_get_obj(obj_info); if (!obj) return false; prj::vector* textures = objset_info_storage_get_set_gentex(obj_info.set_id); obj_mesh_vertex_buffer_divagl* obj_vert_buffer = (obj_mesh_vertex_buffer_divagl*) objset_info_storage_get_obj_mesh_vertex_buffer(obj_info, 0); obj_mesh_index_buffer* obj_index_buffer = objset_info_storage_get_obj_mesh_index_buffer(obj_info, 0); ::obj* obj_morph = 0; obj_mesh_vertex_buffer_divagl* obj_morph_vert_buffer = 0; if (morph.object.set_id != (uint16_t)-1) { obj_morph = objset_info_storage_get_obj(morph.object); obj_morph_vert_buffer = (obj_mesh_vertex_buffer_divagl*) objset_info_storage_get_obj_mesh_vertex_buffer(morph.object, 0); } return entry_obj(obj, mat, obj_vert_buffer, obj_index_buffer, textures, blend_color, bone_mat, obj_morph, obj_morph_vert_buffer, instances_count, instances_mat, func, func_data, enable_bone_mat); } bool DispManager::entry_obj_by_object_info_local(const mat4& mat, object_info obj_info, const vec4* blend_color) { if (obj_info.id == (uint16_t)-1 && obj_info.set_id == (uint16_t)-1) return false; ::obj* obj = objset_info_storage_get_obj(obj_info); if (!obj) return false; prj::vector* textures = objset_info_storage_get_set_gentex(obj_info.set_id); obj_mesh_vertex_buffer_divagl* obj_vert_buffer = (obj_mesh_vertex_buffer_divagl*) objset_info_storage_get_obj_mesh_vertex_buffer(obj_info, 0); obj_mesh_index_buffer* obj_index_buffer = objset_info_storage_get_obj_mesh_index_buffer(obj_info, 0); return entry_obj_local(obj, mat, obj_vert_buffer, obj_index_buffer, textures, blend_color); } bool DispManager::entry_obj_by_object_info(const mat4& mat, object_info obj_info, float_t alpha, const mat4* bone_mat) { vec4 blend_color = 1.0f; blend_color.w = alpha; return entry_obj_by_object_info(mat, obj_info, &blend_color, bone_mat, 0, 0, 0, 0, !!bone_mat); } bool DispManager::entry_obj_by_object_info(const mat4& mat, object_info obj_info, float_t r, float_t g, float_t b, float_t a, const mat4* bone_mat) { vec4 blend_color = { r, g, b, a }; return entry_obj_by_object_info(mat, obj_info, &blend_color, bone_mat, 0, 0, 0, 0, !!bone_mat); } bool DispManager::entry_obj_by_object_info(const mat4& mat, object_info obj_info, const vec4* blend_color, const mat4* bone_mat) { return entry_obj_by_object_info(mat, obj_info, blend_color, bone_mat, 0, 0, 0, 0, !!bone_mat); } void DispManager::entry_obj_by_object_info_object_skin(object_info obj_info, prj::vector* texture_pattern, texture_data_struct* texture_data, float_t alpha, const mat4* matrices, const mat4* ex_data_matrices, const mat4* mat, const mat4& global_mat) { obj_skin* skin = objset_info_storage_get_obj_skin(obj_info); if (!skin) return; if (!*matrix_buffer_init) { *matrix_buffer_init |= 1u; mat4* mat = matrix_buffer; for (int32_t i = 320; i; i--) *mat++ = mat4_null; } obj_skin_set_matrix_buffer(skin, matrices, ex_data_matrices, matrix_buffer, mat, global_mat); vec4 texture_color_coefficients; vec4 texture_color_offset; vec4 texture_specular_coefficients; vec4 texture_specular_offset; if (texture_data && !texture_data->field_0) { vec4 value; get_texture_color_coeff(texture_color_coefficients); *(vec3*)&value = texture_data->texture_color_coefficients * *(vec3*)&texture_color_coefficients; value.w = 0.0f; set_texture_color_coefficients(value); get_texture_color_offset(texture_color_offset); *(vec3*)&value = texture_data->texture_color_offset; value.w = 0.0f; set_texture_color_offset(value); get_texture_specular_coeff(texture_specular_coefficients); *(vec3*)&value = texture_data->texture_specular_coefficients * *(vec3*)&texture_specular_coefficients; value.w = 0.0f; set_texture_specular_coefficients(value); get_texture_specular_offset(texture_specular_offset); *(vec3*)&value = texture_data->texture_specular_offset; value.w = 0.0f; set_texture_specular_offset(value); } size_t texture_pattern_count = texture_pattern ? texture_pattern->size() : 0; if (texture_pattern && texture_pattern_count) set_texture_pattern((int32_t)texture_pattern_count, texture_pattern->data()); if (fabsf(alpha - 1.0f) > 0.000001f) entry_obj_by_object_info(global_mat, obj_info, alpha, matrix_buffer); else entry_obj_by_object_info(global_mat, obj_info, matrix_buffer); if (texture_pattern && texture_pattern_count) set_texture_pattern(); if (texture_data && !texture_data->field_0) { set_texture_color_coefficients(texture_color_coefficients); set_texture_color_offset(texture_color_offset); set_texture_specular_coefficients(texture_specular_coefficients); set_texture_specular_offset(texture_specular_offset); } } void DispManager::entry_obj_etc(const mat4& mat, const EtcObj& etc) { ObjData* data = alloc_obj_data(mdl::OBJ_KIND_ETC); if (!data) return; data->init_etc(mat, etc); if (etc.color.a == 0xFF) { if (obj_flags & OBJ_SHADOW) entry_list((mdl::ObjType)(OBJ_TYPE_SHADOW_CHARA + shadow_type), data); entry_list(OBJ_TYPE_OPAQUE, data); } else entry_list(OBJ_TYPE_TRANSLUCENT, data); } void DispManager::entry_obj_user(const mat4& mat, UserArgsFunc func, void* data, ObjType type) { ObjData* _data = alloc_obj_data(OBJ_KIND_USER); if (_data) { _data->init_user(mat, func, data); entry_list(type, _data); } } GLuint DispManager::get_vertex_array(const ObjSubMeshArgs* args) { const obj_mesh* mesh = args->mesh; const obj_sub_mesh* sub_mesh = args->sub_mesh; const obj_material_data* material = args->material; GLuint vertex_buffer = args->vertex_buffer; size_t vertex_buffer_offset = args->vertex_buffer_offset; GLuint morph_vertex_buffer = args->morph_vertex_buffer; size_t morph_vertex_buffer_offset = args->morph_vertex_buffer_offset; GLuint index_buffer = args->index_buffer; int32_t texcoord_array[2] = { -1, -1 }; int32_t color_tex_index = 0; for (const obj_material_texture_data& i : material->material.texdata) { if (i.tex_index == -1) continue; int32_t texcoord_index = obj_material_texture_type_get_texcoord_index( i.shader_info.m.tex_type, color_tex_index); if (texcoord_index < 0) continue; texcoord_array[texcoord_index] = sub_mesh->uv_index[&i - material->material.texdata]; if (i.shader_info.m.tex_type == OBJ_MATERIAL_TEXTURE_COLOR) color_tex_index++; } GLuint vertex_attrib_buffer_binding[16] = {}; object_data_get_vertex_attrib_buffer_bindings(args, texcoord_array, vertex_attrib_buffer_binding); GLsizei size_vertex = (GLsizei)mesh->size_vertex; obj_vertex_format vertex_format = mesh->vertex_format; for (DispManager::vertex_array& i : vertex_array_cache) if (i.alive_time > 0 && i.vertex_buffer == vertex_buffer && i.vertex_buffer_offset == vertex_buffer_offset && i.morph_vertex_buffer == morph_vertex_buffer && i.morph_vertex_buffer_offset == morph_vertex_buffer_offset && i.index_buffer == index_buffer && i.vertex_format == vertex_format && i.size_vertex == size_vertex && !memcmp(i.vertex_attrib_buffer_binding, vertex_attrib_buffer_binding, sizeof(vertex_attrib_buffer_binding)) && !memcmp(i.texcoord_array, texcoord_array, sizeof(texcoord_array))) return i.vertex_array; return 0; } GLuint DispManager::get_vertex_array(const EtcObj* etc) { EtcObjType type = etc->type; float_t length = 0; switch (type) { case mdl::ETC_OBJ_TEAPOT: case mdl::ETC_OBJ_GRID: case mdl::ETC_OBJ_CUBE: case mdl::ETC_OBJ_SPHERE: case mdl::ETC_OBJ_PLANE: case mdl::ETC_OBJ_CONE: break; case mdl::ETC_OBJ_LINE: length = vec3::distance(etc->data.line.pos[0], etc->data.line.pos[1]); break; case mdl::ETC_OBJ_CROSS: break; case mdl::ETC_OBJ_CAPSULE: // Added length = vec3::distance(etc->data.capsule.pos[0], etc->data.capsule.pos[1]); break; case mdl::ETC_OBJ_CYLINDER: // Added break; default: return 0; } for (DispManager::etc_vertex_array& i : etc_vertex_array_cache) { if (i.alive_time <= 0 || i.type != type) continue; switch (type) { case mdl::ETC_OBJ_TEAPOT: return i.vertex_array; case mdl::ETC_OBJ_GRID: if (!memcmp(&i.data.grid, &etc->data.grid, sizeof(EtcObjGrid))) return i.vertex_array; break; case mdl::ETC_OBJ_CUBE: if (vec3::dot(vec3::abs(i.data.cube.size - etc->data.cube.size), 1.0f) < 0.00001f) return i.vertex_array; case mdl::ETC_OBJ_SPHERE: if (i.data.sphere.slices == etc->data.sphere.slices && i.data.sphere.stacks == etc->data.sphere.stacks && fabsf(i.data.sphere.radius - etc->data.sphere.radius) < 0.00001f) return i.vertex_array; break; case mdl::ETC_OBJ_PLANE: if (i.data.plane.w == etc->data.plane.w && i.data.plane.h == etc->data.plane.h) return i.vertex_array; case mdl::ETC_OBJ_CONE: if (i.data.cone.slices == etc->data.cone.slices && i.data.cone.stacks == etc->data.cone.stacks && fabsf(i.data.cone.base - etc->data.cone.base) < 0.00001f && fabsf(i.data.cone.height - etc->data.cone.height) < 0.00001f) return i.vertex_array; break; case mdl::ETC_OBJ_LINE: if (fabsf(vec3::distance(i.data.line.pos[0], i.data.line.pos[1]) - length) < 0.00001f) return i.vertex_array; break; case mdl::ETC_OBJ_CROSS: if (fabsf(i.data.cross.size - etc->data.cross.size) < 0.00001f) return i.vertex_array; case mdl::ETC_OBJ_CAPSULE: // Added if (i.data.capsule.slices == etc->data.capsule.slices && ((i.data.capsule.stacks + 1)) >> 1 == ((etc->data.capsule.stacks + 1) >> 1) && fabsf(i.data.capsule.radius - etc->data.capsule.radius) < 0.00001f && fabsf(vec3::distance(i.data.capsule.pos[0], i.data.capsule.pos[1]) - length) < 0.00001f) return i.vertex_array; break; case mdl::ETC_OBJ_CYLINDER: // Added if (i.data.cylinder.slices == etc->data.cylinder.slices && i.data.cylinder.stacks == etc->data.cylinder.stacks && fabsf(i.data.cylinder.base - etc->data.cylinder.base) < 0.00001f && fabsf(i.data.cylinder.height - etc->data.cylinder.height) < 0.00001f) return i.vertex_array; break; } } return 0; } bool DispManager::get_chara_color() { return chara_color; } ObjList& DispManager::get_obj_list(ObjType type) { return disp_manager->obj[type]; } ObjList& DispManager::get_obj_list(ObjTypeLocal type) { return rctx->obj_local[type]; } ObjList& DispManager::get_obj_list(ObjTypeReflect type) { return rctx->obj_reflect[type]; } void DispManager::get_morph(object_info& object, float_t& weight) { weight = morph.weight; object = morph.object; } void DispManager::get_obj_center(mat4& mat, const ObjSubMeshArgs* args, vec3& center) { const vec3 bounding_sphere_center = args->sub_mesh->bounding_sphere.center; if (args->mat_count <= 0 || !args->sub_mesh->num_bone_index) { mat4_transform_point(&mat, &bounding_sphere_center, ¢er); return; } vec3 center_sum = 0.0f; int32_t num_bone_index = args->sub_mesh->num_bone_index; for (int32_t i = 0; i < num_bone_index; i++) { vec3 _center; mat4_transform_point(&args->mats[i], &bounding_sphere_center, &_center); center_sum += _center; } center = center_sum * (1.0f / (float_t)num_bone_index); } int32_t DispManager::get_obj_count(ObjType type) { return (int32_t)get_obj_list(type).size(); } int32_t DispManager::get_obj_count(ObjTypeLocal type) { return (int32_t)get_obj_list(type).size(); } int32_t DispManager::get_obj_count(ObjTypeReflect type) { return (int32_t)get_obj_list(type).size(); } ObjFlags DispManager::get_obj_flags() { return obj_flags; } shadow_type_enum DispManager::get_shadow_type() { return shadow_type; } void DispManager::get_texture_color_coeff(vec4& value) { value = texture_color_coefficients; } void DispManager::get_texture_color_offset(vec4& value) { value = texture_color_offset; } void DispManager::get_texture_pattern(int32_t& count, texture_pattern_struct*& value) { count = texture_pattern_count; for (int32_t i = 0; i < count; i++) value[i] = texture_pattern_array[i]; } void DispManager::get_texture_specular_coeff(vec4& value) { value = texture_specular_coefficients; } void DispManager::get_texture_specular_offset(vec4& value) { value = texture_specular_offset; } void DispManager::get_texture_transform(int32_t& count, texture_transform_struct*& value) { count = texture_transform_count; for (int32_t i = 0; i < count; i++) value[i] = texture_transform_array[i]; } float_t DispManager::get_wet_param() { return wet_param; } void DispManager::obj_sort(render_data_context& rend_data_ctx, ObjType type, int32_t compare_func, const cam_data& cam, bool a3) { prj::list& list = get_obj_list(type); if (list.size() < 1) return; if (a3 && type == OBJ_TYPE_TRANSLUCENT) sub_140436760(cam); calc_obj_radius(cam, type); switch (compare_func) { case 0: list.sort([](ObjData* left, ObjData* right) { return left->view_z > right->view_z; }); break; case 1: list.sort([](ObjData* left, ObjData* right) { return left->view_z < right->view_z; }); break; case 2: list.sort([](ObjData* left, ObjData* right) { return left->radius > right->radius; }); break; } } void DispManager::obj_sort(render_data_context& rend_data_ctx, ObjTypeLocal type, int32_t compare_func, const cam_data& cam) { prj::list& list = get_obj_list(type); if (list.size() < 1) return; calc_obj_radius(cam, type); switch (compare_func) { case 0: list.sort([](ObjData* left, ObjData* right) { return left->view_z > right->view_z; }); break; case 1: list.sort([](ObjData* left, ObjData* right) { return left->view_z < right->view_z; }); break; case 2: list.sort([](ObjData* left, ObjData* right) { return left->radius > right->radius; }); break; } } void DispManager::obj_sort(render_data_context& rend_data_ctx, ObjTypeReflect type, int32_t compare_func, const cam_data& cam) { prj::list& list = get_obj_list(type); if (list.size() < 1) return; calc_obj_radius(cam, type); switch (compare_func) { case 0: list.sort([](ObjData* left, ObjData* right) { return left->view_z > right->view_z; }); break; case 1: list.sort([](ObjData* left, ObjData* right) { return left->view_z < right->view_z; }); break; case 2: list.sort([](ObjData* left, ObjData* right) { return left->radius > right->radius; }); break; } } void DispManager::refresh() { culling.passed_prev = culling.passed; culling.culled_prev = culling.culled; culling.passed = {}; culling.culled = {}; obj_flags = (::mdl::ObjFlags)0; field_8 = 0; field_C = 0; texture_pattern_count = 0; memset(texture_pattern_array, 0, sizeof(texture_pattern_array)); texture_transform_count = 0; memset(texture_transform_array, 0, sizeof(texture_transform_array)); texture_color_coefficients = 1.0f; texture_color_offset = 0.0f; texture_specular_coefficients = 1.0f; texture_specular_offset = 0.0f; for (prj::list& i : obj) i.clear(); for (prj::list& i : rctx->obj_local) i.clear(); for (prj::list& i : rctx->obj_reflect) i.clear(); buffer_reset(); } void DispManager::set_chara_color(bool value) { chara_color = value; } void DispManager::set_culling_func(bool(FASTCALL* func)(const obj_bounding_sphere*)) { culling_func = func; } void DispManager::set_obj_flags(ObjFlags flags) { obj_flags = flags; } void DispManager::set_material_list(int32_t count, const material_list_struct* value) { if (count > MATERIAL_LIST_COUNT) return; material_list_count = count; if (count) for (int32_t i = 0; i < count; i++) material_list_array[i] = value[i]; else for (int32_t i = 0; i < MATERIAL_LIST_COUNT; i++) material_list_array[i] = {}; } void DispManager::set_morph(object_info object, float_t weight) { morph.weight = weight; morph.object = object; } void DispManager::set_shadow_type(shadow_type_enum type) { if (type == SHADOW_CHARA || type == SHADOW_STAGE) shadow_type = type; } void DispManager::set_texture_color_coefficients(vec4& value) { texture_color_coefficients = value; } void DispManager::set_texture_color_offset(vec4& value) { texture_color_offset = value; } void DispManager::set_texture_pattern(int32_t count, const texture_pattern_struct* value) { if (count > TEXTURE_PATTERN_COUNT) return; texture_pattern_count = count; if (count) for (int32_t i = 0; i < count; i++) texture_pattern_array[i] = value[i]; else for (int32_t i = 0; i < TEXTURE_PATTERN_COUNT; i++) texture_pattern_array[i] = {}; } void DispManager::set_texture_specular_coefficients(vec4& value) { texture_specular_coefficients = value; } void DispManager::set_texture_specular_offset(vec4& value) { texture_specular_offset = value; } void DispManager::set_texture_transform(int32_t count, const texture_transform_struct* value) { if (count > TEXTURE_TRANSFORM_COUNT) return; texture_transform_count = count; if (count) for (int32_t i = 0; i < count; i++) texture_transform_array[i] = value[i]; else for (int32_t i = count; i < TEXTURE_TRANSFORM_COUNT; i++) texture_transform_array[i] = {}; } void DispManager::set_wet_param(float_t value) { wet_param = value; } HOOK(void, FASTCALL, DataTestItem__disp, 0x0000000140273200, __int64 a1) { int32_t state = *(int32_t*)(a1 + 0x4B0); if (!(((state - 3) & 0xFFFFFFFC) == 0 && state != 4)) return; disp_manager->set_obj_flags((mdl::ObjFlags)(*(int32_t*)(a1 + 0x94) | mdl::OBJ_40 | mdl::OBJ_20)); mat4 mat; mat4_rotate_zyx((vec3*)(a1 + 0x98), &mat); vec3 pos = 0.0f; sub_1405E8A20(shadow_ptr_get(), 0, 0.0f); disp_manager->set_shadow_type(SHADOW_CHARA); if (*(bool*)(a1 + 0xA4)) { for (int32_t i = 0; i < 5; i++) { mat4 _mat; mat4_mul_translate(&mat, ((float_t)i * 0.5f) - 1.0f, (float_t)(i % 2) * 0.5f, 0.0f, &_mat); mat4_transpose(&_mat, &_mat); rob_chara_item_cos_data_set_chara_index((rob_chara_item_cos_data*)(a1 + 0xA8), *(chara_index*)(a1 + 0x78)); rob_chara_item_cos_data_disp_item((rob_chara_item_cos_data*)(a1 + 0xA8), _mat, *(int32_t*)(a1 + 0x74)); } } else { mat4_transpose(&mat, &mat); rob_chara_item_cos_data_set_chara_index((rob_chara_item_cos_data*)(a1 + 0xA8), *(chara_index*)(a1 + 0x78)); rob_chara_item_cos_data_disp_item((rob_chara_item_cos_data*)(a1 + 0xA8), mat, *(int32_t*)(a1 + 0x74)); } disp_manager->set_obj_flags((mdl::ObjFlags)0); } HOOK(void, FASTCALL, DataTestObjectManager__disp, 0x0000000140293E30, __int64 a1) { if (*(int32_t*)(a1 + 0x88) != 3 || *(int32_t*)(a1 + 0x74) < 0 || *(int32_t*)(a1 + 0x74) >= *(int32_t*)(a1 + 0x70)) return; int32_t set_id = object_database_get_set_id(*(int32_t*)(a1 + 0x68)); int32_t id = objset_info_storage_get_set_obj_id(*(int32_t*)(a1 + 0x68), *(int32_t*)(a1 + 0x74)); disp_manager->set_obj_flags((mdl::ObjFlags)(*(int32_t*)(a1 + 0x84) | mdl::OBJ_40 | mdl::OBJ_20)); mat4 mat; mat4_rotate_xyz((vec3*)(a1 + 0x78), &mat); mat4_transpose(&mat, &mat); sub_1405E8A20(shadow_ptr_get(), 0, 0.0f); disp_manager->set_shadow_type(SHADOW_CHARA); disp_manager->entry_obj_by_object_info(mat, object_info((uint16_t)id, (uint16_t)set_id)); disp_manager->set_obj_flags((mdl::ObjFlags)0); } HOOK(void, FASTCALL, disp_stgtst, 0x0000000140299430) { disp_manager->entry_obj_by_object_info(mat4_identity, object_info(0x00, 0x01)); } HOOK(void, FASTCALL, MeshDw__DrawObjAxisAlignedBoundingBox, 0x000000014031AF10, obj_axis_aligned_bounding_box* aabb, color4u8_bgra color) { mdl::EtcObj etc(mdl::ETC_OBJ_CUBE); etc.color = color; etc.fog = false; etc.data.cube.size = aabb->size * 2.0f; mat4 mat; mat4_translate(&aabb->center, &mat); mat4_transpose(&mat, &mat); disp_manager->entry_obj_etc(mat, etc); } HOOK(void, FASTCALL, MeshDw__DrawObjBoundingSphere, 0x000000014031AFE0, obj_bounding_sphere* bounding_sphere, color4u8_bgra color) { mdl::EtcObj etc(mdl::ETC_OBJ_SPHERE); etc.color = color; etc.fog = false; etc.data.sphere.radius = bounding_sphere->radius; etc.data.sphere.slices = 0x20; etc.data.sphere.stacks = 0x20; etc.data.sphere.wire = false; mat4 mat; mat4_translate(&bounding_sphere->center, &mat); mat4_transpose(&mat, &mat); disp_manager->entry_obj_etc(mat, etc); } HOOK(void, FASTCALL, DispManager__entry_obj, 0x00000001404379E0, obj* obj_data, obj_mesh_vertex_buffer* obj_vert_buf, obj_mesh_index_buffer* obj_index_buf, prj::vector* textures, vec4* blend_color, mat4* bone_mat, obj* obj_morph, obj_mesh_vertex_buffer* obj_morph_vert_buf, float_t morph_value, int32_t instances_count, mat4* instances_mat, obj_mesh_vertex_buffer* a12, int32_t* a13, void(FASTCALL* func)(const mdl::ObjSubMeshArgs*), const mdl::ObjSubMeshArgs* func_data, bool enable_bone_mat) { abort(); } HOOK(void, FASTCALL, DispManager__entry_obj_etc, 0x00000001404395C0, const mdl::EtcObj& etc) { disp_manager->entry_obj_etc(mat4_identity, etc); } HOOK(void, FASTCALL, DispManager__entry_obj_by_obj, 0x0000000140439A20, obj* obj_data, prj::vector* textures, obj_mesh_vertex_buffer* obj_vert_buf, obj_mesh_index_buffer* obj_index_buf, mat4* bone_mat, float_t alpha) { disp_manager->entry_obj_by_obj(*rob_chara_item_equip_mat, obj_data, textures, obj_vert_buf, obj_index_buf, bone_mat, alpha); } HOOK(void, FASTCALL, disp_manager_refresh, 0x0000000140439D20) { disp_manager->refresh(); } HOOK(void, FASTCALL, sub_1404BCC60, 0x00000001404BCC60, vec3* pos, float_t width, float_t height) { mdl::EtcObj etc(ETC_OBJ_PLANE); etc.color = spr_color; etc.data.plane.w = (int)width; etc.data.plane.h = (int)height; mat4 mat; mat4_translate(pos, &mat); mat4_transpose(&mat, &mat); disp_manager->entry_obj_etc(mat, etc); } HOOK(void, FASTCALL, DispManager__entry_obj_by_object_info_object_skin, 0x00000001405E8E20, uint32_t obj_info, prj::vector* texture_pattern, texture_data_struct* texture_data, float_t alpha, const mat4* matrices, const mat4* ex_data_matrices, const mat4* mat) { disp_manager->entry_obj_by_object_info_object_skin(obj_info, texture_pattern, texture_data, alpha, matrices, ex_data_matrices, mat, *rob_chara_item_equip_mat); } void disp_manager_patch() { INSTALL_HOOK(DataTestItem__disp); INSTALL_HOOK(DataTestObjectManager__disp); INSTALL_HOOK(disp_stgtst); INSTALL_HOOK(MeshDw__DrawObjAxisAlignedBoundingBox); INSTALL_HOOK(MeshDw__DrawObjBoundingSphere); INSTALL_HOOK(DispManager__entry_obj); INSTALL_HOOK(DispManager__entry_obj_etc); INSTALL_HOOK(DispManager__entry_obj_by_obj); INSTALL_HOOK(disp_manager_refresh); INSTALL_HOOK(sub_1404BCC60); INSTALL_HOOK(DispManager__entry_obj_by_object_info_object_skin); } } static void object_data_get_vertex_attrib_buffer_bindings(const mdl::ObjSubMeshArgs* args, int32_t texcoord_array[2], GLuint vertex_attrib_buffer_binding[16]) { const obj_mesh* mesh = args->mesh; const obj_sub_mesh* sub_mesh = args->sub_mesh; GLuint vertex_buffer = args->vertex_buffer; GLuint morph_vertex_buffer = args->morph_vertex_buffer; uint32_t compression = mesh->attrib.m.compression; GLsizei size_vertex = (GLsizei)mesh->size_vertex; obj_vertex_format vertex_format = mesh->vertex_format; if (vertex_format & OBJ_VERTEX_POSITION) vertex_attrib_buffer_binding[POSITION_INDEX] = vertex_buffer; if (vertex_format & OBJ_VERTEX_NORMAL) vertex_attrib_buffer_binding[NORMAL_INDEX] = vertex_buffer; if (vertex_format & OBJ_VERTEX_TANGENT) vertex_attrib_buffer_binding[TANGENT_INDEX] = vertex_buffer; for (int32_t i = 0; i < 2; i++) { int32_t texcoord_index = texcoord_array[i]; if (texcoord_index >= 0) if (vertex_format & (OBJ_VERTEX_TEXCOORD0 << texcoord_index)) vertex_attrib_buffer_binding[TEXCOORD0_INDEX + i] = vertex_buffer; } if (vertex_format & OBJ_VERTEX_COLOR0) vertex_attrib_buffer_binding[COLOR0_INDEX] = vertex_buffer; if ((vertex_format & OBJ_VERTEX_BONE_DATA) == OBJ_VERTEX_BONE_DATA) { vertex_attrib_buffer_binding[BONE_WEIGHT_INDEX] = vertex_buffer; vertex_attrib_buffer_binding[BONE_INDEX_INDEX] = vertex_buffer; } if (!compression && (vertex_format & OBJ_VERTEX_UNKNOWN)) vertex_attrib_buffer_binding[UNKNOWN_INDEX] = vertex_buffer; if (args->morph_vertex_buffer) { if (vertex_format & OBJ_VERTEX_POSITION) vertex_attrib_buffer_binding[MORPH_POSITION_INDEX] = morph_vertex_buffer; if (vertex_format & OBJ_VERTEX_NORMAL) vertex_attrib_buffer_binding[MORPH_NORMAL_INDEX] = morph_vertex_buffer; if (vertex_format & OBJ_VERTEX_TANGENT) vertex_attrib_buffer_binding[MORPH_TANGENT_INDEX] = morph_vertex_buffer; if (vertex_format & OBJ_VERTEX_TEXCOORD0) vertex_attrib_buffer_binding[MORPH_TEXCOORD0_INDEX] = morph_vertex_buffer; if (vertex_format & OBJ_VERTEX_TEXCOORD1) vertex_attrib_buffer_binding[MORPH_TEXCOORD1_INDEX] = morph_vertex_buffer; if (vertex_format & OBJ_VERTEX_COLOR0) vertex_attrib_buffer_binding[MORPH_COLOR_INDEX] = morph_vertex_buffer; } } // 0x00000001405223C0 static void rob_chara_item_cos_data_disp_item(rob_chara_item_cos_data* item_cos_data, const mat4& mat, int32_t item_no) { if (!item_no) return; static const item_table_item* (FASTCALL * item_table_handler_array_get_item)(::chara_index chara_index, int32_t item_no) = (const item_table_item * (FASTCALL*)(::chara_index chara_index, int32_t item_no))0x0000000140525B30; const item_table_item* item = item_table_handler_array_get_item(item_cos_data->chara_index, item_no); if (!item) return; for (const item_table_item_data_obj& i : item->data.obj) if (i.obj_info.not_null()) rob_chara_item_cos_data_disp_item_object(item_cos_data, i.obj_info, mat, item_no); } // 0x0000000140522480 static void rob_chara_item_cos_data_disp_item_object(rob_chara_item_cos_data* item_cos_data, object_info obj_info, const mat4& mat, int32_t item_no) { mat4* rob_chara_item_cos_data_bone_mat = (mat4*)0x00000001411B2040; texture_pattern_struct* tex_pat = 0; size_t tex_pat_count = 0; obj_skin* skin = objset_info_storage_get_obj_skin(obj_info); auto elem = item_cos_data->texture_change.find(item_no); if (elem != item_cos_data->texture_change.end()) { tex_pat_count = elem->second.size(); if (tex_pat_count) { tex_pat = (texture_pattern_struct*)_operator_new(tex_pat_count * sizeof(texture_pattern_struct)); item_cos_texture_change_tex* v19 = elem->second.data(); for (size_t i = 0; i < tex_pat_count; i++) { tex_pat[i].src = v19[i].org->id; tex_pat[i].dst = v19[i].chg->id; } disp_manager->set_texture_pattern((int32_t)tex_pat_count, tex_pat); } } if (skin && skin->num_bone <= 320) { for (int32_t i = 0; i < skin->num_bone; i++) rob_chara_item_cos_data_bone_mat[i] = mat; disp_manager->entry_obj_by_object_info(mat4_identity, obj_info, rob_chara_item_cos_data_bone_mat); } else disp_manager->entry_obj_by_object_info(mat, obj_info); if (tex_pat_count) { disp_manager->set_texture_pattern(0, 0); _operator_delete(tex_pat); } } // 0x000000014052C530 static void rob_chara_item_cos_data_set_chara_index(rob_chara_item_cos_data* item_cos_data, ::chara_index chara_index) { item_cos_data->chara_index = chara_index; } static void sub_140436760(const cam_data& cam) { for (auto& i : disp_manager->obj[mdl::OBJ_TYPE_TRANSLUCENT]) { if (i->kind != mdl::OBJ_KIND_NORMAL) continue; const obj_mesh* mesh = i->args.sub_mesh.mesh; if (!mesh) continue; const obj_sub_mesh* sub_mesh = i->args.sub_mesh.sub_mesh; const obj_axis_aligned_bounding_box* aabb = sub_mesh->axis_aligned_bounding_box; if (mesh->attrib.m.billboard_y_axis && aabb->size.y > 1.0f && aabb->size.y < 1.2f) { if (!strcmp(mesh->name, "STGD2NS064_EFF_WATESMOKE_A_BMZ_000")) i->view_z += sub_mesh->bounding_sphere.radius; continue; } if (i->args.sub_mesh.material->material.attrib.m.src_blend_factor == OBJ_MATERIAL_BLEND_ZERO && i->args.sub_mesh.material->material.attrib.m.dst_blend_factor == OBJ_MATERIAL_BLEND_ONE && aabb->size.y > 2.0f && aabb->size.y < 2.5f) { if (strcmp(mesh->name, "STGD2NS064_EFF_DISPLAY_MZ_000") && strcmp(mesh->name, "STGD2NS064_EFF_RAY_B_MZ_000")) continue; } else if (aabb->size.y > 3.0f && aabb->size.x > 3.6f && aabb->size.x < 3.7f) { if (strcmp(mesh->name, "STGD2NS064_EFF_WATERFALL_A_MZ_000")) continue; } else continue; mat4 mat; mat4_transpose(&i->mat, &mat); mat4_mul_translate(&mat, &aabb->center, &mat); mat4_mul(&mat, &cam.get_view_mat(), &mat); mat4_transpose(&mat, &mat); vec4 t; *(vec3*)&t = aabb->size; t.w = 1.0f; float_t view_z = vec4::dot(t ^ vec4(0.0f, 0.0f, 0.0f, 0.0f), mat.row2); if (view_z < vec4::dot(t ^ vec4(0.0f, 0.0f, -0.0f, 0.0f), mat.row2)) view_z = vec4::dot(t ^ vec4(0.0f, 0.0f, -0.0f, 0.0f), mat.row2); if (view_z < vec4::dot(t ^ vec4(0.0f, -0.0f, 0.0f, 0.0f), mat.row2)) view_z = -t.y; if (view_z < vec4::dot(t ^ vec4(0.0f, -0.0f, -0.0f, 0.0f), mat.row2)) view_z = vec4::dot(t ^ vec4(0.0f, -0.0f, -0.0f, 0.0f), mat.row2); if (view_z < vec4::dot(t ^ vec4(-0.0f, 0.0f, 0.0f, 0.0f), mat.row2)) view_z = -t.x; if (view_z < vec4::dot(t ^ vec4(-0.0f, 0.0f, -0.0f, 0.0f), mat.row2)) view_z = vec4::dot(t ^ vec4(-0.0f, 0.0f, -0.0f, 0.0f), mat.row2); if (view_z < vec4::dot(t ^ vec4(-0.0f, -0.0f, 0.0f, 0.0f), mat.row2)) view_z = vec4::dot(t ^ vec4(-0.0f, -0.0f, 0.0f, 0.0f), mat.row2); if (view_z < vec4::dot(t ^ vec4(-0.0f, -0.0f, -0.0f, 0.0f), mat.row2)) view_z = vec4::dot(t ^ vec4(-0.0f, -0.0f, -0.0f, 0.0f), mat.row2); i->view_z = view_z; } }