Files
korenkonder_ReDIVA/src/CRE/render_context.cpp
T
2023-11-27 22:24:28 +03:00

4519 lines
162 KiB
C++

/*
by korenkonder
GitHub/GitLab: korenkonder
*/
#include "render_context.hpp"
#include "../KKdLib/sort.hpp"
#include "Glitter/glitter.hpp"
#include "rob/rob.hpp"
#include "file_handler.hpp"
#include "render_manager.hpp"
#include "shader_ft.hpp"
#include "sprite.hpp"
#include "sound.hpp"
#include "stage.hpp"
float_t delta_frame_history = 0;
int32_t delta_frame_history_int = 0;
extern render_context* rctx_ptr;
//extern void dw_gui_ctrl_disp();
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 render_context_light_param_data_ibl_set_diffuse(light_param_ibl_diffuse* diffuse, int32_t level);
static void render_context_light_param_data_ibl_set_specular(light_param_ibl_specular* specular);
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;
struct struc_189 {
GLenum type;
int32_t width;
int32_t height;
int32_t max_level;
GLenum color_format;
GLenum depth_format;
};
static const struc_189 stru_140A24420[] = {
{ GL_TEXTURE_2D, 0x200, 0x100, 0, GL_RGBA8 , GL_DEPTH_COMPONENT24 },
{ GL_TEXTURE_2D, 0x200, 0x100, 0, GL_RGBA16F, GL_DEPTH_COMPONENT24 },
{ GL_TEXTURE_2D, 0x400, 0x400, 0, GL_RGBA8 , GL_ZERO },
{ GL_TEXTURE_2D, 0x400, 0x400, 0, GL_RGBA8 , GL_ZERO },
{ GL_TEXTURE_2D, 0x400, 0x400, 0, GL_RGBA8 , GL_ZERO },
{ GL_TEXTURE_2D, 0x100, 0x100, 0, GL_RGBA8 , GL_ZERO },
{ GL_TEXTURE_2D, 0x100, 0x100, 0, GL_RGBA32F, GL_ZERO },
{ GL_TEXTURE_2D, 0x100, 0x100, 0, GL_RGBA8 , GL_ZERO },
{ GL_TEXTURE_2D, 0x200, 0x100, 0, GL_RGBA16F, GL_ZERO }, // Extra for buf
};
static const int32_t stru_140A244E0[][3] = {
{ 1, 1, 1 },
{ 0, 0, 0 },
{ 6, 6, 6 },
{ 6, 6, 6 },
{ 6, 6, 6 },
{ 2, 2, 2 },
{ 3, 3, 3 },
{ 4, 4, 4 },
{ 5, 5, 5 },
{ 6, 6, 6 },
{ 7, 7, 7 },
{ 8, 8, 8 }, // Extra for buf
};
draw_state_stats::draw_state_stats() : object_draw_count(), object_translucent_draw_count(),
object_reflect_draw_count(), field_C(), field_10(), draw_count(), draw_triangle_count(), field_1C() {
}
void draw_state_stats::reset() {
object_draw_count = 0;
object_translucent_draw_count = 0;
object_reflect_draw_count = 0;
field_C = 0;
field_10 = 0;
draw_count = 0;
draw_triangle_count = 0;
field_1C = 0;
}
sss_data::sss_data() : init(), enable(), npr_contour(), param() {
init = true;
enable = true;
npr_contour = true;
param = { 0.0f, 0.0f, 0.0f, 1.0f };
textures[0].Init(640, 360, 0, GL_RGBA16F, GL_ZERO /*GL_DEPTH_COMPONENT32F*/);
textures[1].Init(320, 180, 0, GL_RGBA16F, GL_ZERO);
textures[2].Init(320, 180, 0, GL_RGBA16F, GL_ZERO);
textures[3].Init(320, 180, 0, GL_RGBA16F, GL_ZERO);
}
sss_data::~sss_data() {
}
draw_state::draw_state() : wireframe(), wireframe_overlay(), light(), self_shadow(),
shader_debug_flag(), use_global_material(), fog_height(), ex_data_mat(), field_68() {
shader = true;
shader_index = -1;
show = -1;
bump_depth = 1.0f;
intensity = 1.0f;
reflectivity = 1.0f;
reflect_uv_scale = 0.1f;
refract_uv_scale = 0.1f;
fresnel = 7.0f;
}
void draw_state::set_fog_height(bool value) {
fog_height = value;
}
material_list_struct::material_list_struct() : blend_color(),
has_blend_color(), emission(), has_emission() {
hash = (uint32_t)-1;
}
material_list_struct::material_list_struct(uint32_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) {
}
texture_pattern_struct::texture_pattern_struct() : src(), dst() {
}
texture_pattern_struct::texture_pattern_struct(texture_id src, texture_id dst) : src(src), dst(dst) {
}
texture_transform_struct::texture_transform_struct() {
id = (uint32_t)-1;
mat = mat4_identity;
}
texture_transform_struct::texture_transform_struct(uint32_t id, mat4& mat) : id(id), mat(mat) {
}
namespace mdl {
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 };
}
EtcObjEllipse::EtcObjEllipse() : 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;
top = 1.0f;
height = 1.0f;
slices = 8;
stacks = 8;
}
EtcObj::Data::Data() : capsule() {
}
EtcObj::EtcObj() : type(), constant(), count(), offset() {
}
void EtcObj::init(EtcObjType type) {
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_ELLIPSE: // Added
data.ellipse = {};
break;
case ETC_OBJ_CYLINDER: // Added
data.cylinder = {};
break;
}
}
void ObjData::init_etc(DispManager* disp_manager, const mat4* mat, mdl::EtcObj* etc) {
kind = mdl::OBJ_KIND_ETC;
this->mat = *mat;
args.etc = *etc;
disp_manager->add_vertex_array(&args.etc, this->mat);
}
void ObjData::init_sub_mesh(DispManager* disp_manager, const mat4* mat, float_t radius,
obj_sub_mesh* sub_mesh, obj_mesh* mesh, obj_material_data* material, std::vector<texture*>* textures,
int32_t mat_count, mat4* mats, /*GLuint vertex_buffer, GLuint index_buffer,*/
obj_mesh_vertex_buffer* vertex_buffer, obj_mesh_index_buffer* index_buffer, vec4* blend_color,
vec4* emission, /*GLuint morph_vertex_buffer,*/ obj_mesh_vertex_buffer* morph_vertex_buffer,
int32_t instances_count, mat4* instances_mat, void(*func)(const ObjSubMeshArgs*)) {
kind = mdl::OBJ_KIND_NORMAL;
this->mat = *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->index_buffer = index_buffer;
args->morph_vertex_buffer = morph_vertex_buffer;
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] = disp_manager->texture_transform_array[i];
if (blend_color && *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) ? 1 : 0;
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;
disp_manager->add_vertex_array(args);
}
void ObjData::init_translucent(const mat4* mat, ObjTranslucentArgs* translucent) {
kind = mdl::OBJ_KIND_TRANSLUCENT;
this->mat = *mat;
args.translucent = *translucent;
}
void ObjData::init_user(const mat4* mat, UserArgsFunc func, void* data) {
kind = OBJ_KIND_USER;
this->mat = *mat;
args.user.func = func;
args.user.data = data;
}
}
light_proj::light_proj(int32_t width, int32_t height) : enable(), texture_id() {
shadow_texture[0].Init(2048, 512, 0, GL_R32F, GL_DEPTH_COMPONENT32F);
shadow_texture[1].Init(2048, 512, 0, GL_R32F, GL_ZERO);
draw_texture.Init(width, height, 0, GL_RGBA8, GL_DEPTH_COMPONENT32F);
}
light_proj::~light_proj() {
}
void light_proj::resize(int32_t width, int32_t height) {
if (!this)
return;
draw_texture.Init(width, height, 0, GL_RGBA8, GL_DEPTH_COMPONENT32F);
}
bool light_proj::set(render_context* rctx) {
if (!this)
return false;
static const vec4 color_clear = 1.0f;
static const GLfloat depth_clear = 1.0f;
shadow_texture[0].Bind();
glViewport(0, 0, 2048, 512);
gl_state_enable_depth_test();
gl_state_set_depth_mask(GL_TRUE);
glClearBufferfv(GL_COLOR, 0, (float_t*)&color_clear);
glClearBufferfv(GL_DEPTH, 0, &depth_clear);
if (set_mat(rctx, false)) {
rctx->draw_state.shader_index = SHADER_FT_SIL;
uniform_value[U0A] = 1;
return true;
}
else {
draw_texture.Bind();
glViewport(0, 0, draw_texture.color_texture->width,
draw_texture.color_texture->height);
gl_state_enable_depth_test();
gl_state_set_depth_mask(GL_TRUE);
glClearBufferfv(GL_COLOR, 0, (float_t*)&color_clear);
glClearBufferfv(GL_DEPTH, 0, &depth_clear);
}
return false;
}
bool light_proj::set_mat(render_context* rctx, bool set_mat) {
light_set* set = &rctx->light_set[LIGHT_SET_MAIN];
light_data* data = &set->lights[LIGHT_PROJECTION];
if (data->get_type() != LIGHT_SPOT)
return false;
vec3 position;
vec3 spot_direction;
data->get_position(position);
data->get_spot_direction(spot_direction);
if (vec3::length_squared(spot_direction) <= 0.000001f)
return false;
float_t spot_cutoff = data->get_spot_cutoff();
float_t fov = atanf(tanf(spot_cutoff * DEG_TO_RAD_FLOAT) * 0.25f) * 2.0f;
vec3 interest = position + spot_direction;
if (set_mat) {
mat4 temp;
mat4_translate(0.5f, 0.5f, 0.5f, &temp);
mat4_scale_rot(&temp, 0.5f, 0.5f, 0.5f, &temp);
mat4 proj;
mat4_persp(fov, 4.0f, 0.1f, 10.0f, &proj);
mat4_mul(&proj, &temp, &proj);
mat4 view;
vec3 up = { 0.0f, 1.0f, 0.0f };
mat4_look_at(&position, &interest, &up, &view);
mat4 mat;
mat4_mul(&view, &proj, &mat);
rctx->obj_scene.set_g_light_projection(mat);
}
else {
mat4_persp(fov, 4.0f, 0.1f, 10.0f, &rctx->proj_mat);
vec3 up = { 0.0f, 1.0f, 0.0f };
mat4_look_at(&position, &interest, &up, &rctx->view_mat);
rctx->obj_scene.set_projection_view(rctx->view_mat, rctx->proj_mat);
}
return true;
}
morph_struct::morph_struct() : weight() {
}
texture_data_struct::texture_data_struct() : field_0() {
}
namespace mdl {
DispManager::DispManager() : obj_flags(), shadow_type(), field_8(), field_C(),
culling(), show_alpha_center(), show_mat_center(), texture_pattern_count(),
texture_pattern_array(), wet_param(), texture_transform_count(),
texture_transform_array(), material_list_count(), material_list_array() {
put_index = -1;
object_culling = true;
object_sort = true;
chara_color = true;
buff_offset = 0;
buff_max = 0;
buff_size = 0x300000;
buff = force_malloc(0x300000);
texture_color_coefficients = 1.0f;
texture_color_offset = 0.0f;
texture_specular_coefficients = 1.0f;
texture_specular_offset = 0.0f;
}
DispManager::~DispManager() {
for (DispManager::vertex_array& i : vertex_array_cache)
glDeleteVertexArrays(1, &i.vertex_array);
vertex_array_cache.clear();
for (DispManager::etc_vertex_array& i : etc_vertex_array_cache) {
glDeleteVertexArrays(1, &i.vertex_array);
if (i.vertex_buffer) {
glDeleteBuffers(1, &i.vertex_buffer);
i.vertex_buffer = 0;
}
if (i.index_buffer) {
glDeleteBuffers(1, &i.index_buffer);
i.index_buffer = 0;
}
}
etc_vertex_array_cache.clear();
free_def(buff);
}
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;
obj_mesh_vertex_buffer* vertex_buffer = args->vertex_buffer;
//GLuint morph_vertex_buffer = args->morph_vertex_buffer;
obj_mesh_vertex_buffer* morph_vertex_buffer = args->morph_vertex_buffer;
//GLuint index_buffer = args->index_buffer;
obj_mesh_index_buffer* 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);
bool compressed = mesh->attrib.m.compressed;
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.morph_vertex_buffer == morph_vertex_buffer
&& i.index_buffer == index_buffer && i.vertex_format == vertex_format
&& i.size_vertex == size_vertex && i.compressed == compressed
&& !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();
}
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);
}
vertex_array->vertex_buffer = vertex_buffer;
vertex_array->morph_vertex_buffer = morph_vertex_buffer;
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->compressed = compressed;
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));
gl_state_bind_vertex_array(vertex_array->vertex_array);
//gl_state_bind_array_buffer(vertex_buffer);
gl_state_bind_array_buffer(vertex_buffer->get_buffer());
if (index_buffer)
//gl_state_bind_element_array_buffer(index_buffer, true);
gl_state_bind_element_array_buffer(index_buffer->buffer, true);
#if SHARED_OBJECT_BUFFER
//size_t offset = vertex_buffer_offset;
size_t offset = vertex_buffer->get_offset();
#else
size_t offset = 0;
#endif
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;
}
if (!compressed) {
glVertexAttribPointer(NORMAL_INDEX,
3, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset);
offset += 12;
}
else {
glVertexAttribPointer(NORMAL_INDEX,
3, GL_SHORT, GL_TRUE, size_vertex, (void*)offset);
offset += 8;
}
}
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;
}
if (!compressed) {
glVertexAttribPointer(TANGENT_INDEX,
4, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset);
offset += 16;
}
else {
glVertexAttribPointer(TANGENT_INDEX,
4, GL_SHORT, GL_TRUE, size_vertex, (void*)offset);
offset += 8;
}
}
else if (vertex_array->vertex_attrib_array[TANGENT_INDEX]) {
glDisableVertexAttribArray(TANGENT_INDEX);
vertex_array->vertex_attrib_array[TANGENT_INDEX] = false;
}
if (!compressed && 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;
}
if (!compressed)
glVertexAttribPointer(TEXCOORD0_INDEX + i, 2, GL_FLOAT, GL_FALSE,
size_vertex, (void*)(offset + 8ULL * texcoord_index));
else
glVertexAttribPointer(TEXCOORD0_INDEX + i, 2, GL_HALF_FLOAT, GL_FALSE,
size_vertex, (void*)(offset + 4ULL * texcoord_index));
}
}
if (!compressed) {
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;
}
else {
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;
}
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;
}
if (!compressed) {
glVertexAttribPointer(COLOR0_INDEX,
4, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset);
offset += 16;
}
else {
glVertexAttribPointer(COLOR0_INDEX,
4, GL_HALF_FLOAT, GL_FALSE, size_vertex, (void*)offset);
offset += 8;
}
}
else if (vertex_array->vertex_attrib_array[COLOR0_INDEX]) {
glDisableVertexAttribArray(COLOR0_INDEX);
vertex_array->vertex_attrib_array[COLOR0_INDEX] = false;
}
if (vertex_format & OBJ_VERTEX_COLOR1)
offset += 16;
if (vertex_format & 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;
}
if (!compressed) {
glVertexAttribPointer(BONE_WEIGHT_INDEX,
4, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset);
offset += 16;
}
else {
glVertexAttribPointer(BONE_WEIGHT_INDEX,
4, GL_UNSIGNED_SHORT, GL_TRUE, size_vertex, (void*)offset);
offset += 8;
}
if (!vertex_array->vertex_attrib_array[BONE_INDEX_INDEX]) {
glEnableVertexAttribArray(BONE_INDEX_INDEX);
vertex_array->vertex_attrib_array[BONE_INDEX_INDEX] = true;
}
glVertexAttribIPointer(BONE_INDEX_INDEX,
4, GL_SHORT, size_vertex, (void*)offset);
offset += 8;
}
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 (!compressed && 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);
gl_state_bind_array_buffer(morph_vertex_buffer->get_buffer());
#if SHARED_OBJECT_BUFFER
//size_t offset = morph_vertex_buffer_offset;
size_t offset = morph_vertex_buffer->get_offset();
#else
size_t offset = 0;
#endif
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;
}
if (!compressed) {
glVertexAttribPointer(MORPH_NORMAL_INDEX,
3, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset);
offset += 12;
}
else {
glVertexAttribPointer(MORPH_NORMAL_INDEX,
3, GL_SHORT, GL_TRUE, size_vertex, (void*)offset);
offset += 8;
}
}
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;
}
if (!compressed) {
glVertexAttribPointer(MORPH_TANGENT_INDEX,
4, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset);
offset += 16;
}
else {
glVertexAttribPointer(MORPH_TANGENT_INDEX,
4, GL_SHORT, GL_TRUE, size_vertex, (void*)offset);
offset += 8;
}
}
else if (vertex_array->vertex_attrib_array[MORPH_TANGENT_INDEX]) {
glDisableVertexAttribArray(MORPH_TANGENT_INDEX);
vertex_array->vertex_attrib_array[MORPH_TANGENT_INDEX] = false;
}
if (!compressed && 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;
}
if (!compressed) {
glVertexAttribPointer(MORPH_TEXCOORD0_INDEX,
2, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset);
offset += 8;
}
else {
glVertexAttribPointer(MORPH_TEXCOORD0_INDEX,
2, GL_HALF_FLOAT, GL_FALSE, size_vertex, (void*)offset);
offset += 4;
}
}
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;
}
if (!compressed) {
glVertexAttribPointer(MORPH_TEXCOORD1_INDEX,
2, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset);
offset += 8;
}
else {
glVertexAttribPointer(MORPH_TEXCOORD1_INDEX,
2, GL_HALF_FLOAT, GL_FALSE, size_vertex, (void*)offset);
offset += 4;
}
}
else if (vertex_array->vertex_attrib_array[MORPH_TEXCOORD1_INDEX]) {
glDisableVertexAttribArray(MORPH_TEXCOORD1_INDEX);
vertex_array->vertex_attrib_array[MORPH_TEXCOORD1_INDEX] = false;
}
if (!compressed) {
if (vertex_format & OBJ_VERTEX_TEXCOORD2)
offset += 8;
if (vertex_format & OBJ_VERTEX_TEXCOORD3)
offset += 8;
}
else {
if (vertex_format & OBJ_VERTEX_TEXCOORD2)
offset += 4;
if (vertex_format & OBJ_VERTEX_TEXCOORD3)
offset += 4;
}
if (vertex_format & OBJ_VERTEX_COLOR0) {
uniform_value[U_MORPH_COLOR] = 1;
if (!vertex_array->vertex_attrib_array[MORPH_COLOR_INDEX]) {
glEnableVertexAttribArray(MORPH_COLOR_INDEX);
vertex_array->vertex_attrib_array[MORPH_COLOR_INDEX] = true;
}
if (!compressed) {
glVertexAttribPointer(MORPH_COLOR_INDEX,
4, GL_FLOAT, GL_FALSE, size_vertex, (void*)offset);
offset += 16;
}
else {
glVertexAttribPointer(MORPH_COLOR_INDEX,
4, GL_HALF_FLOAT, GL_FALSE, size_vertex, (void*)offset);
offset += 8;
}
}
else if (vertex_array->vertex_attrib_array[MORPH_COLOR_INDEX]) {
glDisableVertexAttribArray(MORPH_COLOR_INDEX);
vertex_array->vertex_attrib_array[MORPH_COLOR_INDEX] = false;
}
if (!compressed) {
if (vertex_format & OBJ_VERTEX_COLOR1)
offset += 16;
if (vertex_format & OBJ_VERTEX_BONE_DATA)
offset += 32;
if (vertex_format & OBJ_VERTEX_UNKNOWN)
offset += 16;
}
else {
if (vertex_format & OBJ_VERTEX_BONE_DATA)
offset += 16;
}
}
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 void gen_cube_vertices(std::vector<float_t>& data) {
data.resize(sizeof(vec3) * 2 * 4 * 6);
vec3* vtx = (vec3*)data.data();
*vtx++ = { -1.0f, -1.0f, -1.0f };
*vtx++ = { 0.0f, 0.0f, -1.0f };
*vtx++ = { 1.0f, 1.0f, -1.0f };
*vtx++ = { 0.0f, 0.0f, -1.0f };
*vtx++ = { 1.0f, -1.0f, -1.0f };
*vtx++ = { 0.0f, 0.0f, -1.0f };
*vtx++ = { -1.0f, 1.0f, -1.0f };
*vtx++ = { 0.0f, 0.0f, -1.0f };
*vtx++ = { -1.0f, -1.0f, 1.0f };
*vtx++ = { 0.0f, 0.0f, 1.0f };
*vtx++ = { 1.0f, -1.0f, 1.0f };
*vtx++ = { 0.0f, 0.0f, 1.0f };
*vtx++ = { 1.0f, 1.0f, 1.0f };
*vtx++ = { 0.0f, 0.0f, 1.0f };
*vtx++ = { -1.0f, 1.0f, 1.0f };
*vtx++ = { 0.0f, 0.0f, 1.0f };
*vtx++ = { -1.0f, 1.0f, 1.0f };
*vtx++ = { -1.0f, 0.0f, 0.0f };
*vtx++ = { -1.0f, 1.0f, -1.0f };
*vtx++ = { -1.0f, 0.0f, 0.0f };
*vtx++ = { -1.0f, -1.0f, -1.0f };
*vtx++ = { -1.0f, 0.0f, 0.0f };
*vtx++ = { -1.0f, -1.0f, 1.0f };
*vtx++ = { -1.0f, 0.0f, 0.0f };
*vtx++ = { 1.0f, 1.0f, -1.0f };
*vtx++ = { 1.0f, 0.0f, 0.0f };
*vtx++ = { 1.0f, 1.0f, 1.0f };
*vtx++ = { 1.0f, 0.0f, 0.0f };
*vtx++ = { 1.0f, -1.0f, -1.0f };
*vtx++ = { 1.0f, 0.0f, 0.0f };
*vtx++ = { 1.0f, -1.0f, 1.0f };
*vtx++ = { 1.0f, 0.0f, 0.0f };
*vtx++ = { -1.0f, -1.0f, -1.0f };
*vtx++ = { 0.0f, -1.0f, 0.0f };
*vtx++ = { 1.0f, -1.0f, -1.0f };
*vtx++ = { 0.0f, -1.0f, 0.0f };
*vtx++ = { 1.0f, -1.0f, 1.0f };
*vtx++ = { 0.0f, -1.0f, 0.0f };
*vtx++ = { -1.0f, -1.0f, 1.0f };
*vtx++ = { 0.0f, -1.0f, 0.0f };
*vtx++ = { -1.0f, 1.0f, -1.0f };
*vtx++ = { 0.0f, 1.0f, 0.0f };
*vtx++ = { 1.0f, 1.0f, 1.0f };
*vtx++ = { 0.0f, 1.0f, 0.0f };
*vtx++ = { 1.0f, 1.0f, -1.0f };
*vtx++ = { 0.0f, 1.0f, 0.0f };
*vtx++ = { -1.0f, 1.0f, 1.0f };
*vtx++ = { 0.0f, 1.0f, 0.0f };
}
static size_t gen_cube_indices(std::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(std::vector<float_t>& data,
int32_t slices, int32_t stacks, float_t radius) {
if (slices < 2 || stacks < 2)
return;
data.reserve(sizeof(vec3) * 2);
data.push_back(0.0f);
data.push_back(radius);
data.push_back(0.0f);
data.push_back(0.0f);
data.push_back(1.0f);
data.push_back(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(sizeof(vec3) * 2 * 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);
data.push_back(y * radius);
data.push_back(z * radius);
data.push_back(x);
data.push_back(y);
data.push_back(z);
}
}
data.reserve(sizeof(vec3) * 2);
data.push_back(0.0f);
data.push_back(-radius);
data.push_back(0.0f);
data.push_back(0.0f);
data.push_back(-1.0f);
data.push_back(0.0f);
}
static size_t gen_sphere_indices(std::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_capsule_vertices(std::vector<float_t>& 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.reserve(sizeof(vec3) * 2);
data.push_back(0.0f);
data.push_back(radius + length);
data.push_back(0.0f);
data.push_back(0.0f);
data.push_back(1.0f);
data.push_back(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);
data.reserve(sizeof(vec3) * 2 * 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);
data.push_back(y + length);
data.push_back(z * radius);
data.push_back(x);
data.push_back(y);
data.push_back(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);
data.reserve(sizeof(vec3) * 2 * 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);
data.push_back(y - length);
data.push_back(z * radius);
data.push_back(x);
data.push_back(y);
data.push_back(z);
}
}
data.reserve(sizeof(vec3) * 2);
data.push_back(0.0f);
data.push_back(-radius - length);
data.push_back(0.0f);
data.push_back(0.0f);
data.push_back(-1.0f);
data.push_back(0.0f);
}
static size_t gen_capsule_indices(std::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_ellipse_vertices(std::vector<float_t>& 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.reserve(sizeof(vec3) * 2);
data.push_back(0.0f);
data.push_back(radius + length);
data.push_back(0.0f);
data.push_back(0.0f);
data.push_back(1.0f);
data.push_back(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);
float_t y_n = y;
y *= radius + length;
data.reserve(sizeof(vec3) * 2 * 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);
data.push_back(y);
data.push_back(z * radius);
data.push_back(x);
data.push_back(y_n);
data.push_back(z);
}
}
data.reserve(sizeof(vec3) * 2);
data.push_back(0.0f);
data.push_back(-radius - length);
data.push_back(0.0f);
data.push_back(0.0f);
data.push_back(-1.0f);
data.push_back(0.0f);
}
static size_t gen_ellipse_indices(std::vector<uint32_t>& indices,
int32_t slices, int32_t stacks, float_t length) {
stacks = ((stacks + 1) >> 1) << 1;
return gen_sphere_indices(indices, slices, stacks);
}
static void gen_cylinder_vertices(std::vector<float_t>& data,
int32_t slices, int32_t stacks, float_t base, float_t top, float_t height) {
float_t half_height = height * 0.5f;
if (slices < 2 || stacks < 0)
return;
data.reserve(sizeof(vec3) * 2);
data.push_back(0.0f);
data.push_back(half_height);
data.push_back(0.0f);
data.push_back(0.0f);
data.push_back(1.0f);
data.push_back(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 = lerp_def(half_height, -half_height, (float_t)i / (float_t)stacks);
float_t radius = lerp_def(top, base, (float_t)i / (float_t)stacks);
data.reserve(sizeof(vec3) * 2 * 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 * radius);
data.push_back(y);
data.push_back(z * radius);
data.push_back(x);
data.push_back(0.0f);
data.push_back(z);
}
}
data.reserve(sizeof(vec3) * 2);
data.push_back(0.0f);
data.push_back(-half_height);
data.push_back(0.0f);
data.push_back(0.0f);
data.push_back(-1.0f);
data.push_back(0.0f);
}
static size_t gen_cylinder_indices(std::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_ELLIPSE: // 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;
vec3 size = cube.size * 0.5f;
mat4_scale_rot(&mat, &size, &mat);
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;
mat4_scale_rot(&mat, (float_t)plane.w * 0.5f, 1.0f, (float_t)plane.h * 0.5f, &mat);
} 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;
} break;
case mdl::ETC_OBJ_CROSS: {
EtcObjCross& cross = etc->data.cross;
mat4_scale_rot(&mat, cross.size, &mat);
} 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);
vec3 dir = vec3::normalize(capsule.pos[1] - capsule.pos[0]);
vec3 up = { 0.0f, 1.0f, 0.0f };
vec3 axis;
float_t angle;
Glitter::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_ELLIPSE: { // Added
EtcObjEllipse& ellipse = etc->data.ellipse;
vec3 origin = (ellipse.pos[0] + ellipse.pos[1]) * 0.5f;
mat4_add_translate(&mat, &origin, &mat);
vec3 dir = vec3::normalize(ellipse.pos[1] - ellipse.pos[0]);
vec3 up = { 0.0f, 1.0f, 0.0f };
vec3 axis;
float_t angle;
Glitter::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 = ellipse.wire;
length = vec3::distance(ellipse.pos[0], ellipse.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)
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
|| 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
|| 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
|| type == mdl::ETC_OBJ_CROSS
|| 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_ELLIPSE // Added
&& i.data.ellipse.slices == etc->data.ellipse.slices
&& ((i.data.ellipse.stacks + 1)) >> 1 == ((etc->data.ellipse.stacks + 1) >> 1)
&& fabsf(i.data.ellipse.radius - etc->data.ellipse.radius) < 0.00001f
&& fabsf(vec3::distance(i.data.ellipse.pos[0], i.data.ellipse.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.top - etc->data.cylinder.top) < 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();
}
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);
}
etc_vertex_array->alive_time = 2;
etc_vertex_array->data = etc->data;
etc_vertex_array->type = type;
std::vector<float_t> vtx_data;
std::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;
etc_vertex_array->count = (GLsizei)(vtx_data.size() / 6);
} break;
case mdl::ETC_OBJ_CUBE: {
EtcObjCube& cube = etc->data.cube;
gen_cube_vertices(vtx_data);
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;
etc_vertex_array->count = (GLsizei)(vtx_data.size() / 6);
} 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;
etc_vertex_array->count = (GLsizei)(vtx_data.size() / 6);
} break;
case mdl::ETC_OBJ_CROSS: {
EtcObjCross& cross = etc->data.cross;
etc_vertex_array->count = (GLsizei)(vtx_data.size() / 6);
} 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_ELLIPSE: { // Added
EtcObjEllipse& ellipse = etc->data.ellipse;
gen_ellipse_vertices(vtx_data, ellipse.slices, ellipse.stacks, length, ellipse.radius);
size_t wire_offset = gen_ellipse_indices(vtx_indices, ellipse.slices, ellipse.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.top, 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();
if (etc_vertex_array->vertex_buffer) {
glDeleteBuffers(1, &etc_vertex_array->vertex_buffer);
etc_vertex_array->vertex_buffer = 0;
}
}
if (etc_vertex_array->max_idx < vtx_indices.size()) {
etc_vertex_array->max_idx = vtx_indices.size();
if (etc_vertex_array->index_buffer) {
glDeleteBuffers(1, &etc_vertex_array->index_buffer);
etc_vertex_array->index_buffer = 0;
}
}
GLsizei size_vertex = sizeof(vec3) * 2;
gl_state_bind_vertex_array(etc_vertex_array->vertex_array);
if (!etc_vertex_array->vertex_buffer) {
glGenBuffers(1, &etc_vertex_array->vertex_buffer);
gl_state_bind_array_buffer(etc_vertex_array->vertex_buffer);
if (GLAD_GL_VERSION_4_4)
glBufferStorage(GL_ARRAY_BUFFER, sizeof(float_t)
* vtx_data.size(), vtx_data.data(), GL_DYNAMIC_STORAGE_BIT);
else
glBufferData(GL_ARRAY_BUFFER, sizeof(float_t)
* vtx_data.size(), vtx_data.data(), GL_DYNAMIC_DRAW);
}
else {
gl_state_bind_array_buffer(etc_vertex_array->vertex_buffer);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float_t)
* vtx_data.size(), vtx_data.data());
}
if (indexed)
if (!etc_vertex_array->index_buffer) {
glGenBuffers(1, &etc_vertex_array->index_buffer);
gl_state_bind_element_array_buffer(etc_vertex_array->index_buffer);
if (GLAD_GL_VERSION_4_4)
glBufferStorage(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t)
* vtx_indices.size(), vtx_indices.data(), GL_DYNAMIC_STORAGE_BIT);
else
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t)
* vtx_indices.size(), vtx_indices.data(), GL_DYNAMIC_DRAW);
}
else {
gl_state_bind_element_array_buffer(etc_vertex_array->index_buffer);
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);
}
ObjData* DispManager::alloc_data(ObjKind kind) {
if (!buff)
return 0;
int32_t size = (int32_t)align_val(sizeof(ObjKind) + sizeof(mat4) + sizeof(float_t) * 2, 0x08);
switch (kind) {
case OBJ_KIND_NORMAL:
size += sizeof(ObjSubMeshArgs);
break;
case OBJ_KIND_ETC:
size += sizeof(EtcObj);
break;
case OBJ_KIND_USER:
size += sizeof(UserArgs);
break;
case OBJ_KIND_TRANSLUCENT:
size += sizeof(ObjTranslucentArgs);
break;
default:
return 0;
}
if (buff_offset + size > buff_size)
return 0;
ObjData* data = (ObjData*)((size_t)buff + buff_offset);
buff_offset += size;
if (buff_max < buff_offset)
buff_max = buff_offset;
return data;
}
mat4* DispManager::alloc_data(int32_t count) {
if (!buff)
return 0;
int32_t size = sizeof(mat4) * count;
if (buff_offset + size > buff_size)
return 0;
mat4* mats = (mat4*)((size_t)buff + buff_offset);
buff_offset += size;
if (buff_max < buff_offset)
buff_max = buff_offset;
return mats;
}
void DispManager::buffer_reset() {
buff_offset = 0;
}
void DispManager::check_vertex_arrays() {
for (DispManager::vertex_array& i : vertex_array_cache)
if (i.alive_time > 0 && --i.alive_time <= 0) {
i.vertex_buffer = 0;
i.morph_vertex_buffer = 0;
}
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, true);
gl_state_bind_element_array_buffer(0, true);
gl_state_bind_vertex_array(0);
}
}
void DispManager::draw(ObjType type, int32_t depth_mask, bool a4) {
if (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 = uniform_value[U_REFLECT] == 1;
void(*func)(render_context * rctx, const ObjSubMeshArgs * args) = draw_sub_mesh_default;
for (int32_t i = 0; i < 5; i++)
gl_state_active_bind_texture_2d(i, rctx_ptr->empty_texture_2d);
gl_state_active_bind_texture_cube_map(5, rctx_ptr->empty_texture_cube_map);
gl_state_active_texture(0);
gl_state_set_blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
uniform_value_reset();
gl_state_get();
rctx_ptr->obj_scene_ubo.Bind(0);
rctx_ptr->obj_batch_ubo.Bind(1);
rctx_ptr->obj_skinning_ubo.Bind(3);
switch (type) {
case OBJ_TYPE_TRANSLUCENT:
case OBJ_TYPE_TRANSLUCENT_NO_SHADOW:
case OBJ_TYPE_TRANSLUCENT_LOCAL:
if (depth_mask)
func = draw_sub_mesh_translucent;
else
gl_state_set_depth_mask(GL_FALSE);
alpha_test = 1;
min_alpha = 0.0f;
alpha_threshold = 0.0f;
break;
case OBJ_TYPE_TRANSPARENT:
case OBJ_TYPE_TRANSPARENT_LOCAL:
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_translucent;
gl_state_set_color_mask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
rctx_ptr->draw_state.shader_index = SHADER_FT_SIL;
break;
case OBJ_TYPE_TYPE_7:
func = draw_sub_mesh_translucent;
gl_state_set_color_mask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
rctx_ptr->draw_state.shader_index = SHADER_FT_SIL;
alpha_test = 1;
min_alpha = 0.0f;
alpha_threshold = 0.99999994f;
break;
case OBJ_TYPE_REFLECT_CHARA_OPAQUE:
gl_state_set_cull_face_mode(GL_FRONT);
if (reflect)
func = draw_sub_mesh_reflect;
else if (rctx_ptr->render_manager.reflect_type == STAGE_DATA_REFLECT_REFLECT_MAP)
func = draw_sub_mesh_reflect_reflect_map;
break;
case OBJ_TYPE_REFLECT_CHARA_TRANSLUCENT:
gl_state_set_cull_face_mode(GL_FRONT);
if (reflect)
func = draw_sub_mesh_reflect;
else if (rctx_ptr->render_manager.reflect_type == STAGE_DATA_REFLECT_REFLECT_MAP)
func = draw_sub_mesh_reflect_reflect_map;
min_alpha = 0.0f;
break;
case OBJ_TYPE_REFLECT_CHARA_TRANSPARENT:
gl_state_set_cull_face_mode(GL_FRONT);
if (reflect)
func = draw_sub_mesh_reflect;
else if (rctx_ptr->render_manager.reflect_type == STAGE_DATA_REFLECT_REFLECT_MAP)
func = draw_sub_mesh_reflect_reflect_map;
alpha_test = 1;
min_alpha = 0.1f;
alpha_threshold = 0.5f;
break;
case OBJ_TYPE_REFLECT_OPAQUE:
alpha_test = 1;
if (!a4)
func = draw_sub_mesh_reflect_reflect_map;
break;
case OBJ_TYPE_REFLECT_TRANSLUCENT:
case OBJ_TYPE_REFRACT_TRANSLUCENT:
gl_state_set_depth_mask(GL_FALSE);
min_alpha = 0.0f;
alpha_threshold = 0.0f;
break;
case OBJ_TYPE_REFLECT_TRANSPARENT:
case OBJ_TYPE_REFRACT_TRANSPARENT:
alpha_test = 1;
min_alpha = 0.1f;
alpha_threshold = 0.0f;
break;
case OBJ_TYPE_SSS:
func = draw_sub_mesh_sss;
break;
case OBJ_TYPE_USER:
func = draw_sub_mesh_translucent;
break;
default:
break;
}
rctx_ptr->obj_batch.g_max_alpha = { 0.0f, 0.0f, alpha_threshold, min_alpha };
uniform_value[U_ALPHA_TEST] = alpha_test;
for (ObjData*& i : obj[type]) {
switch (i->kind) {
case OBJ_KIND_NORMAL: {
draw_sub_mesh(rctx_ptr, &i->args.sub_mesh, &i->mat, func);
} break;
case OBJ_KIND_ETC: {
draw_object_model_mat_load(rctx_ptr, i->mat);
draw_etc_obj(rctx_ptr, &i->args.etc);
} break;
case OBJ_KIND_USER: {
draw_object_model_mat_load(rctx_ptr, i->mat);
i->args.user.func(rctx_ptr, i->args.user.data);
} break;
case OBJ_KIND_TRANSLUCENT: {
for (uint32_t j = 0; j < i->args.translucent.count; j++)
draw_sub_mesh(rctx_ptr, i->args.translucent.sub_mesh[j], &i->mat, func);
} break;
}
}
switch (type) {
case OBJ_TYPE_TRANSLUCENT:
case OBJ_TYPE_TRANSLUCENT_NO_SHADOW:
case OBJ_TYPE_REFLECT_TRANSLUCENT:
case OBJ_TYPE_REFRACT_TRANSLUCENT:
if (!depth_mask)
gl_state_set_depth_mask(GL_TRUE);
break;
case OBJ_TYPE_TYPE_6:
case OBJ_TYPE_TYPE_7:
rctx_ptr->draw_state.shader_index = -1;
gl_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:
gl_state_set_cull_face_mode(GL_BACK);
break;
}
uniform_value_reset();
gl_state_bind_vertex_array(0);
shader::unbind();
gl_state_set_blend_func(GL_ONE, GL_ZERO);
for (int32_t i = 0; i < 5; i++)
gl_state_bind_sampler(i, 0);
}
void DispManager::draw_translucent(ObjType type, int32_t alpha) {
if (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 = uniform_value[U_REFLECT] == 1;
void(*func)(render_context * rctx, const ObjSubMeshArgs * args) = draw_sub_mesh_default;
for (int32_t i = 0; i < 5; i++)
gl_state_active_bind_texture_2d(i, rctx_ptr->empty_texture_2d);
gl_state_active_bind_texture_cube_map(5, rctx_ptr->empty_texture_cube_map);
gl_state_active_texture(0);
gl_state_set_blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
uniform_value_reset();
gl_state_get();
rctx_ptr->obj_scene_ubo.Bind(0);
rctx_ptr->obj_batch_ubo.Bind(1);
rctx_ptr->obj_skinning_ubo.Bind(3);
switch (type) {
case OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_1:
case OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_2:
case OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_3:
case OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_2_LOCAL:
gl_state_set_depth_mask(GL_FALSE);
alpha_test = 1;
min_alpha = 0.0f;
alpha_threshold = 0.0f;
break;
case OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_1:
case OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_2:
case OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_3:
case OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_2_LOCAL:
alpha_test = 1;
min_alpha = 0.1f;
alpha_threshold = 0.5f;
break;
}
rctx_ptr->obj_batch.g_max_alpha = { 0.0f, 0.0f, alpha_threshold, min_alpha };
uniform_value[U_ALPHA_TEST] = alpha_test;
for (ObjData*& i : obj[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(rctx_ptr, &i->args.sub_mesh, &i->mat, func);
} break;
case OBJ_KIND_TRANSLUCENT: {
for (uint32_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(rctx_ptr, args, &i->mat, func);
}
} break;
}
}
switch (type) {
case OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_1:
case OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_2:
case OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_3:
gl_state_set_depth_mask(GL_TRUE);
break;
case OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_1:
case OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_2:
case OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_3:
gl_state_set_cull_face_mode(GL_BACK);
break;
}
uniform_value_reset();
shader::unbind();
gl_state_set_blend_func(GL_ONE, GL_ZERO);
}
/*void DispManager::draw_show_vector(ObjType type, int32_t show_vector) {
if (get_obj_count(type) < 1)
return;
for (int32_t i = 0; i < 5; i++)
gl_state_active_bind_texture_2d(i, rctx_ptr->empty_texture_2d);
gl_state_active_bind_texture_cube_map(5, rctx_ptr->empty_texture_cube_map);
gl_state_active_texture(0);
gl_state_set_blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
uniform_value_reset();
gl_state_get();
for (ObjData*& i : obj[type]) {
switch (i->type) {
case OBJ_KIND_NORMAL: {
draw_sub_mesh_show_vector(rctx_ptr, &i->args.sub_mesh,
&i->mat, show_vector);
} break;
case OBJ_KIND_TRANSLUCENT: {
for (uint32_t j = 0; j < i->args.translucent.count; j++)
draw_sub_mesh_show_vector(rctx_ptr, i->args.translucent.sub_mesh[j],
&i->mat, show_vector);
} break;
}
}
gl_state_set_blend_func(GL_ONE, GL_ZERO);
}*/
void DispManager::entry_list(ObjType type, ObjData* data) {
obj[type].push_back(data);
}
static int32_t obj_axis_aligned_bounding_box_check_visibility(
obj_axis_aligned_bounding_box* aabb, camera* cam, 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(mat, &cam->view, &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 = (float_t)-cam->min_distance;
*(vec3*)&v2[1] = cam->field_1E4;
v2[1].w = 0.0f;
*(vec3*)&v2[2] = cam->field_1F0;
v2[2].w = 0.0f;
*(vec3*)&v2[3] = cam->field_1FC;
v2[3].w = 0.0f;
*(vec3*)&v2[4] = cam->field_208;
v2[4].w = 0.0f;
*(vec3*)&v2[5] = { 0.0f, 0.0f, 1.0f };
v2[5].w = (float_t)cam->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_bounding_sphere_check_visibility(obj_bounding_sphere* sphere,
CullingCheck* culling, camera* cam, const mat4* mat) {
if (culling->func)
return culling->func(sphere, &cam->view);
vec3 center;
mat4_transform_point(mat, &sphere->center, &center);
mat4_transform_point(&cam->view, &center, &center);
float_t radius = mat4_get_max_scale(mat) * sphere->radius;
double_t min_depth = (double_t)center.z - (double_t)radius;
double_t max_depth = (double_t)center.z + (double_t)radius;
if (-cam->min_distance < min_depth || -cam->max_distance > max_depth)
return 0;
float_t v5 = vec3::dot(cam->field_1E4, center);
if (v5 < -radius)
return 0;
float_t v6 = vec3::dot(cam->field_1F0, center);
if (v6 < -radius)
return 0;
float_t v7 = vec3::dot(cam->field_1FC, center);
if (v7 < -radius)
return 0;
float_t v8 = vec3::dot(cam->field_208, center);
if (v8 < -radius)
return 0;
if (-cam->min_distance >= max_depth && -cam->max_distance <= min_depth
&& v5 >= radius && v6 >= radius && v7 >= radius && v8 >= radius)
return 1;
return 2;
}
bool DispManager::entry_obj(::obj* object, obj_mesh_vertex_buffer* obj_vertex_buf,
obj_mesh_index_buffer* obj_index_buf, const mat4* mat,
std::vector<texture*>* textures, vec4* blend_color, mat4* bone_mat, ::obj* object_morph,
obj_mesh_vertex_buffer* obj_morph_vertex_buf, int32_t instances_count,
mat4* instances_mat, void(*func)(const ObjSubMeshArgs*), bool enable_bone_mat, bool local) {
if (!obj_vertex_buf || !obj_index_buf) {
printf_debug("mdl::DispManager::entry_obj: no vertex or index object buffer to draw;\n");
printf_debug(" Object: %s\n", object->name);
return false;
}
::camera* cam = rctx_ptr->camera;
cam->update_data();
if (!local && object_culling && !instances_count && !bone_mat && (!object
|| !obj_bounding_sphere_check_visibility(
&object->bounding_sphere, &culling, cam, mat))) {
culling.culled.objects++;
return false;
}
culling.passed.objects++;
for (uint32_t i = 0; i < object->num_mesh; i++) {
obj_mesh* mesh = &object->mesh_array[i];
obj_mesh* mesh_morph = 0;
if (obj_vertex_buf && obj_morph_vertex_buf) {
if (obj_vertex_buf[i].get_size() != obj_morph_vertex_buf[i].get_size())
continue;
if (object_morph && i < object_morph->num_mesh)
mesh_morph = &object_morph->mesh_array[i];
}
if (!local && object_culling && !instances_count && !bone_mat
&& !obj_bounding_sphere_check_visibility(
&mesh->bounding_sphere, &culling, cam, mat)
&& (!mesh_morph || !obj_bounding_sphere_check_visibility(
&mesh_morph->bounding_sphere, &culling, cam, mat))) {
culling.culled.meshes++;
continue;
}
culling.passed.meshes++;
ObjSubMeshArgs* translucent_priority[40];
int32_t translucent_priority_count = 0;
for (uint32_t j = 0; j < mesh->num_submesh; j++) {
obj_sub_mesh* sub_mesh = &mesh->submesh_array[j];
obj_sub_mesh* sub_mesh_morph = 0;
if (sub_mesh->attrib.m.cloth)
continue;
if (!local && object_culling && !instances_count && !bone_mat) {
int32_t v32 = obj_bounding_sphere_check_visibility(
&sub_mesh->bounding_sphere, &culling, cam, mat);
if (v32 != 2 || (!mesh->attrib.m.billboard && !mesh->attrib.m.billboard_y_axis)) {
if (v32 == 2) {
if (culling.func)
v32 = 1;
else
v32 = obj_axis_aligned_bounding_box_check_visibility(
&sub_mesh->axis_aligned_bounding_box, cam, mat);
}
if (!v32) {
if (!mesh_morph || j >= mesh_morph->num_submesh) {
culling.culled.submesh_array++;
continue;
}
sub_mesh_morph = &mesh_morph->submesh_array[j];
if (!sub_mesh_morph) {
culling.culled.submesh_array++;
continue;
}
v32 = obj_bounding_sphere_check_visibility(
&sub_mesh_morph->bounding_sphere, &culling, cam, mat);
if (v32 == 2) {
if (culling.func)
v32 = 1;
else
v32 = obj_axis_aligned_bounding_box_check_visibility(
&sub_mesh_morph->axis_aligned_bounding_box, cam, mat);
}
if (!v32) {
culling.culled.submesh_array++;
continue;
}
}
}
}
culling.passed.submesh_array++;
int32_t num_bone_index = sub_mesh->num_bone_index;
uint16_t* bone_index = sub_mesh->bone_index_array;
mat4* mats;
if (num_bone_index && enable_bone_mat) {
mats = alloc_data(num_bone_index);
if (bone_mat)
for (int32_t k = 0; k < num_bone_index; k++, bone_index++)
mats[k] = bone_mat[*bone_index];
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 = &object->material_array[sub_mesh->material_index];
ObjData* data = alloc_data(OBJ_KIND_NORMAL);
if (!data)
continue;
//GLuint morph_vertex_buffer = 0;
//if (obj_morph_vertex_buf)
// morph_vertex_buffer = obj_morph_vertex_buf[i].get_buffer();
obj_mesh_vertex_buffer* morph_vertex_buffer
= obj_morph_vertex_buf ? &obj_morph_vertex_buf[i] : 0;
//GLuint index_buffer = 0;
//if (obj_index_buf)
// index_buffer = obj_index_buf[i].buffer;
obj_mesh_index_buffer* index_buffer = &obj_index_buf[i];
//GLuint vertex_buffer = 0;
//if (obj_vertex_buf)
// vertex_buffer = obj_vertex_buf[i].get_buffer();
obj_mesh_vertex_buffer* vertex_buffer = &obj_vertex_buf[i];
if (!vertex_buffer || !index_buffer || obj_morph_vertex_buf && !morph_vertex_buffer) {
printf_debug("mdl::DispManager::entry_obj: no vertex or index mesh buffer to draw;\n");
printf_debug(" Object: %s; Mesh: %s; Sub Mesh: %d\n", object->name, mesh->name, j);
continue;
}
uint32_t material_hash = hash_utf8_murmurhash(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;
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(this, mat, object->bounding_sphere.radius, sub_mesh,
mesh, material, textures, num_bone_index, mats, vertex_buffer, index_buffer,
&_blend_color, &_emission, morph_vertex_buffer, instances_count, instances_mat, func);
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;
}
obj_material_attrib_member attrib = material->material.attrib.m;
if (obj_flags & (mdl::OBJ_ALPHA_ORDER_1 | mdl::OBJ_ALPHA_ORDER_2 | mdl::OBJ_ALPHA_ORDER_3)
&& 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.transparent) {
if (!attrib.punch_through) {
if (obj_flags & mdl::OBJ_ALPHA_ORDER_1)
entry_list(OBJ_TYPE_OPAQUE_ALPHA_ORDER_1, data);
else if (obj_flags & mdl::OBJ_ALPHA_ORDER_2)
entry_list(local ? OBJ_TYPE_OPAQUE_ALPHA_ORDER_2_LOCAL
: OBJ_TYPE_OPAQUE_ALPHA_ORDER_2, data);
else
entry_list(OBJ_TYPE_OPAQUE_ALPHA_ORDER_3, data);
}
else {
if (obj_flags & mdl::OBJ_ALPHA_ORDER_1)
entry_list(OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_1, data);
else if (obj_flags & mdl::OBJ_ALPHA_ORDER_2)
entry_list(local ? OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_2_LOCAL
: OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_2, data);
else
entry_list(OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_3, data);
}
if (obj_flags & mdl::OBJ_SSS)
entry_list(OBJ_TYPE_SSS, data);
}
if (obj_flags & mdl::OBJ_ALPHA_ORDER_1)
entry_list(OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_1, data);
else if (obj_flags & mdl::OBJ_ALPHA_ORDER_2)
entry_list(local ? OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_2_LOCAL
: OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_2, data);
else
entry_list(OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_3, data);
}
}
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.transparent) {
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(local ? OBJ_TYPE_TRANSPARENT_LOCAL
: 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(local ? OBJ_TYPE_OPAQUE_LOCAL
: 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 (local)
entry_list(OBJ_TYPE_TRANSLUCENT_LOCAL, data);
else if (mesh->attrib.m.translucent_no_shadow
|| obj_flags & mdl::OBJ_TRANSLUCENT_NO_SHADOW) {
entry_list(OBJ_TYPE_TRANSLUCENT_NO_SHADOW, 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 (rctx_ptr->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_data(OBJ_KIND_TRANSLUCENT);
if (!data)
continue;
data->init_translucent(mat, &translucent_args);
if (obj_flags & mdl::OBJ_ALPHA_ORDER_1)
entry_list(OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_1, data);
else if (obj_flags & mdl::OBJ_ALPHA_ORDER_2)
entry_list(local ? OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_2_LOCAL
: OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_2, data);
else if (obj_flags & mdl::OBJ_ALPHA_ORDER_3)
entry_list(OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_3, data);
else
entry_list(local ? OBJ_TYPE_TRANSLUCENT_LOCAL
: OBJ_TYPE_TRANSLUCENT, data);
}
return true;
}
void DispManager::entry_obj_by_obj(const mat4* mat,
::obj* obj, std::vector<texture*>* textures, obj_mesh_vertex_buffer* obj_vert_buf,
obj_mesh_index_buffer* obj_index_buf, mat4* bone_mat, float_t alpha) {
if (!obj)
return;
vec4 blend_color = { 1.0f, 1.0f, 1.0f, alpha };
vec4* blend_color_ptr = alpha < 1.0f ? &blend_color : 0;
entry_obj(obj, obj_vert_buf, obj_index_buf, mat, textures, blend_color_ptr,
bone_mat, 0, 0, 0, 0, 0, !!bone_mat);
}
bool DispManager::entry_obj_by_object_info(const mat4* mat, object_info obj_info, mat4* bone_mat) {
vec4 blend_color = 1.0f;
return entry_obj_by_object_info(mat, obj_info, &blend_color, bone_mat, 0, 0, 0, true);
}
bool DispManager::entry_obj_by_object_info(const mat4* mat, object_info obj_info,
vec4* blend_color, mat4* bone_mat, int32_t instances_count,
mat4* instances_mat, void(*func)(const ObjSubMeshArgs*), bool enable_bone_mat, bool local) {
if (obj_info.id == -1 && obj_info.set_id == -1)
return false;
::obj* object = object_storage_get_obj(obj_info);
if (!object)
return false;
std::vector<texture*>* textures = object_storage_get_obj_set_textures(obj_info.set_id);
obj_mesh_vertex_buffer* obj_vertex_buffer = object_storage_get_obj_mesh_vertex_buffer(obj_info);
obj_mesh_index_buffer* obj_index_buffer = object_storage_get_obj_mesh_index_buffer(obj_info);
::obj* obj_morph = 0;
obj_mesh_vertex_buffer* obj_morph_vertex_buffer = 0;
if (morph.object.set_id != -1) {
obj_morph = object_storage_get_obj(morph.object);
obj_morph_vertex_buffer = object_storage_get_obj_mesh_vertex_buffer(morph.object);
}
return entry_obj(object, obj_vertex_buffer, obj_index_buffer,
mat, textures, blend_color, bone_mat, obj_morph, obj_morph_vertex_buffer,
instances_count, instances_mat, func, enable_bone_mat, local);
}
bool DispManager::entry_obj_by_object_info(const mat4* mat,
object_info obj_info, float_t alpha, 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, true);
}
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, mat4* bone_mat, bool local) {
vec4 blend_color = { r, g, b, a };
return entry_obj_by_object_info(mat, obj_info, &blend_color, bone_mat, 0, 0, 0, true, local);
}
bool DispManager::entry_obj_by_object_info(const mat4* mat, object_info obj_info,
vec4* blend_color, mat4* bone_mat, bool local) {
return entry_obj_by_object_info(mat, obj_info, blend_color, 0, 0, 0, 0, false, local);
}
void DispManager::entry_obj_by_object_info_object_skin(object_info obj_info,
std::vector<texture_pattern_struct>* texture_pattern, texture_data_struct* texture_data, float_t alpha,
mat4* matrices, mat4* ex_data_matrices, const mat4* mat, const mat4* global_mat) {
obj_skin* skin = object_storage_get_obj_skin(obj_info);
if (!skin)
return;
obj_skin_set_matrix_buffer(skin, matrices, ex_data_matrices, rctx_ptr->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, rctx_ptr->matrix_buffer);
else
entry_obj_by_object_info(global_mat, obj_info, rctx_ptr->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, EtcObj* etc, bool local) {
ObjData* data = alloc_data(mdl::OBJ_KIND_ETC);
if (!data)
return;
data->init_etc(this, mat, etc);
if (etc->color.a == 0xFF) {
if (!local && (obj_flags & OBJ_SHADOW))
mdl::DispManager::entry_list((mdl::ObjType)(OBJ_TYPE_SHADOW_CHARA + shadow_type), data);
mdl::DispManager::entry_list(local ? OBJ_TYPE_OPAQUE_LOCAL : OBJ_TYPE_OPAQUE, data);
}
else
mdl::DispManager::entry_list(local ? OBJ_TYPE_TRANSLUCENT_LOCAL : OBJ_TYPE_TRANSLUCENT, data);
}
void DispManager::entry_obj_user(const mat4* mat, UserArgsFunc func, void* data, ObjType type) {
ObjData* _data = alloc_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;
obj_mesh_vertex_buffer* vertex_buffer = args->vertex_buffer;
//GLuint morph_vertex_buffer = args->morph_vertex_buffer;
obj_mesh_vertex_buffer* morph_vertex_buffer = args->morph_vertex_buffer;
//GLuint index_buffer = args->index_buffer;
obj_mesh_index_buffer* 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);
bool compressed = mesh->attrib.m.compressed;
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.morph_vertex_buffer == morph_vertex_buffer
&& i.index_buffer == index_buffer && i.vertex_format == vertex_format
&& i.size_vertex == size_vertex && i.compressed == compressed
&& !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:
case mdl::ETC_OBJ_LINE:
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_ELLIPSE: // Added
length = vec3::distance(etc->data.ellipse.pos[0], etc->data.ellipse.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:
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:
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:
return i.vertex_array;
case mdl::ETC_OBJ_CROSS:
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_ELLIPSE: // Added
if (i.data.ellipse.slices == etc->data.ellipse.slices
&& ((i.data.ellipse.stacks + 1)) >> 1 == ((etc->data.ellipse.stacks + 1) >> 1)
&& fabsf(i.data.ellipse.radius - etc->data.ellipse.radius) < 0.00001f
&& fabsf(vec3::distance(i.data.ellipse.pos[0], i.data.ellipse.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.top - etc->data.cylinder.top) < 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;
}
ObjFlags DispManager::get_obj_flags() {
return obj_flags;
}
void DispManager::get_material_list(int32_t& count, material_list_struct*& value) {
count = material_list_count;
for (int32_t i = 0; i < count; i++)
value[i] = material_list_array[i];
}
void DispManager::get_morph(object_info& object, float_t& weight) {
weight = morph.weight;
object = morph.object;
}
int32_t DispManager::get_obj_count(ObjType type) {
return (int32_t)obj[type].size();
}
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;
}
static int mdl_obj_data_sort_quicksort_compare0(void const* src1, void const* src2) {
float_t d1 = (*(ObjData**)src1)->view_z;
float_t d2 = (*(ObjData**)src2)->view_z;
return d1 > d2 ? -1 : (d1 < d2 ? 1 : 0);
}
static int mdl_obj_data_sort_quicksort_compare1(void const* src1, void const* src2) {
float_t d1 = (*(ObjData**)src1)->view_z;
float_t d2 = (*(ObjData**)src2)->view_z;
return d1 < d2 ? -1 : (d1 > d2 ? 1 : 0);
}
static int mdl_obj_data_sort_quicksort_compare2(void const* src1, void const* src2) {
float_t r1 = (*(ObjData**)src1)->radius;
float_t r2 = (*(ObjData**)src2)->radius;
return r1 > r2 ? -1 : (r1 < r2 ? 1 : 0);
}
void DispManager::obj_sort(mat4* view, ObjType type, int32_t compare_func) {
std::vector<ObjData*>& vec = obj[type];
if (vec.size() < 1)
return;
for (ObjData*& i : vec) {
vec3 center;
mat4_get_translation(&i->mat, &center);
if (i->kind == OBJ_KIND_NORMAL) {
mat4 mat = i->mat;
if (i->args.sub_mesh.mesh->attrib.m.billboard)
model_mat_face_camera_view(view, &mat, &mat);
else if (i->args.sub_mesh.mesh->attrib.m.billboard_y_axis)
model_mat_face_camera_position(view, &mat, &mat);
const obj_sub_mesh* sub_mesh = i->args.sub_mesh.sub_mesh;
if (i->args.sub_mesh.mat_count < 1 || !sub_mesh->num_bone_index)
mat4_transform_point(&mat, &sub_mesh->bounding_sphere.center, &center);
else {
vec3 center_sum = 0.0f;
for (uint32_t j = 0; j < sub_mesh->num_bone_index; j++) {
center = sub_mesh->bounding_sphere.center;
mat4_transform_point(&i->args.sub_mesh.mats[j], &center, &center);
center_sum += center;
}
center_sum *= 1.0f / (float_t)sub_mesh->num_bone_index;
}
i->radius = i->args.sub_mesh.mesh->bounding_sphere.radius;
}
mat4_transform_point(view, &center, &center);
i->view_z = center.z;
}
switch (compare_func) {
case 0:
quicksort_custom(vec.data(), vec.size(),
sizeof(ObjData*), mdl_obj_data_sort_quicksort_compare0);
break;
case 1:
quicksort_custom(vec.data(), vec.size(),
sizeof(ObjData*), mdl_obj_data_sort_quicksort_compare1);
break;
case 2:
quicksort_custom(vec.data(), vec.size(),
sizeof(ObjData*), mdl_obj_data_sort_quicksort_compare2);
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 (std::vector<ObjData*>& i : obj)
i.clear();
buffer_reset();
}
void DispManager::set_chara_color(bool value) {
chara_color = value;
}
void DispManager::set_obj_flags(ObjFlags flags) {
obj_flags = flags;
}
void DispManager::set_material_list(int32_t count, 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_culling_finc(bool(*func)(obj_bounding_sphere*, mat4*)) {
culling.func = func;
}
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, 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, 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;
}
}
namespace rndr {
RenderManager::RenderManager() : pass_sw(), reflect_blur_num(), reflect_blur_filter(), sync_gpu(),
cpu_time(), gpu_time(), time(), draw_pass_3d(), show_ref_map(), reflect_type(), clear(),
tex_index(), multisample_framebuffer(), multisample_renderbuffer(), multisample(),
show_vector_flags(), show_vector_length(), show_vector_z_offset(), field_2F8(), effect_texture(),
npr_param(), field_31C(), field_31D(), field_31E(), field_31F(), field_320(), npr() {
for (bool& i : pass_sw)
i = true;
set_pass_sw(RND_PASSID_2, false);
set_pass_sw(RND_PASSID_REFLECT, false);
set_pass_sw(RND_PASSID_REFRACT, false);
set_pass_sw(RND_PASSID_PRE_PROCESS, false);
set_pass_sw(RND_PASSID_SHOW_VECTOR, false);
shadow = true;
opaque_z_sort = true;
alpha_z_sort = true;
for (bool& i : draw_pass_3d)
i = true;
shadow_ptr = new Shadow;
if (shadow_ptr)
shadow_ptr->InitData();
for (int32_t i = 0; i < 9; i++) {
const struc_189* v2 = &stru_140A24420[i];
if (v2->type != GL_TEXTURE_2D)
continue;
RenderTexture& rt = render_textures[i];
rt.Init(v2->width, v2->height, v2->max_level, v2->color_format, v2->depth_format);
rt.Bind();
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
gl_state_bind_framebuffer(0);
}
RenderManager::~RenderManager() {
if (multisample_framebuffer) {
glDeleteFramebuffers(1, &multisample_framebuffer);
multisample_framebuffer = 0;
}
if (multisample_renderbuffer) {
glDeleteRenderbuffers(1, &multisample_renderbuffer);
multisample_renderbuffer = 0;
}
delete shadow_ptr;
}
void RenderManager::add_pre_process(int32_t type, void(*func)(void*), void* data) {
pre_process.push_back({ type, func, data });
}
void RenderManager::clear_pre_process(int32_t type) {
for (std::list<draw_pre_process>::iterator i = pre_process.begin(); i != pre_process.end(); i++)
if (i->type == type) {
pre_process.erase(i);
break;
}
}
RenderTexture& RenderManager::get_render_texture(int32_t index) {
return render_textures[stru_140A244E0[index][tex_index[index]]];
}
void RenderManager::resize(int32_t width, int32_t height) {
if (!multisample_framebuffer)
glGenFramebuffers(1, &multisample_framebuffer);
if (!multisample_renderbuffer)
glGenRenderbuffers(1, &multisample_renderbuffer);
glBindFramebuffer(GL_FRAMEBUFFER, multisample_framebuffer);
glBindRenderbuffer(GL_RENDERBUFFER, multisample_renderbuffer);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, 8, GL_RGBA8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, multisample_renderbuffer);
glDrawBuffer(GL_COLOR_ATTACHMENT0);
glReadBuffer(GL_COLOR_ATTACHMENT0);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
void RenderManager::set_effect_texture(texture* value) {
effect_texture = value;
}
void RenderManager::set_multisample(bool value) {
multisample = value;
}
void RenderManager::set_npr_param(int32_t value) {
npr_param = value;
}
void RenderManager::set_pass_sw(RenderPassID id, bool value) {
pass_sw[id] = value;
}
void RenderManager::set_reflect(bool value) {
reflect = value;
}
void RenderManager::set_reflect_blur(int32_t reflect_blur_num, blur_filter_mode reflect_blur_filter) {
this->reflect_blur_num = reflect_blur_num;
this->reflect_blur_filter = reflect_blur_filter;
}
void RenderManager::set_reflect_resolution_mode(reflect_refract_resolution_mode mode) {
tex_index[0] = mode;
}
void RenderManager::set_reflect_type(stage_data_reflect_type type) {
reflect_type = type;
}
void RenderManager::set_refract(bool value) {
refract = value;
}
void RenderManager::set_refract_resolution_mode(reflect_refract_resolution_mode mode) {
tex_index[1] = mode;
}
void RenderManager::set_shadow_false() {
shadow = false;
}
void RenderManager::set_shadow_true() {
shadow = true;
}
}
extern float_t rob_frame;
extern render_context* rctx_ptr;
void obj_scene_shader_data::set_g_irradiance_r_transforms(const mat4& mat) {
mat4 temp;
mat4_transpose(&mat, &temp);
g_irradiance_r_transforms[0] = temp.row0;
g_irradiance_r_transforms[1] = temp.row1;
g_irradiance_r_transforms[2] = temp.row2;
g_irradiance_r_transforms[3] = temp.row3;
}
void obj_scene_shader_data::set_g_irradiance_g_transforms(const mat4& mat) {
mat4 temp;
mat4_transpose(&mat, &temp);
g_irradiance_g_transforms[0] = temp.row0;
g_irradiance_g_transforms[1] = temp.row1;
g_irradiance_g_transforms[2] = temp.row2;
g_irradiance_g_transforms[3] = temp.row3;
}
void obj_scene_shader_data::set_g_irradiance_b_transforms(const mat4& mat) {
mat4 temp;
mat4_transpose(&mat, &temp);
g_irradiance_b_transforms[0] = temp.row0;
g_irradiance_b_transforms[1] = temp.row1;
g_irradiance_b_transforms[2] = temp.row2;
g_irradiance_b_transforms[3] = temp.row3;
}
void obj_scene_shader_data::set_g_normal_tangent_transforms(const mat4& mat) {
mat4 temp;
mat4_transpose(&mat, &temp);
g_normal_tangent_transforms[0] = temp.row0;
g_normal_tangent_transforms[1] = temp.row1;
g_normal_tangent_transforms[2] = temp.row2;
}
void obj_scene_shader_data::set_g_self_shadow_receivers(int32_t index, const mat4& mat) {
size_t _index = index * 3LL;
mat4 temp;
mat4_transpose(&mat, &temp);
g_self_shadow_receivers[_index + 0] = temp.row0;
g_self_shadow_receivers[_index + 1] = temp.row1;
g_self_shadow_receivers[_index + 2] = temp.row2;
}
void obj_scene_shader_data::set_g_light_projection(const mat4& mat) {
mat4 temp;
mat4_transpose(&mat, &temp);
g_light_projection[0] = temp.row0;
g_light_projection[1] = temp.row1;
g_light_projection[2] = temp.row2;
g_light_projection[3] = temp.row3;
}
void obj_scene_shader_data::set_projection_view(const mat4& view, const mat4& proj) {
mat4 temp;
mat4_transpose(&view, &temp);
g_view[0] = temp.row0;
g_view[1] = temp.row1;
g_view[2] = temp.row2;
mat4_invert(&view, &temp);
mat4_transpose(&temp, &temp);
g_view_inverse[0] = temp.row0;
g_view_inverse[1] = temp.row1;
g_view_inverse[2] = temp.row2;
mat4_mul(&view, &proj, &temp);
mat4_transpose(&temp, &temp);
g_projection_view[0] = temp.row0;
g_projection_view[1] = temp.row1;
g_projection_view[2] = temp.row2;
g_projection_view[3] = temp.row3;
}
void obj_batch_shader_data::set_g_joint(const mat4& mat) {
mat4 temp;
mat4_transpose(&mat, &temp);
g_joint[0] = temp.row0;
g_joint[1] = temp.row1;
g_joint[2] = temp.row2;
mat4_invert(&mat, &temp);
mat4_transpose(&temp, &temp);
g_joint_inverse[0] = temp.row0;
g_joint_inverse[1] = temp.row1;
g_joint_inverse[2] = temp.row2;
}
void obj_batch_shader_data::set_g_texcoord_transforms(int32_t index, const mat4& mat) {
size_t _index = index * 2LL;
mat4 temp;
mat4_transpose(&mat, &temp);
g_texcoord_transforms[_index + 0] = temp.row0;
g_texcoord_transforms[_index + 1] = temp.row1;
}
void obj_batch_shader_data::set_transforms(const mat4& model, const mat4& view, const mat4& proj) {
mat4 temp;
mat4_transpose(&model, &temp);
g_worlds[0] = temp.row0;
g_worlds[1] = temp.row1;
g_worlds[2] = temp.row2;
mat4_invert(&model, &temp);
g_worlds_invtrans[0] = temp.row0;
g_worlds_invtrans[1] = temp.row1;
g_worlds_invtrans[2] = temp.row2;
mat4 mv;
mat4_mul(&model, &view, &mv);
mat4_transpose(&mv, &temp);
g_worldview[0] = temp.row0;
g_worldview[1] = temp.row1;
g_worldview[2] = temp.row2;
mat4_invert(&mv, &temp);
mat4_transpose(&temp, &temp);
g_worldview_inverse[0] = temp.row0;
g_worldview_inverse[1] = temp.row1;
g_worldview_inverse[2] = temp.row2;
mat4_mul(&mv, &proj, &temp);
mat4_transpose(&temp, &temp);
g_transforms[0] = temp.row0;
g_transforms[1] = temp.row1;
g_transforms[2] = temp.row2;
g_transforms[3] = temp.row3;
}
render_context::render_context() : litproj(), chara_reflect(), chara_refract(), view_mat(), matrix_buffer(),
box_vao(), box_vbo(), empty_texture_2d(), empty_texture_cube_map(), samplers(), sprite_samplers() {
camera = new ::camera;
static const float_t box_texcoords[] = {
1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
1.0f, 0.0f, 0.0f, 1.0f, -1.0f, 0.0f, 0.0f, -1.0f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
-0.5f, 0.5f, 0.5f, 0.5f, -0.5f, -0.5f, 0.5f, -0.5f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.5f, -1.5f, -1.5f, 0.5f, 1.5f, -0.5f, -0.5f, 1.5f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.5f, -1.5f, -1.5f, 0.5f, 1.5f, -0.5f, -0.5f, 1.5f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.5f, -1.5f, -1.5f, 0.5f, 1.5f, -0.5f, -0.5f, 1.5f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
0.5f, -1.5f, -1.5f, 0.5f, 1.5f, -0.5f, -0.5f, 1.5f,
0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f, 0.0f,
3.5f, -3.5f, -1.5f, -3.5f, 1.5f, -1.5f, -3.5f, -1.5f,
3.5f, 1.5f, -1.5f, 1.5f, 1.5f, 3.5f, -3.5f, 3.5f,
3.5f, -3.5f, -1.5f, -3.5f, 1.5f, -1.5f, -3.5f, -1.5f,
3.5f, 1.5f, -1.5f, 1.5f, 1.5f, 3.5f, -3.5f, 3.5f,
3.5f, -3.5f, -1.5f, -3.5f, 1.5f, -1.5f, -3.5f, -1.5f,
3.5f, 1.5f, -1.5f, 1.5f, 1.5f, 3.5f, -3.5f, 3.5f,
3.5f, -3.5f, -1.5f, -3.5f, 1.5f, -1.5f, -3.5f, -1.5f,
3.5f, 1.5f, -1.5f, 1.5f, 1.5f, 3.5f, -3.5f, 3.5f,
};
glGenVertexArrays(1, &box_vao);
gl_state_bind_vertex_array(box_vao);
glGenBuffers(1, &box_vbo);
gl_state_bind_array_buffer(box_vbo, true);
if (GLAD_GL_VERSION_4_4)
glBufferStorage(GL_ARRAY_BUFFER, sizeof(box_texcoords), box_texcoords, 0);
else
glBufferData(GL_ARRAY_BUFFER, sizeof(box_texcoords), box_texcoords, GL_STATIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, sizeof(float_t) * 16, (void*)0);
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, sizeof(float_t) * 16, (void*)(sizeof(float_t) * 4));
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(float_t) * 16, (void*)(sizeof(float_t) * 8));
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, sizeof(float_t) * 16, (void*)(sizeof(float_t) * 12));
gl_state_bind_array_buffer(0);
gl_state_bind_vertex_array(0);
contour_coef_ubo.Create(sizeof(contour_coef_shader_data));
contour_params_ubo.Create(sizeof(contour_params_shader_data));
filter_scene_ubo.Create(sizeof(filter_scene_shader_data));
esm_filter_batch_ubo.Create(sizeof(esm_filter_batch_shader_data));
imgfilter_batch_ubo.Create(sizeof(imgfilter_batch_shader_data));
glass_eye_batch_ubo.Create(sizeof(glass_eye_batch_shader_data));
quad_ubo.Create(sizeof(quad_shader_data));
sprite_scene_ubo.Create(sizeof(sprite_scene_shader_data));
sss_filter_gaussian_coef_ubo.Create(sizeof(sss_filter_gaussian_coef_shader_data));
transparency_batch_ubo.Create(sizeof(transparency_batch_shader_data));
obj_scene = {};
obj_batch = {};
obj_skinning = {};
obj_scene_ubo.Create(sizeof(obj_scene_shader_data));
obj_batch_ubo.Create(sizeof(obj_batch_shader_data));
obj_skinning_ubo.Create(sizeof(obj_skinning_shader_data));
static const uint8_t empty_texture_data[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
};
static const GLenum target_cube_map_array[] = {
GL_TEXTURE_CUBE_MAP_POSITIVE_X, GL_TEXTURE_CUBE_MAP_NEGATIVE_X,
GL_TEXTURE_CUBE_MAP_POSITIVE_Y, GL_TEXTURE_CUBE_MAP_NEGATIVE_Y,
GL_TEXTURE_CUBE_MAP_POSITIVE_Z, GL_TEXTURE_CUBE_MAP_NEGATIVE_Z
};
glGenTextures(1, &empty_texture_2d);
gl_state_bind_texture_2d(empty_texture_2d);
texture_set_params(GL_TEXTURE_2D, 0, false);
glCompressedTexImage2D(GL_TEXTURE_2D, 0,
GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 4, 4, 0, 8, empty_texture_data);
gl_state_bind_texture_2d(0);
glGenTextures(1, &empty_texture_cube_map);
gl_state_bind_texture_cube_map(empty_texture_cube_map);
texture_set_params(GL_TEXTURE_CUBE_MAP, 0, false);
for (int32_t side = 0; side < 6; side++)
glCompressedTexImage2D(target_cube_map_array[side], 0,
GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, 4, 4, 0, 8, empty_texture_data);
gl_state_bind_texture_cube_map(0);
static const vec4 border_color = 0.0f;
glGenSamplers(18, samplers);
for (int32_t i = 0; i < 18; i++) {
GLuint sampler = samplers[i];
glSamplerParameterfv(sampler, GL_TEXTURE_BORDER_COLOR, (GLfloat*)&border_color);
glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER,
i % 2 ? GL_LINEAR_MIPMAP_LINEAR : GL_LINEAR);
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameterf(sampler, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f);
GLuint wrap_s;
switch (i / 2 % 3) {
case 0:
wrap_s = GL_CLAMP_TO_EDGE;
break;
case 1:
wrap_s = GL_REPEAT;
break;
case 2:
wrap_s = GL_MIRRORED_REPEAT;
break;
}
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, wrap_s);
GLenum wrap_t;
switch (i / 6 % 3) {
case 0:
wrap_t = GL_CLAMP_TO_EDGE;
break;
case 1:
wrap_t = GL_REPEAT;
break;
case 2:
wrap_t = GL_MIRRORED_REPEAT;
break;
}
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_T, wrap_t);
}
GLuint sampler;
glGenSamplers(3, sprite_samplers);
sampler = sprite_samplers[0];
glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glSamplerParameterf(sampler, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f);
sampler = sprite_samplers[1];
glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, GL_REPEAT);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_T, GL_REPEAT);
glSamplerParameterf(sampler, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f);
sampler = sprite_samplers[2];
glSamplerParameterfv(sampler, GL_TEXTURE_BORDER_COLOR, (GLfloat*)&border_color);
glSamplerParameteri(sampler, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glSamplerParameteri(sampler, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glSamplerParameteri(sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
glSamplerParameterf(sampler, GL_TEXTURE_MAX_ANISOTROPY_EXT, 16.0f);
}
render_context::~render_context() {
glDeleteSamplers(3, sprite_samplers);
glDeleteSamplers(18, samplers);
glDeleteTextures(1, &empty_texture_cube_map);
glDeleteTextures(1, &empty_texture_2d);
obj_skinning_ubo.Destroy();
obj_batch_ubo.Destroy();
obj_scene_ubo.Destroy();
transparency_batch_ubo.Destroy();
sss_filter_gaussian_coef_ubo.Destroy();
sprite_scene_ubo.Destroy();
quad_ubo.Destroy();
glass_eye_batch_ubo.Destroy();
imgfilter_batch_ubo.Destroy();
esm_filter_batch_ubo.Destroy();
filter_scene_ubo.Destroy();
contour_params_ubo.Destroy();
contour_coef_ubo.Destroy();
glDeleteVertexArrays(1, &box_vao);
glDeleteBuffers(1, &box_vbo);
if (camera) {
delete camera;
camera = 0;
}
}
void render_context::ctrl() {
delta_frame_history += get_delta_frame();
float_t v1;
delta_frame_history = modff(delta_frame_history, &v1);
delta_frame_history_int = (int32_t)v1;
if (delta_frame_history < 0.001f)
delta_frame_history = 0.0f;
else if (1.0f - delta_frame_history < 0.001f)
delta_frame_history_int++;
rctx_ptr = this;
app::TaskWork::Ctrl();
sound_ctrl();
file_handler_storage_ctrl();
}
void render_context::disp() {
rctx_ptr = this;
disp_manager.refresh();
sprite_manager_reset_req_list();
draw_state.stats_prev = draw_state.stats;
draw_state.stats.reset();
app::TaskWork::Disp();
render_manager.shadow_ptr->Ctrl(this);
int32_t sprite_index = sprite_manager_get_index();
//sprite_manager_set_index(3);
sprite_manager_set_index(0);
extern void dw_gui_ctrl_disp();
dw_gui_ctrl_disp();
sprite_manager_set_index(sprite_index);
post_process.ctrl(camera);
render_manager.render_all(this);
post_process.lens_flare_texture = 0;
post_process.aet_back = 0;
render_manager.field_31C = false;
app::TaskWork::Basic();
}
void render_context::light_param_data_light_set(light_param_light * light) {
for (int32_t i = LIGHT_SET_MAIN; i < LIGHT_SET_MAX; i++) {
light_param_light_group* group = &light->group[i];
::light_set* set = &light_set[i];
for (int32_t j = LIGHT_CHARA; j < LIGHT_MAX; j++) {
light_param_light_data* data = &group->data[j];
light_data* light = &set->lights[j];
if (data->has_type)
light->set_type(data->type);
if (data->has_ambient)
light->set_ambient(data->ambient);
if (data->has_diffuse)
light->set_diffuse(data->diffuse);
if (data->has_specular)
light->set_specular(data->specular);
if (data->has_position)
light->set_position(data->position);
if (data->has_spot_direction)
light->set_spot_direction(data->spot_direction);
if (data->has_spot_exponent)
light->set_spot_exponent(data->spot_exponent);
if (data->has_spot_cutoff)
light->set_spot_cutoff(data->spot_cutoff);
if (data->has_attenuation)
light->set_attenuation(data->attenuation);
light->set_clip_plane(data->clip_plane);
if (data->has_tone_curve)
light->set_tone_curve(data->tone_curve);
}
}
}
void render_context::light_param_data_fog_set(light_param_fog* f) {
for (int32_t i = FOG_DEPTH; i < FOG_MAX; i++) {
light_param_fog_group* group = &f->group[i];
::fog* fog = &this->fog[i];
if (group->has_type)
fog->set_type(group->type);
if (group->has_density)
fog->set_density(group->density);
if (group->has_linear) {
fog->set_start(group->linear_start);
fog->set_end(group->linear_end);
}
if (group->has_color)
fog->set_color(group->color);
}
}
void render_context::light_param_data_glow_set(light_param_glow* glow) {
post_process_blur* blur = post_process.blur;
post_process_tone_map* tone_map = post_process.tone_map;
tone_map->set_auto_exposure(true);
tone_map->set_tone_map_method(TONE_MAP_YCC_EXPONENT);
tone_map->reset_saturate_coeff(0, false);
tone_map->reset_scene_fade(0);
tone_map->reset_tone_trans(0);
if (glow->has_exposure)
tone_map->set_exposure(glow->exposure);
if (glow->has_gamma)
tone_map->set_gamma(glow->gamma);
if (glow->has_saturate_power)
tone_map->set_saturate_power(glow->saturate_power);
if (glow->has_saturate_coef)
tone_map->set_saturate_coeff(glow->saturate_coef, 0, false);
if (glow->has_flare)
tone_map->set_lens(glow->flare);
if (glow->has_sigma)
blur->set_radius(glow->sigma);
if (glow->has_intensity)
blur->set_intensity(glow->intensity);
if (glow->has_auto_exposure)
tone_map->set_auto_exposure(glow->auto_exposure);
if (glow->has_tone_map_method)
tone_map->set_tone_map_method(glow->tone_map_method);
if (glow->has_fade_color) {
vec4 fade_color = glow->fade_color;
tone_map->set_scene_fade(fade_color, 0);
tone_map->set_scene_fade_blend_func(glow->fade_color_blend_func, 0);
}
if (glow->has_tone_transform)
tone_map->set_tone_trans(glow->tone_transform_start, glow->tone_transform_end, 0);
}
void render_context::light_param_data_ibl_set(
light_param_ibl* ibl, light_param_data_storage* storage) {
if (!ibl->ready)
return;
for (int32_t i = 0, j = -1; i < 5; i++, j++) {
gl_state_bind_texture_cube_map(storage->textures[i]);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE);
if (!i) {
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, 1);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
render_context_light_param_data_ibl_set_diffuse(&ibl->diffuse[0], 0);
render_context_light_param_data_ibl_set_diffuse(&ibl->diffuse[1], 1);
}
else {
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAX_LEVEL, ibl->specular[j].max_level);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameterf(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_LOD_BIAS, 0.0f);
render_context_light_param_data_ibl_set_specular(&ibl->specular[j]);
}
}
gl_state_bind_texture_cube_map(0);
::light_set* set = &light_set[LIGHT_SET_MAIN];
set->set_irradiance(ibl->diff_coef[1][0], ibl->diff_coef[1][1], ibl->diff_coef[1][2]);
float_t len;
vec3 pos;
light_data* l = &set->lights[LIGHT_CHARA];
l->get_position(pos);
len = vec3::length(pos);
if (fabsf(len - 1.0f) < 0.02f)
l->set_position(ibl->lit_dir[0]);
l->set_ibl_color0(ibl->lit_col[0]);
l->set_ibl_color1(ibl->lit_col[2]);
l->set_ibl_direction(ibl->lit_dir[0]);
l = &set->lights[LIGHT_STAGE];
l->get_position(pos);
len = vec3::length(pos);
if (fabsf(len - 1.0f) < 0.02f)
l->set_position(ibl->lit_dir[1]);
l->set_ibl_color0(ibl->lit_col[1]);
l->set_ibl_direction(ibl->lit_dir[1]);
}
void render_context::light_param_data_wind_set(light_param_wind* w) {
wind* wind = task_wind->ptr;
if (w->has_scale)
wind->scale = w->scale;
if (w->has_cycle)
wind->cycle = w->cycle;
if (w->has_rot) {
wind->rot_y = w->rot_y;
wind->rot_z = w->rot_z;
}
if (w->has_bias)
wind->bias = w->bias;
for (int32_t i = 0; i < 16; i++)
if (w->has_spc[i]) {
wind->spc[i].cos = w->spc[i].cos;
wind->spc[i].sin = w->spc[i].sin;
}
}
void render_context::light_param_data_face_set(light_param_face* face) {
this->face.set_offset(face->offset);
this->face.set_scale(face->scale);
this->face.set_position(face->position);
this->face.set_direction(face->direction);
}
Shadow::Shadow() : curr_render_textures(), view_region(), range(), field_1C0(), field_1C8(),
field_200(), field_208(), near_blur(), blur_filter(), far_blur(), field_2BC(), distance(),
field_2C4(), z_near(), z_far(), field_2D0(), field_2D4(), field_2D8(), field_2DC(), field_2E0(),
ambient(), field_2E8(), field_2EC(), field_2F0(), self_shadow(), blur_filter_enable(), field_2F5() {
ResetData();
}
Shadow::~Shadow() {
Reset();
}
void Shadow::Ctrl(render_context* rctx) {
for (int32_t i = 0; i < 2; i++)
field_2F0[i] = false;
if (rctx->render_manager.shadow) {
view_mat[0] = rctx->camera->view;
view_mat[1] = rctx->camera->inv_view;
::light_set* set = &rctx->light_set[LIGHT_SET_MAIN];
light_data* data = &set->lights[LIGHT_CHARA];
vec3 position;
data->get_position(position);
float_t length = vec3::length(position);
if (length < 0.000001f)
direction = { 0.0f, 1.0f, 0.0f };
else
direction = -position * (1.0f / length);
for (int32_t i = 0; i < 2; i++)
if (rctx->disp_manager.get_obj_count((mdl::ObjType)((int32_t)mdl::OBJ_TYPE_SHADOW_CHARA + i)))
field_2F0[i] = true;
}
int32_t count = 0;
field_2EC = 0;
for (int32_t i = 0; i < 2; i++)
if (field_2F0[i] && field_1D0[i].size() > 0) {
field_2EC++;
count += (int32_t)field_1D0[i].size();
}
else
field_2F0[i] = false;
if (count < 3) {
for (int32_t i = 0; i < 2; i++) {
field_1A8[i] = 0.0f;
field_1C8[i] = 0.0f;
if (!field_2F0[i] || field_1D0[i].size() < 1)
continue;
vec3 v7 = 0.0f;
for (vec3& j : field_1D0[i])
v7 += j;
float_t v14 = (float_t)(int64_t)field_1D0[i].size();
if (v14 < 0.0f)
v14 += (float_t)UINT64_MAX;
v7 *= 1.0f / v14;
float_t v15 = 0.0f;
for (vec3& j : field_1D0[i]) {
vec3 v22 = v7 - j;
vec3 v25 = direction * vec3::dot(v22, direction);
float_t v24 = vec3::distance(v25, v22);
v24 -= 0.25f;
if (v24 < 0.0f)
v24 = 0.0f;
if (v15 < v24)
v15 = v24;
}
field_1A8[i] = v7;
field_1C8[i] = v15;
}
if (field_2EC > 0) {
vec3 view_point = 0.0f;
vec3 interest = 0.0f;
for (int32_t i = 0; i < 2; i++) {
if (!field_2F0[i])
continue;
vec3 v11 = field_1A8[i] - direction * field_208;
float_t v9 = vec3::distance(this->view_point[i], v11);
float_t v12 = vec3::distance(this->interest[i], field_1A8[i]);
if (v9 > 0.1f || v12 > 0.1f) {
this->view_point[i] = v11;
this->interest[i] = field_1A8[i];
}
view_point += this->view_point[i];
interest += this->interest[i];
}
view_point_shared = view_point * (1.0f / (float_t)field_2EC);
interest_shared = interest * (1.0f / (float_t)field_2EC);
}
float_t v2 = max_def(field_1C8[0], field_1C8[1]);
field_2F5 = false;
view_region = v2 + 1.2f;
field_200[0] = 0;
field_200[1] = 1;
if (field_2EC >= 2) {
vec3 v12 = field_1A8[0] - interest_shared;
vec3 v14 = field_1A8[1] - interest_shared;
float_t v6 = vec3::length(direction * vec3::dot(v12, direction) - v12);
float_t v16 = v6 - 0.25f;
if (v16 < 0.0f)
v16 = 0.0f;
if (v16 > 1.2f) {
view_region = v2 + 2.4f;
field_2F5 = true;
}
else
view_region = v2 + 1.2f + v16;
if (vec3::dot(v12, direction) < vec3::dot(v14, direction)) {
field_200[1] = 0;
field_200[0] = 1;
}
}
}
else {
vec3 v3;
vec3 v86;
if (direction.y * direction.y < 0.99f) {
v86 = vec3::cross(direction, vec3(0.0f, 1.0f, 0.0f));
v3 = vec3::normalize(vec3::cross(v86, direction));
v86 = vec3::normalize(v86);
}
else {
v3 = { 0.0f, 0.0f, 1.0f };
v86 = { 1.0f, 0.0f, 0.0f };
}
for (int32_t i = 0; i < 2; i++) {
field_1A8[i] = 0.0f;
field_1C8[i] = 0.0;
if (!field_2F0[i] || field_1D0[i].size() < 1)
continue;
vec3 v22 = 0.0f;
for (vec3& j : field_1D0[i])
v22 += j;
float_t v29 = (float_t)(int64_t)field_1D0[i].size();
if (v29 < 0.0f)
v29 += (float_t)UINT64_MAX;
float_t v30 = 0.0f;
vec3 v31 = v22 * (1.0f / v29);
for (vec3& j : field_1D0[i]) {
vec3 v34 = v31 - j;
float_t v38 = fabsf(vec3::dot(v34, v3));
float_t v39 = fabsf(vec3::dot(v34, v86));
if (v39 >= v38)
v38 = v39;
if (v30 < v38)
v30 = v38;
}
field_1A8[i] = v31;
field_1C8[i] = v30;
}
if (field_2EC > 0) {
for (int32_t i = 0; i < 2; i++) {
if (!field_2F0[i])
continue;
vec3 v53 = field_1A8[i] - direction * field_208;
float_t v51 = vec3::distance(view_point[i], v53);
float_t v54 = vec3::distance(interest[i], field_1A8[i]);
if (v51 > 0.1f || v54 > 0.1f) {
view_point[i] = v53;
interest[i] = field_1A8[i];
}
}
vec3 view_point = 0.0f;
vec3 interest = 0.0f;
int32_t count = 0;
for (int32_t i = 0; i < 2; i++) {
int32_t c = (int32_t)field_1D0[i].size();
view_point += this->view_point[i] * (float_t)c;
interest += this->interest[i] * (float_t)c;
count += c;
}
view_point_shared = view_point * (1.0f / (float_t)count);
interest_shared = interest * (1.0f / (float_t)count);
}
float_t v2 = 0.0f;
float_t v67 = max_def(field_1C8[0], field_1C8[1]);
field_2F5 = false;
view_region = v67 + 1.2f;
field_200[0] = 0;
field_200[1] = 1;
if (field_2EC >= 2) {
float_t v68 = 0.0f;
float_t v69 = 0.0f;
float_t v70 = 0.0f;
for (int32_t i = 0; i < 2; i++) {
if (!field_2F0[i])
continue;
for (vec3& j : field_1D0[i]) {
vec3 v74 = j - interest_shared;
float_t v77 = vec3::dot(v74, v86);
if (v2 > v77)
v2 = v77;
else if (v69 < v77)
v69 = v77;
float_t v78 = vec3::dot(v74, v3);
if (v68 > v78)
v68 = v78;
else if (v70 < v78)
v70 = v78;
}
}
float_t v79 = -v2;
if (v79 < v69)
v79 = v69;
if (v79 < -v68)
v79 = -v68;
if (v79 < v70)
v79 = v70;
if (v79 > v67 + 1.2f) {
view_region = v67 + 2.4f;
field_2F5 = true;
}
else
view_region = v79 + 1.2f;
if (vec3::dot(field_1A8[0] - interest_shared, direction)
< vec3::dot(field_1A8[1] - interest_shared, direction)) {
field_200[1] = 0;
field_200[0] = 1;
}
}
}
for (std::vector<vec3>& i : field_1D0)
i.clear();
}
int32_t Shadow::InitData() {
struct shadow_texture_init_params {
int32_t width;
int32_t height;
int32_t max_level;
GLenum color_format;
GLenum depth_format;
} init_params[] = {
{ 0x800, 0x800, 0, GL_RGBA8, GL_DEPTH_COMPONENT32F },
{ 0x200, 0x200, 3, GL_RGBA8, GL_ZERO },
{ 0x200, 0x200, 3, GL_RGBA8, GL_ZERO },
{ 0x800, 0x800, 0, GL_R32F , GL_ZERO },
{ 0x800, 0x800, 0, GL_R32F , GL_ZERO },
{ 0x200, 0x200, 0, GL_R32F , GL_ZERO },
{ 0x200, 0x200, 0, GL_R32F , GL_ZERO },
{ 0x200, 0x200, 3, GL_RGBA8, GL_ZERO }, // Extra for buf
};
shadow_texture_init_params* v3 = init_params;
for (int32_t i = 0; i < 8; i++, v3++)
if (render_textures[i].Init(v3->width, v3->height,
v3->max_level, v3->color_format, v3->depth_format) < 0)
return -1;
for (int32_t i = 0; i < 4; i++) {
gl_state_bind_texture_2d(render_textures[i == 3 ? 7 : i].color_texture->tex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER);
static const vec4 border_color = 1.0f;
glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, (GLfloat*)&border_color);
}
gl_state_bind_texture_2d(0);
gl_state_get_error();
return 0;
}
void Shadow::Reset() {
for (RenderTexture& i : render_textures)
i.Free();
ResetData();
}
void Shadow::ResetData() {
view_region = 1.2f;
range = 1.0f;
for (int32_t i = 0; i < 2; i++) {
view_point[i] = 1.0f;
field_1C0[i] = 0.0f;
field_1C8[i] = 0.0f;
field_200[i] = i;
}
for (RenderTexture*& i : curr_render_textures)
i = 0;
view_mat[0] = mat4_identity;
view_mat[1] = mat4_identity;
blur_filter = BLUR_FILTER_9;
near_blur = 1;
field_2BC = 2;
far_blur = 1;
distance = 4.0f;
field_2C4 = 0.4f;
z_near = 0.1f;
z_far = 20.0f;
field_2D0 = 1.4f;
field_2D4 = 10000.0f;
field_2D8 = 80.0f;
field_2DC = 2.0f;
field_2E0 = 0.05f;
ambient = 0.4f;
field_2EC = 0;
direction = vec3(0.0f, -1.0f, -1.0f) * (1.0f / sqrtf(2.0f));
field_2E8 = false;
self_shadow = true;
field_2F5 = false;
field_208 = (z_far - z_near) * 0.5f;
}
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 vertex_buffer = args->vertex_buffer
? args->vertex_buffer->get_buffer() : 0;
//GLuint morph_vertex_buffer = args->morph_vertex_buffer;
GLuint morph_vertex_buffer = args->morph_vertex_buffer
? args->morph_vertex_buffer->get_buffer() : 0;
bool compressed = mesh->attrib.m.compressed;
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) {
vertex_attrib_buffer_binding[BONE_WEIGHT_INDEX] = vertex_buffer;
vertex_attrib_buffer_binding[BONE_INDEX_INDEX] = vertex_buffer;
}
if (!compressed && 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;
}
}
static void render_context_light_param_data_ibl_set_diffuse(light_param_ibl_diffuse* diffuse, int32_t level) {
int32_t size = diffuse->size;
size_t data_size = size;
data_size = 4 * data_size * data_size;
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, level, GL_RGBA16F,
size, size, 0, GL_RGBA, GL_HALF_FLOAT, &diffuse->data[data_size * 0]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, level, GL_RGBA16F,
size, size, 0, GL_RGBA, GL_HALF_FLOAT, &diffuse->data[data_size * 1]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, level, GL_RGBA16F,
size, size, 0, GL_RGBA, GL_HALF_FLOAT, &diffuse->data[data_size * 2]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, level, GL_RGBA16F,
size, size, 0, GL_RGBA, GL_HALF_FLOAT, &diffuse->data[data_size * 3]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, level, GL_RGBA16F,
size, size, 0, GL_RGBA, GL_HALF_FLOAT, &diffuse->data[data_size * 4]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, level, GL_RGBA16F,
size, size, 0, GL_RGBA, GL_HALF_FLOAT, &diffuse->data[data_size * 5]);
}
static void render_context_light_param_data_ibl_set_specular(light_param_ibl_specular* specular) {
int32_t size = specular->size;
int32_t max_level = specular->max_level;
for (int32_t i = 0; i <= max_level; i++, size /= 2) {
std::vector<half_t>& data = specular->data[i];
size_t data_size = size;
data_size = 4 * data_size * data_size;
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X, i, GL_RGBA16F,
size, size, 0, GL_RGBA, GL_HALF_FLOAT, &data[data_size * 0]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_X, i, GL_RGBA16F,
size, size, 0, GL_RGBA, GL_HALF_FLOAT, &data[data_size * 1]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Y, i, GL_RGBA16F,
size, size, 0, GL_RGBA, GL_HALF_FLOAT, &data[data_size * 2]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Y, i, GL_RGBA16F,
size, size, 0, GL_RGBA, GL_HALF_FLOAT, &data[data_size * 3]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_Z, i, GL_RGBA16F,
size, size, 0, GL_RGBA, GL_HALF_FLOAT, &data[data_size * 4]);
glTexImage2D(GL_TEXTURE_CUBE_MAP_NEGATIVE_Z, i, GL_RGBA16F,
size, size, 0, GL_RGBA, GL_HALF_FLOAT, &data[data_size * 5]);
}
}