scene: add emulator

This commit is contained in:
Zack Buhman 2025-07-03 14:02:40 -05:00
parent e0d2ae26b3
commit c3c5c56edb
27 changed files with 541 additions and 24 deletions

BIN
font/ter-u24n-test.data Normal file

Binary file not shown.

BIN
font/ter-u24n.data Normal file

Binary file not shown.

15
font/ter-u24n.data.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
extern uint32_t _binary_font_ter_u24n_data_start __asm("_binary_font_ter_u24n_data_start");
extern uint32_t _binary_font_ter_u24n_data_end __asm("_binary_font_ter_u24n_data_end");
extern uint32_t _binary_font_ter_u24n_data_size __asm("_binary_font_ter_u24n_data_size");
#ifdef __cplusplus
}
#endif

BIN
font/ter-u32n-test.data Normal file

Binary file not shown.

BIN
font/ter-u32n.data Normal file

Binary file not shown.

15
font/ter-u32n.data.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
extern uint32_t _binary_font_ter_u32n_data_start __asm("_binary_font_ter_u32n_data_start");
extern uint32_t _binary_font_ter_u32n_data_end __asm("_binary_font_ter_u32n_data_end");
extern uint32_t _binary_font_ter_u32n_data_size __asm("_binary_font_ter_u32n_data_size");
#ifdef __cplusplus
}
#endif

BIN
pcm/dk.adpcm Normal file

Binary file not shown.

15
pcm/dk.adpcm.h Normal file
View File

@ -0,0 +1,15 @@
#pragma once
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
extern uint32_t _binary_pcm_dk_adpcm_start __asm("_binary_pcm_dk_adpcm_start");
extern uint32_t _binary_pcm_dk_adpcm_end __asm("_binary_pcm_dk_adpcm_end");
extern uint32_t _binary_pcm_dk_adpcm_size __asm("_binary_pcm_dk_adpcm_size");
#ifdef __cplusplus
}
#endif

BIN
pcm/dk.pcm Normal file

Binary file not shown.

112
src/font.cpp Normal file
View File

@ -0,0 +1,112 @@
#include "holly/isp_tsp.hpp"
#include "texture.hpp"
#include "ta_parameter.hpp"
#include "font.hpp"
#include "math/float_types.hpp"
namespace font {
const font fonts[] = {
[font::ter_u24n] = {
.texture_size = tsp_instruction_word::texture_u_size::from_int(256)
| tsp_instruction_word::texture_v_size::from_int(128),
.texture_offset = texture::offset::ter_u24n,
.texture_width = 256,
.texture_height = 128,
.hori_advance = 12,
.width = 12,
.height = 24,
.row_stride = 21,
},
[font::ter_u32n] = {
.texture_size = tsp_instruction_word::texture_u_size::from_int(256)
| tsp_instruction_word::texture_v_size::from_int(256),
.texture_offset = texture::offset::ter_u32n,
.texture_width = 256,
.texture_height = 256,
.hori_advance = 16,
.width = 16,
.height = 32,
.row_stride = 16,
}
};
void draw_glyph_global(ta_parameter_writer& writer, const font& face)
{
global_polygon_textured(writer,
para_control::list_type::punch_through,
face.texture_offset,
face.texture_size | tsp_instruction_word::dst_alpha_instr::inverse_src_alpha,
texture_control_word::pixel_format::_4bpp_palette);
}
static inline vec2 transform_glyph_texture(const font& face, const vec2& t, int char_code)
{
int row = char_code / face.row_stride;
int col = char_code % face.row_stride;
return {
(float)(col * face.width + t.x * face.width) / (float)(face.texture_width),
(float)(row * face.height + t.y * face.height) / (float)(face.texture_height),
};
}
static inline vec3 transform_glyph_position(const font& face, const vec2& p, float x, float y, float z)
{
return {
p.x * face.width + x,
p.y * face.height + y,
z
};
}
void draw_glyph(ta_parameter_writer& writer,
const font& face,
int c,
float x, float y, float z,
int base_color)
{
static const vec2 vtx[] = {
{ 0, 0 },
{ 1, 0 },
{ 1, 1 },
{ 0, 1 },
};
vec3 ap = transform_glyph_position(face, vtx[0], x, y, z);
vec3 bp = transform_glyph_position(face, vtx[1], x, y, z);
vec3 cp = transform_glyph_position(face, vtx[2], x, y, z);
vec3 dp = transform_glyph_position(face, vtx[3], x, y, z);
vec2 at = transform_glyph_texture(face, vtx[0], c);
vec2 bt = transform_glyph_texture(face, vtx[1], c);
vec2 ct = transform_glyph_texture(face, vtx[2], c);
vec2 dt = transform_glyph_texture(face, vtx[3], c);
quad_type_3(writer,
ap, at,
bp, bt,
cp, ct,
dp, dt,
base_color);
}
void draw_string(ta_parameter_writer& writer,
const font& face,
const char * s,
float x, float y, float z,
int base_color)
{
const uint8_t * u8 = (const uint8_t *)s;
int len = 0;
while (*u8) {
len += 1;
int c = *u8++;
draw_glyph(writer, face, c - 32, x, y, z, base_color);
x += face.hori_advance;
}
}
}

40
src/font.hpp Normal file
View File

@ -0,0 +1,40 @@
#pragma once
#include <stdint.h>
#include "holly/ta_parameter.hpp"
namespace font {
struct font {
uint32_t texture_size;
uint32_t texture_offset;
int16_t texture_width;
int16_t texture_height;
int8_t hori_advance;
int8_t width;
int8_t height;
int8_t row_stride;
enum font_type {
ter_u24n,
ter_u32n,
};
};
extern const font fonts[];
void draw_glyph_global(ta_parameter_writer& writer, const font& face);
void draw_glyph(ta_parameter_writer& writer,
const font& face,
int c,
float x, float y, float z,
int base_color);
void draw_string(ta_parameter_writer& writer,
const font& face,
const char * s,
float x, float y, float z,
int base_color);
}

View File

@ -145,7 +145,10 @@ void graphics_event(ta_multiwriter& multi)
multi.op.offset = 0;
multi.pt.offset = 0;
graphics_cursor(multi);
if (scene::current_scene == &scene::scenes[scene::id::tracker]) {
graphics_cursor(multi);
}
assert(scene::current_scene->transfer != nullptr);
scene::current_scene->transfer(multi);
while (ta_in_use);

View File

@ -9,7 +9,7 @@ struct vertex {
vec2 t;
};
const vertex quad_vertices[] = {
static const vertex quad_vertices[] = {
{ { 0, 0 }, {0, 0} },
{ { 1, 0 }, {1, 0} },
{ { 1, 1 }, {1, 1} },

View File

@ -6,6 +6,7 @@
#include "sound.hpp"
#include "scene/scene.hpp"
#include "scene/logo/sound.hpp"
#include "scene/emulator/sound.hpp"
#include "cursor.hpp"
#include "input.hpp"
@ -42,13 +43,21 @@ void vbr600()
graphics_interrupt(istnrm);
} else if (sh7091.CCN.EXPEVT == 0 && sh7091.CCN.INTEVT == 0x360) { // AICA
wait(); aica_sound.common.mcire = (1 << 6); // interrupt timer A
wait(); aica_sound.common.tactl_tima =
aica::tactl_tima::TACTL(0) // increment once every sample
| aica::tactl_tima::TIMA(0xfffd) // interrupt after 3 counts
;
//scene::logo::sound::interrupt();
interpreter::interrupt();
if (scene::current_scene == &scene::scenes[scene::id::tracker]) {
wait(); aica_sound.common.tactl_tima
= aica::tactl_tima::TACTL(0) // increment once every sample
| aica::tactl_tima::TIMA(0xfffd) // interrupt after 3 counts
;
} else {
wait(); aica_sound.common.tactl_tima
= aica::tactl_tima::TACTL(0) // increment once every sample
| aica::tactl_tima::TIMA(0xffff) // interrupt after 1 counts
;
}
assert(scene::current_scene->interrupt != nullptr);
scene::current_scene->interrupt();
} else {
serial::string("vbr600\n");
interrupt_exception();
@ -98,7 +107,7 @@ void main()
//bool emulator = detect_emulator();
//printf("emulator %d\n", emulator);
graphics_init();
scene::scene_init();
scene::scene_init(scene::id::tracker);
input::state_init();
cursor::init();
@ -127,5 +136,7 @@ void main()
input::state_update(send_buf, recv_buf);
graphics_event(multi);
scene::transition();
}
}

View File

@ -0,0 +1,119 @@
#include "holly/background.hpp"
#include "holly/holly.hpp"
#include "scene/emulator/scene.hpp"
#include "holly/ta_bits.hpp"
#include "holly/isp_tsp.hpp"
#include "ta_parameter.hpp"
#include "framebuffer.hpp"
#include "font.hpp"
#include "scene/emulator/sound.hpp"
namespace scene::emulator {
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::no_list
| ta_alloc_ctrl::om_opb::no_list
| ta_alloc_ctrl::o_opb::_32x4byte,
.opb_size = {
.opaque = 32 * 4,
.opaque_modifier = 0,
.translucent = 0,
.translucent_modifier = 0,
.punch_through = 32 * 4
},
.transfer = transfer,
.interrupt = sound::interrupt,
.init = init,
.done = done
};
static float intensity = 0.0;
void draw_title(ta_parameter_writer& writer, int color)
{
const font::font& face = font::fonts[font::font::ter_u32n];
draw_glyph_global(writer, face);
int h_center = framebuffer.px_width / 2 - (30 * face.width) / 2;
draw_string(writer, face, "Counterfeit Dreamcast Detected", h_center, 35, 0.1, color << 16);
}
void draw_paragraph(ta_parameter_writer& writer, int color)
{
const char * paragraph[] = {
"Your counterfeit Dreamcast failed a CORE",
"rasterization test.",
"",
"Dreamcast emulator behavior is highly divergent",
"from a genuine Sega Dreamcast. Some emulator",
"authors deliberately choose to forgo accuracy,",
"and instead are developing a distinct and",
"unrelated fantasy-platform.",
"",
"This program only supports genuine Sega",
"Dreamcasts. Other fantasy-platforms and emulators",
"are not supported."
};
const int paragraph_length = (sizeof (paragraph)) / (sizeof (paragraph[0]));
const font::font& face = font::fonts[font::font::ter_u24n];
draw_glyph_global(writer, face);
float x = 26;
float y = 80;
int base_color = (color << 16) | (color << 8) | (color << 0);
for (int i = 0; i < paragraph_length; i++) {
const char * s = paragraph[i];
draw_string(writer, face, s, x, y, 0.1, base_color);
y += face.height;
}
}
void transfer(ta_multiwriter& multi)
{
using namespace font;
if (intensity < 1.0)
intensity += 0.005;
int color = (int)(255.0 * intensity);
if (color > 255)
color = 255;
draw_title(multi.pt, color);
draw_paragraph(multi.pt, color);
global_polygon_untextured(multi.op,
para_control::list_type::opaque,
tsp_instruction_word::dst_alpha_instr::zero);
quad_type_0(multi.op,
{0, 0, 0.1},
{0, 0, 0.1},
{0, 0, 0.1},
{0, 0, 0.1},
0x0);
}
void init()
{
intensity = 0;
background_parameter2(texture_memory_alloc.background[1].start,
0);
holly.VO_BORDER_COL = 0;
::scene::emulator::sound::init();
}
int done()
{
return -1;
}
}

View File

@ -0,0 +1,15 @@
#pragma once
#include "ta_multiwriter.hpp"
#include "scene/scene.hpp"
namespace scene::emulator {
extern const struct scene::scene scene;
void transfer(ta_multiwriter& multi);
void init();
int done();
}

View File

@ -0,0 +1,82 @@
#include "aica/aica.hpp"
#include "../../sound.hpp"
#include "scene/logo/sound.hpp"
#include "pcm/dk.adpcm.h"
#include "printf/printf.h"
namespace scene::emulator::sound {
const static void * start = reinterpret_cast<void *>(&_binary_pcm_dk_adpcm_start);
const static int size = reinterpret_cast<int>(&_binary_pcm_dk_adpcm_size);
const static int sample_count = size * 2;
const static int loop_length = 65528;
const static int segment_count = sample_count / loop_length;
const static int last_loop = (sample_count % loop_length) & (~0b11);
void init()
{
printf("init\n");
::sound::transfer(start, size);
wait(); aica_sound.common.afsel_mslc_mobuf
= aica::afsel_mslc_mobuf::AFSEL(0)
| aica::afsel_mslc_mobuf::MSLC(0);
wait(); aica_sound.channel[0].LPCTL(1);
wait(); aica_sound.channel[0].PCMS(2); // adpcm
wait(); aica_sound.channel[0].LSA(0);
wait(); aica_sound.channel[0].LEA(loop_length);
wait(); aica_sound.channel[0].D2R(0x0);
wait(); aica_sound.channel[0].D1R(0x0);
wait(); aica_sound.channel[0].RR(0x1f);
wait(); aica_sound.channel[0].AR(0x1f);
wait(); aica_sound.channel[0].OCT(-1);
wait(); aica_sound.channel[0].FNS(0);
wait(); aica_sound.channel[0].DISDL(0xf);
wait(); aica_sound.channel[0].DIPAN(0x0);
wait(); aica_sound.channel[0].KYONB(0);
wait(); aica_sound.channel[0].KYONEX(1);
}
void interrupt()
{
static int segment = 0;
static bool last = false;
wait();
int lp_sgc_eg = aica_sound.common.lp_sgc_eg;
if (aica::lp_sgc_eg::SGC(lp_sgc_eg) == 3) { // release
if (segment != 0)
return;
printf("start\n");
wait(); aica_sound.channel[0].SA(0);
wait(); aica_sound.channel[0].KYONB(1);
wait(); aica_sound.channel[0].KYONEX(1);
return;
}
if (aica::lp_sgc_eg::LP(lp_sgc_eg)) {
segment += 1;
if (segment >= segment_count) {
if (last || last_loop == 0) {
wait(); aica_sound.channel[0].KYONB(0);
wait(); aica_sound.channel[0].KYONEX(1);
return;
} else {
printf("last loop\n", segment);
last = true;
wait(); aica_sound.channel[0].LEA(last_loop);
}
}
printf("loop %d\n", segment);
int sa = 0 + (loop_length / 2) * segment;
wait(); aica_sound.channel[0].SA(sa);
}
}
}

View File

@ -0,0 +1,8 @@
#pragma once
namespace scene::emulator::sound {
void init();
void interrupt();
}

View File

@ -1,3 +1,6 @@
#include "holly/background.hpp"
#include "holly/holly.hpp"
#include "math/float_types.hpp"
#include "math/transform.hpp"
@ -144,7 +147,9 @@ namespace scene::logo {
.punch_through = 0
},
.transfer = transfer,
.init = init
.interrupt = sound::interrupt,
.init = init,
.done = done
};
static int tick = 0;
@ -257,6 +262,21 @@ namespace scene::logo {
void init()
{
background_parameter2(texture_memory_alloc.background[1].start,
0xc0bebc);
holly.VO_BORDER_COL = 0xc0bebc;
::scene::logo::sound::init();
}
int done()
{
if (tick >= (20.000 * 60)) {
int scene_id = ::scene::id::tracker;
printf("scene transition to tracker %d\n", scene_id);
return scene_id;
}
return -1;
}
}

View File

@ -10,5 +10,7 @@ namespace scene::logo {
void init();
int done();
extern const struct scene::scene scene;
}

View File

@ -3,17 +3,20 @@
#include "scene/scene.hpp"
#include "scene/tracker/scene.hpp"
#include "scene/logo/scene.hpp"
static const scene::scene scenes[] = {
scene::tracker::scene,
scene::logo::scene,
};
#include "scene/emulator/scene.hpp"
namespace scene {
const scene * current_scene = &scenes[0];
const scene scenes[] = {
[id::tracker] = tracker::scene,
[id::logo] = logo::scene,
[id::emulator] = emulator::scene,
};
void scene_init()
const scene * current_scene = nullptr;
void scene_init(int scene_id)
{
current_scene = &scenes[scene_id];
graphics_scene_init(&current_scene->opb_size);
printf("scene init\n");
@ -22,4 +25,13 @@ namespace scene {
current_scene->init();
}
}
void transition()
{
assert(current_scene->done != nullptr);
int scene_id = current_scene->done();
if (scene_id >= 0) {
scene_init(scene_id);
}
}
}

View File

@ -4,15 +4,28 @@
#include "ta_multiwriter.hpp"
namespace scene {
namespace id {
enum scene_type {
tracker,
logo,
emulator
};
}
struct scene {
const uint32_t ta_alloc;
const struct opb_size opb_size;
void (* const transfer)(ta_multiwriter& multi);
void (* const interrupt)();
void (* const init)();
int (* const done)();
};
extern const scene scenes[];
extern const scene * current_scene;
void scene_init();
void scene_init(int scene_id);
void transition();
}

View File

@ -1,3 +1,5 @@
#include "holly/background.hpp"
#include "holly/holly.hpp"
#include "holly/ta_bits.hpp"
#include "ta_parameter.hpp"
@ -149,11 +151,17 @@ namespace scene::tracker {
.punch_through = 32 * 4
},
.transfer = transfer,
.interrupt = interpreter::interrupt,
.init = init,
.done = done,
};
void init()
{
background_parameter2(texture_memory_alloc.background[1].start,
0x110012);
holly.VO_BORDER_COL = 0x110012;
float y = 8 + ((glyph::vert_advance + 5) * 2) + 8;
top.freeze(5, y);
playlist::next();
@ -225,4 +233,9 @@ namespace scene::tracker {
notes::draw(multi, 5, y);
}
int done()
{
return -1;
}
}

View File

@ -10,5 +10,7 @@ namespace scene::tracker {
void init();
int done();
extern const struct scene::scene scene;
}

View File

@ -13,6 +13,8 @@
#include "model/32bitlogo/colors.data.h"
#include "font/icons.data.h"
#include "cover/cover1.data.h"
#include "font/ter-u24n.data.h"
#include "font/ter-u32n.data.h"
namespace texture {
@ -32,6 +34,16 @@ namespace texture {
.size = reinterpret_cast<int>(&_binary_font_icons_data_size),
.offset = offset::icons,
},
{
.start = reinterpret_cast<void *>(&_binary_font_ter_u24n_data_start),
.size = reinterpret_cast<int>(&_binary_font_ter_u24n_data_size),
.offset = offset::ter_u24n,
},
{
.start = reinterpret_cast<void *>(&_binary_font_ter_u32n_data_start),
.size = reinterpret_cast<int>(&_binary_font_ter_u32n_data_size),
.offset = offset::ter_u32n,
},
{
.start = reinterpret_cast<void *>(&_binary_cover_cover1_data_start),
.size = reinterpret_cast<int>(&_binary_cover_cover1_data_size),

View File

@ -8,10 +8,12 @@ namespace texture {
};
namespace offset {
constexpr int tandy1k = 0; // 16384
constexpr int logo = tandy1k + 16384; // 128 * 3
constexpr int icons = logo + (128 * 3); // 2048
constexpr int cover1 = icons + 2048;
constexpr int tandy1k = 0 ; // 16384
constexpr int logo = tandy1k + 16384; // 384
constexpr int icons = logo + 384; // 2048
constexpr int ter_u24n = icons + 2048; // 16384
constexpr int ter_u32n = ter_u24n + 16384; // 32768
constexpr int cover1 = ter_u32n + 32768; // 32768
};
extern struct texture textures[];

View File

@ -8,10 +8,13 @@ TEXTURE_OBJ = \
font/icons.data.o \
model/32bitlogo/colors.data.o \
cover/cover1.data.o \
reference_render.data.o
reference_render.data.o \
font/ter-u24n.data.o \
font/ter-u32n.data.o
PCM_OBJ = \
pcm/start3.adpcm.o
pcm/start3.adpcm.o \
pcm/dk.adpcm.o
XM_PLAYER_OBJ = \
$(LIB)/holly/core.o \
@ -25,6 +28,7 @@ XM_PLAYER_OBJ = \
$(LIB)/printf/printf.o \
$(LIB)/printf/unparse.o \
$(LIB)/printf/parse.o \
src/font.o \
src/icons.o \
src/cursor.o \
src/detect_emulator.o \
@ -38,6 +42,8 @@ XM_PLAYER_OBJ = \
src/playlist.o \
src/scene/logo/scene.o \
src/scene/logo/sound.o \
src/scene/emulator/scene.o \
src/scene/emulator/sound.o \
src/scene/scene.o \
src/scene/tracker/channel_status.o \
src/scene/tracker/cover.o \