mirror of
https://github.com/freedoom/freedoom.git
synced 2025-09-01 13:25:46 -04:00
colormaps: Generate colormaps programatically.
This replaces the statically generated colormaps with equivalent colormap lumps that are generated by the colormap.py script (which now has parameters to control the generated colormap).
This commit is contained in:
parent
301ad35237
commit
90fed22627
16 changed files with 200 additions and 68 deletions
2
.gitignore
vendored
2
.gitignore
vendored
|
@ -3,7 +3,7 @@ deutex.log
|
|||
graphics/titlepic/freedm.gif
|
||||
graphics/titlepic/freedoom.gif
|
||||
graphics/titlepic/ultdoom.gif
|
||||
lumps/cph/misc-lumps/colormap.lmp
|
||||
lumps/cph/misc-lumps/*map.lmp
|
||||
lumps/cph/misc-lumps/playpal.lmp
|
||||
lumps/freedoom.lmp
|
||||
lumps/freedm.lmp
|
||||
|
|
|
@ -1 +1 @@
|
|||
cyb/bloodmap.lmp
|
||||
cph/misc-lumps/bloodmap.lmp
|
|
@ -1 +1 @@
|
|||
cyb/bluemap.lmp
|
||||
cph/misc-lumps/bluemap.lmp
|
|
@ -1,20 +1,51 @@
|
|||
all : playpal.lmp colormap.lmp
|
||||
COLORMAPS = colormap.lmp \
|
||||
bloodmap.lmp bluemap.lmp lavamap.lmp nukemap.lmp \
|
||||
fogmap.lmp mfademap.lmp
|
||||
|
||||
playpal.lmp : playpal-base.lmp playpal.py
|
||||
all: playpal.lmp $(COLORMAPS)
|
||||
|
||||
playpal.lmp: playpal-base.lmp playpal.py
|
||||
./playpal.py playpal-base.lmp > playpal.lmp
|
||||
|
||||
colormap.lmp : playpal.lmp colormap.py
|
||||
colormap.lmp: playpal.lmp colormap.py
|
||||
./colormap.py playpal.lmp > colormap.lmp
|
||||
|
||||
SOURCES=playpal.py colormap.py COPYING Makefile
|
||||
VERSION=0.0.1
|
||||
# Blue colormap applies a full blue tint. The brightness here is
|
||||
# adjusted slightly because the default is too dark.
|
||||
|
||||
dist : doom-misc-lumps-$(VERSION).tar.gz
|
||||
bluemap.lmp: playpal.lmp colormap.py
|
||||
./colormap.py --tint_color='#0000ff' --tint_pct=100 \
|
||||
--tint_bright=0.6 playpal.lmp > bluemap.lmp
|
||||
|
||||
doom-misc-lumps-$(VERSION).tar.gz : $(SOURCES)
|
||||
tar czf $@ $(SOURCES)
|
||||
# "Fog" effect maps that darken to a color other than black:
|
||||
|
||||
fogmap.lmp: playpal.lmp colormap.py
|
||||
./colormap.py --dark_color='#505050' playpal.lmp > fogmap.lmp
|
||||
|
||||
mfademap.lmp: playpal.lmp colormap.py
|
||||
./colormap.py --dark_color='#2b230f' playpal.lmp > mfademap.lmp
|
||||
|
||||
# "Liquid" colormaps that apply a tint. With a liquid effect we also
|
||||
# usually want to use --dark_color as well, because we want to darken
|
||||
# to something like the liquid color instead of black.
|
||||
|
||||
bloodmap.lmp: playpal.lmp colormap.py
|
||||
./colormap.py --tint_color='#ff0000' --dark_color='#500000' \
|
||||
--tint_pct=100 playpal.lmp > bloodmap.lmp
|
||||
|
||||
# TODO: The current lava effect is just very bright orange. Before the
|
||||
# change to programatically-generated lavamap we had a better effect.
|
||||
lavamap.lmp: playpal.lmp colormap.py
|
||||
./colormap.py --tint_color='#ff6000' --tint_pct=80 \
|
||||
--tint_bright=0.8 --dark_color='#ff6000' \
|
||||
playpal.lmp > lavamap.lmp
|
||||
|
||||
nukemap.lmp: playpal.lmp colormap.py
|
||||
./colormap.py --tint_color='#00ff00' --tint_pct=70 \
|
||||
--dark_color='#005000' playpal.lmp > nukemap.lmp
|
||||
|
||||
clean:
|
||||
rm -f playpal.lmp colormap.lmp doom-misc-lumps-$(VERSION).tar.gz
|
||||
rm -f playpal.lmp $(COLORMAPS)
|
||||
|
||||
.PHONY: clean
|
||||
|
||||
.PHONY : dist clean
|
||||
|
|
|
@ -1,13 +1,7 @@
|
|||
#!/usr/bin/env python
|
||||
#
|
||||
# Takes PLAYPAL as input (filename is the only parameter)
|
||||
# Produces a light graduated COLORMAP on stdout
|
||||
# O(n^2)
|
||||
#
|
||||
# This is a Python version of Colin's original Perl script.
|
||||
#
|
||||
# Copyright (C) 2001 Colin Phipps <cphipps@doomworld.com>
|
||||
# Copyright (C) 2008 Simon Howard
|
||||
# Copyright (C) 2008, 2013 Simon Howard
|
||||
# Parts copyright (C) 1999 by id Software (http://www.idsoftware.com/)
|
||||
#
|
||||
# This program is free software; you can redistribute it and/or modify
|
||||
|
@ -23,14 +17,44 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program; if not, write to the Free Software
|
||||
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
#
|
||||
#
|
||||
# Takes PLAYPAL as input (filename is the only parameter)
|
||||
# Produces a light graduated COLORMAP on stdout
|
||||
# O(n^2)
|
||||
#
|
||||
# This was originally a Perl script by Colin Phipps; it was converted
|
||||
# to Python and now is a more generic tool for generating all kinds of
|
||||
# COLORMAP effects.
|
||||
#
|
||||
|
||||
import os
|
||||
import sys
|
||||
import struct
|
||||
|
||||
# Return palette read from named file
|
||||
# Parameters affecting colormap generation:
|
||||
|
||||
# "Darkness" is this color, which is usually black, but can be
|
||||
# overridden (RGB 0-255):
|
||||
dark_color = (0, 0, 0)
|
||||
|
||||
# Color to tint the colormap (RGB 0.0-1.0):
|
||||
tint_color = (255, 255, 255)
|
||||
|
||||
# Fractional balance between tint and normal color. 0 is no tint applied,
|
||||
# 1.0 is full tint.
|
||||
tint_frac = 0
|
||||
|
||||
# Fudge factor to adjust brightness when calculating 'tinted' version
|
||||
# of colors. Larger values are brighter but may cause color clipping.
|
||||
# A value of 0.33 is a straight-average of the RGB channels. Maximum
|
||||
# sensible value is 1.0, though it can be overdriven for fancy
|
||||
# brightness effects.
|
||||
tint_bright = 0.5
|
||||
|
||||
def read_palette(filename):
|
||||
"""Read palette from file and return a list of tuples containing
|
||||
RGB values."""
|
||||
f = open(filename, "rb")
|
||||
|
||||
colors = []
|
||||
|
@ -43,17 +67,20 @@ def read_palette(filename):
|
|||
|
||||
return colors
|
||||
|
||||
def square(x):
|
||||
return x * x
|
||||
|
||||
# Return closest palette entry to the given RGB triple
|
||||
|
||||
def search_palette(colors, target):
|
||||
def search_palette(palette, target):
|
||||
"""Search the given palette and find the nearest matching
|
||||
color to the given color, returning an index into the
|
||||
palette of the color that best matches."""
|
||||
best_diff = None
|
||||
best_index = None
|
||||
|
||||
for i in range(len(colors)):
|
||||
color = colors[i]
|
||||
def square(x):
|
||||
return x * x
|
||||
|
||||
for i in range(len(palette)):
|
||||
color = palette[i]
|
||||
|
||||
diff = square(target[0] - color[0]) \
|
||||
+ square(target[1] - color[1]) \
|
||||
|
@ -65,35 +92,78 @@ def search_palette(colors, target):
|
|||
|
||||
return best_index
|
||||
|
||||
def generate_colormap(colors, transform_function):
|
||||
def generate_colormap(colors, palette):
|
||||
"""Given a list of colors, translate these into indexes into
|
||||
the given palette, finding the nearest color where an exact
|
||||
match cannot be found."""
|
||||
result = []
|
||||
|
||||
for color in colors:
|
||||
transformed_color = transform_function(color)
|
||||
transformed_index = search_palette(colors, transformed_color)
|
||||
result.append(transformed_index)
|
||||
index = search_palette(palette, color)
|
||||
result.append(index)
|
||||
|
||||
return result
|
||||
|
||||
def generate_darkened_colormap(colors, factor):
|
||||
def tint_colors(colors, tint, bright=0.5):
|
||||
"""Given a list of colors, tint them a particular color."""
|
||||
|
||||
darken_function = lambda c: ( c[0] * factor, \
|
||||
c[1] * factor, \
|
||||
c[2] * factor )
|
||||
result = []
|
||||
for c in colors:
|
||||
# I've experimented with different methods of calculating
|
||||
# intensity, but this seems to work the best. This is basically
|
||||
# doing an average of the full channels, but a straight
|
||||
# average causes the picture to get darker - eg. (0,0,255)
|
||||
# maps to (87,87,87). So we have a controllable brightness
|
||||
# factor that allows the brightness to be adjusted.
|
||||
intensity = min((c[0] + c[1] + c[2]) * bright, 255) / 255.0
|
||||
result.append((
|
||||
tint[0] * intensity,
|
||||
tint[1] * intensity,
|
||||
tint[2] * intensity,
|
||||
))
|
||||
|
||||
return generate_colormap(colors, darken_function)
|
||||
return result
|
||||
|
||||
def blend_colors(colors1, colors2, factor=0.5):
|
||||
"""Blend the two given lists of colors, with 'factor' controlling
|
||||
the mix between the two. factor=0 is exactly colors1, while
|
||||
factor=1 is exactly colors2. Returns a list of blended colors."""
|
||||
result = []
|
||||
|
||||
for index, c1 in enumerate(colors1):
|
||||
c2 = colors2[index]
|
||||
|
||||
result.append((
|
||||
c2[0] * factor + c1[0] * (1 - factor),
|
||||
c2[1] * factor + c1[1] * (1 - factor),
|
||||
c2[2] * factor + c1[2] * (1 - factor),
|
||||
))
|
||||
|
||||
return result
|
||||
|
||||
def invert_colors(colors):
|
||||
"""Given a list of colors, translate them to inverted monochrome."""
|
||||
result = []
|
||||
|
||||
for color in colors:
|
||||
average = (color[0] + color[1] + color[2]) / 3
|
||||
inverse = 255 - average
|
||||
|
||||
result.append((inverse, inverse, inverse))
|
||||
|
||||
return result
|
||||
|
||||
def solid_color_list(color):
|
||||
"""Generate a 256-entry palette where all entries are the
|
||||
same color."""
|
||||
return [color] * 256
|
||||
|
||||
def output_colormap(colormap):
|
||||
"""Output the given palette to stdout."""
|
||||
for c in colormap:
|
||||
x = struct.pack("B", c)
|
||||
os.write(sys.stdout.fileno(), x)
|
||||
|
||||
def inverse_color(color):
|
||||
average = (color[0] + color[1] + color[2]) / 3
|
||||
inverse = 255 - average
|
||||
|
||||
return (inverse, inverse, inverse)
|
||||
|
||||
def print_palette(colors):
|
||||
for y in range(16):
|
||||
for x in range(16):
|
||||
|
@ -103,25 +173,65 @@ def print_palette(colors):
|
|||
|
||||
print()
|
||||
|
||||
if len(sys.argv) < 2:
|
||||
print("Usage: %s <base filename> > output-file.lmp" % sys.argv[0])
|
||||
def parse_color_code(s):
|
||||
"""Parse a color code in HTML color code format, into an RGB
|
||||
3-tuple value."""
|
||||
if not s.startswith('#') or len(s) != 7:
|
||||
raise Exception('Not in HTML color code form: %s' % s)
|
||||
return (int(s[1:3], 16), int(s[3:5], 16), int(s[5:7], 16))
|
||||
|
||||
def set_parameter(name, value):
|
||||
"""Set configuration value, from command line parameters."""
|
||||
global dark_color, tint_color, tint_frac, tint_bright
|
||||
|
||||
if name == 'dark_color':
|
||||
dark_color = parse_color_code(value)
|
||||
elif name == 'tint_color':
|
||||
tint_color = parse_color_code(value)
|
||||
elif name == 'tint_pct':
|
||||
tint_frac = int(value) / 100.0
|
||||
elif name == 'tint_bright':
|
||||
tint_bright = float(value)
|
||||
else:
|
||||
raise Exception("Unknown parameter: '%s'" % name)
|
||||
|
||||
# Parse command line.
|
||||
|
||||
playpal_filename = None
|
||||
|
||||
for arg in sys.argv[1:]:
|
||||
if arg.startswith('--') and '=' in arg:
|
||||
key, val = arg[2:].split('=', 2)
|
||||
set_parameter(key, val)
|
||||
else:
|
||||
playpal_filename = arg
|
||||
|
||||
if playpal_filename is None:
|
||||
print("Usage: %s playpal.lmp > output-file.lmp" % sys.argv[0])
|
||||
sys.exit(1)
|
||||
|
||||
colors = read_palette(sys.argv[1])
|
||||
palette = read_palette(playpal_filename)
|
||||
colors = palette
|
||||
|
||||
#print_palette(colors)
|
||||
#sys.exit(0)
|
||||
# Apply tint, if enabled.
|
||||
# The tint is intentionally applied *before* the darkening effect is
|
||||
# applied. This allows us to darken to a different color than the tint
|
||||
# color, if so desired.
|
||||
if tint_frac > 0:
|
||||
colors = blend_colors(palette,
|
||||
tint_colors(colors, tint_color, tint_bright),
|
||||
tint_frac)
|
||||
|
||||
# Main color ranges
|
||||
# Generate colormaps for different darkness levels, by blending between
|
||||
# the default colors and a palette where every entry is the "dark" color.
|
||||
dark = solid_color_list(dark_color)
|
||||
|
||||
for i in range(32):
|
||||
darken_factor = (32 - i) / 32.0
|
||||
colormap = generate_darkened_colormap(colors, darken_factor)
|
||||
output_colormap(colormap)
|
||||
darkened_colors = blend_colors(dark, colors, darken_factor)
|
||||
output_colormap(generate_colormap(darkened_colors, palette))
|
||||
|
||||
# Print inverse color map
|
||||
|
||||
inverse_colormap = generate_colormap(colors, inverse_color)
|
||||
|
||||
output_colormap(inverse_colormap)
|
||||
# Inverse color map for invulnerability effect.
|
||||
inverse_colors = invert_colors(palette)
|
||||
output_colormap(generate_colormap(inverse_colors, palette))
|
||||
|
||||
|
|
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
|
@ -1 +1 @@
|
|||
oblivion/fogmap.lmp
|
||||
cph/misc-lumps/fogmap.lmp
|
Binary file not shown.
|
@ -1 +1 @@
|
|||
cyb/lavamap.lmp
|
||||
cph/misc-lumps/lavamap.lmp
|
|
@ -1 +1 @@
|
|||
jond/mfademap.lmp
|
||||
cph/misc-lumps/mfademap.lmp
|
|
@ -1 +1 @@
|
|||
cyb/nukemap.lmp
|
||||
cph/misc-lumps/nukemap.lmp
|
Binary file not shown.
|
@ -1,8 +0,0 @@
|
|||
fogmap.lmp - a colormap that fades to grey, should be placed between C_START and C_END then invoked using linedef #242, meh.
|
||||
|
||||
created by oblivion (thats me) on july 29 2002 using my own short little C program.
|
||||
|
||||
copyrights: public domain, cuz i said so.
|
||||
|
||||
i am uzi666@juno.com
|
||||
|
Loading…
Add table
Add a link
Reference in a new issue