Files
korenkonder_ReDIVA/src/CRE/draw_task.cpp
T
2022-07-06 14:13:11 +03:00

1010 lines
42 KiB
C++

/*
by korenkonder
GitHub/GitLab: korenkonder
*/
#include "draw_task.hpp"
#include "../KKdLib/hash.hpp"
#include "../KKdLib/sort.hpp"
#include "camera.hpp"
#include "fbo.hpp"
#include "post_process.hpp"
#include "shader_ft.hpp"
static void draw_task_add(render_context* rctx, draw_object_type type, draw_task* task);
static void draw_task_object_init(draw_task* task, object_data* object_data, mat4* mat,
float_t bounding_radius, obj_sub_mesh* sub_mesh, obj_mesh* mesh, obj_material_data* material,
std::vector<GLuint>* textures, int32_t mat_count, mat4* mats, GLuint array_buffer,
GLuint element_array_buffer, vec4* blend_color, vec4* emission, int32_t morph_array_buffer,
int32_t instances_count, mat4* instances_mat, void(*draw_object_func)(draw_object*));
static void draw_task_object_translucent_init(draw_task* task, mat4* mat,
draw_task_object_translucent* object);
static int draw_task_sort_quicksort_compare0(void const* src1, void const* src2);
static int draw_task_sort_quicksort_compare1(void const* src1, void const* src2);
static int draw_task_sort_quicksort_compare2(void const* src1, void const* src2);
static int32_t draw_task_translucent_sort_count_layers(render_context* rctx,
int32_t* alpha_array, draw_object_type opaque,
draw_object_type transparent, draw_object_type translucent);
static void draw_task_translucent_sort_has_objects(render_context* rctx, bool* arr, draw_object_type type);
void draw_task_draw_objects_by_type(render_context* rctx, draw_object_type type,
int32_t a2, int32_t show_vector, bool a4, int32_t alpha) {
if (draw_task_get_count(rctx, type) < 1)
return;
int32_t alpha_test = 0;
float_t min_alpha = 1.0f;
bool reflect = uniform_value[U_REFLECT] == 1;
void(*draw_object_func)(render_context* rctx, draw_object* draw) = draw_object_draw_default;
for (int32_t i = 0; i < 6; i++)
gl_state_active_bind_texture_2d(i, 0);
gl_state_active_texture(0);
gl_state_set_blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glPrimitiveRestartIndex(0xFFFF);
uniform_value_reset();
gl_state_get();
switch (type) {
case DRAW_OBJECT_TRANSLUCENT:
case DRAW_OBJECT_TRANSLUCENT_NO_SHADOW:
case DRAW_OBJECT_TRANSLUCENT_TYPE_22:
case DRAW_OBJECT_TRANSLUCENT_TYPE_25:
case DRAW_OBJECT_TRANSLUCENT_TYPE_28:
if (a2)
draw_object_func = draw_object_draw_translucent;
else
gl_state_set_depth_mask(GL_FALSE);
min_alpha = 0.0;
break;
case DRAW_OBJECT_TRANSPARENT:
case DRAW_OBJECT_TRANSPARENT_TYPE_21:
case DRAW_OBJECT_TRANSPARENT_TYPE_24:
case DRAW_OBJECT_TRANSPARENT_TYPE_27:
alpha_test = 1;
min_alpha = 0.1f;
break;
case DRAW_OBJECT_SHADOW_CHARA:
case DRAW_OBJECT_SHADOW_STAGE:
case DRAW_OBJECT_SHADOW_OBJECT_CHARA:
case DRAW_OBJECT_SHADOW_OBJECT_STAGE:
draw_object_func = draw_object_draw_shadow;
min_alpha = 0.5f;
break;
case DRAW_OBJECT_TYPE_6:
draw_object_func = draw_object_draw_translucent;
gl_state_set_color_mask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
rctx->draw_state.shader_index = SHADER_FT_SIL;
break;
case DRAW_OBJECT_TYPE_7:
draw_object_func = draw_object_draw_translucent;
gl_state_set_color_mask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
rctx->draw_state.shader_index = SHADER_FT_SIL;
alpha_test = 1;
min_alpha = 0.0f;
break;
case DRAW_OBJECT_REFLECT_CHARA_OPAQUE:
gl_state_set_cull_face_mode(GL_FRONT);
if (reflect)
draw_object_func = draw_object_draw_reflect;
else if (rctx->draw_pass.reflect_type == STAGE_DATA_REFLECT_REFLECT_MAP)
draw_object_func = draw_object_draw_reflect_reflect_map;
break;
case DRAW_OBJECT_REFLECT_CHARA_TRANSLUCENT:
gl_state_set_cull_face_mode(GL_FRONT);
if (reflect)
draw_object_func = draw_object_draw_reflect;
else if (rctx->draw_pass.reflect_type == STAGE_DATA_REFLECT_REFLECT_MAP)
draw_object_func = draw_object_draw_reflect_reflect_map;
min_alpha = 0.0f;
break;
case DRAW_OBJECT_REFLECT_CHARA_TRANSPARENT:
gl_state_set_cull_face_mode(GL_FRONT);
alpha_test = 1;
min_alpha = 0.1f;
if (reflect)
draw_object_func = draw_object_draw_reflect;
else {
if (rctx->draw_pass.reflect_type == STAGE_DATA_REFLECT_REFLECT_MAP)
draw_object_func = draw_object_draw_reflect_reflect_map;
}
break;
case DRAW_OBJECT_REFLECT_OPAQUE:
alpha_test = 1;
if (!a4)
draw_object_func = draw_object_draw_reflect_reflect_map;
break;
case DRAW_OBJECT_REFLECT_TRANSLUCENT:
case DRAW_OBJECT_REFRACT_TRANSLUCENT:
gl_state_set_depth_mask(GL_FALSE);
min_alpha = 0.0f;
break;
case DRAW_OBJECT_REFLECT_TRANSPARENT:
case DRAW_OBJECT_REFRACT_TRANSPARENT:
alpha_test = 1;
min_alpha = 0.1f;
break;
case DRAW_OBJECT_SSS:
draw_object_func = draw_object_draw_sss;
break;
case DRAW_OBJECT_RIPPLE:
draw_object_func = draw_object_draw_translucent;
break;
default:
break;
}
shaders_ft.env_frag_set(21, 0.0f, 0.0f, 0.0f, min_alpha);
uniform_value[U_ALPHA_TEST] = alpha_test;
std::vector<draw_task*>& vec = rctx->object_data.draw_task_array[type];
if (alpha < 0)
for (draw_task*& i : vec) {
draw_task* task = i;
switch (task->type) {
case DRAW_TASK_TYPE_OBJECT: {
draw_object_draw(rctx, &task->data.object,
&task->mat, draw_object_func, show_vector);
} break;
case DRAW_TASK_TYPE_PRIMITIVE: {
draw_object_model_mat_load(rctx, &task->mat);
//draw_primitive_draw(&task->data.primitive);
} break;
case DRAW_TASK_TYPE_PREPROCESS: {
draw_object_model_mat_load(rctx, &task->mat);
task->data.preprocess.func(rctx, task->data.preprocess.data);
} break;
case DRAW_TASK_TYPE_OBJECT_TRANSLUCENT: {
for (int32_t j = 0; j < task->data.object_translucent.count; j++)
draw_object_draw(rctx, task->data.object_translucent.objects[j],
&task->mat, draw_object_func, show_vector);
} break;
}
}
else
for (draw_task*& i : vec) {
draw_task* task = i;
switch (task->type) {
case DRAW_TASK_TYPE_OBJECT: {
int32_t a = (int32_t)(task->data.object.blend_color.w * 255.0f);
a = clamp(a, 0, 255);
if (a == alpha) {
draw_object_draw(rctx, &task->data.object,
&task->mat, draw_object_func, show_vector);
}
} break;
case DRAW_TASK_TYPE_OBJECT_TRANSLUCENT: {
for (int32_t j = 0; j < task->data.object_translucent.count; j++) {
draw_object* object = task->data.object_translucent.objects[j];
int32_t a = (int32_t)(object->blend_color.w * 255.0f);
a = clamp(a, 0, 255);
if (a == alpha)
draw_object_draw(rctx, object,
&task->mat, draw_object_func, show_vector);
}
} break;
}
}
switch (type) {
case DRAW_OBJECT_TRANSLUCENT:
case DRAW_OBJECT_TRANSLUCENT_NO_SHADOW:
case DRAW_OBJECT_REFLECT_TRANSLUCENT:
case DRAW_OBJECT_REFRACT_TRANSLUCENT:
case DRAW_OBJECT_TRANSLUCENT_TYPE_22:
case DRAW_OBJECT_TRANSLUCENT_TYPE_25:
case DRAW_OBJECT_TRANSLUCENT_TYPE_28:
if (!a2)
gl_state_set_depth_mask(GL_TRUE);
break;
case DRAW_OBJECT_TYPE_6:
case DRAW_OBJECT_TYPE_7:
rctx->draw_state.shader_index = -1;
gl_state_set_color_mask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
break;
case DRAW_OBJECT_REFLECT_CHARA_OPAQUE:
case DRAW_OBJECT_REFLECT_CHARA_TRANSLUCENT:
case DRAW_OBJECT_REFLECT_CHARA_TRANSPARENT:
case DRAW_OBJECT_TRANSPARENT_TYPE_21:
case DRAW_OBJECT_TRANSPARENT_TYPE_24:
case DRAW_OBJECT_TRANSPARENT_TYPE_27:
gl_state_set_cull_face_mode(GL_BACK);
break;
}
uniform_value_reset();
shader::unbind();
gl_state_set_blend_func(GL_ONE, GL_ZERO);
}
void draw_task_draw_objects_by_type_translucent(render_context* rctx, bool opaque_enable,
bool transparent_enable, bool translucent_enable, draw_object_type opaque,
draw_object_type transparent, draw_object_type translucent) {
if (draw_task_get_count(rctx, opaque) < 1)
return;
else if (draw_task_get_count(rctx, transparent) < 1)
return;
else if (draw_task_get_count(rctx, translucent) < 1)
return;
int32_t alpha_array[256];
int32_t count = draw_task_translucent_sort_count_layers(rctx,
alpha_array, opaque, transparent, translucent);
for (int32_t i = 0; i < count; i++) {
int32_t alpha = alpha_array[i];
fbo::blit(rctx->post_process.rend_texture.fbos[0],
rctx->post_process.alpha_layer_texture.fbos[0],
0, 0, rctx->post_process.render_width, rctx->post_process.render_height,
0, 0, rctx->post_process.render_width, rctx->post_process.render_height,
GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT, GL_LINEAR);
if (opaque_enable && draw_task_get_count(rctx, opaque))
draw_task_draw_objects_by_type(rctx, opaque, 0, 0, 1, alpha);
if (transparent_enable && draw_task_get_count(rctx, transparent))
draw_task_draw_objects_by_type(rctx, transparent, 0, 0, 1, alpha);
if (translucent_enable && draw_task_get_count(rctx, translucent)) {
gl_state_enable_blend();
draw_task_draw_objects_by_type(rctx, translucent, 0, 0, 1, alpha);
gl_state_disable_blend();
}
rctx->post_process.buf_texture.bind();
render_texture::shader_set_glsl(&rctx->post_process.alpha_layer_shader);
gl_state_active_bind_texture_2d(0, rctx->post_process.alpha_layer_texture.color_texture->tex);
gl_state_active_bind_texture_2d(1, rctx->post_process.rend_texture.color_texture->tex);
glUniform1f(0, (float_t)(alpha * (1.0 / 255.0)));
render_texture::draw_custom_glsl();
fbo::blit(rctx->post_process.buf_texture.fbos[0],
rctx->post_process.rend_texture.fbos[0],
0, 0, rctx->post_process.render_width, rctx->post_process.render_height,
0, 0, rctx->post_process.render_width, rctx->post_process.render_height, GL_COLOR_BUFFER_BIT, GL_LINEAR);
}
}
inline int32_t draw_task_get_count(render_context* rctx, draw_object_type type) {
return (int32_t)rctx->object_data.draw_task_array[type].size();
}
bool draw_task_add_draw_object(render_context* rctx, obj* object,
obj_mesh_vertex_buffer* obj_vertex_buf, obj_mesh_index_buffer* obj_index_buf, mat4* mat,
std::vector<GLuint>* 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(*draw_object_func)(draw_object*), bool enable_bone_mat) {
object_data* object_data = &rctx->object_data;
draw_task_flags draw_task_flags = object_data->draw_task_flags;
if (object_data->object_culling && !instances_count && !bone_mat && (!object
|| !object_bounding_sphere_check_visibility(&object->bounding_sphere, object_data, rctx->camera, mat))) {
object_data->culled.objects++;
return false;
}
object_data->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 (object_data->object_culling && !instances_count && !bone_mat
&& !object_bounding_sphere_check_visibility(&mesh->bounding_sphere, object_data, rctx->camera, mat)
&& (!mesh_morph || !object_bounding_sphere_check_visibility(
&mesh_morph->bounding_sphere, object_data, rctx->camera, mat))) {
object_data->culled.meshes++;
continue;
}
object_data->passed.meshes++;
draw_object* 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 (object_data->object_culling && !instances_count && !bone_mat) {
int32_t v32 = object_bounding_sphere_check_visibility(
&sub_mesh->bounding_sphere, object_data, rctx->camera, mat);
if (v32 != 2 || (!mesh->attrib.m.billboard && !mesh->attrib.m.billboard_y_axis)) {
if (v32 == 2) {
if (object_data->object_bounding_sphere_check_func)
v32 = 1;
else
v32 = obj_axis_aligned_bounding_box_check_visibility(
&sub_mesh->axis_aligned_bounding_box, rctx->camera, mat);
}
if (!v32) {
if (!mesh_morph || j >= mesh_morph->num_submesh) {
object_data->culled.submesh_array++;
continue;
}
sub_mesh_morph = &mesh_morph->submesh_array[j];
if (!sub_mesh_morph) {
object_data->culled.submesh_array++;
continue;
}
v32 = object_bounding_sphere_check_visibility(
&sub_mesh_morph->bounding_sphere, object_data, rctx->camera, mat);
if (v32 == 2) {
if (object_data->object_bounding_sphere_check_func)
v32 = 1;
else
v32 = obj_axis_aligned_bounding_box_check_visibility(
&sub_mesh_morph->axis_aligned_bounding_box, rctx->camera, mat);
}
if (!v32) {
object_data->culled.submesh_array++;
continue;
}
}
}
}
object_data->passed.submesh_array++;
int32_t bone_indices_count = sub_mesh->bone_indices_count;
uint16_t* bone_indices = sub_mesh->bone_indices;
mat4* mats;
if (bone_indices_count && enable_bone_mat) {
mats = object_data->buffer.add_mat4(bone_indices_count);
if (bone_mat)
for (int32_t k = 0; k < bone_indices_count; k++)
mats[k] = bone_mat[*bone_indices++];
else
for (int32_t k = 0; k < bone_indices_count; k++)
mats[k] = mat4_identity;
}
else {
mats = 0;
bone_indices_count = 0;
}
obj_material_data* material = &object->material_array[sub_mesh->material_index];
draw_task* task = object_data->buffer.add_draw_task(DRAW_TASK_TYPE_OBJECT);
if (!task)
continue;
GLuint morph_array_buffer = 0;
if (obj_morph_vertex_buf)
morph_array_buffer = obj_morph_vertex_buf[i].get_buffer();
GLuint element_array_buffer = 0;
if (obj_index_buf)
element_array_buffer = obj_index_buf[i].buffer;
GLuint array_buffer = 0;
if (obj_vertex_buf)
array_buffer = obj_vertex_buf[i].get_buffer();
uint32_t material_hash = hash_utf8_murmurhash(material->material.name);
material_list_struct* mat_list = 0;
for (int32_t k = 0; k < object_data->material_list_count; k++)
if (object_data->material_list_array[k].hash == material_hash) {
mat_list = &object_data->material_list_array[k];
break;
}
vec4 _blend_color = vec4_identity;
vec4 _emission = vec4_null;
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
vec4_mult(_blend_color, *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;
}
draw_task_object_init(task, object_data, mat, object->bounding_sphere.radius, sub_mesh,
mesh, material, textures, bone_indices_count, mats, array_buffer, element_array_buffer,
&_blend_color, &_emission, morph_array_buffer, instances_count, instances_mat, draw_object_func);
if (draw_task_flags & DRAW_TASK_SHADOW_OBJECT) {
draw_task_add(rctx, (draw_object_type)(DRAW_OBJECT_SHADOW_OBJECT_CHARA
+ object_data->shadow_type), task);
if (draw_task_flags & DRAW_TASK_RIPPLE)
draw_task_add(rctx, DRAW_OBJECT_RIPPLE, task);
continue;
}
obj_material_attrib_member attrib = material->material.attrib.m;
if (draw_task_flags & (DRAW_TASK_10000 | DRAW_TASK_20000 | DRAW_TASK_40000)
&& task->data.object.blend_color.w < 1.0f) {
if (~draw_task_flags & DRAW_TASK_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 (draw_task_flags & DRAW_TASK_10000)
draw_task_add(rctx, DRAW_OBJECT_OPAQUE_TYPE_20, task);
else if (draw_task_flags & DRAW_TASK_20000)
draw_task_add(rctx, DRAW_OBJECT_OPAQUE_TYPE_23, task);
else
draw_task_add(rctx, DRAW_OBJECT_OPAQUE_TYPE_26, task);
}
else {
if (draw_task_flags & DRAW_TASK_10000)
draw_task_add(rctx, DRAW_OBJECT_TRANSPARENT_TYPE_21, task);
else if (draw_task_flags & DRAW_TASK_20000)
draw_task_add(rctx, DRAW_OBJECT_TRANSPARENT_TYPE_24, task);
else
draw_task_add(rctx, DRAW_OBJECT_TRANSPARENT_TYPE_27, task);
}
if (draw_task_flags & DRAW_TASK_SSS)
draw_task_add(rctx, DRAW_OBJECT_SSS, task);
}
if (draw_task_flags & DRAW_TASK_10000)
draw_task_add(rctx, DRAW_OBJECT_TRANSLUCENT_TYPE_22, task);
else if (draw_task_flags & DRAW_TASK_20000)
draw_task_add(rctx, DRAW_OBJECT_TRANSLUCENT_TYPE_25, task);
else
draw_task_add(rctx, DRAW_OBJECT_TRANSLUCENT_TYPE_28, task);
}
}
else {
if (attrib.flag_28 || task->data.object.blend_color.w >= 1.0f
&& (attrib.punch_through || !(attrib.alpha_texture | attrib.alpha_material))
&& !sub_mesh->attrib.m.transparent) {
if (draw_task_flags & DRAW_TASK_SHADOW)
draw_task_add(rctx, (draw_object_type)(DRAW_OBJECT_SHADOW_CHARA
+ object_data->shadow_type), task);
if (draw_task_flags & DRAW_TASK_SSS)
draw_task_add(rctx, DRAW_OBJECT_SSS, task);
if (material->material.attrib.m.punch_through) {
if (!(draw_task_flags & DRAW_TASK_NO_TRANSLUCENCY))
draw_task_add(rctx, DRAW_OBJECT_TRANSPARENT, task);
if (draw_task_flags & DRAW_TASK_CHARA_REFLECT)
draw_task_add(rctx, DRAW_OBJECT_REFLECT_CHARA_OPAQUE, task);
if (draw_task_flags & DRAW_TASK_REFLECT)
draw_task_add(rctx, DRAW_OBJECT_REFLECT_OPAQUE, task);
if (draw_task_flags & DRAW_TASK_REFRACT)
draw_task_add(rctx, DRAW_OBJECT_REFRACT_TRANSPARENT, task);
}
else {
if (!(draw_task_flags & DRAW_TASK_NO_TRANSLUCENCY))
draw_task_add(rctx, DRAW_OBJECT_OPAQUE, task);
if (draw_task_flags & DRAW_TASK_20)
draw_task_add(rctx, DRAW_OBJECT_TYPE_6, task);
if (draw_task_flags & DRAW_TASK_CHARA_REFLECT)
draw_task_add(rctx, DRAW_OBJECT_REFLECT_CHARA_OPAQUE, task);
if (draw_task_flags & DRAW_TASK_REFLECT)
draw_task_add(rctx, DRAW_OBJECT_REFLECT_OPAQUE, task);
if (draw_task_flags & DRAW_TASK_REFRACT)
draw_task_add(rctx, DRAW_OBJECT_REFRACT_OPAQUE, task);
}
if (draw_task_flags & DRAW_TASK_RIPPLE)
draw_task_add(rctx, DRAW_OBJECT_RIPPLE, task);
continue;
}
else if (!(draw_task_flags & DRAW_TASK_NO_TRANSLUCENCY)) {
if (!attrib.translucent_priority)
if (mesh->attrib.m.translucent_no_shadow
|| draw_task_flags & DRAW_TASK_TRANSLUCENT_NO_SHADOW)
draw_task_add(rctx, DRAW_OBJECT_TRANSLUCENT_NO_SHADOW, task);
else
draw_task_add(rctx, DRAW_OBJECT_TRANSLUCENT, task);
else if (translucent_priority_count < 40)
translucent_priority[translucent_priority_count++] = &task->data.object;
}
}
if (draw_task_flags & DRAW_TASK_SHADOW)
draw_task_add(rctx, (draw_object_type)(DRAW_OBJECT_SHADOW_CHARA
+ object_data->shadow_type), task);
if (draw_task_flags & DRAW_TASK_40)
draw_task_add(rctx, DRAW_OBJECT_TYPE_7, task);
if (draw_task_flags & DRAW_TASK_CHARA_REFLECT)
draw_task_add(rctx, DRAW_OBJECT_REFLECT_CHARA_OPAQUE, task);
if (draw_task_flags & DRAW_TASK_REFLECT) {
if (rctx->draw_pass.reflect_type != STAGE_DATA_REFLECT_REFLECT_MAP)
draw_task_add(rctx, DRAW_OBJECT_REFLECT_OPAQUE, task);
else
draw_task_add(rctx, DRAW_OBJECT_REFLECT_TRANSLUCENT, task);
}
if (draw_task_flags & DRAW_TASK_REFRACT)
draw_task_add(rctx, DRAW_OBJECT_REFRACT_TRANSLUCENT, task);
if (draw_task_flags & DRAW_TASK_RIPPLE)
draw_task_add(rctx, DRAW_OBJECT_RIPPLE, task);
}
if (!translucent_priority_count)
continue;
draw_task_object_translucent object_translucent;
object_translucent.count = 0;
for (int32_t j = 62; j; j--)
for (int32_t k = 0; k < translucent_priority_count; k++) {
draw_object* object = translucent_priority[k];
if (object->material->material.attrib.m.translucent_priority != j)
continue;
object_translucent.objects[object_translucent.count] = object;
object_translucent.count++;
}
draw_task* task = rctx->object_data.buffer.add_draw_task(DRAW_TASK_TYPE_OBJECT_TRANSLUCENT);
if (!task)
continue;
draw_task_object_translucent_init(task, mat, &object_translucent);
if (draw_task_flags & DRAW_TASK_10000)
draw_task_add(rctx, DRAW_OBJECT_TRANSLUCENT_TYPE_22, task);
else if (draw_task_flags & DRAW_TASK_20000)
draw_task_add(rctx, DRAW_OBJECT_TRANSLUCENT_TYPE_25, task);
else if (draw_task_flags & DRAW_TASK_40000)
draw_task_add(rctx, DRAW_OBJECT_TRANSLUCENT_TYPE_28, task);
else
draw_task_add(rctx, DRAW_OBJECT_TRANSLUCENT, task);
}
return true;
}
inline void draw_task_add_draw_object_by_obj(render_context* rctx, mat4* mat, obj* obj, std::vector<GLuint>* 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;
draw_task_add_draw_object(rctx, obj, obj_vert_buf, obj_index_buf, mat, textures, blend_color_ptr,
bone_mat, 0, 0, 0, 0, 0, !!bone_mat);
}
inline bool draw_task_add_draw_object_by_object_info(render_context* rctx, mat4* mat,
object_info obj_info, mat4* bone_mat) {
vec4 blend_color = vec4_identity;
return draw_task_add_draw_object_by_object_info(rctx,
mat, obj_info, &blend_color, bone_mat, 0, 0, 0, true);
}
bool draw_task_add_draw_object_by_object_info(render_context* rctx, mat4* mat,
object_info obj_info, vec4* blend_color, mat4* bone_mat, int32_t instances_count,
mat4* instances_mat, void(*draw_object_func)(draw_object*), bool enable_bone_mat) {
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<GLuint>* 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;
object_data* object_data = &rctx->object_data;
if (object_data->morph.object.set_id != -1) {
obj_morph = object_storage_get_obj(object_data->morph.object);
obj_morph_vertex_buffer = object_storage_get_obj_mesh_vertex_buffer(object_data->morph.object);
}
return draw_task_add_draw_object(rctx, object, obj_vertex_buffer, obj_index_buffer,
mat, textures, blend_color, bone_mat, obj_morph, obj_morph_vertex_buffer,
instances_count, instances_mat, draw_object_func, enable_bone_mat);
}
inline bool draw_task_add_draw_object_by_object_info_alpha(render_context* rctx, mat4* mat,
object_info obj_info, float_t alpha, mat4* bone_mat) {
vec4 blend_color = vec4_identity;
blend_color.w = alpha;
return draw_task_add_draw_object_by_object_info(rctx,
mat, obj_info, &blend_color, bone_mat, 0, 0, 0, true);
}
inline bool draw_task_add_draw_object_by_object_info_color(render_context* rctx, mat4* mat,
object_info obj_info, float_t r, float_t g, float_t b, float_t a, mat4* bone_mat) {
vec4 blend_color = { r, g, b, a };
return draw_task_add_draw_object_by_object_info(rctx,
mat, obj_info, &blend_color, bone_mat, 0, 0, 0, false);
}
inline bool draw_task_add_draw_object_by_object_info_color_vec4(render_context* rctx, mat4* mat,
object_info obj_info, vec4* blend_color, mat4* bone_mat) {
return draw_task_add_draw_object_by_object_info(rctx,
mat, obj_info, blend_color, 0, 0, 0, 0, false);
}
void draw_task_add_draw_object_by_object_info_object_skin(render_context* rctx, 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, mat4* mat, 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->matrix_buffer, mat, global_mat);
vec4 texture_color_coeff;
vec4 texture_color_offset;
vec4 texture_specular_coeff;
vec4 texture_specular_offset;
object_data* object_data = &rctx->object_data;
if (texture_data && !texture_data->field_0) {
vec4 value;
object_data->get_texture_color_coeff(texture_color_coeff);
vec3_mult(texture_data->texture_color_coeff, *(vec3*)&texture_color_coeff, *(vec3*)&value);
value.w = 0.0f;
object_data->set_texture_color_coeff(value);
object_data->get_texture_color_offset(texture_color_offset);
*(vec3*)&value = texture_data->texture_color_offset;
value.w = 0.0f;
object_data->set_texture_color_offset(value);
object_data->get_texture_specular_coeff(texture_specular_coeff);
vec3_mult(texture_data->texture_specular_coeff, *(vec3*)&texture_specular_coeff, *(vec3*)&value);
value.w = 0.0f;
object_data->set_texture_specular_coeff(value);
object_data->get_texture_specular_offset(texture_specular_offset);
*(vec3*)&value = texture_data->texture_specular_offset;
value.w = 0.0f;
object_data->set_texture_specular_offset(value);
}
size_t texture_pattern_count = texture_pattern ? texture_pattern->size() : 0;
if (texture_pattern && texture_pattern_count)
object_data->set_texture_pattern((int32_t)texture_pattern_count, texture_pattern->data());
if (fabsf(alpha - 1.0f) > 0.000001f)
draw_task_add_draw_object_by_object_info_alpha(rctx,
global_mat, obj_info, alpha, rctx->matrix_buffer);
else
draw_task_add_draw_object_by_object_info(rctx,
global_mat, obj_info, rctx->matrix_buffer);
if (texture_pattern && texture_pattern_count)
object_data->set_texture_pattern();
if (texture_data && !texture_data->field_0) {
object_data->set_texture_color_coeff(texture_color_coeff);
object_data->set_texture_color_offset(texture_color_offset);
object_data->set_texture_specular_coeff(texture_specular_coeff);
object_data->set_texture_specular_offset(texture_specular_offset);
}
}
void draw_task_sort(render_context* rctx, draw_object_type type, int32_t compare_func) {
std::vector<draw_task*>& vec = rctx->object_data.draw_task_array[type];
if (vec.size() < 1)
return;
object_data* object_data = &rctx->object_data;
for (draw_task*& i : vec) {
draw_task* task = i;
vec3 center;
mat4_get_translation(&task->mat, &center);
if (task->type == DRAW_TASK_TYPE_OBJECT) {
mat4 mat = task->mat;
if (task->data.object.mesh->attrib.m.billboard)
model_mat_face_camera_view(&rctx->camera->view, &mat, &mat);
else if (task->data.object.mesh->attrib.m.billboard_y_axis)
model_mat_face_camera_position(&rctx->camera->view, &mat, &mat);
obj_sub_mesh* sub_mesh = task->data.object.sub_mesh;
if (task->data.object.mat_count < 1 || !sub_mesh->bone_indices_count)
mat4_mult_vec3_trans(&mat, &sub_mesh->bounding_sphere.center, &center);
else {
vec3 center_sum = vec3_null;
for (uint32_t j = 0; j < sub_mesh->bone_indices_count; j++) {
center = sub_mesh->bounding_sphere.center;
mat4_mult_vec3_trans(&task->data.object.mats[j], &center, &center);
vec3_add(center_sum, center, center_sum);
}
vec3_mult_scalar(center_sum, 1.0f / (float_t)sub_mesh->bone_indices_count, center);
}
task->bounding_radius = task->data.object.mesh->bounding_sphere.radius;
}
mat4_mult_vec3_trans(&rctx->camera->view, &center, &center);
task->depth = center.z;
}
switch (compare_func) {
case 0:
quicksort_custom(vec.data(), vec.size(),
sizeof(draw_task*), draw_task_sort_quicksort_compare0);
break;
case 1:
quicksort_custom(vec.data(), vec.size(),
sizeof(draw_task*), draw_task_sort_quicksort_compare1);
break;
case 2:
quicksort_custom(vec.data(), vec.size(),
sizeof(draw_task*), draw_task_sort_quicksort_compare2);
break;
}
}
int32_t obj_axis_aligned_bounding_box_check_visibility(
obj_axis_aligned_bounding_box* aabb, camera* cam, mat4* mat) {
vec3 size;
vec3 points[8];
vec3 neg;
neg = { 0.0f, 0.0f, 0.0f };
vec3_xor(aabb->size, neg, size);
vec3_add(aabb->center, size, points[0]);
neg = { -0.0f, -0.0f, -0.0f };
vec3_xor(aabb->size, neg, size);
vec3_add(aabb->center, size, points[1]);
neg = { -0.0f, 0.0f, 0.0f };
vec3_xor(aabb->size, neg, size);
vec3_add(aabb->center, size, points[2]);
neg = { 0.0f, -0.0f, -0.0f };
vec3_xor(aabb->size, neg, size);
vec3_add(aabb->center, size, points[3]);
neg = { 0.0f, -0.0f, 0.0f };
vec3_xor(aabb->size, neg, size);
vec3_add(aabb->center, size, points[4]);
neg = { -0.0f, 0.0f, -0.0f };
vec3_xor(aabb->size, neg, size);
vec3_add(aabb->center, size, points[5]);
neg = { 0.0f, 0.0f, -0.0f };
vec3_xor(aabb->size, neg, size);
vec3_add(aabb->center, size, points[6]);
neg = { -0.0f, -0.0f, 0.0f };
vec3_xor(aabb->size, neg, size);
vec3_add(aabb->center, size, points[7]);
mat4 view_mat;
mat4_mult(mat, &cam->view, &view_mat);
for (int32_t i = 0; i < 8; i++)
mat4_mult_vec3_trans(&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 = 0.0f;
vec3_dot(*(vec3*)&v2[i], points[j], v34);
v34 += v2[i].w;
if (v34 > 0.0f)
break;
if (j == 7)
return 0;
}
return 1;
}
int32_t object_bounding_sphere_check_visibility(obj_bounding_sphere* sphere,
object_data* object_data, camera* cam, mat4* mat) {
if (object_data->object_bounding_sphere_check_func)
return object_data->object_bounding_sphere_check_func(sphere, cam);
vec3 center;
mat4_mult_vec3_trans(mat, &sphere->center, &center);
mat4_mult_vec3_trans(&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, v5);
if (v5 < -radius)
return 0;
float_t v6;
vec3_dot(cam->field_1F0, center, v6);
if (v6 < -radius)
return 0;
float_t v7;
vec3_dot(cam->field_1FC, center, v7);
if (v7 < -radius)
return 0;
float_t v8;
vec3_dot(cam->field_208, center, v8);
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;
}
inline static void draw_task_add(render_context* rctx, draw_object_type type, draw_task* task) {
rctx->object_data.draw_task_array[type].push_back(task);
}
inline static void draw_task_object_init(draw_task* task, object_data* object_data, mat4* mat,
float_t bounding_radius, obj_sub_mesh* sub_mesh, obj_mesh* mesh, obj_material_data* material,
std::vector<GLuint>* textures, int32_t mat_count, mat4* mats, GLuint array_buffer,
GLuint element_array_buffer, vec4* blend_color, vec4* emission, int32_t morph_array_buffer,
int32_t instances_count, mat4* instances_mat, void(*draw_object_func)(draw_object*)) {
task->type = DRAW_TASK_TYPE_OBJECT;
task->mat = *mat;
task->bounding_radius = bounding_radius;
task->data.object.mesh = mesh;
task->data.object.morph_value = object_data->morph.value;
task->data.object.material = material;
task->data.object.sub_mesh = sub_mesh;
task->data.object.textures = textures;
task->data.object.mat_count = mat_count;
task->data.object.mats = mats;
task->data.object.array_buffer = array_buffer;
task->data.object.element_array_buffer = element_array_buffer;
task->data.object.morph_array_buffer = morph_array_buffer;
draw_object* draw = &task->data.object;
draw->texture_pattern_count = object_data->texture_pattern_count;
for (int32_t i = 0; i < object_data->texture_pattern_count && i < TEXTURE_PATTERN_COUNT; i++)
draw->texture_pattern_array[i] = object_data->texture_pattern_array[i];
draw->texture_transform_count = object_data->texture_transform_count;
for (int32_t i = 0; i < object_data->texture_transform_count && i < TEXTURE_TRANSFORM_COUNT; i++)
draw->texture_transform_array[i] = object_data->texture_transform_array[i];
if (blend_color && memcmp(blend_color, &vec4_identity, sizeof(vec4))) {
draw->set_blend_color = true;
draw->blend_color = *blend_color;
}
else {
draw->set_blend_color = false;
draw->blend_color = vec4_identity;
}
draw->emission = *emission;
draw->chara_color = object_data->chara_color;
draw->self_shadow = object_data->draw_task_flags & (DRAW_TASK_8 | DRAW_TASK_4) ? 1 : 0;
draw->shadow = object_data->shadow_type;
draw->texture_color_coeff = object_data->texture_color_coeff;
draw->texture_color_coeff.w = object_data->wet_param;
draw->texture_color_offset = object_data->texture_color_offset;
draw->texture_specular_coeff = object_data->texture_specular_coeff;
draw->texture_specular_offset = object_data->texture_specular_offset;
draw->instances_count = instances_count;
draw->instances_mat = instances_mat;
draw->draw_object_func = draw_object_func;
}
inline static void draw_task_object_translucent_init(draw_task* task, mat4* mat,
draw_task_object_translucent* object) {
task->type = DRAW_TASK_TYPE_OBJECT_TRANSLUCENT;
task->mat = *mat;
task->data.object_translucent = *object;
}
static int draw_task_sort_quicksort_compare0(void const* src1, void const* src2) {
float_t d1 = (*(draw_task**)src1)->depth;
float_t d2 = (*(draw_task**)src2)->depth;
return d1 > d2 ? -1 : (d1 < d2 ? 1 : 0);
}
static int draw_task_sort_quicksort_compare1(void const* src1, void const* src2) {
float_t d1 = (*(draw_task**)src1)->depth;
float_t d2 = (*(draw_task**)src2)->depth;
return d1 < d2 ? -1 : (d1 > d2 ? 1 : 0);
}
static int draw_task_sort_quicksort_compare2(void const* src1, void const* src2) {
float_t r1 = (*(draw_task**)src1)->bounding_radius;
float_t r2 = (*(draw_task**)src2)->bounding_radius;
return r1 < r2 ? 1 : (r1 > r2 ? -1 : 0);
}
inline static int32_t draw_task_translucent_sort_count_layers(render_context* rctx,
int32_t* alpha_array, draw_object_type opaque,
draw_object_type transparent, draw_object_type translucent) {
bool arr[256] = { 0 };
draw_task_translucent_sort_has_objects(rctx, arr, opaque);
draw_task_translucent_sort_has_objects(rctx, arr, transparent);
draw_task_translucent_sort_has_objects(rctx, arr, translucent);
int32_t count = 0;
for (int32_t i = 0xFF; i >= 1; i--)
if (arr[i]) {
count++;
*alpha_array++ = i;
}
return count;
}
inline static void draw_task_translucent_sort_has_objects(render_context* rctx, bool* arr, draw_object_type type) {
std::vector<draw_task*>& vec = rctx->object_data.draw_task_array[type];
for (draw_task*& i : vec) {
draw_task* task = i;
if (task->type != DRAW_TASK_TYPE_OBJECT)
continue;
int32_t alpha = (int32_t)(task->data.object.blend_color.w * 255.0f);
alpha = clamp(alpha, 0, 255);
arr[alpha] = true;
}
}