[Scummvm-git-logs] scummvm master -> fb95a2e5ffdf0d486d47fad068ff1184c971e385

neuromancer noreply at scummvm.org
Tue Mar 4 07:39:41 UTC 2025


This automated email contains information about 1 new commit which have been
pushed to the 'scummvm' repo located at https://github.com/scummvm/scummvm .

Summary:
fb95a2e5ff FREESCAPE: some code to load doodle images in c64 releases


Commit: fb95a2e5ffdf0d486d47fad068ff1184c971e385
    https://github.com/scummvm/scummvm/commit/fb95a2e5ffdf0d486d47fad068ff1184c971e385
Author: neuromancer (gustavo.grieco at gmail.com)
Date: 2025-03-04T08:38:34+01:00

Commit Message:
FREESCAPE: some code to load doodle images in c64 releases

Changed paths:
  A engines/freescape/doodle.cpp
  A engines/freescape/doodle.h
    engines/freescape/detection.cpp
    engines/freescape/freescape.cpp
    engines/freescape/freescape.h
    engines/freescape/games/driller/c64.cpp
    engines/freescape/module.mk


diff --git a/engines/freescape/detection.cpp b/engines/freescape/detection.cpp
index be8737da048..d3116cbe0ae 100644
--- a/engines/freescape/detection.cpp
+++ b/engines/freescape/detection.cpp
@@ -95,21 +95,21 @@ static const ADGameDescription gameDescriptions[] = {
 		GUIO2(GUIO_NOMIDI, GAMEOPTION_AUTOMATIC_DRILLING)
 	},
 	{
-		"driller",
+		"driller", // Original tape relase?
 		"",
-		AD_ENTRY1s("DRILLER.C64.DATA", "73a6f206e54fb13245fe6d92f60fbb34", 41071),
+		AD_ENTRY1s("DRILLER.C64.DATA", "055b261bf28f313041bc4c23ff03c8da", 54532),
 		Common::EN_ANY,
 		Common::kPlatformC64,
-		ADGF_UNSTABLE,
+		ADGF_UNSTABLE | GF_C64_RETAIL,
 		GUIO2(GUIO_NOMIDI, GAMEOPTION_AUTOMATIC_DRILLING)
 	},
 	{
-		"driller", // Tape re-releae
+		"driller", // Tape re-relase
 		"",
-		AD_ENTRY1s("DRILLER.C64.DATA", "606bc969e5442634c8ab057bfde9d9d2", 64750),
+		AD_ENTRY1s("DRILLER.C64.DATA", "4afec6eea3887343e7f91fb21a2f2948", 43278),
 		Common::EN_ANY,
 		Common::kPlatformC64,
-		ADGF_UNSTABLE,
+		ADGF_UNSTABLE | GF_C64_BUDGET,
 		GUIO2(GUIO_NOMIDI, GAMEOPTION_AUTOMATIC_DRILLING)
 	},
 	{
diff --git a/engines/freescape/doodle.cpp b/engines/freescape/doodle.cpp
new file mode 100644
index 00000000000..bb018e463a1
--- /dev/null
+++ b/engines/freescape/doodle.cpp
@@ -0,0 +1,123 @@
+#include "common/file.h"
+#include "common/stream.h"
+#include "graphics/pixelformat.h"
+#include "graphics/surface.h"
+
+#include "engines/freescape/doodle.h"
+
+namespace Image {
+
+DoodleDecoder::DoodleDecoder(const byte *palette) : _surface(nullptr), _palette(nullptr) {
+    // Copy the pointer to the provided palette
+    _palette = palette;
+}
+
+DoodleDecoder::~DoodleDecoder() {
+    destroy();
+}
+
+void DoodleDecoder::destroy() {
+    if (_surface) {
+        _surface->free();
+        delete _surface;
+        _surface = nullptr;
+    }
+}
+
+bool DoodleDecoder::loadStream(Common::SeekableReadStream &stream) {
+    // This method should not be used
+    error("DoodleDecoder::loadStream - Use loadStreams instead");
+    return false;
+}
+
+bool DoodleDecoder::loadStreams(Common::SeekableReadStream &highresStream,
+                               Common::SeekableReadStream &colorStream1,
+                               Common::SeekableReadStream &colorStream2) {
+    destroy();
+
+    // Check stream sizes
+    if (highresStream.size() != 8192) {
+        error("DoodleDecoder: Invalid high-resolution data size");
+        return false;
+    }
+
+    if (colorStream1.size() != 1026 || colorStream2.size() != 1026) {
+        error("DoodleDecoder: Invalid color data size");
+        return false;
+    }
+
+    // Skip headers
+    highresStream.skip(2);
+    colorStream1.skip(2);
+    colorStream2.skip(2);
+
+    // Read high-resolution data
+    byte *highresData = new byte[8000];
+    highresStream.read(highresData, 8000);
+
+    // Skip remaining header bytes in highres file
+    highresStream.skip(190);
+
+    // Read color data
+    byte *colorData1 = new byte[kColorDataSize];
+    byte *colorData2 = new byte[kColorDataSize];
+
+    colorStream1.read(colorData1, kColorDataSize);
+    colorStream2.read(colorData2, kColorDataSize);
+
+	int width = 320;
+	int height = 200;
+
+    // Create surface
+    _surface = new Graphics::Surface();
+    _surface->create(width, height, Graphics::PixelFormat::createFormatCLUT8());
+
+    // Process each cell
+    for (int cellIdx = 0; cellIdx < 1000; ++cellIdx) {
+        processDoodleCell(cellIdx, highresData, colorData1, colorData2);
+    }
+
+    // Cleanup
+    delete[] highresData;
+    delete[] colorData1;
+    delete[] colorData2;
+
+    return true;
+}
+
+void DoodleDecoder::processDoodleCell(int cellIdx, const byte *highresData,
+                                     const byte *colorData1, const byte *colorData2) {
+    // Calculate cell coordinates
+    int cellX = (cellIdx % 40) * 8;
+    int cellY = (cellIdx / 40) * 8;
+
+    // Get colors for this cell
+    byte color1 = colorData2[cellIdx] & 0xf;
+    byte color2 = colorData1[cellIdx] >> 4;
+    byte color3 = colorData1[cellIdx] & 0xf;
+
+    // Process each row in the cell
+    for (int row = 0; row < 8; ++row) {
+        byte pixelByte = highresData[cellIdx * 8 + row];
+
+        // Process 4 pixel pairs (8 pixels total) in multicolor mode
+        for (int bit = 0; bit < 4; ++bit) {
+            byte pixelPair = (pixelByte >> (6 - bit * 2)) & 0x03;
+
+            // Determine final color
+            byte color = 0;
+            switch (pixelPair) {
+                case 0: color = 0; break;
+                case 1: color = color2; break;
+                case 2: color = color3; break;
+                case 3: color = color1; break;
+            }
+
+            // Set pixel colors (2 pixels for each pair due to multicolor mode)
+            _surface->setPixel(cellX + bit * 2, cellY + row, color);
+            _surface->setPixel(cellX + bit * 2 + 1, cellY + row, color);
+        }
+    }
+}
+
+} // End of namespace Image
\ No newline at end of file
diff --git a/engines/freescape/doodle.h b/engines/freescape/doodle.h
new file mode 100644
index 00000000000..85a4bf063a6
--- /dev/null
+++ b/engines/freescape/doodle.h
@@ -0,0 +1,59 @@
+#ifndef IMAGE_DOODLE_DECODER_H
+#define IMAGE_DOODLE_DECODER_H
+
+#include "image/image_decoder.h"
+#include "common/stream.h"
+#include "graphics/surface.h"
+
+namespace Image {
+
+class DoodleDecoder : public ImageDecoder {
+public:
+    /**
+     * Constructor for the DoodleDecoder
+     * @param palette Pointer to RGB palette data (16 colors * 3 components)
+     */
+    DoodleDecoder(const byte *palette);
+    ~DoodleDecoder() override;
+
+    // ImageDecoder interface
+    bool loadStream(Common::SeekableReadStream &stream) override;
+    void destroy() override;
+    const Graphics::Surface *getSurface() const override { return _surface; }
+    const byte *getPalette() const override { return _palette; }
+    uint16 getPaletteColorCount() const override { return 16; }
+
+    /**
+     * Load a C64 doodle image from its component streams
+     * @param highresStream Stream containing high-resolution pixel data
+     * @param colorStream1 Stream containing first color data file
+     * @param colorStream2 Stream containing second color data file
+     * @return Whether loading succeeded
+     */
+    bool loadStreams(Common::SeekableReadStream &highresStream,
+                    Common::SeekableReadStream &colorStream1,
+                    Common::SeekableReadStream &colorStream2);
+
+private:
+    static const int kWidth = 320;
+    static const int kHeight = 200;
+    static const int kHeaderSize = 192;
+    static const int kColorDataSize = 1000;  // 40x25 color cells
+
+    Graphics::Surface *_surface;
+    const byte *_palette;
+
+    /**
+     * Process an 8x8 cell of the image
+     * @param cellIdx Cell index (0-999)
+     * @param highresData Pointer to high-resolution pixel data
+     * @param colorData1 First color data array
+     * @param colorData2 Second color data array
+     */
+    void processDoodleCell(int cellIdx, const byte *highresData,
+                          const byte *colorData1, const byte *colorData2);
+};
+
+} // End of namespace Image
+
+#endif
\ No newline at end of file
diff --git a/engines/freescape/freescape.cpp b/engines/freescape/freescape.cpp
index 2ed5e8eca06..2a38a4b048f 100644
--- a/engines/freescape/freescape.cpp
+++ b/engines/freescape/freescape.cpp
@@ -32,6 +32,7 @@
 #include "freescape/language/8bitDetokeniser.h"
 #include "freescape/objects/sensor.h"
 #include "freescape/sweepAABB.h"
+#include "freescape/doodle.h"
 
 namespace Freescape {
 
@@ -641,7 +642,7 @@ void FreescapeEngine::processInput() {
 
 				_eventManager->purgeMouseEvents();
 				rotate(event.relMouse.x * _mouseSensitivity, event.relMouse.y * _mouseSensitivity);
-			}			
+			}
 			break;
 
 		case Common::EVENT_LBUTTONDOWN:
@@ -1127,6 +1128,16 @@ Graphics::ManagedSurface *FreescapeEngine::loadAndConvertNeoImage(Common::Seekab
 	return surface;
 }
 
+Graphics::ManagedSurface *FreescapeEngine::loadAndConvertDoodleImage(Common::SeekableReadStream *bitmap, Common::SeekableReadStream *color1, Common::SeekableReadStream *color2, byte *palette) {
+	Image::DoodleDecoder decoder(palette);
+	decoder.loadStreams(*bitmap, *color1, *color2);
+	Graphics::ManagedSurface *surface = new Graphics::ManagedSurface();
+	surface->copyFrom(*decoder.getSurface());
+	surface->convertToInPlace(_gfx->_currentPixelFormat, decoder.getPalette(), decoder.getPaletteColorCount());
+	return surface;
+}
+
+
 Graphics::ManagedSurface *FreescapeEngine::loadAndCenterScrImage(Common::SeekableReadStream *stream) {
 	Image::ScrDecoder decoder;
 	decoder.loadStream(*stream);
diff --git a/engines/freescape/freescape.h b/engines/freescape/freescape.h
index e8e7d911435..fbd859368de 100644
--- a/engines/freescape/freescape.h
+++ b/engines/freescape/freescape.h
@@ -253,6 +253,8 @@ public:
 	byte *getPaletteFromNeoImage(Common::SeekableReadStream *stream, int offset);
 	Graphics::ManagedSurface *loadAndConvertNeoImage(Common::SeekableReadStream *stream, int offset, byte *palette = nullptr);
 	Graphics::ManagedSurface *loadAndCenterScrImage(Common::SeekableReadStream *stream);
+	Graphics::ManagedSurface *loadAndConvertDoodleImage(Common::SeekableReadStream *bitmap, Common::SeekableReadStream *color1, Common::SeekableReadStream *color2, byte *palette);
+
 	void loadPalettes(Common::SeekableReadStream *file, int offset);
 	byte *loadPalette(Common::SeekableReadStream *file);
 	void swapPalette(uint16 areaID);
@@ -599,7 +601,9 @@ enum GameReleaseFlags {
 	GF_CPC_BUDGET = (1 << 7),
 	GF_CPC_VIRTUALWORLDS = (1 << 8),
 	GF_ATARI_RETAIL = (1 << 9),
-	GF_ATARI_BUDGET = (1 << 10)
+	GF_ATARI_BUDGET = (1 << 10),
+	GF_C64_RETAIL = (1 << 11),
+	GF_C64_BUDGET = (1 << 12),
 };
 
 extern FreescapeEngine *g_freescape;
diff --git a/engines/freescape/games/driller/c64.cpp b/engines/freescape/games/driller/c64.cpp
index 556b86f8707..a3bfd4edb08 100644
--- a/engines/freescape/games/driller/c64.cpp
+++ b/engines/freescape/games/driller/c64.cpp
@@ -27,6 +27,8 @@
 
 namespace Freescape {
 
+extern byte kDrillerC64Palette[16][3];
+
 void DrillerEngine::initC64() {
 	_viewArea = Common::Rect(32, 16, 288, 120);
 }
@@ -41,12 +43,22 @@ void DrillerEngine::loadAssetsC64FullGame() {
 		loadGlobalObjects(&file, 0x1855, 8);
 	} else if (_targetName.hasPrefix("driller")) {
 		file.open("driller.c64.data");
-		//loadMessagesFixedSize(&file, 0x167a - 0x400, 14, 20);
-		//loadFonts(&file, 0xae54);
-		loadFonts(&file, 0x4ee);
-		load8bitBinary(&file, 0x8eee, 16);
-		loadMessagesFixedSize(&file, 0x1766, 14, 20);
-		loadGlobalObjects(&file, 0x1941, 8);
+
+		if (_variant & GF_C64_RETAIL) {
+			loadFonts(&file, 0x402);
+			load8bitBinary(&file, 0x8b04, 16);
+			loadMessagesFixedSize(&file, 0x167a, 14, 20);
+			loadGlobalObjects(&file, 0x1855, 8);
+		} else if (_variant & GF_C64_BUDGET) {
+			//loadFonts(&file, 0x402);
+			load8bitBinary(&file, 0x7df7, 16);
+			loadMessagesFixedSize(&file, 0x1399, 14, 20);
+			loadGlobalObjects(&file, 0x150a, 8);
+		} else {
+			//error("Unknown C64 release");
+			assert(false);
+		}
+
 
 		// The color map from the C64 version looks invalid
 		// so we'll just hardcode the Dark Side one which works fine
@@ -134,8 +146,15 @@ void DrillerEngine::loadAssetsC64FullGame() {
 		_border = new Graphics::ManagedSurface();
 		_border->copyFrom(*surf);
 
-		//_border = _title;
-		//loadGlobalObjects(&file, 0x1855 - 0x400, 8);
+		/*file.close();
+		file.open("driller.c64.title.bitmap");
+
+		Common::File colorFile1;
+		colorFile1.open("driller.c64.title.colors1");
+		Common::File colorFile2;
+		colorFile2.open("driller.c64.title.colors2");
+
+		_title = loadAndConvertDoodleImage(&file, &colorFile1, &colorFile2, (byte *)&kDrillerC64Palette);*/
 	} else
 		error("Unknown C64 release");
 }
diff --git a/engines/freescape/module.mk b/engines/freescape/module.mk
index 9c860d08f8b..2c03a2d26e9 100644
--- a/engines/freescape/module.mk
+++ b/engines/freescape/module.mk
@@ -6,6 +6,7 @@ MODULE_OBJS := \
 	font.o \
 	events.o \
 	demo.o \
+	doodle.o \
 	freescape.o \
 	games/castle/castle.o \
 	games/castle/amiga.o \




More information about the Scummvm-git-logs mailing list