From ea321b71d34a053bbcc2c8dc4ec1e1b79cd1163d Mon Sep 17 00:00:00 2001
From: sz <sz@recv.cc>
Date: Mon, 29 Jan 2024 00:22:27 -0600
Subject: [PATCH] Add toggle to switch to old "4c" mode in the cimbar_js and
 the cli tools

Somewhat of a misnomer as an option -- might call it just "c" mode
eventually (the 4 would be the default number of colors per tile, which
can still be overriden to 8)
---
 src/exe/cimbar/cimbar.cpp       | 12 ++++++++----
 src/exe/cimbar_recv/recv.cpp    |  6 +++++-
 src/exe/cimbar_send/send.cpp    |  5 ++++-
 src/lib/cimbar_js/cimbar_js.cpp |  7 +++++--
 src/lib/cimbar_js/cimbar_js.h   |  2 +-
 web/main.js                     |  2 +-
 6 files changed, 24 insertions(+), 10 deletions(-)

diff --git a/src/exe/cimbar/cimbar.cpp b/src/exe/cimbar/cimbar.cpp
index 08840bdb..f7dfa067 100644
--- a/src/exe/cimbar/cimbar.cpp
+++ b/src/exe/cimbar/cimbar.cpp
@@ -101,7 +101,7 @@ namespace {
 }
 
 template <typename FilenameIterable>
-int encode(const FilenameIterable& infiles, const std::string& outpath, int ecc, int color_bits, int compression_level, bool no_fountain)
+int encode(const FilenameIterable& infiles, const std::string& outpath, int ecc, int color_bits, int compression_level, bool legacy_mode, bool no_fountain)
 {
 	Encoder en(ecc, cimbar::Config::symbol_bits(), color_bits);
 	for (const string& f : infiles)
@@ -180,6 +180,7 @@ int main(int argc, char** argv)
 		("c,color-bits", "Color bits. [0-3]", cxxopts::value<int>()->default_value(turbo::str::str(colorBits)))
 		("e,ecc", "ECC level", cxxopts::value<unsigned>()->default_value(turbo::str::str(ecc)))
 		("z,compression", "Compression level. 0 == no compression.", cxxopts::value<int>()->default_value(turbo::str::str(compressionLevel)))
+		("4c", "Use 0.5.x mode (4c)", cxxopts::value<bool>())
 		("color-correct", "Toggle decoding color correction. 2 == full (fountain mode only). 1 == simple. 0 == off.", cxxopts::value<int>()->default_value("2"))
 		("color-correction-file", "Debug -- save color correction matrix generated during fountain decode, or use it for non-fountain decodes", cxxopts::value<string>())
 		("encode", "Run the encoder!", cxxopts::value<bool>())
@@ -218,13 +219,14 @@ int main(int argc, char** argv)
 	colorBits = std::min(3, result["color-bits"].as<int>());
 	compressionLevel = result["compression"].as<int>();
 	ecc = result["ecc"].as<unsigned>();
+	bool legacy_mode = result.count("4c");
 
 	if (encodeFlag)
 	{
 		if (useStdin)
-			return encode(StdinLineReader(), outpath, ecc, colorBits, compressionLevel, no_fountain);
+			return encode(StdinLineReader(), outpath, ecc, colorBits, compressionLevel, legacy_mode, no_fountain);
 		else
-			return encode(infiles, outpath, ecc, colorBits, compressionLevel, no_fountain);
+			return encode(infiles, outpath, ecc, colorBits, compressionLevel, legacy_mode, no_fountain);
 	}
 
 	// else, decode
@@ -236,7 +238,9 @@ int main(int argc, char** argv)
 		color_correction_file = result["color-correction-file"].as<string>();
 	int preprocess = result["preprocess"].as<int>();
 
-	Decoder d(ecc, colorBits);
+	unsigned color_mode = legacy_mode? 0 : 1;
+	bool coupled = legacy_mode;
+	Decoder d(ecc, colorBits, color_mode, coupled);
 
 	if (no_fountain)
 	{
diff --git a/src/exe/cimbar_recv/recv.cpp b/src/exe/cimbar_recv/recv.cpp
index ecc6cacd..5e072eaa 100644
--- a/src/exe/cimbar_recv/recv.cpp
+++ b/src/exe/cimbar_recv/recv.cpp
@@ -44,6 +44,7 @@ int main(int argc, char** argv)
 		("c,colorbits", "Color bits. [0-3]", cxxopts::value<int>()->default_value(turbo::str::str(colorBits)))
 		("e,ecc", "ECC level", cxxopts::value<unsigned>()->default_value(turbo::str::str(ecc)))
 		("f,fps", "Target decode FPS", cxxopts::value<unsigned>()->default_value(turbo::str::str(defaultFps)))
+		("4c", "Use 0.5.x mode (4c)", cxxopts::value<bool>())
 		("h,help", "Print usage")
 	;
 	options.show_positional_help();
@@ -62,6 +63,8 @@ int main(int argc, char** argv)
 
 	colorBits = std::min(3, result["colorbits"].as<int>());
 	ecc = result["ecc"].as<unsigned>();
+	bool legacy_mode = result.count("4c");
+
 	unsigned fps = result["fps"].as<unsigned>();
 	if (fps == 0)
 		fps = defaultFps;
@@ -95,7 +98,8 @@ int main(int argc, char** argv)
 	window.auto_scale_to_window();
 
 	Extractor ext;
-	Decoder dec;
+	unsigned color_mode = legacy_mode? 0 : 1;
+	Decoder dec(-1, -1, color_mode, legacy_mode);
 
 	unsigned chunkSize = cimbar::Config::fountain_chunk_size(ecc, colorBits+cimbar::Config::symbol_bits());
 	fountain_decoder_sink<cimbar::zstd_decompressor<std::ofstream>> sink(outpath, chunkSize);
diff --git a/src/exe/cimbar_send/send.cpp b/src/exe/cimbar_send/send.cpp
index 73bcae1c..2000e89d 100644
--- a/src/exe/cimbar_send/send.cpp
+++ b/src/exe/cimbar_send/send.cpp
@@ -43,6 +43,7 @@ int main(int argc, char** argv)
 		("e,ecc", "ECC level", cxxopts::value<unsigned>()->default_value(turbo::str::str(ecc)))
 		("f,fps", "Target FPS", cxxopts::value<unsigned>()->default_value(turbo::str::str(defaultFps)))
 		("z,compression", "Compression level. 0 == no compression.", cxxopts::value<int>()->default_value(turbo::str::str(compressionLevel)))
+		("4c", "Use 0.5.x mode (4c)", cxxopts::value<bool>())
 		("h,help", "Print usage")
 	;
 	options.show_positional_help();
@@ -61,6 +62,8 @@ int main(int argc, char** argv)
 	colorBits = std::min(3, result["colorbits"].as<int>());
 	compressionLevel = result["compression"].as<int>();
 	ecc = result["ecc"].as<unsigned>();
+	bool legacy_mode = result.count("4c");
+
 	unsigned fps = result["fps"].as<unsigned>();
 	if (fps == 0)
 		fps = defaultFps;
@@ -73,7 +76,7 @@ int main(int argc, char** argv)
 		return 70;
 	}
 
-	configure(colorBits, ecc, compressionLevel);
+	configure(colorBits, ecc, compressionLevel, legacy_mode);
 
 	std::chrono::time_point start = std::chrono::high_resolution_clock::now();
 	while (true)
diff --git a/src/lib/cimbar_js/cimbar_js.cpp b/src/lib/cimbar_js/cimbar_js.cpp
index 9efdc489..89be49ee 100644
--- a/src/lib/cimbar_js/cimbar_js.cpp
+++ b/src/lib/cimbar_js/cimbar_js.cpp
@@ -22,6 +22,7 @@ namespace {
 	unsigned _ecc = cimbar::Config::ecc_bytes();
 	unsigned _colorBits = cimbar::Config::color_bits();
 	int _compressionLevel = cimbar::Config::compression_level();
+	bool _legacyMode = false;
 }
 
 extern "C" {
@@ -109,16 +110,18 @@ int encode(unsigned char* buffer, unsigned size, int encode_id)
 	return 1;
 }
 
-int configure(unsigned color_bits, unsigned ecc, int compression)
+int configure(unsigned color_bits, unsigned ecc, int compression, bool legacy_mode)
 {
 	// defaults
 	if (color_bits > 3)
 		color_bits = cimbar::Config::color_bits();
-	if (ecc < 0 or ecc >= 150)
+	if (ecc >= 150)
 		ecc = cimbar::Config::ecc_bytes();
 	if (compression < 0 or compression > 22)
 		compression = cimbar::Config::compression_level();
 
+	_legacyMode = legacy_mode; // legacy mode shouldn't need a refresh, so just change it
+
 	// check if we need to refresh the stream
 	bool refresh = (color_bits != _colorBits or ecc != _ecc or compression != _compressionLevel);
 	if (refresh)
diff --git a/src/lib/cimbar_js/cimbar_js.h b/src/lib/cimbar_js/cimbar_js.h
index a04c6741..7eb06962 100644
--- a/src/lib/cimbar_js/cimbar_js.h
+++ b/src/lib/cimbar_js/cimbar_js.h
@@ -10,7 +10,7 @@ int initialize_GL(int width, int height);
 int render();
 int next_frame();
 int encode(unsigned char* buffer, unsigned size, int encode_id);  // encode_id == -1 -> auto-increment
-int configure(unsigned color_bits, unsigned ecc, int compression);
+int configure(unsigned color_bits, unsigned ecc, int compression, bool legacy_mode);
 
 #ifdef __cplusplus
 }
diff --git a/web/main.js b/web/main.js
index ca51a768..ca5aa01e 100644
--- a/web/main.js
+++ b/web/main.js
@@ -156,7 +156,7 @@ return {
 
   setColorBits : function(color_bits)
   {
-    Module._configure(color_bits, 255, 255);
+    Module._configure(color_bits, 255, 255, false);
 
     var nav = document.getElementById("nav-container");
     if (color_bits == 2) {