mirror of
https://github.com/gbdk-2020/gbdk-2020.git
synced 2026-02-20 00:32:21 +01:00
Add hi-color conversion utility and example
This commit is contained in:
4
LICENSE
4
LICENSE
@@ -43,3 +43,7 @@ MIT License. @Zal0 is the original author + additional contributors
|
||||
LCC License, traditionally named as the "CPYRIGHT" file
|
||||
|
||||
|
||||
### png2hicolorgb:
|
||||
Public Domain. Glen Cook and others are the original authors, @bbbbbr authored the cross platform console port
|
||||
|
||||
|
||||
|
||||
13
Makefile
13
Makefile
@@ -151,6 +151,8 @@ endif
|
||||
@$(MAKE) -C $(GBDKSUPPORTDIR)/makecom TOOLSPREFIX=$(TOOLSPREFIX) TARGETDIR=$(TARGETDIR)/ --no-print-directory
|
||||
@echo Building makebin
|
||||
@$(MAKE) -C $(GBDKSUPPORTDIR)/makebin TOOLSPREFIX=$(TOOLSPREFIX) TARGETDIR=$(TARGETDIR)/ --no-print-directory
|
||||
@echo Building png2hicolorgb
|
||||
@$(MAKE) -C $(GBDKSUPPORTDIR)/png2hicolorgb TOOLSPREFIX=$(TOOLSPREFIX) TARGETDIR=$(TARGETDIR)/ --no-print-directory
|
||||
@echo
|
||||
|
||||
gbdk-support-install: gbdk-support-build $(BUILDDIR)/bin
|
||||
@@ -184,6 +186,9 @@ gbdk-support-install: gbdk-support-build $(BUILDDIR)/bin
|
||||
@echo Installing makebin
|
||||
@cp $(GBDKSUPPORTDIR)/makebin/makebin$(EXEEXTENSION) $(BUILDDIR)/bin/makebin$(EXEEXTENSION)
|
||||
@$(TARGETSTRIP) $(BUILDDIR)/bin/makebin$(EXEEXTENSION)
|
||||
@echo Installing png2hicolorgb
|
||||
@cp $(GBDKSUPPORTDIR)/png2hicolorgb/png2hicolorgb$(EXEEXTENSION) $(BUILDDIR)/bin/png2hicolorgb$(EXEEXTENSION)
|
||||
@$(TARGETSTRIP) $(BUILDDIR)/bin/png2hicolorgb$(EXEEXTENSION)
|
||||
@echo
|
||||
|
||||
gbdk-support-clean:
|
||||
@@ -202,6 +207,8 @@ gbdk-support-clean:
|
||||
@$(MAKE) -C $(GBDKSUPPORTDIR)/makecom clean
|
||||
@echo Cleaning makebin
|
||||
@$(MAKE) -C $(GBDKSUPPORTDIR)/makebin clean
|
||||
@echo Cleaning png2hicolorgb
|
||||
@$(MAKE) -C $(GBDKSUPPORTDIR)/png2hicolorgb clean
|
||||
@echo
|
||||
|
||||
# Rules for gbdk-lib
|
||||
@@ -468,6 +475,12 @@ ifneq (,$(wildcard $(BUILDDIR)/bin/))
|
||||
echo \`\`\` >> $(TOOLCHAIN_DOCS_FILE);
|
||||
$(BUILDDIR)/bin/png2asset >> $(TOOLCHAIN_DOCS_FILE) 2>&1
|
||||
echo \`\`\` >> $(TOOLCHAIN_DOCS_FILE)
|
||||
# png2hicolorgb
|
||||
echo \@anchor png2hicolorgb-settings >> $(TOOLCHAIN_DOCS_FILE);
|
||||
echo \# png2hicolorgb settings >> $(TOOLCHAIN_DOCS_FILE);
|
||||
echo \`\`\` >> $(TOOLCHAIN_DOCS_FILE);
|
||||
$(BUILDDIR)/bin/png2hicolorgb -h >> $(TOOLCHAIN_DOCS_FILE) 2>&1
|
||||
echo \`\`\` >> $(TOOLCHAIN_DOCS_FILE)
|
||||
endif
|
||||
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
gbdk-4.2.0
|
||||
- Library fixes/improvements
|
||||
- Added: set_bkg_attributes(), set_bkg_submap_attributes(), set_bkg_attribute_xy()
|
||||
- Added set_bkg_attributes(), set_bkg_submap_attributes(), set_bkg_attribute_xy()
|
||||
- Some functions renamed (old names will work for now)
|
||||
- vsync(): replaces wait_vbl_done()
|
||||
- set_default_palette(): replaces cgb_compatibility()
|
||||
@@ -21,17 +21,19 @@ gbdk-4.2.0
|
||||
- Refactored interrupts to use less space
|
||||
- lcc "lcc"
|
||||
- Fixed `--sdccbindir`
|
||||
- utility_png2asset "png2asset"
|
||||
- png2asset
|
||||
- Added `-repair_index_pal`: Tries to repair tile palettes
|
||||
- Added `-no_palettes`: Do not export palette data
|
||||
- Fixed support for indexed color pngs with less than 8 bits color depth
|
||||
- Fixed incorrect palettes when different colors have same luma value
|
||||
- Added png2hicolorgb
|
||||
- Added sdld6808 (for NES)
|
||||
- Examples
|
||||
- Wav Playback: Improved support on AGB/AGS hardware
|
||||
- Large Map: Added color for supported platforms
|
||||
- Added GB-Type example
|
||||
- Updated documentation
|
||||
- Added Game Boy Color Hi-Color example using png2hicolorgb
|
||||
- Updated documentation and improved search
|
||||
|
||||
gbdk-4.1.1
|
||||
- Library fixes/improvements
|
||||
|
||||
@@ -308,3 +308,30 @@ Converts a binary .rom file to .msxdos com format, including splitting the banks
|
||||
|
||||
- For detailed settings see @ref makecom-settings
|
||||
|
||||
|
||||
@anchor utility_png2hicolorgb
|
||||
## png2hicolorgb
|
||||
An updated version of Glen Cook's Windows GUI "hicolour.exe" 1.2 conversion tool for the Game Boy Color. The starting code base was the 1.2 release.
|
||||
|
||||
- For detailed settings see @ref png2hicolorgb-settings
|
||||
|
||||
"Hi Color" on the Game Boy Color is a technique for displaying backgrounds with thousands of colors instead being limtied to 32 colors for the entire screen background. It achieves this by changing ~16 colors of the background palette per scanline. The main tradeoffs are that it uses much of the Game Boy's available cpu processing per frame and requires more ROM space. The tile patterns, map, attributes and per-scanline palettes are pre-calculated using the PC based conversion tool.
|
||||
|
||||
Example: `png2hicolorgb myimage.png --csource -o=my_output_filename`
|
||||
Example with higher quality (slower conversion): `png2hicolorgb myimage.png --csource -o=my_output_filename --type=3 -L=2 -R=2`
|
||||
|
||||
```
|
||||
Historical credits and info:
|
||||
Original Concept : Icarus Productions
|
||||
Original Code : Jeff Frohwein
|
||||
Full Screen Modification : Anon
|
||||
Adaptive Code : Glen Cook
|
||||
Windows Interface : Glen Cook
|
||||
Additional Windows Programming : Rob Jones
|
||||
Original Quantiser Code : Benny
|
||||
Quantiser Conversion : Glen Cook
|
||||
```
|
||||
|
||||
### Additional Details
|
||||
For technical details about the conversion process and rendering, see:
|
||||
https://github.com/bbbbbr/png2hicolorgb
|
||||
|
||||
@@ -38,6 +38,7 @@ https://github.com/gbdk-2020/gbdk-2020/releases
|
||||
- Workaround for possible HALT bug in Crash Handler
|
||||
- Refactored interrupts to use less space
|
||||
- Toolchain / Utilities
|
||||
- Added @ref utility_png2hiclorgb "png2hicolorgb"
|
||||
- @ref lcc "lcc"
|
||||
- Fixed `--sdccbindir`
|
||||
- Removed the unused `-DINT_16_BITS` from the default SDCC compiler and preprocessor arguments
|
||||
@@ -59,7 +60,8 @@ https://github.com/gbdk-2020/gbdk-2020/releases
|
||||
- Metasprites: Added sub-palette switching for GBC and NES, software metasprite flipping for sms/gg
|
||||
- Large Map: Added color for supported platforms
|
||||
- LCD ISR Wobble: Improved interrupt flag settings
|
||||
- Added GB-Type example:
|
||||
- Added GB-Type example
|
||||
- Added Game Boy Color Hi-Color example using @ref utility_png2hiclorgb "png2hicolorgb"
|
||||
- Docs:
|
||||
- Improved search to do partial matches instead of matching start of string only
|
||||
- Added SDAS assembler manual (asmlnk_manual.txt)
|
||||
|
||||
@@ -598,3 +598,42 @@ usage: png2asset <file>.png [options]
|
||||
-bin export to binary format
|
||||
-transposed export transposed (column-by-column instead of row-by-row)
|
||||
```
|
||||
@anchor png2hicolorgb-settings
|
||||
# png2hicolorgb settings
|
||||
```
|
||||
|
||||
png2hicolorgb input_image.png [options]
|
||||
version 1.4.1: bbbbbr. Based on Glen Cook's Windows GUI "hicolour.exe" 1.2
|
||||
Convert an image to Game Boy Hi-Color format
|
||||
|
||||
Options
|
||||
-h : Show this help
|
||||
-v* : Set log level: "-v" verbose, "-vQ" quiet, "-vE" only errors, "-vD" debug
|
||||
-o <file> : Set base output filename (otherwise from input image)
|
||||
--csource : Export C source format with incbins for data files
|
||||
--bank=N : Set bank number for C source output where N is decimal bank number 1-511
|
||||
--type=N : Set conversion type where N is one of below
|
||||
1: Median Cut - No Dither (*Default*)
|
||||
2: Median Cut - With Dither
|
||||
3: Wu Quantiser
|
||||
-p : Show screen attribute pattern options (no processing)
|
||||
-L=N : Set Left screen attribute pattern where N is decimal entry (-p to show patterns)
|
||||
-R=N : Set Right screen attribute pattern where N is decimal entry (-p to show patterns)
|
||||
--vaddrid : Map uses vram id (128->255->0->127) instead of (*Default*) sequential tile order (0->255)
|
||||
--nodedupe : Turn off tile pattern deduplication
|
||||
|
||||
Example 1: "png2hicolorgb myimage.png"
|
||||
Example 2: "png2hicolorgb myimage.png --csource -o=my_output_filename"
|
||||
* Default settings provide good results. Better quality but slower: "--type=3 -L=2 -R=2"
|
||||
|
||||
Historical credits and info:
|
||||
Original Concept : Icarus Productions
|
||||
Original Code : Jeff Frohwein
|
||||
Full Screen Modification : Anon
|
||||
Adaptive Code : Glen Cook
|
||||
Windows Interface : Glen Cook
|
||||
Additional Windows Programming : Rob Jones
|
||||
Original Quantiser Code : Benny
|
||||
Quantiser Conversion : Glen Cook
|
||||
|
||||
```
|
||||
|
||||
109
gbdk-lib/examples/gb/hicolor/Makefile
Normal file
109
gbdk-lib/examples/gb/hicolor/Makefile
Normal file
@@ -0,0 +1,109 @@
|
||||
# If you move this project you can change the directory
|
||||
# to match your GBDK root directory (ex: GBDK_HOME = "C:/GBDK/"
|
||||
ifndef GBDK_HOME
|
||||
GBDK_HOME = ../../../
|
||||
endif
|
||||
|
||||
LCC = $(GBDK_HOME)bin/lcc
|
||||
LCC = $(GBDK_HOME)bin/lcc
|
||||
|
||||
# You can set flags for LCC here
|
||||
LCCFLAGS += -debug # Uncomment to enable debug output
|
||||
# LCCFLAGS += -v # Uncomment for lcc verbose output
|
||||
LCCFLAGS += -Wm-yC # GB Color required for Hi Color
|
||||
LCCFLAGS += -Wf-MMD -Wf-Wp-MP # Header file dependency output (-MMD) for Makefile use + per-header Phoney rules (-MP)
|
||||
LCCFLAGS += -Wl-yt0x19 # MBC5
|
||||
LCCFLAGS += -autobank -Wb-v -Wb-ext=.rel # Auto-bank packing
|
||||
|
||||
# For testing only: randomize autobank assignment
|
||||
# LCCFLAGS += -Wb-random -Wb-max=3 -Wb-v
|
||||
|
||||
# For Hi Color:
|
||||
PNG2HICOLORGB = $(GBDK_HOME)bin/png2hicolorgb
|
||||
# Use conversion method type 1, Faster Adaptive attribute sizing for Left / Right side of screen, C source output
|
||||
# Bank 255 for auto-banking
|
||||
HICOLOR_FLAGS = --type=1 -L=1 -R=1 --csource --bank=255
|
||||
# Add the object dir as an include dir since that's
|
||||
# where the converted png source files will get generated
|
||||
LCCFLAGS += -I$(OBJDIR) -I$(SRCDIR)
|
||||
|
||||
|
||||
# You can set the name of the .gb ROM file here
|
||||
PROJECTNAME = hicolor_pic
|
||||
|
||||
BINDIR = bin
|
||||
SRCDIR = src
|
||||
OBJDIR = obj
|
||||
RESDIR = res
|
||||
HICOLORDIR = $(RESDIR)/hicolor
|
||||
MKDIRS = $(OBJDIR) $(BINDIR) # See bottom of Makefile for directory auto-creation
|
||||
|
||||
|
||||
BINS = $(BINDIR)/$(PROJECTNAME).gb
|
||||
CSOURCES = $(foreach dir,$(SRCDIR),$(notdir $(wildcard $(dir)/*.c))) $(foreach dir,$(RESDIR),$(notdir $(wildcard $(dir)/*.c)))
|
||||
ASMSOURCES = $(foreach dir,$(SRCDIR),$(notdir $(wildcard $(dir)/*.s)))
|
||||
|
||||
# For Hi Color:
|
||||
# The HICOLORS entries should be first in the OBJS list so they get generated before anything which might depend on them
|
||||
HICOLORS = $(foreach dir,$(HICOLORDIR),$(notdir $(wildcard $(dir)/*.png)))
|
||||
HICOLOR_SRCS = $(HICOLORS:%.png=$(OBJDIR)/%.c) $(HICOLORS:%.png=$(OBJDIR)/%_pal.c)
|
||||
OBJS = $(HICOLOR_SRCS:%.c=%.o) $(CSOURCES:%.c=$(OBJDIR)/%.o) $(ASMSOURCES:%.s=$(OBJDIR)/%.o)
|
||||
|
||||
all: $(BINS)
|
||||
|
||||
# Dependencies (using output from -Wf-MMD -Wf-Wp-MP)
|
||||
DEPS = $(OBJS:%.o=%.d)
|
||||
|
||||
-include $(DEPS)
|
||||
|
||||
|
||||
# == Start Hi Color conversion ==
|
||||
|
||||
# Convert png images in res/hicolor to .c files (which incbin the generated .til/.map/.pal/.atr files)
|
||||
# The resulting C files will get compiled to object files afterward
|
||||
.SECONDEXPANSION:
|
||||
$(OBJDIR)/%.c: $(HICOLORDIR)/%.png
|
||||
$(PNG2HICOLORGB) $< $(HICOLOR_FLAGS) -o $@
|
||||
|
||||
# Prevent make from deleting intermediary generated hi-color C source files
|
||||
.SECONDARY: $(HICOLOR_SRCS)
|
||||
|
||||
# Compile hicolor .c files in "obj/" to .o object files
|
||||
$(OBJDIR)/%.o: $(OBJDIR)/%.c
|
||||
$(LCC) $(LCCFLAGS) -c -o $@ $<
|
||||
|
||||
# == End Hi Color conversion ==
|
||||
|
||||
|
||||
# Compile .c files in "src/" to .o object files
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.c
|
||||
$(LCC) $(LCCFLAGS) -c -o $@ $<
|
||||
|
||||
# Compile .c files in "res/" to .o object files
|
||||
$(OBJDIR)/%.o: $(RESDIR)/%.c
|
||||
$(LCC) $(LCCFLAGS) -c -o $@ $<
|
||||
|
||||
# Compile .s assembly files in "src/" to .o object files
|
||||
$(OBJDIR)/%.o: $(SRCDIR)/%.s
|
||||
$(LCC) $(LCCFLAGS) -c -o $@ $<
|
||||
|
||||
# If needed, compile .c files in "src/" to .s assembly files
|
||||
# (not required if .c is compiled directly to .o)
|
||||
$(OBJDIR)/%.s: $(SRCDIR)/%.c
|
||||
$(LCC) $(LCCFLAGS) -S -o $@ $<
|
||||
|
||||
# Link the compiled object files into a .gb ROM file
|
||||
$(BINS): $(OBJS)
|
||||
$(LCC) $(LCCFLAGS) -o $(BINS) $(OBJS)
|
||||
|
||||
|
||||
clean:
|
||||
rm -f $(OBJDIR)/*.* $(BINDIR)/*.*
|
||||
|
||||
compile.bat: Makefile
|
||||
@echo "REM Automatically generated from Makefile" > compile.bat
|
||||
@make -sn | sed y/\\//\\\\/ | sed s/mkdir\ -p\/mkdir\/ | grep -v make >> compile.bat
|
||||
|
||||
# create necessary directories after Makefile is parsed but before build
|
||||
# info prevents the command from being pasted into the makefile
|
||||
$(info $(shell mkdir -p $(MKDIRS)))
|
||||
16
gbdk-lib/examples/gb/hicolor/Readme.md
Normal file
16
gbdk-lib/examples/gb/hicolor/Readme.md
Normal file
@@ -0,0 +1,16 @@
|
||||
# GBDK Example
|
||||
This example Requires GBDK-2020 4.2.0 or higher (due to using `vsync()`)
|
||||
|
||||
PNG images placed in the res/hicolor folder will get automatically converted and compiled.
|
||||
|
||||
To use them, include the automatically generated header file (based on the png filename) and then use the `hicolor_start()` and `hicolor_stop()` functions.
|
||||
|
||||
# Pallete ISR
|
||||
The new palette update ISR is contributed by Toxa
|
||||
https://github.com/untoxa
|
||||
|
||||
|
||||
# Example image
|
||||
Example image Pixel art originally by RodrixAP under Creative Commons Attribution 2.0 Generic (CC BY 2.0)
|
||||
https://www.flickr.com/photos/rodrixap/10591266994/in/album-72157637154901153/
|
||||
|
||||
BIN
gbdk-lib/examples/gb/hicolor/res/hicolor/example_image.png
Normal file
BIN
gbdk-lib/examples/gb/hicolor/res/hicolor/example_image.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 48 KiB |
BIN
gbdk-lib/examples/gb/hicolor/res/hicolor/test_pattern_short.png
Normal file
BIN
gbdk-lib/examples/gb/hicolor/res/hicolor/test_pattern_short.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 12 KiB |
BIN
gbdk-lib/examples/gb/hicolor/res/hicolor/test_pattern_tall.png
Normal file
BIN
gbdk-lib/examples/gb/hicolor/res/hicolor/test_pattern_tall.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 22 KiB |
164
gbdk-lib/examples/gb/hicolor/src/gbc_hicolor.c
Normal file
164
gbdk-lib/examples/gb/hicolor/src/gbc_hicolor.c
Normal file
@@ -0,0 +1,164 @@
|
||||
// TODO: Permissive License
|
||||
|
||||
#include <gbdk/platform.h>
|
||||
#include <gbdk/incbin.h>
|
||||
#include <gb/isr.h>
|
||||
|
||||
#include <gbc_hicolor.h>
|
||||
|
||||
#define MIN(A,B) ((A)<(B)?(A):(B))
|
||||
|
||||
static uint16_t SP_SAVE;
|
||||
static uint8_t STAT_SAVE;
|
||||
static uint8_t * p_hicolor_palettes;
|
||||
static uint8_t hicolor_palettes_bank;
|
||||
static uint8_t hicolor_last_scanline;
|
||||
|
||||
|
||||
// ISR function which updates 4 CGB palettes per scanline
|
||||
// alternating between Palettes 0-3 and 4-7
|
||||
void hicolor_palette_isr(void) NONBANKED {
|
||||
__asm
|
||||
ldh a, (__current_bank) ; switch ROM bank
|
||||
push af
|
||||
ld a, (_hicolor_palettes_bank)
|
||||
or a
|
||||
jr z, 3$
|
||||
ldh (__current_bank), a
|
||||
ld (_rROMB0), a
|
||||
3$:
|
||||
ld (_SP_SAVE), sp ; save SP
|
||||
|
||||
ld hl, #_p_hicolor_palettes ; load address of picture palettes buffer
|
||||
ld a, (hl+)
|
||||
ld d, (hl)
|
||||
ld e, a
|
||||
|
||||
ldh a, (_SCY_REG)
|
||||
swap a
|
||||
ld l, a
|
||||
and #0x0f
|
||||
ld h, a
|
||||
ld a, #0xf0
|
||||
and l
|
||||
ld l, a
|
||||
add hl, hl
|
||||
add hl, de ; offset address by SCY * (4 * 4 * 2)
|
||||
ld sp, hl
|
||||
|
||||
rlca ; compensate odd/even line
|
||||
and #0x20 ; if odd then start from 4-th palette; offset == 32
|
||||
or #BCPSF_AUTOINC ; set auto-increment
|
||||
|
||||
ld hl, #_BCPS_REG
|
||||
ld (hl+), a ; HL now points to BCPD
|
||||
|
||||
ld c, #(8 * 4) ; read and set the the colors that come from previous lines
|
||||
2$:
|
||||
pop de
|
||||
ld (hl), e
|
||||
ld (hl), d
|
||||
dec c
|
||||
jr nz, 2$
|
||||
|
||||
0$:
|
||||
ldh a, (_STAT_REG)
|
||||
and #STATF_BUSY
|
||||
jr z, 0$ ; wait for mode 3
|
||||
|
||||
ldh a, (_STAT_REG)
|
||||
ld (_STAT_SAVE), a
|
||||
|
||||
ld a, #STATF_MODE00
|
||||
ldh (_STAT_REG), a
|
||||
xor a
|
||||
ldh (_IF_REG), a
|
||||
|
||||
1$:
|
||||
pop bc ; preload the first two colors
|
||||
pop de
|
||||
|
||||
xor a
|
||||
ldh (_IF_REG), a
|
||||
halt ; wait for mode 0
|
||||
|
||||
ld (hl), c ; set the first two colors
|
||||
ld (hl), b
|
||||
ld (hl), e
|
||||
ld (hl), d
|
||||
|
||||
.rept (4*4)-2 ; read and set four palettes except the two previously set colors
|
||||
pop de
|
||||
ld (hl), e
|
||||
ld (hl), d
|
||||
.endm
|
||||
|
||||
ld a, (_hicolor_last_scanline)
|
||||
ld c, a
|
||||
ldh a, (_LY_REG)
|
||||
cp c
|
||||
jr c, 1$ ; load the next 4 palettes
|
||||
|
||||
ld a, (_STAT_SAVE)
|
||||
ldh (_STAT_REG), a
|
||||
xor a
|
||||
ldh (_IF_REG), a
|
||||
|
||||
ld sp, #_SP_SAVE
|
||||
pop hl
|
||||
ld sp, hl ; restore SP
|
||||
|
||||
pop af
|
||||
ldh (__current_bank), a
|
||||
ld (_rROMB0), a
|
||||
|
||||
ret
|
||||
__endasm;
|
||||
}
|
||||
|
||||
|
||||
// Loads Tile Patterns, Map and Map Attributes for the HiColor image,
|
||||
// then installs the HiColor ISR handler which updates palettes per scanline.
|
||||
//
|
||||
// The intput argument should be a pointer to the struct generated by the
|
||||
// png2hicolorgb program with C source output mode enabled
|
||||
void hicolor_start(const hicolor_data * p_hicolor, const uint8_t hicolor_bank, const uint8_t hicolor_bank_pal) NONBANKED {
|
||||
// prevent installing HiColor ISR twice
|
||||
CRITICAL {
|
||||
remove_LCD(hicolor_palette_isr);
|
||||
}
|
||||
|
||||
if (!p_hicolor) return;
|
||||
hicolor_palettes_bank = hicolor_bank_pal;
|
||||
|
||||
uint8_t bank_save = _current_bank;
|
||||
if (hicolor_bank) SWITCH_ROM(hicolor_bank);
|
||||
|
||||
// Copy address of palette into local var used by HiColor ISR
|
||||
p_hicolor_palettes = p_hicolor->p_palette;
|
||||
|
||||
// TODO: if less than screen height, then converter must emit tail palettes and the cutting scanline must be moved accordingly
|
||||
hicolor_last_scanline = (p_hicolor->height_in_tiles > DEVICE_SCREEN_HEIGHT) ? (DEVICE_SCREEN_PX_HEIGHT - 1) : ((p_hicolor->height_in_tiles << 3) - 1);
|
||||
|
||||
// Load the first 256 tiles or less and set BG Map
|
||||
VBK_REG = VBK_BANK_0;
|
||||
set_bkg_data(0u, MIN(p_hicolor->tile_count, 256), p_hicolor->p_tiles);
|
||||
set_bkg_tiles(0u, 0u, DEVICE_SCREEN_WIDTH, p_hicolor->height_in_tiles, p_hicolor->p_map);
|
||||
|
||||
// Load remaining 256 tiles and set Attribute Map into alternate bank
|
||||
VBK_REG = VBK_BANK_1;
|
||||
if (p_hicolor->tile_count > 256) set_bkg_data(0u, (p_hicolor->tile_count - 256), p_hicolor->p_tiles + (256 * 16));
|
||||
set_bkg_tiles(0, 0, DEVICE_SCREEN_WIDTH, p_hicolor->height_in_tiles, p_hicolor->p_attribute_map);
|
||||
VBK_REG = VBK_BANK_0;
|
||||
|
||||
SWITCH_ROM(bank_save);
|
||||
|
||||
// Set up and install the HiColor ISR
|
||||
CRITICAL {
|
||||
LYC_REG = 152;
|
||||
STAT_REG = STATF_LYC;
|
||||
// install the HiColor ISR
|
||||
add_LCD(hicolor_palette_isr);
|
||||
}
|
||||
set_interrupts(IE_REG | LCD_IFLAG);
|
||||
}
|
||||
27
gbdk-lib/examples/gb/hicolor/src/gbc_hicolor.h
Normal file
27
gbdk-lib/examples/gb/hicolor/src/gbc_hicolor.h
Normal file
@@ -0,0 +1,27 @@
|
||||
// TODO: Permissive License
|
||||
|
||||
#ifndef GBC_HICOLOR_H
|
||||
#define GBC_HICOLOR_H
|
||||
|
||||
#define HICOLOR_VAR(varname) varname ## _data
|
||||
|
||||
typedef struct hicolor_data {
|
||||
uint16_t tile_count;
|
||||
uint8_t height_in_tiles;
|
||||
uint8_t * p_tiles;
|
||||
uint8_t * p_map;
|
||||
uint8_t * p_attribute_map;
|
||||
uint8_t * p_palette;
|
||||
} hicolor_data;
|
||||
|
||||
// Loads Tile Patterns, Map and Map Attributes for the HiColor image,
|
||||
// then installs the HiColor ISR handler which updates palettes per scanline.
|
||||
void hicolor_start(const hicolor_data * p_hicolor, const uint8_t hicolor_bank, const uint8_t hicolor_bank_pal) NONBANKED;
|
||||
|
||||
// De-installs the HiColor ISR handler
|
||||
inline void hicolor_stop(void) {
|
||||
hicolor_start(NULL, 0, 0);
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
114
gbdk-lib/examples/gb/hicolor/src/main.c
Normal file
114
gbdk-lib/examples/gb/hicolor/src/main.c
Normal file
@@ -0,0 +1,114 @@
|
||||
#include <gbdk/platform.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <gbc_hicolor.h>
|
||||
|
||||
// GBC HiColor images; header file names align with png file names
|
||||
#include "example_image.h"
|
||||
#include "test_pattern_tall.h"
|
||||
#include "test_pattern_short.h"
|
||||
|
||||
|
||||
#define BG_LAST_TILE 255u
|
||||
const uint8_t blank_tile[] = {0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0};
|
||||
|
||||
#define ARRAY_LEN(A) sizeof(A) / sizeof(A[0])
|
||||
|
||||
uint8_t buttons, buttons_prev;
|
||||
#define UPDATE_BUTTONS() (buttons_prev = buttons, buttons = joypad())
|
||||
#define BUTTON_TOGGLED(BUTTON_MASK) ((buttons & (~buttons_prev)) & (BUTTON_MASK))
|
||||
#define BUTTON_PRESSED(BUTTON_MASK) (buttons & (BUTTON_MASK))
|
||||
|
||||
typedef struct hicolor_rec_t {
|
||||
uint8_t bank;
|
||||
uint8_t bank_pal;
|
||||
const void * ptr;
|
||||
} hicolor_rec_t;
|
||||
|
||||
// Array of pointers to the generated hicolor data structures
|
||||
const hicolor_rec_t hicolors[] = {
|
||||
{ BANK(test_pattern_tall), BANK(test_pattern_tall_pal), &HICOLOR_VAR(test_pattern_tall) },
|
||||
{ BANK(example_image), BANK(example_image_pal), &HICOLOR_VAR(example_image) },
|
||||
{ BANK(test_pattern_short), BANK(test_pattern_short_pal), &HICOLOR_VAR(test_pattern_short) }
|
||||
};
|
||||
|
||||
|
||||
void main(void) {
|
||||
// Image toggling variable, by default show the "example_image"
|
||||
uint8_t img_select = 0;
|
||||
bool first_pass = true;
|
||||
uint8_t scroll_limit = 0;
|
||||
const hicolor_data * p_hicolor;
|
||||
uint8_t hicolor_bank;
|
||||
uint8_t hicolor_bank_pal;
|
||||
|
||||
SHOW_BKG;
|
||||
|
||||
// Require Game Boy Color
|
||||
if (_cpu == CGB_TYPE) {
|
||||
// CGB running in the double speed mode is required
|
||||
cpu_fast();
|
||||
|
||||
while(true) {
|
||||
|
||||
vsync();
|
||||
UPDATE_BUTTONS();
|
||||
|
||||
// Change displayed Hi Color image when pressing A or B
|
||||
if (BUTTON_TOGGLED(J_A | J_B) || first_pass) {
|
||||
|
||||
vsync();
|
||||
DISPLAY_OFF;
|
||||
|
||||
// Set current image to show
|
||||
hicolor_bank = hicolors[img_select].bank;
|
||||
hicolor_bank_pal = hicolors[img_select].bank_pal;
|
||||
p_hicolor = (const hicolor_data *)hicolors[img_select].ptr;
|
||||
|
||||
uint8_t bank_save = _current_bank;
|
||||
if (hicolor_bank) SWITCH_ROM(hicolor_bank);
|
||||
|
||||
// Reset Y scroll and set scroll range based on converted image height
|
||||
SCY_REG = 0u;
|
||||
if ((p_hicolor->height_in_tiles * 8u) > DEVICE_SCREEN_PX_HEIGHT)
|
||||
scroll_limit = ((p_hicolor->height_in_tiles * 8u) - DEVICE_SCREEN_PX_HEIGHT);
|
||||
else scroll_limit = 0;
|
||||
|
||||
// Optional:
|
||||
// If the Hi Color image is shorter than screen height
|
||||
// then fill the remaining screen area with a tile.
|
||||
//
|
||||
// Put the tile at the end of CGB tile pattern vram since
|
||||
// the short Hi Color image will be too small to use all of it.
|
||||
if ((p_hicolor->height_in_tiles * 8u) < DEVICE_SCREEN_PX_HEIGHT) {
|
||||
VBK_REG = VBK_BANK_1;
|
||||
set_bkg_data(BG_LAST_TILE, 1u, blank_tile);
|
||||
fill_bkg_rect(0u, (p_hicolor->height_in_tiles), DEVICE_SCREEN_WIDTH, DEVICE_SCREEN_HEIGHT, BKGF_BANK1);
|
||||
VBK_REG = VBK_BANK_0;
|
||||
fill_bkg_rect(0u, (p_hicolor->height_in_tiles), DEVICE_SCREEN_WIDTH, DEVICE_SCREEN_HEIGHT, BG_LAST_TILE);
|
||||
}
|
||||
|
||||
SWITCH_ROM(bank_save);
|
||||
|
||||
// Load and display the HiColor image
|
||||
hicolor_start(p_hicolor, hicolor_bank, hicolor_bank_pal);
|
||||
|
||||
DISPLAY_ON;
|
||||
|
||||
// Cycle through which image to show next
|
||||
img_select++;
|
||||
if (img_select == ARRAY_LEN(hicolors)) img_select = 0;
|
||||
|
||||
first_pass = false;
|
||||
}
|
||||
// Scroll Up/Down if available
|
||||
else if (BUTTON_PRESSED(J_UP)) {
|
||||
if (SCY_REG) SCY_REG--;
|
||||
} else if (BUTTON_PRESSED(J_DOWN)) {
|
||||
if (SCY_REG < scroll_limit) SCY_REG++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
45
gbdk-support/png2hicolorgb/Makefile
Normal file
45
gbdk-support/png2hicolorgb/Makefile
Normal file
@@ -0,0 +1,45 @@
|
||||
ifndef TARGETDIR
|
||||
TARGETDIR = /opt/gbdk
|
||||
endif
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
BUILD_OS := Windows_NT
|
||||
LDFLAGS = -s -static
|
||||
else
|
||||
BUILD_OS := $(shell uname -s)
|
||||
LDFLAGS = -s
|
||||
endif
|
||||
|
||||
# Target older macOS version than whatever build OS is for better compatibility
|
||||
ifeq ($(BUILD_OS),Darwin)
|
||||
export MACOSX_DEPLOYMENT_TARGET=10.10
|
||||
endif
|
||||
|
||||
CC = $(TOOLSPREFIX)gcc
|
||||
CFLAGS = -O -Wno-incompatible-pointer-types -DGBDKLIBDIR=\"$(TARGETDIR)\"
|
||||
CFLAGS += -Isrc -Isrc/lodepng -Isrc/hicolor
|
||||
OBJ = src/common.o \
|
||||
src/tile_dedupe.o \
|
||||
src/lodepng/lodepng.o \
|
||||
src/hicolor/Wu.o \
|
||||
src/hicolor/median.o \
|
||||
src/hicolor/hicolour.o \
|
||||
src/c_source.o \
|
||||
src/logging.o \
|
||||
src/files.o \
|
||||
src/options.o \
|
||||
src/main.o \
|
||||
src/path_ops.o \
|
||||
src/image_load.o
|
||||
|
||||
BIN = png2hicolorgb
|
||||
|
||||
all: $(BIN)
|
||||
|
||||
$(BIN): $(OBJ)
|
||||
$(CC) -o $(BIN) $^ $(CFLAGS) $(LDFLAGS)
|
||||
|
||||
clean:
|
||||
rm -f *.o $(BIN) *~ src/*.o src/lodepng/*.o src/hicolor/*.o
|
||||
rm -f *.exe
|
||||
|
||||
BIN
gbdk-support/png2hicolorgb/png2hicolorgb
Executable file
BIN
gbdk-support/png2hicolorgb/png2hicolorgb
Executable file
Binary file not shown.
169
gbdk-support/png2hicolorgb/src/c_source.c
Normal file
169
gbdk-support/png2hicolorgb/src/c_source.c
Normal file
@@ -0,0 +1,169 @@
|
||||
// See LICENSE file for license details
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "image_info.h"
|
||||
#include "path_ops.h"
|
||||
#include "logging.h"
|
||||
#include "options.h"
|
||||
|
||||
|
||||
// Writes a buffer to a file in C source format
|
||||
// Adds a matching .h if possible
|
||||
//
|
||||
bool file_c_output_write(const char * fname_base, int bank_num, int tile_count, int height_in_tiles) {
|
||||
|
||||
char varname_withpath[MAX_PATH * 2];
|
||||
strcpy(varname_withpath, fname_base);
|
||||
|
||||
// Main C output (Tiles, Map, Attributes)
|
||||
char filename_c[MAX_PATH * 2];
|
||||
strcpy(filename_c, fname_base);
|
||||
strcat(filename_c, ".c");
|
||||
|
||||
// Secondary C output (Palette)
|
||||
// Split from the others for more efficient bank packing
|
||||
char filename_c_pal[MAX_PATH * 2];
|
||||
strcpy(filename_c_pal, fname_base);
|
||||
strcat(filename_c_pal, "_pal.c");
|
||||
|
||||
// Header File
|
||||
char filename_h[MAX_PATH * 2];
|
||||
strcpy(filename_h, fname_base);
|
||||
strcat(filename_h, ".h");
|
||||
|
||||
FILE * file_out;
|
||||
|
||||
// Fix up filename to be usable in the C source file
|
||||
char * varname = (char *)get_filename_from_path(varname_withpath);
|
||||
char * ch = varname;
|
||||
while (*ch != '\0') {
|
||||
if ((*ch == ' ') || (*ch == '-')) *ch = '_';
|
||||
ch++;
|
||||
}
|
||||
|
||||
log_verbose("Writing C format to: %s, %s, %s\n", filename_c, filename_c_pal, filename_h);
|
||||
|
||||
// === C Source output ===
|
||||
file_out = fopen(filename_c, "w");
|
||||
if (file_out) {
|
||||
|
||||
fprintf(file_out,
|
||||
"#include <gbdk/platform.h>\n"
|
||||
"#include <gbdk/incbin.h>\n\n");
|
||||
|
||||
// If Bank Num is set add a .h bank ref
|
||||
if (bank_num != BANK_NUM_UNSET) {
|
||||
fprintf(file_out, "#pragma bank %d\n", bank_num);
|
||||
fprintf(file_out, "BANKREF(%s)\n\n", varname);
|
||||
}
|
||||
|
||||
fprintf(file_out,
|
||||
"#include <gbc_hicolor.h>\n"
|
||||
"\n"
|
||||
"// Generated by png2hicolorgb\n"
|
||||
"\n"
|
||||
"// Note: filepath is relative to the working directory of the tool that is calling it (often a makefile's working directory), NOT to the file it's being included into.\n"
|
||||
"\n"
|
||||
"INCBIN(%s_tiles, \"%s.til\")\n"
|
||||
"INCBIN(%s_map, \"%s.map\")\n"
|
||||
"INCBIN(%s_attr, \"%s.atr\")\n"
|
||||
"\n"
|
||||
"INCBIN_EXTERN(%s_tiles)\n"
|
||||
"INCBIN_EXTERN(%s_map)\n"
|
||||
"INCBIN_EXTERN(%s_attr)\n"
|
||||
"INCBIN_EXTERN(%s_palette)\n"
|
||||
"\n"
|
||||
"const hicolor_data %s_data = {\n"
|
||||
" .tile_count = %du,\n"
|
||||
" .height_in_tiles = %du,\n"
|
||||
" .p_tiles = %s_tiles,\n"
|
||||
" .p_map = %s_map,\n"
|
||||
" .p_attribute_map = %s_attr,\n"
|
||||
" .p_palette = %s_palette\n"
|
||||
"};\n"
|
||||
"\n"
|
||||
,varname, fname_base,
|
||||
varname, fname_base,
|
||||
varname, fname_base,
|
||||
varname, varname, varname, varname,
|
||||
varname,
|
||||
tile_count, height_in_tiles,
|
||||
varname, varname, varname, varname
|
||||
);
|
||||
fclose(file_out);
|
||||
} else {
|
||||
printf("Error: Failed to open output file: %s\n", filename_c);
|
||||
return false;
|
||||
}
|
||||
|
||||
// === C Source output ===
|
||||
file_out = fopen(filename_c_pal, "w");
|
||||
if (file_out) {
|
||||
|
||||
fprintf(file_out,
|
||||
"#include <gbdk/platform.h>\n"
|
||||
"#include <gbdk/incbin.h>\n\n");
|
||||
|
||||
// If Bank Num is set add a .h bank ref
|
||||
if (bank_num != BANK_NUM_UNSET) {
|
||||
fprintf(file_out, "#pragma bank %d\n", bank_num);
|
||||
fprintf(file_out, "BANKREF(%s_pal)\n\n", varname);
|
||||
}
|
||||
|
||||
fprintf(file_out,
|
||||
"#include <gbc_hicolor.h>\n"
|
||||
"\n"
|
||||
"// Generated by png2hicolorgb\n"
|
||||
"\n"
|
||||
"// Note: filepath is relative to the working directory of the tool that is calling it (often a makefile's working directory), NOT to the file it's being included into.\n"
|
||||
"\n"
|
||||
"INCBIN(%s_palette, \"%s.pal\")\n"
|
||||
"\n"
|
||||
,varname, fname_base
|
||||
);
|
||||
fclose(file_out);
|
||||
} else {
|
||||
printf("Error: Failed to open output file: %s\n", filename_c);
|
||||
return false;
|
||||
}
|
||||
|
||||
// === Header output ===
|
||||
file_out = fopen(filename_h, "w");
|
||||
if (file_out) {
|
||||
|
||||
// If Bank Num is set add a .h bank ref
|
||||
if (bank_num != BANK_NUM_UNSET) {
|
||||
fprintf(file_out, "#include <gbdk/platform.h>\n\n");
|
||||
fprintf(file_out, "BANKREF_EXTERN(%s)\n\n", varname);
|
||||
fprintf(file_out, "BANKREF_EXTERN(%s_pal)\n\n", varname);
|
||||
}
|
||||
|
||||
fprintf(file_out,
|
||||
"#ifndef __%s_h_\n"
|
||||
"#define __%s_h_\n"
|
||||
"\n"
|
||||
"#include <gbc_hicolor.h>\n"
|
||||
"\n"
|
||||
"// Generated by png2hicolorgb\n"
|
||||
"\n"
|
||||
"extern const hicolor_data %s_data;\n"
|
||||
"\n"
|
||||
"#endif\n"
|
||||
"\n"
|
||||
,varname, varname,
|
||||
varname
|
||||
);
|
||||
fclose(file_out);
|
||||
} else {
|
||||
printf("Error: Failed to open output file: %s\n", filename_h);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
9
gbdk-support/png2hicolorgb/src/c_source.h
Normal file
9
gbdk-support/png2hicolorgb/src/c_source.h
Normal file
@@ -0,0 +1,9 @@
|
||||
// "c_source.h"
|
||||
|
||||
#ifndef C_SOURCE_H
|
||||
#define C_SOURCE_H
|
||||
|
||||
bool file_c_output_write(const char * fname_base, int bank_num, int tile_count, int height_in_tiles);
|
||||
|
||||
#endif
|
||||
|
||||
17
gbdk-support/png2hicolorgb/src/common.c
Normal file
17
gbdk-support/png2hicolorgb/src/common.c
Normal file
@@ -0,0 +1,17 @@
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "common.h"
|
||||
|
||||
bool exit_error = false;
|
||||
void set_exit_error(void) {
|
||||
exit_error = true;
|
||||
}
|
||||
|
||||
bool get_exit_error(void) {
|
||||
return exit_error;
|
||||
}
|
||||
|
||||
23
gbdk-support/png2hicolorgb/src/common.h
Normal file
23
gbdk-support/png2hicolorgb/src/common.h
Normal file
@@ -0,0 +1,23 @@
|
||||
// See LICENSE file for license details
|
||||
|
||||
#ifndef _COMMON_H
|
||||
#define _COMMON_H
|
||||
|
||||
#define TILE_HEIGHT_PX 8
|
||||
#define TILE_WIDTH_PX 8
|
||||
|
||||
#define MAX_STR_LEN 4096
|
||||
#define DEFAULT_STR_LEN 100
|
||||
|
||||
#define ARRAY_LEN(A) sizeof(A) / sizeof(A[0])
|
||||
|
||||
#define MAX_PATH (MAX_STR_LEN)
|
||||
|
||||
enum {
|
||||
IMG_TYPE_PNG
|
||||
};
|
||||
|
||||
void set_exit_error(void);
|
||||
bool get_exit_error(void);
|
||||
|
||||
#endif // _COMMON_H
|
||||
118
gbdk-support/png2hicolorgb/src/files.c
Normal file
118
gbdk-support/png2hicolorgb/src/files.c
Normal file
@@ -0,0 +1,118 @@
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
|
||||
|
||||
// Read from a file into a buffer (will allocate needed memory)
|
||||
// Returns NULL if reading file didn't succeed
|
||||
uint8_t * file_read_into_buffer(char * filename, uint32_t *ret_size) {
|
||||
|
||||
long fsize;
|
||||
FILE * file_in = fopen(filename, "rb");
|
||||
uint8_t * filedata = NULL;
|
||||
|
||||
if (file_in) {
|
||||
// Get file size
|
||||
fseek(file_in, 0, SEEK_END);
|
||||
fsize = ftell(file_in);
|
||||
if (fsize != -1L) {
|
||||
fseek(file_in, 0, SEEK_SET);
|
||||
|
||||
filedata = (uint8_t *)malloc(fsize);
|
||||
if (filedata) {
|
||||
if (fsize != fread(filedata, 1, fsize, file_in)) {
|
||||
printf("Warning: File read size didn't match expected for %s\n", filename);
|
||||
filedata = NULL;
|
||||
}
|
||||
// Read was successful, set return size
|
||||
*ret_size = fsize;
|
||||
} else printf("ERROR: Failed to allocate memory to read file %s\n", filename);
|
||||
|
||||
} else printf("ERROR: Failed to read size of file %s\n", filename);
|
||||
|
||||
fclose(file_in);
|
||||
} else printf("ERROR: Failed to open input file %s\n", filename);
|
||||
|
||||
return filedata;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Writes a buffer to a file
|
||||
bool file_write_from_buffer(char * filename, uint8_t * p_buf, uint32_t data_len) {
|
||||
|
||||
bool status = false;
|
||||
size_t wrote_bytes;
|
||||
FILE * file_out = fopen(filename, "wb");
|
||||
|
||||
if (file_out) {
|
||||
if (data_len == fwrite(p_buf, 1, data_len, file_out))
|
||||
status = true;
|
||||
else
|
||||
printf("Warning: File write size didn't match expected for %s\n", filename);
|
||||
|
||||
fclose(file_out);
|
||||
} else
|
||||
printf("Warning: Unable to open file: %s\n", filename);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// Read from a file into a buffer (will allocate needed memory)
|
||||
// Returns NULL if reading file didn't succeed
|
||||
char * file_read_into_buffer_char(char * filename, uint32_t *ret_size) {
|
||||
|
||||
long fsize;
|
||||
// On windows windows fread() will auto-translate CRLF to just LF and
|
||||
// report it as one byte read, messing up the size check
|
||||
FILE * file_in = fopen(filename, "rb");
|
||||
char * filedata = NULL;
|
||||
|
||||
if (file_in) {
|
||||
// Get file size
|
||||
fseek(file_in, 0, SEEK_END);
|
||||
fsize = ftell(file_in);
|
||||
if (fsize != -1L) {
|
||||
fseek(file_in, 0, SEEK_SET);
|
||||
|
||||
filedata = (char *)malloc(fsize);
|
||||
if (filedata) {
|
||||
if (fsize != fread(filedata, 1, fsize, file_in)) {
|
||||
printf("Warning: File read size didn't match expected for %s\n", filename);
|
||||
filedata = NULL;
|
||||
}
|
||||
// Read was successful, set return size
|
||||
*ret_size = fsize;
|
||||
} else printf("ERROR: Failed to allocate memory to read file %s\n", filename);
|
||||
|
||||
} else printf("ERROR: Failed to read size of file %s\n", filename);
|
||||
|
||||
fclose(file_in);
|
||||
} else printf("ERROR: Failed to open input file %s\n", filename);
|
||||
|
||||
return filedata;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Writes a buffer to a file
|
||||
bool file_write_from_buffer_char(char * filename, char * p_buf, uint32_t data_len) {
|
||||
|
||||
bool status = false;
|
||||
size_t wrote_bytes;
|
||||
FILE * file_out = fopen(filename, "w");
|
||||
|
||||
if (file_out) {
|
||||
if (data_len == fwrite(p_buf, 1, data_len, file_out))
|
||||
status = true;
|
||||
else
|
||||
printf("Warning: File write size didn't match expected for %s\n", filename);
|
||||
|
||||
fclose(file_out);
|
||||
}
|
||||
return status;
|
||||
}
|
||||
11
gbdk-support/png2hicolorgb/src/files.h
Normal file
11
gbdk-support/png2hicolorgb/src/files.h
Normal file
@@ -0,0 +1,11 @@
|
||||
#ifndef _FILES_H
|
||||
#define _FILES_H
|
||||
|
||||
uint8_t * file_read_into_buffer(char * filename, uint32_t *ret_size);
|
||||
bool file_write_from_buffer(char * filename, uint8_t * p_buf, uint32_t data_len);
|
||||
|
||||
char * file_read_into_buffer_char(char * filename, uint32_t *ret_size);
|
||||
bool file_write_from_buffer_char(char * filename, char * p_buf, uint32_t data_len);
|
||||
|
||||
#endif // _FILES_H
|
||||
|
||||
475
gbdk-support/png2hicolorgb/src/hicolor/Wu.c
Normal file
475
gbdk-support/png2hicolorgb/src/hicolor/Wu.c
Normal file
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
C Implementation of Wu's Color Quantizer (v2.0)
|
||||
-- Xiaolin Wu.
|
||||
From the Graphics Gems.
|
||||
|
||||
Memory hungry.
|
||||
|
||||
Some fixes and additional code by Benny.
|
||||
*/
|
||||
/**********************************************************************
|
||||
C Implementation of Wu's Color Quantizer (v. 2)
|
||||
(see Graphics Gems vol. II, pp. 126-133)
|
||||
|
||||
Author: Xiaolin Wu
|
||||
Dept. of Computer Science
|
||||
Univ. of Western Ontario
|
||||
London, Ontario N6A 5B7
|
||||
wu@csd.uwo.ca
|
||||
|
||||
Algorithm: Greedy orthogonal bipartition of RGB space for variance
|
||||
minimization aided by inclusion-exclusion tricks.
|
||||
For speed no nearest neighbor search is done. Slightly
|
||||
better performance can be expected by more sophisticated
|
||||
but more expensive versions.
|
||||
|
||||
The author thanks Tom Lane at Tom_Lane@G.GP.CS.CMU.EDU for much of
|
||||
additional documentation and a cure to a previous bug.
|
||||
|
||||
Free to distribute, comments and suggestions are appreciated.
|
||||
**********************************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "defines.h"
|
||||
#include "hicolour.h"
|
||||
#include "median.h"
|
||||
#include "wu.h"
|
||||
|
||||
|
||||
#define NOINVERT // RGB or BGR
|
||||
|
||||
//void error(char *s);
|
||||
|
||||
|
||||
#define MAXCOLOR 256
|
||||
#define RED 2
|
||||
#define GREEN 1
|
||||
#define BLUE 0
|
||||
|
||||
|
||||
/* Histogram is in elements 1..HISTSIZE along each axis,
|
||||
element 0 is for base or marginal value.
|
||||
NB: these must start out 0! */
|
||||
s32 wt[BOX][BOX][BOX],mr[BOX][BOX][BOX],mg[BOX][BOX][BOX],mb[BOX][BOX][BOX];
|
||||
float m2[BOX][BOX][BOX];
|
||||
|
||||
s32 ImageSize; /* image size */
|
||||
s32 PalSize; /* color look-up table size */
|
||||
|
||||
u16 *Qadd; // *must* be unsigned?
|
||||
u8 *TrueColorPic;
|
||||
|
||||
|
||||
// s16 AQadd[7*8*3*2]; // Signed in original code, type clash with QAdd and bit shifting
|
||||
u16 AQadd[7*8*3*2];
|
||||
u8 Atag[BOX * BOX * BOX];
|
||||
|
||||
|
||||
/* build 3-D color histogram of counts, r/g/b, c^2 */
|
||||
void Hist3d(s32 *vwt,s32 *vmr,s32 *vmg,s32 *vmb, float *m_2)
|
||||
{
|
||||
s32 ind,r,g,b;
|
||||
s32 inr,ing,inb,table[256];
|
||||
s32 i;
|
||||
|
||||
for (i = 0; i < 256; ++i)
|
||||
table[i] = i * i;
|
||||
|
||||
for (i = 0; i < ImageSize; ++i)
|
||||
{
|
||||
r = TrueColorPic[i*3 ];
|
||||
g = TrueColorPic[i*3+1];
|
||||
b = TrueColorPic[i*3+2];
|
||||
|
||||
inr = (r >> 3) + 1;
|
||||
ing = (g >> 3) + 1;
|
||||
inb = (b >> 3) + 1;
|
||||
Qadd[i] = ind = (inr << 10) + (inr << 6) + inr + (ing << 5) + ing + inb;
|
||||
++vwt[ind];
|
||||
vmr[ind] += r;
|
||||
vmg[ind] += g;
|
||||
vmb[ind] += b;
|
||||
m_2[ind] += (float) (table[r] + table[g] + table[b]);
|
||||
}
|
||||
}
|
||||
|
||||
/* At conclusion of the histogram step, we can interpret
|
||||
* wt[r][g][b] = sum over voxel of P(c)
|
||||
* mr[r][g][b] = sum over voxel of r*P(c) , similarly for mg, mb
|
||||
* m2[r][g][b] = sum over voxel of c^2*P(c)
|
||||
* Actually each of these should be divided by 'size' to give the usual
|
||||
* interpretation of P() as ranging from 0 to 1, but we needn't do that here.
|
||||
*/
|
||||
|
||||
/* We now convert histogram into moments so that we can rapidly calculate
|
||||
* the sums of the above quantities over any desired box.
|
||||
*/
|
||||
|
||||
void Momt3d(s32 *vwt, s32 *vmr, s32 *vmg, s32 *vmb, float *m_2)
|
||||
{
|
||||
u16 ind1,ind2;
|
||||
u8 i,r,g,b;
|
||||
s32 line,line_r,line_g,line_b,area[BOX],area_r[BOX],area_g[BOX],area_b[BOX];
|
||||
float line2,area2[BOX];
|
||||
|
||||
for (r = 1; r <= 32; ++r)
|
||||
{
|
||||
for (i = 0; i <= 32; ++i)
|
||||
{
|
||||
area[i] = area_r[i] = area_g[i] = area_b[i] = 0;
|
||||
area2[i] = 0.0;
|
||||
}
|
||||
|
||||
for (g = 1; g <= 32; ++g)
|
||||
{
|
||||
line2 = 0.0;
|
||||
line = line_r = line_g = line_b = 0;
|
||||
|
||||
for (b = 1; b <= 32; ++b)
|
||||
{
|
||||
ind1 = (r << 10) + (r << 6) + r + (g << 5) + g + b;
|
||||
line += vwt[ind1];
|
||||
line_r += vmr[ind1];
|
||||
line_g += vmg[ind1];
|
||||
line_b += vmb[ind1];
|
||||
line2 += m_2[ind1];
|
||||
area[b] += line;
|
||||
area_r[b] += line_r;
|
||||
area_g[b] += line_g;
|
||||
area_b[b] += line_b;
|
||||
area2[b] += line2;
|
||||
ind2 = ind1 - 1089;
|
||||
vwt[ind1] = vwt[ind2] + area[b];
|
||||
vmr[ind1] = vmr[ind2] + area_r[b];
|
||||
vmg[ind1] = vmg[ind2] + area_g[b];
|
||||
vmb[ind1] = vmb[ind2] + area_b[b];
|
||||
m_2[ind1] = m_2[ind2] + area2[b];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s32 Vol(struct box * cube, s32 mmt[BOX][BOX][BOX])
|
||||
{
|
||||
return (mmt[cube->r1][cube->g1][cube->b1] - mmt[cube->r1][cube->g1][cube->b0] - mmt[cube->r1][cube->g0][cube->b1]
|
||||
+ mmt[cube->r1][cube->g0][cube->b0] - mmt[cube->r0][cube->g1][cube->b1] + mmt[cube->r0][cube->g1][cube->b0]
|
||||
+ mmt[cube->r0][cube->g0][cube->b1] - mmt[cube->r0][cube->g0][cube->b0]);
|
||||
}
|
||||
|
||||
/* The next two routines allow a slightly more efficient calculation
|
||||
* of Vol() for a proposed subbox of a given box. The sum of Top()
|
||||
* and Bottom() is the Vol() of a subbox split in the given direction
|
||||
* and with the specified new upper bound.
|
||||
*/
|
||||
|
||||
/* Compute part of Vol(cube, mmt) that doesn't depend on r1, g1, or b1 */
|
||||
/* (depending on dir) */
|
||||
s32 Bottom(struct box * cube, u8 dir, s32 mmt[BOX][BOX][BOX])
|
||||
{
|
||||
switch (dir)
|
||||
{
|
||||
|
||||
case RED:
|
||||
|
||||
return (-mmt[cube->r0][cube->g1][cube->b1] + mmt[cube->r0][cube->g1][cube->b0]
|
||||
+ mmt[cube->r0][cube->g0][cube->b1] - mmt[cube->r0][cube->g0][cube->b0]);
|
||||
case GREEN:
|
||||
|
||||
return (-mmt[cube->r1][cube->g0][cube->b1] + mmt[cube->r1][cube->g0][cube->b0]
|
||||
+ mmt[cube->r0][cube->g0][cube->b1] - mmt[cube->r0][cube->g0][cube->b0]);
|
||||
|
||||
case BLUE:
|
||||
|
||||
return (-mmt[cube->r1][cube->g1][cube->b0] + mmt[cube->r1][cube->g0][cube->b0]
|
||||
+ mmt[cube->r0][cube->g1][cube->b0] - mmt[cube->r0][cube->g0][cube->b0]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
s32 Top(struct box * cube, u8 dir, s32 pos, s32 mmt[BOX][BOX][BOX])
|
||||
{
|
||||
switch (dir)
|
||||
{
|
||||
|
||||
case RED:
|
||||
|
||||
return (mmt[pos][cube->g1][cube->b1] - mmt[pos][cube->g1][cube->b0]
|
||||
- mmt[pos][cube->g0][cube->b1] + mmt[pos][cube->g0][cube->b0]);
|
||||
|
||||
case GREEN:
|
||||
|
||||
return (mmt[cube->r1][pos][cube->b1] - mmt[cube->r1][pos][cube->b0]
|
||||
- mmt[cube->r0][pos][cube->b1] + mmt[cube->r0][pos][cube->b0]);
|
||||
|
||||
case BLUE:
|
||||
|
||||
return (mmt[cube->r1][cube->g1][pos] - mmt[cube->r1][cube->g0][pos]
|
||||
- mmt[cube->r0][cube->g1][pos] + mmt[cube->r0][cube->g0][pos]);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compute the weighted variance of a box */
|
||||
/* NB: as with the raw statistics, this is really the variance * size */
|
||||
float Var(struct box * cube)
|
||||
{
|
||||
float dr,dg,db,xx;
|
||||
|
||||
dr = (float)Vol(cube, mr);
|
||||
dg = (float)Vol(cube, mg);
|
||||
db = (float)Vol(cube, mb);
|
||||
xx = m2[cube->r1][cube->g1][cube->b1] - m2[cube->r1][cube->g1][cube->b0] - m2[cube->r1][cube->g0][cube->b1]
|
||||
+ m2[cube->r1][cube->g0][cube->b0] - m2[cube->r0][cube->g1][cube->b1] + m2[cube->r0][cube->g1][cube->b0]
|
||||
+ m2[cube->r0][cube->g0][cube->b1] - m2[cube->r0][cube->g0][cube->b0];
|
||||
|
||||
return (xx - (dr * dr + dg * dg + db * db) / (float) Vol(cube, wt));
|
||||
}
|
||||
|
||||
/* We want to minimize the sum of the variances of two subboxes.
|
||||
* The sum(c^2) terms can be ignored since their sum over both subboxes
|
||||
* is the same (the sum for the whole box) no matter where we split.
|
||||
* The remaining terms have a minus sign in the variance formula,
|
||||
* so we drop the minus sign and MAXIMIZE the sum of the two terms.
|
||||
*/
|
||||
|
||||
float Maximize(struct box *cube, u8 dir, s32 first, s32 last, s32 *cut, s32 whole_r, s32 whole_g, s32 whole_b, s32 whole_w)
|
||||
{
|
||||
s32 half_r,half_g,half_b,half_w;
|
||||
s32 base_r,base_g,base_b,base_w;
|
||||
s32 i;
|
||||
float temp,max;
|
||||
|
||||
base_r = Bottom(cube, dir, mr);
|
||||
base_g = Bottom(cube, dir, mg);
|
||||
base_b = Bottom(cube, dir, mb);
|
||||
base_w = Bottom(cube, dir, wt);
|
||||
|
||||
max = 0.0;
|
||||
*cut = -1;
|
||||
|
||||
for (i = first; i < last; ++i)
|
||||
{
|
||||
half_r = base_r + Top(cube, dir, i, mr);
|
||||
half_g = base_g + Top(cube, dir, i, mg);
|
||||
half_b = base_b + Top(cube, dir, i, mb);
|
||||
half_w = base_w + Top(cube, dir, i, wt);
|
||||
// now half_x is sum over lower half of box, if split at i
|
||||
if (half_w == 0)
|
||||
{
|
||||
// subbox could be empty of pixels!
|
||||
// never split into an empty box
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp = ((float) half_r * half_r + (float) half_g * half_g + (float) half_b * half_b) / half_w;
|
||||
}
|
||||
|
||||
half_r = whole_r - half_r;
|
||||
half_g = whole_g - half_g;
|
||||
half_b = whole_b - half_b;
|
||||
half_w = whole_w - half_w;
|
||||
|
||||
if (half_w == 0)
|
||||
{
|
||||
// subbox could be empty of pixels!
|
||||
// never split into an empty box
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
temp += ((float) half_r * half_r + (float) half_g * half_g + (float) half_b * half_b) / half_w;
|
||||
}
|
||||
|
||||
if (temp > max)
|
||||
{
|
||||
max = temp;
|
||||
*cut = i;
|
||||
}
|
||||
}
|
||||
|
||||
return (max);
|
||||
}
|
||||
|
||||
s32 Cut(struct box * set1, struct box * set2)
|
||||
{
|
||||
u8 dir;
|
||||
s32 cutr,cutg,cutb;
|
||||
float maxr,maxg,maxb;
|
||||
s32 whole_r,whole_g,whole_b,whole_w;
|
||||
|
||||
whole_r = Vol(set1, mr);
|
||||
whole_g = Vol(set1, mg);
|
||||
whole_b = Vol(set1, mb);
|
||||
whole_w = Vol(set1, wt);
|
||||
|
||||
maxr = Maximize(set1, RED, set1->r0 + 1, set1->r1, &cutr, whole_r, whole_g, whole_b, whole_w);
|
||||
maxg = Maximize(set1, GREEN, set1->g0 + 1, set1->g1, &cutg, whole_r, whole_g, whole_b, whole_w);
|
||||
maxb = Maximize(set1, BLUE, set1->b0 + 1, set1->b1, &cutb, whole_r, whole_g, whole_b, whole_w);
|
||||
|
||||
if ((maxr >= maxg) && (maxr >= maxb))
|
||||
{
|
||||
dir = RED;
|
||||
|
||||
if (cutr < 0)
|
||||
return 0; /* can't split the box */
|
||||
}
|
||||
else if ((maxg >= maxr) && (maxg >= maxb))
|
||||
{
|
||||
dir = GREEN;
|
||||
}
|
||||
else
|
||||
{
|
||||
dir = BLUE;
|
||||
}
|
||||
|
||||
set2->r1 = set1->r1;
|
||||
set2->g1 = set1->g1;
|
||||
set2->b1 = set1->b1;
|
||||
|
||||
switch (dir)
|
||||
{
|
||||
|
||||
case RED:
|
||||
|
||||
set2->r0 = set1->r1 = cutr;
|
||||
set2->g0 = set1->g0;
|
||||
set2->b0 = set1->b0;
|
||||
break;
|
||||
|
||||
case GREEN:
|
||||
|
||||
set2->g0 = set1->g1 = cutg;
|
||||
set2->r0 = set1->r0;
|
||||
set2->b0 = set1->b0;
|
||||
break;
|
||||
|
||||
case BLUE:
|
||||
|
||||
set2->b0 = set1->b1 = cutb;
|
||||
set2->r0 = set1->r0;
|
||||
set2->g0 = set1->g0;
|
||||
break;
|
||||
}
|
||||
|
||||
set1->vol = (set1->r1 - set1->r0) * (set1->g1 - set1->g0) * (set1->b1 - set1->b0);
|
||||
set2->vol = (set2->r1 - set2->r0) * (set2->g1 - set2->g0) * (set2->b1 - set2->b0);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
void Mark(struct box *cube, s32 label, u8 *tag)
|
||||
{
|
||||
s32 r,g,b;
|
||||
|
||||
for (r = cube->r0 + 1; r <= cube->r1; ++r)
|
||||
for (g = cube->g0 + 1; g <= cube->g1; ++g)
|
||||
for (b = cube->b0 + 1; b <= cube->b1; ++b)
|
||||
tag[(r << 10) + (r << 6) + r + (g << 5) + g + b] = label;
|
||||
}
|
||||
|
||||
|
||||
|
||||
s32 wuReduce(u8 *RGBpic, s32 numcolors, s32 picsize)
|
||||
{
|
||||
struct box cube[MAXCOLOR];
|
||||
u8 *tag = 0;
|
||||
float vv[MAXCOLOR],temp = 0.;
|
||||
s32 i = 0,weight = 0;
|
||||
s32 next = 0;
|
||||
s32 j = 0,k = 0,l = 0;
|
||||
|
||||
TrueColorPic = RGBpic;
|
||||
ImageSize = picsize;
|
||||
PalSize = numcolors;
|
||||
|
||||
for (j=0;j<BOX;j++)
|
||||
for (k=0;k<BOX;k++)
|
||||
for (l=0;l<BOX;l++)
|
||||
{
|
||||
wt[j][k][l] = 0;
|
||||
mr[j][k][l] = 0;
|
||||
mg[j][k][l] = 0;
|
||||
mb[j][k][l] = 0;
|
||||
m2[j][k][l] = 0.;
|
||||
}
|
||||
|
||||
Qadd = AQadd;
|
||||
|
||||
// Hist3d((long *)&wt, (long *)&mr, (long *)&mg, (long *)&mb, (float *)&m2);
|
||||
// Momt3d((long *)&wt, (long *)&mr, (long *)&mg, (long *)&mb, (float *)&m2);
|
||||
Hist3d((s32 *)&wt, (s32 *)&mr, (s32 *)&mg, (s32 *)&mb, (float *)&m2);
|
||||
// Histogram done
|
||||
Momt3d((s32 *)&wt, (s32 *)&mr, (s32 *)&mg, (s32 *)&mb, (float *)&m2);
|
||||
// Moments done
|
||||
|
||||
cube[0].r0 = cube[0].g0 = cube[0].b0 = 0;
|
||||
cube[0].r1 = cube[0].g1 = cube[0].b1 = 32;
|
||||
next = 0;
|
||||
|
||||
for (i = 1; i < PalSize; ++i)
|
||||
{
|
||||
if (Cut(&cube[next], &cube[i]))
|
||||
{
|
||||
// volume test ensures we won't try to cut one-cell box
|
||||
vv[next] = (float)((cube[next].vol > 1) ? Var(&cube[next]) : 0.0);
|
||||
vv[i] = (float)((cube[i].vol > 1) ? Var(&cube[i]) : 0.0);
|
||||
}
|
||||
else
|
||||
{
|
||||
vv[next] = 0.0;
|
||||
i--;
|
||||
}
|
||||
|
||||
next = 0;
|
||||
temp = vv[0];
|
||||
|
||||
for (k = 1; k <= i; ++k)
|
||||
{
|
||||
if (vv[k] > temp)
|
||||
{
|
||||
temp = vv[k];
|
||||
next = k;
|
||||
}
|
||||
}
|
||||
|
||||
if (temp <= 0.0)
|
||||
{
|
||||
PalSize = i + 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
tag = Atag;
|
||||
|
||||
for (k = 0; k < PalSize; ++k)
|
||||
{
|
||||
Mark(&cube[k], k, tag);
|
||||
weight = Vol(&cube[k], wt);
|
||||
|
||||
if (weight)
|
||||
{
|
||||
|
||||
QuantizedPalette[k][2] = (unsigned char)(Vol(&cube[k], mr) / weight);
|
||||
QuantizedPalette[k][0] = (unsigned char)(Vol(&cube[k], mb) / weight);
|
||||
QuantizedPalette[k][1] = (unsigned char)(Vol(&cube[k], mg) / weight);
|
||||
}
|
||||
else
|
||||
{
|
||||
QuantizedPalette[k][0] = QuantizedPalette[k][1] = QuantizedPalette[k][2] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < ImageSize; i++)
|
||||
Picture256[i] = tag[Qadd[i]];
|
||||
|
||||
return 0;
|
||||
}
|
||||
69
gbdk-support/png2hicolorgb/src/hicolor/defines.h
Normal file
69
gbdk-support/png2hicolorgb/src/hicolor/defines.h
Normal file
@@ -0,0 +1,69 @@
|
||||
|
||||
|
||||
#ifndef __defines_h__
|
||||
#define __defines_h__
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <common.h>
|
||||
|
||||
// Originates on Windows format is BGRX24
|
||||
// TODO: is this right & ok for what code expects?
|
||||
typedef struct tagRGBQUAD {
|
||||
uint8_t rgbBlue;
|
||||
uint8_t rgbGreen;
|
||||
uint8_t rgbRed;
|
||||
uint8_t rgbReserved;
|
||||
} RGBQUAD;
|
||||
|
||||
#define CGB_ATTR_TILES_BANK_0 0x00u
|
||||
#define CGB_ATTR_TILES_BANK_1 0x08u
|
||||
#define CGB_ATTR_TILES_BANK 0x08u
|
||||
#define CGB_ATTR_NO_FLIP 0x00u
|
||||
#define CGB_ATTR_VFLIP 0x40u
|
||||
#define CGB_ATTR_HFLIP 0x20u
|
||||
#define CGB_ATTR_PALLETES_ONLY 0x07u
|
||||
#define CGB_ATTR_WITHOUT_PALLETES (~(CGB_ATTR_PALLETES_ONLY))
|
||||
|
||||
#define CGB_TILES_START_BANK_0 0u
|
||||
#define CGB_TILES_START_BANK_1 256u
|
||||
|
||||
#define RGB_SZ 3 // RGB888 size in bytes
|
||||
#define TILE_SZ 16u // Tile size in bytes: (8 x 8) pixels x 2 Bits per pixel
|
||||
|
||||
#define u8 uint8_t
|
||||
#define u16 uint16_t
|
||||
#define u32 uint32_t
|
||||
#define s8 int8_t
|
||||
#define s16 int16_t
|
||||
#define s32 int32_t
|
||||
|
||||
enum conversion_types {
|
||||
CONV_TYPE_MED_CUT_NO_DITHER = 1,
|
||||
CONV_TYPE_MED_CUT_YES_DITHER = 2,
|
||||
CONV_TYPE_WU = 3,
|
||||
|
||||
CONV_TYPE_MIN = CONV_TYPE_MED_CUT_NO_DITHER,
|
||||
CONV_TYPE_MAX = CONV_TYPE_WU
|
||||
};
|
||||
|
||||
#define CONV_SIDE_LEFT 0
|
||||
#define CONV_SIDE_RIGHT 1
|
||||
|
||||
#define CONV_Y_SHIFT_UP_1 1
|
||||
#define CONV_Y_SHIFT_NO 0
|
||||
|
||||
|
||||
#define PAL_REGION_HEIGHT_PX 2
|
||||
|
||||
// #define BUF_WIDTH 160 // Originally 160
|
||||
// #define BUF_WIDTH_TILE_MAX (BUF_WIDTH / TILE_WIDTH_PX)
|
||||
#define BUF_HEIGHT 256 // Originally 144
|
||||
#define BUF_HEIGHT_IN_TILES (BUF_HEIGHT / TILE_HEIGHT_PX)
|
||||
#define BUF_HEIGHT_IN_TILES_RNDUP (BUF_HEIGHT_IN_TILES+1) // Use larger size[side] for rounded up amount
|
||||
#define BUF_Y_REGION_COUNT_LR_RNDUP (((BUF_HEIGHT / PAL_REGION_HEIGHT_PX) + 1))
|
||||
|
||||
#define VALIDATE_WIDTH 160 // (BUF_WIDTH)
|
||||
#define VALIDATE_HEIGHT (BUF_HEIGHT)
|
||||
|
||||
#endif
|
||||
554
gbdk-support/png2hicolorgb/src/hicolor/fsdither.h
Normal file
554
gbdk-support/png2hicolorgb/src/hicolor/fsdither.h
Normal file
@@ -0,0 +1,554 @@
|
||||
/* The GIMP -- an image manipulation program
|
||||
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
||||
*/
|
||||
#ifndef __FSDITHER_H__
|
||||
#define __FSDITHER_H__
|
||||
|
||||
/* The following 5 arrays are used in performing floyd-steinberg
|
||||
* error diffusion dithering. The range array allows the quick
|
||||
* bounds checking of pixel values. The 4 error arrays contain
|
||||
* the error computations for the east, south-east, south and
|
||||
* south-west pixels surrounding the current pixel respectively.
|
||||
*/
|
||||
|
||||
//short
|
||||
unsigned char
|
||||
range_array[] = {
|
||||
/*
|
||||
1 2 3 4 5 6 7 8 9 0
|
||||
*/
|
||||
0,0,0,0,0,0,0,0,0,0, // L20
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,1,2,3, // L45 (+25) 250 - 260-4=256
|
||||
4,5,6,7,8,9,10,11,12,13,
|
||||
14,15,16,17,18,19,20,21,22,23,
|
||||
24,25,26,27,28,29,30,31,32,33,
|
||||
34,35,36,37,38,39,40,41,42,43,
|
||||
44,45,46,47,48,49,50,51,52,53,
|
||||
54,55,56,57,58,59,60,61,62,63,
|
||||
64,65,66,67,68,69,70,71,72,73,
|
||||
74,75,76,77,78,79,80,81,82,83,
|
||||
84,85,86,87,88,89,90,91,92,93,
|
||||
94,95,96,97,98,99,100,101,102,103,
|
||||
104,105,106,107,108,109,110,111,112,113,
|
||||
114,115,116,117,118,119,120,121,122,123,
|
||||
124,125,126,127,128,129,130,131,132,133,
|
||||
134,135,136,137,138,139,140,141,142,143,
|
||||
144,145,146,147,148,149,150,151,152,153,
|
||||
154,155,156,157,158,159,160,161,162,163,
|
||||
164,165,166,167,168,169,170,171,172,173,
|
||||
174,175,176,177,178,179,180,181,182,183,
|
||||
184,185,186,187,188,189,190,191,192,193,
|
||||
194,195,196,197,198,199,200,201,202,203,
|
||||
204,205,206,207,208,209,210,211,212,213,
|
||||
214,215,216,217,218,219,220,221,222,223,
|
||||
224,225,226,227,228,229,230,231,232,233,
|
||||
234,235,236,237,238,239,240,241,242,243,
|
||||
244,245,246,247,248,249,250,251,252,253,
|
||||
254,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255,255,255,255,255,255,
|
||||
255,255,255,255,255, // L122 : 122-20=102
|
||||
// 102*10-5 = 1015
|
||||
};
|
||||
|
||||
short floyd_steinberg_error1[] = {
|
||||
-223,-223,-222,-222,-221,-221,-220,-220,-220,-219,
|
||||
-219,-218,-218,-217,-217,-217,-216,-216,-215,-215,
|
||||
-214,-214,-213,-213,-213,-212,-212,-211,-211,-210,
|
||||
-210,-210,-209,-209,-208,-208,-207,-207,-206,-206,
|
||||
-206,-205,-205,-204,-204,-203,-203,-203,-202,-202,
|
||||
-201,-201,-200,-200,-199,-199,-199,-198,-198,-197,
|
||||
-197,-196,-196,-196,-195,-195,-194,-194,-193,-193,
|
||||
-192,-192,-192,-191,-191,-190,-190,-189,-189,-189,
|
||||
-188,-188,-187,-187,-186,-186,-185,-185,-185,-184,
|
||||
-184,-183,-183,-182,-182,-182,-181,-181,-180,-180,
|
||||
-179,-179,-178,-178,-178,-177,-177,-176,-176,-175,
|
||||
-175,-175,-174,-174,-173,-173,-172,-172,-171,-171,
|
||||
-171,-170,-170,-169,-169,-168,-168,-168,-167,-167,
|
||||
-166,-166,-165,-165,-164,-164,-164,-163,-163,-162,
|
||||
-162,-161,-161,-161,-160,-160,-159,-159,-158,-158,
|
||||
-157,-157,-157,-156,-156,-155,-155,-154,-154,-154,
|
||||
-153,-153,-152,-152,-151,-151,-150,-150,-150,-149,
|
||||
-149,-148,-148,-147,-147,-147,-146,-146,-145,-145,
|
||||
-144,-144,-143,-143,-143,-142,-142,-141,-141,-140,
|
||||
-140,-140,-139,-139,-138,-138,-137,-137,-136,-136,
|
||||
-136,-135,-135,-134,-134,-133,-133,-133,-132,-132,
|
||||
-131,-131,-130,-130,-129,-129,-129,-128,-128,-127,
|
||||
-127,-126,-126,-126,-125,-125,-124,-124,-123,-123,
|
||||
-122,-122,-122,-121,-121,-120,-120,-119,-119,-119,
|
||||
-118,-118,-117,-117,-116,-116,-115,-115,-115,-114,
|
||||
-114,-113,-113,-112,-112,-112,-111,-111,-110,-110,
|
||||
-109,-109,-108,-108,-108,-107,-107,-106,-106,-105,
|
||||
-105,-105,-104,-104,-103,-103,-102,-102,-101,-101,
|
||||
-101,-100,-100,-99,-99,-98,-98,-98,-97,-97,
|
||||
-96,-96,-95,-95,-94,-94,-94,-93,-93,-92,
|
||||
-92,-91,-91,-91,-90,-90,-89,-89,-88,-88,
|
||||
-87,-87,-87,-86,-86,-85,-85,-84,-84,-84,
|
||||
-83,-83,-82,-82,-81,-81,-80,-80,-80,-79,
|
||||
-79,-78,-78,-77,-77,-77,-76,-76,-75,-75,
|
||||
-74,-74,-73,-73,-73,-72,-72,-71,-71,-70,
|
||||
-70,-70,-69,-69,-68,-68,-67,-67,-66,-66,
|
||||
-66,-65,-65,-64,-64,-63,-63,-63,-62,-62,
|
||||
-61,-61,-60,-60,-59,-59,-59,-58,-58,-57,
|
||||
-57,-56,-56,-56,-55,-55,-54,-54,-53,-53,
|
||||
-52,-52,-52,-51,-51,-50,-50,-49,-49,-49,
|
||||
-48,-48,-47,-47,-46,-46,-45,-45,-45,-44,
|
||||
-44,-43,-43,-42,-42,-42,-41,-41,-40,-40,
|
||||
-39,-39,-38,-38,-38,-37,-37,-36,-36,-35,
|
||||
-35,-35,-34,-34,-33,-33,-32,-32,-31,-31,
|
||||
-31,-30,-30,-29,-29,-28,-28,-28,-27,-27,
|
||||
-26,-26,-25,-25,-24,-24,-24,-23,-23,-22,
|
||||
-22,-21,-21,-21,-20,-20,-19,-19,-18,-18,
|
||||
-17,-17,-17,-16,-16,-15,-15,-14,-14,-14,
|
||||
-13,-13,-12,-12,-11,-11,-10,-10,-10,-9,
|
||||
-9,-8,-8,-7,-7,-7,-6,-6,-5,-5,
|
||||
-4,-4,-3,-3,-3,-2,-2,-1,-1,
|
||||
0,
|
||||
0,0,0,0,1,1,2,2,3,3,
|
||||
3,4,4,5,5,6,6,7,7,7,
|
||||
8,8,9,9,10,10,10,11,11,12,
|
||||
12,13,13,14,14,14,15,15,16,16,
|
||||
17,17,17,18,18,19,19,20,20,21,
|
||||
21,21,22,22,23,23,24,24,24,25,
|
||||
25,26,26,27,27,28,28,28,29,29,
|
||||
30,30,31,31,31,32,32,33,33,34,
|
||||
34,35,35,35,36,36,37,37,38,38,
|
||||
38,39,39,40,40,41,41,42,42,42,
|
||||
43,43,44,44,45,45,45,46,46,47,
|
||||
47,48,48,49,49,49,50,50,51,51,
|
||||
52,52,52,53,53,54,54,55,55,56,
|
||||
56,56,57,57,58,58,59,59,59,60,
|
||||
60,61,61,62,62,63,63,63,64,64,
|
||||
65,65,66,66,66,67,67,68,68,69,
|
||||
69,70,70,70,71,71,72,72,73,73,
|
||||
73,74,74,75,75,76,76,77,77,77,
|
||||
78,78,79,79,80,80,80,81,81,82,
|
||||
82,83,83,84,84,84,85,85,86,86,
|
||||
87,87,87,88,88,89,89,90,90,91,
|
||||
91,91,92,92,93,93,94,94,94,95,
|
||||
95,96,96,97,97,98,98,98,99,99,
|
||||
100,100,101,101,101,102,102,103,103,104,
|
||||
104,105,105,105,106,106,107,107,108,108,
|
||||
108,109,109,110,110,111,111,112,112,112,
|
||||
113,113,114,114,115,115,115,116,116,117,
|
||||
117,118,118,119,119,119,120,120,121,121,
|
||||
122,122,122,123,123,124,124,125,125,126,
|
||||
126,126,127,127,128,128,129,129,129,130,
|
||||
130,131,131,132,132,133,133,133,134,134,
|
||||
135,135,136,136,136,137,137,138,138,139,
|
||||
139,140,140,140,141,141,142,142,143,143,
|
||||
143,144,144,145,145,146,146,147,147,147,
|
||||
148,148,149,149,150,150,150,151,151,152,
|
||||
152,153,153,154,154,154,155,155,156,156,
|
||||
157,157,157,158,158,159,159,160,160,161,
|
||||
161,161,162,162,163,163,164,164,164,165,
|
||||
165,166,166,167,167,168,168,168,169,169,
|
||||
170,170,171,171,171,172,172,173,173,174,
|
||||
174,175,175,175,176,176,177,177,178,178,
|
||||
178,179,179,180,180,181,181,182,182,182,
|
||||
183,183,184,184,185,185,185,186,186,187,
|
||||
187,188,188,189,189,189,190,190,191,191,
|
||||
192,192,192,193,193,194,194,195,195,196,
|
||||
196,196,197,197,198,198,199,199,199,200,
|
||||
200,201,201,202,202,203,203,203,204,204,
|
||||
205,205,206,206,206,207,207,208,208,209,
|
||||
209,210,210,210,211,211,212,212,213,213,
|
||||
213,214,214,215,215,216,216,217,217,217,
|
||||
218,218,219,219,220,220,220,221,221,222,
|
||||
222,223,223,224,224,
|
||||
};
|
||||
|
||||
short floyd_steinberg_error2[] = {
|
||||
-95,-95,-95,-95,-95,-94,-94,-94,-94,-94,
|
||||
-93,-93,-93,-93,-93,-93,-92,-92,-92,-92,
|
||||
-92,-91,-91,-91,-91,-91,-90,-90,-90,-90,
|
||||
-90,-90,-89,-89,-89,-89,-89,-88,-88,-88,
|
||||
-88,-88,-87,-87,-87,-87,-87,-87,-86,-86,
|
||||
-86,-86,-86,-85,-85,-85,-85,-85,-84,-84,
|
||||
-84,-84,-84,-84,-83,-83,-83,-83,-83,-82,
|
||||
-82,-82,-82,-82,-81,-81,-81,-81,-81,-81,
|
||||
-80,-80,-80,-80,-80,-79,-79,-79,-79,-79,
|
||||
-78,-78,-78,-78,-78,-78,-77,-77,-77,-77,
|
||||
-77,-76,-76,-76,-76,-76,-75,-75,-75,-75,
|
||||
-75,-75,-74,-74,-74,-74,-74,-73,-73,-73,
|
||||
-73,-73,-72,-72,-72,-72,-72,-72,-71,-71,
|
||||
-71,-71,-71,-70,-70,-70,-70,-70,-69,-69,
|
||||
-69,-69,-69,-69,-68,-68,-68,-68,-68,-67,
|
||||
-67,-67,-67,-67,-66,-66,-66,-66,-66,-66,
|
||||
-65,-65,-65,-65,-65,-64,-64,-64,-64,-64,
|
||||
-63,-63,-63,-63,-63,-63,-62,-62,-62,-62,
|
||||
-62,-61,-61,-61,-61,-61,-60,-60,-60,-60,
|
||||
-60,-60,-59,-59,-59,-59,-59,-58,-58,-58,
|
||||
-58,-58,-57,-57,-57,-57,-57,-57,-56,-56,
|
||||
-56,-56,-56,-55,-55,-55,-55,-55,-54,-54,
|
||||
-54,-54,-54,-54,-53,-53,-53,-53,-53,-52,
|
||||
-52,-52,-52,-52,-51,-51,-51,-51,-51,-51,
|
||||
-50,-50,-50,-50,-50,-49,-49,-49,-49,-49,
|
||||
-48,-48,-48,-48,-48,-48,-47,-47,-47,-47,
|
||||
-47,-46,-46,-46,-46,-46,-45,-45,-45,-45,
|
||||
-45,-45,-44,-44,-44,-44,-44,-43,-43,-43,
|
||||
-43,-43,-42,-42,-42,-42,-42,-42,-41,-41,
|
||||
-41,-41,-41,-40,-40,-40,-40,-40,-39,-39,
|
||||
-39,-39,-39,-39,-38,-38,-38,-38,-38,-37,
|
||||
-37,-37,-37,-37,-36,-36,-36,-36,-36,-36,
|
||||
-35,-35,-35,-35,-35,-34,-34,-34,-34,-34,
|
||||
-33,-33,-33,-33,-33,-33,-32,-32,-32,-32,
|
||||
-32,-31,-31,-31,-31,-31,-30,-30,-30,-30,
|
||||
-30,-30,-29,-29,-29,-29,-29,-28,-28,-28,
|
||||
-28,-28,-27,-27,-27,-27,-27,-27,-26,-26,
|
||||
-26,-26,-26,-25,-25,-25,-25,-25,-24,-24,
|
||||
-24,-24,-24,-24,-23,-23,-23,-23,-23,-22,
|
||||
-22,-22,-22,-22,-21,-21,-21,-21,-21,-21,
|
||||
-20,-20,-20,-20,-20,-19,-19,-19,-19,-19,
|
||||
-18,-18,-18,-18,-18,-18,-17,-17,-17,-17,
|
||||
-17,-16,-16,-16,-16,-16,-15,-15,-15,-15,
|
||||
-15,-15,-14,-14,-14,-14,-14,-13,-13,-13,
|
||||
-13,-13,-12,-12,-12,-12,-12,-12,-11,-11,
|
||||
-11,-11,-11,-10,-10,-10,-10,-10,-9,-9,
|
||||
-9,-9,-9,-9,-8,-8,-8,-8,-8,-7,
|
||||
-7,-7,-7,-7,-6,-6,-6,-6,-6,-6,
|
||||
-5,-5,-5,-5,-5,-4,-4,-4,-4,-4,
|
||||
-3,-3,-3,-3,-3,-3,-2,-2,-2,-2,
|
||||
-2,-1,-1,-1,-1,-1,
|
||||
0,0,0,0,
|
||||
0,0,0,0,0,0,0,1,1,1,
|
||||
1,1,2,2,2,2,2,3,3,3,
|
||||
3,3,3,4,4,4,4,4,5,5,
|
||||
5,5,5,6,6,6,6,6,6,7,
|
||||
7,7,7,7,8,8,8,8,8,9,
|
||||
9,9,9,9,9,10,10,10,10,10,
|
||||
11,11,11,11,11,12,12,12,12,12,
|
||||
12,13,13,13,13,13,14,14,14,14,
|
||||
14,15,15,15,15,15,15,16,16,16,
|
||||
16,16,17,17,17,17,17,18,18,18,
|
||||
18,18,18,19,19,19,19,19,20,20,
|
||||
20,20,20,21,21,21,21,21,21,22,
|
||||
22,22,22,22,23,23,23,23,23,24,
|
||||
24,24,24,24,24,25,25,25,25,25,
|
||||
26,26,26,26,26,27,27,27,27,27,
|
||||
27,28,28,28,28,28,29,29,29,29,
|
||||
29,30,30,30,30,30,30,31,31,31,
|
||||
31,31,32,32,32,32,32,33,33,33,
|
||||
33,33,33,34,34,34,34,34,35,35,
|
||||
35,35,35,36,36,36,36,36,36,37,
|
||||
37,37,37,37,38,38,38,38,38,39,
|
||||
39,39,39,39,39,40,40,40,40,40,
|
||||
41,41,41,41,41,42,42,42,42,42,
|
||||
42,43,43,43,43,43,44,44,44,44,
|
||||
44,45,45,45,45,45,45,46,46,46,
|
||||
46,46,47,47,47,47,47,48,48,48,
|
||||
48,48,48,49,49,49,49,49,50,50,
|
||||
50,50,50,51,51,51,51,51,51,52,
|
||||
52,52,52,52,53,53,53,53,53,54,
|
||||
54,54,54,54,54,55,55,55,55,55,
|
||||
56,56,56,56,56,57,57,57,57,57,
|
||||
57,58,58,58,58,58,59,59,59,59,
|
||||
59,60,60,60,60,60,60,61,61,61,
|
||||
61,61,62,62,62,62,62,63,63,63,
|
||||
63,63,63,64,64,64,64,64,65,65,
|
||||
65,65,65,66,66,66,66,66,66,67,
|
||||
67,67,67,67,68,68,68,68,68,69,
|
||||
69,69,69,69,69,70,70,70,70,70,
|
||||
71,71,71,71,71,72,72,72,72,72,
|
||||
72,73,73,73,73,73,74,74,74,74,
|
||||
74,75,75,75,75,75,75,76,76,76,
|
||||
76,76,77,77,77,77,77,78,78,78,
|
||||
78,78,78,79,79,79,79,79,80,80,
|
||||
80,80,80,81,81,81,81,81,81,82,
|
||||
82,82,82,82,83,83,83,83,83,84,
|
||||
84,84,84,84,84,85,85,85,85,85,
|
||||
86,86,86,86,86,87,87,87,87,87,
|
||||
87,88,88,88,88,88,89,89,89,89,
|
||||
89,90,90,90,90,90,90,91,91,91,
|
||||
91,91,92,92,92,92,92,93,93,93,
|
||||
93,93,93,94,94,94,94,94,95,95,
|
||||
95,95,95,96,96,
|
||||
};
|
||||
|
||||
short floyd_steinberg_error3[] = {
|
||||
-159,-159,-159,-158,-158,-158,-157,-157,-157,-156,
|
||||
-156,-156,-155,-155,-155,-155,-154,-154,-154,-153,
|
||||
-153,-153,-152,-152,-152,-151,-151,-151,-150,-150,
|
||||
-150,-150,-149,-149,-149,-148,-148,-148,-147,-147,
|
||||
-147,-146,-146,-146,-145,-145,-145,-145,-144,-144,
|
||||
-144,-143,-143,-143,-142,-142,-142,-141,-141,-141,
|
||||
-140,-140,-140,-140,-139,-139,-139,-138,-138,-138,
|
||||
-137,-137,-137,-136,-136,-136,-135,-135,-135,-135,
|
||||
-134,-134,-134,-133,-133,-133,-132,-132,-132,-131,
|
||||
-131,-131,-130,-130,-130,-130,-129,-129,-129,-128,
|
||||
-128,-128,-127,-127,-127,-126,-126,-126,-125,-125,
|
||||
-125,-125,-124,-124,-124,-123,-123,-123,-122,-122,
|
||||
-122,-121,-121,-121,-120,-120,-120,-120,-119,-119,
|
||||
-119,-118,-118,-118,-117,-117,-117,-116,-116,-116,
|
||||
-115,-115,-115,-115,-114,-114,-114,-113,-113,-113,
|
||||
-112,-112,-112,-111,-111,-111,-110,-110,-110,-110,
|
||||
-109,-109,-109,-108,-108,-108,-107,-107,-107,-106,
|
||||
-106,-106,-105,-105,-105,-105,-104,-104,-104,-103,
|
||||
-103,-103,-102,-102,-102,-101,-101,-101,-100,-100,
|
||||
-100,-100,-99,-99,-99,-98,-98,-98,-97,-97,
|
||||
-97,-96,-96,-96,-95,-95,-95,-95,-94,-94,
|
||||
-94,-93,-93,-93,-92,-92,-92,-91,-91,-91,
|
||||
-90,-90,-90,-90,-89,-89,-89,-88,-88,-88,
|
||||
-87,-87,-87,-86,-86,-86,-85,-85,-85,-85,
|
||||
-84,-84,-84,-83,-83,-83,-82,-82,-82,-81,
|
||||
-81,-81,-80,-80,-80,-80,-79,-79,-79,-78,
|
||||
-78,-78,-77,-77,-77,-76,-76,-76,-75,-75,
|
||||
-75,-75,-74,-74,-74,-73,-73,-73,-72,-72,
|
||||
-72,-71,-71,-71,-70,-70,-70,-70,-69,-69,
|
||||
-69,-68,-68,-68,-67,-67,-67,-66,-66,-66,
|
||||
-65,-65,-65,-65,-64,-64,-64,-63,-63,-63,
|
||||
-62,-62,-62,-61,-61,-61,-60,-60,-60,-60,
|
||||
-59,-59,-59,-58,-58,-58,-57,-57,-57,-56,
|
||||
-56,-56,-55,-55,-55,-55,-54,-54,-54,-53,
|
||||
-53,-53,-52,-52,-52,-51,-51,-51,-50,-50,
|
||||
-50,-50,-49,-49,-49,-48,-48,-48,-47,-47,
|
||||
-47,-46,-46,-46,-45,-45,-45,-45,-44,-44,
|
||||
-44,-43,-43,-43,-42,-42,-42,-41,-41,-41,
|
||||
-40,-40,-40,-40,-39,-39,-39,-38,-38,-38,
|
||||
-37,-37,-37,-36,-36,-36,-35,-35,-35,-35,
|
||||
-34,-34,-34,-33,-33,-33,-32,-32,-32,-31,
|
||||
-31,-31,-30,-30,-30,-30,-29,-29,-29,-28,
|
||||
-28,-28,-27,-27,-27,-26,-26,-26,-25,-25,
|
||||
-25,-25,-24,-24,-24,-23,-23,-23,-22,-22,
|
||||
-22,-21,-21,-21,-20,-20,-20,-20,-19,-19,
|
||||
-19,-18,-18,-18,-17,-17,-17,-16,-16,-16,
|
||||
-15,-15,-15,-15,-14,-14,-14,-13,-13,-13,
|
||||
-12,-12,-12,-11,-11,-11,-10,-10,-10,-10,
|
||||
-9,-9,-9,-8,-8,-8,-7,-7,-7,-6,
|
||||
-6,-6,-5,-5,-5,-5,-4,-4,-4,-3,
|
||||
-3,-3,-2,-2,-2,-1,-1,-1,
|
||||
0,0,
|
||||
0,0,0,0,0,1,1,1,2,2,
|
||||
2,3,3,3,4,4,4,5,5,5,
|
||||
5,6,6,6,7,7,7,8,8,8,
|
||||
9,9,9,10,10,10,10,11,11,11,
|
||||
12,12,12,13,13,13,14,14,14,15,
|
||||
15,15,15,16,16,16,17,17,17,18,
|
||||
18,18,19,19,19,20,20,20,20,21,
|
||||
21,21,22,22,22,23,23,23,24,24,
|
||||
24,25,25,25,25,26,26,26,27,27,
|
||||
27,28,28,28,29,29,29,30,30,30,
|
||||
30,31,31,31,32,32,32,33,33,33,
|
||||
34,34,34,35,35,35,35,36,36,36,
|
||||
37,37,37,38,38,38,39,39,39,40,
|
||||
40,40,40,41,41,41,42,42,42,43,
|
||||
43,43,44,44,44,45,45,45,45,46,
|
||||
46,46,47,47,47,48,48,48,49,49,
|
||||
49,50,50,50,50,51,51,51,52,52,
|
||||
52,53,53,53,54,54,54,55,55,55,
|
||||
55,56,56,56,57,57,57,58,58,58,
|
||||
59,59,59,60,60,60,60,61,61,61,
|
||||
62,62,62,63,63,63,64,64,64,65,
|
||||
65,65,65,66,66,66,67,67,67,68,
|
||||
68,68,69,69,69,70,70,70,70,71,
|
||||
71,71,72,72,72,73,73,73,74,74,
|
||||
74,75,75,75,75,76,76,76,77,77,
|
||||
77,78,78,78,79,79,79,80,80,80,
|
||||
80,81,81,81,82,82,82,83,83,83,
|
||||
84,84,84,85,85,85,85,86,86,86,
|
||||
87,87,87,88,88,88,89,89,89,90,
|
||||
90,90,90,91,91,91,92,92,92,93,
|
||||
93,93,94,94,94,95,95,95,95,96,
|
||||
96,96,97,97,97,98,98,98,99,99,
|
||||
99,100,100,100,100,101,101,101,102,102,
|
||||
102,103,103,103,104,104,104,105,105,105,
|
||||
105,106,106,106,107,107,107,108,108,108,
|
||||
109,109,109,110,110,110,110,111,111,111,
|
||||
112,112,112,113,113,113,114,114,114,115,
|
||||
115,115,115,116,116,116,117,117,117,118,
|
||||
118,118,119,119,119,120,120,120,120,121,
|
||||
121,121,122,122,122,123,123,123,124,124,
|
||||
124,125,125,125,125,126,126,126,127,127,
|
||||
127,128,128,128,129,129,129,130,130,130,
|
||||
130,131,131,131,132,132,132,133,133,133,
|
||||
134,134,134,135,135,135,135,136,136,136,
|
||||
137,137,137,138,138,138,139,139,139,140,
|
||||
140,140,140,141,141,141,142,142,142,143,
|
||||
143,143,144,144,144,145,145,145,145,146,
|
||||
146,146,147,147,147,148,148,148,149,149,
|
||||
149,150,150,150,150,151,151,151,152,152,
|
||||
152,153,153,153,154,154,154,155,155,155,
|
||||
155,156,156,156,157,157,157,158,158,158,
|
||||
159,159,159,160,160,
|
||||
};
|
||||
|
||||
short floyd_steinberg_error4[] = {
|
||||
-34,-33,-33,-33,-33,-33,-34,-33,-32,-33,
|
||||
-33,-33,-33,-33,-32,-31,-33,-32,-32,-32,
|
||||
-32,-32,-33,-32,-31,-32,-32,-32,-32,-32,
|
||||
-31,-30,-32,-31,-31,-31,-31,-31,-32,-31,
|
||||
-30,-31,-31,-31,-31,-31,-30,-29,-31,-30,
|
||||
-30,-30,-30,-30,-31,-30,-29,-30,-30,-30,
|
||||
-30,-30,-29,-28,-30,-29,-29,-29,-29,-29,
|
||||
-30,-29,-28,-29,-29,-29,-29,-29,-28,-27,
|
||||
-29,-28,-28,-28,-28,-28,-29,-28,-27,-28,
|
||||
-28,-28,-28,-28,-27,-26,-28,-27,-27,-27,
|
||||
-27,-27,-28,-27,-26,-27,-27,-27,-27,-27,
|
||||
-26,-25,-27,-26,-26,-26,-26,-26,-27,-26,
|
||||
-25,-26,-26,-26,-26,-26,-25,-24,-26,-25,
|
||||
-25,-25,-25,-25,-26,-25,-24,-25,-25,-25,
|
||||
-25,-25,-24,-23,-25,-24,-24,-24,-24,-24,
|
||||
-25,-24,-23,-24,-24,-24,-24,-24,-23,-22,
|
||||
-24,-23,-23,-23,-23,-23,-24,-23,-22,-23,
|
||||
-23,-23,-23,-23,-22,-21,-23,-22,-22,-22,
|
||||
-22,-22,-23,-22,-21,-22,-22,-22,-22,-22,
|
||||
-21,-20,-22,-21,-21,-21,-21,-21,-22,-21,
|
||||
-20,-21,-21,-21,-21,-21,-20,-19,-21,-20,
|
||||
-20,-20,-20,-20,-21,-20,-19,-20,-20,-20,
|
||||
-20,-20,-19,-18,-20,-19,-19,-19,-19,-19,
|
||||
-20,-19,-18,-19,-19,-19,-19,-19,-18,-17,
|
||||
-19,-18,-18,-18,-18,-18,-19,-18,-17,-18,
|
||||
-18,-18,-18,-18,-17,-16,-18,-17,-17,-17,
|
||||
-17,-17,-18,-17,-16,-17,-17,-17,-17,-17,
|
||||
-16,-15,-17,-16,-16,-16,-16,-16,-17,-16,
|
||||
-15,-16,-16,-16,-16,-16,-15,-14,-16,-15,
|
||||
-15,-15,-15,-15,-16,-15,-14,-15,-15,-15,
|
||||
-15,-15,-14,-13,-15,-14,-14,-14,-14,-14,
|
||||
-15,-14,-13,-14,-14,-14,-14,-14,-13,-12,
|
||||
-14,-13,-13,-13,-13,-13,-14,-13,-12,-13,
|
||||
-13,-13,-13,-13,-12,-11,-13,-12,-12,-12,
|
||||
-12,-12,-13,-12,-11,-12,-12,-12,-12,-12,
|
||||
-11,-10,-12,-11,-11,-11,-11,-11,-12,-11,
|
||||
-10,-11,-11,-11,-11,-11,-10,-9,-11,-10,
|
||||
-10,-10,-10,-10,-11,-10,-9,-10,-10,-10,
|
||||
-10,-10,-9,-8,-10,-9,-9,-9,-9,-9,
|
||||
-10,-9,-8,-9,-9,-9,-9,-9,-8,-7,
|
||||
-9,-8,-8,-8,-8,-8,-9,-8,-7,-8,
|
||||
-8,-8,-8,-8,-7,-6,-8,-7,-7,-7,
|
||||
-7,-7,-8,-7,-6,-7,-7,-7,-7,-7,
|
||||
-6,-5,-7,-6,-6,-6,-6,-6,-7,-6,
|
||||
-5,-6,-6,-6,-6,-6,-5,-4,-6,-5,
|
||||
-5,-5,-5,-5,-6,-5,-4,-5,-5,-5,
|
||||
-5,-5,-4,-3,-5,-4,-4,-4,-4,-4,
|
||||
-5,-4,-3,-4,-4,-4,-4,-4,-3,-2,
|
||||
-4,-3,-3,-3,-3,-3,-4,-3,-2,-3,
|
||||
-3,-3,-3,-3,-2,-1,-3,-2,-2,-2,
|
||||
-2,-2,-3,-2,-1,-2,-2,-2,-2,-2,
|
||||
-1,
|
||||
0,1,2,2,2,2,2,1,2,
|
||||
3,2,2,2,2,2,3,1,2,3,
|
||||
3,3,3,3,2,3,4,3,3,3,
|
||||
3,3,4,2,3,4,4,4,4,4,
|
||||
3,4,5,4,4,4,4,4,5,3,
|
||||
4,5,5,5,5,5,4,5,6,5,
|
||||
5,5,5,5,6,4,5,6,6,6,
|
||||
6,6,5,6,7,6,6,6,6,6,
|
||||
7,5,6,7,7,7,7,7,6,7,
|
||||
8,7,7,7,7,7,8,6,7,8,
|
||||
8,8,8,8,7,8,9,8,8,8,
|
||||
8,8,9,7,8,9,9,9,9,9,
|
||||
8,9,10,9,9,9,9,9,10,8,
|
||||
9,10,10,10,10,10,9,10,11,10,
|
||||
10,10,10,10,11,9,10,11,11,11,
|
||||
11,11,10,11,12,11,11,11,11,11,
|
||||
12,10,11,12,12,12,12,12,11,12,
|
||||
13,12,12,12,12,12,13,11,12,13,
|
||||
13,13,13,13,12,13,14,13,13,13,
|
||||
13,13,14,12,13,14,14,14,14,14,
|
||||
13,14,15,14,14,14,14,14,15,13,
|
||||
14,15,15,15,15,15,14,15,16,15,
|
||||
15,15,15,15,16,14,15,16,16,16,
|
||||
16,16,15,16,17,16,16,16,16,16,
|
||||
17,15,16,17,17,17,17,17,16,17,
|
||||
18,17,17,17,17,17,18,16,17,18,
|
||||
18,18,18,18,17,18,19,18,18,18,
|
||||
18,18,19,17,18,19,19,19,19,19,
|
||||
18,19,20,19,19,19,19,19,20,18,
|
||||
19,20,20,20,20,20,19,20,21,20,
|
||||
20,20,20,20,21,19,20,21,21,21,
|
||||
21,21,20,21,22,21,21,21,21,21,
|
||||
22,20,21,22,22,22,22,22,21,22,
|
||||
23,22,22,22,22,22,23,21,22,23,
|
||||
23,23,23,23,22,23,24,23,23,23,
|
||||
23,23,24,22,23,24,24,24,24,24,
|
||||
23,24,25,24,24,24,24,24,25,23,
|
||||
24,25,25,25,25,25,24,25,26,25,
|
||||
25,25,25,25,26,24,25,26,26,26,
|
||||
26,26,25,26,27,26,26,26,26,26,
|
||||
27,25,26,27,27,27,27,27,26,27,
|
||||
28,27,27,27,27,27,28,26,27,28,
|
||||
28,28,28,28,27,28,29,28,28,28,
|
||||
28,28,29,27,28,29,29,29,29,29,
|
||||
28,29,30,29,29,29,29,29,30,28,
|
||||
29,30,30,30,30,30,29,30,31,30,
|
||||
30,30,30,30,31,29,30,31,31,31,
|
||||
31,31,30,31,32,31,31,31,31,31,
|
||||
32,30,31,32,32,32,32,32,31,32,
|
||||
33,32,32,32,32,32,33,31,32,33,
|
||||
33,33,33,33,32,33,34,33,33,33,
|
||||
33,33,34,32,33,
|
||||
};
|
||||
|
||||
#endif /* __FSDITHER_H__ */
|
||||
958
gbdk-support/png2hicolorgb/src/hicolor/hicolour.c
Normal file
958
gbdk-support/png2hicolorgb/src/hicolor/hicolour.c
Normal file
@@ -0,0 +1,958 @@
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include "defines.h"
|
||||
#include "hicolour.h"
|
||||
#include "median.h"
|
||||
#include "wu.h"
|
||||
|
||||
|
||||
#include <common.h>
|
||||
#include <options.h>
|
||||
#include <files.h>
|
||||
#include <image_info.h>
|
||||
#include <logging.h>
|
||||
#include <c_source.h>
|
||||
#include <tile_dedupe.h>
|
||||
|
||||
/* Gameboy Hi-Colour Convertor */
|
||||
/* Glen Cook */
|
||||
/* Jeff Frohwein */
|
||||
/* Rob Jones */
|
||||
|
||||
|
||||
/*
|
||||
|
||||
This code is based on the code written by Jeff Frohwein. Jeff originally wrote a 128x128
|
||||
Gameboy HiColour convertor and made the source publically available. The problem with
|
||||
the original work, is that the output from the original code had a large white border
|
||||
making the picture look framed.
|
||||
|
||||
The original code was then modified by another party to produce a full screen image, using
|
||||
a fixed attribute block size of 3-2-3-2-3-2-3-2. The output from this modified code looked
|
||||
great, but some pictures had artifacts, due to the fixed attribute size.
|
||||
|
||||
I then decided to modify the full screen code, to produce pictures with less artifacts, the
|
||||
attribute blocks are not fixed, they can adapt their size based on the type of picture that
|
||||
is being converted.
|
||||
|
||||
This program will step through every possible combination of attributes to find the best
|
||||
possible solution.
|
||||
|
||||
The program gives the user the option of using fixed or adaptive attribute blocks, fixed
|
||||
attribute blocks are much quicker to calculate, but the picture quality may not be perfect.
|
||||
|
||||
After creating a DOS version of this program, I then went ahead and wrote a windows interface
|
||||
for it, to tidy it up, and also give me the chance to learn some windows programming. This is
|
||||
my first windows program, so please be kind.
|
||||
|
||||
The best method for converting the pictures, is to use Adaptive method 3, although this can
|
||||
take quite a bit longer to calculate than the fixed size calculations.
|
||||
|
||||
I believe that the new median cut method with dither produces the best results in general,
|
||||
but the other quantisers can produce better results for other picture types.
|
||||
|
||||
I am releasing this program into the public domain, feel free to adapt it in anyway that you
|
||||
deem fit. I you feel you have improved this program in anyway, drop me a line, and I will
|
||||
incorperate the changes into newer versions. (GlenCook@hotmail.com)
|
||||
|
||||
*/
|
||||
|
||||
|
||||
/* HISTORY */
|
||||
|
||||
|
||||
// V1.0 - 27th March 2000 - First public release
|
||||
// V1.1 - 30th March 2000 - Rob Jones added seperate thread for conversion process
|
||||
// V1.2 - 8th April 2000 - Added other quantisation methods
|
||||
// V1.4 - 2023 - Converted to cross platform console utility with PNG support (bbbbbr)
|
||||
|
||||
|
||||
// Function prototypes
|
||||
|
||||
int br,bg,bb;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
u8 p1;
|
||||
u8 p2;
|
||||
u8 FileType;
|
||||
u8 p3[9];
|
||||
u16 XSize;
|
||||
u16 YSize;
|
||||
u8 BitDepth;
|
||||
u8 c1;
|
||||
u8 data[160*BUF_HEIGHT][3];
|
||||
} IMG_TYPE;
|
||||
|
||||
|
||||
// u8 QR[BUF_HEIGHT][160][3];
|
||||
u8 TileOffset[4]; // Offset into screen for attribute start
|
||||
u8 TileWidth[4]; // No of character attributes width
|
||||
u8 Pal[8][BUF_Y_REGION_COUNT_LR_RNDUP][28][3]; // Palettes for every other line
|
||||
u8 IdealPal[8][BUF_Y_REGION_COUNT_LR_RNDUP][4][3]; // The best fit palette
|
||||
u8 pic[160][BUF_HEIGHT][3]; // Original Picture
|
||||
u8 pic2[160][BUF_HEIGHT][3]; // Output picture
|
||||
u8 out[160][BUF_HEIGHT]; // Output data
|
||||
|
||||
u8 raw[2][160][BUF_HEIGHT][3]; // Original Picture Raw format.
|
||||
// sourced from [0] = Normal , [1] = GB Color selected by ViewType
|
||||
|
||||
// TODO: delete?
|
||||
s32 ViewType=0; // Type of view to show: 0 = Normal , 1 = GB Color
|
||||
|
||||
u8 Best[2][BUF_HEIGHT_IN_TILES_RNDUP]; // Best Attribute type to use
|
||||
u8 LConversion; // Conversion type for left hand side of the screen
|
||||
u8 RConversion; // Conversion type for right hand side of the screen
|
||||
// HWND Ghdwnd; // Global window handle
|
||||
u8 MapTileIDs[20][BUF_HEIGHT_IN_TILES]; // Attribute table for final render
|
||||
u8 MapAttributes[20][BUF_HEIGHT_IN_TILES]; // Attribute table for final render
|
||||
uint8_t TileSet[20 * BUF_HEIGHT_IN_TILES * TILE_SZ]; // Sequential Tileset Data in Game Boy 2bpp format
|
||||
uint8_t TileSetDeduped[20 * BUF_HEIGHT_IN_TILES * TILE_SZ]; // Sequential Tileset Data in Game Boy 2bpp format
|
||||
unsigned int TileCountDeduped;
|
||||
// u8 OldLConv=0; // Conversion type
|
||||
// u8 OldRConv=0;
|
||||
uint8_t * pBuffer;
|
||||
// u8 Message[2000];
|
||||
s32 ConvertType; //=2;
|
||||
|
||||
u8 Data[160*BUF_HEIGHT*3]; // Gets used for quantizing regions. Maybe other things too?
|
||||
|
||||
u32 TempD;
|
||||
s32 BestLine=0; // TODO: convert to local var
|
||||
u32 BestQuantLine;
|
||||
// RGBQUAD GBView; // converted to local vars
|
||||
|
||||
|
||||
|
||||
// Shim buffers for the former windows rendered images that were also used for some calculationss
|
||||
// bmihsource.biWidth = 160;
|
||||
// bmihsource.biHeight = BUF_HEIGHT;
|
||||
// bmihsource.biPlanes = 1;
|
||||
// bmihsource.biBitCount = 24;
|
||||
static uint8_t Bitsdest[160 * BUF_HEIGHT * 3]; // TODO: RGBA 4 bytes per pixel?
|
||||
static uint8_t Bitssource[160 * BUF_HEIGHT * 3];
|
||||
//
|
||||
static uint8_t *pBitsdest = Bitsdest;
|
||||
uint8_t *pBitssource = Bitssource;
|
||||
|
||||
|
||||
#define MAX_CONVERSION_TYPES 83
|
||||
#define MAX_QUANTISER_TYPES 4
|
||||
|
||||
int image_y_min;
|
||||
int image_y_max;
|
||||
int image_height;
|
||||
int y_region_count_left;
|
||||
int y_region_count_right;
|
||||
int y_region_count_lr_rndup;
|
||||
int y_region_count_both_sides;
|
||||
int y_height_in_tiles_left;
|
||||
int y_height_in_tiles_right;
|
||||
int y_height_in_tiles;
|
||||
int y_height_in_tiles_lr_rndup;
|
||||
|
||||
|
||||
static void PrepareTileSet(void);
|
||||
static void PrepareMap(void);
|
||||
static void PrepareAttributes(void);
|
||||
|
||||
static void DedupeTileset(void);
|
||||
|
||||
static void ExportPalettes(const char * fname_base);
|
||||
static void ExportTileSet(const char * fname_base);
|
||||
static void ExportMap(const char * fname_base);
|
||||
static void ExportMapAttributes(const char * fname_base);
|
||||
|
||||
|
||||
void hicolor_init(void) {
|
||||
// Defaults
|
||||
LConversion = 3; // Default Conversion (Fixed 3-2-3-2) Left Screen
|
||||
RConversion = 3; // Default Conversion (Fixed 3-2-3-2) Righ Screen
|
||||
ConvertType = 1; // Normal default is 1 ("Median cut - no dither")
|
||||
}
|
||||
|
||||
static void hicolor_vars_prep(image_data * p_loaded_image) {
|
||||
log_debug("hicolor_vars_prep()\n");
|
||||
|
||||
image_height = p_loaded_image->height;
|
||||
image_y_min = 0;
|
||||
image_y_max = p_loaded_image->height - 1;
|
||||
|
||||
// // Screen palette region updates are 80 pixels wide and 2 pixels tall
|
||||
// // since palette 0-3 allocated to left side, 4-7 allocated to right side
|
||||
// // and only 4 palettes are updated per scanline, so Left and Right alternate in gettig udpates
|
||||
// // 73(L) & 72(R) for standard GB screen
|
||||
|
||||
// One extra region due to starting at -1 Y offset from screen grid, and so there is a last extra entry that "hangs off" the bottom of the screen
|
||||
y_region_count_left = ((image_height / PAL_REGION_HEIGHT_PX) + 1);
|
||||
y_region_count_right = (image_height / PAL_REGION_HEIGHT_PX);
|
||||
// Use larger size[side] for rounded up amount
|
||||
y_region_count_lr_rndup = (y_region_count_left);
|
||||
y_region_count_both_sides = (y_region_count_left + y_region_count_right);
|
||||
|
||||
// 19(L) & 18(R) for standard GB Full screen height
|
||||
// One extra region due to starting at -1 Y offset from screen grid, and so there is a last extra entry that "hangs off" the bottom of the screen
|
||||
y_height_in_tiles_left = ((image_height / TILE_HEIGHT_PX) + 1);
|
||||
y_height_in_tiles_right = (image_height / TILE_HEIGHT_PX);
|
||||
y_height_in_tiles = (image_height / TILE_HEIGHT_PX);
|
||||
// Use larger size[side] for rounded up amount
|
||||
y_height_in_tiles_lr_rndup = (y_height_in_tiles_left);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void hicolor_set_convert_left_pattern(uint8_t new_value) {
|
||||
// IDC_CONVERTLEFT
|
||||
LConversion = new_value;
|
||||
log_verbose("HiColor: Left pattern set to %d\n", new_value);
|
||||
}
|
||||
|
||||
|
||||
void hicolor_set_convert_right_pattern(uint8_t new_value) {
|
||||
// IDC_CONVERTRIGHT
|
||||
RConversion = new_value;
|
||||
log_verbose("HiColor: Right pattern set to %d\n", new_value);
|
||||
}
|
||||
|
||||
|
||||
void hicolor_set_type(uint8_t new_value) {
|
||||
// IDC_CONVERTTYPE
|
||||
ConvertType = new_value;
|
||||
log_verbose("HiColor: Convert type set to %d\n", new_value);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////
|
||||
|
||||
// Equivalent of former file loading
|
||||
static void hicolor_image_import(image_data * p_loaded_image) {
|
||||
log_debug("hicolor_image_import()\n");
|
||||
|
||||
// TODO: input guarding
|
||||
// TODO: deduplicate some of the array copying around
|
||||
uint8_t * p_input_img = p_loaded_image->p_img_data;
|
||||
|
||||
for (int y=0; y< image_height; y++) {
|
||||
for (int x=0; x< 160; x++) {
|
||||
|
||||
// Clamp to CGB max R/G/B value in RGB 888 mode (31u << 3)
|
||||
// png_image[].rgb -> pic2[].rgb -> pBitssource[].bgr??
|
||||
pic2[x][y][0] = (p_input_img[RGB_RED] & 0xf8u);
|
||||
pic2[x][y][1] = (p_input_img[RGB_GREEN] & 0xf8u);
|
||||
pic2[x][y][2] = (p_input_img[RGB_BLUE] & 0xf8u);
|
||||
|
||||
p_input_img += RGB_24SZ; // Move to next pixel of source image
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Eventually clean up data pathway to remove some vestigial former display rendering buffers
|
||||
// It's convoluted, but pBitssource & pBitsdest are used for:
|
||||
// - display as windows DIBs (formerly)
|
||||
// - and for some calculations at the end of ConvertRegions()
|
||||
for (int y=0; y<image_height; y++) {
|
||||
for (int x=0; x<160; x++) {
|
||||
for (int z=0; z<3; z++) {
|
||||
// TODO: (2-z) seems to be swapping RGB for BGR?
|
||||
*(pBitssource+(image_y_max-y)*3*160+x*3+z) = pic2[x][y][2-z]; // Invert the dib, cos windows likes it like that !!
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// TODO: fix
|
||||
// TODO: Operates on RGB data in pic[] copied from RGB data in pic2
|
||||
static void hicolor_convert(void) {
|
||||
log_debug("hicolor_convert()\n");
|
||||
|
||||
for(int x=0; x<160; x++)
|
||||
{
|
||||
for(int y=0; y<image_height; y++)
|
||||
{
|
||||
pic[x][y][0] = pic2[x][y][0];
|
||||
pic[x][y][1] = pic2[x][y][1];
|
||||
pic[x][y][2] = pic2[x][y][2];
|
||||
|
||||
for(int i=0; i<3; i++)
|
||||
{
|
||||
*(Data + y*160*3+x*3+i) = pic[x][y][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ConvertToHiColor(ConvertType-1);
|
||||
}
|
||||
|
||||
|
||||
static void hicolor_save(const char * fname_base) {
|
||||
|
||||
// Default tile count to non-deduplicated number
|
||||
int tile_count = y_height_in_tiles * (160 / TILE_WIDTH_PX);
|
||||
|
||||
log_debug("hicolor_save()\n");
|
||||
PrepareTileSet();
|
||||
PrepareMap();
|
||||
PrepareAttributes();
|
||||
|
||||
if (opt_get_tile_dedupe()) {
|
||||
DedupeTileset();
|
||||
tile_count = TileCountDeduped;
|
||||
}
|
||||
|
||||
ExportTileSet(fname_base);
|
||||
ExportPalettes(fname_base);
|
||||
ExportMap(fname_base);
|
||||
ExportMapAttributes(fname_base);
|
||||
|
||||
if (opt_get_c_file_output()) {
|
||||
file_c_output_write(fname_base, opt_get_bank_num(), tile_count, y_height_in_tiles);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Currently expects width x height x 3(RGB888)
|
||||
void hicolor_process_image(image_data * p_loaded_image, const char * fname_base) {
|
||||
log_debug("hicolor_process_image(), fname_base: \"%s\"\n", fname_base);
|
||||
|
||||
hicolor_vars_prep(p_loaded_image);
|
||||
hicolor_image_import(p_loaded_image);
|
||||
hicolor_convert();
|
||||
hicolor_save(fname_base);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
static void DedupeTileset(void)
|
||||
{
|
||||
unsigned int map_tile_id;
|
||||
uint8_t new_tile_id, new_attribs;
|
||||
|
||||
TileCountDeduped = 0;
|
||||
// Traverse all tiles in the image/map
|
||||
for (int mapy = 0; mapy < y_height_in_tiles; mapy++) {
|
||||
for (int mapx = 0; mapx < 20; mapx++) {
|
||||
|
||||
map_tile_id = MapTileIDs[mapx][mapy];
|
||||
map_tile_id += (MapAttributes[mapx][mapy] & CGB_ATTR_TILES_BANK) ? CGB_TILES_START_BANK_1 : CGB_TILES_START_BANK_0;
|
||||
|
||||
if (!tileset_find_matching_tile(&TileSet[map_tile_id * TILE_SZ], &TileSetDeduped[0], TileCountDeduped, &new_tile_id, &new_attribs)) {
|
||||
// If no match, copy tile to new tile set and save new index for remapping
|
||||
new_tile_id = TileCountDeduped;
|
||||
new_attribs = (TileCountDeduped < CGB_TILES_START_BANK_1) ? CGB_ATTR_TILES_BANK_0 : CGB_ATTR_TILES_BANK_1;
|
||||
memcpy(&TileSetDeduped[TileCountDeduped * TILE_SZ], &TileSet[map_tile_id * TILE_SZ], TILE_SZ);
|
||||
TileCountDeduped++;
|
||||
}
|
||||
|
||||
// Update map data and attributes to new index
|
||||
// Mask out everything except palettes and then apply the new attribs (bank, vflip, hflip)
|
||||
MapTileIDs[mapx][mapy] = new_tile_id;
|
||||
MapAttributes[mapx][mapy] = (MapAttributes[mapx][mapy] & CGB_ATTR_PALLETES_ONLY) | new_attribs;
|
||||
}
|
||||
}
|
||||
log_verbose("DedupeTileset(): Reduced tiles from %d (%d bytes) to %d (%d bytes) = %d bytes saved. %%%d of original size\n",
|
||||
map_tile_id + 1, (map_tile_id + 1) * TILE_SZ, TileCountDeduped, TileCountDeduped * TILE_SZ,
|
||||
((map_tile_id + 1) * TILE_SZ) - (TileCountDeduped * TILE_SZ), (TileCountDeduped * 100) / (map_tile_id + 1));
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
static void PrepareTileSet(void) {
|
||||
uint32_t byteWritten;
|
||||
u32 x, y;
|
||||
u8 c1,c2;
|
||||
u8 dx,dy;
|
||||
u8 c;
|
||||
|
||||
uint8_t * p_buf = TileSet;
|
||||
|
||||
// Write out tilemap data, Left -> Right, Top -> Bottom, 16 bytes per tile
|
||||
for (y=0; y<image_height; y=y+8)
|
||||
{
|
||||
for (x=0; x<160; x=x+8)
|
||||
{
|
||||
for (dy=0; dy<8; dy++)
|
||||
{
|
||||
c1 = 0;
|
||||
c2 = 0;
|
||||
for (dx=0; dx<8; dx++)
|
||||
{
|
||||
c1 = (u8)(c1 << 1);
|
||||
c2 = (u8)(c2 << 1);
|
||||
c = out[x+dx][y+dy];
|
||||
if (c & 2) c1++;
|
||||
if (c & 1) c2++;
|
||||
}
|
||||
|
||||
*p_buf++ = c2;
|
||||
*p_buf++ = c1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void PrepareMap(void) {
|
||||
// Set up export Map Tile IDs
|
||||
// Note: The indexes are clipped to 0-255 (instead of 0-512),
|
||||
// the attribute tile index+256 bit is auto-calculated in the attribute map in PrepareAttributes()
|
||||
int tile_id = 0;
|
||||
for (int mapy = 0; mapy < y_height_in_tiles; mapy++) {
|
||||
for (int mapx = 0; mapx < 20; mapx++) {
|
||||
|
||||
MapTileIDs[mapx][mapy] = (uint8_t)tile_id;
|
||||
tile_id++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void PrepareAttributes(void) {
|
||||
// Set up the Map Attributes table
|
||||
unsigned int tile_id = 0;
|
||||
for(int MastY=0;MastY<y_height_in_tiles_right;MastY++)
|
||||
{
|
||||
for(int MastX=0;MastX<2;MastX++)
|
||||
{
|
||||
int Line=Best[MastX][MastY];
|
||||
int width=0;
|
||||
for(int i=0;i<4;i++)
|
||||
{
|
||||
TileOffset[i]=width;
|
||||
TileWidth[i]=SplitData[Line][i];
|
||||
width+=TileWidth[i];
|
||||
}
|
||||
|
||||
for(int x=0;x<4;x++) {
|
||||
for(int z=TileOffset[x];z<(TileOffset[x]+TileWidth[x]);z++) {
|
||||
MapAttributes[MastX*10+z][MastY]=x+MastX*4;
|
||||
// Mask in second CGB Tile Bank flag if tile index is over 256 tiles
|
||||
if (tile_id++ >= 256)
|
||||
MapAttributes[MastX*10+z][MastY] |= CGB_ATTR_TILES_BANK_1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ExportTileSet(const char * fname_base)
|
||||
{
|
||||
char filename[MAX_PATH*2];
|
||||
|
||||
strcpy(filename, fname_base);
|
||||
strcat(filename, ".til");
|
||||
log_verbose("Writing Tile Patterns to: %s\n", filename);
|
||||
|
||||
if (opt_get_tile_dedupe()) {
|
||||
|
||||
int outbuf_sz_tiles = TileCountDeduped * TILE_SZ;
|
||||
if (!file_write_from_buffer(filename, TileSetDeduped, outbuf_sz_tiles))
|
||||
set_exit_error();
|
||||
} else {
|
||||
|
||||
int outbuf_sz_tiles = ((image_height / TILE_HEIGHT_PX) * (160 / TILE_WIDTH_PX) * 8 * 2);
|
||||
if (!file_write_from_buffer(filename, TileSet, outbuf_sz_tiles))
|
||||
set_exit_error();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void ExportPalettes(const char * fname_base)
|
||||
{
|
||||
char filename[MAX_PATH * 2];
|
||||
uint32_t byteWritten;
|
||||
uint8_t tmpByte;
|
||||
s32 i, j, k;
|
||||
s32 r,g,b,v;
|
||||
|
||||
strcpy(filename, fname_base);
|
||||
strcat(filename, ".pal");
|
||||
log_verbose("Writing Palette to: %s\n", filename);
|
||||
|
||||
int outbuf_sz_pals = (((y_region_count_both_sides) * 4 * 4 * 2) + 1);
|
||||
uint8_t output_buf[outbuf_sz_pals];
|
||||
uint8_t * p_buf = output_buf;
|
||||
|
||||
|
||||
for (i = 0; i < (y_region_count_both_sides); i++) // Number of palette sets (left side updates + right side updates)
|
||||
{
|
||||
for (j = 0; j < 4; j++) // Each palette in the set
|
||||
{
|
||||
for(k=0; k<4;k++) // Each color in the palette
|
||||
{
|
||||
r = IdealPal[(i%2)*4+j][i/2][k][0];
|
||||
g = IdealPal[(i%2)*4+j][i/2][k][1];
|
||||
b = IdealPal[(i%2)*4+j][i/2][k][2];
|
||||
|
||||
// TODO: Converting to BGR555 probably
|
||||
v = ((b/8)*32*32) + ((g/8)*32) + (r/8);
|
||||
|
||||
// 2 bytes per color
|
||||
*p_buf++ = (u8)(v & 255);
|
||||
*p_buf++ = (u8)(v / 256);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: What is this and why? :)
|
||||
*p_buf++ = 0x2d;
|
||||
|
||||
if (!file_write_from_buffer(filename, output_buf, outbuf_sz_pals))
|
||||
set_exit_error();
|
||||
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
static void ExportMap(const char * fname_base)
|
||||
{
|
||||
char filename[MAX_PATH*2];
|
||||
|
||||
strcpy(filename, fname_base);
|
||||
strcat(filename, ".map");
|
||||
log_verbose("Writing Tile Map to: %s\n", filename);
|
||||
|
||||
int outbuf_sz_map = (20 * y_height_in_tiles);
|
||||
uint8_t output_buf_map[outbuf_sz_map];
|
||||
|
||||
int tile_id = 0;
|
||||
for (int y = 0; y < y_height_in_tiles; y++) {
|
||||
for (int x = 0; x < 20; x++) {
|
||||
uint8_t tile_num = MapTileIDs[x][y];
|
||||
|
||||
// This needs to happen here, after optional deduplication stage
|
||||
// since that may rewrite the tile pattern order and indexes
|
||||
if (opt_get_map_tile_order() != OPT_MAP_TILE_SEQUENTIAL_ORDER) // implied: OPT_MAP_TILE_ORDER_BY_VRAM_ID
|
||||
tile_num = ((tile_num < 128) ? (tile_num) + 128 : (tile_num) - 128); // Previous ordering that was: 128 -> 255 -> 0 -> 127
|
||||
|
||||
output_buf_map[tile_id] = tile_num;
|
||||
tile_id++;
|
||||
}
|
||||
}
|
||||
|
||||
if (!file_write_from_buffer(filename, output_buf_map, outbuf_sz_map))
|
||||
set_exit_error();
|
||||
}
|
||||
|
||||
|
||||
static void ExportMapAttributes(const char * fname_base)
|
||||
{
|
||||
char filename[MAX_PATH*2];
|
||||
|
||||
strcpy(filename, fname_base);
|
||||
strcat(filename, ".atr");
|
||||
log_verbose("Writing Attribute Map to: %s\n", filename);
|
||||
|
||||
int outbuf_sz_map = (20 * y_height_in_tiles);
|
||||
uint8_t output_buf_map[outbuf_sz_map];
|
||||
|
||||
int tile_id = 0;
|
||||
for (int y = 0; y < y_height_in_tiles; y++)
|
||||
{
|
||||
for (int x = 0; x < 20; x++)
|
||||
{
|
||||
output_buf_map[tile_id++] = MapAttributes[x][y];
|
||||
}
|
||||
}
|
||||
|
||||
if (!file_write_from_buffer(filename, output_buf_map, outbuf_sz_map))
|
||||
set_exit_error();
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// This section of code is used to convert an RGB (pc) triplet into a RGB (gameboy)
|
||||
// triplet. This section of code was kindly donated by Brett Bibby (GameBrains).
|
||||
|
||||
uint8_t intensity[32] =
|
||||
{
|
||||
0x00,0x10,0x20,0x30,0x40,0x50,0x5e,0x6c,0x7a,0x88,0x94,0xa0,0xae,0xb7,0xbf,0xc6,
|
||||
0xce,0xd3,0xd9,0xdf,0xe3,0xe7,0xeb,0xef,0xf3,0xf6,0xf9,0xfb,0xfd,0xfe,0xff,0xff
|
||||
};
|
||||
|
||||
unsigned char influence[3][3] =
|
||||
{
|
||||
{16,4,4},
|
||||
{8,16,8},
|
||||
{0,8,16}
|
||||
};
|
||||
|
||||
RGBQUAD translate(uint8_t rgb[3])
|
||||
{
|
||||
RGBQUAD color;
|
||||
uint8_t tmp[3];
|
||||
uint8_t m[3][3];
|
||||
uint8_t i,j;
|
||||
|
||||
for (i=0;i<3;i++)
|
||||
for (j=0;j<3;j++)
|
||||
m[i][j] = (intensity[rgb[i]>>3]*influence[i][j]) >> 5;
|
||||
|
||||
for (i=0;i<3;i++)
|
||||
{
|
||||
if (m[0][i]>m[1][i])
|
||||
{
|
||||
j=m[0][i];
|
||||
m[0][i]=m[1][i];
|
||||
m[1][i]=j;
|
||||
}
|
||||
|
||||
if (m[1][i]>m[2][i])
|
||||
{
|
||||
j=m[1][i];
|
||||
m[1][i]=m[2][i];
|
||||
m[2][i]=j;
|
||||
}
|
||||
|
||||
if (m[0][i]>m[1][i])
|
||||
{
|
||||
j=m[0][i];
|
||||
m[0][i]=m[1][i];
|
||||
m[1][i]=j;
|
||||
}
|
||||
|
||||
tmp[i]=(((m[0][i]+m[1][i]*2+m[2][i]*4)*5) >> 4)+32;
|
||||
}
|
||||
|
||||
color.rgbRed = tmp[0];
|
||||
color.rgbGreen = tmp[1];
|
||||
color.rgbBlue = tmp[2];
|
||||
|
||||
return color;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
// Data table containing all of the possible combinations of attribute blocks
|
||||
// for one side of the screen.
|
||||
|
||||
// The higher the adaptive level, the more combinations of attributes are tested.
|
||||
|
||||
u8 SplitData[80][4]=
|
||||
{
|
||||
{3,2,3,2},{2,3,2,3},{2,2,3,3},{2,3,3,2},{3,2,2,3},{3,3,2,2},{4,2,2,2},{2,2,2,4},{2,2,4,2},{2,4,2,2},{1,1,2,6},
|
||||
{1,1,3,5},{1,1,4,4},{1,1,5,3},{1,1,6,2},{1,2,1,6},{1,2,2,5},{1,2,3,4},{1,2,4,3},{1,2,5,2},{1,2,6,1},{1,3,1,5},
|
||||
{1,3,2,4},{1,3,3,3},{1,3,4,2},{1,3,5,1},{1,4,1,4},{1,4,2,3},{1,4,3,2},{1,4,4,1},{1,5,1,3},{1,5,2,2},{1,5,3,1},
|
||||
{1,6,1,2},{1,6,2,1},{2,1,1,6},{2,1,2,5},{2,1,3,4},{2,1,4,3},{2,1,5,2},{2,1,6,1},{2,2,1,5},{2,2,5,1},{2,3,1,4},
|
||||
{2,3,4,1},{2,4,1,3},{2,4,3,1},{2,5,1,2},{2,5,2,1},{2,6,1,1},{3,1,1,5},{3,1,2,4},{3,1,3,3},{3,1,4,2},{3,1,5,1},
|
||||
{3,2,1,4},{3,2,4,1},{3,3,1,3},{3,3,3,1},{3,4,1,2},{3,4,2,1},{3,5,1,1},{4,1,1,4},{4,1,2,3},{4,1,3,2},{4,1,4,1},
|
||||
{4,2,1,3},{4,2,3,1},{4,3,1,2},{4,3,2,1},{4,4,1,1},{5,1,1,3},{5,1,2,2},{5,1,3,1},{5,2,1,2},{5,2,2,1},{5,3,1,1},
|
||||
{6,1,1,2},{6,1,2,1},{6,2,1,1}
|
||||
};
|
||||
|
||||
|
||||
|
||||
unsigned int ImageRating(u8 *src, u8 *dest, int StartX, int StartY, int Width, int Height)
|
||||
{
|
||||
log_debug("ImageRating()\n");
|
||||
unsigned int tot;
|
||||
int x,y;
|
||||
unsigned int accum=0;
|
||||
int scradd;
|
||||
|
||||
for(y=StartY;y<(StartY+Height);y++)
|
||||
{
|
||||
for(x=StartX;x<(StartX+Width);x++)
|
||||
{
|
||||
scradd=(image_y_max-y)*(160*3)+x*3;
|
||||
tot=(*(src+scradd)-*(dest+scradd)) * (*(src+scradd)-*(dest+scradd));
|
||||
tot+=(*(src+scradd+1)-*(dest+scradd+1)) * (*(src+scradd+1)-*(dest+scradd+1));
|
||||
tot+=(*(src+scradd+2)-*(dest+scradd+2)) * (*(src+scradd+2)-*(dest+scradd+2));
|
||||
accum+=tot;
|
||||
}
|
||||
}
|
||||
|
||||
return accum;
|
||||
}
|
||||
|
||||
|
||||
// TODO: rename to something that aligns with other convert functions
|
||||
void ConvertToHiColor(int ConvertType)
|
||||
{
|
||||
log_debug("ConvertToHiColor()\n");
|
||||
int res;
|
||||
int x,y,z,i;
|
||||
int StartSplit=0;
|
||||
int NumSplit=1;
|
||||
int Steps;
|
||||
int MastX,MastY;
|
||||
int Line;
|
||||
int width;
|
||||
unsigned int tile_id;
|
||||
|
||||
switch(LConversion)
|
||||
{
|
||||
case 0:
|
||||
|
||||
StartSplit=0;
|
||||
NumSplit=6;
|
||||
Steps=504;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
|
||||
StartSplit=0;
|
||||
NumSplit=10;
|
||||
Steps=792;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
||||
StartSplit=0;
|
||||
NumSplit=80;
|
||||
Steps=5832;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
StartSplit=LConversion-3;
|
||||
NumSplit=1;
|
||||
Steps=image_height;
|
||||
break;
|
||||
}
|
||||
|
||||
switch(RConversion)
|
||||
{
|
||||
case 0:
|
||||
|
||||
Steps+=504;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
|
||||
Steps+=792;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
||||
Steps+=5832;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
Steps+=image_height;
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// Convert left side with one extra tile of height to fix
|
||||
// the glitching where the last scanline on left bottom region
|
||||
// lacks tile and palette data
|
||||
res=ConvertRegions(0,1,0,y_height_in_tiles_left,StartSplit,NumSplit,ConvertType); // Step through all options
|
||||
ConvertRegions(0,1,0,y_height_in_tiles_left,res,1,ConvertType);
|
||||
|
||||
// Formerly: for(y=0;y<189;y++)
|
||||
// Treating it as a typo (intended a "18") since 189 would be out of bounds for the original array
|
||||
for(y=0;y<y_height_in_tiles_left;y++)
|
||||
Best[0][y]=res;
|
||||
|
||||
|
||||
switch(RConversion)
|
||||
{
|
||||
case 0:
|
||||
|
||||
StartSplit=0;
|
||||
NumSplit=6;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
|
||||
StartSplit=0;
|
||||
NumSplit=10;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
|
||||
StartSplit=0;
|
||||
NumSplit=80;
|
||||
break;
|
||||
|
||||
default:
|
||||
|
||||
StartSplit=RConversion-3;
|
||||
NumSplit=1;
|
||||
break;
|
||||
}
|
||||
|
||||
for(y=0;y<y_height_in_tiles_right;y++)
|
||||
{
|
||||
res=ConvertRegions(1,1,y,1,StartSplit,NumSplit,ConvertType); // Step through all options
|
||||
ConvertRegions(1,1,y,1,res,1,ConvertType);
|
||||
Best[1][y]=res;
|
||||
}
|
||||
|
||||
|
||||
// TODO: fix me -> pBitsdest being used in conversion process
|
||||
for(y=0;y<image_height;y++)
|
||||
{
|
||||
for(x=0;x<160;x++)
|
||||
{
|
||||
raw[0][x][y][0] = *(pBitsdest+(image_y_max-y)*3*160+x*3+2);
|
||||
raw[0][x][y][1] = *(pBitsdest+(image_y_max-y)*3*160+x*3+1);
|
||||
raw[0][x][y][2] = *(pBitsdest+(image_y_max-y)*3*160+x*3);
|
||||
|
||||
RGBQUAD GBView=translate(raw[0][x][y]);
|
||||
|
||||
raw[1][x][y][0] = GBView.rgbRed;
|
||||
raw[1][x][y][1] = GBView.rgbGreen;
|
||||
raw[1][x][y][2] = GBView.rgbBlue;
|
||||
}
|
||||
}
|
||||
log_progress("\n");
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Start X = 0 for Left / 1 for Right
|
||||
// Width = 1 for half screen 2 = full screen
|
||||
// StartY = 0 - 17 : Starting attribute block
|
||||
// Height = Number of attribute blocks to check / process
|
||||
|
||||
int ConvertRegions(int StartX, int Width, int StartY, int Height, int StartJ, int FinishJ, int ConvertType)
|
||||
{
|
||||
log_debug("ConvertRegions()\n");
|
||||
u32 Accum,width,x1,ts,tw,y2,x2,y_offset;
|
||||
s32 x,y;
|
||||
s32 i,j;
|
||||
u8 col;
|
||||
|
||||
|
||||
BestQuantLine=0xffffffff;
|
||||
|
||||
for(x=StartX;x<(StartX+Width);x++)
|
||||
{
|
||||
// Left side of screen is offset by -1 Y
|
||||
// (Left side calcs hang off top and bottom of screen
|
||||
// due to Left/Right palette update interleaving)
|
||||
if (x == CONV_SIDE_LEFT)
|
||||
y_offset = CONV_Y_SHIFT_UP_1;
|
||||
else
|
||||
y_offset = CONV_Y_SHIFT_NO;
|
||||
|
||||
for(j=StartJ;j<(StartJ+FinishJ);j++)
|
||||
{
|
||||
Accum=0;
|
||||
width=0;
|
||||
for(i=0;i<4;i++)
|
||||
{
|
||||
TileOffset[i]=width;
|
||||
TileWidth[i]=SplitData[j][i]<<3;
|
||||
width+=TileWidth[i];
|
||||
}
|
||||
|
||||
for(y=StartY*4;y<(StartY+Height)*4;y++)
|
||||
{
|
||||
log_progress(".");
|
||||
|
||||
for(x1=0;x1<4;x1++)
|
||||
{
|
||||
ts=TileOffset[x1];
|
||||
tw=TileWidth[x1];
|
||||
|
||||
for(y2=0;y2<2;y2++)
|
||||
{
|
||||
// Skip if Y line is outside image borders (prevents buffer overflow)
|
||||
// (Left side calcs hang off top and bottom of screen
|
||||
// due to Left/Right palette update interleaving)
|
||||
s32 y_line = (y*2+y2-y_offset);
|
||||
if ((y_line < image_y_min) || (y_line > image_y_max)) continue;
|
||||
|
||||
for(x2=0;x2<tw;x2++)
|
||||
{
|
||||
// i is iterating over r/g/b slots for the current pixel
|
||||
for(i=0;i<3;i++)
|
||||
{
|
||||
*(Data+(tw*3*y2)+x2*3+i) = pic[x*80+ts+x2][y*2+y2-y_offset][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch(ConvertType)
|
||||
{
|
||||
case 0:
|
||||
to_indexed(Data,4,0,TileWidth[x1],2); // Median Reduction No Dither
|
||||
break;
|
||||
|
||||
case 1:
|
||||
|
||||
to_indexed(Data,4,1,TileWidth[x1],2); // Median Reduction With Dither
|
||||
break;
|
||||
|
||||
case 2:
|
||||
wuReduce(Data,4,TileWidth[x1]*2); // Wu Reduction
|
||||
break;
|
||||
}
|
||||
|
||||
for(y2=0;y2<4;y2++)
|
||||
{
|
||||
// Skip if Y is outside allocated Palette size (prevents buffer overflow)
|
||||
// (Left side calcs hang off top and bottom of screen
|
||||
// due to Left/Right palette update interleaving)
|
||||
if (y >= y_region_count_lr_rndup) continue;
|
||||
|
||||
IdealPal[x*4+x1][y][y2][0]=QuantizedPalette[y2][2];
|
||||
IdealPal[x*4+x1][y][y2][1]=QuantizedPalette[y2][1];
|
||||
IdealPal[x*4+x1][y][y2][2]=QuantizedPalette[y2][0];
|
||||
}
|
||||
|
||||
for(y2=0;y2<2;y2++)
|
||||
{
|
||||
for(x2=0;x2<tw;x2++)
|
||||
{
|
||||
// Skip if Y line is outside image borders (prevents buffer overflow)
|
||||
// since Left side calcs hang off top and bottom of image/screen
|
||||
s32 y_line = (y*2+y2-y_offset);
|
||||
if ((y_line < image_y_min) || (y_line > image_y_max)) continue;
|
||||
|
||||
col=Picture256[y2*tw+x2];
|
||||
out[x*80+x2+ts][y*2+y2-y_offset]=col;
|
||||
|
||||
for(i=0;i<3;i++)
|
||||
{
|
||||
*(pBitsdest+(image_y_max-(y*2+y2-y_offset))*3*160+(x*80+ts+x2)*3+i)=QuantizedPalette[col][i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TempD=ImageRating(pBitssource,pBitsdest,StartX*80,StartY*8,Width*80,Height*8);
|
||||
|
||||
if(TempD<BestQuantLine)
|
||||
{
|
||||
BestLine=j;
|
||||
BestQuantLine=TempD;
|
||||
}
|
||||
}
|
||||
}
|
||||
return BestLine;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
63
gbdk-support/png2hicolorgb/src/hicolor/hicolour.h
Normal file
63
gbdk-support/png2hicolorgb/src/hicolor/hicolour.h
Normal file
@@ -0,0 +1,63 @@
|
||||
#ifndef __hicolour_h__
|
||||
#define __hicolour_h__
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#include <defines.h>
|
||||
|
||||
#include <image_info.h>
|
||||
#include <logging.h>
|
||||
|
||||
// For displaying available conversion patterns to the user
|
||||
#define HELP_CONV_PATTERN_STR \
|
||||
"Available conversion palette/attribute pattern widths for -cL:N and -cR:N\n" \
|
||||
"\n" \
|
||||
"- Default for Left and Right is 3\n" \
|
||||
"- Fixed pattern widths are faster but less optimal than adaptive\n" \
|
||||
"- Adaptive pattern width speeds are 1: fastest, 2: medium, 3: slowest (slower = higher quality)\n" \
|
||||
"\n" \
|
||||
" 0: Adaptive-1 1: Adaptive-2 2: Adaptive-3 3: 3-2-3-2 4: 2-3-2-3 \n" \
|
||||
" 5: 2-2-3-3 6: 2-3-3-2 7: 3-2-2-3 8: 3-3-2-2 9: 4-2-2-2 \n" \
|
||||
" 10: 2-2-2-4 11: 2-2-4-2 12: 2-4-2-2 13: 1-1-2-6 14: 1-1-3-5 \n" \
|
||||
" 15: 1-1-4-4 16: 1-1-5-3 17: 1-1-6-2 18: 1-2-1-6 19: 1-2-2-5 \n" \
|
||||
" 20: 1-2-3-4 21: 1-2-4-3 22: 1-2-5-2 23: 1-2-6-1 24: 1-3-1-5 \n" \
|
||||
" 25: 1-3-2-4 26: 1-3-3-3 27: 1-3-4-2 28: 1-3-5-1 29: 1-4-1-4 \n" \
|
||||
" 30: 1-4-2-3 31: 1-4-3-2 32: 1-4-4-1 33: 1-5-1-3 34: 1-5-2-2 \n" \
|
||||
" 35: 1-5-3-1 36: 1-6-1-2 37: 1-6-2-1 38: 2-1-1-6 39: 2-1-2-5 \n" \
|
||||
" 40: 2-1-3-4 41: 2,1,4,3 42: 2-1-5-2 43: 2-1-6-1 44: 2-2-1-5 \n" \
|
||||
" 45: 2-2-5-1 46: 2-3-1-4 47: 2-3-4-1 48: 2-4-1-3 49: 2-4-3-1 \n" \
|
||||
" 50: 2-5-1-2 51: 2-5-2-1 52: 2-6-1-1 53: 3-1-1-5 54: 3-1-2-4 \n" \
|
||||
" 55: 3-1-3-3 56: 3-1-4-2 57: 3-1-5-1 58: 3-2-1-4 59: 3-2-4-1 \n" \
|
||||
" 60: 3-3-1-3 61: 3-3-3-1 62: 3-4-1-2 63: 3-4-2-1 64: 3-5-1-1 \n" \
|
||||
" 65: 4-1-1-4 66: 4-1-2-3 67: 4-1-3-2 68: 4-1-4-1 69: 4-2-1-3 \n" \
|
||||
" 70: 4-2-3-1 71: 4-3-1-2 72: 4-3-2-1 73: 4-4-1-1 74: 5-1-1-3 \n" \
|
||||
" 75: 5-1-2-2 76: 5-1-3-1 77: 5-2-1-2 78: 5-2-2-1 79: 5-3-1-1 \n" \
|
||||
" 80: 6-1-1-2 81: 6-1-2-1 82: 6-2-1-1 \n"
|
||||
|
||||
|
||||
extern u8 TileOffset[4]; // Offset into screen for attribute start
|
||||
extern u8 TileWidth[4]; // No of character attributes width
|
||||
extern u8 SplitData[80][4];
|
||||
|
||||
extern RGBQUAD GBView;
|
||||
|
||||
void hicolor_init(void);
|
||||
|
||||
void hicolor_set_type(uint8_t new_value);
|
||||
void hicolor_set_convert_left_pattern(uint8_t new_value);
|
||||
void hicolor_set_convert_right_pattern(uint8_t new_value);
|
||||
|
||||
void hicolor_process_image(image_data * p_decoded_image, const char * fname);
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
RGBQUAD translate(uint8_t rgb[3]);
|
||||
unsigned int ImageRating(u8 *src, u8 *dest, int StartX, int StartY, int Width, int Height);
|
||||
void ConvertToHiColor(int ConvertType);
|
||||
int ConvertRegions(int StartX, int Width, int StartY, int Height, int StartJ, int FinishJ, int ConvertType);
|
||||
|
||||
|
||||
#endif
|
||||
1017
gbdk-support/png2hicolorgb/src/hicolor/median.c
Normal file
1017
gbdk-support/png2hicolorgb/src/hicolor/median.c
Normal file
File diff suppressed because it is too large
Load Diff
74
gbdk-support/png2hicolorgb/src/hicolor/median.h
Normal file
74
gbdk-support/png2hicolorgb/src/hicolor/median.h
Normal file
@@ -0,0 +1,74 @@
|
||||
#ifndef __median_h__
|
||||
#define __median_h__
|
||||
|
||||
|
||||
#define MAXNUMCOLORS 256
|
||||
|
||||
#define PRECISION_R 5
|
||||
#define PRECISION_G 5
|
||||
#define PRECISION_B 5
|
||||
|
||||
#define R_SCALE << 1
|
||||
#define G_SCALE * 3
|
||||
#define B_SCALE
|
||||
|
||||
#define HIST_R_ELEMS (1<<PRECISION_R)
|
||||
#define HIST_G_ELEMS (1<<PRECISION_G)
|
||||
#define HIST_B_ELEMS (1<<PRECISION_B)
|
||||
|
||||
#define MR HIST_G_ELEMS*HIST_B_ELEMS
|
||||
#define MG HIST_B_ELEMS
|
||||
|
||||
#define BITS_IN_SAMPLE 8
|
||||
|
||||
#define R_SHIFT (BITS_IN_SAMPLE - PRECISION_R)
|
||||
#define G_SHIFT (BITS_IN_SAMPLE - PRECISION_G)
|
||||
#define B_SHIFT (BITS_IN_SAMPLE - PRECISION_B)
|
||||
|
||||
typedef struct _Color Color;
|
||||
typedef struct _QuantizeObj QuantizeObj;
|
||||
typedef void (*Pass_Func) (QuantizeObj *, unsigned char *, unsigned char *, long, long);
|
||||
typedef unsigned long ColorFreq;
|
||||
|
||||
typedef ColorFreq *Histogram;
|
||||
|
||||
|
||||
struct _Color
|
||||
{
|
||||
int red;
|
||||
int green;
|
||||
int blue;
|
||||
};
|
||||
|
||||
typedef struct
|
||||
{
|
||||
int Rmin, Rmax; // The bounds of the box (inclusive); expressed as histogram indexes
|
||||
int Gmin, Gmax;
|
||||
int Bmin, Bmax;
|
||||
int volume; // The volume (actually 2-norm) of the box
|
||||
long colorcount; //The number of nonzero histogram cells within this box */
|
||||
} mbox, *boxptr;
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
extern u8 Picture256[160*BUF_HEIGHT*3];
|
||||
extern u8 QuantizedPalette[256][3];
|
||||
|
||||
|
||||
void zero_histogram_rgb(void);
|
||||
boxptr find_biggest_color_pop(boxptr boxlist,s32 numboxes);
|
||||
boxptr find_biggest_volume(boxptr boxlist,s32 numboxes);
|
||||
void update_box_rgb(boxptr boxp);
|
||||
s32 median_cut_rgb(boxptr boxlist,s32 numboxes);
|
||||
void compute_color_rgb(boxptr boxp,s32 icolor);
|
||||
s32 find_nearby_colors(s32 minR,s32 minG,s32 minB,s32 colorlist[]);
|
||||
void find_best_colors(s32 minR, s32 minG, s32 minB,s32 numcolors,s32 colorlist[],s32 bestcolor[]);
|
||||
void fill_inverse_cmap_rgb(s32 R, s32 G, s32 B);
|
||||
void median_cut_pass1_rgb(u8 *src,u8 *dest,s32 width,s32 height);
|
||||
s32 *init_error_limit(void);
|
||||
void to_indexed(u8 *input,s32 ncolors,s32 dither,s32 width,s32 height);
|
||||
|
||||
|
||||
#endif
|
||||
30
gbdk-support/png2hicolorgb/src/hicolor/wu.h
Normal file
30
gbdk-support/png2hicolorgb/src/hicolor/wu.h
Normal file
@@ -0,0 +1,30 @@
|
||||
#ifndef __WU_H__
|
||||
#define __WU_H__
|
||||
|
||||
|
||||
struct box
|
||||
{
|
||||
s32 r0; /* min value, exclusive */
|
||||
s32 r1; /* max value, inclusive */
|
||||
s32 g0;
|
||||
s32 g1;
|
||||
s32 b0;
|
||||
s32 b1;
|
||||
s32 vol;
|
||||
};
|
||||
|
||||
#define BOX 33
|
||||
|
||||
|
||||
void Hist3d(s32 *vwt,s32 *vmr,s32 *vmg,s32 *vmb, float *m_2);
|
||||
void Momt3d(s32 *vwt, s32 *vmr, s32 *vmg, s32 *vmb, float *m_2);
|
||||
s32 Vol(struct box * cube, s32 mmt[BOX][BOX][BOX]);
|
||||
s32 Bottom(struct box * cube, u8 dir, s32 mmt[BOX][BOX][BOX]);
|
||||
s32 Top(struct box * cube, u8 dir, s32 pos, s32 mmt[BOX][BOX][BOX]);
|
||||
float Var(struct box * cube);
|
||||
float Maximize(struct box *cube, u8 dir, s32 first, s32 last, s32 *cut, s32 whole_r, s32 whole_g, s32 whole_b, s32 whole_w);
|
||||
s32 Cut(struct box * set1, struct box * set2);
|
||||
void Mark(struct box *cube, s32 label, u8 *tag);
|
||||
s32 wuReduce(u8 *RGBpic, s32 numcolors, s32 picsize);
|
||||
|
||||
#endif
|
||||
53
gbdk-support/png2hicolorgb/src/image_info.h
Normal file
53
gbdk-support/png2hicolorgb/src/image_info.h
Normal file
@@ -0,0 +1,53 @@
|
||||
//
|
||||
// image_info.h
|
||||
//
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#ifndef IMAGE_INFO_HEADER
|
||||
#define IMAGE_INFO_HEADER
|
||||
|
||||
#define RGBA_32SZ 4 // 4 bytes
|
||||
#define RGBA_RED 0
|
||||
#define RGBA_GREEN 1
|
||||
#define RGBA_BLUE 2
|
||||
#define RGBA_ALPHA 3
|
||||
|
||||
#define RGB_24SZ 3 // 3 bytes
|
||||
#define RGB_RED 0
|
||||
#define RGB_GREEN 1
|
||||
#define RGB_BLUE 2
|
||||
|
||||
#define BGRX_BLUE 0
|
||||
#define BGRX_GREEN 1
|
||||
#define BGRX_RED 2
|
||||
|
||||
#define MODE_8_BIT_INDEXED ( 8 / 8)
|
||||
#define MODE_8_BIT_INDEXED_ALPHA (16 / 8)
|
||||
#define MODE_24_BIT_RGB (24 / 8)
|
||||
#define MODE_32_BIT_RGBA (32 / 8)
|
||||
|
||||
#define COLOR_DATA_PAL_MAX_COUNT 256 // 255 Colors max for indexed
|
||||
#define COLOR_DATA_BYTES_PER_COLOR 3 // RGB 1 byte per color
|
||||
#define COLOR_DATA_PAL_SIZE COLOR_DATA_PAL_MAX_COUNT * COLOR_DATA_BYTES_PER_COLOR
|
||||
|
||||
#define USER_PAL_MAX_COLORS 32
|
||||
|
||||
|
||||
typedef struct {
|
||||
uint8_t bytes_per_pixel;
|
||||
// uint16_t width;
|
||||
// uint16_t height;
|
||||
unsigned int width;
|
||||
unsigned int height;
|
||||
uint32_t size; // size in bytes
|
||||
uint8_t * p_img_data;
|
||||
uint16_t tile_width; // should be even multiple of width
|
||||
uint16_t tile_height; // should be even multiple of height
|
||||
|
||||
uint16_t palette_tile_width; // should be even multiple of width
|
||||
uint16_t palette_tile_height; // should be even multiple of height
|
||||
} image_data;
|
||||
|
||||
|
||||
#endif
|
||||
114
gbdk-support/png2hicolorgb/src/image_load.c
Normal file
114
gbdk-support/png2hicolorgb/src/image_load.c
Normal file
@@ -0,0 +1,114 @@
|
||||
// image_load.c
|
||||
|
||||
//
|
||||
// Handles loading PNG images and reformatting them to a usable state
|
||||
//
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "logging.h"
|
||||
#include "image_info.h"
|
||||
#include "options.h"
|
||||
|
||||
#include <defines.h>
|
||||
#include <lodepng.h>
|
||||
|
||||
|
||||
static bool image_validate(image_data *);
|
||||
static bool image_load_png(image_data *, const char *);
|
||||
|
||||
|
||||
// Validates incoming image properties
|
||||
// Return: true if success
|
||||
static bool image_validate(image_data * p_decoded_image) {
|
||||
|
||||
if (p_decoded_image->width != VALIDATE_WIDTH) {
|
||||
log_error("Error: Image width is %d, must be %d\n", p_decoded_image->width, VALIDATE_WIDTH);
|
||||
return false;
|
||||
}
|
||||
|
||||
// TODO: There is a soft upper bound of 25 since:
|
||||
// Width is currently fixed at 160 pixels (20 tiles)
|
||||
// 20 tiles wide x 25 tiles high = 500 tiles
|
||||
// Which is the highest possible within the 512 available on the CGB
|
||||
// without reloading the tiles and maps using an offset
|
||||
if ((p_decoded_image->height == 0) || (p_decoded_image->height > VALIDATE_HEIGHT)) {
|
||||
log_error("Error: Image height is %d, must be between 0 and %d\n", p_decoded_image->height, VALIDATE_HEIGHT);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((p_decoded_image->height % 8) != 0u) {
|
||||
log_verbose("Error: Image height must be a multiple of 8, %d is not\n", p_decoded_image->height);
|
||||
return false;
|
||||
}
|
||||
|
||||
if ((p_decoded_image->width % 8) != 0u) {
|
||||
log_verbose("Error: Image width must be a multiple of 8, %d is not\n", p_decoded_image->width);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Loads a PNG image image into RGB888(24) format
|
||||
// Return: true if success
|
||||
static bool image_load_png(image_data * p_decoded_image, const char * filename) {
|
||||
|
||||
bool status = true;
|
||||
LodePNGState png_state;
|
||||
lodepng_state_init(&png_state);
|
||||
|
||||
// Decode with auto conversion to RGB888(24)
|
||||
unsigned error = lodepng_decode24_file(&p_decoded_image->p_img_data, &p_decoded_image->width, &p_decoded_image->height, filename);
|
||||
|
||||
if (error) {
|
||||
status = false;
|
||||
log_error("Error: PNG load: %u: %s\n", error, lodepng_error_text(error));
|
||||
} else {
|
||||
p_decoded_image->bytes_per_pixel = RGB_24SZ;
|
||||
p_decoded_image->size = p_decoded_image->width * p_decoded_image->height * p_decoded_image->bytes_per_pixel;
|
||||
}
|
||||
|
||||
// Free resources
|
||||
lodepng_state_cleanup(&png_state);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
// Loads an image image
|
||||
// Return: true if success
|
||||
bool image_load(image_data * p_decoded_image, const char * filename, const uint8_t image_type) {
|
||||
|
||||
bool status = true;
|
||||
|
||||
log_verbose("Loading image from file: %s, type: %d\n", filename, image_type);
|
||||
|
||||
switch (image_type) {
|
||||
case IMG_TYPE_PNG:
|
||||
status = image_load_png(p_decoded_image, filename);
|
||||
break;
|
||||
|
||||
default:
|
||||
status = false;
|
||||
log_error("Invalid image format. No image will be loaded\n");
|
||||
break;
|
||||
}
|
||||
|
||||
if (status)
|
||||
status = image_validate(p_decoded_image);
|
||||
|
||||
if (status) {
|
||||
log_verbose("Decoded image.width: %d\n", p_decoded_image->width);
|
||||
log_verbose("Decoded image.height: %d\n", p_decoded_image->height);
|
||||
log_verbose("Decoded image.size: %d\n", p_decoded_image->size);
|
||||
log_verbose("Decoded image.bytes_per_pixel: %d\n", p_decoded_image->bytes_per_pixel);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
9
gbdk-support/png2hicolorgb/src/image_load.h
Normal file
9
gbdk-support/png2hicolorgb/src/image_load.h
Normal file
@@ -0,0 +1,9 @@
|
||||
|
||||
#ifndef _IMAGE_LOAD_C
|
||||
#define _IMAGE_LOAD_C
|
||||
|
||||
#include "image_info.h"
|
||||
|
||||
bool image_load(image_data * p_src_image, const char * filename, const uint8_t img_type);
|
||||
|
||||
#endif
|
||||
21
gbdk-support/png2hicolorgb/src/lodepng/LICENSE
Normal file
21
gbdk-support/png2hicolorgb/src/lodepng/LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
Copyright (c) 2005-2018 Lode Vandevenne
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
6285
gbdk-support/png2hicolorgb/src/lodepng/lodepng.c
Normal file
6285
gbdk-support/png2hicolorgb/src/lodepng/lodepng.c
Normal file
File diff suppressed because it is too large
Load Diff
1710
gbdk-support/png2hicolorgb/src/lodepng/lodepng.h
Normal file
1710
gbdk-support/png2hicolorgb/src/lodepng/lodepng.h
Normal file
File diff suppressed because it is too large
Load Diff
48
gbdk-support/png2hicolorgb/src/logging.c
Normal file
48
gbdk-support/png2hicolorgb/src/logging.c
Normal file
@@ -0,0 +1,48 @@
|
||||
// logging.c
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "logging.h"
|
||||
|
||||
int output_level = OUTPUT_LEVEL_DEFAULT;
|
||||
|
||||
|
||||
#define VA_LIST_PRINT() \
|
||||
va_list args; \
|
||||
va_start (args, format); \
|
||||
vprintf (format, args); \
|
||||
va_end (args); \
|
||||
fflush(stdout); // If logging a lot of output to a file turn off the excessive flushing
|
||||
|
||||
|
||||
void log_set_level(int new_output_level) {
|
||||
output_level = new_output_level;
|
||||
}
|
||||
|
||||
void log_debug(const char * format, ...){
|
||||
|
||||
if (output_level > OUTPUT_LEVEL_DEBUG) return;
|
||||
VA_LIST_PRINT();
|
||||
}
|
||||
|
||||
void log_verbose(const char * format, ...){
|
||||
|
||||
if (output_level > OUTPUT_LEVEL_VERBOSE) return;
|
||||
VA_LIST_PRINT();
|
||||
}
|
||||
|
||||
void log_standard(const char * format, ...){
|
||||
|
||||
// Only print if quiet mode and error_only are NOT enabled
|
||||
if ((output_level == OUTPUT_LEVEL_QUIET) ||
|
||||
(output_level == OUTPUT_LEVEL_ONLY_ERRORS)) return;
|
||||
VA_LIST_PRINT();
|
||||
}
|
||||
|
||||
void log_error(const char * format, ...){
|
||||
|
||||
// Only print if quiet mode is NOT enabled
|
||||
if (output_level == OUTPUT_LEVEL_QUIET) return;
|
||||
VA_LIST_PRINT();
|
||||
}
|
||||
22
gbdk-support/png2hicolorgb/src/logging.h
Normal file
22
gbdk-support/png2hicolorgb/src/logging.h
Normal file
@@ -0,0 +1,22 @@
|
||||
// logging.h
|
||||
|
||||
#ifndef _LOGGING_H
|
||||
#define _LOGGING_H
|
||||
|
||||
enum output_levels {
|
||||
OUTPUT_LEVEL_DEBUG,
|
||||
OUTPUT_LEVEL_VERBOSE,
|
||||
OUTPUT_LEVEL_DEFAULT,
|
||||
OUTPUT_LEVEL_ONLY_ERRORS,
|
||||
OUTPUT_LEVEL_QUIET
|
||||
};
|
||||
|
||||
#define log_progress log_verbose
|
||||
|
||||
void log_set_level(int new_output_level);
|
||||
void log_debug(const char * format, ...);
|
||||
void log_verbose(const char * format, ...);
|
||||
void log_standard(const char * format, ...);
|
||||
void log_error(const char * format, ...);
|
||||
|
||||
#endif
|
||||
244
gbdk-support/png2hicolorgb/src/main.c
Normal file
244
gbdk-support/png2hicolorgb/src/main.c
Normal file
@@ -0,0 +1,244 @@
|
||||
// See LICENSE file for license details
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
|
||||
#include "common.h"
|
||||
#include "path_ops.h"
|
||||
#include "options.h"
|
||||
#include "logging.h"
|
||||
#include "image_load.h"
|
||||
|
||||
#include <hicolour.h>
|
||||
|
||||
|
||||
#define VERSION "version 1.4.1"
|
||||
|
||||
static void init(void);
|
||||
static void cleanup(void);
|
||||
static void display_help(void);
|
||||
static int handle_args(int argc, char * argv[]);
|
||||
static void set_drag_and_drop_mode_defaults(void);
|
||||
|
||||
image_data src_image;
|
||||
char filename_in[MAX_STR_LEN] = {'\0'};
|
||||
char opt_filename_out[MAX_STR_LEN] = "";
|
||||
// bool opt_strip_output_filename_ext = true;
|
||||
|
||||
int show_help_and_exit = false;
|
||||
|
||||
|
||||
static void init(void) {
|
||||
// Handle global init
|
||||
src_image.p_img_data = NULL;
|
||||
hicolor_init();
|
||||
}
|
||||
|
||||
|
||||
// Registered as an atexit handler
|
||||
static void cleanup(void) {
|
||||
// Handle any cleanup on exit
|
||||
// Free the image data
|
||||
if (src_image.p_img_data != NULL)
|
||||
free(src_image.p_img_data);
|
||||
|
||||
}
|
||||
|
||||
|
||||
int main( int argc, char *argv[] ) {
|
||||
|
||||
int ret = EXIT_FAILURE; // Default to failure on exit
|
||||
|
||||
// Register cleanup with exit handler
|
||||
atexit(cleanup);
|
||||
|
||||
init();
|
||||
|
||||
#ifdef DRAG_AND_DROP_MODE
|
||||
// Non-interactive mode, set some reasonable default
|
||||
set_drag_and_drop_mode_defaults();
|
||||
#endif
|
||||
|
||||
if (handle_args(argc, argv)) {
|
||||
|
||||
if (show_help_and_exit) {
|
||||
ret = EXIT_SUCCESS;
|
||||
}
|
||||
else {
|
||||
// detect file extension
|
||||
if (matches_extension(filename_in, (char *)".png")) {
|
||||
|
||||
// Load source image (from first argument)
|
||||
if (image_load(&src_image, filename_in, IMG_TYPE_PNG)) {
|
||||
|
||||
// If output filename is not specified, use source filename
|
||||
if (opt_filename_out[0] == '\0')
|
||||
strcpy(opt_filename_out, filename_in);
|
||||
|
||||
filename_remove_extension(opt_filename_out);
|
||||
hicolor_process_image(&src_image, opt_filename_out);
|
||||
ret = EXIT_SUCCESS; // Exit with success
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Override exit code if was set during processing
|
||||
if (get_exit_error())
|
||||
ret = EXIT_FAILURE;
|
||||
|
||||
// if (ret == EXIT_FAILURE)
|
||||
// log_error("Error loading, converting or writing out the image: %s\n", filename_in);
|
||||
|
||||
#ifdef DRAG_AND_DROP_MODE
|
||||
// Wait for input to keep the console window open after processing
|
||||
log_standard("\n\nPress Any Key to Continue\n");
|
||||
getchar();
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
static void display_help(void) {
|
||||
log_standard(
|
||||
"\n"
|
||||
"png2hicolorgb input_image.png [options]\n"
|
||||
VERSION": bbbbbr. Based on Glen Cook's Windows GUI \"hicolour.exe\" 1.2\n"
|
||||
"Convert an image to Game Boy Hi-Color format\n"
|
||||
"\n"
|
||||
"Options\n"
|
||||
"-h : Show this help\n"
|
||||
"-v* : Set log level: \"-v\" verbose, \"-vQ\" quiet, \"-vE\" only errors, \"-vD\" debug\n"
|
||||
"-o <file> : Set base output filename (otherwise from input image)\n"
|
||||
// "--keepext : Do not strip extension from output filename\n"
|
||||
"--csource : Export C source format with incbins for data files\n"
|
||||
"--bank=N : Set bank number for C source output where N is decimal bank number 1-511\n"
|
||||
"--type=N : Set conversion type where N is one of below \n"
|
||||
" 1: Median Cut - No Dither (*Default*)\n"
|
||||
" 2: Median Cut - With Dither\n"
|
||||
" 3: Wu Quantiser\n"
|
||||
"-p : Show screen attribute pattern options (no processing)\n"
|
||||
"-L=N : Set Left screen attribute pattern where N is decimal entry (-p to show patterns)\n"
|
||||
"-R=N : Set Right screen attribute pattern where N is decimal entry (-p to show patterns)\n"
|
||||
"--vaddrid : Map uses vram id (128->255->0->127) instead of (*Default*) sequential tile order (0->255)\n"
|
||||
"--nodedupe : Turn off tile pattern deduplication\n"
|
||||
"\n"
|
||||
"Example 1: \"png2hicolorgb myimage.png\"\n"
|
||||
"Example 2: \"png2hicolorgb myimage.png --csource -o=my_output_filename\"\n"
|
||||
"* Default settings provide good results. Better quality but slower: \"--type=3 -L=2 -R=2\"\n"
|
||||
"\n"
|
||||
"Historical credits and info:\n"
|
||||
" Original Concept : Icarus Productions\n"
|
||||
" Original Code : Jeff Frohwein\n"
|
||||
" Full Screen Modification : Anon\n"
|
||||
" Adaptive Code : Glen Cook\n"
|
||||
" Windows Interface : Glen Cook\n"
|
||||
" Additional Windows Programming : Rob Jones\n"
|
||||
" Original Quantiser Code : Benny\n"
|
||||
" Quantiser Conversion : Glen Cook\n"
|
||||
"\n"
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Default options for Windows Drag and Drop recipient mode
|
||||
static void set_drag_and_drop_mode_defaults(void) {
|
||||
|
||||
// Set some options here
|
||||
}
|
||||
|
||||
|
||||
static int handle_args(int argc, char * argv[]) {
|
||||
|
||||
int i;
|
||||
|
||||
if( argc < 2 ) {
|
||||
display_help();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Copy input filename (if not preceded with option dash)
|
||||
if (argv[1][0] != '-')
|
||||
snprintf(filename_in, sizeof(filename_in), "%s", argv[1]);
|
||||
|
||||
// Start at first optional argument, argc is zero based
|
||||
for (i = 1; i <= (argc -1); i++ ) {
|
||||
|
||||
if ((strstr(argv[i], "-h") == argv[i]) || (strstr(argv[i], "-?") == argv[i])) {
|
||||
display_help();
|
||||
show_help_and_exit = true;
|
||||
return true; // Don't parse further input when -h is used
|
||||
} else if (strstr(argv[i], "-p") == argv[i]) {
|
||||
log_standard(HELP_CONV_PATTERN_STR);
|
||||
show_help_and_exit = true;
|
||||
return true; // Don't parse further input when -h is used
|
||||
|
||||
} else if (strstr(argv[i], "-vD") == argv[i]) {
|
||||
log_set_level(OUTPUT_LEVEL_DEBUG);
|
||||
} else if (strstr(argv[i], "-vE") == argv[i]) {
|
||||
log_set_level(OUTPUT_LEVEL_ONLY_ERRORS);
|
||||
} else if (strstr(argv[i], "-vQ") == argv[i]) {
|
||||
log_set_level(OUTPUT_LEVEL_QUIET);
|
||||
} else if (strstr(argv[i], "-v") == argv[i]) {
|
||||
log_set_level(OUTPUT_LEVEL_VERBOSE);
|
||||
|
||||
} else if (strstr(argv[i], "--type=") == argv[i]) {
|
||||
uint8_t new_type = strtol(argv[i] + strlen("--type="), NULL, 10);
|
||||
if ((new_type < CONV_TYPE_MIN) || (new_type > CONV_TYPE_MAX)) {
|
||||
log_standard("Error: --type specified with invalid conversion setting: %d\n", new_type);
|
||||
display_help();
|
||||
show_help_and_exit = true;
|
||||
return false; // Abort
|
||||
}
|
||||
else
|
||||
hicolor_set_type(new_type);
|
||||
} else if (strstr(argv[i], "-L=") == argv[i]) {
|
||||
hicolor_set_convert_left_pattern( strtol(argv[i] + strlen("-L="), NULL, 10));
|
||||
} else if (strstr(argv[i], "-R=") == argv[i]) {
|
||||
hicolor_set_convert_right_pattern( strtol(argv[i] + strlen("-R="), NULL, 10));
|
||||
|
||||
} else if (strstr(argv[i], "-o") == argv[i]) {
|
||||
i++; // Move to next argument
|
||||
// Require colon and filename to be present
|
||||
if (*argv[i] == '-')
|
||||
log_standard("Warning: -o specified but filename has dash and looks like an option argument. Usage: -o my_base_output_filename\n");
|
||||
snprintf(opt_filename_out, sizeof(opt_filename_out), "%s", argv[i]);
|
||||
|
||||
// } else if (strstr(argv[i], "--keepext") == argv[i]) {
|
||||
// opt_strip_output_filename_ext = false;
|
||||
|
||||
} else if (strstr(argv[i], "--csource") == argv[i]) {
|
||||
opt_set_c_file_output(true);
|
||||
|
||||
} else if (strstr(argv[i], "--bank=") == argv[i]) {
|
||||
opt_set_bank_num( strtol(argv[i] + strlen("--bank="), NULL, 10) );
|
||||
if ((opt_get_bank_num() < BANK_NUM_MIN) || (opt_get_bank_num() > BANK_NUM_MAX)) {
|
||||
log_standard("Error: Invalid bank number specified with --bank=%d\n", opt_get_bank_num());
|
||||
display_help();
|
||||
show_help_and_exit = true;
|
||||
return false; // Abort
|
||||
}
|
||||
|
||||
} else if (strstr(argv[i], "--vaddrid") == argv[i]) {
|
||||
opt_set_map_tile_order(OPT_MAP_TILE_ORDER_BY_VRAM_ID);
|
||||
|
||||
} else if (strstr(argv[i], "--nodedupe") == argv[i]) {
|
||||
opt_set_tile_dedupe(false);
|
||||
|
||||
} else if (argv[i][0] == '-') {
|
||||
log_error("Unknown argument: %s\n\n", argv[i]);
|
||||
display_help();
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
28
gbdk-support/png2hicolorgb/src/options.c
Normal file
28
gbdk-support/png2hicolorgb/src/options.c
Normal file
@@ -0,0 +1,28 @@
|
||||
//
|
||||
// options.c
|
||||
//
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <options.h>
|
||||
|
||||
// Use sequential tile order number (0->255) for map index instead of VRAM tile index (128->255->0->127)
|
||||
bool opt_map_use_sequential_tile_index = true;
|
||||
bool opt_tile_dedupe = true;
|
||||
bool opt_c_file_output = false;
|
||||
int opt_bank_num = BANK_NUM_UNSET;
|
||||
|
||||
void opt_set_map_tile_order(bool newval) { opt_map_use_sequential_tile_index = newval; }
|
||||
bool opt_get_map_tile_order(void) { return opt_map_use_sequential_tile_index; }
|
||||
|
||||
void opt_set_tile_dedupe(bool newval) { opt_tile_dedupe = newval; }
|
||||
bool opt_get_tile_dedupe(void) { return opt_tile_dedupe; }
|
||||
|
||||
void opt_set_c_file_output(bool newval) { opt_c_file_output = newval; }
|
||||
bool opt_get_c_file_output(void) { return opt_c_file_output; }
|
||||
|
||||
void opt_set_bank_num(int newval) { opt_bank_num = newval; }
|
||||
int opt_get_bank_num(void) { return opt_bank_num; }
|
||||
|
||||
31
gbdk-support/png2hicolorgb/src/options.h
Normal file
31
gbdk-support/png2hicolorgb/src/options.h
Normal file
@@ -0,0 +1,31 @@
|
||||
// "options.h"
|
||||
|
||||
#ifndef OPTIONS_H
|
||||
#define OPTIONS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#define BANK_NUM_UNSET 0
|
||||
#define BANK_NUM_MIN 1
|
||||
#define BANK_NUM_MAX 511
|
||||
|
||||
#define OPTION_UNSET 0xFFFF
|
||||
|
||||
#define OPT_MAP_TILE_ORDER_BY_VRAM_ID false
|
||||
#define OPT_MAP_TILE_SEQUENTIAL_ORDER true
|
||||
|
||||
void opt_set_map_tile_order(bool newval);
|
||||
bool opt_get_map_tile_order(void);
|
||||
|
||||
void opt_set_tile_dedupe(bool newval);
|
||||
bool opt_get_tile_dedupe(void);
|
||||
|
||||
void opt_set_c_file_output(bool newval);
|
||||
bool opt_get_c_file_output(void);
|
||||
|
||||
void opt_set_bank_num(int newval);
|
||||
int opt_get_bank_num(void);
|
||||
|
||||
#endif
|
||||
|
||||
157
gbdk-support/png2hicolorgb/src/path_ops.c
Normal file
157
gbdk-support/png2hicolorgb/src/path_ops.c
Normal file
@@ -0,0 +1,157 @@
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
// For more information, please refer to <https://unlicense.org>
|
||||
// bbbbbr 2020
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include "common.h"
|
||||
#include "path_ops.h"
|
||||
|
||||
const char kExtensionSeparator = '.';
|
||||
const char kPathSeparator =
|
||||
|
||||
#ifdef _WIN32
|
||||
#ifndef _WIN32
|
||||
#define __WIN32__
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef __WIN32__
|
||||
'\\';
|
||||
#else
|
||||
'/';
|
||||
#endif
|
||||
|
||||
const char kPathSeparator_unix = '/';
|
||||
|
||||
|
||||
void filename_replace_extension(char * filename, char * new_ext, size_t maxlen) {
|
||||
|
||||
// Use a temp work string in case out and in filename are the same pointer
|
||||
char temp[MAX_PATH];
|
||||
char ext_sep[2] = {'\0'}; // default to empty string
|
||||
|
||||
// Add leading . to path if needed
|
||||
if (new_ext[0] != kExtensionSeparator) {
|
||||
ext_sep[0] = kExtensionSeparator;
|
||||
ext_sep[1] = '\0';
|
||||
}
|
||||
|
||||
// Strip extension from filename, append new extension
|
||||
filename_remove_extension(filename);
|
||||
snprintf(temp, maxlen, "%s%s%s", filename, ext_sep, new_ext);
|
||||
snprintf(filename, maxlen, "%s", temp);
|
||||
}
|
||||
|
||||
|
||||
void filename_replace_path(char * filename, char * new_path, size_t maxlen) {
|
||||
|
||||
// Use a temp work string in case out and in filename are the same pointer
|
||||
char temp[MAX_PATH];
|
||||
char path_sep[2] = {'\0'}; // default to empty string
|
||||
|
||||
// Add trailing slash to path if needed (Windows needs both for when running under linix like env)
|
||||
#ifdef __WIN32__
|
||||
if (((new_path[(strlen(new_path)-1)] != kPathSeparator)) &&
|
||||
((new_path[(strlen(new_path)-1)] != kPathSeparator_unix)))
|
||||
#else
|
||||
if ((new_path[(strlen(new_path)-1)] != kPathSeparator))
|
||||
#endif
|
||||
{
|
||||
path_sep[0] = kPathSeparator;
|
||||
path_sep[1] = '\0';
|
||||
}
|
||||
|
||||
// Strip path from path+filename, pre-pend new path
|
||||
snprintf(temp, maxlen, "%s%s%s", new_path, path_sep, get_filename_from_path(filename));
|
||||
snprintf(filename, maxlen, "%s", temp);
|
||||
}
|
||||
|
||||
|
||||
const char * get_filename_from_path(const char * path)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
// Returns string starting at last occurrance of path separator char
|
||||
for(i = strlen(path) - 1; i; i--) {
|
||||
|
||||
// Add trailing slash to path if needed (Windows needs both for when running under linix like env)
|
||||
#ifdef __WIN32__
|
||||
if ((path[i] == kPathSeparator) || (path[i] == kPathSeparator_unix))
|
||||
#else
|
||||
if (path[i] == kPathSeparator)
|
||||
#endif
|
||||
{
|
||||
return &path[i+1];
|
||||
}
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
|
||||
void filename_remove_extension(char * path)
|
||||
{
|
||||
char * last_ext;
|
||||
char * last_slash;
|
||||
|
||||
// Find the last path separator if present
|
||||
// Starting from here ensures that no path ".." characters
|
||||
// get mistaken as extension delimiters.
|
||||
last_slash = strrchr (path, kExtensionSeparator);
|
||||
if (!last_slash)
|
||||
last_slash = path;
|
||||
|
||||
// Then check to see if there is an extension (starting with the last occurance of '.')
|
||||
// (tries to remove *all* trailing extensions backward until the last slash)
|
||||
last_ext = strrchr (last_slash, kExtensionSeparator);
|
||||
while (last_ext) {
|
||||
if (last_ext != NULL) {
|
||||
// If an extension is found then overwrite it with a string terminator
|
||||
*last_ext = '\0';
|
||||
}
|
||||
last_ext = strrchr (last_slash, kExtensionSeparator);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool get_path_without_filename(const char * path, char * path_only, uint32_t str_max)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (strlen(path) + 1 > str_max)
|
||||
return false;
|
||||
|
||||
for(i = strlen(path) - 1; i; i--) {
|
||||
|
||||
// Add trailing slash to path if needed (Windows needs both for when running under linix like env)
|
||||
#ifdef __WIN32__
|
||||
if ((path[i] == kPathSeparator) || (path[i] == kPathSeparator_unix))
|
||||
#else
|
||||
if (path[i] == kPathSeparator)
|
||||
#endif
|
||||
{
|
||||
memcpy(path_only, path, i+1 );
|
||||
path_only[i+1] = '\0';
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// memcpy(path_only, path, strlen(path));
|
||||
// No separater found, so no path
|
||||
path_only[0] = '\0';
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
// Case insensitive
|
||||
bool matches_extension(char * filename, char * extension) {
|
||||
|
||||
if (strlen(filename) >= strlen(extension)) {
|
||||
char * str_ext = filename + (strlen(filename) - strlen(extension));
|
||||
|
||||
return (strncasecmp(str_ext, extension, strlen(extension)) == 0);
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
18
gbdk-support/png2hicolorgb/src/path_ops.h
Normal file
18
gbdk-support/png2hicolorgb/src/path_ops.h
Normal file
@@ -0,0 +1,18 @@
|
||||
// This is free and unencumbered software released into the public domain.
|
||||
// For more information, please refer to <https://unlicense.org>
|
||||
// bbbbbr 2020
|
||||
|
||||
#ifndef _PATH_OPS_H
|
||||
#define _PATH_OPS_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
void filename_replace_extension(char * filename, char * new_ext, size_t maxlen);
|
||||
void filename_replace_path(char * filename, char * new_path, size_t maxlen);
|
||||
const char * get_filename_from_path(const char * path);
|
||||
void filename_remove_extension(char * path);
|
||||
bool get_path_without_filename(const char * path, char * path_only, uint32_t str_max);
|
||||
bool matches_extension(char *, char *);
|
||||
|
||||
#endif // _PATH_OPS_H
|
||||
109
gbdk-support/png2hicolorgb/src/tile_dedupe.c
Normal file
109
gbdk-support/png2hicolorgb/src/tile_dedupe.c
Normal file
@@ -0,0 +1,109 @@
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <common.h>
|
||||
#include <defines.h>
|
||||
#include <logging.h>
|
||||
#include <options.h>
|
||||
|
||||
|
||||
static void tile_calc_flip_gb2bpp(uint8_t * flipped_tile, const uint8_t* src_tile, bool flip_x, bool flip_y);
|
||||
static void tile_generate_flips(const uint8_t * p_src_tile);
|
||||
|
||||
uint8_t tile_permutations[4 * TILE_SZ];
|
||||
#define FLIP_X_YES true
|
||||
#define FLIP_X_NO false
|
||||
#define FLIP_Y_YES true
|
||||
#define FLIP_Y_NO false
|
||||
|
||||
// These should match the order of tile flip permutations in tile_generate_flips()
|
||||
const uint8_t tile_flip_flags[] = {
|
||||
CGB_ATTR_NO_FLIP,
|
||||
CGB_ATTR_HFLIP,
|
||||
CGB_ATTR_VFLIP,
|
||||
CGB_ATTR_HFLIP | CGB_ATTR_VFLIP};
|
||||
|
||||
|
||||
const uint8_t bits_reverse_LUT[256] = {
|
||||
0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
|
||||
0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
|
||||
0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
|
||||
0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
|
||||
0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
|
||||
0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
|
||||
0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
|
||||
0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
|
||||
0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
|
||||
0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
|
||||
0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
|
||||
0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
|
||||
0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
|
||||
0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
|
||||
0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
|
||||
0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
|
||||
0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
|
||||
0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
|
||||
0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
|
||||
0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
|
||||
0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
|
||||
0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
|
||||
0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
|
||||
0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
|
||||
0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
|
||||
0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
|
||||
0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
|
||||
0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
|
||||
0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
|
||||
0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
|
||||
0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
|
||||
0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff,
|
||||
};
|
||||
|
||||
|
||||
static void tile_calc_flip_gb2bpp(uint8_t * flipped_tile, const uint8_t * src_tile, bool flip_x, bool flip_y)
|
||||
{
|
||||
for (int ty = 0; ty < TILE_HEIGHT_PX; ty++) {
|
||||
int y = flip_y ? (TILE_HEIGHT_PX - 1 - ty) : ty;
|
||||
flipped_tile[2 * ty] = flip_x ? bits_reverse_LUT[src_tile[2 * y]] : src_tile[2 * y];
|
||||
flipped_tile[2 * ty + 1] = flip_x ? bits_reverse_LUT[src_tile[2 * y + 1]] : src_tile[2 * y + 1];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Generate all the X/Y flipped combinations of a 2bpp Game Boy tile
|
||||
// Output is used for testing if CGB flipping map attributes allow for tile pattern deduplciation
|
||||
//
|
||||
// tile_permutations[] should be 4 x 16 bytes
|
||||
static void tile_generate_flips(const uint8_t * p_src_tile)
|
||||
{
|
||||
tile_calc_flip_gb2bpp(&tile_permutations[0 * TILE_SZ], p_src_tile, FLIP_X_NO, FLIP_Y_NO);
|
||||
tile_calc_flip_gb2bpp(&tile_permutations[1 * TILE_SZ], p_src_tile, FLIP_X_YES, FLIP_Y_NO);
|
||||
tile_calc_flip_gb2bpp(&tile_permutations[2 * TILE_SZ], p_src_tile, FLIP_X_NO, FLIP_Y_YES);
|
||||
tile_calc_flip_gb2bpp(&tile_permutations[3 * TILE_SZ], p_src_tile, FLIP_X_YES, FLIP_Y_YES);
|
||||
}
|
||||
|
||||
|
||||
// bool tileset_find_matching_tile(unsigned int source_tile_id, unsigned int * TileCountDeduped, uint8_t * new_tile_id, uint8_t * new_attribs)
|
||||
bool tileset_find_matching_tile(const uint8_t * src_tile, const uint8_t * tile_set_deduped, const unsigned int tile_count_deduped, uint8_t * new_tile_id, uint8_t * new_attribs)
|
||||
{
|
||||
tile_generate_flips(src_tile);
|
||||
|
||||
for (unsigned int index_dedupe = 0; index_dedupe < tile_count_deduped; index_dedupe++) {
|
||||
|
||||
for (int f = 0; f < ARRAY_LEN(tile_flip_flags); f++) {
|
||||
if (memcmp(&tile_set_deduped[index_dedupe * TILE_SZ], &tile_permutations[f * TILE_SZ], TILE_SZ) == 0) {
|
||||
|
||||
// Match Found
|
||||
*new_tile_id = (uint8_t)(index_dedupe & 0xFFu);
|
||||
*new_attribs = (index_dedupe < CGB_TILES_START_BANK_1) ? CGB_ATTR_TILES_BANK_0 : CGB_ATTR_TILES_BANK_1;
|
||||
*new_attribs |= tile_flip_flags[f];
|
||||
// log_debug(" * Tile Dedupe MATCH. new ID -> %d (dedupe count=%d), new_tile_id=%d, new_attribs=0x%02x, flip_index=%d\n", *new_tile_id, tile_count_deduped, *new_tile_id, *new_attribs, f);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false; // No match found
|
||||
}
|
||||
|
||||
10
gbdk-support/png2hicolorgb/src/tile_dedupe.h
Normal file
10
gbdk-support/png2hicolorgb/src/tile_dedupe.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#ifndef TILE_DEDUPE_H
|
||||
#define TILE_DEDUPE_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
bool tileset_find_matching_tile(const uint8_t * src_tile, const uint8_t * tile_set_deduped, unsigned int tile_count_deduped, uint8_t * new_tile_id, uint8_t * new_attribs);
|
||||
|
||||
#endif
|
||||
|
||||
93
licenses/LICENSE_png2hicolorgb
Normal file
93
licenses/LICENSE_png2hicolorgb
Normal file
@@ -0,0 +1,93 @@
|
||||
|
||||
The updated version of this software is released under the same license used by the original author.
|
||||
|
||||
- bbbbbr
|
||||
|
||||
GBDK Example project
|
||||
----------------------------------------------------------------------
|
||||
Source code: CC0 1.0 Universal (CC0 1.0) Public Domain Dedication
|
||||
|
||||
Example image: Pixel art originally by RodrixAP under Creative Commons Attribution 2.0 Generic (CC BY 2.0)
|
||||
https://www.flickr.com/photos/rodrixap/10591266994/in/album-72157637154901153/
|
||||
|
||||
|
||||
|
||||
Main program:
|
||||
----------------------------------------------------------------------
|
||||
|
||||
...
|
||||
|
||||
Feel free to use this code any way you feel fit.
|
||||
|
||||
You can use this code / algorithm in any commercial product. It would be great
|
||||
if you could send me an e-mail letting me know.
|
||||
|
||||
|
||||
And now for the usual bull..
|
||||
|
||||
This software is supplied on an as-is basis, although I don't believe that
|
||||
there are any bugs in my code, I will not be held responsible for any damage
|
||||
this program may cause....
|
||||
|
||||
Glen Cook.
|
||||
|
||||
...
|
||||
|
||||
I am releasing this program into the public domain, feel free to adapt it in anyway that you
|
||||
deem fit. I you feel you have improved this program in anyway, drop me a line, and I will
|
||||
incorperate the changes into newer versions. (GlenCook --a--t-- hotmail -- com)
|
||||
|
||||
|
||||
|
||||
Wu quantizer:
|
||||
----------------------------------------------------------------------
|
||||
|
||||
C Implementation of Wu's Color Quantizer (v. 2)
|
||||
(see Graphics Gems vol. II, pp. 126-133)
|
||||
|
||||
Author: Xiaolin Wu
|
||||
Dept. of Computer Science
|
||||
Univ. of Western Ontario
|
||||
London, Ontario N6A 5B7
|
||||
wu@csd.uwo.ca
|
||||
|
||||
Algorithm: Greedy orthogonal bipartition of RGB space for variance
|
||||
minimization aided by inclusion-exclusion tricks.
|
||||
For speed no nearest neighbor search is done. Slightly
|
||||
better performance can be expected by more sophisticated
|
||||
but more expensive versions.
|
||||
|
||||
The author thanks Tom Lane at Tom_Lane@G.GP.CS.CMU.EDU for much of
|
||||
additional documentation and a cure to a previous bug.
|
||||
|
||||
Free to distribute, comments and suggestions are appreciated.
|
||||
|
||||
|
||||
PNG support:
|
||||
----------------------------------------------------------------------
|
||||
|
||||
Lodepng license
|
||||
|
||||
|
||||
Copyright (c) 2005-2018 Lode Vandevenne
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
|
||||
3. This notice may not be removed or altered from any source
|
||||
distribution.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user