summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CMakeLists.txt45
-rw-r--r--GEMINI.md1
-rw-r--r--HOWTO.md45
-rw-r--r--PROJECT_CONTEXT.md1
-rw-r--r--assets/final/assets.txt0
-rw-r--r--src/main.cc7
-rw-r--r--tools/asset_packer.cc125
7 files changed, 220 insertions, 4 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 69e51c6..1d06033 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -138,6 +138,7 @@ if(DEMO_BUILD_TESTS)
endif()
option(DEMO_BUILD_TOOLS "Build tools" OFF)
+
if(DEMO_BUILD_TOOLS)
add_executable(spectool
tools/spectool.cc
@@ -161,4 +162,46 @@ if(DEMO_BUILD_TOOLS)
tools/specview.cc
)
target_include_directories(specview PRIVATE src)
-endif() \ No newline at end of file
+
+ add_executable(asset_packer
+ tools/asset_packer.cc
+ )
+endif()
+
+# Configure asset generation
+set(ASSETS_TXT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/assets/final/assets.txt)
+set(GENERATED_ASSETS_H ${CMAKE_CURRENT_BINARY_DIR}/src/assets.h)
+set(GENERATED_ASSETS_DATA_CC ${CMAKE_CURRENT_BINARY_DIR}/src/assets_data.cc)
+
+add_custom_command(
+ OUTPUT ${GENERATED_ASSETS_H} ${GENERATED_ASSETS_DATA_CC}
+ COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/src
+ COMMAND asset_packer ${ASSETS_TXT_PATH} ${GENERATED_ASSETS_H} ${GENERATED_ASSETS_DATA_CC}
+ DEPENDS tools/asset_packer.cc ${ASSETS_TXT_PATH}
+ COMMENT "Generating assets.h and assets_data.cc"
+)
+
+add_custom_target(generate_assets ALL
+ DEPENDS ${GENERATED_ASSETS_H} ${GENERATED_ASSETS_DATA_CC}
+)
+
+add_executable(demo64k
+ src/main.cc
+ src/platform.cc
+ src/gpu/gpu.cc
+ src/audio/audio.cc
+ src/audio/fdct.cc
+ src/audio/idct.cc
+ src/audio/window.cc
+ src/audio/synth.cc
+ third_party/glfw3webgpu/glfw3webgpu.c
+ ${GENERATED_ASSETS_DATA_CC}
+)
+
+# Ensure demo64k depends on the generated assets
+add_dependencies(demo64k generate_assets)
+
+target_link_libraries(demo64k PRIVATE ${DEMO_LIBS})
+
+# Include generated assets header for compilation
+target_include_directories(demo64k PRIVATE ${CMAKE_CURRENT_BINARY_DIR}/src) \ No newline at end of file
diff --git a/GEMINI.md b/GEMINI.md
index 66ba8af..cd4ca4b 100644
--- a/GEMINI.md
+++ b/GEMINI.md
@@ -1,5 +1,6 @@
# Project Context
@PROJECT_CONTEXT.md
+@ASSET_SYSTEM.md
@BUILD.md
@FETCH_DEPS.md
@CONTRIBUTING.md
diff --git a/HOWTO.md b/HOWTO.md
index 5716524..1f2560c 100644
--- a/HOWTO.md
+++ b/HOWTO.md
@@ -119,8 +119,47 @@ The executable will be located at `build/specview`.
./build/specview path/to/input.spec
```
-## References and links
+### Asset Management System
-drum-kit: https://drive.google.com/file/d/13tc7XjkMg-tigvje5qpp6XazK-VcOjoc/view
-(got from https://www.reddit.com/r/Drumkits/)
+This system allows embedding binary assets directly into the demo executable.
+#### Defining Assets
+
+Assets are defined in `assets/final/assets.txt`. Each line specifies:
+* `ASSET_NAME`: The identifier for the asset in C++ (e.g., `SAMPLE_142`).
+* `filename.ext`: The path to the asset file (relative to `assets/final/`).
+* `NONE`: Compression type (currently only `NONE` is supported).
+* `"Description"`: An optional description.
+
+Example `assets/final/assets.txt` entry:
+```
+SAMPLE_142, sample_142.spec, NONE, "A drum kick sample"
+```
+
+#### Building with Assets
+
+The `asset_packer` tool processes `assets/final/assets.txt` and generates two files:
+* `build/src/assets.h`: Contains the `AssetId` enum and `GetAsset` function declaration.
+* `build/src/assets_data.cc`: Contains the binary data for each asset.
+
+These files are automatically generated as part of the normal build process when `demo64k` is built. To trigger generation, simply run:
+
+```bash
+cmake -S . -B build
+cmake --build build
+```
+
+#### Accessing Assets in Code
+
+Include `assets.h` and use the `GetAsset` function:
+
+```cpp
+#include "assets.h"
+
+// ...
+size_t asset_size;
+const uint8_t* my_asset = GetAsset(AssetId::ASSET_SAMPLE_142, &asset_size);
+// ...
+// For lazy decompression (scaffolding only):
+// DropAsset(AssetId::ASSET_SAMPLE_142, my_asset);
+```
diff --git a/PROJECT_CONTEXT.md b/PROJECT_CONTEXT.md
index 2fb533c..28f86f8 100644
--- a/PROJECT_CONTEXT.md
+++ b/PROJECT_CONTEXT.md
@@ -36,6 +36,7 @@ Incoming tasks in no particular order:
- [x] 8. add a #define STRIP_ALL to remove all unnecessary code for the final build
(for instance, command-line args parsing, or unnecessary options, constant
parameters to function calls, etc.)
+- [ ] 9. work on the compact in-line and off-line asset system (@ASSET_SYSTEM.md)
- 9. work on the compact in-line and off-line asset system (@ASSET_SYSTEM.md)
## Session Decisions and Current State
diff --git a/assets/final/assets.txt b/assets/final/assets.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/assets/final/assets.txt
diff --git a/src/main.cc b/src/main.cc
index 31e1c58..bcf6015 100644
--- a/src/main.cc
+++ b/src/main.cc
@@ -1,5 +1,6 @@
#include "audio/audio.h"
#include "audio/synth.h"
+#include "assets.h" // Include generated asset header
#include "gpu/gpu.h"
#include "platform.h"
#include "util/math.h"
@@ -54,6 +55,12 @@ int main(int argc, char **argv) {
const Spectrogram spec = {g_spec_buffer_a, g_spec_buffer_b, SPEC_FRAMES};
int tone_id = synth_register_spectrogram(&spec);
+ // Dummy call to ensure asset system is linked
+ size_t dummy_size;
+ const uint8_t* dummy_asset = GetAsset(AssetId::ASSET_NULL_ASSET, &dummy_size);
+ (void)dummy_asset;
+ (void)dummy_size;
+
double last_beat_time = 0.0;
int beat_count = 0;
diff --git a/tools/asset_packer.cc b/tools/asset_packer.cc
new file mode 100644
index 0000000..8b06829
--- /dev/null
+++ b/tools/asset_packer.cc
@@ -0,0 +1,125 @@
+#include <fstream>
+#include <iostream>
+#include <map>
+#include <string>
+#include <vector>
+
+int main(int argc, char *argv[]) {
+ if (argc != 4) {
+ std::cerr << "Usage: " << argv[0]
+ << " <assets.txt_path> <output_assets_h_path> "
+ "<output_assets_data_cc_path>\n";
+ return 1;
+ }
+
+ std::string assets_txt_path = argv[1];
+ std::string output_assets_h_path = argv[2];
+ std::string output_assets_data_cc_path = argv[3];
+
+ std::ifstream assets_txt_file(assets_txt_path);
+ if (!assets_txt_file.is_open()) {
+ std::cerr << "Error: Could not open assets.txt at " << assets_txt_path
+ << "\n";
+ return 1;
+ }
+
+ std::ofstream assets_h_file(output_assets_h_path);
+ if (!assets_h_file.is_open()) {
+ std::cerr << "Error: Could not open output assets.h at "
+ << output_assets_h_path << "\n";
+ return 1;
+ }
+
+ std::ofstream assets_data_cc_file(output_assets_data_cc_path);
+ if (!assets_data_cc_file.is_open()) {
+ std::cerr << "Error: Could not open output assets_data.cc at "
+ << output_assets_data_cc_path << "\n";
+ return 1;
+ }
+
+ // Generate assets.h
+ assets_h_file << "#pragma once\n";
+ assets_h_file << "#include <cstdint>\n\n";
+ assets_h_file << "enum class AssetId : uint16_t {\n";
+
+ // Generate assets_data.cc header
+ assets_data_cc_file << "#include \"assets.h\"\n\n";
+ assets_data_cc_file << "#include <vector>\n\n";
+
+ std::string line;
+ int asset_id_counter = 0;
+ std::vector<std::string> asset_names;
+
+ while (std::getline(assets_txt_file, line)) {
+ if (line.empty() || line[0] == '#')
+ continue; // Skip empty lines and comments
+
+ size_t first_comma = line.find(',');
+ if (first_comma == std::string::npos) {
+ std::cerr << "Warning: Skipping malformed line in assets.txt: " << line
+ << "\n";
+ continue;
+ }
+
+ std::string asset_name = line.substr(0, first_comma);
+ asset_name.erase(0, asset_name.find_first_not_of(" \t\r\n"));
+ asset_name.erase(asset_name.find_last_not_of(" \t\r\n") + 1);
+
+ if (asset_name.empty()) {
+ std::cerr << "Warning: Skipping line with empty asset name: " << line
+ << "\n";
+ continue;
+ }
+
+ asset_names.push_back(asset_name);
+
+ // Add to assets.h enum
+ assets_h_file << " ASSET_" << asset_name << " = " << asset_id_counter
+ << ",\n";
+
+ // Placeholder for assets_data.cc (empty data for now)
+ assets_data_cc_file << "const uint8_t ASSET_DATA_" << asset_name
+ << "[] = {};\n";
+ assets_data_cc_file << "const size_t ASSET_SIZE_" << asset_name
+ << " = 0;\n\n";
+
+ asset_id_counter++;
+ }
+
+ assets_h_file << "};\n\n";
+
+ // Generate GetAsset function declaration in assets.h
+ assets_h_file
+ << "const uint8_t *GetAsset(AssetId asset_id, size_t *out_size = nullptr);\n";
+ assets_h_file << "void DropAsset(AssetId asset_id, const uint8_t *asset); // For lazy "
+ "decompression scaffolding\n";
+ assets_h_file.close();
+
+ // Generate GetAsset function implementation in assets_data.cc
+ assets_data_cc_file << "const uint8_t *GetAsset(AssetId asset_id, size_t *out_size) {\n";
+ assets_data_cc_file << " if (out_size) *out_size = 0;\n"; // Default for now
+ assets_data_cc_file << " switch (asset_id) {\n";
+ for (const std::string &name : asset_names) {
+ assets_data_cc_file << " case AssetId::ASSET_" << name << ":\n";
+ assets_data_cc_file << " if (out_size) *out_size = ASSET_SIZE_" << name << ";\n";
+ assets_data_cc_file << " return ASSET_DATA_" << name << ";\n";
+ }
+ assets_data_cc_file << " default:\n";
+ assets_data_cc_file << " return nullptr;\n";
+ assets_data_cc_file << " }\n";
+ assets_data_cc_file << "}\n\n";
+
+ // Dummy DropAsset implementation
+ assets_data_cc_file << "void DropAsset(AssetId asset_id, const uint8_t *asset) {\n";
+ assets_data_cc_file << " (void)asset_id;\n";
+ assets_data_cc_file << " (void)asset;\n";
+ assets_data_cc_file << " // No-op for now, actual implementation for lazy decompression goes here\n";
+ assets_data_cc_file << "}\n";
+
+ assets_data_cc_file.close();
+
+ std::cout << "Asset packer successfully generated: " << output_assets_h_path
+ << " and " << output_assets_data_cc_path << "\n";
+
+ return 0;
+}