@@ -151,10 +151,14 @@ static void ConvertFromTiles4BppCell(unsigned char *src, unsigned char *dest, in
151151 dest [idxComponentY * pitch + idxComponentX ] = (leftPixel << 4 ) | rightPixel ;
152152 }
153153 } else {
154- srcPixelPair = src [idxComponentY * pitch + idxComponentX ];
155- leftPixel = srcPixelPair & 0xF ;
156- rightPixel = srcPixelPair >> 4 ;
157-
154+ if (image -> hasPalette ) {
155+ leftPixel = src [idxComponentY * pitch + idxComponentX * 2 + 0 ] & 0xF ;
156+ rightPixel = src [idxComponentY * pitch + idxComponentX * 2 + 1 ] & 0xF ;
157+ } else {
158+ srcPixelPair = src [idxComponentY * pitch + idxComponentX ];
159+ leftPixel = srcPixelPair & 0xF ;
160+ rightPixel = srcPixelPair >> 4 ;
161+ }
158162 * dest ++ = (leftPixel << 4 ) | rightPixel ;
159163 }
160164 } else {
@@ -169,7 +173,13 @@ static void ConvertFromTiles4BppCell(unsigned char *src, unsigned char *dest, in
169173 dest [idxComponentY * pitch + idxComponentX ] = * src ++ ;
170174 }
171175 } else {
172- * dest ++ = src [idxComponentY * pitch + idxComponentX ];
176+ if (image -> hasPalette ) {
177+ rightPixel = src [idxComponentY * pitch + idxComponentX * 2 + 0 ] & 0xF ;
178+ leftPixel = src [idxComponentY * pitch + idxComponentX * 2 + 1 ] & 0xF ;
179+ * dest ++ = leftPixel | (rightPixel << 4 );
180+ } else {
181+ * dest ++ = src [idxComponentY * pitch + idxComponentX ];
182+ }
173183 }
174184 }
175185 }
@@ -245,6 +255,8 @@ static void ConvertFromTiles8Bpp(unsigned char *src, unsigned char *dest, int nu
245255}
246256
247257static void ConvertFromTiles8BppCell (unsigned char * src , unsigned char * dest , int oamWidth , int oamHeight , int imageWidth , int startX , int startY , bool hFlip , bool vFlip , bool hvFlip , bool toPNG , int plttNum , int mappingType , struct Image * image ) {
258+ static bool setTransparencyColor = false;
259+
248260 int tilesSoFar = 0 ;
249261 int rowsSoFar = 0 ;
250262 int chunkStartX = 0 ;
@@ -271,20 +283,71 @@ static void ConvertFromTiles8BppCell(unsigned char *src, unsigned char *dest, in
271283 }
272284
273285 if (toPNG ) {
274- if (mappingType == 2 ) {
286+ if (image -> hasPalette && mappingType == 2 ) {
287+ // Color mode 256x16 extpltt is handled specially
288+ // The underlying PNG image is 24-bit RGB or 32-bit RGBA
275289 int colorIdx = plttNum * 256 + (* src ++ );
276290 struct Color * color = & image -> palette .colors [colorIdx ];
277291 dest [idxComponentY * pitch + idxComponentX * pitchFactor + 0 ] = color -> red ;
278292 dest [idxComponentY * pitch + idxComponentX * pitchFactor + 1 ] = color -> green ;
279293 dest [idxComponentY * pitch + idxComponentX * pitchFactor + 2 ] = color -> blue ;
280294 if (image -> hasTransparency ) {
295+ // Alpha on DS is binary. Alpha in PNG is 8-bit. Scale accordingly.
281296 dest [idxComponentY * pitch + idxComponentX * pitchFactor + 3 ] = colorIdx == 0 ? 0 : 255 ;
282297 }
283298 } else {
284299 dest [idxComponentY * pitch + idxComponentX ] = * src ++ ;
285300 }
286301 } else {
287- * dest ++ = src [idxComponentY * pitch + idxComponentX ];
302+ if (image -> hasPalette && mappingType == 2 ) {
303+ // Color mode 256x16 extpltt is handled specially
304+ // The underlying PNG image is 24-bit RGB or 32-bit RGBA
305+ int colorIdx ;
306+ struct Color color = {
307+ .red = src [idxComponentY * pitch + idxComponentX * pitchFactor + 0 ],
308+ .green = src [idxComponentY * pitch + idxComponentX * pitchFactor + 1 ],
309+ .blue = src [idxComponentY * pitch + idxComponentX * pitchFactor + 2 ],
310+ };
311+ if (image -> hasTransparency && src [idxComponentY * pitch + idxComponentX * pitchFactor + 3 ] == 0 ) {
312+ // First color is hardcoded to be transparency
313+ colorIdx = 0 ;
314+ if (!setTransparencyColor ) {
315+ memcpy (& image -> palette .colors [0 ], & color , sizeof (struct Color ));
316+ setTransparencyColor = true;
317+ if (image -> palette .numColors == 0 ) {
318+ image -> palette .numColors = 1 ;
319+ }
320+ } else {
321+ // No other color is permitted to be transparency
322+ if (memcmp (& image -> palette .colors [0 ], & color , sizeof (struct Color )) != 0 ) {
323+ FATAL_ERROR ("Transparency color is not uniform\n" );
324+ }
325+ }
326+ } else if (image -> palette .numColors == 0 ) {
327+ // Haven't registered a color yet, and the very first pixel is not transparency
328+ memcpy (& image -> palette .colors [1 ], & color , sizeof (struct Color ));
329+ image -> palette .numColors = 2 ;
330+ colorIdx = 1 ;
331+ } else {
332+ // Assume that palette is arranged in order of use, excluding transparency
333+ // It is not known whether this holds for retail ROMs
334+ for (colorIdx = 1 ; colorIdx < 4096 && colorIdx < image -> palette .numColors ; colorIdx ++ ) {
335+ if (memcmp (& image -> palette .colors [colorIdx ], & color , sizeof (struct Color )) == 0 ) {
336+ break ;
337+ }
338+ }
339+ if (colorIdx == image -> palette .numColors ) {
340+ if (colorIdx == 4096 ) {
341+ FATAL_ERROR ("Too many unique colors for DS object extpltt\n" );
342+ }
343+ memcpy (& image -> palette .colors [colorIdx ], & color , sizeof (struct Color ));
344+ image -> palette .numColors ++ ;
345+ }
346+ }
347+ * dest ++ = colorIdx & 0xFF ;
348+ } else {
349+ * dest ++ = src [idxComponentY * pitch + idxComponentX ];
350+ }
288351 }
289352 }
290353 }
@@ -826,7 +889,7 @@ void ReadNtrScrn(char *path, struct NSCRFile **ppScrnHeader) {
826889 free (data );
827890}
828891
829- static inline uint32_t tileToPixelOffset (uint32_t tileIdx , uint32_t width , int bitDepth ) {
892+ static inline uint32_t NSCR_tileToPixelOffset (uint32_t tileIdx , uint32_t width , int bitDepth ) {
830893 div_t tile_yx = div (tileIdx , width / 8 );
831894 return tile_yx .quot * bitDepth * width + tile_yx .rem * bitDepth ;
832895}
@@ -893,7 +956,7 @@ void ApplyScrnToImage(char *scrnFilePath, struct Image *image) {
893956 int i , x , y , xOffset , yOffset ;
894957
895958 for (i = 0 ; i < numTiles ; ++ i ) {
896- dstOffset = tileToPixelOffset (i , pScrnHeader -> scrnWidth , 8 * outSizeMul / outSizeDiv );
959+ dstOffset = NSCR_tileToPixelOffset (i , pScrnHeader -> scrnWidth , 8 * outSizeMul / outSizeDiv );
897960 if (pScrnHeader -> scrnMode == 1 ) {
898961 tileIdx = pScrnHeader -> data [i ];
899962 } else {
@@ -903,7 +966,7 @@ void ApplyScrnToImage(char *scrnFilePath, struct Image *image) {
903966 vFlip = (tileData >> 11 ) & 1 ;
904967 plttIndex = (tileData >> 12 ) & 0xF ;
905968 }
906- srcOffset = tileToPixelOffset (tileIdx , image -> width , image -> bitDepth );
969+ srcOffset = NSCR_tileToPixelOffset (tileIdx , image -> width , image -> bitDepth );
907970 for (y = 0 ; y < 8 ; ++ y ) {
908971 yOffset = vFlip ? 7 - y : y ;
909972 for (x = 0 ; x < 8 ; ++ x ) {
0 commit comments