diff --git a/.gitignore b/.gitignore index bad83f7d..bb2d4e33 100644 --- a/.gitignore +++ b/.gitignore @@ -7,15 +7,9 @@ lumps/cph/misc-lumps/playpal.lmp lumps/freedoom.lmp lumps/freedm.lmp sprites/jond/placeholder/*.gif -textures/phase1/pnames.txt -textures/phase1/texture1.txt -textures/phase2/pnames.txt -textures/phase2/texture1.txt -textures/freedm/pnames.txt -textures/freedm/texture1.txt -textures/texture1.txt wads/*.wad wads/*.zip +pnames.txt wad*.txt *.bak *.pyc diff --git a/Makefile b/Makefile index cfc2a77d..c85a1551 100644 --- a/Makefile +++ b/Makefile @@ -51,34 +51,18 @@ subdirs: force: -# build texture1.txt for different builds - -textures/phase1/texture1.txt: textures/combined.txt - @mkdir -p textures/phase1 - $(CPP) -DDOOM1 -DULTDOOM < $< > $@ -textures/phase2/texture1.txt: textures/combined.txt - @mkdir -p textures/phase2 - $(CPP) -DDOOM1 -DDOOM2 < $< > $@ -textures/freedm/texture1.txt: textures/combined.txt - @mkdir -p textures/freedm - $(CPP) -DFREEDM < $< > $@ - -textures/phase1/pnames.txt: textures/phase1/texture1.txt - scripts/extract-pnames.py -a > $@ -textures/phase2/pnames.txt: textures/phase2/texture1.txt - scripts/extract-pnames.py -a > $@ -textures/freedm/pnames.txt: textures/freedm/texture1.txt +pnames.txt: scripts/extract-pnames.py -a > $@ # update wadinfo.txt -wadinfo.txt: buildcfg.txt force textures/phase2/pnames.txt +wadinfo.txt: buildcfg.txt force pnames.txt $(CPP) -P -DDOOM2 < $< | scripts/wadinfo-builder.py > $@ -wadinfo_phase1.txt: buildcfg.txt force textures/phase1/pnames.txt +wadinfo_phase1.txt: buildcfg.txt force pnames.txt $(CPP) -P -DDOOM1 -DULTDOOM < $< | scripts/wadinfo-builder.py -dummy > $@ -wadinfo_phase2.txt: buildcfg.txt force textures/phase2/pnames.txt +wadinfo_phase2.txt: buildcfg.txt force pnames.txt $(CPP) -P -DDOOM2 < $< | scripts/wadinfo-builder.py -dummy > $@ -wadinfo_freedm.txt : buildcfg.txt force textures/freedm/pnames.txt +wadinfo_freedm.txt : buildcfg.txt force pnames.txt $(CPP) -P -DFREEDM < $< | scripts/wadinfo-builder.py -dummy > $@ %.wad.gz: %.wad @@ -96,7 +80,6 @@ wadinfo_freedm.txt : buildcfg.txt force textures/freedm/pnames.txt $(FREEDM): wadinfo_freedm.txt subdirs force @mkdir -p $(WADS) - ln -sf freedm/texture1.txt textures/texture1.txt rm -f $@ $(DEUTEX) $(DEUTEX_ARGS) -iwad -build wadinfo_freedm.txt $@ @@ -105,18 +88,16 @@ $(FREEDM): wadinfo_freedm.txt subdirs force $(FREEDOOM1): wadinfo_phase1.txt subdirs force @mkdir -p $(WADS) - ln -sf phase1/texture1.txt textures/texture1.txt rm -f $@ - $(DEUTEX) $(DEUTEX_ARGS) -iwad -textures -lumps -patch -flats -sounds -musics -graphics -sprites -levels -build wadinfo_phase1.txt $@ + $(DEUTEX) $(DEUTEX_ARGS) -iwad -lumps -patch -flats -sounds -musics -graphics -sprites -levels -build wadinfo_phase1.txt $@ #--------------------------------------------------------- # phase 2 (doom2) iwad $(FREEDOOM2): wadinfo_phase2.txt subdirs force @mkdir -p $(WADS) - ln -sf phase2/texture1.txt textures/texture1.txt rm -f $@ - $(DEUTEX) $(DEUTEX_ARGS) -iwad -textures -lumps -patch -flats -sounds -musics -graphics -sprites -levels -build wadinfo_phase2.txt $@ + $(DEUTEX) $(DEUTEX_ARGS) -iwad -lumps -patch -flats -sounds -musics -graphics -sprites -levels -build wadinfo_phase2.txt $@ doc: BUILD-SYSTEM.asc README.asc asciidoc BUILD-SYSTEM.asc @@ -135,14 +116,8 @@ clean: ./wadinfo_phase2.txt ./wadinfo_freedm.txt \ ./lumps/freedoom.lmp \ ./lumps/freedm.lmp \ - ./textures/phase1/pnames.txt \ - ./textures/phase1/texture1.txt \ - ./textures/phase2/pnames.txt \ - ./textures/phase2/texture1.txt \ - ./textures/freedm/pnames.txt \ - ./textures/freedm/texture1.txt \ - ./textures/texture1.txt - -rmdir $(WADS) textures/phase1 textures/phase2 textures/freedm + pnames.txt + -rmdir $(WADS) make -C lumps clean make -C graphics/text clean diff --git a/buildcfg.txt b/buildcfg.txt index 1b03ea34..64426a64 100644 --- a/buildcfg.txt +++ b/buildcfg.txt @@ -219,9 +219,28 @@ FOGMAP MFADEMAP C_END -; List of definitions for TEXTURE1 -[texture1] -TEXTURE1 +; Textures: + +#ifndef DOOM2 + +TEXTURE1 = fd1txtr1 +TEXTURE2 = fd1txtr2 +PNAMES = fd1pname + +#else +#ifdef FREEDM + +TEXTURE1 = fdmtxtr1 +PNAMES = fdmpname + +#else + +TEXTURE1 = fd2txtr1 +PNAMES = fd2pname + +#endif +#endif + ; List of Sounds [sounds] @@ -2538,19 +2557,7 @@ YSKUB0 7 18 [patches] -#ifdef ULTDOOM -#include "textures/phase1/pnames.txt" -#endif - -#ifdef DOOM2 - -#ifdef FREEDM -#include "textures/freedm/pnames.txt" -#else -#include "textures/phase2/pnames.txt" -#endif - -#endif +#include "pnames.txt" [flats] diff --git a/lumps/Makefile b/lumps/Makefile index 6dbcfa90..da34ee03 100644 --- a/lumps/Makefile +++ b/lumps/Makefile @@ -1,5 +1,6 @@ -all : freedoom.lmp freedm.lmp misc-lumps genmidi-lump dmxgus.lmp +all : freedoom.lmp freedm.lmp misc-lumps genmidi-lump dmxgus.lmp \ + fd1txtr1.lmp fd2txtr1.lmp fdmtxtr1.lmp misc-lumps: make -C cph/misc-lumps @@ -10,6 +11,9 @@ genmidi-lump: dmxgus.lmp: make -C dmxgus +fd1txtr1.lmp fd2txtr1.lmp fdmtxtr1.lmp: + make -C textures + freedoom.lmp: force echo $(VERSION) > freedoom.lmp @@ -22,4 +26,5 @@ clean: make -C cph/misc-lumps clean make -C genmidi clean make -C dmxgus clean + make -C textures clean diff --git a/lumps/fd1pname.lmp b/lumps/fd1pname.lmp new file mode 120000 index 00000000..12100203 --- /dev/null +++ b/lumps/fd1pname.lmp @@ -0,0 +1 @@ +textures/phase1/pnames.lmp \ No newline at end of file diff --git a/lumps/fd1txtr1.lmp b/lumps/fd1txtr1.lmp new file mode 120000 index 00000000..6b8378dc --- /dev/null +++ b/lumps/fd1txtr1.lmp @@ -0,0 +1 @@ +textures/phase1/texture1.lmp \ No newline at end of file diff --git a/lumps/fd1txtr2.lmp b/lumps/fd1txtr2.lmp new file mode 120000 index 00000000..b41b8f6a --- /dev/null +++ b/lumps/fd1txtr2.lmp @@ -0,0 +1 @@ +textures/phase1/texture2.lmp \ No newline at end of file diff --git a/lumps/fd2pname.lmp b/lumps/fd2pname.lmp new file mode 120000 index 00000000..3c7ed1df --- /dev/null +++ b/lumps/fd2pname.lmp @@ -0,0 +1 @@ +textures/phase2/pnames.lmp \ No newline at end of file diff --git a/lumps/fd2txtr1.lmp b/lumps/fd2txtr1.lmp new file mode 120000 index 00000000..fcfc9448 --- /dev/null +++ b/lumps/fd2txtr1.lmp @@ -0,0 +1 @@ +textures/phase2/texture1.lmp \ No newline at end of file diff --git a/lumps/fdmpname.lmp b/lumps/fdmpname.lmp new file mode 120000 index 00000000..a1f5b12b --- /dev/null +++ b/lumps/fdmpname.lmp @@ -0,0 +1 @@ +textures/freedm/pnames.lmp \ No newline at end of file diff --git a/lumps/fdmtxtr1.lmp b/lumps/fdmtxtr1.lmp new file mode 120000 index 00000000..4e1bb62b --- /dev/null +++ b/lumps/fdmtxtr1.lmp @@ -0,0 +1 @@ +textures/freedm/texture1.lmp \ No newline at end of file diff --git a/lumps/textures/Makefile b/lumps/textures/Makefile new file mode 100644 index 00000000..fbcb881d --- /dev/null +++ b/lumps/textures/Makefile @@ -0,0 +1,36 @@ + +CPP=../../scripts/simplecpp +PHASE1_OUTPUTS = phase1/texture1.lmp phase1/texture2.lmp \ + phase1/pnames.lmp +PHASE2_OUTPUTS = phase2/texture1.lmp phase2/pnames.lmp +FREEDM_OUTPUTS = freedm/texture1.lmp freedm/pnames.lmp + +all: $(PHASE1_OUTPUTS) $(PHASE2_OUTPUTS) $(FREEDM_OUTPUTS) + +$(PHASE1_OUTPUTS): textures.cfg + $(CPP) -DDOOM1 -DULTDOOM < textures.cfg | \ + ./build-textures -compat_texture1=doom1/texture1.txt \ + -compat_texture2=doom1/texture2.txt \ + -compat_pnames=doom1/pnames.txt \ + -output_texture1=phase1/texture1.lmp \ + -output_texture2=phase1/texture2.lmp \ + -output_pnames=phase1/pnames.lmp + +$(PHASE2_OUTPUTS): textures.cfg + $(CPP) -DDOOM1 -DDOOM2 < textures.cfg | \ + ./build-textures -compat_texture1=doom2/texture1.txt \ + -compat_pnames=doom2/pnames.txt \ + -output_texture1=phase2/texture1.lmp \ + -output_pnames=phase2/pnames.lmp + +$(FREEDM_OUTPUTS): textures.cfg + $(CPP) -DDOOM1 -DDOOM2 -DFREEDM < textures.cfg | \ + ./build-textures -compat_texture1=doom2/texture1.txt \ + -compat_pnames=doom2/pnames.txt \ + -output_texture1=freedm/texture1.lmp \ + -output_pnames=freedm/pnames.lmp + + +clean: + rm -f $(PHASE1_OUTPUTS) $(PHASE2_OUTPUTS) $(FREEDM_OUTPUTS) + diff --git a/lumps/textures/build-textures b/lumps/textures/build-textures new file mode 100755 index 00000000..ee564fba --- /dev/null +++ b/lumps/textures/build-textures @@ -0,0 +1,352 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014 +# Contributors to the Freedoom project. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of the freedoom project nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS +# IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED +# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER +# OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING +# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# +# +# Texture lump builder for Freedoom +# +# This script builds the TEXTURE1, TEXTURE2 and PNAMES lumps for +# Freedoom - the lumps containing the texture definitions. +# +# Freedoom does not use deutex's built-in texture builder for several +# reasons: +# +# Firstly, Freedoom's texture lumps need to be compatible with those +# of the original Doom WADs. There are several examples of PWADs that +# replace only PNAMES, or only TEXTURE1. Because the TEXTURE1 format +# is tightly coupled to the ordering of the PNAMES lump, this means +# that these WADs will fail in Freedoom unless the ordering is +# strictly maintained. For example, if entry #3 in PNAMES is DOOR2_4, +# it must also be the same in Freedoom's version of PNAMES. +# +# Freedoom has a single configuration file where all its textures are +# defined, but doom.wad contains two separate lumps: TEXTURE1/TEXTURE2. +# Similarly to the first problem, it's important that the compatible +# lumps are built with the same textures in each: some WADs replace +# TEXTURE1 but not TEXTURE2, with the result that many textures end +# up missing. +# +# Finally, deutex does not allow a filename to be specified for +# TEXTURE entries. That is to say, you can't do this: +# +# [textures] +# TEXTURE1 = fdtxtr1.txt +# +# This is an annoying limitation that means that the different +# Freedoom IWADs cannot be built in parallel by make. + +import collections +import re +import sys +import struct + +COMMENT_RE = re.compile(r"\s*;.*") +TEXTURE_NAME_RE = re.compile(r"\s*([\w-]+)\s+(-?\d+)\s+(-?\d+)") +PATCH_NAME_RE = re.compile(r"\s*\*\s+([\w-]+)\s+(-?\d+)\s+(-?\d+)") + +Texture = collections.namedtuple("Texture", ["w", "h", "patches"]) +TexturePatch = collections.namedtuple("TexturePatch", ["pname", "x", "y"]) + +class TextureSet(collections.OrderedDict): + def __init__(self, pnames): + """Initialize a new set of textures. + + Args: + pnames: List of PNAMES to use for the textures. New + patches will be added to this list as the texture + set is extended. + """ + super(TextureSet, self).__init__() + self.pnames = pnames + + def pname_index(self, pname): + """Get the index into the PNAMES list for the given patch. + + If the patch is not in the list, it will be added to the + list. + + Args: + pname: Name of the patch to look up. + Returns: + Index into the PNAMES list where this patch can be found. + """ + try: + return self.pnames.index(pname) + except ValueError: + self.pnames.append(pname.upper()) + return len(self.pnames) - 1 + + def add_texture(self, name, width=0, height=0): + """Add a new texture to the set. + + If a texture is already defined with the given name, the + current definition is erased (though the ordering of + textures is maintained). + + Args: + name: Name of the texture. + width: Width of the texture in pixels. + height: Height of the texture in pixels. + """ + self[name] = Texture(width, height, []) + + def add_texture_patch(self, txname, patch, x, y): + """Add a patch to the given texture. + + Args: + txname: Name of the texture. + patch: Name of the patch to add. + x: X offset for the patch in pixels. + y: Y offset for the patch in pixels. + """ + texture = self[txname] + tp = TexturePatch(self.pname_index(patch), x, y) + texture.patches.append(tp) + + def write_texture_lump(self, filename): + """Build the texture lump and output to a file. + + Args: + filename: Path to file in which to store the resulting + lump. + """ + with open(filename, "w") as out: + # Header indicating number of textures: + out.write(struct.pack(" 8: + raise NamesFileError( + 'Invalid name in %s: %s' % (filename, line)) + if line != '': + result.append(line.upper()) + return result + +def load_compat_textures(textures, compat_file): + """Pre-populate a texture set from a compatibility file. + + Args: + textures: TextureSet to populate. + compat_file: Path to text file containing list of textures. If + None, do not do anything. + """ + if compat_file is None: + return + + for texture in read_names_file(compat_file): + textures.add_texture(texture) + +class TextureConfigError(Exception): + pass + +def parse_textures(stream): + """Parse texture config from the given input stream. + + Args: + stream: Input stream from which to read lines of input. + Yields: + A tuple for each parsed texture, containing: + Texture name + Width + Height + List of tuples representing each patch, where each contains: + Patch name + X offset + Y offset + """ + current_texture = None + current_patches = [] + linenum = 0 + for line in sys.stdin: + line = COMMENT_RE.sub('', line).strip() + linenum += 1 + + match = TEXTURE_NAME_RE.match(line) + if match: + if current_texture is not None: + yield current_texture + + current_patches = [] + current_texture = ( + match.group(1), # Texture name + int(match.group(2)), # Width + int(match.group(3)), # Height + current_patches, # List of patches + ) + continue + + match = PATCH_NAME_RE.match(line) + if match and current_texture: + current_patches.append(( + match.group(1), # Patch name + int(match.group(2)), # X offset + int(match.group(3)), # Y offset + )) + continue + + if line != '': + raise TextureConfigError( + 'input:%i:Invalid config line: %s' % + (linenum, line)) + + # Last texture: + if current_texture is not None: + yield current_texture + +def write_pnames_lump(pnames, filename): + """Write a PNAMES list to a file. + + Args: + pnames: List of strings containing patch names. + filename: Output filename. + """ + with open(filename, "w") as out: + out.write(struct.pack("