From 7afce9e5b91c79db5001ffc909e7b909ebfaf717 Mon Sep 17 00:00:00 2001 From: Zack Buhman Date: Wed, 2 Jul 2025 20:55:11 -0500 Subject: [PATCH] display cover art and tracklist --- cover/cover1.data | 116 ++++++++++++ cover/cover1.data.h | 15 ++ cover/cover1.png | Bin 0 -> 9818 bytes reference_render.data | Bin 0 -> 2048 bytes reference_render.data.h | 15 ++ src/detect_emulator.cpp | 254 +++++++++++++++++++++++++++ src/detect_emulator.hpp | 3 + src/graphics.cpp | 2 +- src/interpreter.cpp | 38 ++-- src/interpreter.hpp | 4 +- src/main.cpp | 4 + src/playlist.cpp | 5 +- src/playlist.hpp | 3 + src/scene/tracker/channel_status.cpp | 4 +- src/scene/tracker/cover.cpp | 70 ++++++++ src/scene/tracker/cover.hpp | 7 + src/scene/tracker/metadata.cpp | 165 +++++++++++++++++ src/scene/tracker/metadata.hpp | 9 + src/scene/tracker/notes.cpp | 43 ++++- src/scene/tracker/scene.cpp | 110 ++++++++++-- src/scene/tracker/tracklist.cpp | 110 ++++++++++++ src/scene/tracker/tracklist.hpp | 7 + src/texture.cpp | 10 ++ src/texture.hpp | 9 +- xm_player.mk | 8 +- 25 files changed, 971 insertions(+), 40 deletions(-) create mode 100644 cover/cover1.data create mode 100644 cover/cover1.data.h create mode 100644 cover/cover1.png create mode 100644 reference_render.data create mode 100644 reference_render.data.h create mode 100644 src/detect_emulator.cpp create mode 100644 src/detect_emulator.hpp create mode 100644 src/scene/tracker/cover.cpp create mode 100644 src/scene/tracker/cover.hpp create mode 100644 src/scene/tracker/metadata.cpp create mode 100644 src/scene/tracker/metadata.hpp create mode 100644 src/scene/tracker/tracklist.cpp create mode 100644 src/scene/tracker/tracklist.hpp diff --git a/cover/cover1.data b/cover/cover1.data new file mode 100644 index 0000000..8a30f3d --- /dev/null +++ b/cover/cover1.data @@ -0,0 +1,116 @@ +пцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцџюїї?їпцџюџю?ї?ї?џ?џ?џпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцПопцПопцпцпцпцпцПоПоПояџю?їяпцпцпцпц?џї?џ?їпцпцџюпцпцПопцПоПоПоПоПопцпцпцпцПоПопцПопцпцпцпцпцпцпцџюпцпцпцпцпцџюџю?її?џ?ї?џ?џ?џ?џ?џ?ї?џ?џ?џ?џ?џ?џ?џпцпцпцпця?їя?їпцпцпцпцџю?їпцџю?џ?џ?џ?џ?џ?џ?џ?џ?џ?џ?ї?џ?џ?џ?џ?џ?џ?ї?џ?џџюпцїпц?џ?џ?џ?џїџю?їџюпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпц?џ?џ?џ?џ?їџю?їџц?џ?џ?џ?џ?їџюїпцпцпцпцпцпцпцпцпцпцпцпцпцпцПоПоПоПоПоПоПоПоПоПоŸЮПоПоПоПоПоŸЮПоŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮПоПоПоПоŸЮŸЮŸЮŸЮПоПоПоПоŸЮŸЮПоŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮОŸЮОООООŸЮŸЮŸЮŸЮООООŸЅŸЅŸЅŸЅŸЅŸЅŸЅŸЅОŸЅОŸЅŸЅŸЅŸЅŸЅŸЮŸЮŸЮŸЮŸЮОŸЮŸЮŸЮŸЮŸЮŸЮŸЮООООŸЅООŸЅŸЅŸЅŸЅООООŸЅŸЅОŸЅПоПопцПоПоПоПоПопцПопцПоПоПоПоПоŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮПоŸЮПоПоŸЮŸЮŸЮŸЮпцПоПоПоПоПоПоПоПоПоПоПоПоПоПоПоПоПоПоŸЮŸЮŸЮŸЮŸЮПоŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮОООООŸЮОŸЮООООООООООŸЅООООООООООŸЮŸЮŸЮŸЮООООŸЮŸЮŸЮŸЮŸЮОŸЮООООООŸЅОŸЅОООŸЅŸЅŸЅŸЅŸЅпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцџю?џџю?ї?џ?џ?џ?џпцїпцџю?ї?їїїпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпц?џ?ї?їџюџюпцпцпцїпцџюпцпцпцпцпцпцПопцПоПоПоПоПопцПопцпцПоПоПоПопцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцПопцПопцпцпцпцпцПопцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцџюїпцпцїџюпцпцпцпцпцџюџюїпцпцпцџюї?џї?џї?ї?џ?џ?її?џ?ї?џ?џ?џ?џ?џ?ї?џ?џпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцпцПоПоПопцпцџцпцпцпцпцпцџюпцїпцпцпцпцпцпцПопцПоПоПоПоПоПоПоПоПоПоПоПоПоПоПоПоПоПоПоПоŸЮПоПоПоПоŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮПоПоПоПоŸЮŸЮПоŸЮПоПоПоПоПоŸЮПоПоŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮОŸЮŸЮŸЮŸЮОООООŸЅОŸЅŸЅŸЅŸЅŸЅОŸЅООŸЅŸЅŸЅŸЅŸЮŸЮŸЮОООООŸЮОООООООООООŸЅŸЅОŸЅОООООŸЅООПоПоПоПоПоПоПоПоПоПоПоПоПоПоПоПоПоŸЮПоŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮОŸЮОПоПоПоПоПоŸЮŸЮŸЮПоŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮŸЮООООŸЮŸЮŸЮŸЮŸЮОŸЮŸЮОООООООООООООООООООООŸЅŸЅŸЅОООŸЅŸЅŸЅŸЅŸЅОООООООООООООООООŸЅŸЅŸЅŸЅŸЅŸЅŸЅŸЅŸЅŸЅŸЅŸЅŸЅŸЅŸЅŸЅ_ОŸЅ_ОŸЮŸЮŸЮŸЮŸЅ_ОŸЅ_ОŸЮЦ_ЦЦŸЮŸЮЦŸЮŸЮЦŸЮЦЦŸЮ_ЦЦŸЮЦŸЮŸЮŸЅ_ОŸЅ_О_ОЦ_ОЦŸЅ_ОŸЅ_О_ОЦ_ОЦ_Ц_Ц_Ц_ЦŸЮŸЮŸЮŸЮ_ЦЦЦŸЮŸЮЦŸЮЦŸЮПжŸЮŸжПжПжЦŸЮŸЮЦŸЮЦЦŸЮЦŸЮПжПжПЮŸЮПжПжЦЦЦЦŸЮ_Ц_Ц_Ц_ОЦŸЮ_ЦЦ_ЦЦŸЮЦŸЮЦ_ЦЦЦŸЮПжПжПжŸЮ_ЦЦЦ_ЦŸЮЦŸЮЦŸЮЦŸжŸжПжŸжЦŸЅ_ОŸЅ_О_ОЦ_ОЦŸЅ_ОŸЅ_О_ОЦ_О_ОЦŸЮЦŸЮŸЮЦЦЦŸЮŸЮŸЮŸЮŸЮŸЮŸЮ_ЦŸЅ_ОŸЅ_О_О_О_О_ОŸЅ_ОŸЅ_О_О_О_ОŸЮŸЮ_ЦЦ_ЦŸЮ_ЦŸЮŸЮЦ_ОЦ_О_ЦŸЮ_ОЦЮŸЮŸЮПЮПжПжПжПжЦПЮЦŸжПжПЮПжŸжПжПжПжПжЦ_О_Ц_ОЦ_ЦЦ_О_О_О_ОŸЮЦŸЮЦŸЮПжŸЮЦŸЮŸЮ_ЦЮ_ЦЦŸЮ_ЦЦЦ_ОЦ_О_ОŸЮŸЮŸЮŸЮ_ОŸЮŸЮŸЮQЬQЬQЬПжПжŸЮЦПж_ОПж_ОŸЮЦЦŸжЦ_ОŸжПж_О_О_ОПж_ОПж_ОПжПжПжПжПжПжПжПжПжПЮПжПжŸжПжПж_ОПжЦПж_О_О_ОПж_О_О_ОПжПжЦПжПжŸжПжПж_Ц_О_О_ОЎ_Оџ­_ОЦ_ОПжŸжПжŸжЦ_ОПжПжŸжЦŸЮЦЦŸЮЦŸЮЦ_О_О_О_ОŸЮЦŸЮЦПж_ОПжПжПжПжПжПжŸЮЦŸЮЦŸжПжŸЮŸЮЦŸЮЦŸЮŸЮЦŸЮЦПжПжПжПЮŸЮЦŸЮЦ_О_Ц_О_О_ОПџ_ОOд_О_ОПџЦOдАмOдАмПџЦПџЦ_О_О_ОџЅџ­џЅџЅџЅ_ОџЅ_О_ОџЅџЅџЅџЅАмАмOдАмПџ_ОПџ_•QЬQЬФФПџ_•Пџ_•_О_О_О_О_ОџЅ_ОџЅ_О_ОџЅџЅ_ОџЅџЅџЅџ­ŸЮџЅ_ОЦЦ_ОЦџЅ_ОџЅџ­_О_Ц_О_ОŸЮЦŸЮПж_О_О_О_ОПжПж_Ц_Ц_О_О_О_ОџЅџ­џЅџ­_О_О_О_ОџЅ_ОџЅ_О_О_О_О_О_О_О_О_О_О_О_О_О_О_О_О_О_О_О_Оџ­ŸЅ_ОŸЅ_О_ОŸЮ_ОŸЮŸЅ_ОŸЅ_О_ОŸЮ_ОŸЮŸЮ_О_О_ОЦ_ЦЦЦ_ОЦЦЦ_ОЦЦЦŸЅ_ОŸЅ_О_О_О_О_ОŸЅ_ОŸЅ_О_О_О_О_ЦЦЦЦЦЦЦЦЦЦЦЦЦЦЦЦЦŸЮ_О_О_О_ОЦ_ОŸЮЦ_ОЦŸЮŸЮŸЮŸЮQЬŸЮŸЮŸЮQЬQЬФQЬФQЬQЬQЬФФФФФЦŸЮЦŸЮŸЮQЬQЬQЬЦŸЮŸЮŸЮQЬяЛQЬяЛяЛФяЛяЛФФФФяЛяЛяЛяЛяЛФяЛяЛŸЅ_ОŸЅ_ОЦ_ЦЦЦŸЅ_ЦŸЅ_ОЦЦЦЦЦЦЦ_ЦŸЮŸЮŸЮŸЮ_ЦЦЦЦŸЮŸЮŸЮŸЮŸЅ_ОŸЅ_ОЦЦ_ОЦŸЅ_ОŸЅ_О_О_О_О_О_ЦЦЦŸЮŸЮŸЮŸЮŸЮ_ОŸЮ_ОQЬQЬQЬQЬяЛŸЮŸЮŸЮŸЮQЬяЛŸЮQЬŸЮŸЮŸЮQЬQЬQЬФФяЛяЛяЛяЛяЛяЛяЛO“QЬQЬФO“O“‹z‹z‹zQЬФQЬФФФФФQЬФQЬФФO“ФO“O“‹zO“‹zЬ‚‹zЬ‚Jj‹zЬ‚‹z‹z‹zJjЬ‚JjФФФФПџ_•Пџ_•ФФФФПџ_•Пџ_•џЅџЅ_•џЅџЅџЅџЅџЅџЅџЅџЅџЅџЅџЅџЅџЅФФФФПџ_•Пџ_•ФФФO“Пџ_•Пџ_•џЅџЅџЅџЅџЅџЅџЅџЅ_•џЅ_•_•џЅџЅџЅџЅџЅџ­џЅџЅ_О_О_О_ОџЅџЅџЅџЅ_О_О_О_О_О_О_О_Оџ­џЅЎџЅ_О_О_О?О?ОџЅџ­џЅџЅџЅџЅџЅ_О_ОџЅ?ОџЅџЅџЅџЅпЅ•џЅ•_Оџ­?ОпЅŸпЅ••џЅпЅпЅпЅ•••_•O“‹z‹z‹zПџ_•ПџКSЬ‚Jj‹zJjџ +Ь‚Пџ_•_•КS_•_•џЅ_•_•КSКS +КKкS_•КSкSЬ‚‹zЬ‚‹zЬ‚ПџПџ +‹z‹zЬ‚‹zПџSПџS +КK3КK;_8; + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t _binary_cover_cover1_data_start __asm("_binary_cover_cover1_data_start"); +extern uint32_t _binary_cover_cover1_data_end __asm("_binary_cover_cover1_data_end"); +extern uint32_t _binary_cover_cover1_data_size __asm("_binary_cover_cover1_data_size"); + +#ifdef __cplusplus +} +#endif diff --git a/cover/cover1.png b/cover/cover1.png new file mode 100644 index 0000000000000000000000000000000000000000..e3c156364f2d8eca494c1499bdbe2cb7ad85f87c GIT binary patch literal 9818 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 + +#ifdef __cplusplus +extern "C" { +#endif + +extern uint32_t _binary_reference_render_data_start __asm("_binary_reference_render_data_start"); +extern uint32_t _binary_reference_render_data_end __asm("_binary_reference_render_data_end"); +extern uint32_t _binary_reference_render_data_size __asm("_binary_reference_render_data_size"); + +#ifdef __cplusplus +} +#endif diff --git a/src/detect_emulator.cpp b/src/detect_emulator.cpp new file mode 100644 index 0000000..d125de5 --- /dev/null +++ b/src/detect_emulator.cpp @@ -0,0 +1,254 @@ +#include + +#include "memorymap.hpp" + +#include "holly/background.hpp" +#include "holly/core.hpp" +#include "holly/isp_tsp.hpp" +#include "holly/object_list_data.hpp" +#include "holly/region_array.hpp" +#include "holly/texture_memory_alloc9.hpp" + +#include "math/float_types.hpp" + +#include "reference_render.data.h" + +const struct opb_size opb_size = { .opaque = 0 + , .opaque_modifier = 8 * 4 + , .translucent = 0 + , .translucent_modifier = 0 + , .punch_through = 8 * 4 + }; + +static const int framebuffer_width = 32; +static const int framebuffer_height = 32; +static const int tile_width = framebuffer_width / 32; +static const int tile_height = framebuffer_height / 32; + +struct triangle_parameter_vertex { + float x; + float y; + float z; + uint32_t color1; + uint32_t color2; +}; + +struct triangle_parameter { + uint32_t isp_tsp_instruction_word; + uint32_t tsp_instruction_word_0; + uint32_t texture_control_word_0; + uint32_t tsp_instruction_word_1; + uint32_t texture_control_word_1; + triangle_parameter_vertex a; + triangle_parameter_vertex b; + triangle_parameter_vertex c; +}; + +struct modifier_volume_parameter_vertex { + float x; + float y; + float z; +}; + +struct modifier_volume_parameter { + uint32_t isp_tsp_instruction_word; + uint32_t pad1; + uint32_t pad2; + modifier_volume_parameter_vertex a; + modifier_volume_parameter_vertex b; + modifier_volume_parameter_vertex c; +}; + +template +struct object_pointer_block { + uint32_t pointer[N]; +}; +static_assert((sizeof (object_pointer_block<8>)) == 32); + +using vec2i = vec<2, int>; + +static const int opaque_modifier_start = 0; +static const int punch_through_start = (sizeof (triangle_parameter)); + +static volatile uint8_t * const object_list = (volatile uint8_t *)(&texture_memory32[texture_memory_alloc.object_list.start / 4]); +static volatile uint8_t * const isp_tsp_parameters = (volatile uint8_t *)(&texture_memory32[texture_memory_alloc.isp_tsp_parameters.start / 4]); + +static inline void transfer_object_list(volatile uint8_t * mem) +{ + auto blocks = reinterpret_cast *>(mem); + + { // opaque modifier + auto& block = blocks[0]; + block.pointer[0] = object_list_data::pointer_type::triangle_array + | object_list_data::triangle_array::number_of_triangles(0) + | object_list_data::triangle_array::skip(0) + | object_list_data::triangle_array::start(opaque_modifier_start / 4); + + block.pointer[1] = object_list_data::pointer_type::object_pointer_block_link + | object_list_data::object_pointer_block_link::end_of_list; + } + + { // punch through + auto& block = blocks[1]; + block.pointer[0] = object_list_data::pointer_type::triangle_array + | object_list_data::triangle_array::number_of_triangles(0) + | object_list_data::triangle_array::shadow + | object_list_data::triangle_array::skip(1) + | object_list_data::triangle_array::start(punch_through_start / 4); + + block.pointer[1] = object_list_data::pointer_type::object_pointer_block_link + | object_list_data::object_pointer_block_link::end_of_list; + } +} + +static inline void transfer_isp_tsp_parameters(volatile uint8_t * mem, + const vec3& ap, const vec2i& ac, + const vec3& bp, const vec2i& bc, + const vec3& cp, const vec2i& cc) +{ + auto params = reinterpret_cast(mem); + params->isp_tsp_instruction_word = isp_tsp_instruction_word::depth_compare_mode::greater + | isp_tsp_instruction_word::culling_mode::no_culling + | isp_tsp_instruction_word::gouraud_shading; + + params->tsp_instruction_word_0 = tsp_instruction_word::src_alpha_instr::one + | tsp_instruction_word::dst_alpha_instr::zero + | tsp_instruction_word::fog_control::no_fog; + + params->texture_control_word_0 = 0; + + params->tsp_instruction_word_1 = tsp_instruction_word::src_alpha_instr::one + | tsp_instruction_word::dst_alpha_instr::one + | tsp_instruction_word::fog_control::no_fog; + + params->texture_control_word_1 = 0; + + params->a.x = ap.x; + params->a.y = ap.y; + params->a.z = ap.z; + params->a.color1 = ac.x; + params->a.color2 = ac.y; + + params->b.x = bp.x; + params->b.y = bp.y; + params->b.z = bp.z; + params->b.color1 = bc.x; + params->b.color2 = bc.y; + + params->c.x = cp.x; + params->c.y = cp.y; + params->c.z = cp.z; + params->c.color1 = cc.x; + params->c.color2 = cc.y; +} + +static inline void transfer_modifier_volume_isp_tsp_parameters(volatile uint8_t * mem, + const vec3& ap, + const vec3& bp, + const vec3& cp) +{ + auto params = reinterpret_cast(mem); + params->isp_tsp_instruction_word = isp_tsp_instruction_word::volume_instruction::inside_last_polygon + | isp_tsp_instruction_word::culling_mode::no_culling; + + params->pad1 = 0; + params->pad2 = 0; + + params->a.x = ap.x; + params->a.y = ap.y; + params->a.z = ap.z; + + params->b.x = bp.x; + params->b.y = bp.y; + params->b.z = bp.z; + + params->c.x = cp.x; + params->c.y = cp.y; + params->c.z = cp.z; +} + +static void transfer_punch_through() +{ + vec3 ap = {18.2192f, 1.0f, 0.01f}; + vec3 bp = {27.8808f, 25.4219f, 0.01f}; + vec3 cp = { 1.9f, 21.5781f, 0.01f}; + + vec2i ac = {0x0000ff, 0xff0000}; + vec2i bc = {0x00ff00, 0x0000ff}; + vec2i cc = {0xff0000, 0x00ff00}; + + transfer_isp_tsp_parameters(&isp_tsp_parameters[punch_through_start], + ap, ac, + bp, bc, + cp, cc); +} + +static void transfer_opaque_modifier() +{ + vec3 ap = { 0.0f, -50.0f, 0.1f}; + vec3 bp = {100.0f, 0.0f, 0.1f}; + vec3 cp = { 0.0f, 50.0f, 0.1f}; + + transfer_modifier_volume_isp_tsp_parameters(&isp_tsp_parameters[opaque_modifier_start], + ap, + bp, + cp); +} + +static void init_texture_memory() +{ + region_array_multipass(tile_width, + tile_height, + &opb_size, + 1, + texture_memory_alloc.region_array.start, + texture_memory_alloc.object_list.start); + + background_parameter2(texture_memory_alloc.background[0].start, + 0xff000000); + + transfer_object_list(object_list); + + transfer_punch_through(); + + transfer_opaque_modifier(); +} + +template +static inline bool compare_equal(T a, T b, int length) +{ + for (int i = 0; i < length; i++) { + if (a[i] != b[i]) + return false; + } + return true; +} + +bool detect_emulator() +{ + init_texture_memory(); + + bool dither = true; + core_start_render2(texture_memory_alloc.region_array.start, + texture_memory_alloc.isp_tsp_parameters.start, + texture_memory_alloc.background[0].start, + texture_memory_alloc.framebuffer[0].start, + framebuffer_width, + dither); + core_wait_end_of_render_video(); + + uint32_t * a = (uint32_t *)&_binary_reference_render_data_start; + uint32_t * b = (uint32_t *)&texture_memory32[texture_memory_alloc.framebuffer[0].start / 4]; + int length = 32 * 32 * 2 / 4; + + int equal = compare_equal(a, b, length); + + for (uint32_t i = 0; i < (8 * 1024 * 1024 / 32); i++) { + asm volatile ("ocbp @%0" + : // output + : "r" (((uint32_t)texture_memory32) + (32 * i)) // input + : "memory"); + } + + return !equal; +} diff --git a/src/detect_emulator.hpp b/src/detect_emulator.hpp new file mode 100644 index 0000000..db3921c --- /dev/null +++ b/src/detect_emulator.hpp @@ -0,0 +1,3 @@ +#pragma once + +bool detect_emulator(); diff --git a/src/graphics.cpp b/src/graphics.cpp index d62911f..923697f 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -104,7 +104,7 @@ void graphics_init() framebuffer_init(); background_parameter2(texture_memory_alloc.background[1].start, - 0x35003a); + 0x110012); texture::transfer_texture_memory(); transfer_palettes(); diff --git a/src/interpreter.cpp b/src/interpreter.cpp index 6197eb7..cbaec2f 100644 --- a/src/interpreter.cpp +++ b/src/interpreter.cpp @@ -180,19 +180,30 @@ void rekey_note(int ch, const xm_pattern_format_t * pf) static inline void next_pattern() { - if (state.pattern_break >= 0) - state.next_line_index = state.pattern_break; + if (state.reverse) + state.pattern_order_table_index -= 1; else - state.next_line_index = 0; - state.pattern_break = -1; + state.pattern_order_table_index += 1; - state.pattern_order_table_index += 1; + if (state.pattern_order_table_index < 0) + state.pattern_order_table_index = state.xm.song_length - 1; if (state.pattern_order_table_index >= state.xm.song_length) state.pattern_order_table_index = 0; printf("pattern_order_table_index: %d\n", state.pattern_order_table_index); state.pattern_index = state.xm.header->pattern_order_table[state.pattern_order_table_index]; + if (state.pattern_break >= 0) { + state.next_line_index = state.pattern_break; + } else { + int line_count = state.xm.pattern_note_count[state.pattern_index] / state.xm.number_of_channels; + if (state.reverse) + state.next_line_index = line_count - 1; + else + state.next_line_index = 0; + } + state.pattern_break = -1; + printf("note_count: %d\n", state.xm.pattern_note_count[state.pattern_index]); } @@ -245,7 +256,7 @@ void interrupt() } wait(); aica_sound.channel[0].KYONEX(1); - if ((state.interrupt_clock % state.tick_rate) != 0) { + if ((state.interrupt_clock % state.current_tick_rate) != 0) { return; } for (int ch = 0; ch < 64; ch++) { @@ -260,7 +271,10 @@ void interrupt() if (note_tick) { // execute notes state.line_index = state.next_line_index; - state.next_line_index += 1; + if (state.reverse) + state.next_line_index -= 1; + else + state.next_line_index += 1; execute_line(state.line_index); } else { @@ -276,7 +290,10 @@ void interrupt() next_pattern(); } int note_index = state.next_line_index * state.xm.number_of_channels; - bool end_of_pattern = note_index >= state.xm.pattern_note_count[state.pattern_index]; + bool end_of_pattern + = note_index < 0 + || note_index >= state.xm.pattern_note_count[state.pattern_index]; + if (end_of_pattern) { printf("end_of_pattern\n"); next_pattern(); @@ -299,7 +316,8 @@ void init(float clock_multiplier) printf("default_tempo %d\n", default_tempo); printf("tick_rate %d\n", tick_rate); - state.tick_rate = tick_rate; + state.current_tick_rate = tick_rate; + state.default_tick_rate = tick_rate; state.ticks_per_line = default_tempo; state.tick = 0; state.line_index = 0; @@ -310,7 +328,7 @@ void init(float clock_multiplier) } state.paused = false; - printf("tick_rate %d\n", state.tick_rate); + printf("tick_rate %d\n", state.current_tick_rate); } void stop_sound() diff --git a/src/interpreter.hpp b/src/interpreter.hpp index f70d0cf..713c467 100644 --- a/src/interpreter.hpp +++ b/src/interpreter.hpp @@ -13,7 +13,8 @@ struct channel_state { struct interpreter_state { int interrupt_clock; - int tick_rate; + int current_tick_rate; + int default_tick_rate; int ticks_per_line; int tick; int pattern_order_table_index; @@ -22,6 +23,7 @@ struct interpreter_state { int line_index; int next_line_index; // within the current pattern bool paused; + bool reverse; int deferred_load_tick; int sample_data_ix; diff --git a/src/main.cpp b/src/main.cpp index 4f4936c..b80db6f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -9,6 +9,8 @@ #include "cursor.hpp" #include "input.hpp" +#include "detect_emulator.hpp" + void vbr100() { serial::string("vbr100\n"); @@ -93,6 +95,8 @@ void main() printf("main\n"); sound::init(); + //bool emulator = detect_emulator(); + //printf("emulator %d\n", emulator); graphics_init(); scene::scene_init(); input::state_init(); diff --git a/src/playlist.cpp b/src/playlist.cpp index 9ee1799..09cf652 100644 --- a/src/playlist.cpp +++ b/src/playlist.cpp @@ -13,17 +13,20 @@ namespace playlist { .playlist_ix = -1 }; - const static playlist_item playlist[] = { + const playlist_item playlist[] = { { "Shiroiii", + "CottageFantasy2", (int)&_binary_xm_CottageFantasy2_xm_start, }, { "Shiroiii", + "CloudsAhead6", (int)&_binary_xm_CloudsAhead6_xm_start, }, { "leon du star", + "milkypack01", (int)&_binary_xm_milkypack01_xm_start, }, }; diff --git a/src/playlist.hpp b/src/playlist.hpp index d8c413d..1b8bf97 100644 --- a/src/playlist.hpp +++ b/src/playlist.hpp @@ -3,6 +3,7 @@ namespace playlist { struct playlist_item { const char * const artist; + const char * const title; const int start; }; @@ -14,4 +15,6 @@ namespace playlist { void prev(); extern struct state state; + extern const playlist_item playlist[]; + extern const int playlist_length; } diff --git a/src/scene/tracker/channel_status.cpp b/src/scene/tracker/channel_status.cpp index 301fa97..aa11610 100644 --- a/src/scene/tracker/channel_status.cpp +++ b/src/scene/tracker/channel_status.cpp @@ -73,8 +73,8 @@ void draw(ta_multiwriter& multi, int x, int y) if (ch < state.xm.number_of_channels) { transfer_global_polygon_glyph(multi.pt); - int hori_center = inner_width / 2 - (glyph::hori_advance * (ch >= 10)) / 2; - transfer_integer(multi.pt, ch, + int hori_center = inner_width / 2 - (glyph::hori_advance * ((ch + 1) >= 10)) / 2; + transfer_integer(multi.pt, ch + 1, xi + hori_center, y + vert_center, 0.0001f, 0, 0, 0xa7a7a7); diff --git a/src/scene/tracker/cover.cpp b/src/scene/tracker/cover.cpp new file mode 100644 index 0000000..9191c77 --- /dev/null +++ b/src/scene/tracker/cover.cpp @@ -0,0 +1,70 @@ +#include "graphics_primitive.hpp" +#include "cover.hpp" +#include "ta_parameter.hpp" +#include "playlist.hpp" +#include "texture.hpp" + +namespace scene::tracker::cover { + + constexpr float texture_width = 1.0 / 128.0; + constexpr float texture_height = 1.0 / 128.0; + + constexpr inline vec3 transform_position(const vec2& p, + float x, float y, float z) + { + return { + x + p.x * 128, + y + p.y * 128, + z + }; + } + + constexpr inline vec2 transform_texture(const vec2& t) + { + return { + (0 + t.x * 72) * texture_width, + (0 + t.y * 72) * texture_height, + }; + } + + constexpr vec2 vtx[] = { + {0, 0}, + {1, 0}, + {1, 1}, + {0, 1}, + }; + + void draw(ta_multiwriter& multi, float x, float y) + { + uint32_t texture_size = tsp_instruction_word::texture_u_size::from_int(128) + | tsp_instruction_word::texture_v_size::from_int(128) + | tsp_instruction_word::dst_alpha_instr::zero; + + global_polygon_textured(multi.op, + para_control::list_type::opaque, + texture::offset::cover1, + texture_size, + texture_control_word::pixel_format::_565); + + float z = 1.0 / 10.0f; + + int base_color = 0xffffff; + + vec3 ap = transform_position(vtx[0], x, y, z); + vec3 bp = transform_position(vtx[1], x, y, z); + vec3 cp = transform_position(vtx[2], x, y, z); + vec3 dp = transform_position(vtx[3], x, y, z); + + vec2 at = transform_texture(vtx[0]); + vec2 bt = transform_texture(vtx[1]); + vec2 ct = transform_texture(vtx[2]); + vec2 dt = transform_texture(vtx[3]); + + quad_type_3(multi.op, + ap, at, + bp, bt, + cp, ct, + dp, dt, + base_color); + } +} diff --git a/src/scene/tracker/cover.hpp b/src/scene/tracker/cover.hpp new file mode 100644 index 0000000..8a76625 --- /dev/null +++ b/src/scene/tracker/cover.hpp @@ -0,0 +1,7 @@ +#pragma once + +#include "ta_multiwriter.hpp" + +namespace scene::tracker::cover { + void draw(ta_multiwriter& multi, float x, float y); +} diff --git a/src/scene/tracker/metadata.cpp b/src/scene/tracker/metadata.cpp new file mode 100644 index 0000000..7fedad0 --- /dev/null +++ b/src/scene/tracker/metadata.cpp @@ -0,0 +1,165 @@ +#include "graphics_primitive.hpp" +#include "metadata.hpp" +#include "interpreter.hpp" +#include "playlist.hpp" +#include "ta_parameter.hpp" + +namespace scene::tracker::metadata { + + void draw_labels(ta_parameter_writer& writer, float x, float y) + { + transfer_string(writer, "artist:", + x, y, 1.0 / 10.0, + 0xa7a7a7); + transfer_string(writer, "artist:", + x+1, y+1, 1.0 / 11.0, + 0x000000); + + y += glyph::vert_advance + 8; + + transfer_string(writer, " title:", + x, y, 1.0 / 10.0, + 0xa7a7a7); + transfer_string(writer, " title:", + x+1, y+1, 1.0 / 11.0, + 0x000000); + } + + void draw_values(ta_parameter_writer& writer, float x, float y) + { + using namespace interpreter; + + const char * artist = playlist::playlist[playlist::state.playlist_ix].artist; + + transfer_string(writer, artist, + x, y, 1.0 / 10.0, + 0xffffff); + + y += glyph::vert_advance + 8; + + const char * title = (const char *)state.xm.header->module_name; + + transfer_string(writer, title, + x, y, 1.0 / 10.0, + 0xffffff); + } + + const float border_width = 20 * glyph::hori_advance + 2 * 2; + const float border_height = 1 * glyph::vert_advance + 2 * 2; + + const float outer_top_depth = 1.0 / 20; + const int outer_top_color = 0x101414; + + const float inner_top_depth = 1.0 / 18; + const int inner_top_color = 0x1d2326; + + const float inner_middle_depth = 1.0 / 16; + const int inner_middle_color = 0x161b1d; + + const float inner_bottom_depth = 1.0 / 19; + const int inner_bottom_color = 0x060808; + + const float outer_bottom_depth = 1.0 / 21; + const float outer_bottom_color = 0x2a3536; + + void draw_value_border_outer_top(ta_parameter_writer& writer, float x, float y) + { + float x0 = x; + float x1 = x + border_width - 1; + float y0 = y; + float y1 = y + border_height - 1; + + quad_type_0(writer, + {x0, y0, outer_top_depth}, + {x1, y0, outer_top_depth}, + {x1, y1, outer_top_depth}, + {x0, y1, outer_top_depth}, + outer_top_color); + } + + void draw_value_border_inner_top(ta_parameter_writer& writer, float x, float y) + { + float x0 = x + 1; + float x1 = x + border_width - 2; + float y0 = y + 1; + float y1 = y + border_height - 2; + + quad_type_0(writer, + {x0, y0, inner_top_depth}, + {x1, y0, inner_top_depth}, + {x1, y1, inner_top_depth}, + {x0, y1, inner_top_depth}, + inner_top_color); + } + + void draw_value_border_inner_bottom(ta_parameter_writer& writer, float x, float y) + { + float x0 = x + 1; + float x1 = x + border_width - 1; + float y0 = y + 1; + float y1 = y + border_height - 1; + + quad_type_0(writer, + {x0, y0, inner_bottom_depth}, + {x1, y0, inner_bottom_depth}, + {x1, y1, inner_bottom_depth}, + {x0, y1, inner_bottom_depth}, + inner_bottom_color); + } + + void draw_value_border_inner_middle(ta_parameter_writer& writer, float x, float y) + { + float x0 = x + 2; + float x1 = x + border_width - 2; + float y0 = y + 2; + float y1 = y + border_height - 2; + + quad_type_0(writer, + {x0, y0, inner_middle_depth}, + {x1, y0, inner_middle_depth}, + {x1, y1, inner_middle_depth}, + {x0, y1, inner_middle_depth}, + inner_middle_color); + } + + void draw_value_border_outer_bottom(ta_parameter_writer& writer, float x, float y) + { + float x0 = x; + float x1 = x + border_width; + float y0 = y; + float y1 = y + border_height; + + quad_type_0(writer, + {x0, y0, outer_bottom_depth}, + {x1, y0, outer_bottom_depth}, + {x1, y1, outer_bottom_depth}, + {x0, y1, outer_bottom_depth}, + outer_bottom_color); + } + + void draw_border(ta_parameter_writer& writer, float x, float y) + { + draw_value_border_outer_top(writer, x, y); + draw_value_border_inner_top(writer, x, y); + draw_value_border_inner_bottom(writer, x, y); + draw_value_border_inner_middle(writer, x, y); + draw_value_border_outer_bottom(writer, x, y); + } + + void draw(ta_multiwriter& multi, float x, float y) + { + transfer_global_polygon_glyph(multi.pt); + + draw_labels(multi.pt, x + 5, y + 3); + + float x_values = x + 5 + glyph::hori_advance * 8; + draw_values(multi.pt, x_values + 3, y + 3); + + global_polygon_untextured(multi.op, + para_control::list_type::opaque, + tsp_instruction_word::dst_alpha_instr::zero); + + draw_border(multi.op, x_values, y); + draw_border(multi.op, x_values, y + glyph::vert_advance + 8); + } +} diff --git a/src/scene/tracker/metadata.hpp b/src/scene/tracker/metadata.hpp new file mode 100644 index 0000000..7d24c0e --- /dev/null +++ b/src/scene/tracker/metadata.hpp @@ -0,0 +1,9 @@ +#pragma once + +#include "ta_multiwriter.hpp" + +namespace scene::tracker::metadata { + + void draw(ta_multiwriter& multi, float x, float y); + +} diff --git a/src/scene/tracker/notes.cpp b/src/scene/tracker/notes.cpp index ea3d010..1caa70c 100644 --- a/src/scene/tracker/notes.cpp +++ b/src/scene/tracker/notes.cpp @@ -1,7 +1,7 @@ -#include "../../ta_parameter.hpp" +#include "ta_parameter.hpp" -#include "../../graphics_primitive.hpp" -#include "../../interpreter.hpp" +#include "graphics_primitive.hpp" +#include "interpreter.hpp" #include "notes.hpp" #include "framebuffer.hpp" @@ -45,7 +45,7 @@ const columns line_columns = { const int line_column_total_advance = line_columns.sum() * glyph::hori_advance; const int line_column_width = line_column_total_advance + (line_columns.count() + 1) + 3; -const int line_rows_half = 15; +const int line_rows_half = 14; const int line_rows = line_rows_half * 2 + 1; const int line_column_height = line_rows * glyph::vert_advance + 3 + 1; @@ -236,8 +236,6 @@ void draw_borders(ta_parameter_writer& writer, int x, int y) { using namespace interpreter; - int x0 = x; - //transfer_vertical_border(writer, x, y, line_column_height); x += 3 + glyph::hori_advance * 2 + 2; @@ -296,7 +294,7 @@ void draw_middle_line(ta_parameter_writer& writer, float x, float y) {x + middle_width, y + 0, depth / 2.0}, 0x404040); - y += middle_width; + y += middle_height; quad_type_0(writer, {x + 0, y + 0, depth / 2.0}, @@ -306,10 +304,41 @@ void draw_middle_line(ta_parameter_writer& writer, float x, float y) 0x202020); } +void draw_heading(ta_parameter_writer& writer, float x, float y) +{ + transfer_string(writer, "pattern:", + x, y, 1.0 / 10.0, + 0xa7a7a7); + + + transfer_integer(writer, interpreter::state.pattern_index, + x + glyph::hori_advance * 10, y, 1.0 / 10.0, + 2, ' ', + 0xffffff); + + transfer_string(writer, "( / )", + x + glyph::hori_advance * 15, y, 1.0 / 11.0, + 0xa7a7a7); + + transfer_integer(writer, interpreter::state.pattern_order_table_index, + x + glyph::hori_advance * 17, y, 1.0 / 10.0, + 2, ' ', + 0xffffff); + + transfer_integer(writer, interpreter::state.xm.song_length, + x + glyph::hori_advance * 22, y, 1.0 / 10.0, + 2, ' ', + 0xffffff); +} + void draw(ta_multiwriter& multi, float x, float y) { transfer_global_polygon_glyph(multi.pt); + draw_heading(multi.pt, x, y); + + y += glyph::vert_advance + 3; + draw_lines(multi.pt, x, y); global_polygon_untextured(multi.op, diff --git a/src/scene/tracker/scene.cpp b/src/scene/tracker/scene.cpp index e9a27f6..0935314 100644 --- a/src/scene/tracker/scene.cpp +++ b/src/scene/tracker/scene.cpp @@ -7,6 +7,7 @@ #include "notes.hpp" #include "channel_status.hpp" #include "texture.hpp" +#include "graphics_primitive.hpp" #include "widget/button_label.hpp" #include "widget/button_icon.hpp" #include "widget/left_aligned.hpp" @@ -14,9 +15,27 @@ #include "playlist.hpp" #include "interpreter.hpp" #include "icons.hpp" +#include "metadata.hpp" +#include "tracklist.hpp" +#include "cover.hpp" #include "cursor.hpp" +void play_click() +{ + using namespace interpreter; + printf("play\n"); + state.reverse = false; + state.current_tick_rate = state.default_tick_rate; + interpreter::unpause(); +} + +void pause_click() +{ + printf("pause\n"); + interpreter::pause(); +} + void prev_click() { printf("prev\n"); @@ -29,19 +48,48 @@ void next_click() playlist::next(); } +void rrr_click() +{ + using namespace interpreter; + printf("rr\n"); + if (state.reverse) + state.current_tick_rate = state.current_tick_rate * 22 / 23; + state.reverse = true; +} + +void rr_click() +{ + using namespace interpreter; + printf("rr\n"); + state.current_tick_rate = state.current_tick_rate * 23 / 22; +} + +void ff_click() +{ + using namespace interpreter; + printf("ff\n"); + state.current_tick_rate = state.current_tick_rate * 22 / 23; +} + +void fff_click() +{ + using namespace interpreter; + printf("fff\n"); + state.current_tick_rate = state.current_tick_rate / 2; +} + #define __length(c) ((sizeof (c)) / (sizeof (c[0]))) -//widget::button_label play_button(75, 60, "play", nullptr); -widget::button_icon play_button(75, 60, icons::play, nullptr); -widget::button_icon pause_button(75, 33, icons::pause, nullptr); +widget::button_icon play_button(75, 60, icons::play, play_click); +widget::button_icon pause_button(75, 33, icons::pause, pause_click); widget::button_icon prev_button(79, 30, icons::prev, prev_click); widget::button_icon next_button(79, 30, icons::next, next_click); -widget::button_icon rrr_button(39, 21, icons::rrr, nullptr); -widget::button_icon rr_button(39, 21, icons::rr, nullptr); -widget::button_icon ff_button(39, 21, icons::ff, nullptr); -widget::button_icon fff_button(39, 21, icons::fff, nullptr); +widget::button_icon rrr_button(39, 21, icons::rrr, rrr_click); +widget::button_icon rr_button(39, 21, icons::rr, rr_click); +widget::button_icon ff_button(39, 21, icons::ff, ff_click); +widget::button_icon fff_button(39, 21, icons::fff, fff_click); widget::widget * play_pause_children[] = { &play_button, @@ -90,13 +138,13 @@ namespace scene::tracker { const struct scene::scene scene = { .ta_alloc = ta_alloc_ctrl::pt_opb::_32x4byte | ta_alloc_ctrl::tm_opb::no_list - | ta_alloc_ctrl::t_opb::_8x4byte + | ta_alloc_ctrl::t_opb::no_list | ta_alloc_ctrl::om_opb::no_list | ta_alloc_ctrl::o_opb::_32x4byte, .opb_size = { .opaque = 32 * 4, .opaque_modifier = 0, - .translucent = 8 * 4, + .translucent = 0, .translucent_modifier = 0, .punch_through = 32 * 4 }, @@ -106,7 +154,8 @@ namespace scene::tracker { void init() { - top.freeze(5, 5); + float y = 8 + ((glyph::vert_advance + 5) * 2) + 8; + top.freeze(5, y); playlist::next(); } @@ -123,17 +172,56 @@ namespace scene::tracker { } } + void draw_button_labels(ta_parameter_writer& writer) + { + using namespace interpreter; + + transfer_global_polygon_glyph(writer); + + float ratio = (float)state.default_tick_rate / (float)state.current_tick_rate; + + float x = 100; + float y = 100; + transfer_string(writer, "speed: . x", + x, y, 1.0 / 10.0, + 0xa7a7a7); + if (state.reverse) + transfer_glyph(writer, '-', + x + glyph::hori_advance * 7, y, 1.0 / 10.0, + 0xffffff); + + transfer_integer(writer, (int)ratio, + x + glyph::hori_advance * 8, y, 1.0 / 10.0, + 2, ' ', + 0xffffff); + + float ratio_fraction = (ratio - ((int)ratio)) * 100; + + transfer_integer(writer, (int)ratio_fraction, + x + glyph::hori_advance * 11, y, 1.0 / 10.0, + 2, '0', + 0xffffff); + } + void transfer(ta_multiwriter& multi) { update(); + metadata::draw(multi, 5, 8); + top.draw(multi); + draw_button_labels(multi.pt); + + tracklist::draw(multi, top.width + 5, 5); + float y = top.y() + top.height + 5; channel_status::draw(multi, 5, y); - y += channel_status::height + 5; + cover::draw(multi, 480, 8); + + y += channel_status::height + 10; notes::draw(multi, 5, y); } diff --git a/src/scene/tracker/tracklist.cpp b/src/scene/tracker/tracklist.cpp new file mode 100644 index 0000000..f6fcddd --- /dev/null +++ b/src/scene/tracker/tracklist.cpp @@ -0,0 +1,110 @@ +#include "graphics_primitive.hpp" +#include "tracklist.hpp" +#include "ta_parameter.hpp" +#include "playlist.hpp" + +namespace scene::tracker::tracklist { + + const float width = glyph::hori_advance * 20 + 3 * 2; + const int line_rows_half = 5; + const int line_rows = line_rows_half * 2 + 1; + const float height = glyph::vert_advance * line_rows + 3 * 2; + + void draw_borders(ta_parameter_writer& writer, float x, float y) + { + transfer_horizontal_border(writer, x, y, width); + transfer_horizontal_border(writer, x, y + height - 3, width); + + transfer_vertical_border(writer, x, y, height); + transfer_vertical_border(writer, x + width - 3, y, height); + } + + void draw_track_names(ta_parameter_writer& writer, float x, float y) + { + for (int i = 0; i < line_rows; i++) { + int track_ix = playlist::state.playlist_ix - line_rows_half + i; + + if (track_ix >= 0 && track_ix < playlist::playlist_length) { + const char * title = playlist::playlist[track_ix].title; + transfer_string(writer, title, + x, y, 1.0 / 10.0, + 0xffffff); + } + y += glyph::vert_advance; + } + } + + void draw_middle_line(ta_parameter_writer& writer, float x, float y) + { + int middle_width = width; + int middle_height = glyph::vert_advance - 1; + + y += 2; + + y += glyph::vert_advance * (line_rows_half + 1); + + quad_type_0(writer, + {x + 0, y + 0, 1.0 / 20.0}, + {x + 0, y + 1, 1.0 / 20.0}, + {x + middle_width, y + 1, 1.0 / 20.0}, + {x + middle_width, y + 0, 1.0 / 20.0}, + 0x555555); + + y += 1; + + quad_type_0(writer, + {x + 0, y + 0, 1.0 / 20.0}, + {x + 0, y + middle_height, 1.0 / 20.0}, + {x + middle_width, y + middle_height, 1.0 / 20.0}, + {x + middle_width, y + 0, 1.0 / 20.0}, + 0x404040); + + y += middle_height; + + quad_type_0(writer, + {x + 0, y + 0, 1.0 / 20.0}, + {x + 0, y + 1, 1.0 / 20.0}, + {x + middle_width, y + 1, 1.0 / 20.0}, + {x + middle_width, y + 0, 1.0 / 20.0}, + 0x202020); + } + + void draw_heading(ta_parameter_writer& writer, float x, float y) + { + transfer_string(writer, "playlist:", + x, y, 1.0 / 10.0, + 0xa7a7a7); + + transfer_string(writer, "( / )", + x + glyph::hori_advance * 10, y, 1.0 / 11.0, + 0xa7a7a7); + + transfer_integer(writer, playlist::state.playlist_ix + 1, + x + glyph::hori_advance * (10 + 2), y, 1.0 / 10.0, + 2, ' ', + 0xffffff); + + transfer_integer(writer, playlist::playlist_length, + x + glyph::hori_advance * (10 + 7), y, 1.0 / 10.0, + 2, ' ', + 0xffffff); + } + + void draw(ta_multiwriter& multi, float x, float y) + { + transfer_global_polygon_glyph(multi.pt); + + draw_heading(multi.pt, x, y); + + draw_middle_line(multi.op, x, y + 3); + + global_polygon_untextured(multi.op, + para_control::list_type::opaque, + tsp_instruction_word::dst_alpha_instr::zero); + + float yi = y + glyph::vert_advance + 3; + draw_borders(multi.op, x, yi); + + draw_track_names(multi.pt, x + 3, yi + 3); + } +} diff --git a/src/scene/tracker/tracklist.hpp b/src/scene/tracker/tracklist.hpp new file mode 100644 index 0000000..fd5fe8a --- /dev/null +++ b/src/scene/tracker/tracklist.hpp @@ -0,0 +1,7 @@ +#pragma once + +#include "ta_multiwriter.hpp" + +namespace scene::tracker::tracklist { + void draw(ta_multiwriter& multi, float x, float y); +} diff --git a/src/texture.cpp b/src/texture.cpp index 14e9f2a..26a686c 100644 --- a/src/texture.cpp +++ b/src/texture.cpp @@ -9,6 +9,11 @@ #include "holly/texture_memory_alloc9.hpp" +#include "font/tandy1k.data.h" +#include "model/32bitlogo/colors.data.h" +#include "font/icons.data.h" +#include "cover/cover1.data.h" + namespace texture { struct texture textures[] = { @@ -26,6 +31,11 @@ namespace texture { .start = reinterpret_cast(&_binary_font_icons_data_start), .size = reinterpret_cast(&_binary_font_icons_data_size), .offset = offset::icons, + }, + { + .start = reinterpret_cast(&_binary_cover_cover1_data_start), + .size = reinterpret_cast(&_binary_cover_cover1_data_size), + .offset = offset::cover1, } }; diff --git a/src/texture.hpp b/src/texture.hpp index 6a322ba..6814cb9 100644 --- a/src/texture.hpp +++ b/src/texture.hpp @@ -1,9 +1,5 @@ #pragma once -#include "font/tandy1k.data.h" -#include "model/32bitlogo/colors.data.h" -#include "font/icons.data.h" - namespace texture { struct texture { void * start; @@ -13,8 +9,9 @@ namespace texture { namespace offset { constexpr int tandy1k = 0; // 16384 - constexpr int logo = 16384; // 128 * 3 - constexpr int icons = 16384 + (128 * 3); // 2048 + constexpr int logo = tandy1k + 16384; // 128 * 3 + constexpr int icons = logo + (128 * 3); // 2048 + constexpr int cover1 = icons + 2048; }; extern struct texture textures[]; diff --git a/xm_player.mk b/xm_player.mk index a543324..7249869 100644 --- a/xm_player.mk +++ b/xm_player.mk @@ -6,7 +6,9 @@ XM_OBJ = \ TEXTURE_OBJ = \ font/tandy1k.data.o \ font/icons.data.o \ - model/32bitlogo/colors.data.o + model/32bitlogo/colors.data.o \ + cover/cover1.data.o \ + reference_render.data.o PCM_OBJ = \ pcm/start3.adpcm.o @@ -25,6 +27,7 @@ XM_PLAYER_OBJ = \ $(LIB)/printf/parse.o \ src/icons.o \ src/cursor.o \ + src/detect_emulator.o \ src/framebuffer.o \ src/graphics.o \ src/graphics_primitive.o \ @@ -37,8 +40,11 @@ XM_PLAYER_OBJ = \ src/scene/logo/sound.o \ src/scene/scene.o \ src/scene/tracker/channel_status.o \ + src/scene/tracker/cover.o \ src/scene/tracker/notes.o \ src/scene/tracker/scene.o \ + src/scene/tracker/metadata.o \ + src/scene/tracker/tracklist.o \ src/sound.o \ src/texture.o \ src/widget/button.o \