24constexpr float kPi = 3.14159265358979323846f;
25constexpr float kTwoPi = kPi * 2.f;
26constexpr int kGenRate = 22050;
28void writeS16(std::vector<uint8_t> &pcm,
int sampleIndex,
float sample) {
29 if (sample > 1.f) sample = 1.f;
30 if (sample < -1.f) sample = -1.f;
31 const int16_t
v =
static_cast<int16_t
>(sample * 32767.f);
32 const size_t off =
static_cast<size_t>(sampleIndex) * 2u;
33 if (off + 1 >= pcm.size())
return;
34 pcm[off] =
static_cast<uint8_t
>(
v & 0xff);
35 pcm[off + 1] =
static_cast<uint8_t
>((
v >> 8) & 0xff);
38float noteFreq(
int semitoneFromA4) {
39 return 440.f * std::pow(2.f, semitoneFromA4 / 12.f);
42sound::SoundData *makeMusic() {
43 const int samples = kGenRate * 4;
44 std::vector<uint8_t> pcm(
static_cast<size_t>(samples) * 2u, 0);
45 const int pattern[] = {-12, -9, -5, -2, 0, -2, -5, -9};
46 const int beatSamples = kGenRate / 4;
47 for (
int i = 0; i < samples; ++i) {
48 const int beat = (i / beatSamples) % 8;
49 const float freq = noteFreq(pattern[beat]);
50 const float t =
static_cast<float>(i) /
static_cast<float>(kGenRate);
51 const float phase = t * freq;
52 float s = (std::fmod(phase, 1.f) < 0.5f) ? 0.18f : -0.18f;
53 if (beat == 0 || beat == 4) {
54 const float bf = noteFreq(pattern[0] - 12);
55 s += 0.12f * std::sin(t * bf * 6.2831853f);
57 const float local =
static_cast<float>(i % beatSamples) /
static_cast<float>(beatSamples);
58 const float env = (local < 0.08f) ? (local / 0.08f) : (1.f - (local - 0.08f) * 0.35f);
59 writeS16(pcm, i,
s * std::max(0.05f, env));
61 return new sound::SoundData(std::move(pcm), kGenRate, 16, 1);
64sound::SoundData *makeShoot() {
65 const int samples =
static_cast<int>(kGenRate * 0.12f);
66 std::vector<uint8_t> pcm(
static_cast<size_t>(samples) * 2u, 0);
67 for (
int i = 0; i < samples; ++i) {
68 const float t =
static_cast<float>(i) /
static_cast<float>(kGenRate);
69 const float env = 1.f - t / 0.12f;
70 const float freq = 880.f + 1200.f * env;
71 writeS16(pcm, i, env * 0.35f * std::sin(t * freq * 6.2831853f));
73 return new sound::SoundData(std::move(pcm), kGenRate, 16, 1);
76sound::SoundData *makeExplode() {
77 const int samples =
static_cast<int>(kGenRate * 0.35f);
78 std::vector<uint8_t> pcm(
static_cast<size_t>(samples) * 2u, 0);
79 uint32_t rng = 0xC0FFEEu;
80 for (
int i = 0; i < samples; ++i) {
81 rng = rng * 1664525u + 1013904223u;
82 const float noise = (
static_cast<float>(rng & 0xffffu) / 32768.f) - 1.f;
83 const float t =
static_cast<float>(i) /
static_cast<float>(kGenRate);
84 const float env = std::exp(-t * 8.f);
85 const float boom = std::sin(t * 90.f * 6.2831853f) * std::exp(-t * 6.f);
86 writeS16(pcm, i, env * (0.45f * noise + 0.35f * boom));
88 return new sound::SoundData(std::move(pcm), kGenRate, 16, 1);
91sound::SoundData *makeHit() {
92 const int samples =
static_cast<int>(kGenRate * 0.08f);
93 std::vector<uint8_t> pcm(
static_cast<size_t>(samples) * 2u, 0);
94 for (
int i = 0; i < samples; ++i) {
95 const float t =
static_cast<float>(i) /
static_cast<float>(kGenRate);
96 const float env = 1.f - t / 0.08f;
97 writeS16(pcm, i, env * 0.3f * std::sin(t * 220.f * 6.2831853f));
99 return new sound::SoundData(std::move(pcm), kGenRate, 16, 1);
102float hash3(
int x,
int y,
int z) {
103 uint32_t
n = uint32_t(
x) * 374761393u + uint32_t(
y) * 668265263u + uint32_t(
z) * 2246822519u;
104 n = (
n ^ (
n >> 13u)) * 1274126177u;
105 return float(
n & 0xffffu) / 65535.f;
108float valueNoise3(
float x,
float y,
float z) {
109 const int x0 = int(std::floor(
x));
110 const int y0 = int(std::floor(
y));
111 const int z0 = int(std::floor(
z));
112 const float fx =
x - float(x0);
113 const float fy =
y - float(y0);
114 const float fz =
z - float(z0);
115 const float sx = fx * fx * (3.f - 2.f * fx);
116 const float sy = fy * fy * (3.f - 2.f * fy);
117 const float sz = fz * fz * (3.f - 2.f * fz);
119 const float n000 = hash3(x0, y0, z0);
120 const float n100 = hash3(x0 + 1, y0, z0);
121 const float n010 = hash3(x0, y0 + 1, z0);
122 const float n110 = hash3(x0 + 1, y0 + 1, z0);
123 const float n001 = hash3(x0, y0, z0 + 1);
124 const float n101 = hash3(x0 + 1, y0, z0 + 1);
125 const float n011 = hash3(x0, y0 + 1, z0 + 1);
126 const float n111 = hash3(x0 + 1, y0 + 1, z0 + 1);
128 const float x00 = n000 + (n100 - n000) * sx;
129 const float x10 = n010 + (n110 - n010) * sx;
130 const float x01 = n001 + (n101 - n001) * sx;
131 const float x11 = n011 + (n111 - n011) * sx;
132 const float yz0 = x00 + (x10 - x00) * sy;
133 const float yz1 = x01 + (x11 - x01) * sy;
134 return yz0 + (yz1 - yz0) * sz;
137float fbm3(
float x,
float y,
float z) {
141 for (
int i = 0; i < 5; ++i) {
142 v += amp * valueNoise3(
x * freq,
y * freq,
z * freq);
149float planetNoise(
float u,
float v,
float freq) {
150 const float phi =
v * kPi;
151 const float theta =
u * kTwoPi;
152 const float sp = std::sin(phi);
153 const float px = sp * std::cos(theta) * freq;
154 const float py = std::cos(phi) * freq;
155 const float pz = sp * std::sin(theta) * freq;
156 return fbm3(
px, py, pz);
162 if (
kind ==
"music")
return makeMusic();
163 if (
kind ==
"shoot")
return makeShoot();
164 if (
kind ==
"explode")
return makeExplode();
165 if (
kind ==
"hit")
return makeHit();
166 throw eve::Exception(
"Demo.newSound: unknown kind (expected music/shoot/explode/hit)");
170 if (!gfx)
throw eve::Exception(
"Demo.newPlanetTexture: null Graphics");
171 constexpr int W = 512;
172 constexpr int H = 256;
173 std::vector<uint8_t>
px(
size_t(W) *
size_t(H) * 4u);
174 for (
int y = 0;
y < H; ++
y) {
175 const float v = (float(
y) + 0.5f) /
float(H);
176 const float lat = (
v - 0.5f) * 2.f;
177 for (
int x = 0;
x < W; ++
x) {
178 const float u = (float(
x) + 0.5f) /
float(W);
179 float n = planetNoise(
u,
v, 3.0f);
180 n =
n * 0.82f + 0.18f * planetNoise(
u + 0.13f,
v, 7.0f);
183 const float absLat = std::abs(lat);
184 if (absLat > 0.72f) {
185 const float ice = (absLat - 0.72f) / 0.28f;
186 const float grain = planetNoise(
u,
v, 14.f);
187 r = uint8_t(160 + 50 * ice + 20 * grain);
188 g = uint8_t(185 + 40 * ice + 15 * grain);
189 b = uint8_t(210 + 35 * ice);
190 }
else if (
n > 0.52f) {
191 const float elev = (
n - 0.52f) / 0.48f;
192 r = uint8_t(40 + 80 * elev);
193 g = uint8_t(110 + 70 * elev);
194 b = uint8_t(45 + 40 * elev);
196 const float depth =
n / 0.52f;
197 r = uint8_t(10 + 25 *
depth);
198 g = uint8_t(40 + 70 *
depth);
199 b = uint8_t(110 + 90 *
depth);
202 const float clouds = planetNoise(
u + 0.27f,
v, 5.5f);
203 if (clouds > 0.62f && absLat < 0.68f) {
204 const float c = (clouds - 0.62f) / 0.38f;
205 r = uint8_t(r * (1.f - 0.45f *
c) + 220 * 0.45f *
c);
206 g = uint8_t(g * (1.f - 0.45f *
c) + 228 * 0.45f *
c);
207 b = uint8_t(
b * (1.f - 0.45f *
c) + 240 * 0.45f *
c);
210 const size_t i = (size_t(
y) * size_t(W) + size_t(
x)) * 4u;
220void Demo::expose(ssq::Table &table) {
221 auto cls = table.addClass(
name, Demo::create,
false);
225void Demo::expose(ssq::Class &
cls) {
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.