#include "holly/background.hpp" #include "holly/holly.hpp" #include "math/float_types.hpp" #include "math/transform.hpp" #include "ta_parameter.hpp" #include "scene/logo/scene.hpp" #include "scene/logo/sound.hpp" #include "texture.hpp" #include "framebuffer.hpp" #include "model/blender_export.h" #include "model/32bitlogo/model.h" static vec3 screen_transform(const vec3& v) { return {v.x, v.y, 1.0f / v.z}; } static inline float light_intensity(vec3 n, vec3 l) { float ambient = 0.4f; float diffuse_strength = 0.7f; float n_dot_l = dot(n, l); float diffuse = 0; if (n_dot_l > 0) diffuse = diffuse_strength * n_dot_l * (inverse_length(n) * inverse_length(l)); return ambient + diffuse; } vec3 light_vec = (vec3){-1, -1, -1} - (vec3){0, 0, 0}; using vec3i = vec<3, int>; static inline vec3i color_lerp(const vec3i& a, const vec3i& b, float f) { float dr = b.x - a.x; float dg = b.y - a.y; float db = b.z - a.z; return { (int)((float)a.x + dr * f), (int)((float)a.y + dg * f), (int)((float)a.z + db * f), }; } static inline int vec3i_to_int(const vec3i& a) { return (a.x << 16) | (a.y << 8) | (a.z << 0); } static void render_mesh(ta_parameter_writer& writer, const mesh& mesh, const mat4x4& trans, float base_intensity, bool wireframe, bool diffuse) { if (wireframe) { global_polygon_untextured(writer, para_control::list_type::translucent, tsp_instruction_word::dst_alpha_instr::zero); } else { uint32_t texture_size = tsp_instruction_word::texture_u_size::from_int(8) | tsp_instruction_word::texture_v_size::from_int(8); global_polygon_intensity(writer, para_control::list_type::translucent, texture::offset::logo, texture_size, texture_control_word::pixel_format::_565); } vec3 position_cache[mesh.position_length]; for (int i = 0; i < mesh.position_length; i++) { position_cache[i] = screen_transform(trans * mesh.position[i]); } vec3 normal_cache[mesh.polygons_length]; for (int i = 0; i < mesh.polygons_length; i++) { normal_cache[i] = normal_multiply(trans, mesh.polygon_normal[i]); } const vec3i white = vec3i(0xc0, 0xbe, 0xbc); const vec3i green = vec3i(0x33, 0xd1, 0x7a); const int wireframe_color = vec3i_to_int(color_lerp(white, green, base_intensity)); //const int green = (int)(255.f * base_intensity) << 8; for (int i = 0; i < mesh.polygons_length; i++) { const polygon& p = mesh.polygons[i]; vec3 ap = position_cache[p.a]; vec3 bp = position_cache[p.b]; vec3 cp = position_cache[p.c]; vec3 dp = position_cache[p.d]; if (wireframe) { line_type_0(writer, ap, bp, wireframe_color); line_type_0(writer, bp, cp, wireframe_color); if (p.d == -1) { line_type_0(writer, cp, ap, wireframe_color); } else { line_type_0(writer, cp, dp, wireframe_color); line_type_0(writer, dp, ap, wireframe_color); } } else { vec2 at = mesh.uv_layers[0][p.uv_index + 0]; vec2 bt = mesh.uv_layers[0][p.uv_index + 1]; vec2 ct = mesh.uv_layers[0][p.uv_index + 2]; vec2 dt = mesh.uv_layers[0][p.uv_index + 3]; float intensity = diffuse ? light_intensity(normal_cache[i], light_vec) : 1.0; if (p.d == -1) { tri_type_7(writer, ap, at, bp, bt, cp, ct, intensity); } else { quad_type_7(writer, ap, at, bp, bt, cp, ct, dp, dt, intensity); } } } } namespace scene::logo { const struct scene::scene scene = { .ta_alloc = ta_alloc_ctrl::pt_opb::no_list | ta_alloc_ctrl::tm_opb::no_list | ta_alloc_ctrl::t_opb::_32x4byte | ta_alloc_ctrl::om_opb::no_list | ta_alloc_ctrl::o_opb::no_list, .opb_size = { .opaque = 0, .opaque_modifier = 0, .translucent = 32 * 4, .translucent_modifier = 0, .punch_through = 0 }, .transfer = transfer, .interrupt = sound::interrupt, .init = init, .done = done }; static int tick = 0; static int last_tick = 0; struct keyframe { float i; // intensity float rx; // rotate_x float ry; // rotate_y float s; // scale float duration; }; const struct keyframe keyframes[] = { { .i = 0, .rx = 0, .ry = pi, .s = 0.01, .duration = 1.0 / (3.670), }, { .i = 1, .rx = 0, .ry = pi, .s = 0.1, .duration = 1.0 / (10.988), }, { .i = 1, .rx = pi / 4, .ry = -(pi - pi / 4), .s = 0.7, .duration = 1.0 / (10), }, }; const int keyframes_length = (sizeof (keyframes)) / (sizeof (keyframes[0])); static inline float clamp(float f) { if (f > 1.0) return 1.0; else if (f < 0.0) return 0.0; else return f; } static inline keyframe interpolate(const keyframe& a, const keyframe& b, const float dt, const float tick_div) { float ratio = clamp(dt * a.duration * tick_div); float di = b.i - a.i; float drx = b.rx - a.rx; float dry = b.ry - a.ry; float ds = b.s - a.s; return { .i = a.i + di * ratio, .rx = a.rx + drx * ratio, .ry = a.ry + dry * ratio, .s = a.s + ds * ratio, .duration = 0, }; } void transfer(ta_multiwriter& multi) { vec3 t = {framebuffer.px_width / 2.f, framebuffer.px_height / 2.f, 0}; float s = framebuffer.px_height / 3.f; static int keyframe_ix = 0; const float tick_div = framebuffer.px_height == 480 ? (1.0 / 60.0) : (1.0 / 120.0); const float tick_mul = framebuffer.px_height == 480 ? 60 : 120; float dt = tick - last_tick; if (dt * keyframes[keyframe_ix].duration * tick_div >= 1) { if (keyframe_ix < (keyframes_length - 2)) { last_tick = tick; dt = 0; keyframe_ix += 1; } } keyframe k = interpolate(keyframes[keyframe_ix], keyframes[keyframe_ix + 1], dt, tick_div); mat4x4 trans = translate(t) * scale((vec3){s, s, 1}) * translate((vec3){0, 0, 10}) //* rotate_x(pi / 8) //* rotate_y(pi + pi/8) * scale(k.s) * rotate_x(k.rx) * rotate_y(k.ry) * scale((vec3){-1, -1, 1}); bool _32_wf = tick < (10.988 * tick_mul); bool bit_wf = tick < (11.908 * tick_mul); bool jam_wf = tick < (12.825 * tick_mul); bool diffuse = tick >= (14.608 * tick_mul); render_mesh(multi.op, mesh_thirty_two, trans, k.i, _32_wf, diffuse); if (keyframe_ix > 0) { render_mesh(multi.op, mesh_bit, trans, k.i, bit_wf, diffuse); render_mesh(multi.op, mesh_jam, trans, k.i, jam_wf, diffuse); } tick += 1; } void init() { background_parameter2(texture_memory_alloc.background[1].start, 0xc0bebc); holly.VO_BORDER_COL = 0xc0bebc; ::scene::logo::sound::init(); } int done() { float tick_mul = framebuffer.px_height == 480 ? 60 : 120; if (tick >= (20.000 * tick_mul)) { int scene_id = ::scene::id::tracker; printf("scene transition to tracker %d\n", scene_id); return scene_id; } return -1; } }