Files
korenkonder_AFTMods/src/DivaGL/mdl/disp_manager.cpp
T

4338 lines
168 KiB
C++

/*
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 <Helpers.h>
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<DispManager::vertex_array> vertex_array_cache;
prj::vector<DispManager::etc_vertex_array> 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<GLuint>* 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<prj::pair<vec3, vec3>>& 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<prj::pair<vec3, vec3>>& 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<uint32_t>& 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<prj::pair<vec3, vec3>>& 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<uint32_t>& 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<prj::pair<vec3, vec3>>& 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<prj::pair<vec3, vec3>>& 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<prj::pair<vec3, vec3>>& 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<prj::pair<vec3, vec3>>& 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<uint32_t>& 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<prj::pair<vec3, vec3>>& 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<uint32_t>& 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<prj::pair<vec3, vec3>> vtx_data;
prj::vector<uint32_t> 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<vec3> alpha_center;
prj::vector<vec3> 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, &center);
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(), &center, &center);
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(), &center, &center);
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(), &center, &center);
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, &center, &_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, &center);
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<GLuint>* 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<GLuint>* 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<GLuint>* 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<GLuint>* 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<GLuint>* 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<GLuint>* 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_struct>* 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, &center);
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<ObjData*>& 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<ObjData*>& 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<ObjData*>& 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<ObjData*>& i : obj)
i.clear();
for (prj::list<ObjData*>& i : rctx->obj_local)
i.clear();
for (prj::list<ObjData*>& 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<GLuint>* 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<GLuint>* 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_struct>* 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;
}
}