From 3ee9c642f6bacfbe5fa464c44c281b9da881db8b Mon Sep 17 00:00:00 2001 From: korenkonder Date: Sat, 9 Dec 2023 01:03:13 +0300 Subject: [PATCH] Task Effect --- src/DivaGL/DivaGL.vcxproj | 4 + src/DivaGL/camera.cpp | 5 + src/DivaGL/camera.hpp | 2 + src/DivaGL/file_handler.cpp | 60 ++ src/DivaGL/file_handler.hpp | 35 + src/DivaGL/hook.cpp | 2 + src/DivaGL/render_manager.cpp | 31 +- src/DivaGL/stage_param.cpp | 50 +- src/DivaGL/stage_param.hpp | 7 +- src/DivaGL/task_effect.cpp | 1621 +++++++++++++++++++++++++++++++++ src/DivaGL/task_effect.hpp | 58 ++ 11 files changed, 1863 insertions(+), 12 deletions(-) create mode 100644 src/DivaGL/file_handler.cpp create mode 100644 src/DivaGL/file_handler.hpp create mode 100644 src/DivaGL/task_effect.cpp create mode 100644 src/DivaGL/task_effect.hpp diff --git a/src/DivaGL/DivaGL.vcxproj b/src/DivaGL/DivaGL.vcxproj index 3d2dce5..8d9fbdd 100644 --- a/src/DivaGL/DivaGL.vcxproj +++ b/src/DivaGL/DivaGL.vcxproj @@ -250,6 +250,7 @@ del "$(SolutionDir)bin\$(TargetName).lib" + @@ -281,6 +282,7 @@ del "$(SolutionDir)bin\$(TargetName).lib" + @@ -293,6 +295,7 @@ del "$(SolutionDir)bin\$(TargetName).lib" + @@ -324,6 +327,7 @@ del "$(SolutionDir)bin\$(TargetName).lib" + diff --git a/src/DivaGL/camera.cpp b/src/DivaGL/camera.cpp index 09dd676..8a44e03 100644 --- a/src/DivaGL/camera.cpp +++ b/src/DivaGL/camera.cpp @@ -81,6 +81,11 @@ HOOK(void, FASTCALL, camera_update, 0x00000001401F8970) { camera_data->fast_change = false; } +void camera_struct::get_view_point(vec4& value) { + *(vec3*)&value = view_point; + value.w = 0.0f; +} + void camera_struct::update_data() { implOfcamera_data_update_projection(); camera_struct__update_view(camera_data); diff --git a/src/DivaGL/camera.hpp b/src/DivaGL/camera.hpp index 0644066..a3b0911 100644 --- a/src/DivaGL/camera.hpp +++ b/src/DivaGL/camera.hpp @@ -50,6 +50,8 @@ struct camera_struct { bool fast_change_hist1; int32_t field_22C; + void get_view_point(vec4& value); + static void update_data(); }; diff --git a/src/DivaGL/file_handler.cpp b/src/DivaGL/file_handler.cpp new file mode 100644 index 0000000..2a201f4 --- /dev/null +++ b/src/DivaGL/file_handler.cpp @@ -0,0 +1,60 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include +#include "../KKdLib/io/file_stream.hpp" +#include "../KKdLib/hash.hpp" +#include "file_handler.hpp" +#include + +void p_file_handler::call_free_callback() { + static void(FASTCALL * p_file_handler__call_free_callback)(p_file_handler * pfhndl) + = (void(FASTCALL*)(p_file_handler * pfhndl))0x0000000140181F30; + p_file_handler__call_free_callback(this); +} + +bool p_file_handler::check_not_ready() { + static bool(FASTCALL * p_file_handler__check_not_ready)(p_file_handler * pfhndl) + = (bool(FASTCALL*)(p_file_handler * pfhndl))0x0000000140183340; + return p_file_handler__check_not_ready(this); +} + +const void* p_file_handler::get_data() { + static const void* (FASTCALL * p_file_handler__get_data)(p_file_handler * pfhndl) + = (const void* (FASTCALL*)(p_file_handler * pfhndl))0x0000000140182EA0; + return p_file_handler__get_data(this); +} + +ssize_t p_file_handler::get_size() { + static ssize_t(FASTCALL * p_file_handler__get_size)(p_file_handler * pfhndl) + = (ssize_t(FASTCALL*)(p_file_handler * pfhndl))0x0000000140183250; + return p_file_handler__get_size(this); +} + +bool p_file_handler::read_file(const char* farc_path, const char* file_path, int32_t heap_malloc_type, bool cache) { + static bool (FASTCALL * p_file_handler__read_file)(p_file_handler * pfhndl, const char* farc_path, + const char* file_path, int32_t heap_malloc_type, bool cache) + = (bool (FASTCALL*)(p_file_handler * pfhndl, const char* farc_path, + const char* file_path, int32_t heap_malloc_type, bool cache))0x0000000140183430; + return p_file_handler__read_file(this, farc_path, file_path, heap_malloc_type, cache); +} + +void p_file_handler::read_now() { + static void (FASTCALL * p_file_handler__read_now)(p_file_handler * pfhndl) + = (void (FASTCALL*)(p_file_handler * pfhndl))0x00000001401841F0; + p_file_handler__read_now(this); +} + +void p_file_handler::reset() { + static void (FASTCALL * p_file_handler__reset)(p_file_handler * pfhndl) + = (void (FASTCALL*)(p_file_handler * pfhndl))0x0000000140182CA0; + p_file_handler__reset(this); +} + +void p_file_handler::set_callback_data(int32_t index, PFNFILEHANDLERCALLBACK* func, void* data) { + static void (FASTCALL * p_file_handler__set_callback_data)(p_file_handler * pfhndl, int32_t index, PFNFILEHANDLERCALLBACK func, void* data) + = (void (FASTCALL*)(p_file_handler * pfhndl, int32_t index, PFNFILEHANDLERCALLBACK func, void* data))0x0000000140183F40; + p_file_handler__set_callback_data(this, index, func, data); +} diff --git a/src/DivaGL/file_handler.hpp b/src/DivaGL/file_handler.hpp new file mode 100644 index 0000000..d46406a --- /dev/null +++ b/src/DivaGL/file_handler.hpp @@ -0,0 +1,35 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include +#include +#include +#include +#include +#include "../KKdLib/default.hpp" +#include "../KKdLib/farc.hpp" + +typedef void (PFNFILEHANDLERCALLBACK)(void*, const void*); + +struct file_handler_callback_func { + PFNFILEHANDLERCALLBACK* func; + void* data; + bool ready; +}; + +struct p_file_handler { + struct file_handler* ptr; + + void call_free_callback(); + bool check_not_ready(); + const void* get_data(); + ssize_t get_size(); + bool read_file(const char* farc_path, const char* file_path, int32_t heap_malloc_type, bool cache); + void read_now(); + void reset(); + void set_callback_data(int32_t index, PFNFILEHANDLERCALLBACK* func, void* data); +}; diff --git a/src/DivaGL/hook.cpp b/src/DivaGL/hook.cpp index 48a1a34..e9ce94c 100644 --- a/src/DivaGL/hook.cpp +++ b/src/DivaGL/hook.cpp @@ -12,6 +12,7 @@ #include "shader_glsl_ft.hpp" #include "sprite.hpp" #include "stage.hpp" +#include "task_effect.hpp" #include "texture.hpp" #include @@ -25,6 +26,7 @@ HOOK(int32_t, FASTCALL, data_init, 0x0000000140192FF0) { rob_patch(); sprite_patch(); stage_patch(); + task_effect_patch(); Glitter::Patch(); rctx = new render_context; diff --git a/src/DivaGL/render_manager.cpp b/src/DivaGL/render_manager.cpp index bc50cfd..fd2873e 100644 --- a/src/DivaGL/render_manager.cpp +++ b/src/DivaGL/render_manager.cpp @@ -17,6 +17,7 @@ #include "shader_glsl_ft.hpp" #include "sprite.hpp" #include "stage_param.hpp" +#include "task_effect.hpp" #include "texture.hpp" #include @@ -153,6 +154,16 @@ namespace rndr { } void RenderManager::render_all() { + static const GLfloat color_clear[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + static const GLfloat depth_clear = 1.0f; + static const GLint stencil_clear = 0; + + gl_state_bind_framebuffer(0); + gl_state_set_depth_mask(GL_TRUE); + glClearBufferfv(GL_COLOR, 0, color_clear); + glClearDepthf(depth_clear); + gl_state_set_depth_mask(GL_FALSE); + static const int32_t ibl_texture_index[] = { 9, 10, 11, 12, 13 }; @@ -721,7 +732,7 @@ namespace rndr { pass_3d_contour(); render->draw_lens_flare(); - //star_catalog_draw(); + star_catalog_draw(); draw_pass_3d_translucent( draw_pass_3d[DRAW_PASS_3D_OPAQUE], @@ -731,10 +742,10 @@ namespace rndr { mdl::OBJ_TYPE_TRANSPARENT_ALPHA_ORDER_3, mdl::OBJ_TYPE_TRANSLUCENT_ALPHA_ORDER_3); - //snow_particle_draw(); - //rain_particle_draw(); - //leaf_particle_draw(); - //particle_draw(); + snow_particle_draw(); + rain_particle_draw(); + leaf_particle_draw(); + particle_draw(); gl_state_disable_depth_test(); gl_state_set_color_mask(GL_TRUE, GL_TRUE, GL_TRUE, GL_FALSE); @@ -1012,7 +1023,7 @@ void draw_pass_set_camera() { mat4_transpose(&camera_data->projection_matrix, &rctx->proj_mat); mat4_transpose(&camera_data->view_projection_matrix, &rctx->vp_mat); rctx->obj_scene.set_projection_view(rctx->view_mat, rctx->proj_mat); - *(vec3*)&rctx->obj_scene.g_view_position = camera_data->view_point; + camera_data->get_view_point(rctx->obj_scene.g_view_position); rctx->obj_scene.g_view_position.w = 0.0f; float_t max_distance = camera_data->max_distance; @@ -1292,10 +1303,10 @@ static void draw_pass_shadow_esm_filter(RenderTexture* dst, RenderTexture* buf, } static bool draw_pass_shadow_litproj() { - if (!*stage_param_data_litproj_current) + if (!stage_param_data_litproj_current) return false; - texture* tex = texture_handler_get_texture((*stage_param_data_litproj_current)->tex_id); + texture* tex = texture_handler_get_texture(stage_param_data_litproj_current->tex_id); if (!tex) return false; @@ -1321,7 +1332,7 @@ static bool draw_pass_shadow_litproj() { } static bool draw_pass_shadow_litproj_set() { - if (!*stage_param_data_litproj_current) + if (!stage_param_data_litproj_current) return 0; static const vec4 color_clear = 1.0f; @@ -1781,5 +1792,5 @@ static void blur_filter_apply(RenderTexture* dst, RenderTexture* src, rctx->filter_scene_ubo.Bind(0); rctx->imgfilter_batch_ubo.Bind(1); gl_state_active_bind_texture_2d(0, src->GetColorTex()); - //shaders_ft.draw_arrays(GL_TRIANGLE_STRIP, (GLint)(filter * 4LL), 4); + shaders_ft.draw_arrays(GL_TRIANGLE_STRIP, (GLint)(filter * 4LL), 4); } diff --git a/src/DivaGL/stage_param.cpp b/src/DivaGL/stage_param.cpp index eee9d05..2bbe2f3 100644 --- a/src/DivaGL/stage_param.cpp +++ b/src/DivaGL/stage_param.cpp @@ -5,4 +5,52 @@ #include "stage_param.hpp" -stage_param_data_litproj** stage_param_data_litproj_current = (stage_param_data_litproj**)0x0000000141194D80; +stage_param_data_litproj*& stage_param_data_litproj_current = *(stage_param_data_litproj**)0x0000000141194D80; + +double_t stage_param_data_star_utc::to_julian_date() const { + int64_t year = this->year; + int64_t month = this->month; + if (month == 1 || month == 2) { + year--; + month += 12; + } + + return (double_t)(day + year / 400 + (int64_t)((double_t)year * 365.25) + - (int32_t)((double_t)(month - 2) * -30.59) - year / 100) + + 1721088.5 + + (double_t)hour * (1.0 / 24.0) + + (double_t)minute * (1.0 / 1440.0) + + (double_t)second * (1.0 / 86400.0); +} + +void stage_param_data_star::get_mat(mat4& mat, const float_t observer_north_latitude, + const float_t observer_east_longitude, const stage_param_data_star_utc& utc, const float_t rotation_y) { + double_t v7 = (utc.to_julian_date() - 2440000.5) * 1.0027379094 + 0.671262; + + mat3 rot_y; + mat3_rotate_y((float_t)(v7 - (double_t)(int64_t)v7) * (float_t)(M_PI * 2.0) + observer_east_longitude, &rot_y); + + float_t latitude_sin = sinf(observer_north_latitude); + float_t latitude_cos = cosf(observer_north_latitude) * 0.99664718f; + + vec3 x_axis = { 0.0f, latitude_cos, -latitude_sin }; + mat3_transform_vector(&rot_y, &x_axis, &x_axis); + + vec3 y_axis = { 0.0f, latitude_sin, latitude_cos }; + mat3_transform_vector(&rot_y, &y_axis, &y_axis); + + vec3 z_axis = { 1.0f, 0.0f, 0.0f }; + mat3_transform_vector(&rot_y, &z_axis, &z_axis); + + x_axis = vec3::normalize(x_axis); + y_axis = vec3::normalize(y_axis); + + float_t rot_y_sin = sinf(rotation_y); + float_t rot_y_cos = cosf(rotation_y); + + mat4 temp = mat4_identity; + *(vec3*)&temp.row0 = x_axis * -rot_y_sin + z_axis * rot_y_cos; + *(vec3*)&temp.row1 = y_axis; + *(vec3*)&temp.row2 = x_axis * -rot_y_cos + z_axis * -rot_y_sin; + mat4_transpose(&temp, &mat); +} diff --git a/src/DivaGL/stage_param.hpp b/src/DivaGL/stage_param.hpp index c38b9ee..c388912 100644 --- a/src/DivaGL/stage_param.hpp +++ b/src/DivaGL/stage_param.hpp @@ -144,6 +144,8 @@ struct stage_param_data_star_utc { int32_t hour; int32_t minute; float_t second; + + double_t to_julian_date() const; }; static_assert(sizeof(stage_param_data_star_utc) == 0x18, "\"stage_param_data_star_utc\" struct should have a size of 0x18"); @@ -165,8 +167,11 @@ struct stage_param_data_star { float_t observer_north_latitude_deg; float_t observer_east_longitude_deg; stage_param_data_star_modifiers modifiers[2]; + + static void get_mat(mat4& mat, const float_t observer_north_latitude, + const float_t observer_east_longitude, const stage_param_data_star_utc& utc, const float_t rotation_y); }; static_assert(sizeof(stage_param_data_star) == 0x50, "\"stage_param_data_star\" struct should have a size of 0x50"); -extern stage_param_data_litproj** stage_param_data_litproj_current; +extern stage_param_data_litproj*& stage_param_data_litproj_current; diff --git a/src/DivaGL/task_effect.cpp b/src/DivaGL/task_effect.cpp new file mode 100644 index 0000000..111d066 --- /dev/null +++ b/src/DivaGL/task_effect.cpp @@ -0,0 +1,1621 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#include "task_effect.hpp" +#include "../KKdLib/prj/algorithm.hpp" +#include "../KKdLib/hash.hpp" +#include "auth_3d.hpp" +#include "file_handler.hpp" +#include "gl_state.hpp" +#include "gl_element_array_buffer.hpp" +#include "render_context.hpp" +#include "render_manager.hpp" +#include "shader_glsl_ft.hpp" +#include "stage_param.hpp" +#include "texture.hpp" +#include + +struct __declspec(align(16)) leaf_particle_data { + vec4 position; + vec4 direction; + vec4 normal; + vec4 rotation; + vec4 rotation_add; + float_t size; + int32_t type; + int32_t field_58; + int32_t field_5C; +}; + +static_assert(sizeof(leaf_particle_data) == 0x60, "\"particle_data\" struct should have a size of 0x60"); + +struct leaf_particle_vertex_data { + vec3 position; + vec3 normal; + vec2 texcoord; +}; + +struct __declspec(align(16)) particle_data { + vec4 position; + float_t size; + float_t alpha; + int32_t life_time; + int32_t pad_1C; + vec4 velocity; + vec4 direction; +}; + +static_assert(sizeof(particle_data) == 0x40, "\"particle_data\" struct should have a size of 0x40"); + +struct __declspec(align(16)) particle_rot_data { + vec4 position; + vec4 direction; + vec4 normal; + vec4 rotation; + vec4 rotation_add; + vec4 color; + bool alive; + float_t type; + float_t life_time; + float_t size; +}; + +static_assert(sizeof(particle_rot_data) == 0x70, "\"particle_rot_data\" struct should have a size of 0x70"); + +struct particle_vertex_data { + vec3 position; + vec3 normal; + vec4 color; + vec2 texcoord; +}; + +struct star_catalog_milky_way { + GLArrayBuffer vbo; + GLElementArrayBuffer ebo; + GLuint vao; + uint16_t restart_index; + int32_t idx_count; + int32_t longitude_degs_10; + int32_t latitude_degs_10; + float_t longitude_offset_degs_10; + float_t latitude_offset_degs_10; + float_t latitude; + float_t longitude; + float_t uv_rec_scale_u; + float_t uv_rec_scale_v; + + void create_buffers(int32_t subdivs, float_t uv_rec_scale_u, float_t uv_rec_scale_v, + int32_t longitude_degs_10, int32_t latitude_degs_10, + float_t longitude_offset_degs_10, float_t latitude_offset_degs_10); + void create_default_sphere(); + void delete_buffers(); + void draw(const mat4& vp, const mat4& model, texture* tex, GLUniformBuffer& scene_ubo); +}; + +static_assert(sizeof(star_catalog_milky_way) == 0x34, "\"star_catalog_milky_way\" struct should have a size of 0x34"); + +struct star_catalog { + GLuint vbo; + GLuint vao; + bool random; + bool enable; + stage_param_data_star* stage_param_data_ptr; + stage_param_data_star stage_param_data; + star_catalog_milky_way milky_way; + int32_t stars_count; + p_file_handler file_handler; + uint32_t star_tex; + uint32_t star_b_tex; + uint32_t milky_way_tex_id; + + void draw(); + void free(); + bool init(); +}; + +static_assert(sizeof(star_catalog) == 0xB8, "\"star_catalog\" struct should have a size of 0xB8"); + +struct leaf_particle_scene_shader_data { + vec4 g_transform[4]; + vec4 g_view_pos; + vec4 g_color; + vec4 g_light_env_stage_diffuse; + vec4 g_light_env_stage_specular; + vec4 g_lit_dir; + vec4 g_lit_luce; +}; + +struct particle_scene_shader_data { + vec4 g_transform[4]; + vec4 g_view_pos; + vec4 g_light_env_chara_diffuse; + vec4 g_light_env_chara_specular; +}; + +struct rain_particle_scene_shader_data { + vec4 g_view[4]; + vec4 g_proj[4]; + vec4 g_range_scale; + vec4 g_range_offset; +}; + +struct rain_particle_batch_shader_data { + vec4 g_pos_offset; + vec4 g_tangent; + vec4 g_color; +}; + +struct ripple_batch_shader_data { + vec4 g_params; +}; + +struct ripple_scene_shader_data { + vec4 g_transform; + vec4 g_texcoord; +}; + +struct ripple_emit_scene_shader_data { + vec4 g_size_in_projection; + vec4 g_transform; + vec4 g_framebuffer_size; +}; + +struct snow_particle_vertex_data { + vec3 position; + float_t size; + float_t alpha; +}; + +struct snow_particle_gpu_vertex_data { + vec3 position; + float_t size; +}; + +struct snow_particle_scene_shader_data { + vec4 g_transform[4]; + vec4 g_view_world_row2; + vec4 g_size_in_projection; + vec4 g_state_point_attenuation; + vec4 g_range_scale; + vec4 g_range_offset; + vec4 g_framebuffer_size; + vec4 g_near_far; +}; + +struct snow_particle_batch_shader_data { + vec4 g_pos_offset; + vec4 g_color; + vec4i start_vertex_location; +}; + +struct star_catalog_scene_shader_data { + vec4 g_transform[4]; +}; + +struct star_catalog_batch_shader_data { + vec4 g_size_in_projection; + vec4 g_modifiers; + vec4 g_thresholds; +}; + +static GLuint leaf_ptcl_vao; +static GLArrayBuffer leaf_ptcl_vbo; +static GLElementArrayBuffer leaf_ptcl_ebo; +static GLUniformBuffer leaf_particle_scene_ubo; +static const size_t leaf_ptcl_count = 0x800; + +static GLuint ptcl_vao; +static GLArrayBuffer ptcl_vbo; +static GLUniformBuffer particle_scene_ubo; +static const size_t ptcl_count = 0x400; + +static GLShaderStorageBuffer rain_ssbo; +static GLUniformBuffer rain_particle_scene_ubo; +static GLUniformBuffer rain_particle_batch_ubo; +static const size_t rain_ptcl_count = 0x8000; + +static GLUniformBuffer ripple_batch_ubo; +static GLUniformBuffer ripple_scene_ubo; + +static GLShaderStorageBuffer ripple_emit_ssbo; +static GLUniformBuffer ripple_emit_scene_ubo; + +static GLShaderStorageBuffer snow_ssbo; +static GLShaderStorageBuffer snow_gpu_ssbo; +static GLShaderStorageBuffer snow_fallen_ssbo; +static GLUniformBuffer snow_particle_scene_ubo; +static GLUniformBuffer snow_particle_batch_ubo; +static const size_t snow_ptcl_count = 0x8000; +static const size_t snow_ptcl_fallen_count = 0x2000; + +static GLShaderStorageBuffer stars_ssbo; +static GLUniformBuffer stars_scene_ubo; +static GLUniformBuffer stars_batch_ubo; +static int32_t star_count; +static int32_t star_b_count; +static GLuint star_sampler; + +static float_t& snow_particle_delta_frame = *(float_t*)0x0000000140C9A4E0; + +static stage_param_data_leaf*& stage_param_data_leaf_current = *(stage_param_data_leaf**)0x0000000141194D40; +static bool& leaf_particle_enable = *(bool*)0x0000000141194D48; +static bool& stage_param_data_leaf_set = *(bool*)0x0000000141194D49; +static float_t& leaf_particle_emit_timer = *(float_t*)0x0000000141194D4C; +static float_t& leaf_particle_emit_interval = *(float_t*)0x0000000141194D50; +static int32_t& leaf_particle_num_ptcls = *(int32_t*)0x0000000141194D54; +static leaf_particle_data*& leaf_ptcl_data = *(leaf_particle_data**)0x0000000141194D58; +static leaf_particle_vertex_data*& leaf_ptcl_vertex_data = *(leaf_particle_vertex_data**)0x0000000141194D60; + +static bool& particle_enable = *(bool*)0x0000000141194E30; +static particle_rot_data*& ptcl_data = *(particle_rot_data**)0x0000000141194E38; +static int32_t& particle_index = *(int32_t*)0x0000000141194E48; +static int32_t& particle_count = *(int32_t*)0x0000000141194E4C; +static vec3& particle_wind = *(vec3*)0x0000000141194E50; + +static particle_data* rain_ptcl_data = (particle_data*)0x0000000141194E70; +static stage_param_data_rain*& stage_param_data_rain_current = *(stage_param_data_rain**)0x0000000141195070; +static bool& rain_particle_enable = *(bool*)0x0000000141195078; +static bool& stage_param_data_rain_set = *(bool*)0x0000000141195079; + +static float_t& snow_particle_size_mid = *(float_t*)0x0000000141195CF0; +static float_t& snow_particle_size_min = *(float_t*)0x0000000141195CF4; +static float_t& snow_particle_size_max = *(float_t*)0x0000000141195CF8; +static bool& snow_particle_enable = *(bool*)0x0000000141195CFC; +static bool& stage_param_data_snow_set = *(bool*)0x0000000141195CFD; +static int32_t& snow_particle_fallen_count = *(int32_t*)0x0000000141195D04; +static particle_data*& snow_ptcl_data = *(particle_data**)0x0000000141195D08; +static particle_data* snow_ptcl_gpu = (particle_data*)0x0000000141195D10; +static particle_data*& snow_ptcl_fallen_data = *(particle_data**)0x0000000141195E10; +static int32_t snow_particle_fallen_index = *(int32_t*)0x0000000141195E18; +static stage_param_data_snow*& stage_param_data_snow_current = *(stage_param_data_snow**)0x0000000141195E20; + +static star_catalog& star_catalog_data = *(star_catalog*)0x0000000141195E90; + +static float_t(FASTCALL* rand_state_array_get_float)(int32_t id) + = (float_t(FASTCALL*)(int32_t id))0x00000001404FFE60; +static int32_t(FASTCALL* rand_state_array_get_int)(uint32_t min, uint32_t max, int32_t id) + = (int32_t(FASTCALL*)(uint32_t min, uint32_t max, int32_t id))0x00000001404FFD80; + +static void (FASTCALL* snow_particle_data_init)() = (void (FASTCALL*)())0x000000014035C930; +static void (FASTCALL* snow_particle_data_free)() = (void (FASTCALL*)())0x000000014035DB90; + +extern render_context* rctx; + +static int32_t leaf_particle_disp(); + +static int32_t particle_disp(particle_vertex_data* vtx_data, particle_rot_data* data, int32_t count); + +static void rain_particle_free(); + +static void snow_particle_data_emit_fallen(particle_data* data); +static void snow_particle_data_kill_fallen(particle_data* data, bool kill); +static void snow_particle_data_reset(particle_data* data); +static particle_data* snow_particle_emit_fallen(); +static vec3 snow_particle_get_random_velocity(); +static void snow_particle_free(); + +void leaf_particle_draw() { + if (!stage_param_data_leaf_current || !leaf_ptcl_data + || !leaf_particle_enable || !stage_param_data_leaf_set) + return; + + texture* tex = texture_handler_get_texture(stage_param_data_leaf_current->tex_id); + if (!tex) + return; + + int32_t count = leaf_particle_disp(); + if (!count) + return; + + const light_data& light_stage = light_set_data[LIGHT_SET_MAIN].lights[LIGHT_STAGE]; + + leaf_particle_scene_shader_data shader_data = {}; + mat4 temp; + mat4_transpose(&rctx->vp_mat, &temp); + shader_data.g_transform[0] = temp.row0; + shader_data.g_transform[1] = temp.row1; + shader_data.g_transform[2] = temp.row2; + shader_data.g_transform[3] = temp.row3; + camera_data->get_view_point(shader_data.g_view_pos); + shader_data.g_color = stage_param_data_leaf_current->color; + light_stage.get_diffuse(shader_data.g_light_env_stage_diffuse); + light_stage.get_specular(shader_data.g_light_env_stage_specular); + shader_data.g_lit_dir = rctx->obj_scene.g_light_chara_dir; + shader_data.g_lit_luce = rctx->obj_scene.g_light_chara_luce; + leaf_particle_scene_ubo.WriteMemory(shader_data); + + gl_state_active_bind_texture_2d(0, tex->tex); + shaders_ft.set(SHADER_FT_LEAF_PT); + leaf_particle_scene_ubo.Bind(0); + gl_state_bind_vertex_array(leaf_ptcl_vao); + shaders_ft.draw_elements(GL_TRIANGLES, count / 4 * 6, GL_UNSIGNED_INT, 0); + gl_state_bind_vertex_array(0); +} + +void rain_particle_draw() { + if (!stage_param_data_rain_current || !rain_particle_enable || !stage_param_data_rain_set) + return; + + texture* tex = texture_handler_get_texture(stage_param_data_rain_current->tex_id); + if (!tex) + return; + + stage_param_data_rain* rain = stage_param_data_rain_current; + vec3 range = rain->range; + vec3 range_scale = rain->range; + vec3 range_offset = rain->offset; + range_offset.x -= range.x * 0.5f; + range_offset.z -= range.z * 0.5f; + + rain_particle_scene_shader_data scene_shader_data = {}; + mat4 temp; + mat4_transpose(&rctx->view_mat, &temp); + scene_shader_data.g_view[0] = temp.row0; + scene_shader_data.g_view[1] = temp.row1; + scene_shader_data.g_view[2] = temp.row2; + scene_shader_data.g_view[3] = temp.row3; + mat4_transpose(&rctx->proj_mat, &temp); + scene_shader_data.g_proj[0] = temp.row0; + scene_shader_data.g_proj[1] = temp.row1; + scene_shader_data.g_proj[2] = temp.row2; + scene_shader_data.g_proj[3] = temp.row3; + scene_shader_data.g_range_scale = { range_scale.x, range_scale.y, range_scale.z, 0.0f }; + scene_shader_data.g_range_offset = { range_offset.x, range_offset.y, range_offset.z, 0.0f }; + rain_particle_scene_ubo.WriteMemory(scene_shader_data); + + gl_state_enable_blend(); + gl_state_set_blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl_state_enable_depth_test(); + gl_state_set_depth_mask(GL_FALSE); + gl_state_active_bind_texture_2d(0, tex->tex); + shaders_ft.set(SHADER_FT_RAIN); + + float_t tangent_sign = -rain->psize.x; + float_t tangent_size = -rain->psize.y * (float_t)(1.0 / 30.0); + + int32_t first = 0; + int32_t count = min_def(rain->num_rain, (int32_t)rain_ptcl_count) / 2 / 4 * 6; + + vec4 color = rain->color; + float_t color_a = color.w; + rain_particle_scene_ubo.Bind(0); + rain_particle_batch_ubo.Bind(1); + rain_ssbo.Bind(0); + gl_state_bind_vertex_array(rctx->common_vao); + for (int32_t i = 0; i < 8; i++, first += count) { + particle_data& data = rain_ptcl_data[i]; + vec3 pos_offset = *(vec3*)&data.position / range; + vec3 tangent = *(vec3*)&data.velocity * tangent_size; + color.w = color_a * data.alpha; + + rain_particle_batch_shader_data batch_shader_data = {}; + batch_shader_data.g_pos_offset = { pos_offset.x, pos_offset.y, pos_offset.z, 0.075f }; + batch_shader_data.g_tangent = { tangent.x, tangent.y, tangent.z, tangent_sign }; + batch_shader_data.g_color = color; + rain_particle_batch_ubo.WriteMemory(batch_shader_data); + shaders_ft.draw_arrays(GL_TRIANGLES, first, count); + } + gl_state_bind_vertex_array(0); + gl_state_active_bind_texture_2d(0, 0); + gl_state_set_depth_mask(GL_TRUE); + gl_state_disable_blend(); +} + +void particle_draw() { + if (!ptcl_data) + return; + + particle_vertex_data* vtx_data = (particle_vertex_data*)ptcl_vbo.MapMemory(); + if (!vtx_data) + return; + + int32_t count = particle_disp(vtx_data, ptcl_data, ptcl_count); + + ptcl_vbo.UnmapMemory(); + + if (!count) + return; + + const light_data& light_chara = light_set_data[LIGHT_SET_MAIN].lights[LIGHT_CHARA]; + + particle_scene_shader_data shader_data = {}; + mat4 temp; + mat4_transpose(&rctx->vp_mat, &temp); + shader_data.g_transform[0] = temp.row0; + shader_data.g_transform[1] = temp.row1; + shader_data.g_transform[2] = temp.row2; + shader_data.g_transform[3] = temp.row3; + camera_data->get_view_point(shader_data.g_view_pos); + light_chara.get_diffuse(shader_data.g_light_env_chara_diffuse); + light_chara.get_specular(shader_data.g_light_env_chara_specular); + particle_scene_ubo.WriteMemory(shader_data); + + shaders_ft.set(SHADER_FT_PARTICL); + particle_scene_ubo.Bind(0); + gl_state_bind_vertex_array(ptcl_vao); + shaders_ft.draw_arrays(GL_TRIANGLES, 0, count); + gl_state_bind_vertex_array(0); +} + +void snow_particle_draw() { + if (!stage_param_data_snow_current || !snow_particle_enable || !stage_param_data_snow_set) + return; + + texture* tex = texture_handler_get_texture(stage_param_data_snow_current->tex_id); + if (!tex) + return; + + stage_param_data_snow* snow = stage_param_data_snow_current; + draw_pass_set_camera(); + + gl_state_enable_blend(); + gl_state_set_blend_func(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + gl_state_enable_depth_test(); + gl_state_set_depth_mask(GL_FALSE); + + float_t point_attenuation = powf(tanf((float_t)camera_data->fov + * 0.5f * DEG_TO_RAD_FLOAT) * 3.4f, 2.0f) * 0.1f; + + snow_particle_scene_shader_data snow_scene = {}; + mat4 temp; + mat4_transpose(&rctx->vp_mat, &temp); + snow_scene.g_transform[0] = temp.row0; + snow_scene.g_transform[1] = temp.row1; + snow_scene.g_transform[2] = temp.row2; + snow_scene.g_transform[3] = temp.row3; + + mat4_transpose(&rctx->view_mat, &temp); + snow_scene.g_view_world_row2 = temp.row2; + snow_scene.g_size_in_projection.x = 1.0f / (float_t)render->render_width[0]; + snow_scene.g_size_in_projection.y = 1.0f / (float_t)render->render_height[0]; + snow_scene.g_size_in_projection.z = snow_particle_size_min; + snow_scene.g_size_in_projection.w = snow_particle_size_max; + snow_scene.g_state_point_attenuation = { 0.0f, 0.0f, point_attenuation, 0.0f }; + snow_scene.g_range_scale.x = snow->range_gpu.x; + snow_scene.g_range_scale.y = snow->range_gpu.y; + snow_scene.g_range_scale.z = snow->range_gpu.z; + snow_scene.g_range_offset.x = snow->offset_gpu.x - snow->range_gpu.x * 0.5f; + snow_scene.g_range_offset.y = snow->offset_gpu.y; + snow_scene.g_range_offset.z = snow->offset_gpu.z - snow->range_gpu.z * 0.5f; + snow_particle_scene_ubo.WriteMemory(snow_scene); + + snow_particle_batch_shader_data snow_batch = {}; + snow_batch.g_color = snow->color; + snow_batch.start_vertex_location.x = 0; + snow_particle_batch_ubo.WriteMemory(snow_batch); + + gl_state_active_bind_texture_2d(0, tex->tex); + gl_state_active_bind_texture_2d(1, render->rend_texture[0].GetDepthTex()); + gl_state_bind_vertex_array(rctx->common_vao); + + uniform->arr[U_SNOW_PARTICLE] = 0; + shaders_ft.set(SHADER_FT_SNOW_PT); + snow_particle_scene_ubo.Bind(0); + snow_particle_batch_ubo.Bind(1); + + snow_ssbo.Bind(0); + shaders_ft.draw_arrays(GL_TRIANGLES, 0, snow->num_snow * 6); + + snow_fallen_ssbo.Bind(0); + shaders_ft.draw_arrays(GL_TRIANGLES, 0, (GLsizei)(snow_ptcl_fallen_count * 6)); + + uniform->arr[U_SNOW_PARTICLE] = 1; + shaders_ft.set(SHADER_FT_SNOW_PT); + snow_particle_scene_ubo.Bind(0); + snow_particle_batch_ubo.Bind(1); + + point_attenuation = powf(tanf((float_t)camera_data->fov + * 0.5f * DEG_TO_RAD_FLOAT) * 3.4f, 2.0f) * 0.06f; + + snow_scene.g_state_point_attenuation = { 0.0f, 0.0f, point_attenuation, 0.0f }; + snow_particle_scene_ubo.WriteMemory(snow_scene); + + snow_gpu_ssbo.Bind(0); + + int32_t count = snow->num_snow_gpu / 4; + count = min_def(count, (int32_t)snow_ptcl_count / 4) * 6; + + int32_t first = 0; + for (int32_t i = 0; i < 4; i++) { + particle_data& j = snow_ptcl_gpu[i]; + vec3 pos_offset = *(vec3*)&j.position / snow->range_gpu; + vec4 color = snow->color; + color.w *= j.alpha; + + snow_batch = {}; + snow_batch.g_pos_offset = { pos_offset.x, pos_offset.y, pos_offset.z, 0.0f }; + snow_batch.g_color = color; + snow_batch.start_vertex_location.x = first; + snow_particle_batch_ubo.WriteMemory(snow_batch); + + shaders_ft.draw_arrays(GL_TRIANGLES, 0, count); + first += count; + } + + gl_state_active_bind_texture_2d(1, 0); + gl_state_active_bind_texture_2d(0, 0); + + gl_state_disable_depth_test(); + gl_state_set_depth_mask(GL_TRUE); + gl_state_disable_blend(); +} + +void star_catalog_draw() { + star_catalog_data.draw(); +} + +HOOK(void, FASTCALL, leaf_particle_free, 0x000000014034BB30) { + if (leaf_ptcl_data) { + free(leaf_ptcl_data); + leaf_ptcl_data = 0; + } + + if (leaf_ptcl_vao) { + glDeleteVertexArrays(1, &leaf_ptcl_vao); + leaf_ptcl_vao = 0; + } + + leaf_ptcl_vbo.Destroy(); + leaf_ptcl_ebo.Destroy(); + + leaf_particle_scene_ubo.Destroy(); +} + +HOOK(void, FASTCALL, leaf_particle_init, 0x000000014034C530, bool change_stage) { + leaf_particle_emit_timer = 0.0f; + leaf_particle_emit_interval = stage_param_data_leaf_current->emit_interval; + if (change_stage) + return; + + implOfleaf_particle_free(); + + const size_t leaf_ptcl_vtx_count = leaf_ptcl_count * 0x08; + + leaf_ptcl_data = force_malloc(leaf_ptcl_count); + + leaf_particle_num_ptcls = stage_param_data_leaf_current->num_initial_ptcls; + + static void (FASTCALL * leaf_particle_data__init)(leaf_particle_data * leaf_ptcl_data) + = (void (FASTCALL*)(leaf_particle_data * leaf_ptcl_data))0x000000014034BDD0; + + leaf_particle_data* data = leaf_ptcl_data; + int32_t i = 0; + for (; i < leaf_particle_num_ptcls; i++, data++) + leaf_particle_data__init(data); + + for (; i < leaf_ptcl_count; i++, data++) + data->type = 0; + + if (!leaf_ptcl_vao) + glGenVertexArrays(1, &leaf_ptcl_vao); + + static const GLsizei buffer_size = sizeof(leaf_particle_vertex_data); + + leaf_ptcl_vbo.Create(buffer_size * leaf_ptcl_vtx_count); + leaf_ptcl_vbo.Bind(); + + gl_state_bind_vertex_array(leaf_ptcl_vao); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, buffer_size, + (void*)offsetof(leaf_particle_vertex_data, position)); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, buffer_size, + (void*)offsetof(leaf_particle_vertex_data, texcoord)); + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, buffer_size, + (void*)offsetof(leaf_particle_vertex_data, normal)); + + size_t ebo_count = leaf_ptcl_vtx_count / 4 * 6; + uint32_t* ebo_data = force_malloc(ebo_count); + for (size_t i = 0, j = 0; i < ebo_count; i += 6, j += 4) { + ebo_data[i + 0] = (uint32_t)(j + 0); + ebo_data[i + 1] = (uint32_t)(j + 1); + ebo_data[i + 2] = (uint32_t)(j + 2); + ebo_data[i + 3] = (uint32_t)(j + 0); + ebo_data[i + 4] = (uint32_t)(j + 2); + ebo_data[i + 5] = (uint32_t)(j + 3); + } + + leaf_ptcl_ebo.Create(sizeof(uint32_t) * ebo_count, ebo_data); + leaf_ptcl_ebo.Bind(); + free_def(ebo_data); + + gl_state_bind_vertex_array(0); + gl_state_bind_array_buffer(0); + gl_state_bind_element_array_buffer(0); + + leaf_particle_scene_ubo.Create(sizeof(leaf_particle_scene_shader_data)); +} + +HOOK(bool, FASTCALL, TaskEffectRain__Dest, 0x0000000140353DA0, size_t task_eff_rain) { + if (stage_param_data_rain_current) { + implOfleaf_particle_free(); + stage_param_data_rain_current = 0; + void (FASTCALL * stage_param_data_rain_storage_clear)() + = (void (FASTCALL*)())0x0000000140353CD0; + stage_param_data_rain_storage_clear(); + stage_param_data_rain_set = 0; + *(int32_t*)(task_eff_rain + 0x70) = -1; + *(size_t*)(task_eff_rain + 0x80) = *(size_t*)(task_eff_rain + 0x78); + } + return true; +} + +HOOK(void, FASTCALL, rain_particle_init, 0x00000001403546A0, bool change_stage) { + vec3 velocity = stage_param_data_rain_current->velocity; + vec3 vel_range = stage_param_data_rain_current->vel_range; + + for (int32_t i = 0; i < 8; i++) { + particle_data& data = rain_ptcl_data[i]; + data.position.x = 0.0f; + data.position.y = ((float_t)i * -12.5f) - 5.0f; + data.position.z = 0.0f; + data.size = 1.0f; + data.alpha = 1.0f; + data.life_time = 1; + vec3 _velocity; + _velocity.x = rand_state_array_get_float(4); + _velocity.y = rand_state_array_get_float(4); + _velocity.z = rand_state_array_get_float(4); + *(vec3*)&data.velocity = (_velocity - 0.5f) * vel_range + velocity; + } + + if (change_stage) + return; + + rain_particle_free(); + + vec3* vtx_data = force_malloc(rain_ptcl_count); + for (int32_t i = 0; i < rain_ptcl_count; i++) { + vec3 position; + position.x = rand_state_array_get_float(4); + position.y = rand_state_array_get_float(4); + position.z = rand_state_array_get_float(4); + *vtx_data++ = position; + } + + vtx_data -= rain_ptcl_count; + + rain_ssbo.Create(sizeof(vec3) * rain_ptcl_count, vtx_data); + + free_def(vtx_data); + + rain_particle_scene_ubo.Create(sizeof(rain_particle_scene_shader_data)); + rain_particle_batch_ubo.Create(sizeof(rain_particle_batch_shader_data)); +} + +HOOK(void, FASTCALL, particle_free, 0x0000000140351600) { + if (ptcl_data) + delete[] ptcl_data; + + ptcl_data = 0; + particle_index = 0; + particle_count = 0; + + if (ptcl_vao) { + glDeleteVertexArrays(1, &ptcl_vao); + ptcl_vao = 0; + } + + ptcl_vbo.Destroy(); + + particle_scene_ubo.Destroy(); +} + +HOOK(void, FASTCALL, particle_init, 0x0000000140351C50, vec3* offset) { + implOfparticle_free(); + + const size_t ptcl_vtx_count = ptcl_count * 0x06; + + ptcl_data = force_malloc(ptcl_count); + + particle_rot_data* data = ptcl_data; + for (size_t i = 0; i < ptcl_count; i++, data++) + data->alive = false; + + particle_index = 0; + particle_count = 0; + + if (offset) + particle_wind = *offset; + else + particle_wind = 0.0f; + + if (!ptcl_vao) + glGenVertexArrays(1, &ptcl_vao); + + static const GLsizei buffer_size = sizeof(particle_vertex_data); + + ptcl_vbo.Create(buffer_size * ptcl_vtx_count); + ptcl_vbo.Bind(); + + gl_state_bind_vertex_array(ptcl_vao); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, buffer_size, + (void*)offsetof(particle_vertex_data, position)); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 4, GL_FLOAT, GL_FALSE, buffer_size, + (void*)offsetof(particle_vertex_data, color)); + glEnableVertexAttribArray(2); + glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, buffer_size, + (void*)offsetof(particle_vertex_data, texcoord)); + glEnableVertexAttribArray(3); + glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, buffer_size, + (void*)offsetof(particle_vertex_data, normal)); + + gl_state_bind_vertex_array(0); + gl_state_bind_array_buffer(0); + + particle_scene_ubo.Create(sizeof(particle_scene_shader_data)); +} + +HOOK(bool, FASTCALL, TaskEffectSnow__Dest, 0x000000014035CEF0, size_t task_eff_snow) { + snow_particle_data_free(); + snow_particle_free(); + + stage_param_data_snow_current = 0; + void (FASTCALL * stage_param_data_snow_storage_clear)() + = (void (FASTCALL*)())0x000000014035CE20; + stage_param_data_snow_storage_clear(); + stage_param_data_snow_set = 0; + *(int32_t*)(task_eff_snow + 0x70) = -1; + *(size_t*)(task_eff_snow + 0x80) = *(size_t*)(task_eff_snow + 0x78); + return true; +} + +HOOK(void, FASTCALL, snow_particle_ctrl, 0x000000014035CA20) { + if (!stage_param_data_snow_current) + return; + + stage_param_data_snow* snow = stage_param_data_snow_current; + float_t colli_ground_y = snow->colli_ground.y + 0.03f; + float_t offset_y = snow->offset.y; + + float_t delta_time = (float_t)(snow_particle_delta_frame * (1.0 / 60.0)); + + vec4 _colli_ground_xz = { + -snow->colli_ground.min_x, + snow->colli_ground.max_x, + -snow->colli_ground.min_z, + snow->colli_ground.max_z + }; + + __m128 colli_ground_xz = vec4::load_xmm(_colli_ground_xz); + + if (snow->num_snow > 0) { + particle_data* snow_ptcl = snow_ptcl_data; + for (int32_t i = ((snow->num_snow - 1) >> 1) + 1; i; i--, snow_ptcl += 2) { + vec3 direction; + if (--snow_ptcl[0].life_time > 0) + direction = *(vec3*)&snow_ptcl[0].direction; + else { + snow_ptcl[0].life_time = rand_state_array_get_int(15, 35, 4); + direction = snow_particle_get_random_velocity(); + *(vec3*)&snow_ptcl[0].direction = direction; + } + + vec3 velocity = (direction * delta_time + *(vec3*)&snow_ptcl[0].velocity) * 0.98f; + vec3 position = velocity * delta_time + *(vec3*)&snow_ptcl[0].position; + *(vec3*)&snow_ptcl[0].velocity = velocity; + *(vec3*)&snow_ptcl[0].position = position; + + if (position.y < offset_y) + snow_particle_data_reset(snow_ptcl); + else if (colli_ground_y > position.y) { + __m128 pos = vec3::load_xmm(position); + if (!_mm_movemask_ps(_mm_add_ps(_mm_mul_ps(_mm_shuffle_ps(pos, pos, 0xA0), + vec4::load_xmm({ 1.0f, -1.0f, 1.0f, -1.0f })), colli_ground_xz))) { + snow_ptcl[0].position.y = colli_ground_y; + snow_particle_data_emit_fallen(snow_ptcl); + snow_particle_data_reset(snow_ptcl); + } + } + + snow_ptcl[1].position = snow_ptcl[0].position + snow_ptcl[1].velocity; + } + } + + for (int32_t i = 0; i < 4; i++) { + particle_data& j = snow_ptcl_gpu[i]; + + vec3 direction; + if (--j.life_time > 0) + direction = *(vec3*)&j.direction; + else { + j.life_time = rand_state_array_get_int(0xFu, 0x23u, 4); + direction = snow_particle_get_random_velocity(); + *(vec3*)&j.direction = direction; + } + + vec3 velocity = (direction * delta_time + *(vec3*)&j.velocity) * 0.98f; + vec3 position = velocity * delta_time + *(vec3*)&j.position; + *(vec3*)&j.velocity = velocity; + j.alpha = 1.0f; + *(vec3*)&j.position = position; + if (position.y > -1.0f) + j.alpha = max_def(-position.y, 0.0f); + else if (position.y < -99.0f) { + j.alpha = max_def(position.y + 100.0f, 0.0f); + if (position.y < -100.0f) + j.position = 0.0f; + } + } + + particle_data* snow_ptcl_fallen = snow_ptcl_fallen_data; + for (size_t i = snow->num_snow; i; i--, snow_ptcl_fallen++) + if (snow_ptcl_fallen->size != 0.0f) { + snow_ptcl_fallen->alpha *= 0.95f; + if (snow_ptcl_fallen->alpha < 0.02f) + snow_particle_data_kill_fallen(snow_ptcl_fallen, true); + } + + snow_particle_vertex_data* vtx_data = (snow_particle_vertex_data*)snow_ssbo.MapMemory(); + if (vtx_data) { + particle_data* snow_ptcl = snow_ptcl_data; + for (int32_t i = snow->num_snow; i; i--, snow_ptcl++, vtx_data++) { + vtx_data->position = *(vec3*)&snow_ptcl->position; + vtx_data->size = snow_ptcl->size; + vtx_data->alpha = snow_ptcl->alpha; + } + } + snow_ssbo.UnmapMemory(); + + snow_particle_vertex_data* fallen_vtx_data = (snow_particle_vertex_data*)snow_fallen_ssbo.MapMemory(); + if (fallen_vtx_data) { + particle_data* snow_ptcl_fallen = snow_ptcl_fallen_data; + for (size_t i = snow_ptcl_fallen_count; i; i--, snow_ptcl_fallen++, fallen_vtx_data++) { + fallen_vtx_data->position = *(vec3*)&snow_ptcl_fallen->position; + fallen_vtx_data->size = snow_ptcl_fallen->size; + fallen_vtx_data->alpha = snow_ptcl_fallen->alpha; + } + } + snow_fallen_ssbo.UnmapMemory(); +} + + +HOOK(void, FASTCALL, snow_particle_init, 0x000000014035DD30, bool change_stage) { + stage_param_data_snow* snow = stage_param_data_snow_current; + + float_t colli_ground_y = stage_param_data_snow_current->colli_ground.y; + + snow_particle_fallen_count = 0; + snow_particle_fallen_index = 0; + + int32_t render_height = render->render_height[0]; + float_t snow_particle_size = (float_t)render_height * (float_t)(1.0 / 720.0); + snow_particle_size_min = snow_particle_size; + snow_particle_size_mid = snow_particle_size * 31.0f; + snow_particle_size_max = snow_particle_size * 63.0f; + + snow_particle_data_free(); + snow_particle_data_init(); + + vec3 velocity = snow->velocity; + vec3 vel_range = snow->vel_range; + vec3 range = snow->range; + vec3 offset = snow->offset; + range.y = offset.y + range.y - max_def(offset.y, colli_ground_y); + + if (stage_param_data_snow_current->num_snow > 0) { + particle_data* snow_ptcl = snow_ptcl_data; + for (int32_t i = ((stage_param_data_snow_current->num_snow - 1) >> 1) + 1; i; i--, snow_ptcl += 2) { + vec3 position; + position.x = rand_state_array_get_float(4) - 0.5f; + position.y = rand_state_array_get_float(4); + position.z = rand_state_array_get_float(4) - 0.5f; + *(vec3*)&snow_ptcl[0].position = position * range + offset; + + snow_ptcl[0].size = rand_state_array_get_float(4) * 0.4f + 0.3f; + snow_ptcl[0].alpha = rand_state_array_get_float(4) * 0.5f + 0.4f; + snow_ptcl[0].life_time = 1; + + vec3 _velocity; + _velocity.x = rand_state_array_get_float(4); + _velocity.y = rand_state_array_get_float(4); + _velocity.z = rand_state_array_get_float(4); + *(vec3*)&snow_ptcl[0].velocity = (_velocity - 0.5f) * vel_range + velocity; + + snow_ptcl[0].direction = 0.0f; + + snow_ptcl[1].size = ((rand_state_array_get_float(4) * 0.5f) + 0.3f) * snow_ptcl[0].size; + snow_ptcl[1].alpha = (rand_state_array_get_float(4) + 1.0f) * 0.3f; + + _velocity.x = rand_state_array_get_float(4); + _velocity.y = rand_state_array_get_float(4); + _velocity.z = rand_state_array_get_float(4); + *(vec3*)&snow_ptcl[1].velocity = (_velocity - 0.5f) * 0.035f * (snow_ptcl[1].size + snow_ptcl[0].size); + + snow_ptcl[0].size = snow_particle_size_mid * snow_ptcl[0].size; + snow_ptcl[1].size = snow_particle_size_mid * snow_ptcl[1].size; + } + } + + for (int32_t i = 0; i < snow_ptcl_fallen_count; i++) + snow_particle_data_kill_fallen(&snow_ptcl_fallen_data[i], false); + + for (int32_t i = 0; i < 4; i++) { + particle_data& j = snow_ptcl_gpu[i]; + j.position.x = 0.0f; + j.position.y = (float_t)i * -25.0f - 5.0f; + j.position.z = 0.0f; + j.alpha = 1.0; + j.life_time = 1; + + vec3 _velocity; + _velocity.x = rand_state_array_get_float(4); + _velocity.y = rand_state_array_get_float(4); + _velocity.z = rand_state_array_get_float(4); + *(vec3*)&j.velocity = (_velocity - 0.5f) * vel_range + velocity; + j.direction = 0.0f; + } + + if (change_stage) + return; + + snow_particle_free(); + + snow_ssbo.Create(sizeof(snow_particle_vertex_data) * snow->num_snow); + + snow_particle_gpu_vertex_data* vtx_data = force_malloc(snow_ptcl_count); + + for (int32_t i = 0; i < snow_ptcl_count; i++, vtx_data++) { + vtx_data->position.x = rand_state_array_get_float(4); + vtx_data->position.y = rand_state_array_get_float(4); + vtx_data->position.z = rand_state_array_get_float(4); + vtx_data->size = (rand_state_array_get_float(4) * 0.5f + 0.4f) * snow_particle_size_mid; + } + + vtx_data -= snow_ptcl_count; + + snow_gpu_ssbo.Create(sizeof(snow_particle_gpu_vertex_data) * snow_ptcl_count, vtx_data); + + free_def(vtx_data); + + snow_fallen_ssbo.Create(sizeof(snow_particle_vertex_data) * snow_ptcl_fallen_count); + + snow_particle_scene_ubo.Create(sizeof(snow_particle_scene_shader_data)); + snow_particle_batch_ubo.Create(sizeof(snow_particle_batch_shader_data)); +} + +HOOK(bool, FASTCALL, TaskEffectStar__Dest, 0x000000014036A830, size_t tast_eff_star){ + star_catalog_data.free(); + void (FASTCALL * stage_param_data_star_storage_clear)() + = (void (FASTCALL*)())0x000000014036A0E0; + stage_param_data_star_storage_clear(); + return true; +} + +HOOK(bool, FASTCALL, star_catalog__init, 0x000000014036CD50, star_catalog* star){ + return star->init(); +} + +void task_effect_patch() { + INSTALL_HOOK(leaf_particle_free); + INSTALL_HOOK(leaf_particle_init); + INSTALL_HOOK(particle_free); + INSTALL_HOOK(particle_init); + INSTALL_HOOK(TaskEffectRain__Dest); + INSTALL_HOOK(rain_particle_init); + INSTALL_HOOK(TaskEffectSnow__Dest); + INSTALL_HOOK(snow_particle_ctrl); + INSTALL_HOOK(snow_particle_init); + INSTALL_HOOK(TaskEffectStar__Dest); + INSTALL_HOOK(star_catalog__init); +} + +void star_catalog_milky_way::create_buffers(int32_t subdivs, float_t uv_rec_scale_u, float_t uv_rec_scale_v, + int32_t longitude_degs_10, int32_t latitude_degs_10, + float_t longitude_offset_degs_10, float_t latitude_offset_degs_10) { + delete_buffers(); + + const int32_t sectors_count = 2 * subdivs + 1; + const int32_t vtx_count = (subdivs - 1) * sectors_count + 2; + restart_index = (uint16_t)0xFFFFFFFF; + + gl_state_bind_vertex_array(0); + gl_state_bind_array_buffer(0); + gl_state_bind_element_array_buffer(0); + + const float_t rec_longitude_degs_10 = 1.0f / (float_t)longitude_degs_10; + const float_t rec_latitude_degs_10 = 1.0f / (float_t)latitude_degs_10; + + struct star_catalog_vertex { + vec3 position; + vec2 texcoord; + }; + + star_catalog_vertex* vtx_data = force_malloc(vtx_count); + vtx_data[0].position = { 0.0f, 1.0f, 0.0f }; + vtx_data[0].texcoord.x = 0.5f; + vtx_data[0].texcoord.y = (latitude_offset_degs_10 + (1.0f / uv_rec_scale_v) * 90.0f) * rec_latitude_degs_10; + size_t vtx = 1; + if (subdivs - 1 > 0) { + float_t rec_stack_step = 1.0f / (float_t)subdivs; + float_t rec_sector_step = 1.0f / (float_t)(2 * subdivs); + for (uint32_t i = subdivs - 1, j = 1; i; i--, j++) { + float_t stack_angle = (float_t)M_PI_2 - (float_t)j * (float_t)M_PI * rec_stack_step; + float_t xz = cosf(stack_angle); + float_t y = sinf(stack_angle); + float_t texcoord_y = (latitude_offset_degs_10 + stack_angle * (float_t)(1.0 / M_PI) + * 180.0f * (float_t)(1.0 / uv_rec_scale_v)) * rec_latitude_degs_10; + for (uint32_t k = sectors_count, l = 0; k; k--, l++, vtx++) { + float_t sector_angle = (float_t)l * (float_t)(2.0 * M_PI) * rec_sector_step; + vtx_data[vtx].position.x = sinf(sector_angle) * xz; + vtx_data[vtx].position.y = y; + vtx_data[vtx].position.z = cosf(sector_angle) * xz; + vtx_data[vtx].texcoord.x = (longitude_offset_degs_10 + (float_t)l * rec_sector_step + * 360.0f * (1.0f / uv_rec_scale_u)) * rec_longitude_degs_10; + vtx_data[vtx].texcoord.y = texcoord_y; + } + } + } + vtx_data[vtx].position = { 0.0f, -1.0f, 0.0f }; + vtx_data[vtx].texcoord.x = 1.0f; + vtx_data[vtx].texcoord.y = (latitude_offset_degs_10 - (1.0f / uv_rec_scale_v) * 90.0f) * rec_latitude_degs_10; + + if (!vao) + glGenVertexArrays(1, &vao); + + vbo.Create(sizeof(star_catalog_vertex) * vtx_count, vtx_data); + vbo.Bind(); + free_def(vtx_data); + + static const GLsizei buffer_size = sizeof(star_catalog_vertex); + + gl_state_bind_vertex_array(vao); + glEnableVertexAttribArray(0); + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, buffer_size, + (void*)offsetof(star_catalog_vertex, position)); + glEnableVertexAttribArray(1); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, buffer_size, + (void*)offsetof(star_catalog_vertex, texcoord)); + + const uint16_t first_vertex = 0; + const uint16_t last_vertex = (uint16_t)(vtx_count - 1); + uint16_t restart_index = this->restart_index; + + const int32_t ebo_count = (subdivs - 2) * (2 * sectors_count + 1) + 8 * sectors_count - 8; + idx_count = ebo_count; + uint16_t* ebo_data = force_malloc(ebo_count); + size_t idx = 0; + for (uint32_t i = sectors_count - 1, j = 1; i; i--, j++, idx += 4) { + ebo_data[idx + 0] = first_vertex; + ebo_data[idx + 1] = (uint16_t)(j + 1); + ebo_data[idx + 2] = (uint16_t)j; + ebo_data[idx + 3] = restart_index; + } + + uint16_t v37 = 1; + for (uint32_t i = subdivs - 2; i; i--, idx++) { + for (uint32_t j = sectors_count; j; j--, idx += 2, v37++) { + ebo_data[idx + 0] = (uint16_t)(v37 + sectors_count); + ebo_data[idx + 1] = (uint16_t)(v37); + } + ebo_data[idx] = restart_index; + } + + for (uint32_t i = sectors_count - 1; i; i--, idx += 4, v37++) { + ebo_data[idx + 0] = last_vertex; + ebo_data[idx + 1] = (uint16_t)v37; + ebo_data[idx + 2] = (uint16_t)(v37 + 1); + ebo_data[idx + 3] = restart_index; + } + + ebo.Create(sizeof(uint16_t) * ebo_count, ebo_data); + ebo.Bind(); + free_def(ebo_data); + + if (!star_sampler) + glGenSamplers(1, &star_sampler); + glSamplerParameteri(star_sampler, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glSamplerParameteri(star_sampler, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glSamplerParameteri(star_sampler, GL_TEXTURE_WRAP_S, GL_REPEAT); + glSamplerParameteri(star_sampler, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + gl_state_bind_vertex_array(0); + gl_state_bind_array_buffer(0); + gl_state_bind_element_array_buffer(0); +} + +void star_catalog_milky_way::create_default_sphere() { + create_buffers(16, uv_rec_scale_u, uv_rec_scale_v, longitude_degs_10, latitude_degs_10, + longitude_offset_degs_10, latitude_offset_degs_10); +} + +void star_catalog_milky_way::delete_buffers() { + if (star_sampler) { + glDeleteSamplers(1, &star_sampler); + star_sampler = 0; + } + + vbo.Destroy(); + ebo.Destroy(); + + if (vao) { + glDeleteVertexArrays(1, &vao); + vao = 0; + } +} + +void star_catalog_milky_way::draw(const mat4& vp, const mat4& mat, texture* tex, GLUniformBuffer& scene_ubo) { + if (!vao) + return; + + mat4 latitude_mat; + mat4 longitude_mat; + mat4_rotate_x(latitude * DEG_TO_RAD_FLOAT, &latitude_mat); + mat4_rotate_y(longitude * DEG_TO_RAD_FLOAT, &longitude_mat); + + mat4 model; + mat4_mul(&latitude_mat, &longitude_mat, &model); + + const float_t pitch_forward = -0.50503153f; + const float_t yaw_forward = 4.6496463f; + const float_t pitch_up = 0.47347879f; + const float_t yaw_up = 3.3660336f; + + vec3 forward; + vec3 up; + forward.x = sinf(yaw_forward) * cosf(pitch_forward); + forward.y = sinf(pitch_forward); + forward.z = cosf(yaw_forward) * cosf(pitch_forward); + up.x = sinf(yaw_up) * cosf(pitch_up); + up.y = sinf(pitch_up); + up.z = cosf(yaw_up) * cosf(pitch_up); + + mat4 view = mat4_identity; + *(vec3*)&view.row0 = vec3::cross(up, forward); + *(vec3*)&view.row1 = up; + *(vec3*)&view.row2 = forward; + + mat4_mul(&model, &view, &model); + mat4_mul(&model, &mat, &model); + + star_catalog_scene_shader_data scene_shader_data = {}; + mat4 temp; + mat4_mul(&model, &vp, &temp); + mat4_transpose(&temp, &temp); + scene_shader_data.g_transform[0] = temp.row0; + scene_shader_data.g_transform[1] = temp.row1; + scene_shader_data.g_transform[2] = temp.row2; + scene_shader_data.g_transform[3] = temp.row3; + scene_ubo.WriteMemory(scene_shader_data); + + gl_state_enable_cull_face(); + gl_state_disable_blend(); + gl_state_set_depth_mask(GL_FALSE); + gl_state_active_bind_texture_2d(0, tex->tex); + gl_state_bind_sampler(0, star_sampler); + gl_state_enable_primitive_restart(); + gl_state_set_primitive_restart_index(restart_index); + uniform->arr[U_STAR] = 1; + shaders_ft.set(SHADER_FT_STAR); + + gl_state_bind_vertex_array(vao); + scene_ubo.Bind(0); + shaders_ft.draw_elements(GL_TRIANGLE_STRIP, idx_count, GL_UNSIGNED_SHORT, 0); + gl_state_bind_vertex_array(0); + + gl_state_bind_sampler(0, 0); + gl_state_active_bind_texture_2d(0, 0); + gl_state_disable_primitive_restart(); + gl_state_set_depth_mask(GL_TRUE); + gl_state_enable_blend(); + gl_state_disable_cull_face(); + + +} + +void star_catalog::draw() { + if (!stage_param_data_ptr || !enable) + return; + + texture* star_tex = texture_handler_get_texture(this->star_tex); + texture* star_b_tex = texture_handler_get_texture(this->star_b_tex); + if (!star_tex || !star_b_tex) + return; + + mat4 model; + stage_param_data_star::get_mat(model, + stage_param_data.observer_north_latitude_deg * DEG_TO_RAD_FLOAT, + stage_param_data.observer_east_longitude_deg * DEG_TO_RAD_FLOAT, + stage_param_data.utc, + stage_param_data.rotation_y_deg * DEG_TO_RAD_FLOAT); + + const mat4& view = rctx->view_mat; + model.row3.x = vec3::dot(-*(vec3*)&view.row0, *(vec3*)&view.row3) + model.row3.x; + model.row3.y = vec3::dot(-*(vec3*)&view.row1, *(vec3*)&view.row3) + model.row3.y; + model.row3.z = vec3::dot(-*(vec3*)&view.row2, *(vec3*)&view.row3) + model.row3.z; + + mat4 proj = rctx->proj_mat; + proj.row0.z = proj.row0.w; + proj.row1.z = proj.row1.w; + proj.row2.z = proj.row2.w; + proj.row3.z = proj.row3.w; + + mat4 vp; + mat4_mul(&rctx->view_mat, &proj, &vp); + + texture* milky_way_tex = texture_handler_get_texture(milky_way_tex_id); + if (milky_way_tex) + milky_way.draw(vp, model, milky_way_tex, stars_scene_ubo); + + star_catalog_scene_shader_data scene_shader_data = {}; + mat4 temp; + mat4_mul(&model, &vp, &temp); + mat4_transpose(&temp, &temp); + scene_shader_data.g_transform[0] = temp.row0; + scene_shader_data.g_transform[1] = temp.row1; + scene_shader_data.g_transform[2] = temp.row2; + scene_shader_data.g_transform[3] = temp.row3; + stars_scene_ubo.WriteMemory(scene_shader_data); + + uniform->arr[U_STAR] = 0; + shaders_ft.set(SHADER_FT_STAR); + gl_state_enable_blend(); + gl_state_set_blend_func(GL_ONE, GL_ONE); + gl_state_enable_depth_test(); + gl_state_set_depth_mask(false); + gl_state_bind_vertex_array(rctx->common_vao); + for (int32_t i = 0; i < 2; i++) { + stage_param_data_star_modifiers& modifiers = stage_param_data.modifiers[i]; + + star_catalog_batch_shader_data batch_shader_data = {}; + batch_shader_data.g_size_in_projection = { + (float_t)(1.0 / 1280.0), (float_t)(1.0 / 720.0), 0.0f, modifiers.size_max + }; + batch_shader_data.g_modifiers = { + modifiers.color_scale, modifiers.color_scale * modifiers.offset_scale, + modifiers.pos_scale, modifiers.pos_scale * modifiers.offset_scale + }; + batch_shader_data.g_thresholds = { modifiers.threshold * modifiers.pos_scale, 0.0f, 0.0f, 0.0f }; + stars_batch_ubo.WriteMemory(batch_shader_data); + + stars_scene_ubo.Bind(0); + stars_batch_ubo.Bind(1); + stars_ssbo.Bind(0); + if (i) { + gl_state_active_bind_texture_2d(0, star_b_tex->tex); + shaders_ft.draw_arrays(GL_TRIANGLES, 0, star_b_count * 6); + } + else { + gl_state_active_bind_texture_2d(0, star_tex->tex); + shaders_ft.draw_arrays(GL_TRIANGLES, 0, star_count * 6); + } + } + gl_state_active_bind_texture_2d(0, 0); + gl_state_bind_vertex_array(0); + +} + +void star_catalog::free() { + stars_ssbo.Destroy(); + + stars_batch_ubo.Destroy(); + stars_scene_ubo.Destroy(); + + star_catalog_data.file_handler.reset(); + star_catalog_data.milky_way.delete_buffers(); + + star_catalog_data.stage_param_data_ptr = 0; +} + +bool star_catalog::init() { + if (file_handler.check_not_ready()) + return false; + + if (file_handler.get_data()) { + struct stars_buffer_data { + vec3 position; + vec4 color; + float_t size; + + inline stars_buffer_data() : size() { + + } + }; + + prj::vector vec; + file_handler.get_size(); + const void* data = file_handler.get_data(); + void (FASTCALL* star_catalog__parse_data)(prj::vector* vec, size_t data) + = (void (FASTCALL*)(prj::vector*vec, size_t data))0x000000014036C6A0; + star_catalog__parse_data(&vec, (size_t)data); + std::sort(vec.begin(), vec.end(), [](stars_buffer_data a, stars_buffer_data b) { + return a.size > b.size; + }); + + stars_buffer_data* stars_data = vec.data(); + size_t length = vec.size(); + size_t temp; + while (length > 0) + if (stars_data[temp = length / 2].size <= 0.0f) + length = temp; + else { + stars_data += temp + 1; + length -= temp + 1; + } + + if (stars_data != vec.data() + vec.size()) + vec.resize(stars_data - vec.data()); + + stars_data = vec.data(); + length = vec.size(); + while (length > 0) + if (stars_data[temp = length / 2].size <= 2.0f) + length = temp; + else { + stars_data += temp + 1; + length -= temp + 1; + } + + if (stars_data != vec.data() + vec.size()) + star_b_count = (int32_t)(stars_data - vec.data()); + else + star_b_count = (int32_t)vec.size(); + + file_handler.reset(); + + star_count = (int32_t)vec.size(); + + stars_ssbo.Create(sizeof(stars_buffer_data) * vec.size(), vec.data()); + } + + milky_way.create_default_sphere(); + + stars_scene_ubo.Create(sizeof(star_catalog_scene_shader_data)); + stars_batch_ubo.Create(sizeof(star_catalog_batch_shader_data)); + return true; +} + +static std::pair sub_1406427A0(vec3 x, vec3 y) { + float_t t1 = vec3::length_squared(x); + if (t1 <= 1.0e-30f) + return { y, 0.0f }; + + float_t t2 = 1.0f / sqrtf(t1); + float_t t3 = (t2 * 1.5f + t1 * t2 * t2 * t2 * -0.5f); + return { t3 * x, t3 * t1 }; +} + +static int32_t leaf_particle_disp() { + float_t size = leaf_ptcl_data[0].size; + + vec3 position[4]; + vec3 normal[4]; + position[0] = vec3(-0.5f, -0.5f, 0.0f) * size; + position[1] = vec3( 0.5f, -0.5f, 0.2f) * size; + position[2] = vec3( 0.5f, 0.5f, 0.0f) * size; + position[3] = vec3(-0.5f, 0.5f, 0.2f) * size; + normal[0] = sub_1406427A0(vec3( 0.0f, 0.0f, 1.0f), vec3(0.0f, 1.0f, 0.0f)).first; + normal[1] = sub_1406427A0(vec3(-0.4f, 0.4f, 1.0f), vec3(0.0f, 1.0f, 0.0f)).first; + normal[2] = sub_1406427A0(vec3(-0.2f, -0.2f, 1.0f), vec3(0.0f, 1.0f, 0.0f)).first; + normal[3] = sub_1406427A0(vec3( 0.4f, -0.4f, 1.0f), vec3(0.0f, 1.0f, 0.0f)).first; + + leaf_particle_vertex_data* vtx_data = (leaf_particle_vertex_data*)leaf_ptcl_vbo.MapMemory(); + if (!vtx_data) + return 0; + + int32_t vtx_count = 0; + leaf_particle_data* data = leaf_ptcl_data; + bool split_tex = stage_param_data_leaf_current->split_tex; + for (int32_t i = 0; i < leaf_particle_num_ptcls; i++, data++) { + if (!data->type) + continue; + + vec3 pos = *(vec3*)&data->position; + + mat3 mat; + mat3_rotate_xyz((vec3*)&data->rotation, &mat); + + vec3 t0; + vec3 t1; + vec3 t2; + vec3 t3; + mat3_transform_vector(&mat, &position[0], &t0); + mat3_transform_vector(&mat, &position[1], &t1); + mat3_transform_vector(&mat, &position[2], &t2); + mat3_transform_vector(&mat, &position[3], &t3); + vtx_data[0].position = pos + t0; + vtx_data[1].position = pos + t1; + vtx_data[2].position = pos + t2; + vtx_data[3].position = pos + t3; + + mat3_transform_vector(&mat, &normal[0], &t0); + mat3_transform_vector(&mat, &normal[1], &t1); + mat3_transform_vector(&mat, &normal[2], &t2); + mat3_transform_vector(&mat, &normal[3], &t3); + vtx_data[0].normal = t0; + vtx_data[1].normal = t1; + vtx_data[2].normal = t2; + vtx_data[3].normal = t3; + *(vec3*)&data[0].normal = t0; + + if (split_tex) { + const float_t u = i & 0x01 ? 1.0f : 0.0f; + const float_t v = i & 0x02 ? 1.0f : 0.0f; + + float_t u0 = u * 0.5f; + float_t v0 = v * 0.5f; + float_t u1 = (u + 1.0f) * 0.5f; + float_t v1 = (v + 1.0f) * 0.5f; + + vtx_data[0].texcoord = vec2(u0, v0); + vtx_data[1].texcoord = vec2(u1, v0); + vtx_data[2].texcoord = vec2(u1, v1); + vtx_data[3].texcoord = vec2(u0, v1); + } + else { + vtx_data[0].texcoord = 0.0f; + vtx_data[1].texcoord = vec2(1.0f, 0.0f); + vtx_data[2].texcoord = 1.0f; + vtx_data[3].texcoord = vec2(0.0f, 1.0f); + } + + if (data->type == 1) { + vtx_data[4] = vtx_data[0]; + vtx_data[5] = vtx_data[3]; + vtx_data[6] = vtx_data[2]; + vtx_data[7] = vtx_data[1]; + vtx_data[4].normal = -vtx_data[4].normal; + vtx_data[5].normal = -vtx_data[5].normal; + vtx_data[6].normal = -vtx_data[6].normal; + vtx_data[7].normal = -vtx_data[7].normal; + vtx_data += 8; + vtx_count += 8; + } + else { + vtx_data += 4; + vtx_count += 4; + } + } + + leaf_ptcl_vbo.UnmapMemory(); + return vtx_count; +} + +static int32_t particle_disp(particle_vertex_data* vtx_data, particle_rot_data* data, int32_t count) { + int32_t vtx_count = 0; + for (size_t i = 0; i < count; i++, data++) { + if (!data->alive) + continue; + + vec3 pos = *(vec3*)&data->position; + + mat3 mat; + mat3_rotate_xyz((vec3*)&data->rotation, &mat); + + float_t size = data->size; + + vec3 t0 = vec3(0.0125f, 0.007216875f, 0.0f) * size; + vec3 t1 = vec3(-0.0125f, 0.007216875f, 0.0f) * size; + vec3 t2 = vec3(0.0f, -0.01443375f, 0.0f) * size; + mat3_transform_vector(&mat, &t0, &t0); + mat3_transform_vector(&mat, &t1, &t1); + mat3_transform_vector(&mat, &t2, &t2); + t0 += pos; + t1 += pos; + t2 += pos; + + vec3 normal = vec3(0.0f, 0.0f, 1.0f); + mat3_transform_vector(&mat, &normal, &normal); + *(vec3*)&data->normal = normal; + + vec4 color = data->color; + vtx_data[0].position = t0; + vtx_data[1].position = t1; + vtx_data[2].position = t2; + vtx_data[0].normal = normal; + vtx_data[1].normal = normal; + vtx_data[2].normal = normal; + vtx_data[0].color = color; + vtx_data[1].color = color; + vtx_data[2].color = color; + vtx_data[0].texcoord = vec2(0.0f); + vtx_data[1].texcoord = vec2(1.0f, 0.5f); + vtx_data[2].texcoord = vec2(0.0f, 1.0f); + + normal = -normal; + vtx_data[3].position = t2; + vtx_data[4].position = t1; + vtx_data[5].position = t0; + vtx_data[3].normal = normal; + vtx_data[4].normal = normal; + vtx_data[5].normal = normal; + vtx_data[3].color = color; + vtx_data[4].color = color; + vtx_data[5].color = color; + vtx_data[3].texcoord = vec2(0.0f, 1.0f); + vtx_data[4].texcoord = vec2(1.0f, 0.5f); + vtx_data[5].texcoord = vec2(0.0f); + vtx_data += 6; + vtx_count += 6; + } + return vtx_count; +} + +static void rain_particle_free() { + rain_ssbo.Destroy(); + + rain_particle_scene_ubo.Destroy(); + rain_particle_batch_ubo.Destroy(); +} + +static void snow_particle_data_emit_fallen(particle_data* data) { + for (int32_t i = 0; i < 6; i++) { + particle_data* d = snow_particle_emit_fallen(); + if (!d) + break; + + d->position.x = (rand_state_array_get_float(4) - 0.5f) * 0.05f + data->position.x; + d->position.y = data->position.y; + d->position.z = (rand_state_array_get_float(4) - 0.5f) * 0.05f + data->position.z; + d->size = (rand_state_array_get_float(4) * 0.5f + 0.2f) * data->size; + d->velocity = 0.0f; + d->alpha = data->alpha * 0.60f; + } +} + +static void snow_particle_data_kill_fallen(particle_data* data, bool kill) { + if (kill) + --snow_particle_fallen_count; + + data->position = { 0.0f, -10.0f, 0.0f, 0.0f }; + data->size = 0.0f; + data->alpha = 1.0f; +} + +static void snow_particle_data_reset(particle_data* data) { + stage_param_data_snow* snow = stage_param_data_snow_current; + vec3 position; + position.x = rand_state_array_get_float(4) - 0.5f; + position.y = 1.0f; + position.z = rand_state_array_get_float(4) - 0.5f; + *(vec3*)&data->position = position * snow->range + snow->offset; + + data->life_time = 1; + + vec3 velocity; + velocity.x = rand_state_array_get_float(4); + velocity.y = rand_state_array_get_float(4); + velocity.z = rand_state_array_get_float(4); + *(vec3*)&data->velocity = (velocity - 0.5f) * snow->vel_range + snow->velocity; + data->direction = 0.0f; +} + +static particle_data* snow_particle_emit_fallen() { + if (snow_particle_fallen_count >= snow_ptcl_fallen_count) + return 0; + + for (int32_t i = 0; i < snow_ptcl_fallen_count; i++) { + particle_data* data = &snow_ptcl_fallen_data[snow_particle_fallen_index++]; + if (snow_particle_fallen_index >= snow_ptcl_fallen_count) + snow_particle_fallen_index = 0; + + if (data->size == 0.0f) { + snow_particle_fallen_count++; + return data; + } + } + return 0; +} + +static vec3 snow_particle_get_random_velocity() { + stage_param_data_snow* snow = stage_param_data_snow_current; + vec3 velocity; + velocity.x = rand_state_array_get_float(4); + velocity.y = rand_state_array_get_float(4); + velocity.z = rand_state_array_get_float(4); + return (velocity - 0.5f) * snow->vel_range + snow->velocity; +} + +static void snow_particle_free() { + snow_ssbo.Destroy(); + snow_gpu_ssbo.Destroy(); + snow_fallen_ssbo.Destroy(); + + snow_particle_scene_ubo.Destroy(); + snow_particle_batch_ubo.Destroy(); +} diff --git a/src/DivaGL/task_effect.hpp b/src/DivaGL/task_effect.hpp new file mode 100644 index 0000000..c7d3657 --- /dev/null +++ b/src/DivaGL/task_effect.hpp @@ -0,0 +1,58 @@ +/* + by korenkonder + GitHub/GitLab: korenkonder +*/ + +#pragma once + +#include "../KKdLib/default.hpp" +#include "../KKdLib/vec.hpp" +#include "../KKdLib/mat.hpp" +#include "../KKdLib/vec.hpp" +#include "gl_shader_storage_buffer.hpp" +#include "gl_uniform_buffer.hpp" +#include "rob/rob.hpp" +#include "render_texture.hpp" +#include "stage.hpp" +#include "stage_param.hpp" + +enum TaskEffectType { + TASK_EFFECT_INVALID = -1, + TASK_EFFECT_AUTH_3D = 0x00, + TASK_EFFECT_TYPE_1 = 0x01, + TASK_EFFECT_LEAF = 0x02, + TASK_EFFECT_TYPE_3 = 0x03, + TASK_EFFECT_SNOW = 0x04, + TASK_EFFECT_TYPE_5 = 0x05, + TASK_EFFECT_RIPPLE = 0x06, + TASK_EFFECT_RAIN = 0x07, + TASK_EFFECT_TYPE_8 = 0x08, + TASK_EFFECT_TYPE_9 = 0x09, + TASK_EFFECT_TYPE_10 = 0x0A, + TASK_EFFECT_TYPE_11 = 0x0B, + TASK_EFFECT_SPLASH = 0x0C, + TASK_EFFECT_TYPE_13 = 0x0D, + TASK_EFFECT_FOG_ANIM = 0x0E, + TASK_EFFECT_TYPE_15 = 0x0F, + TASK_EFFECT_FOG_RING = 0x10, + TASK_EFFECT_TYPE_17 = 0x11, + TASK_EFFECT_PARTICLE = 0x12, + TASK_EFFECT_LITPROJ = 0x13, + TASK_EFFECT_STAR = 0x14, +}; + +struct particle_init_data { + float_t field_0; + float_t field_4; + float_t field_8; + vec3 trans; + float_t scale_y; +}; + +extern void leaf_particle_draw(); +extern void rain_particle_draw(); +extern void particle_draw(); +extern void snow_particle_draw(); +extern void star_catalog_draw(); + +extern void task_effect_patch();