载入中...
搜索中...
未找到
Demo.cpp
浏览该文件的文档.
1#include "demo/Demo.h"
2
3#include "common/Exception.h"
4#include "graphics/Graphics.h"
5#include "graphics/Texture.h"
6#include "sound/SoundData.h"
7
8#include <simplesquirrel/simplesquirrel.hpp>
9
10#include <algorithm>
11#include <cmath>
12#include <cstdint>
13#include <vector>
14
15namespace eve::demo {
16
18
19Demo::Demo() = default;
20Demo::~Demo() = default;
21
22namespace {
23
24constexpr float kPi = 3.14159265358979323846f;
25constexpr float kTwoPi = kPi * 2.f;
26constexpr int kGenRate = 22050;
27
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);
36}
37
38float noteFreq(int semitoneFromA4) {
39 return 440.f * std::pow(2.f, semitoneFromA4 / 12.f);
40}
41
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);
56 }
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));
60 }
61 return new sound::SoundData(std::move(pcm), kGenRate, 16, 1);
62}
63
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));
72 }
73 return new sound::SoundData(std::move(pcm), kGenRate, 16, 1);
74}
75
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));
87 }
88 return new sound::SoundData(std::move(pcm), kGenRate, 16, 1);
89}
90
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));
98 }
99 return new sound::SoundData(std::move(pcm), kGenRate, 16, 1);
100}
101
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;
106}
107
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);
118
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);
127
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;
135}
136
137float fbm3(float x, float y, float z) {
138 float v = 0.f;
139 float amp = 0.5f;
140 float freq = 1.f;
141 for (int i = 0; i < 5; ++i) {
142 v += amp * valueNoise3(x * freq, y * freq, z * freq);
143 freq *= 2.f;
144 amp *= 0.5f;
145 }
146 return v;
147}
148
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);
157}
158
159} // namespace
160
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)");
167}
168
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);
181
182 uint8_t r, g, b;
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);
195 } else {
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);
200 }
201
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);
208 }
209
210 const size_t i = (size_t(y) * size_t(W) + size_t(x)) * 4u;
211 px[i + 0] = r;
212 px[i + 1] = g;
213 px[i + 2] = b;
214 px[i + 3] = 255;
215 }
216 }
217 return gfx->newTexture(W, H, px.data(), true, false);
218}
219
220void Demo::expose(ssq::Table &table) {
221 auto cls = table.addClass(name, Demo::create, false);
222 expose(cls);
223}
224
225void Demo::expose(ssq::Class &cls) {
226 cls.addFunc("getName", &Demo::getName);
227 cls.addFunc("newSound", &Demo::newSound);
228 cls.addFunc("newPlanetTexture", &Demo::newPlanetTexture);
229}
230
231} // namespace eve::demo
Tok kind
HSQOBJECT cls
Definition ECS.cpp:21
int y
Definition Grass.cpp:135
int z
Definition Grass.cpp:135
float u
Definition Grass.cpp:234
int x
Definition Grass.cpp:135
glm::vec3 n
Definition Grass.cpp:64
std::vector< Colorf > px
float depth
uint32_t b
uint32_t c
#define Module_IMPL(ModuleName, newExpr)
Definition Module.h:24
const char * name
Definition RockMesh.cpp:21
int v
uint32_t s
Definition Weather.cpp:28
virtual std::string getName() const =0
Optional demo-only helpers (procedural SFX / planet albedo). Built only when EVENGINE_BUILD_DEMO=ON; ...
Definition Demo.h:22
sound::SoundData * newSound(const std::string &kind)
kind: "music" | "shoot" | "explode" | "hit"
Definition Demo.cpp:161
~Demo() override
graphics::Texture * newPlanetTexture(graphics::Graphics *gfx)
Equirectangular planet albedo uploaded via Graphics::newTexture.
Definition Demo.cpp:169
virtual Texture * newTexture(int width, int height, const uint8_t *rgba, bool repeatU=false, bool repeatV=false)=0
GPU texture created via Graphics::newTexture. Owns GPU resources through an opaque backend handle.
Definition Texture.h:17
Raw PCM audio buffer with format metadata (samples/rate/bit depth/channels).
Definition SoundData.h:13