diff --git a/BSD b/BSD new file mode 100644 index 00000000..79fe1f97 --- /dev/null +++ b/BSD @@ -0,0 +1,28 @@ +Copyright (c) 2001, Loki software, inc. +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 Loki software 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 REGENTS 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. + diff --git a/CHANGES-MACOS b/CHANGES-MACOS new file mode 100644 index 00000000..fbe54618 --- /dev/null +++ b/CHANGES-MACOS @@ -0,0 +1,11 @@ +Changes file for the MacOS port of GtkRadiant 1.1-TA +---------------------------------------------------- +05/24/2001 +TTimo + Patching the MacOS branch to build on linux +04/15/2001 +Pradeep + Changes so that the whole project compiles under MacOSX/XFree. +03/28/2001 +TTimo + added this file and gave write access to pradeep on the tree (testing write access) diff --git a/COMPILING b/COMPILING new file mode 100644 index 00000000..a53331be --- /dev/null +++ b/COMPILING @@ -0,0 +1,7 @@ + * understand relative paths in the .game file + * ignore warnings: 4996 4244 4267 + ( some CRT API warning stuff, and size conversion warnings) + * using the same updated Gtk win32 as GtkR 1.5 (may be packaged a bit differently for sanity) + * converted the project files to VC8 + * disabled all the modules that are not necessary for Q3 editing + * default parameters can't be used in function typedefs anymore, removed those and fixed the code accordingly diff --git a/CONTRIBUTORS b/CONTRIBUTORS new file mode 100644 index 00000000..3cfab6d2 --- /dev/null +++ b/CONTRIBUTORS @@ -0,0 +1,65 @@ +GtkRadiant CONTRIBUTORS and CREDITS +last update: 01/15/2001 +======================= + +Loki +---- +Leonardo Zide leo@lokigames.com +Mike Phillips (Loki QA) +Bernd Kreimeier (overall coordination) + +QER.com +------- +TTimo timo@qeradiant.com +^Fishman (Pablo Zurita) fish@gamedesign.net +RR2DO2 rr2do2@q3f.com + +Curry plugin +------------ +Mike "mickey" Jackman +Tim "Maj" Rennie +William "SmallPileOfGibs" Joseph + +PrtView plugin, various bug fixes and q3map guru +------------------------------------------------ +Geoffrey DeWan + +Gensurf plugin +-------------- +David Hyde + +PicoModel +--------- +seaw0lf with assist by ydnar + +Q3Map2 +------ +Randy 'ydnar' Reddig + +Updated shader files, textures, entities.def, keyboard shortcut list +overall testing and feedback +---------------------------- +Jean-Francois "Eutectic" Groleau + +Improvements and bug fixing +--------------------------- +Jan Paul "MrElusive" van Waveren +Robert Duffy + +Web +--- +Dave "Bargle" Koenig and Jason "Wolfen" Spencer + +Thanks to John Hutton, AstroCreep and W2k for web help + +FAQ +--- +Equim and Wex + +Misc +---- +Thanks to everyone on the beta mailing list and +irc.telefragged.com #qeradiant for testing and feedback. +Updated icons by AstroCreep! +Bitch-slapping by RaYGunn! +Last minute bugs by SpoG! (SpoG--) diff --git a/CONTRIBUTOR_AGREEMENT b/CONTRIBUTOR_AGREEMENT new file mode 100644 index 00000000..e69de29b diff --git a/DarwinCompileInfo.rtf b/DarwinCompileInfo.rtf new file mode 100644 index 00000000..ff5cfb16 --- /dev/null +++ b/DarwinCompileInfo.rtf @@ -0,0 +1,55 @@ +{\rtf1\mac\ansicpg10000\cocoartf100 +{\fonttbl\f0\fswiss\fcharset77 Helvetica;} +{\colortbl;\red255\green255\blue255;} +\margl1440\margr1440\vieww9000\viewh9000\viewkind0 +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural + +\f0\fs24 \cf0 \ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural +\cf0 Install XFree86\ + see\ + http://xfree86.org and http://mrcla.com/XonX \ + on installing X Window System on your OS X\ +\ +Download these:\ +ftp://gnu-darwin.sourceforge.net/pub/gnu-darwin/gtk+-1.2.8.tgz\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural +\cf0 ftp://gnu-darwin.sourceforge.net/pub/gnu-darwin/Mesa-3.4.tgz\ +\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural +\cf0 Untar these with \ + tar xzvf gtk+-1.2.8.tgz\ + tar xzvf Mesa-3.4.tgz\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural +\cf0 \ +change to root , go into these directory and type:\ +make install\ +(This will install gtk and Mesa)\ +\ +download this:\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural +\cf0 http://prdownloads.sourceforge.net/fink/dlcompat-20010123.tar.gz\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural +\cf0 tar xzvf dlcompat*\ +cd dlcompat*\ +make\ +make install # do this as soot\ +\ +cd GtkRadiant/libs/libxml2/\ +./configure\ +make\ +make install\ +\ +cd GtkRadiant/libs/\ +make\ +\ +cd GtrRadiant/tools/\ +make\ +(This will give you a q3map executable )\ +\ +cd GtkRadiant/radiant/\ +make\ +\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\ql\qnatural +\cf0 (This will give you a radiant executable )\ +\ +} diff --git a/DoxyConfig b/DoxyConfig new file mode 100644 index 00000000..fc7f6821 --- /dev/null +++ b/DoxyConfig @@ -0,0 +1,47 @@ +# Included Doxygen Config file +#--------------------------------------------------------------------------- +# Project name & version number +#--------------------------------------------------------------------------- +PROJECT_NAME = +PROJECT_NUMBER = + +#--------------------------------------------------------------------------- +# Where to put the output +# Note: The images dir should be next to the created html dir within the +# output dir. +# eg; +# [Current Dir] +# L__[OUTPUT_DIRECTORY] +# L__[html] +# L__[images] +#--------------------------------------------------------------------------- +OUTPUT_DIRECTORY = ../GtkRadiant-doxygen + +#--------------------------------------------------------------------------- +# Where to read the sources +# you can add more than one source... +# INPUT = radiant/ \ +# tools/quake3/q3map \ +# tools/quake3/q3data +# +# Recursive is set on, so setting it to ./ (current dir) would read source +# files recursively from the current dir down. (which would take a while) +# +# eg: To document just include, if the current directory is ../GtkRadiant/ +# then... +#--------------------------------------------------------------------------- +INPUT = GtkRadiant/include/ + +#--------------------------------------------------------------------------- +# Misc settings +# TAB_SIZE - sets the indenting for the inline source and the source +# browser +# INCLUDE_PATH - will include documentation for included files from other +# packages. You can specify more than one path the same as +# shown in the INPUT example Leave it blank if you don't want +# this. +# PERL_PATH - path to the perl executable +# +#--------------------------------------------------------------------------- +PERL_PATH = /usr/bin/perl + diff --git a/Doxyfile b/Doxyfile new file mode 100644 index 00000000..a992b3d4 --- /dev/null +++ b/Doxyfile @@ -0,0 +1,170 @@ +# Doxyfile 1.2.5-20010304 +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = +PROJECT_NUMBER = +OUTPUT_DIRECTORY = +OUTPUT_LANGUAGE = English +EXTRACT_ALL = YES +EXTRACT_PRIVATE = NO +EXTRACT_STATIC = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = NO +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = $(PWD)/ +INTERNAL_DOCS = YES +CLASS_DIAGRAMS = YES +SOURCE_BROWSER = YES +INLINE_SOURCES = YES +STRIP_CODE_COMMENTS = YES +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +VERBATIM_HEADERS = YES +SHOW_INCLUDE_FILES = YES +JAVADOC_AUTOBRIEF = YES +INHERIT_DOCS = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = +ENABLED_SECTIONS = +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +ALIASES = +MAX_INITIALIZER_LINES = 30 +OPTIMIZE_OUTPUT_FOR_C = NO +SHOW_USED_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = doxygen.log +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = +FILE_PATTERNS = *.h \ + *.cpp \ + *.c +RECURSIVE = YES +EXCLUDE = *.dsp \ + *.dsw \ + *.o \ + *.d \ + *.ico \ + *.bmp \ + *.txt \ + *.rc \ + Entries \ + Entries.Log \ + Repository \ + Root +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +IMAGE_PATH = +INPUT_FILTER = +FILTER_SOURCE_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 4 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = +HTML_HEADER = Doxygen_extras/doxygen_gtkradiant_head.html +HTML_FOOTER = Doxygen_extras/doxygen_gtkradiant_foot.html +HTML_STYLESHEET = Doxygen_extras/doxygen_gtkradiant.css +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = +MAN_EXTENSION = .3 +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = YES +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +GRAPHICAL_HIERARCHY = YES +DOT_PATH = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO +CGI_NAME = search.cgi +CGI_URL = +DOC_URL = +DOC_ABSPATH = +BIN_ABSPATH = /usr/local/bin/ +EXT_DOC_PATHS = + +#--------------------------------------------------------------------------- +# Include file, at the bottom to over-ride anything I missed. +#--------------------------------------------------------------------------- +@INCLUDE = DoxyConfig diff --git a/Doxygen_files/Doxyfile b/Doxygen_files/Doxyfile new file mode 100644 index 00000000..912e2b99 --- /dev/null +++ b/Doxygen_files/Doxyfile @@ -0,0 +1,159 @@ +# Doxyfile 1.2.5-20010304 +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = +PROJECT_NUMBER = +OUTPUT_DIRECTORY = +OUTPUT_LANGUAGE = English +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = YES +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = $(PWD)/ +INTERNAL_DOCS = YES +CLASS_DIAGRAMS = YES +SOURCE_BROWSER = YES +INLINE_SOURCES = YES +STRIP_CODE_COMMENTS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +VERBATIM_HEADERS = YES +SHOW_INCLUDE_FILES = YES +JAVADOC_AUTOBRIEF = YES +INHERIT_DOCS = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 2 +ENABLED_SECTIONS = +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +ALIASES = +MAX_INITIALIZER_LINES = 30 +OPTIMIZE_OUTPUT_FOR_C = NO +SHOW_USED_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = doxygen.log +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = +FILE_PATTERNS = *.h \ + *.cpp \ + *.c +RECURSIVE = YES +EXCLUDE = +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +IMAGE_PATH = +INPUT_FILTER = +FILTER_SOURCE_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 4 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = +HTML_HEADER = Doxygen_files/doxygen_gtkradiant_head.html +HTML_FOOTER = Doxygen_files/doxygen_gtkradiant_foot.html +HTML_STYLESHEET = Doxygen_files/doxygen_gtkradiant.css +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = +MAN_EXTENSION = .3 +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +GRAPHICAL_HIERARCHY = YES +DOT_PATH = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO +CGI_NAME = search.cgi +CGI_URL = +DOC_URL = +DOC_ABSPATH = +BIN_ABSPATH = /usr/local/bin/ +EXT_DOC_PATHS = + +#--------------------------------------------------------------------------- +# Include file, at the bottom to over-ride anything I missed. +#--------------------------------------------------------------------------- +@INCLUDE = genConf \ No newline at end of file diff --git a/Doxygen_files/doxy_mainpage.h b/Doxygen_files/doxy_mainpage.h new file mode 100644 index 00000000..34e4bc50 --- /dev/null +++ b/Doxygen_files/doxy_mainpage.h @@ -0,0 +1,45 @@ +/* +** Doxygen index.html generation file +** +*/ + +/*! \mainpage +project+ Doxygen Index + + \section intro Introduction + + This documentation was generated from GtkRadiant source code using Doxygen.
+ Generated from source in: +target+ + + \section links Links + General Links
+ Doxygen Homepage
+ GtkRadiant Homepage
+ Zerowing - GtkRadiant Development
+ + Local Links
+ Doxygen Quick Reference (Local)
+ +

+ GtkRadiant FAQ Links
+ GtkRadiant FAQ
+ GtkRadiant FAQ: Open Tasks
+ GtkRadiant FAQ: Compiling instructions
+ GtkRadiant FAQ: Creating/Submitting patches
+ GtkRadiant FAQ: Coding Conventions & Guidelines
+

+ + Misc Links
+ idsoftware.com
+ +

+ + * Note: The content on this page was generated from this file. + It is moved into the path when the doxygen documentation is generated, and removed immediately + afterwards. + +

+ + This page generated: by +user+ on +machine+
+ On +date+ +
+*/ diff --git a/Doxygen_files/doxygen_gtkradiant.css b/Doxygen_files/doxygen_gtkradiant.css new file mode 100644 index 00000000..b875556c --- /dev/null +++ b/Doxygen_files/doxygen_gtkradiant.css @@ -0,0 +1,34 @@ +body { background-color: black; } +IMG { border-color: #222222; border: 0; } +em { font-size: 11px; font-style: italic; font-weight: normal; color: #888888; } +H1 { text-align: center; font-size: 15px; color: #2222AA; font-family: Geneva, Verdana, Helvetica, Arial, sans-serif; } +H3 { text-align: center; font-size: 18px; color: #2222AA; font-family: Geneva, Verdana, Helvetica, Arial, sans-serif; } +A { text-decoration: none; color: #6666DD; } +A:HOVER { text-decoration: underline; color: #4444FF; } +A:VISITED { text-decoration: none; color: #8888AA; } +A.qindex { text-decoration: none; color: #6666DD; font-size: 11px; } +A.qindex:HOVER { text-decoration: underline; color: #4444FF; font-size: 11px; } +A.qindex:VISITED { text-decoration: none; color: #8888AA; font-size: 11px; } +A.qindexRef { font-size: 11px; } +A.el { text-decoration: none; font-weight: bold; } +A.elRef { font-weight: bold; } +A.code { text-decoration: none; font-weight: normal; color: #6666DD; } +A.code:HOVER { text-decoration: underline; font-weight: normal; color: #4444FF; } +A.code:VISITED { text-decoration: none; font-weight: normal; color: #8888AA; } +A.codeRef { text-decoration: none; font-weight: normal; color: #6666DD; } +A.codeRef:HOVER { text-decoration: underline; font-weight: normal; color: #4444FF; } +A.codeRef:VISITED { text-decoration: none; font-weight: normal; color: #8888AA; } +DL.el { margin-left: 2cm; width: 99%; } +DIV.fragment { background-color: #FFFFFF; width: 99%; } +DIV.ah { background-color: #AAAAAA; width: 99%; margin-bottom: 3; margin-top: 3; } +TD.md { cellpadding: 0; background-color: #DDDDDD; border: 0; width: 99%; color: #222222; } +DIV.groupHeader { margin-left: 16; margin-top: 12; margin-bottom: 6; font-weight: bold; color: #222222; } +DIV.groupText { margin-left: 16; font-style: italic; font-size: smaller; } +FONT.keyword { color: #0080A0; } +FONT.keywordtype { color: #604020; } +FONT.keywordflow { color: #E08000; } +FONT.comment { color: #800000; } +FONT.comment { color: #009900; text-decoration: italic; } +FONT.preprocessor { color: #806020; } +FONT.stringliteral{ color: #002080; } +FONT.charliteral { color: #008080; } diff --git a/Doxygen_files/doxygen_gtkradiant_foot.html b/Doxygen_files/doxygen_gtkradiant_foot.html new file mode 100644 index 00000000..46162436 --- /dev/null +++ b/Doxygen_files/doxygen_gtkradiant_foot.html @@ -0,0 +1,49 @@ + + + + + +

+
+ + + + + +
+ Documentation generated by : Doxygen $doxygenversion + + + ttimo@idsoftware.com + +
+
+ +
+
+ +   + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Doxygen_files/doxygen_gtkradiant_head.html b/Doxygen_files/doxygen_gtkradiant_head.html new file mode 100644 index 00000000..5e0a9eaf --- /dev/null +++ b/Doxygen_files/doxygen_gtkradiant_head.html @@ -0,0 +1,38 @@ + + + + $projectname $projectnumber Doxygen Documentation + + + + + +
+
+ + + + + + +
+ +
idsoftware
+
+ + + + + + + + + + + + +
+ + +
 
+

+
+ + + + + + + + +
+ \ No newline at end of file diff --git a/Doxygen_files/doxygen_index.html b/Doxygen_files/doxygen_index.html new file mode 100644 index 00000000..6b24c2fc --- /dev/null +++ b/Doxygen_files/doxygen_index.html @@ -0,0 +1,7 @@ + + + + + + Redirecting to Doxygen index + diff --git a/Doxygen_files/doxygen_reference_foot.html b/Doxygen_files/doxygen_reference_foot.html new file mode 100644 index 00000000..a7390bc5 --- /dev/null +++ b/Doxygen_files/doxygen_reference_foot.html @@ -0,0 +1,46 @@ + +

+
+ + + + + +
+ + Doxygen is: Copyright © 1997-2001 by Dimitri van Heesch. + + + GtkRadiant Doxygen Maintainer: Gef +
+
+ +
+
+
 
+ + + + + +
+ +
+
+
+ +
+ + + diff --git a/Doxygen_files/doxygen_reference_head.html b/Doxygen_files/doxygen_reference_head.html new file mode 100644 index 00000000..e735c9e4 --- /dev/null +++ b/Doxygen_files/doxygen_reference_head.html @@ -0,0 +1,38 @@ + + + + GtkRadiant - Doxygen Quick Reference + + + + + +
+ +
+ + + + + + +
+ + +
idsoftware
+
+ + + + + + + + + + + + +
+ + +
&nsbp;
+

+ \ No newline at end of file diff --git a/Doxygen_files/example/annotated.html b/Doxygen_files/example/annotated.html new file mode 100644 index 00000000..852a7f00 --- /dev/null +++ b/Doxygen_files/example/annotated.html @@ -0,0 +1,103 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

IEPairsClassDocumentationExample Compound List

Here are the classes, structs, unions and interfaces with brief descriptions:
    +
  • IEpair (Virtual class to allow plugin operations on entity pairs) +
+ + +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ +
+
+ +
+ + + diff --git a/Doxygen_files/example/classIEpair-members.html b/Doxygen_files/example/classIEpair-members.html new file mode 100644 index 00000000..ed4d8778 --- /dev/null +++ b/Doxygen_files/example/classIEpair-members.html @@ -0,0 +1,110 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

IEpair Member List

This is the complete list of members for IEpair, including all inherited members. + + +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/classIEpair.html b/Doxygen_files/example/classIEpair.html new file mode 100644 index 00000000..cba38de1 --- /dev/null +++ b/Doxygen_files/example/classIEpair.html @@ -0,0 +1,414 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

IEpair Class Reference

Virtual class to allow plugin operations on entity pairs. +More... +

+List of all members. + + + + + + + + + + + + + + + + + +

Public Methods

virtual void IncRef ()=0
 Increment the number of references to this object. More...

virtual void DecRef ()=0
 Decrement the reference count. More...

virtual void GetVectorForKey (char *key, vec3_t vec)=0
 Get a vector from a key. More...

virtual float FloatForKey (char *key)=0
 Get a float from a key. More...

virtual char* ValueForKey (char *key)=0
 Get a string (char *) from a key. More...

virtual void SetKeyValue (char *key, char *value)=0
 Set a key value to char *value. More...

virtual void GetEntityOrigin (vec3_t vec)=0
 Get a vec3_t for the entities origin. More...

virtual void CalculateRotatedBounds (vec3_t mins, vec3_t maxs)=0
 Compute the rotated bounds of the BBox based on "angle" and "angles" keys. More...

+


Detailed Description

+Virtual class to allow plugin operations on entity pairs. +

+ +

+

+Todo:
+Write more complete documentation for this class so that it's use is clear
+

+An interface to entity keys and key pairs that allows plugins to; read and write entity keys and key values, get a key value as a vec3_t +

+ +

+Definition at line 10 of file iepairs.h.


Member Function Documentation

+

+ + + + +
+ + + + + + + + + + +
+void IEpair::CalculateRotatedBounds ( + +vec3_t mins, +
+vec3_t maxs ) [pure virtual] +
+
+ + + + + +
+   + + +

+Compute the rotated bounds of the BBox based on "angle" and "angles" keys. +

+

+

+ + + + +
+ + + + + + +
+void IEpair::DecRef ( + +) [pure virtual] +
+
+ + + + + +
+   + + +

+Decrement the reference count. +

+

+

+ + + + +
+ + + + + + +
+float IEpair::FloatForKey ( + +char * key ) [pure virtual] +
+
+ + + + + +
+   + + +

+Get a float from a key. +

+

+

+ + + + +
+ + + + + + +
+void IEpair::GetEntityOrigin ( + +vec3_t vec ) [pure virtual] +
+
+ + + + + +
+   + + +

+Get a vec3_t for the entities origin. +

+

+

+ + + + +
+ + + + + + + + + + +
+void IEpair::GetVectorForKey ( + +char * key, +
+vec3_t vec ) [pure virtual] +
+
+ + + + + +
+   + + +

+Get a vector from a key. +

+

+

+ + + + +
+ + + + + + +
+void IEpair::IncRef ( + +) [pure virtual] +
+
+ + + + + +
+   + + +

+Increment the number of references to this object. +

+

+

+ + + + +
+ + + + + + + + + + +
+void IEpair::SetKeyValue ( + +char * key, +
+char * value ) [pure virtual] +
+
+ + + + + +
+   + + +

+Set a key value to char *value. +

+

+Parameters:
+ + + +
key +The (char *) containing the keyname
value +The (char *) to set the key value to
+
+

+ + + + +
+ + + + + + +
+char * IEpair::ValueForKey ( + +char * key ) [pure virtual] +
+
+ + + + + +
+   + + +

+Get a string (char *) from a key. +

+

+


The documentation for this class was generated from the following file: + + +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/classes.html b/Doxygen_files/example/classes.html new file mode 100644 index 00000000..7e5bd909 --- /dev/null +++ b/Doxygen_files/example/classes.html @@ -0,0 +1,103 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

IEPairsClassDocumentationExample Compound Index

+ +
  I  
IEpair   
+ + +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/doxygen.gif b/Doxygen_files/example/doxygen.gif new file mode 100644 index 00000000..192c83ce Binary files /dev/null and b/Doxygen_files/example/doxygen.gif differ diff --git a/Doxygen_files/example/doxygen_gtkradiant.css b/Doxygen_files/example/doxygen_gtkradiant.css new file mode 100644 index 00000000..c0ddae2d --- /dev/null +++ b/Doxygen_files/example/doxygen_gtkradiant.css @@ -0,0 +1,35 @@ +body { background-color: black; } +IMG { border-color: #222222; border: 1; } +em { font-size: 11px; font-style: italic; font-weight: normal; color: #888888; } +H1 { text-align: center; font-size: 15px; color: #2222AA; font-family: Geneva, Verdana, Helvetica, Arial, sans-serif; } +H3 { text-align: center; font-size: 18px; color: #2222AA; font-family: Geneva, Verdana, Helvetica, Arial, sans-serif; } +A { text-decoration: none; color: #6666DD; } +A:HOVER { text-decoration: underline; color: #4444FF; } +A:VISITED { text-decoration: none; color: #8888AA; } +A.qindex { text-decoration: none; color: #6666DD; font-size: 11px; } +A.qindex:HOVER { text-decoration: underline; color: #4444FF; font-size: 11px; } +A.qindex:VISITED { text-decoration: none; color: #8888AA; font-size: 11px; } +A.qindexRef { font-size: 11px; } +A.el { text-decoration: none; font-weight: bold; } +A.elRef { font-weight: bold; } +A.code { text-decoration: none; font-weight: normal; color: #6666DD; } +A.code:HOVER { text-decoration: underline; font-weight: normal; color: #4444FF; } +A.code:VISITED { text-decoration: none; font-weight: normal; color: #8888AA; } +A.codeRef { text-decoration: none; font-weight: normal; color: #6666DD; } +A.codeRef:HOVER { text-decoration: underline; font-weight: normal; color: #4444FF; } +A.codeRef:VISITED { text-decoration: none; font-weight: normal; color: #8888AA; } +DL.el { margin-left: 2cm; width: 99%; } +DIV.fragment { background-color: #FFFFFF; width: 99%; } +DIV.ah { background-color: #AAAAAA; width: 99%; margin-bottom: 3; margin-top: 3; } +TD.md { cellpadding: 2; background-color: #DDDDDD; border: 1; width: 99%; color: #222222; } +DIV.groupHeader { margin-left: 16; margin-top: 12; margin-bottom: 6; font-weight: bold; color: #222222; } +DIV.groupText { margin-left: 16; font-style: italic; font-size: smaller; } +FONT.keyword { color: #0080A0; } +FONT.keywordtype { color: #604020; } +FONT.keywordflow { color: #E08000; } +FONT.comment { color: #800000; } +FONT.comment { color: #009900; text-decoration: italic; } +FONT.preprocessor { color: #806020; } +FONT.stringliteral{ color: #002080; } +FONT.charliteral { color: #008080; } + diff --git a/Doxygen_files/example/files.html b/Doxygen_files/example/files.html new file mode 100644 index 00000000..5b00181d --- /dev/null +++ b/Doxygen_files/example/files.html @@ -0,0 +1,102 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

IEPairsClassDocumentationExample File List

Here is a list of all files with brief descriptions: + + +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/functions.html b/Doxygen_files/example/functions.html new file mode 100644 index 00000000..0c245e22 --- /dev/null +++ b/Doxygen_files/example/functions.html @@ -0,0 +1,110 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

IEPairsClassDocumentationExample Compound Members

Here is a list of all class members with links to the class documentation for each member: + + +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/graph_legend.dot b/Doxygen_files/example/graph_legend.dot new file mode 100644 index 00000000..f4efdeb7 --- /dev/null +++ b/Doxygen_files/example/graph_legend.dot @@ -0,0 +1,16 @@ +digraph inheritance +{ + Node7 [shape="box",label="Inherited",fontsize=10,height=0.2,width=0.4,fontname="doxfont",color="black",style="filled" fontcolor="white"]; + Node8 -> Node7 [dir=back,color="midnightblue",fontsize=10,style="solid",fontname="doxfont"]; + Node8 [shape="box",label="PublicBase",fontsize=10,height=0.2,width=0.4,fontname="doxfont",color="black",URL="$class_publicbase.html"]; + Node9 -> Node8 [dir=back,color="midnightblue",fontsize=10,style="solid",fontname="doxfont"]; + Node9 [shape="box",label="Truncated",fontsize=10,height=0.2,width=0.4,fontname="doxfont",color="red",URL="$class_truncated.html"]; + Node11 -> Node7 [dir=back,color="darkgreen",fontsize=10,style="solid",fontname="doxfont"]; + Node11 [shape="box",label="ProtectedBase",fontsize=10,height=0.2,width=0.4,fontname="doxfont",color="black",URL="$class_protectedbase.html"]; + Node12 -> Node7 [dir=back,color="firebrick4",fontsize=10,style="solid",fontname="doxfont"]; + Node12 [shape="box",label="PrivateBase",fontsize=10,height=0.2,width=0.4,fontname="doxfont",color="black",URL="$class_privatebase.html"]; + Node13 -> Node7 [dir=back,color="midnightblue",fontsize=10,style="solid",fontname="doxfont"]; + Node13 [shape="box",label="Undocumented",fontsize=10,height=0.2,width=0.4,fontname="doxfont",color="grey75"]; + Node14 -> Node7 [dir=back,color="darkorchid3",fontsize=10,style="dashed",label="m_usedClass",fontname="doxfont"]; + Node14 [shape="box",label="Used",fontsize=10,height=0.2,width=0.4,fontname="doxfont",color="black",URL="$class_used.html"]; +} diff --git a/Doxygen_files/example/graph_legend.gif b/Doxygen_files/example/graph_legend.gif new file mode 100644 index 00000000..f4f1a005 Binary files /dev/null and b/Doxygen_files/example/graph_legend.gif differ diff --git a/Doxygen_files/example/graph_legend.html b/Doxygen_files/example/graph_legend.html new file mode 100644 index 00000000..29599cb0 --- /dev/null +++ b/Doxygen_files/example/graph_legend.html @@ -0,0 +1,141 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

Graph Legend

This page explains how to interpret the graphs that are generated by doxygen. +

+ Consider the following example:

/*! Invisible class because of truncation */
+class Invisible { };
+
+/*! Truncated class, inheritance relation is hidden */
+class Truncated : public Invisible { };
+
+/* Class not documented with doxygen comments */
+class Undocumented { };
+
+/*! Class that is inherited using public inheritance */
+class PublicBase : public Truncated { };
+
+/*! Class that is inherited using protected inheritance */
+class ProtectedBase { };
+
+/*! Class that is inherited using private inheritance */
+class PrivateBase { };
+
+/*! Class that is used by the Inherited class */
+class Used { };
+
+/*! Super class that inherits a number of other classes */
+class Inherited : public PublicBase,
+                  protected ProtectedBase,
+                  private PrivateBase,
+                  public Undocumented
+{
+  private:
+    Used *m_usedClass;
+};
If the MAX_DOT_GRAPH_HEIGHT tag in the configuration file is set to 200 this will result in the following graph: +

+

+
+ +

+ The boxes in the above graph have the following meaning:

    +
  • A filled black box represents the struct or class for which the graph is generated.
  • A box with a black border denotes a documented struct or class.
  • A box with a grey border denotes an undocumented struct or class.
  • A box with a red border denotes a documented struct or class for which not all inheritance/containment relations are shown. A graph is truncated if it does not fit within the specified boundaries.
+ The arrows have the following meaning:
    +
  • A dark blue arrow is used to visualize a public inheritance relation between two classes.
  • A dark green arrow is used for protected inheritance.
  • A dark red arrow is used for private inheritance.
  • A purple dashed arrow is used if a class is contained or used by another class. The arrow is labeled with the variable(s) through which the pointed class or struct is accessible.
+ + +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/index.html b/Doxygen_files/example/index.html new file mode 100644 index 00000000..4cfcdd8a --- /dev/null +++ b/Doxygen_files/example/index.html @@ -0,0 +1,102 @@ + + + + IEPairs Class Example Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

IEPairs Class Example Documentation

+

+ + +

+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/pages.html b/Doxygen_files/example/pages.html new file mode 100644 index 00000000..24287679 --- /dev/null +++ b/Doxygen_files/example/pages.html @@ -0,0 +1,104 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

IEPairsClassDocumentationExample Related Pages

Here is a list of all related documentation pages: + + +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/test_8c-source.html b/Doxygen_files/example/test_8c-source.html new file mode 100644 index 00000000..9b67ae0a --- /dev/null +++ b/Doxygen_files/example/test_8c-source.html @@ -0,0 +1,140 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

iepairs.h

Go to the documentation of this file.
00001 //! Virtual class to allow plugin operations on entity pairs
+00002 /*!
+00003   \todo Write more complete documentation for this class so that it's use
+00004   is clear
+00005                         
+00006   An interface to entity keys and key pairs that allows plugins to;
+00007   read and write entity keys and key values, get a key value as a
+00008   vec3_t
+00009 */
+00010 class IEpair
+00011 {
+00012   public:
+00013     //! Increment the number of references to this object
+00014     virtual void IncRef () = 0;
+00015                                 
+00016     //! Decrement the reference count
+00017     virtual void DecRef () = 0;
+00018                                 
+00019     //! Get a vector from a key
+00020     virtual void GetVectorForKey( char* key, vec3_t vec ) = 0;
+00021                                 
+00022     //! Get a float from a key
+00023     virtual float FloatForKey( char *key ) = 0;
+00024                                 
+00025     //! Get a string (char *) from a key
+00026     virtual char* ValueForKey( char *key ) = 0;
+00027                                 
+00028     //! Set a key value to char *value
+00029     /*!
+00030       \param key The (char *) containing the keyname
+00031       \param value The (char *) to set the key value to
+00032     */
+00033     virtual void SetKeyValue( char *key, char *value ) = 0;
+00034                                 
+00035     //! Get a vec3_t for the entities origin
+00036     virtual void GetEntityOrigin( vec3_t vec ) = 0;
+00037                                 
+00038     //! Compute the rotated bounds of the BBox based on "angle" and "angles" keys
+00039     virtual void CalculateRotatedBounds( vec3_t mins, vec3_t maxs ) = 0;
+00040 };
+
+ +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/test_8c.html b/Doxygen_files/example/test_8c.html new file mode 100644 index 00000000..2b7d1cd7 --- /dev/null +++ b/Doxygen_files/example/test_8c.html @@ -0,0 +1,107 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

iepairs.h File Reference

+

+Go to the source code of this file. + + + +

Compounds

class  IEpair
 Virtual class to allow plugin operations on entity pairs. More...

+ + +

+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/example/todo.html b/Doxygen_files/example/todo.html new file mode 100644 index 00000000..88b90db9 --- /dev/null +++ b/Doxygen_files/example/todo.html @@ -0,0 +1,105 @@ + + + + IEPairsClassDocumentationExample Doxygen Documentation + + + + + +
+ + + + + + + +
+ + +
idsoftware +
+ +
+ + + + + + + + + + + + + + + + + +
+ + + + + +
 
+

+ +
+
+ + + + + +
+Main Page   Alphabetical List   Compound List   File List   Compound Members   Related Pages  
+

Todo List

+ +
+
Class IEpair
Write more complete documentation for this class so that it's use is clear +
+ + +
+
+ +

+
+ + + + + +
+ Documentation generated by : Doxygen 1.2.8.1 on 11 Aug 2001 + + + ttimo@idsoftware.com + +
+
+ +
+
+
 
+ + + + + +
+ + + + + + + +
+ + + diff --git a/Doxygen_files/genDoxyfile b/Doxygen_files/genDoxyfile new file mode 100644 index 00000000..9421dc18 --- /dev/null +++ b/Doxygen_files/genDoxyfile @@ -0,0 +1,159 @@ +# Doxyfile 1.2.5-20010304 +#--------------------------------------------------------------------------- +# General configuration options +#--------------------------------------------------------------------------- +PROJECT_NAME = +PROJECT_NUMBER = +OUTPUT_DIRECTORY = +OUTPUT_LANGUAGE = English +EXTRACT_ALL = YES +EXTRACT_PRIVATE = YES +EXTRACT_STATIC = YES +HIDE_UNDOC_MEMBERS = NO +HIDE_UNDOC_CLASSES = NO +BRIEF_MEMBER_DESC = YES +REPEAT_BRIEF = YES +ALWAYS_DETAILED_SEC = YES +FULL_PATH_NAMES = YES +STRIP_FROM_PATH = $(PWD)/ +INTERNAL_DOCS = YES +CLASS_DIAGRAMS = YES +SOURCE_BROWSER = YES +INLINE_SOURCES = YES +STRIP_CODE_COMMENTS = NO +CASE_SENSE_NAMES = YES +HIDE_SCOPE_NAMES = NO +VERBATIM_HEADERS = YES +SHOW_INCLUDE_FILES = YES +JAVADOC_AUTOBRIEF = YES +INHERIT_DOCS = YES +INLINE_INFO = YES +SORT_MEMBER_DOCS = YES +DISTRIBUTE_GROUP_DOC = NO +TAB_SIZE = 2 +ENABLED_SECTIONS = +GENERATE_TODOLIST = YES +GENERATE_TESTLIST = YES +GENERATE_BUGLIST = YES +ALIASES = +MAX_INITIALIZER_LINES = 30 +OPTIMIZE_OUTPUT_FOR_C = NO +SHOW_USED_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to warning and progress messages +#--------------------------------------------------------------------------- +QUIET = YES +WARNINGS = YES +WARN_IF_UNDOCUMENTED = YES +WARN_FORMAT = "$file:$line: $text" +WARN_LOGFILE = doxygen.log +#--------------------------------------------------------------------------- +# configuration options related to the input files +#--------------------------------------------------------------------------- +INPUT = +FILE_PATTERNS = *.h \ + *.cpp \ + *.c +RECURSIVE = YES +EXCLUDE = +EXCLUDE_PATTERNS = +EXAMPLE_PATH = +EXAMPLE_PATTERNS = +IMAGE_PATH = +INPUT_FILTER = +FILTER_SOURCE_FILES = YES +#--------------------------------------------------------------------------- +# configuration options related to the alphabetical class index +#--------------------------------------------------------------------------- +ALPHABETICAL_INDEX = YES +COLS_IN_ALPHA_INDEX = 4 +IGNORE_PREFIX = +#--------------------------------------------------------------------------- +# configuration options related to the HTML output +#--------------------------------------------------------------------------- +GENERATE_HTML = YES +HTML_OUTPUT = +HTML_HEADER = Doxygen_files/doxygen_gtkradiant_head.html +HTML_FOOTER = Doxygen_files/doxygen_gtkradiant_foot.html +HTML_STYLESHEET = Doxygen_files/doxygen_gtkradiant.css +HTML_ALIGN_MEMBERS = YES +GENERATE_HTMLHELP = NO +GENERATE_CHI = NO +BINARY_TOC = NO +TOC_EXPAND = NO +DISABLE_INDEX = NO +ENUM_VALUES_PER_LINE = 4 +GENERATE_TREEVIEW = NO +TREEVIEW_WIDTH = 250 +#--------------------------------------------------------------------------- +# configuration options related to the LaTeX output +#--------------------------------------------------------------------------- +GENERATE_LATEX = NO +LATEX_OUTPUT = +COMPACT_LATEX = NO +PAPER_TYPE = a4wide +EXTRA_PACKAGES = +LATEX_HEADER = +PDF_HYPERLINKS = NO +USE_PDFLATEX = NO +LATEX_BATCHMODE = NO +#--------------------------------------------------------------------------- +# configuration options related to the RTF output +#--------------------------------------------------------------------------- +GENERATE_RTF = NO +RTF_OUTPUT = +COMPACT_RTF = NO +RTF_HYPERLINKS = NO +RTF_STYLESHEET_FILE = +#--------------------------------------------------------------------------- +# configuration options related to the man page output +#--------------------------------------------------------------------------- +GENERATE_MAN = NO +MAN_OUTPUT = +MAN_EXTENSION = .3 +#--------------------------------------------------------------------------- +# Configuration options related to the preprocessor +#--------------------------------------------------------------------------- +ENABLE_PREPROCESSING = YES +MACRO_EXPANSION = YES +EXPAND_ONLY_PREDEF = NO +SEARCH_INCLUDES = YES +INCLUDE_PATH = +INCLUDE_FILE_PATTERNS = +PREDEFINED = +EXPAND_AS_DEFINED = +#--------------------------------------------------------------------------- +# Configuration::addtions related to external references +#--------------------------------------------------------------------------- +TAGFILES = +GENERATE_TAGFILE = +ALLEXTERNALS = NO +#--------------------------------------------------------------------------- +# Configuration options related to the dot tool +#--------------------------------------------------------------------------- +HAVE_DOT = YES +CLASS_GRAPH = YES +COLLABORATION_GRAPH = YES +INCLUDE_GRAPH = YES +INCLUDED_BY_GRAPH = YES +GRAPHICAL_HIERARCHY = YES +DOT_PATH = +MAX_DOT_GRAPH_WIDTH = 1024 +MAX_DOT_GRAPH_HEIGHT = 1024 +GENERATE_LEGEND = YES +DOT_CLEANUP = YES +#--------------------------------------------------------------------------- +# Configuration::addtions related to the search engine +#--------------------------------------------------------------------------- +SEARCHENGINE = NO +CGI_NAME = search.cgi +CGI_URL = +DOC_URL = +DOC_ABSPATH = +BIN_ABSPATH = /usr/local/bin/ +EXT_DOC_PATHS = + +#--------------------------------------------------------------------------- +# Include file, at the bottom to over-ride anything I missed. +#--------------------------------------------------------------------------- +@INCLUDE = ./Doxygen_files/genConf diff --git a/Doxygen_files/gendoxfunctions b/Doxygen_files/gendoxfunctions new file mode 100644 index 00000000..fd48dd85 --- /dev/null +++ b/Doxygen_files/gendoxfunctions @@ -0,0 +1,421 @@ +#!/bin/bash +# Functions for the gendox script +# +# Gef, Aug 2001 + +#------------------------------------------------------------------------ +# Set the doxygen output language from the system locale +#------------------------------------------------------------------------ +get_language() { + if [ -n "$LANG" ] ; then + local LANG=`locale | grep LANG | cut -d= -f2`; + fi + case "$LANG" in + czech) + OUPUTLANGUAGE="Czech"; + ;; + german) + OUPUTLANGUAGE="German"; + ;; + spanish) + OUPUTLANGUAGE="Spanish"; + ;; + finnish) + OUPUTLANGUAGE="Finnish"; + ;; + french) + OUPUTLANGUAGE="French"; + ;; + italian) + OUPUTLANGUAGE="Italian"; + ;; + japanese*) + OUPUTLANGUAGE="Japanese"; + ;; + dutch) + OUPUTLANGUAGE="Dutch"; + ;; + swedish) + OUPUTLANGUAGE="Swedish"; + ;; + *) + OUPUTLANGUAGE="English"; + ;; + esac +} + +#------------------------------------------------------------------------ +# Output usage info & output help +#------------------------------------------------------------------------ +output_usage() { + echo -e "Usage: $0 [] [-o ]"; + return; +} + +output_help() { + output_usage; + echo -e "\nOptions:"; + echo -e " []"; + echo -e " This is an optional parameter that specifies the directory, or multiple"; + echo -e " directories from which to generate the documentation."; + echo -e ""; + echo -e " [-o ]"; + echo -e " An optional parameter that specifies the output directory in which"; + echo -e " to save the generated documentation."; + echo -e ""; + echo -e " -q or --quiet"; + echo -e " Prevents the output of status information" + echo -e "" + echo -e " --help, or -h"; + echo -e " Displays this information"; + echo -e "" + echo -e " -q or --quiet"; + echo -e " Prevents the output of status information" + echo -e "" + echo -e " -k or --kill"; + echo -e " kills running doxygen pids." + echo -e "" + echo -e "* Further information on using this script, can be found in README.doxygen"; + echo -e "* in the current directory."; + +} + +#------------------------------------------------------------------------ +# Set the target to what was passed on the command line +#------------------------------------------------------------------------ +parse_commandline() { + # todo: + # need to add the ability to check for an auto gen'd version + # used for automatically generating new documentation for each commit + # to the cvs server + + # funky bash shell array + declare -a OPTLIST[$#]; + + if [ $OPTCOUNT == 0 ] ; then + # No options on the command line so set the target list to the core + TARGETCOUNT=0; + OUTPUTDIR="../$(basename `pwd`)-doxygen"; + else + # put all the command line options into an array + for f in $COMLINE ; do + OPTLIST[$COUNTER]="$f"; + let COUNTER++; + done + + for (( COUNTER=0 ; $COUNTER < $OPTCOUNT; $[COUNTER++] )) ; do + if [ "${OPTLIST[$COUNTER]}" == "--help" ] ; then + # output usage information + output_help; + RETVAL=1; + return; + elif [ "${OPTLIST[$COUNTER]}" == "-h" ] ; then + # output usage information + output_help; + RETVAL=1; + return; + fi + + case ${OPTLIST[$COUNTER]} in + -q) + QUIETMODE=1; + ;; + --quiet) + QUIETMODE=1; + ;; + -k) + KILLON=1; + ;; + --kill) + KILLON=1; + ;; + -o) + # look for the -o switch, and get the next command line option as the output dir + if [ -z ${OPTLIST[$COUNTER + 1]} ] ; then + [ $QUIETMODE -gt 0 ] || echo -e " ** Output switch used, but no output dir passed..."; + [ $QUIETMODE -gt 0 ] || echo -e " ** Setting default output dir."; + else + let COUNTER++; + OUTPUTDIR=${OPTLIST[$COUNTER]}; + fi + break; + ;; + **) + # If the command line option is anything other that -o then assume it's a target + # Check to make sure the target exists first... + if [ -d ${OPTLIST[$COUNTER]} ] ; then + TARGETLIST[$COUNTER]=${OPTLIST[$COUNTER]}; + else + output_usage; + echo -e " ** Error: Non-existent directory specified as a target.\nExiting."; + RETVAL=1; + return; + fi + let TARGETCOUNT++; + ;; + esac + done + + fi # if [ $OPTCOUNT == 0 ] ; + + if [ $TARGETCOUNT == 0 ] ; then + TARGETCOUNT=4; + TARGETLIST[0]="include"; + TARGETLIST[1]="libs"; + TARGETLIST[2]="radiant"; + TARGETLIST[3]="plugins"; + # Gef: outputdir for default core when no targets are passed on the command line + # TTimo problem still there, if -o used on command line, don't override + if [ -z $OUTPUTDIR ] ; then + OUTPUTDIR="../$(basename `pwd`)-doxygen"; + fi + fi + + # Add trailing slash's to the lines that need them + TARGETSTRING=`echo ${TARGETLIST[*]} | sed -e 's/" "/", "/'` + [ $QUIETMODE -gt 0 ] || echo -ne " -> Set Input to: "; + for (( COUNTER=0; COUNTER < $TARGETCOUNT ; $[COUNTER++] )) ; do + if [ $COUNTER == $[TARGETCOUNT - 1] ] ; then + [ $QUIETMODE -gt 0 ] || echo -ne "${TARGETLIST[$COUNTER]}\n"; + TARGETLIST[$COUNTER]="${TARGETLIST[$COUNTER]}"; + else + [ $QUIETMODE -gt 0 ] || echo -ne "${TARGETLIST[$COUNTER]}, "; + TARGETLIST[$COUNTER]="${TARGETLIST[$COUNTER]} \\"; + fi + done + [ $QUIETMODE -gt 0 ] || echo -e " -> Set Output Dir to: $OUTPUTDIR"; + return; +} + +#------------------------------------------------------------------------ +# Try to extract the version number +# todo: find a better way to determine the version +#------------------------------------------------------------------------ +get_version() { + VERSION=`grep PROJECT_NUMBER $DOXYCONFIG | grep -v \# | cut -d= -f2`; + if [ -z $VERSION ] ; then + if [ -f "./include/version.default" ] ; then # checks that we are in the right dir + VERSION=`cat ./include/version.default`; + else + VERSION="(Unknown)"; + fi + fi + return; +} + +#------------------------------------------------------------------------ +# Create a projectname from the tree name +#------------------------------------------------------------------------ +get_projectname() { + PROJECTNAME=`grep PROJECT_NAME $DOXYCONFIG | grep -v \# | cut -d= -f2`; + if [ -z $PROJECTNAME ] ; then + # PROJECTNAME=`echo $TARGET | sed -e s/[^A-Za-z0-9]/!/ | cut -d! -f1`; + PROJECTNAME="$(basename `pwd`)"; + fi + return; +} + +#------------------------------------------------------------------------ +# function to determine the path to the perl executable +#------------------------------------------------------------------------ +get_perlpath() { + if [ -f "$DOXYCONFIG" ] ; then + PERLPATH=`grep PERL_PATH $DOXYCONFIG | grep = | cut -d= -f2` + fi + + if [ 'basename $PERLPATH &2>/dev/null' != "perl" ] ; then + PERLPATH=`which perl 2>/dev/null | sed -e 's/perl//'`; + elif [ 'basename $PERLPATH &2>/dev/null' != "perl" ] ; then + PERLPATH=""; + fi + return; +} + +#------------------------------------------------------------------------ +# Function to determine the path to the dot executable +#------------------------------------------------------------------------ +get_dotpath() { + if [ -f "$DOXYCONFIG" ] ; then + DOTPATH=`grep DOT_PATH $DOXYCONFIG | grep = | cut -d= -f2` + fi + + if [ -z $DOTPATH ] || [ `basename $DOTPATH 2>/dev/null` != "dot" ] ; then + DOTPATH=`which dot 2>/dev/null`; + fi + + if [ -z $DOTPATH ] || [ `basename $DOTPATH 2>/dev/null` != "dot" ] ; then + DOTPATH=""; + HAVEDOT="No"; + echo -e "** Warning: dot not found."; + [ $QUIETMODE -gt 0 ] || echo -e "** dot is part of the GraphVis package and is used to generate"; + [ $QUIETMODE -gt 0 ] || echo -e "** dependancy/inheritance/include (etc) diagrams."; + [ $QUIETMODE -gt 0 ] || echo -e "** It's suggested that you install the GraphVis package for those"; + [ $QUIETMODE -gt 0 ] || echo -e "** features."; + [ $QUIETMODE -gt 0 ] || echo -e "** GraphVis can be downloaded from www.graphvis.org"; + else + HAVEDOT="Yes"; + DOTPATH=`echo $DOTPATH | sed -e 's/dot//'`; + fi + + return; +} + +#------------------------------------------------------------------------ +# Function to move stuff around +#------------------------------------------------------------------------ +# eg: move the images into the output directory & the reference doc into the +# html directory. +# called after doxygen has finished generating documentation +move_stuff() { + [ $QUIETMODE -gt 0 ] || echo -ne " -> Move stuff.\n"; + if [ ! -d $OUTPUTDIR ] ; then + mkdir $OUTPUTDIR; + fi + + if [ ! -d "$EXTRAS_PATH/images/" ] ; then + [ $QUIETMODE -gt 0 ] || echo -e " - Looking for images."; + [ $QUIETMODE -gt 0 ] || sleep 2; + [ $QUIETMODE -gt 0 ] || echo -e " - I can't find the images..."; + [ $QUIETMODE -gt 0 ] || sleep 1; + [ $QUIETMODE -gt 0 ] || echo -e " - Where did you put the images!?"; + [ $QUIETMODE -gt 0 ] || sleep 2; + [ $QUIETMODE -gt 0 ] || echo -e " - They have to be here somewhere..."; + [ $QUIETMODE -gt 0 ] || sleep 1; + [ $QUIETMODE -gt 0 ] || echo -e " - Looking in /dev/null"; + [ $QUIETMODE -gt 0 ] || sleep 3; + [ $QUIETMODE -gt 0 ] || echo -e " - YOU FOOL, YOU DELETED THE IMAGES!!!"; + [ $QUIETMODE -gt 0 ] || sleep 1; + [ $QUIETMODE -gt 0 ] || echo -e " - I quit!"; + RETVAL=666; + else + if [ ! -d $OUTPUTDIR/images ] ; then + mkdir $OUTPUTDIR/images ; + fi + cp $EXTRAS_PATH/images/* $OUTPUTDIR/images/ ; + RETVAL=0; + fi + return; +} + +#------------------------------------------------------------------------ +# clean_up() removes old versions of the documentation +#------------------------------------------------------------------------ +clean_up() { + if [ -f $OUTPUTDIR/html/index.html ] ; then + [ $QUIETMODE -gt 0 ] || echo -e " -> Trashing old dox."; + rm -f $OUTPUTDIR/html/* + fi + return; +} + +#------------------------------------------------------------------------ +# Create a new genConf & Doxyfile +#------------------------------------------------------------------------ +gen_doxyconfig() { + [ $QUIETMODE -gt 0 ] || echo -e " -> Generating DoxyConfig."; + RETVAL=0; + # first need to make sure there is a Doxyfile here + if [ ! -f $DOXYFILE ] ; then + # what now? (could generate one with 'doxygen -e Doxyfile') but it would be screwed. + echo -e "No Doxyfile here..."; + RETVAL=3; + return; + else + # Create a new doxyfile with the @INCLUDE statement including the generated stuff + echo "`cat $DOXYFILE | grep -v @INCLUDE`" > $NEWDOXYFILE + echo "@INCLUDE = $CONFIG_OUTPUT" >> $NEWDOXYFILE + fi + + # remove the old config file + rm -f $CONFIG_OUTPUT + + # create a new one + touch $CONFIG_OUTPUT + echo "# Generated configuration - Do Not Edit." >> $CONFIG_OUTPUT; + echo "# If you want to modify options, edit DoxyConfig and re-run genconf." >> $CONFIG_OUTPUT; + echo -e "\n" >> $CONFIG_OUTPUT; + echo -e "PROJECT_NAME=$PROJECTNAME" >> $CONFIG_OUTPUT; + echo -e "PROJECT_NUMBER=$VERSION" >> $CONFIG_OUTPUT; + echo -e "PERL_PATH=$PERLPATH" >> $CONFIG_OUTPUT; + echo -e "HAVE_DOT=$HAVEDOT" >> $CONFIG_OUTPUT; + echo -e "DOT_PATH=$DOTPATH" >> $CONFIG_OUTPUT; + echo -e "OUTPUT_LANGUAGE=$OUTPUTLANGUAGE" >> $CONFIG_OUTPUT; + + echo -n "INPUT=" >> $CONFIG_OUTPUT; + for (( COUNTER=0 ; COUNTER < $TARGETCOUNT; $[COUNTER++] )) ; do + # echo -e "${TARGETLIST[$COUNTER]}"; + echo -e "${TARGETLIST[$COUNTER]}" >> $CONFIG_OUTPUT + done + # echo -e "INPUT=$TARGET" >> $CONFIG_OUTPUT; + + echo -e "OUTPUT_DIRECTORY=$OUTPUTDIR" >> $CONFIG_OUTPUT; + echo -e "\n" >> $CONFIG_OUTPUT; + return; +} + +#------------------------------------------------------------------------ +# Build the reference page & index +#------------------------------------------------------------------------ +build_extra_html() { + # file locations + REF_OUT="$OUTPUTDIR/reference/index.html" + INDEX_OUT="$OUTPUTDIR/index.html" + + # Make the output directory if it doesn't exist + if [ ! -d $OUTPUTDIR/reference/ ] ; then + [ $QUIETMODE -gt 0 ] || echo -e " -> Making reference directory"; + mkdir $OUTPUTDIR/reference + fi + + # cat the files together and output the result to each file + [ $QUIETMODE -gt 0 ] || echo -e " -> Building reference document"; + cat $EXTRAS_PATH/doxygen_reference_head.html $EXTRAS_PATH/reference1.html $EXTRAS_PATH/doxygen_reference_foot.html > $REF_OUT; + + if [ ! -d $OUTPUTDIR/example/ ] ; then + [ $QUIETMODE -gt 0 ] || echo -e " -> Making example dir"; + mkdir $OUTPUTDIR/example + fi + [ $QUIETMODE -gt 0 ] || echo -e " -> Moving example docs"; + cp $EXTRAS_PATH/example/* $OUTPUTDIR/example/ + cp $EXTRAS_PATH/doxygen_gtkradiant.css $OUTPUTDIR/example/ + + # Make a redirecting index.html + cat $EXTRAS_PATH/doxygen_index.html > $INDEX_OUT; + return; +} + +#------------------------------------------------------------------------ +# Execute doxygen +#------------------------------------------------------------------------ +run_doxygen() { + # copy doxy_mainpage.h to the target directory + # pipe it through sed to add generation time/date and username - $machine + TEMPLOCATION=`echo $TARGETSTRING | cut -d' ' -f1`; + if [ X"$USERNAME" == "X" ] ; then + USERNAME=`whoami`; + fi + MACHINE=`uname -n`; # `uname -n` or `hostname` ?? + cp $EXTRAS_PATH/doxy_mainpage.h temp.h + cat temp.h | + sed "s/+project+/$PROJECTNAME/" | + sed "s|+target+|$TARGETSTRING|" | + sed "s/+user+/$USERNAME/" | + sed "s/+machine+/$MACHINE/" | + sed "s/+date+/$(date '+%b %d %Y')/" > $TEMPLOCATION/doxy_mainpage.h ; + + rm -f temp.h + + # Start doxygen with the command "doxygen $DOXYFILE" + [ $QUIETMODE -gt 0 ] || echo -e " -> Executing doxygen."; + [ $QUIETMODE -gt 0 ] || echo -e "> doxygen $NEWDOXYFILE"; + doxygen $NEWDOXYFILE + RETVAL=$? + + # remove doxy_mainpage.h from the target directory + rm -f $TEMPLOCATION/doxy_mainpage.h + return; +} + +#------------------------------------------------------------------------ +# End. + diff --git a/Doxygen_files/images/body-left-tile.gif b/Doxygen_files/images/body-left-tile.gif new file mode 100644 index 00000000..676dda0a Binary files /dev/null and b/Doxygen_files/images/body-left-tile.gif differ diff --git a/Doxygen_files/images/body-lower-left.gif b/Doxygen_files/images/body-lower-left.gif new file mode 100644 index 00000000..e22fcecd Binary files /dev/null and b/Doxygen_files/images/body-lower-left.gif differ diff --git a/Doxygen_files/images/body-lower-right.gif b/Doxygen_files/images/body-lower-right.gif new file mode 100644 index 00000000..b9d1f992 Binary files /dev/null and b/Doxygen_files/images/body-lower-right.gif differ diff --git a/Doxygen_files/images/body-lower-tile.gif b/Doxygen_files/images/body-lower-tile.gif new file mode 100644 index 00000000..f9bfad72 Binary files /dev/null and b/Doxygen_files/images/body-lower-tile.gif differ diff --git a/Doxygen_files/images/body-right-tile.gif b/Doxygen_files/images/body-right-tile.gif new file mode 100644 index 00000000..576d7a1a Binary files /dev/null and b/Doxygen_files/images/body-right-tile.gif differ diff --git a/Doxygen_files/images/body-upper-left.gif b/Doxygen_files/images/body-upper-left.gif new file mode 100644 index 00000000..e8e433bd Binary files /dev/null and b/Doxygen_files/images/body-upper-left.gif differ diff --git a/Doxygen_files/images/body-upper-right.gif b/Doxygen_files/images/body-upper-right.gif new file mode 100644 index 00000000..af29319f Binary files /dev/null and b/Doxygen_files/images/body-upper-right.gif differ diff --git a/Doxygen_files/images/body-upper-tile.gif b/Doxygen_files/images/body-upper-tile.gif new file mode 100644 index 00000000..89e8c660 Binary files /dev/null and b/Doxygen_files/images/body-upper-tile.gif differ diff --git a/Doxygen_files/images/gtkr_splash.jpg b/Doxygen_files/images/gtkr_splash.jpg new file mode 100644 index 00000000..ebf3a2db Binary files /dev/null and b/Doxygen_files/images/gtkr_splash.jpg differ diff --git a/Doxygen_files/images/gtkr_splash_sm.jpg b/Doxygen_files/images/gtkr_splash_sm.jpg new file mode 100644 index 00000000..2f1f3cc5 Binary files /dev/null and b/Doxygen_files/images/gtkr_splash_sm.jpg differ diff --git a/Doxygen_files/images/history_id_logo.gif b/Doxygen_files/images/history_id_logo.gif new file mode 100644 index 00000000..117f9be1 Binary files /dev/null and b/Doxygen_files/images/history_id_logo.gif differ diff --git a/Doxygen_files/images/top-right.gif b/Doxygen_files/images/top-right.gif new file mode 100644 index 00000000..0cf8a660 Binary files /dev/null and b/Doxygen_files/images/top-right.gif differ diff --git a/Doxygen_files/images/top-tile.gif b/Doxygen_files/images/top-tile.gif new file mode 100644 index 00000000..0c6d3b2f Binary files /dev/null and b/Doxygen_files/images/top-tile.gif differ diff --git a/Doxygen_files/images/top-title.gif b/Doxygen_files/images/top-title.gif new file mode 100644 index 00000000..b4460064 Binary files /dev/null and b/Doxygen_files/images/top-title.gif differ diff --git a/Doxygen_files/reference1.html b/Doxygen_files/reference1.html new file mode 100644 index 00000000..51cff17d --- /dev/null +++ b/Doxygen_files/reference1.html @@ -0,0 +1,333 @@ +
+ + +
+GtkRadiant Doxygen Documentation + + +

Doxygen Quick Reference

+
+

+ +

Index

+
    +
  1. Commenting styles
  2. +
  3. Qt Style C++ Class Example
  4. +
  5. JavaDoc Style C++ Class Example
  6. +
  7. Special Tags
  8. +
  9. Structural Tags
  10. +
+

+ +
+ +

1. Commenting Styles

+There are two different styles of commenting that doxygen recognises. +

+Qt Style:
+ +/*!
+ .... text ....
+*/
+
+
+Qt Style Single line
+ +//! .... one line of text ....
+
+

+ +

+JavaDoc Style:
+ +/**
+ * .... text ....
+ */
+
+
+JavaDoc Style Single line
+ +/// .... one line of text ....
+
+

+ +

+ Doxygen only allows one brief and one detailed description for each declaration/definition. + If there is a brief description before a declaration, and one before the a definition, only + the one before the declaration will be used. If the same situation occurs for a detailed + description the one before the definition is preferred and the one before the declaration will + be ignored.
+ A useful method is to have the brief documentation with the declaration in the header file, + and the detailed documentation with the definition in the source file. +

+ Note: Standard C/C++ comments are ignored by doxygen, but will be included in the code listing + for that file. +

+

+

top

+
+ + +

2. Qt Style C++ Class Example

+

+ Here is an example of a C++ class using Qt Style documentation.
+ The IEpair class from include/iepairs.h is used here. The html result of using these comments + can be found here.
+

+ Note: The resulting html was generated from a single file. If it were generated as part of + the whole documentation, many of the function names and variables would be hyperlinks to + their definitions.
+

+
+//! Virtual class to allow plugin operations on entity pairs
+/*!
+  \todo Write more complete documentation for this class so that it's use
+  is clear
+			
+  An interface to entity keys and key pairs that allows plugins to;
+  read and write entity keys and key values, get a key value as a
+  vec3_t
+*/
+class IEpair
+{
+  public:
+    //! Increment the number of references to this object
+    virtual void IncRef () = 0;
+				
+    //! Decrement the reference count
+    virtual void DecRef () = 0;
+				
+    //! Get a vector from a key
+    virtual void GetVectorForKey( char* key, vec3_t vec ) = 0;
+				
+    //! Get a float from a key
+    virtual float FloatForKey( char *key ) = 0;
+				
+    //! Get a string (char *) from a key
+    virtual char* ValueForKey( char *key ) = 0;
+				
+    //! Set a key value to char *value
+    /*!
+      \param key The (char *) containing the keyname
+      \param value The (char *) to set the key value to
+    */
+    virtual void SetKeyValue( char *key, char *value ) = 0;
+				
+    //! Get a vec3_t for the entities origin
+    virtual void GetEntityOrigin( vec3_t vec ) = 0;
+				
+    //! Compute the rotated bounds of the BBox based on "angle" and "angles" keys
+    virtual void CalculateRotatedBounds( vec3_t mins, vec3_t maxs ) = 0;
+};
+
+

+

+

top

+ +

3. JavaDoc Style C++ Class Example

+ + The same class documented using JavaDoc Style comments +
+/// Virtual class to allow plugin operations on entity pairs
+/**
+  * @todo Write more complete documentation for this class so that it's use
+  * is clear
+  *	
+  * An interface to entity keys and key pairs that allows plugins to;
+  * read and write entity keys and key values, get a key value as a
+  * vec3_t
+  */
+class IEpair
+{
+  public:
+    /// Increment the number of references to this object
+    virtual void IncRef () = 0;
+				
+    /// Decrement the reference count
+    virtual void DecRef () = 0;
+				
+    /// Get a vector from a key
+    virtual void GetVectorForKey( char* key, vec3_t vec ) = 0;
+				
+    /// Get a float from a key
+    virtual float FloatForKey( char *key ) = 0;
+				
+    /// Get a string (char *) from a key
+    virtual char* ValueForKey( char *key ) = 0;
+				
+    /** Set a key value to char *value
+      * @param key The (char *) containing the keyname
+      * @param value The (char *) to set the key value to
+      */
+    virtual void SetKeyValue( char *key, char *value ) = 0;
+				
+    //! Get a vec3_t for the entities origin
+    virtual void GetEntityOrigin( vec3_t vec ) = 0;
+				
+    //! Compute the rotated bounds of the BBox based on "angle" and "angles" keys
+    virtual void CalculateRotatedBounds( vec3_t mins, vec3_t maxs ) = 0;
+};
+
+

+

top

+
+ + +

4. Special Tags

+

+ Special tags using the Qt style begin with a " \ ", or using JavaDoc style a " @ " (the two should not be mixed).
+
+ Common special tags
+

+ + + +
+ author + + The author or a list of comma separated authors/contributers +
+ see + + A reference to another class, class member, function, etc... +
+ param + + A description of a specific function argument or parameter +
+ return + + A description of the value returned from a function/method +
+ bug + + Starts a paragraph where one or more bugs may be listed. +
+ note + + Starts a paragraph where a note may be entered. +
+ todo + + Starts a paragraph where a TODO item is described.
+ Note: All TODO items are collated into a separate todo list, each linking to each other +
+ version + + Starts a paragraph where one or more version strings may be entered. +
+ warning + + Starts a paragraph where one or more warning messages may be entered. +
+ brief + + A single line comment in place of the //! or /// comment. +
+
+
+

top

+
+ +

5. Structural Tags

+

+These are used to document a named object, and are not required to be located near that +object definition or declaration. This allows the documentation for an object to be located +anywhere in the doxygen input files. The exception to this rule however, is that these +documentation blocks cannot be within the body of a function or within C style comment blocks. +All structural commands are preceded by either a " \ " or a " @ ", depending on the +documentation style, and require one or more parameters to specify the name of the object +the description is referring to.
+

+

+An example of the \file structural tag: +

+/*! \file iepairs.h
+    \brief One line documentation for this file
+    \author Author(s)
+    Long description of this file
+*/
+
+

+ +Common Structural Tags

+
+ + + +
+ class + + Documents a class
+ eg:
+ /*! \class IEpair
+ \brief Short description of the IEpair class
+
+ Detailed description of the IEpair class
+ */
+
+
+
+ def + + Describes a #define
+ eg:
+ /*! \def MAX_VALUE The name of the define
+ \brief Description of MAX_VALUE
+ */
+
+
+
+ file + + Describes a file
+ eg:
+ /*! \file iepairs.h The name of the file
+ \brief Description of the file iepairs.h
+
+ Details
+ */
+
+
+
+ struct + + Documents a struct
+ eg:
+ /*! \struct BTListList_t the name of the struct
+ \brief Description of BTListList_t
+
+ Details
+ */
+
+
+
+ var + + Documents a typedef, variable or enum value
+ eg:
+ /*! \var typedef unsigned int UINT32
+ \brief Short description
+ */
+
+
+
+ fn + + Documents a function + eg:
+ /*! \fn virtual void IEpair::DecRef() = 0;
+ \brief Short description of this function
+
+ Detailed description of this function
+ */
+
+ +
+
+ +
+

top

+
+
+
diff --git a/GPL b/GPL new file mode 100644 index 00000000..2128a66e --- /dev/null +++ b/GPL @@ -0,0 +1,280 @@ + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/GtkRadiant.prj b/GtkRadiant.prj new file mode 100644 index 00000000..c2af2961 --- /dev/null +++ b/GtkRadiant.prj @@ -0,0 +1,688 @@ +# Anjuta Version 1.1.97 +Compatibility Level: 1 + + +level editor for Id technology games + + + + + + + + + + + + + + + + + + +props.file.type=project + +anjuta.version=1.1.97 +anjuta.compatibility.level=1 + +project.name=GtkRadiant +project.type=GENERIC +project.target.type=EXECUTABLE +project.version=changesallthetime +project.author=qeradiant.com dev team +project.source.target=install/radiant.x86 +project.has.gettext=0 +project.gui.command= +project.programming.language=C_C++ +project.excluded.modules= intl + +project.config.extra.modules.before= +project.config.extra.modules.after= +project.config.blocked=1 +project.config.disable.overwriting=1 1 1 1 1 1 1 1 1 + +project.menu.entry=GtkRadiant Version changesallthetime +project.menu.group=Application +project.menu.comment=GtkRadiant Version changesallthetime +project.menu.icon= +project.menu.need.terminal=0 + +project.configure.options= +anjuta.program.arguments= +cons.linkeddir= + +preferences.build.option.jobs=0 +preferences.build.option.silent=0 +preferences.build.option.autosave=1 +preferences.make=scons +preferences.build.option.keep.going=1 +preferences.build.option.warn.undef=0 +preferences.autoformat.custom.style= -i8 -sc -bli0 -bl0 -cbi0 -ss +preferences.autoformat.style=Style of Kangleipak +preferences.indent.opening=0 +preferences.autoformat.disable=0 +preferences.indent.automatic=1 +preferences.use.tabs=0 +preferences.indent.size=2 +preferences.tabsize=2 +preferences.indent.closing=0 + +module.include.name=. +module.include.type= +module.include.files=\ + Doxygen_files/doxy_mainpage.h\ + contrib/bobtoolz/CPortals.h\ + contrib/bobtoolz/DBobView.h\ + contrib/bobtoolz/DBrush.h\ + contrib/bobtoolz/DEPair.h\ + contrib/bobtoolz/DEntity.h\ + contrib/bobtoolz/DListener.h\ + contrib/bobtoolz/DMap.h\ + contrib/bobtoolz/DPatch.h\ + contrib/bobtoolz/DPlane.h\ + contrib/bobtoolz/DPoint.h\ + contrib/bobtoolz/DShape.h\ + contrib/bobtoolz/DVisDrawer.h\ + contrib/bobtoolz/DWinding.h\ + contrib/bobtoolz/StdAfx.h\ + contrib/bobtoolz/bobToolz.h\ + contrib/bobtoolz/bsploader.h\ + contrib/bobtoolz/ctfresource_gtk.h\ + contrib/bobtoolz/funchandlers.h\ + contrib/bobtoolz/lists.h\ + contrib/bobtoolz/misc.h\ + contrib/bobtoolz/resource-gtk.h\ + contrib/bobtoolz/resource.h\ + contrib/bobtoolz/shapes.h\ + contrib/bobtoolz/visfind.h\ + contrib/bobtoolz/dialogs/AboutDialog.h\ + contrib/bobtoolz/dialogs/AutoCaulkDialog.h\ + contrib/bobtoolz/dialogs/AutoCaulkStartDialog.h\ + contrib/bobtoolz/dialogs/BrushCheckDialog.h\ + contrib/bobtoolz/dialogs/DoorDialog.h\ + contrib/bobtoolz/dialogs/IntersectDialog.h\ + contrib/bobtoolz/dialogs/IntersectInfoDialog.h\ + contrib/bobtoolz/dialogs/PolygonDialog.h\ + contrib/bobtoolz/dialogs/StairDialog.h\ + contrib/bobtoolz/dialogs/TextureResetDialog.h\ + contrib/bobtoolz/dialogs/dialogs-gtk.h\ + contrib/bobtoolz/dialogs/pathplotterdialog.h\ + contrib/gtkgensurf/gendlgs.h\ + contrib/gtkgensurf/gensurf.h\ + contrib/gtkgensurf/triangle.h\ + contrib/patches/Gtk/fileselect/linux/gtkfilesel-01222001.h\ + contrib/prtview/AboutDialog.h\ + contrib/prtview/ConfigDialog.h\ + contrib/prtview/LoadPortalFileDialog.h\ + contrib/prtview/gtkdlgs.h\ + contrib/prtview/portals.h\ + contrib/prtview/prtview.h\ + contrib/prtview/resource.h\ + contrib/prtview/stdafx.h\ + docs/developer/XMLPush/StdAfx.h\ + include/gtkr_list.h\ + include/gtkr_vector.h\ + include/ibrush.h\ + include/ibspfrontend.h\ + include/idata.h\ + include/idatastream.h\ + include/ientity.h\ + include/iepairs.h\ + include/ifilesystem.h\ + include/igl.h\ + include/iimage.h\ + include/imap.h\ + include/imodel.h\ + include/ipatch.h\ + include/ipluginentities.h\ + include/irefcount.h\ + include/iscriplib.h\ + include/iselectedface.h\ + include/ishaders.h\ + include/ishadersmanager.h\ + include/isurfaceplugin.h\ + include/iui.h\ + include/iui_gtk.h\ + include/qerplugin.h\ + include/qertypes.h\ + include/qsysprintf.h\ + include/stl_check.h\ + include/stream_version.h\ + libs/bytebool.h\ + libs/cmdlib.h\ + libs/jpeglib.h\ + libs/mathlib.h\ + libs/missing.h\ + libs/multimon.h\ + libs/pakstuff.h\ + libs/str.h\ + libs/synapse.h\ + libs/jpeg6/jchuff.h\ + libs/jpeg6/jconfig.h\ + libs/jpeg6/jdct.h\ + libs/jpeg6/jdhuff.h\ + libs/jpeg6/jerror.h\ + libs/jpeg6/jinclude.h\ + libs/jpeg6/jmemsys.h\ + libs/jpeg6/jmorecfg.h\ + libs/jpeg6/jpegint.h\ + libs/jpeg6/jversion.h\ + libs/l_net/l_net.h\ + libs/l_net/l_net_wins.h\ + libs/pak/unzip.h\ + plugins/image/bmp.h\ + plugins/image/image.h\ + plugins/image/lbmlib.h\ + plugins/mapq3/plugin.h\ + plugins/mapxml/plugin.h\ + plugins/md3model/entitymodel.h\ + plugins/md3model/md3.h\ + plugins/md3model/md3model.h\ + plugins/md3model/md3surface.h\ + plugins/md3model/plugin.h\ + plugins/md3model/surface.h\ + plugins/sample/stdafx.h\ + plugins/sample/str.h\ + plugins/shaders/plugin.h\ + plugins/shaders/shaders.h\ + plugins/surface/plugtexdef.h\ + plugins/surface/surfdlg.h\ + plugins/surface/surfplug.h\ + plugins/textool/2DView.h\ + plugins/textool/ControlPointsManager.h\ + plugins/textool/StdAfx.h\ + plugins/textool/resource.h\ + plugins/vfspak/vfs.h\ + plugins/vfspak/vfspak.h\ + plugins/vfspk3/unzip-vfspk3.h\ + plugins/vfspk3/vfs.h\ + plugins/vfspk3/vfspk3.h\ + radiant/brush.h\ + radiant/camera.h\ + radiant/camwindow.h\ + radiant/dialog.h\ + radiant/entity.h\ + radiant/epairswrapper.h\ + radiant/feedback.h\ + radiant/file.h\ + radiant/filters.h\ + radiant/findtexturedialog.h\ + radiant/glwidget.h\ + radiant/glwindow.h\ + radiant/groupdialog.h\ + radiant/gtkfilesel-darwin.h\ + radiant/gtkfilesel-linux.h\ + radiant/gtkfilesel.h\ + radiant/gtkmisc.h\ + radiant/mainframe.h\ + radiant/map.h\ + radiant/parse.h\ + radiant/patchdialog.h\ + radiant/plugin.h\ + radiant/pluginmanager.h\ + radiant/points.h\ + radiant/preferences.h\ + radiant/qe3.h\ + radiant/qedefs.h\ + radiant/qfiles.h\ + radiant/qgl.h\ + radiant/resource.h\ + radiant/select.h\ + radiant/stdafx.h\ + radiant/surfacedialog.h\ + radiant/texmanip.h\ + radiant/textures.h\ + radiant/texwindow.h\ + radiant/ui.h\ + radiant/undo.h\ + radiant/watchbsp.h\ + radiant/winding.h\ + radiant/xmlstuff.h\ + radiant/xywindow.h\ + radiant/z.h\ + radiant/zwindow.h\ + tools/quake3/common/aselib.h\ + tools/quake3/common/bspfile.h\ + tools/quake3/common/cmdlib.h\ + tools/quake3/common/imagelib.h\ + tools/quake3/common/inout.h\ + tools/quake3/common/l3dslib.h\ + tools/quake3/common/mutex.h\ + tools/quake3/common/polylib.h\ + tools/quake3/common/polyset.h\ + tools/quake3/common/qfiles.h\ + tools/quake3/common/qthreads.h\ + tools/quake3/common/scriplib.h\ + tools/quake3/common/surfaceflags.h\ + tools/quake3/common/trilib.h\ + tools/quake3/common/unzip.h\ + tools/quake3/common/vfs.h\ + tools/quake3/q3data/3dslib.h\ + tools/quake3/q3data/md3lib.h\ + tools/quake3/q3data/p3dlib.h\ + tools/quake3/q3data/q3data.h\ + tools/quake3/q3map/Heapagnt.h\ + tools/quake3/q3map/game_t.h\ + tools/quake3/q3map/light.h\ + tools/quake3/q3map/mesh.h\ + tools/quake3/q3map/qbsp.h\ + tools/quake3/q3map/shaders.h\ + tools/quake3/q3map/vis.h + +module.source.name=. +module.source.type= +module.source.files=\ + contrib/bobtoolz/DBobView.cpp\ + contrib/bobtoolz/DBrush.cpp\ + contrib/bobtoolz/DEPair.cpp\ + contrib/bobtoolz/DEntity.cpp\ + contrib/bobtoolz/DListener.cpp\ + contrib/bobtoolz/DMap.cpp\ + contrib/bobtoolz/DPatch.cpp\ + contrib/bobtoolz/DPlane.cpp\ + contrib/bobtoolz/DPoint.cpp\ + contrib/bobtoolz/DShape.cpp\ + contrib/bobtoolz/DVisDrawer.cpp\ + contrib/bobtoolz/DWinding.cpp\ + contrib/bobtoolz/StdAfx.cpp\ + contrib/bobtoolz/bobToolz-GTK.cpp\ + contrib/bobtoolz/bobToolz.cpp\ + contrib/bobtoolz/bsploader.cpp\ + contrib/bobtoolz/cportals.cpp\ + contrib/bobtoolz/ctfToolz-GTK.cpp\ + contrib/bobtoolz/funchandlers-GTK.cpp\ + contrib/bobtoolz/funchandlers-ctf-GTK.cpp\ + contrib/bobtoolz/funchandlers.cpp\ + contrib/bobtoolz/lists.cpp\ + contrib/bobtoolz/misc.cpp\ + contrib/bobtoolz/shapes.cpp\ + contrib/bobtoolz/visfind.cpp\ + contrib/bobtoolz/dialogs/AboutDialog.cpp\ + contrib/bobtoolz/dialogs/AutoCaulkDialog.cpp\ + contrib/bobtoolz/dialogs/AutoCaulkStartDialog.cpp\ + contrib/bobtoolz/dialogs/DoorDialog.cpp\ + contrib/bobtoolz/dialogs/IntersectDialog.cpp\ + contrib/bobtoolz/dialogs/IntersectInfoDialog.cpp\ + contrib/bobtoolz/dialogs/PolygonDialog.cpp\ + contrib/bobtoolz/dialogs/StairDialog.cpp\ + contrib/bobtoolz/dialogs/TextureResetDialog.cpp\ + contrib/bobtoolz/dialogs/brushcheckdialog.cpp\ + contrib/bobtoolz/dialogs/dialogs-gtk.cpp\ + contrib/bobtoolz/dialogs/pathplotterdialog.cpp\ + contrib/gtkgensurf/bitmap.cpp\ + contrib/gtkgensurf/dec.cpp\ + contrib/gtkgensurf/face.cpp\ + contrib/gtkgensurf/font.cpp\ + contrib/gtkgensurf/gendlgs.cpp\ + contrib/gtkgensurf/genmap.cpp\ + contrib/gtkgensurf/gensurf.cpp\ + contrib/gtkgensurf/heretic.cpp\ + contrib/gtkgensurf/plugin.cpp\ + contrib/gtkgensurf/triangle.c\ + contrib/gtkgensurf/view.cpp\ + contrib/patches/Gtk/fileselect/linux/gtkfilesel-01222001.c\ + contrib/prtview/AboutDialog.cpp\ + contrib/prtview/ConfigDialog.cpp\ + contrib/prtview/LoadPortalFileDialog.cpp\ + contrib/prtview/gtkdlgs.cpp\ + contrib/prtview/portals.cpp\ + contrib/prtview/prtview.cpp\ + contrib/prtview/stdafx.cpp\ + docs/developer/XMLPush/StdAfx.cpp\ + docs/developer/XMLPush/XMLPush.cpp\ + docs/manual/quake3/Compile_Manual/cfgq3.c\ + libs/cmdlib/cmdlib.cpp\ + libs/jpeg6/jcomapi.cpp\ + libs/jpeg6/jdapimin.cpp\ + libs/jpeg6/jdapistd.cpp\ + libs/jpeg6/jdatasrc.cpp\ + libs/jpeg6/jdcoefct.cpp\ + libs/jpeg6/jdcolor.cpp\ + libs/jpeg6/jddctmgr.cpp\ + libs/jpeg6/jdhuff.cpp\ + libs/jpeg6/jdinput.cpp\ + libs/jpeg6/jdmainct.cpp\ + libs/jpeg6/jdmarker.cpp\ + libs/jpeg6/jdmaster.cpp\ + libs/jpeg6/jdpostct.cpp\ + libs/jpeg6/jdsample.cpp\ + libs/jpeg6/jdtrans.cpp\ + libs/jpeg6/jerror.cpp\ + libs/jpeg6/jfdctflt.cpp\ + libs/jpeg6/jidctflt.cpp\ + libs/jpeg6/jmemmgr.cpp\ + libs/jpeg6/jmemnobs.cpp\ + libs/jpeg6/jpgload.cpp\ + libs/jpeg6/jutils.cpp\ + libs/l_net/l_net.c\ + libs/l_net/l_net_berkley.c\ + libs/l_net/l_net_wins.c\ + libs/mathlib/bbox.c\ + libs/mathlib/linear.c\ + libs/mathlib/m4x4.c\ + libs/mathlib/mathlib.c\ + libs/mathlib/ray.c\ + libs/pak/pakstuff.cpp\ + libs/pak/unzip.cpp\ + libs/synapse/synapse.cpp\ + plugins/image/bmp.cpp\ + plugins/image/image.cpp\ + plugins/image/jpeg.cpp\ + plugins/image/lbmlib.cpp\ + plugins/mapq3/parse.cpp\ + plugins/mapq3/plugin.cpp\ + plugins/mapq3/write.cpp\ + plugins/mapxml/plugin.cpp\ + plugins/mapxml/xmlparse.cpp\ + plugins/mapxml/xmlwrite.cpp\ + plugins/md3model/eclassmodel.cpp\ + plugins/md3model/entitymodel.cpp\ + plugins/md3model/md3model.cpp\ + plugins/md3model/md3surface.cpp\ + plugins/md3model/miscmodel.cpp\ + plugins/md3model/plugin.cpp\ + plugins/sample/sample.cpp\ + plugins/sample/stdafx.cpp\ + plugins/shaders/plugin.cpp\ + plugins/shaders/shaders.cpp\ + plugins/surface/plugtexdef.cpp\ + plugins/surface/surfdlg.cpp\ + plugins/surface/surfplug.cpp\ + plugins/textool/2DView.cpp\ + plugins/textool/ControlPointsManager.cpp\ + plugins/textool/StdAfx.cpp\ + plugins/textool/TexTool.cpp\ + plugins/vfspak/vfs.cpp\ + plugins/vfspak/vfspak.cpp\ + plugins/vfspk3/unzip.cpp\ + plugins/vfspk3/vfs.cpp\ + plugins/vfspk3/vfspk3.cpp\ + radiant/bp_dlg.cpp\ + radiant/brush.cpp\ + radiant/brush_primit.cpp\ + radiant/brushscript.cpp\ + radiant/camwindow.cpp\ + radiant/csg.cpp\ + radiant/dialog.cpp\ + radiant/dialoginfo.cpp\ + radiant/drag.cpp\ + radiant/eclass.cpp\ + radiant/entity.cpp\ + radiant/feedback.cpp\ + radiant/file.cpp\ + radiant/filters.cpp\ + radiant/findtexturedialog.cpp\ + radiant/glinterface.cpp\ + radiant/glwidget.cpp\ + radiant/glwindow.cpp\ + radiant/groupdialog.cpp\ + radiant/gtkdlgs.cpp\ + radiant/gtkfilesel-darwin.c\ + radiant/gtkfilesel-linux.c\ + radiant/gtkfilesel.c\ + radiant/gtkmisc.cpp\ + radiant/iepairs.cpp\ + radiant/main.cpp\ + radiant/mainframe.cpp\ + radiant/map.cpp\ + radiant/missing.cpp\ + radiant/parse.cpp\ + radiant/patchdialog.cpp\ + radiant/plugin.cpp\ + radiant/pluginentities.cpp\ + radiant/pluginmanager.cpp\ + radiant/pmesh.cpp\ + radiant/points.cpp\ + radiant/preferences.cpp\ + radiant/profile.cpp\ + radiant/qe3.cpp\ + radiant/qgl-mac.c\ + radiant/qgl.c\ + radiant/queuedraw.cpp\ + radiant/select.cpp\ + radiant/selectedface.cpp\ + radiant/stdafx.cpp\ + radiant/surfacedialog.cpp\ + radiant/surfaceplugin.cpp\ + radiant/texmanip.cpp\ + radiant/texwindow.cpp\ + radiant/ui.cpp\ + radiant/undo.cpp\ + radiant/vertsel.cpp\ + radiant/watchbsp.cpp\ + radiant/winding.cpp\ + radiant/xywindow.cpp\ + radiant/z.cpp\ + radiant/zwindow.cpp\ + tools/quake3/common/aselib.c\ + tools/quake3/common/bspfile.c\ + tools/quake3/common/cmdlib.c\ + tools/quake3/common/imagelib.c\ + tools/quake3/common/inout.c\ + tools/quake3/common/l3dslib.c\ + tools/quake3/common/md4.c\ + tools/quake3/common/mutex.c\ + tools/quake3/common/polylib.c\ + tools/quake3/common/scriplib.c\ + tools/quake3/common/threads.c\ + tools/quake3/common/trilib.c\ + tools/quake3/common/unzip.c\ + tools/quake3/common/vfs.c\ + tools/quake3/q3data/3dslib.c\ + tools/quake3/q3data/compress.c\ + tools/quake3/q3data/images.c\ + tools/quake3/q3data/md3lib.c\ + tools/quake3/q3data/models.c\ + tools/quake3/q3data/oldstuff.c\ + tools/quake3/q3data/p3dlib.c\ + tools/quake3/q3data/polyset.c\ + tools/quake3/q3data/q3data.c\ + tools/quake3/q3data/stripper.c\ + tools/quake3/q3data/video.c\ + tools/quake3/q3map/NetConnect/main.c\ + tools/quake3/q3map/brush.c\ + tools/quake3/q3map/brush_primit.c\ + tools/quake3/q3map/bsp.c\ + tools/quake3/q3map/facebsp.c\ + tools/quake3/q3map/fog.c\ + tools/quake3/q3map/gldraw.c\ + tools/quake3/q3map/glfile.c\ + tools/quake3/q3map/leakfile.c\ + tools/quake3/q3map/light.c\ + tools/quake3/q3map/light_bounce.c\ + tools/quake3/q3map/light_trace.c\ + tools/quake3/q3map/lightmaps.c\ + tools/quake3/q3map/lightv.c\ + tools/quake3/q3map/map.c\ + tools/quake3/q3map/mesh.c\ + tools/quake3/q3map/misc_model.c\ + tools/quake3/q3map/nodraw.c\ + tools/quake3/q3map/patch.c\ + tools/quake3/q3map/path_init.c\ + tools/quake3/q3map/portals.c\ + tools/quake3/q3map/prtfile.c\ + tools/quake3/q3map/shaders.c\ + tools/quake3/q3map/surface.c\ + tools/quake3/q3map/terrain.c\ + tools/quake3/q3map/tjunction.c\ + tools/quake3/q3map/tree.c\ + tools/quake3/q3map/vis.c\ + tools/quake3/q3map/visflow.c\ + tools/quake3/q3map/writebsp.c\ + tools/quake3/q3map/NetTest/main.c + +module.pixmap.name=. +module.pixmap.type= +module.pixmap.files=\ + Doxygen_files/example/doxygen.gif\ + Doxygen_files/example/graph_legend.gif\ + Doxygen_files/images/body-left-tile.gif\ + Doxygen_files/images/body-lower-left.gif\ + Doxygen_files/images/body-lower-right.gif\ + Doxygen_files/images/body-lower-tile.gif\ + Doxygen_files/images/body-right-tile.gif\ + Doxygen_files/images/body-upper-left.gif\ + Doxygen_files/images/body-upper-right.gif\ + Doxygen_files/images/body-upper-tile.gif\ + Doxygen_files/images/gtkr_splash.jpg\ + Doxygen_files/images/gtkr_splash_sm.jpg\ + Doxygen_files/images/history_id_logo.gif\ + Doxygen_files/images/top-right.gif\ + Doxygen_files/images/top-tile.gif\ + Doxygen_files/images/top-title.gif\ + contrib/patches/Gtk/fileselect/back.xpm\ + contrib/patches/Gtk/fileselect/forward.xpm\ + contrib/patches/Gtk/fileselect/refresh.xpm\ + contrib/patches/Gtk/fileselect/up.xpm\ + docs/developer/Inspector/classdiagram1.gif\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image002.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image003.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image004.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image006.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image008.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image010.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image012.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image014.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image016.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image018.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image020.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image022.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image024.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image026.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image028.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image030.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image032.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image034.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image035.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image038.png\ + docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image040.png\ + docs/manual/quake3/Q3AShader_Manual/q3ashader_manual_files/image002.jpg\ + docs/manual/quake3/Team_Arena_Mapping_Help/pics/CRUSADER.gif\ + docs/manual/quake3/Team_Arena_Mapping_Help/pics/INTRUDER.gif\ + docs/manual/quake3/Team_Arena_Mapping_Help/pics/MAINPOP.gif\ + docs/manual/quake3/Team_Arena_Mapping_Help/pics/MENUBACKgif.gif\ + docs/manual/quake3/Team_Arena_Mapping_Help/pics/PAGANs.gif\ + docs/manual/quake3/Team_Arena_Mapping_Help/pics/STROGGS.gif\ + docs/manual/quake3/Team_Arena_Mapping_Help/pics/THEFALLEN.gif\ + docs/manual/quake3/Team_Arena_Mapping_Help/pics/logo.gif\ + docs/manual/quake3/Terrain_Manual/pages/Image3.gif\ + docs/manual/quake3/Terrain_Manual/pages/Image4.gif\ + docs/manual/quake3/Terrain_Manual/pages/Image5.gif\ + docs/manual/quake3/Terrain_Manual/pages/Image6.gif\ + docs/manual/quake3/Terrain_Manual/pics/background.jpg\ + docs/manual/quake3/Terrain_Manual/pics/start.gif\ + docs/manual/quake3/Terrain_Manual/pics/terrain.jpg\ + plugins/textool/Doc/Image2.jpg\ + setup/linux/Help/DocsArt/toolback.jpg\ + setup/linux/radiant.xpm\ + setup/linux/setup.data/splash.xpm + +module.data.name=. +module.data.type= +module.data.files= + +module.help.name=. +module.help.type= +module.help.files= + +module.doc.name=. +module.doc.type= +module.doc.files=\ + INSTALL\ + README\ + Doxygen_files/example/annotated.html\ + Doxygen_files/example/classIEpair-members.html\ + Doxygen_files/example/classIEpair.html\ + Doxygen_files/example/classes.html\ + Doxygen_files/example/files.html\ + Doxygen_files/example/functions.html\ + Doxygen_files/example/graph_legend.html\ + Doxygen_files/example/index.html\ + Doxygen_files/example/pages.html\ + Doxygen_files/example/test_8c-source.html\ + Doxygen_files/example/test_8c.html\ + Doxygen_files/example/todo.html\ + Doxygen_files/doxygen_gtkradiant_foot.html\ + Doxygen_files/doxygen_gtkradiant_head.html\ + Doxygen_files/doxygen_index.html\ + Doxygen_files/doxygen_reference_foot.html\ + Doxygen_files/doxygen_reference_head.html\ + Doxygen_files/reference1.html\ + contrib/patches/Gtk/fileselect/README\ + docs/developer/TODO\ + docs/manual/quake3/Compile_Manual/index.html\ + docs/manual/quake3/Compile_Manual/q3map.html\ + docs/manual/quake3/New_Teams_For_Q3TA/index.html\ + docs/manual/quake3/Q3AShader_Manual/appendix/appA.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/pages/design_tips.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/pages/map_converters_checklist.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/pages/preface.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/pages/related_links.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/pages/ta_game_types.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_arena_entity_definitions.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_arena_prefabs.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_powerup_bases.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/pages/using_new_game_entities.html\ + docs/manual/quake3/Team_Arena_Mapping_Help/start.html\ + docs/manual/quake3/Terrain_Manual/pages/adding_bots.html\ + docs/manual/quake3/Terrain_Manual/pages/adding_buildings_to_terrain.html\ + docs/manual/quake3/Terrain_Manual/pages/art_tools.html\ + docs/manual/quake3/Terrain_Manual/pages/blocking_vis.html\ + docs/manual/quake3/Terrain_Manual/pages/boxing_in_the_world.html\ + docs/manual/quake3/Terrain_Manual/pages/clipping_the_terrain.html\ + docs/manual/quake3/Terrain_Manual/pages/creating_the_alphamap.html\ + docs/manual/quake3/Terrain_Manual/pages/creating_the_terrain.html\ + docs/manual/quake3/Terrain_Manual/pages/entity_keys_and_values.html\ + docs/manual/quake3/Terrain_Manual/pages/glossary.html\ + docs/manual/quake3/Terrain_Manual/pages/height_map_into_terrain_mesh.html\ + docs/manual/quake3/Terrain_Manual/pages/height_maps.html\ + docs/manual/quake3/Terrain_Manual/pages/introduction.html\ + docs/manual/quake3/Terrain_Manual/pages/key_changes.html\ + docs/manual/quake3/Terrain_Manual/pages/lighting_the_terrain.html\ + docs/manual/quake3/Terrain_Manual/pages/manipulating_the_terrain_mesh.html\ + docs/manual/quake3/Terrain_Manual/pages/mapping_the_textures.html\ + docs/manual/quake3/Terrain_Manual/pages/new_or_revised_q3map_shader_comm.html\ + docs/manual/quake3/Terrain_Manual/pages/other_possible_height_map_tools.html\ + docs/manual/quake3/Terrain_Manual/pages/related_links.html\ + docs/manual/quake3/Terrain_Manual/pages/suggested_gensurf_settings.html\ + docs/manual/quake3/Terrain_Manual/pages/table_of_contents.html\ + docs/manual/quake3/Terrain_Manual/pages/terrain_entity.html\ + docs/manual/quake3/Terrain_Manual/pages/terrain_mesh_into_terrain_entity.html\ + docs/manual/quake3/Terrain_Manual/pages/terrain_related_worldspawn_features.html\ + docs/manual/quake3/Terrain_Manual/pages/terrain_texture.html\ + docs/manual/quake3/Terrain_Manual/pages/the_meta_shader.html\ + docs/manual/quake3/Terrain_Manual/start.html\ + plugins/textool/Doc/TexTool.html\ + setup/PluginSDK/README.html\ + setup/PluginSDK/TODO\ + setup/data/tools/credits.html\ + setup/linux/Help/Index.html\ + setup/win32/TODO\ + www/coding.html\ + www/files.html\ + www/gtkradiant.html\ + www/hosted.html\ + www/index.html\ + www/reviews.html + +module.po.files= + +compiler.options.supports= +compiler.options.include.paths=\ + .\ + .. +compiler.options.library.paths= +compiler.options.libraries= +compiler.options.libraries.selected= +compiler.options.defines=\ + HAVE_CONFIG_H +compiler.options.defines.selected= +compiler.options.warning.buttons=0 0 1 1 0 1 0 0 0 0 0 0 0 1 0 0 +compiler.options.optimize.buttons=0 0 1 0 +compiler.options.other.buttons=1 0 +compiler.options.other.c.flags= +compiler.options.other.l.flags= +compiler.options.other.l.libs= + +project.src.paths= diff --git a/INSTALL.txt b/INSTALL.txt new file mode 100644 index 00000000..022a6510 --- /dev/null +++ b/INSTALL.txt @@ -0,0 +1,7 @@ +Compilation instructions +------------------------ + +See latest information for compiling and installation +on the developer pages: + +http://www.qeradiant.com/wikifaq/index.php?GtkRadiant%20Hacker diff --git a/LGPL b/LGPL new file mode 100644 index 00000000..f95d0f63 --- /dev/null +++ b/LGPL @@ -0,0 +1,458 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..e8d70b6f --- /dev/null +++ b/LICENSE @@ -0,0 +1,36 @@ +LICENSE ( last update: Wed Feb 8 17:16:40 CST 2006 ) +----------------------------------------------------- + +There are 3 license types used throughout GtkRadiant source code. + +BSD - modified Berkeley Software Distribution license +( each BSD licensed source file starts with the appropriate header ) +LGPL - GNU Lesser General Public License v2.1 +( see LGPL at the root of the tree ) +GPL - GNU General Public License +( see GPL at the root of the tree ) + +How do I check which license applies to a given part of the source code? + +Each source file in the tree comes with a license header which explains what +license applies. To sum up shortly: + +GPL: ( except some files contributed by Loki Software under BSD license ) +GtkRadiant Core +GtkRadiant Modules +GtkRadiant Libraries +Quake III Tools +Quake II Tools +Background2D Plugin +HydraToolz Plugin + +BSD: +JPEG Library +MD5 Library +DDS Library +PicoModel Library +PrtView Plugin + +LGPL +BobToolz Plugin +GenSurf Plugin diff --git a/LICENSE_ID b/LICENSE_ID new file mode 100644 index 00000000..e69de29b diff --git a/README b/README new file mode 100644 index 00000000..c0370749 --- /dev/null +++ b/README @@ -0,0 +1,49 @@ +Terms and Conditions of Use + + +------- + +GTKRadiant contains software developed by Id Software, Loki Software and third +party contributors. + +All portions of GTKRadiant which are licensed by Id Software are subject to the +terms of its LIMITED USE SOFTWARE LICENSE AGREEMENT, a copy of which is included +with GTKRadiant. If you did not receive a LIMITED USE SOFTWARE LICENSE +AGREEMENT, please contact Id Software immediately at info@idsoftware.com. + +All portions of GTKRadiant which have been developed by Loki Software and/or +third party contributors are licensed under the terms set forth below. + +------- + +Copyright (c) 1999-2000, Loki Software, Inc. +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 Loki Software nor the names of its contributors may be used +to endorse or promote products derived from this software without specific prior +written permission. No license is hereby granted to any trademarks, tradenames +or logos. + +THIS SOFTWARE IS PROVIDED BY LOKI AND THE CONTRIBUTORS "AS IS." ANY AND ALL +WARRANTUES, EXPRESS OR IMPLIED, INCLUDING, WITHOUT LIMITATION, ANY IMPLIED +WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRENGEMENT ARE HEREBY DISCLAIMED. IN NO EVENT SHALL LOKI OR THE +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, +OR CONSEQUENTIAL DAMAGES (INCLUDING, WITHOUT LIMITATION, 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. + +------- diff --git a/README.doxygen b/README.doxygen new file mode 100644 index 00000000..effbf3f4 --- /dev/null +++ b/README.doxygen @@ -0,0 +1,51 @@ + Documentation for generating doxygen documentation +--------------------------------------------------------- + +1. Options for gendox +More up-to-date command line options are available via +the command ./gendox --help + +usage: "sh gendox [ ] [ -o ]" + or "./gendox [ ] [ -o ]" + + + The directory, or directories to generate the + documentation from. + +-o + Specifies the output directory which + should follow the -o switch + +-q --quiet + Stops the script from outputing status information, + other than errors. + +-k --kill + Kills other running doxygen pids. + +eg: ./gendox include/ -o ../Documentation + +* This will produce documentation for the include files, +and output to the directory specified one level above the +current directory. + +The target can be the current directory "./" in which case +doxygen will generate documentation for all subdirectories +of the current directory recursively. + +The default output directory is currently ... +> ../GtkRadiant-doxygen + +* If the script is called without any target directories +it will generate documentation for the core of radiant... +include/ libs/ radiant/ and plugins/ + +If there are specific options that you'd like to customise, +the DoxyConfig file is used to generate the file from which +doxygen gets its settings from. So any changes that need +to be made should be made to this file. + + +Gef :] +(gefdavis@dingoblue.net.au) +--------------------------------------------------------- diff --git a/SConscript b/SConscript new file mode 100644 index 00000000..aa055778 --- /dev/null +++ b/SConscript @@ -0,0 +1,839 @@ +import os, sys, commands, string +from makeversion import get_version +# OS Detection: +OS = commands.getoutput('uname') + +Import('GLOBALS') +Import(GLOBALS) + +# make scons link shared libs against static libs +g_env['STATIC_AND_SHARED_OBJECTS_ARE_THE_SAME'] = 1 + +# make gcc accept default parameters in function typedefs +g_env['CXXFLAGS'] += '-fpermissive ' + +g_env['CXXFLAGS'] += '-fPIC ' +g_env['CCFLAGS'] += '-fPIC ' + +def build_list(s_prefix, s_string): + s_list = Split(s_string) + for i in range(len(s_list)): + s_list[i] = s_prefix + '/' + s_list[i] + return s_list + +# common code ------------------------------------------------------ + +cmdlib_lib = g_env.StaticLibrary(target='libs/cmdlib', source='libs/cmdlib/cmdlib.cpp') + + +mathlib_src = 'mathlib.c bbox.c linear.c m4x4.c ray.c' +mathlib_lib = g_env.StaticLibrary(target='libs/mathlib', source=build_list('libs/mathlib', mathlib_src)) + + +md5lib_lib = g_env.StaticLibrary(target='libs/md5lib', source='libs/md5lib/md5lib.c') + + +ddslib_lib = g_env.StaticLibrary(target='libs/ddslib', source='libs/ddslib/ddslib.c') + + +jpeg_env = g_env.Copy() +jpeg_env.Prepend(CPPPATH = 'libs/jpeg6') +jpeg_src = 'jcomapi.cpp jdcoefct.cpp jdinput.cpp jdpostct.cpp jfdctflt.cpp jpgload.cpp jdapimin.cpp jdcolor.cpp jdmainct.cpp jdsample.cpp jidctflt.cpp jutils.cpp jdapistd.cpp jddctmgr.cpp jdmarker.cpp jdtrans.cpp jmemmgr.cpp jdatasrc.cpp jdhuff.cpp jdmaster.cpp jerror.cpp jmemnobs.cpp' +jpeg_lib = jpeg_env.StaticLibrary(target='libs/jpeg', source=build_list('libs/jpeg6', jpeg_src)) + + +net_lib = g_env.StaticLibrary(target='libs/l_net', source=['libs/l_net/l_net.c', 'libs/l_net/l_net_berkley.c']) + + +picomodel_src = 'picointernal.c picomodel.c picomodules.c pm_3ds.c pm_ase.c pm_md3.c pm_obj.c\ + pm_ms3d.c pm_mdc.c pm_fm.c pm_md2.c pm_lwo.c lwo/clip.c lwo/envelope.c lwo/list.c lwo/lwio.c\ + lwo/lwo2.c lwo/lwob.c lwo/pntspols.c lwo/surface.c lwo/vecmath.c lwo/vmap.c' +picomodel_lib = g_env.StaticLibrary(target='libs/picomodel', source=build_list('libs/picomodel', picomodel_src)) + + +synapse_env = g_env.Copy() +synapse_env.useGlib2() +synapse_env.useXML2() +synapse_env['CPPPATH'].append('include') +synapse_src = 'synapse.cpp' +synapse_lib = synapse_env.StaticLibrary(target='libs/synapse', source=build_list('libs/synapse', synapse_src)) +# scons 0.95. Doesn't recognize archive compatible for dynamic modules +# see thread: http://scons.tigris.org/servlets/BrowseList?listName=users&by=thread&from=168952&to=168952&first=1&count=2 + + +splines_env = g_env.Copy() +splines_src = build_list('libs/splines', +'math_angles.cpp math_matrix.cpp math_quaternion.cpp math_vector.cpp q_parse.cpp q_shared.cpp splines.cpp util_str.cpp') +splines_env['CPPPATH'].append('include') +splines_lib = splines_env.StaticLibrary(target='libs/splines', source=splines_src) + + +# end static / common libraries --------------------------------------------------- + +# q3map --------------------------------------------------------------------------- + +q3map_env = g_env.Copy() +q3map_env['CPPPATH'].append('include') +q3map_env.useXML2() +q3map_env.useGlib2() +q3map_env.usePNG() +q3map_env.usePThread() +q3map_env.Prepend(CPPPATH='tools/quake3/common') + +q3map_common_src = [ + 'common/cmdlib.c', + 'common/imagelib.c', + 'common/inout.c', + 'common/mutex.c', + 'common/polylib.c', + 'common/scriplib.c', + 'common/threads.c', + 'common/unzip.c', + 'common/vfs.c' ] + +q3map_src = [ + 'q3map2/brush.c', + 'q3map2/brush_primit.c', + 'q3map2/bsp.c', + 'q3map2/facebsp.c', + 'q3map2/fog.c', + 'q3map2/leakfile.c', + 'q3map2/map.c', + 'q3map2/model.c', + 'q3map2/patch.c', + 'q3map2/portals.c', + 'q3map2/prtfile.c', + 'q3map2/surface.c', + 'q3map2/surface_fur.c', + 'q3map2/surface_meta.c', + 'q3map2/tjunction.c', + 'q3map2/tree.c', + 'q3map2/writebsp.c', + 'q3map2/image.c', + 'q3map2/light.c', + 'q3map2/light_bounce.c', + 'q3map2/light_trace.c', + 'q3map2/light_ydnar.c', + 'q3map2/lightmaps_ydnar.c', + 'q3map2/vis.c', + 'q3map2/visflow.c', + 'q3map2/bspfile_abstract.c', + 'q3map2/bspfile_ibsp.c', + 'q3map2/bspfile_rbsp.c', + 'q3map2/decals.c', + 'q3map2/main.c', + 'q3map2/mesh.c', + 'q3map2/path_init.c', + 'q3map2/shaders.c', + 'q3map2/surface_extra.c', + 'q3map2/surface_foliage.c', + 'q3map2/convert_ase.c', + 'q3map2/convert_map.c' ] + +q3map_full_src = [ ] +for i in q3map_common_src + q3map_src: + q3map_full_src.append('tools/quake3/' + i) + +q3map_full_src.append('libs/libmathlib.a') +q3map_full_src.append('libs/libl_net.a') +q3map_full_src.append('libs/libjpeg.a') +q3map_full_src.append('libs/libpicomodel.a') +q3map_full_src.append('libs/libmd5lib.a') +q3map_full_src.append('libs/libddslib.a') + +q3map_env.Program(target='q3map2.' + g_cpu, source=q3map_full_src ) +q3map_env.Install(INSTALL, 'q3map2.' + g_cpu) + +# end q3map2 ---------------------------------------------------------------------- + +# q3data --------------------------------------------------------------------------- + +q3data_env = q3map_env.Copy() + +q3data_common_src = [ + 'common/aselib.c', + 'common/bspfile.c', + 'common/cmdlib.c', + 'common/imagelib.c', + 'common/inout.c', + 'common/scriplib.c', + 'common/trilib.c', + 'common/unzip.c', + 'common/vfs.c' + ] + +q3data_src = [ + 'q3data/3dslib.c', + 'q3data/compress.c', + 'q3data/images.c', + 'q3data/md3lib.c', + 'q3data/models.c', + 'q3data/p3dlib.c', + 'q3data/polyset.c', + 'q3data/q3data.c', + 'q3data/stripper.c', + 'q3data/video.c' ] + +q3data_full_src = [ ] +for i in q3data_common_src + q3data_src: + q3data_full_src.append('tools/quake3/' + i) + +q3data_full_src.append('libs/libmathlib.a') +q3data_full_src.append('libs/libl_net.a') + +q3data_env.Program( target = 'q3data.' + g_cpu, source = q3data_full_src ) +q3data_env.Install( INSTALL, 'q3data.' + g_cpu ) + +# end q3data ---------------------------------------------------------------------- + +# q2_tools --------------------------------------------------------------------------- + +q2_tools_env = g_env.Copy() +q2_tools_env['CPPPATH'].append('include') +q2_tools_env.useXML2() +q2_tools_env.usePThread() +q2_tools_env.Prepend(CPPPATH='tools/quake2/common') + +q2_tools_common_src = [ + 'common/bspfile.c', + 'common/cmdlib.c', + 'common/inout.c', + 'common/l3dslib.c', + 'common/lbmlib.c', + 'common/mathlib.c', + 'common/path_init.c', + 'common/polylib.c', + 'common/scriplib.c', + 'common/threads.c', + 'common/trilib.c' +] + + +q2_tools_q2map_src = [ + 'q2map/brushbsp.c', + 'q2map/csg.c', + 'q2map/faces.c', + 'q2map/flow.c', + 'q2map/glfile.c', + 'q2map/leakfile.c', + 'q2map/lightmap.c', + 'q2map/main.c', + 'q2map/map.c', + 'q2map/nodraw.c', + 'q2map/patches.c', + 'q2map/portals.c', + 'q2map/prtfile.c', + 'q2map/qbsp.c', + 'q2map/qrad.c', + 'q2map/qvis.c', + 'q2map/textures.c', + 'q2map/trace.c', + 'q2map/tree.c', + 'q2map/writebsp.c' +] + +q2_tools_qdata3_common_src = [ + 'common/bspfile.c', + 'common/cmdlib.c', + 'common/inout.c', + 'common/l3dslib.c', + 'common/lbmlib.c', + 'common/mathlib.c', + 'common/path_init.c', + 'common/scriplib.c', + 'common/threads.c', + 'common/trilib.c' +] + +q2_tools_qdata3_src = [ + 'qdata/images.c', + 'qdata/models.c', + 'qdata/qdata.c', + 'qdata/sprites.c', + 'qdata/tables.c', + 'qdata/video.c' +] + +q2_tools_q2map_full_src = [ ] +for i in q2_tools_common_src + q2_tools_q2map_src: + q2_tools_q2map_full_src.append('tools/quake2/' + i) + +q2_tools_q2map_full_src.append('libs/libl_net.a') + +q2_tools_qdata3_full_src = [ ] +for i in q2_tools_common_src + q2_tools_qdata3_src: + q2_tools_qdata3_full_src.append('tools/quake2/' + i) + +q2_tools_qdata3_full_src.append('libs/libl_net.a') + +if ( OS != 'Darwin' ): + q2_tools_env.Program(target='quake2_tools/q2map', source=q2_tools_q2map_full_src ) + q2_tools_env.Install(INSTALL + '/q2', 'quake2_tools/q2map' ) + + q2_tools_env.Program(target='quake2_tools/qdata3', source=q2_tools_qdata3_full_src ) + q2_tools_env.Install(INSTALL + '/q2', 'quake2_tools/qdata3' ) + + +# end q2_tools ---------------------------------------------------------------------- + +# qdata3_heretic2 --------------------------------------------------------------------------- + +heretic2_tools_env = g_env.Copy() +heretic2_tools_env['CPPPATH'].append('include') +heretic2_tools_env.useXML2() +heretic2_tools_env.usePThread() +heretic2_tools_env.Prepend(CPPPATH='tools/quake2/qdata_heretic2') +heretic2_tools_env.Prepend(CPPPATH='tools/quake2/qdata_heretic2/qcommon') +heretic2_tools_env.Prepend(CPPPATH='tools/quake2/qdata_heretic2/common') + +heretic2_tools_qdata3_common_src = [ + 'qdata_heretic2/common/bspfile.c', + 'qdata_heretic2/common/cmdlib.c', + 'qdata_heretic2/common/inout.c', + 'qdata_heretic2/common/l3dslib.c', + 'qdata_heretic2/common/lbmlib.c', + 'qdata_heretic2/common/mathlib.c', + 'qdata_heretic2/common/path_init.c', + 'qdata_heretic2/common/qfiles.c', + 'qdata_heretic2/common/scriplib.c', + 'qdata_heretic2/common/threads.c', + 'qdata_heretic2/common/token.c', + 'qdata_heretic2/common/trilib.c' +] + +heretic2_tools_qdata3_qcommon_src = [ + 'qdata_heretic2/qcommon/reference.c', + 'qdata_heretic2/qcommon/resourcemanager.c', + 'qdata_heretic2/qcommon/skeletons.c' +] + +heretic2_tools_qdata3_src = [ + 'qdata_heretic2/animcomp.c', + 'qdata_heretic2/book.c', + 'qdata_heretic2/fmodels.c', + 'qdata_heretic2/images.c', + 'qdata_heretic2/jointed.c', + 'qdata_heretic2/models.c', + 'qdata_heretic2/pics.c', + 'qdata_heretic2/qdata.c', + 'qdata_heretic2/qd_skeletons.c', + 'qdata_heretic2/sprites.c', + 'qdata_heretic2/svdcmp.c', + 'qdata_heretic2/tables.c', + 'qdata_heretic2/tmix.c', + 'qdata_heretic2/video.c' +] + +heretic2_tools_qdata3_full_src = [ ] +for i in heretic2_tools_qdata3_common_src + heretic2_tools_qdata3_qcommon_src + heretic2_tools_qdata3_src: + heretic2_tools_qdata3_full_src.append('tools/quake2/' + i) + +heretic2_tools_qdata3_full_src.append('libs/libl_net.a') + +heretic2_tools_env['CCFLAGS'] += '-D_LINUX ' + +if ( OS != 'Darwin' ): + heretic2_tools_env.Program(target='heretic2_tools/qdata3', source=heretic2_tools_qdata3_full_src ) + heretic2_tools_env.Install(INSTALL + '/heretic2', 'heretic2_tools/qdata3' ) + + heretic2_q2map_env = q2_tools_env + heretic2_q2map_env.Install(INSTALL + '/heretic2', 'quake2_tools/q2map' ) + +# end heretic2_tools ---------------------------------------------------------------------- + + + +# radiant, modules and plugins ---------------------------------------------------- + +module_env = g_env.Copy() +module_env['CPPPATH'].append('include') +if ( OS == 'Darwin' ): + module_env['LINKFLAGS'] += '-dynamiclib -ldl ' +else: + module_env['LINKFLAGS'] += '-ldl ' +module_env['LIBPREFIX'] = '' +module_env.useGlib2() +module_env.useXML2() + +module_env.SharedLibrarySafe(target='fgd', source=['plugins/eclassfgd/plugin.cpp', 'libs/libsynapse.a']) +module_env.Install(INSTALL + '/modules', 'fgd.so') + +vfspk3_lst=build_list('plugins/vfspk3', 'vfspk3.cpp vfs.cpp unzip.cpp') +vfspk3_lst.append('libs/libsynapse.a') +module_env.SharedLibrarySafe(target='vfspk3', source=vfspk3_lst) +module_env.Install(INSTALL + '/modules', 'vfspk3.so') + +vfswad_lst=build_list('plugins/vfswad', 'unwad.cpp vfs.cpp vfswad.cpp') +vfswad_lst.append('libs/libsynapse.a') +module_env.SharedLibrarySafe(target='vfswad', source=vfswad_lst) +module_env.Install(INSTALL + '/modules', 'vfswad.so') + +vfspak_lst=build_list('plugins/vfspak', 'vfspak.cpp vfs.cpp') +vfspak_lst.append('libs/libsynapse.a') +module_env.SharedLibrarySafe(target='vfspak', source=vfspak_lst) +module_env.Install(INSTALL + '/q2/modules', 'vfspak.so') +module_env.Install(INSTALL + '/heretic2/modules', 'vfspak.so') + +shaders_lst=build_list('plugins/shaders', 'shaders.cpp plugin.cpp') +shaders_lst.append('libs/libsynapse.a') +module_env.SharedLibrarySafe(target='shaders', source=shaders_lst) +module_env.Install(INSTALL + '/modules', 'shaders.so') + +image_lst=build_list('plugins/image', 'jpeg.cpp image.cpp lbmlib.cpp') +image_lst.append('libs/libsynapse.a') +image_lst.append('libs/libjpeg.a') +module_env.SharedLibrarySafe(target='image', source=image_lst) +module_env.Install(INSTALL + '/modules', 'image.so') + +imagewal_lst=build_list('plugins/imagewal', 'wal.cpp imagewal.cpp') +imagewal_lst.append('libs/libsynapse.a') +module_env.SharedLibrarySafe(target='imagewal', source=imagewal_lst) +module_env.Install(INSTALL + '/q2/modules', 'imagewal.so') + +imagem8_lst=build_list('plugins/imagem8', 'm8.cpp m32.cpp imagem8.cpp') +imagem8_lst.append('libs/libsynapse.a') +module_env.SharedLibrarySafe(target='imagem8', source=imagem8_lst) +module_env.Install(INSTALL + '/heretic2/modules', 'imagem8.so') + +imagehl_lst=build_list('plugins/imagehl', 'imagehl.cpp lbmlib.cpp') +imagehl_lst.append('libs/libsynapse.a') +module_env.SharedLibrarySafe(target='imagehl', source=imagehl_lst) +module_env.Install(INSTALL + '/modules', 'imagehl.so') + +imagepng_lst=build_list('plugins/imagepng', 'plugin.cpp') +imagepng_lst.append('libs/libsynapse.a') +module_env.usePNG() +module_env.SharedLibrarySafe(target='imagepng', source=imagepng_lst) +module_env.Install(INSTALL + '/modules', 'imagepng.so') + +map_lst=build_list('plugins/map', 'plugin.cpp parse.cpp write.cpp') +map_lst.append('libs/libsynapse.a') +map_lst.append('libs/libcmdlib.a') +module_env.SharedLibrarySafe(target='map', source=map_lst) +module_env.Install(INSTALL + '/modules', 'map.so') + +mapxml_lst=build_list('plugins/mapxml', 'plugin.cpp xmlparse.cpp xmlwrite.cpp') +mapxml_lst.append('libs/libsynapse.a') +module_env.SharedLibrarySafe(target='mapxml', source=mapxml_lst) +module_env.Install(INSTALL + '/modules', 'mapxml.so') + +model_lst=build_list('plugins/model', 'plugin.cpp model.cpp cpicomodel.cpp cpicosurface.cpp remap.cpp') +model_lst.append('libs/libsynapse.a') +model_lst.append('libs/libpicomodel.a') +model_lst.append('libs/libmathlib.a') +module_env.SharedLibrarySafe(target='model', source=model_lst) +module_env.Install(INSTALL + '/modules', 'model.so') + +entity_lst = build_list('plugins/entity', 'plugin.cpp entity_entitymodel.cpp miscmodel.cpp eclassmodel.cpp entity.cpp light.cpp') +entity_lst.append('libs/libsynapse.a') +entity_lst.append('libs/libmathlib.a') +module_env.SharedLibrarySafe(target='entity', source=entity_lst) +module_env.Install(INSTALL + '/modules', 'entity.so') + +bob_env = module_env.Copy() +bob_env.useGtk2() +bob_lst = build_list('contrib/bobtoolz/', +'dialogs/dialogs-gtk.cpp bobToolz-GTK.cpp bsploader.cpp cportals.cpp DBobView.cpp \ +DBrush.cpp DEntity.cpp DEPair.cpp DListener.cpp DMap.cpp DPatch.cpp DPlane.cpp DPoint.cpp \ +DShape.cpp DTrainDrawer.cpp DTreePlanter.cpp DVisDrawer.cpp DWinding.cpp funchandlers-GTK.cpp \ +lists.cpp misc.cpp ScriptParser.cpp shapes.cpp visfind.cpp') +bob_lst.append('libs/libsynapse.a') +bob_lst.append('libs/libmathlib.a') +bob_lst.append('libs/libcmdlib.a') +bob_env['CPPPATH'].append('contrib/bobtoolz/dialogs') +bob_env.SharedLibrarySafe(target='bobtoolz', source=bob_lst) +bob_env.Install(INSTALL + '/plugins', 'bobtoolz.so') + +camera_lst = build_list('contrib/camera', +'camera.cpp dialogs.cpp dialogs_common.cpp funchandlers.cpp listener.cpp misc.cpp renderer.cpp') +camera_lst.append('libs/libsynapse.a') +camera_lst.append('libs/libsplines.a') +bob_env.SharedLibrarySafe(target='camera', source=camera_lst) +bob_env.Install(INSTALL + '/plugins', 'camera.so') + +prtview_lst = build_list('contrib/prtview', +'AboutDialog.cpp ConfigDialog.cpp LoadPortalFileDialog.cpp portals.cpp prtview.cpp') +prtview_lst.append('libs/libsynapse.a') +prtview_env = bob_env.Copy() +prtview_env['CXXFLAGS'] += '-DGTK_PLUGIN ' +prtview_env.SharedLibrarySafe(target='prtview', source=prtview_lst) +prtview_env.Install(INSTALL + '/plugins', 'prtview.so') + +gensurf_lst = build_list('contrib/gtkgensurf', +'bitmap.cpp dec.cpp face.cpp font.cpp gendlgs.cpp genmap.cpp gensurf.cpp heretic.cpp plugin.cpp view.cpp triangle.c') +gensurf_lst.append('libs/libsynapse.a') +bob_env.SharedLibrarySafe(target='gensurf', source=gensurf_lst) +bob_env.Install(INSTALL + '/plugins', 'gensurf.so') + +surface_lst = build_list('plugins/surface', 'surfdlg_plugin.cpp surfacedialog.cpp') +surface_lst.append('libs/libsynapse.a') +surface_lst.append('libs/libmathlib.a') +surface_env = module_env.Copy() +surface_env.useGtk2() +surface_env.SharedLibrarySafe(target='surface', source=surface_lst) +surface_env.Install(INSTALL + '/modules', 'surface.so') + +surface_quake2_lst = build_list('plugins/surface_quake2', 'surfdlg_plugin.cpp surfacedialog.cpp surfaceflagsdialog_quake2.cpp') +surface_quake2_lst.append('libs/libsynapse.a') +surface_quake2_lst.append('libs/libmathlib.a') +surface_quake2_env = module_env.Copy() +surface_quake2_env.useGtk2() +surface_quake2_env.SharedLibrarySafe(target='surface_quake2', source=surface_quake2_lst) +surface_quake2_env.Install(INSTALL + '/q2/modules', 'surface_quake2.so') + +surface_heretic2_lst = build_list('plugins/surface_heretic2', 'surfdlg_plugin.cpp surfacedialog.cpp surfaceflagsdialog_heretic2.cpp') +surface_heretic2_lst.append('libs/libsynapse.a') +surface_heretic2_lst.append('libs/libmathlib.a') +surface_heretic2_env = module_env.Copy() +surface_heretic2_env.useGtk2() +surface_heretic2_env.SharedLibrarySafe(target='surface_heretic2', source=surface_heretic2_lst) +surface_heretic2_env.Install(INSTALL + '/heretic2/modules', 'surface_heretic2.so') + +bkgrnd2d_list = build_list( 'contrib/bkgrnd2d', 'bkgrnd2d.cpp plugin.cpp dialog.cpp' ) +bkgrnd2d_list.append( 'libs/libsynapse.a' ) +bkgrnd2d_env = module_env.Copy() +bkgrnd2d_env.useGtk2() +bkgrnd2d_env.SharedLibrarySafe( target='bkgrnd2d', source=bkgrnd2d_list ) +bkgrnd2d_env.Install( INSTALL + '/plugins', 'bkgrnd2d.so' ) + +radiant_env = g_env.Copy() +radiant_env['CPPPATH'].append('include') +radiant_env['LINKFLAGS'] += '-ldl ' +if ( OS == 'Darwin' ): + radiant_env['CXXFLAGS'] += '-fno-common ' + radiant_env['CCFLAGS'] += '-fno-common ' + radiant_env['LINKFLAGS'] += '-lX11 -lGL -lGLU ' +radiant_env['LIBPREFIX'] = '' +radiant_env.useGlib2() +radiant_env.useXML2() +radiant_env.useGtk2() +radiant_env.useGtkGLExt() + +radiant_src=[ 'qgl.c', 'brush.cpp', 'brush_primit.cpp', 'brushscript.cpp', 'camwindow.cpp', 'csg.cpp', + 'dialog.cpp', 'dialoginfo.cpp', 'drag.cpp', 'eclass.cpp', 'eclass_def.cpp', 'error.cpp', 'feedback.cpp', + 'file.cpp', 'findtexturedialog.cpp', 'glinterface.cpp', 'glwidget.cpp', 'glwindow.cpp', 'groupdialog.cpp', + 'gtkdlgs.cpp', 'gtkmisc.cpp', 'main.cpp', 'mainframe.cpp', 'map.cpp', 'missing.cpp', 'parse.cpp', + 'patchdialog.cpp', 'pluginentities.cpp', 'pluginmanager.cpp', 'pmesh.cpp', 'points.cpp', 'preferences.cpp', + 'profile.cpp', 'qe3.cpp', 'qgl_ext.cpp', 'select.cpp', 'selectedface.cpp', 'surfacedialog.cpp', + 'surfaceplugin.cpp', 'targetname.cpp', 'texmanip.cpp', 'texwindow.cpp', 'undo.cpp', 'vertsel.cpp', + 'watchbsp.cpp', 'winding.cpp', 'xywindow.cpp', 'z.cpp', 'zwindow.cpp', 'filters.cpp', 'bp_dlg.cpp', 'ui.cpp' ] + +for i in range(len(radiant_src)): + radiant_src[i] = 'radiant/' + radiant_src[i] + +radiant_src.append('libs/libmathlib.a') +radiant_src.append('libs/libcmdlib.a') +radiant_src.append('libs/libl_net.a') +radiant_src.append('libs/libsynapse.a') + +radiant_env.Program(target='radiant.' + g_cpu, source=radiant_src) +radiant_env.Install(INSTALL, 'radiant.' + g_cpu) + +# setup ------------------------------------------------------------------------------------------- + +class setup_builder: + + g_dryrun = 0 + + def system(self, cmd): + if (self.g_dryrun): + print cmd + else: + sys.stdout.write(cmd) + ret = commands.getstatusoutput(cmd) + print ret[1] + if (ret[0] != 0): + raise 'command failed' + + def copy_core(self): + # binaries and misc + self.system('mkdir -p %s/modules' % self.SETUP_BIN_DIR) + self.system('mkdir -p %s/plugins' % self.SETUP_BIN_DIR) + self.system('cp install/%s %s' % (self.EDITOR_BIN, self.SETUP_BIN_DIR)) + self.system('cp install/modules/*.so %s/modules' % self.SETUP_BIN_DIR ) + self.system('cp install/plugins/*.so %s/plugins' % self.SETUP_BIN_DIR ) + self.system('cp install/q3map2.%s %s' % ( g_cpu, self.SETUP_BIN_DIR ) ) + self.M4_STDC = '' + if (not self.g_darwin): + # fugly + # copy libgcc_s and stdc++ over to distribute it and reduce potential ABI fuckups + ret = commands.getstatusoutput('ldd -r install/' + self.EDITOR_BIN + ' 2>/dev/null | grep libgcc_s | sed -e \'s/.* => \\([^ ]*\\) .*/\\1/\'') + if (ret[0] != 0): + raise 'ldd command failed' + self.system('cp ' + ret[1] + ' ' + self.SETUP_BIN_DIR) + ret = commands.getstatusoutput('ldd -r install/' + self.EDITOR_BIN + ' 2>/dev/null | grep libstdc++ | sed -e \'s/.* => \\([^ ]*\\) .*/\\1/\'') + if (ret[0] != 0): + raise 'ldd command failed' + lines = string.split(ret[1], '\n') + self.M4_STDC = '"' + for i in lines: + self.system('cp ' + i + ' ' + self.SETUP_BIN_DIR) + self.M4_STDC += os.path.basename(i) + ' \n' + self.M4_STDC += '"' + # hack for symlink + # setup process generates the wrapper at install time + # but we need a dummy executable for symlink in loki_setup + self.system('echo -n "#!/bin/sh\necho If you read this then there was a bug during setup. Report the bug and try running %s directly from it\'s installation directory.\n" > %s/radiant' % (self.EDITOR_BIN, self.SETUP_BIN_DIR)); + self.system('echo -n "#!/bin/sh\necho If you read this then there was a bug during setup. Report the bug and try running %s directly from it\'s installation directory.\n" > %s/q3map2' % (self.EDITOR_BIN, self.SETUP_BIN_DIR)); + ## this goes to the core install directory + DEST = self.SETUP_DIR + '/core' + self.system('mkdir -p ' + DEST + '/modules/bitmaps') + # general content stuff + self.system('cp -R plugins/model/bitmaps/* ' + DEST + '/modules/bitmaps') + self.system('cp -R setup/data/tools/* ' + DEST) + self.system('cp -R radiant/bitmaps ' + DEST) + self.system('cp setup/changelog.txt ' + DEST) + self.system('cp setup/openurl.sh ' + DEST) + self.system('cp tools/quake3/q3map2/changelog.q3map2.txt ' + DEST) + # documentation + self.system('cp -R docs/manual/Q3Rad_Manual ' + DEST) + self.system('cp -R docs/manual/quake3/Compile_Manual ' + DEST) + self.system('cp -R docs/manual/quake3/Model_Manual ' + DEST) + self.system('cp -R docs/manual/quake3/Terrain_Manual ' + DEST) + # copy plugins media + self.system('mkdir -p ' + DEST + '/plugins/bitmaps') + self.system('cp -R contrib/bobtoolz/bitmaps/* ' + DEST + '/plugins/bitmaps') + self.system('cp -R contrib/bobtoolz/bt ' + DEST + '/plugins') + self.system('cp -R contrib/camera/bitmaps/* ' + DEST + '/plugins/bitmaps' ) + self.system('cp -R contrib/bkgrnd2d/bitmaps/* ' + DEST + '/plugins/bitmaps' ) + + def copy_q3(self): + # binaries + self.system('mkdir -p ' + self.SETUP_BIN_DIR + '/q3') + if ( self.g_darwin == 0 ): + self.system('cp setup/linux/bspc ' + self.SETUP_BIN_DIR + '/q3') + + # goes in core + DEST = self.SETUP_DIR + '/core/q3' + self.system('mkdir -p ' + DEST) + self.system('cp setup/data/tools/synapse.config ' + DEST) + self.system('cp setup/data/tools/game.xlink ' + DEST) + self.system('cp -R docs/manual/quake3/Team_Arena_Mapping_Help ' + DEST) + self.system('cp -R docs/manual/quake3/New_Teams_For_Q3TA ' + DEST) + self.system('cp -R docs/manual/quake3/Q3AShader_Manual ' + DEST) + + # goes in the game install path + DEST = self.SETUP_DIR + '/q3' + self.system('mkdir -p ' + DEST) + self.system('cp -R setup/data/baseq3 ' + DEST) + self.system('cp -R setup/data/missionpack ' + DEST) + + def copy_wolf(self): + # binaries + self.system('mkdir -p ' + self.SETUP_BIN_DIR + '/wolf') + if ( self.g_darwin == 0 ): + self.system('cp ../WolfPack/bin/Linux/bspc ' + self.SETUP_BIN_DIR + '/wolf') + + # goes in core + DEST = self.SETUP_DIR + '/core/wolf' + self.system('mkdir -p ' + DEST) + self.system('cp ../WolfPack/synapse.config ' + DEST) + self.system('cp -R ../WolfPack/docs ' + DEST) + self.system('cp ../WolfPack/game.xlink ' + DEST) + self.system('cp ../WolfPack/bin/aascfg_lg.c ' + DEST) + self.system('cp ../WolfPack/bin/aascfg_sm.c ' + DEST) + self.system('cp ../WolfPack/bin/bspc.ai ' + DEST) + + # goes in the game install path + DEST = self.SETUP_DIR + '/wolf/main' + self.system('mkdir -p ' + DEST) + self.system('cp ../WolfPack/astro-skies.pk3 ' + DEST) + self.system('cp ../WolfPack/common-astro-spog.pk3 ' + DEST) + self.system('cp ../WolfPack/lights.pk3 ' + DEST) + self.system('cp -R ../WolfPack/scripts ' + DEST) + self.system('cp -R ../WolfPack/maps ' + DEST) + self.system('cp -R ../WolfPack/models ' + DEST) + + def copy_et(self): + # goes in core + DEST = self.SETUP_DIR + '/core/et' + self.system('mkdir -p ' + DEST) + self.system('cp -R ../ETPack/bitmaps ' + DEST) + self.system('cp -R ../ETPack/docs ' + DEST) + self.system('cp ../ETPack/game.xlink ' + DEST) + self.system('cp ../ETPack/synapse.config ' + DEST) + + # goes in game install path + DEST = self.SETUP_DIR + '/et/etmain' + self.system('mkdir -p ' + DEST) + self.system('cp ../ETPack/astro-skies.pk3 ' + DEST) + self.system('cp ../ETPack/common.pk3 ' + DEST) + self.system('cp ../ETPack/goldrush.pcx ' + DEST) + self.system('cp ../ETPack/lights.pk3 ' + DEST) + self.system('cp ../ETPack/mapmedia.pk3 ' + DEST) + self.system('cp -R ../ETPack/scripts ' + DEST) + self.system('cp -R ../ETPack/maps ' + DEST) + self.system('cp -R ../ETPack/models ' + DEST) + + def copy_q2(self): + # binaries + self.system('cp -R install/q2 %s' % (self.SETUP_BIN_DIR)) + + # goes in core + DEST = self.SETUP_DIR + '/core/q2' + self.system('mkdir -p ' + DEST + '/modules') + self.system('cp ../Q2Pack/game.xlink ' + DEST) + self.system('cp ../Q2Pack/synapse.config ' + DEST) + self.system('cp install/q2/q2map install/q2/qdata3 ' + DEST) + self.system('cp -R install/q2/modules ' + DEST ) + + # goes in game install path + DEST = self.SETUP_DIR + '/q2' + self.system('mkdir -p ' + DEST + '/baseq2') + self.system('cp -R ../Q2Pack/baseq2/* ' + DEST + '/baseq2') + + def copy_her2(self): + # binaries + self.system('cp -R install/heretic2 %s' % (self.SETUP_BIN_DIR)) + + # goes in core + DEST = self.SETUP_DIR + '/core/heretic2' + self.system('mkdir -p ' + DEST + '/modules') + self.system('cp ../Her2Pack/game.xlink ' + DEST) + self.system('cp ../Her2Pack/synapse.config ' + DEST) + self.system('cp install/q2/q2map install/heretic2/qdata3 ' + DEST) + self.system('cp -R install/heretic2/modules ' + DEST ) + + # goes in game install path + DEST = self.SETUP_DIR + '/heretic2' + self.system('mkdir -p ' + DEST + '/base') + self.system('cp -R ../Her2Pack/base/* ' + DEST + '/base') + + def build_setup(self): + self.system( 'cp -R ' + self.SETUP_IMAGE_OS + '/* ' + self.SETUP_DIR ) + self.system( 'cp -fR ' + self.SETUP_IMAGE + '/* ' + self.SETUP_DIR ) + self.system('cp setup/license.txt ' + self.SETUP_DIR) + self.system('cp setup/linux/README ' + self.SETUP_DIR) + OS_DEFS='' + if (self.g_darwin): + OS_DEFS='--define=M4_OSX' + M4_LINE = OS_DEFS + ' --define=M4_VER_MAJOR=' + self.major + ' --define=M4_VER_MINOR=' + self.minor + ' --define=M4_VER=' + self.line + M4_LINE += ' --define=M4_GAME_ET=%d' % self.DO_GAME_ET + M4_LINE += ' --define=M4_GAME_Q2=%d' % self.DO_GAME_Q2 + if ( self.M4_STDC != '' ): + M4_LINE += ' --define=M4_STDC=' + self.M4_STDC + # setup.xml + self.system('m4 ' + M4_LINE + ' ' + self.SETUP_DIR + '/setup.data/setup.xml.in > ' + self.SETUP_DIR + '/setup.data/setup.xml') + # postinstall.sh + self.system('m4 ' + M4_LINE + ' ' + self.SETUP_DIR + '/setup.data/postinstall.sh.in > ' + self.SETUP_DIR + '/setup.data/postinstall.sh') + # config.sh + self.system('m4 ' + M4_LINE + ' ' + self.SETUP_DIR + '/setup.data/config.sh.in > ' + self.SETUP_DIR + '/setup.data/config.sh') + # setup.sh + self.system('m4 ' + M4_LINE + ' ' + self.SETUP_DIR + '/setup.sh.in > ' + self.SETUP_DIR + '/setup.sh') + self.system('chmod +x ' +self.SETUP_DIR + '/setup.sh') + self.system('find ' + self.SETUP_DIR + ' -name .svn | while read i ; do rm -r "$i" ; done') + # pack it up + self.system('setup/linux/makeself/makeself.sh ' + self.SETUP_DIR + ' ' + self.SETUP_TARGET + ' "GtkRadiant ' + self.line + ' setup" ./setup.sh') + if (self.g_darwin): + def build_fink_deb(self): + print "Building installer .deb\n" + self.F_REV = '1' + self.FINKINFO_DIR = '/sw/fink/10.2/unstable/main/finkinfo/games' + self.TARBALL_DIR='radiant-' + self.F_REV + '.' + self.major + self.TARBALL_NAME='radiant-' + self.F_REV + '.' + self.major + '.tar.gz' + self.TARBALL_DEST='/sw/src' + + # prepare package description + self.system('mkdir -p ' + self.FINKINFO_DIR) + self.system('m4 ' + M4_LINE + ' --define=M4_SETUP_TARGET=' + self.SETUP_TARGET + ' --define=M4_F_REV=' + self.F_REV + ' ' + 'setup/osx/radiant.info.m4 > ' + self.FINKINFO_DIR + '/radiant-' + self.TARBALL_DIR + '.info') + + # build the tarball + self.system('if [ -r /tmp/' + self.TARBALL_DIR + ' ] ; then rm -r ' '/tmp/' + self.TARBALL_DIR + ' ; fi') + self.system('mkdir -p ' '/tmp/' + self.TARBALL_DIR) + self.system('cp ' + self.SETUP_TARGET + ' ' + '/tmp/' + self.TARBALL_DIR) + self.system('cd /tmp ; tar -cvzf ' + self.TARBALL_NAME + ' ' + self.TARBALL_DIR + ' ; cp ' + self.TARBALL_NAME + ' ' + self.TARBALL_DEST + '/') + self.system('/sw/bin/fink rebuild radiant') + + build_fink_deb(self) + + def spawn_setup(self, env, target, source): + if ( OS == 'Darwin' ): + self.g_darwin = 1 + else: + self.g_darwin = 0 + (self.line, self.major, self.minor) = get_version() + print 'Setup: GtkRadiant %s' % self.line + if ( self.g_darwin ): + self.SETUP_IMAGE_OS = '../loki_setup/image' + else: + self.SETUP_IMAGE_OS = 'setup/linux/setup_image.Linux' + self.SETUP_IMAGE = 'setup/linux/setup_image' + self.SETUP_DIR = '/tmp/radiant-setup.%d' % os.getpid() + self.EDITOR_BIN='radiant.' + g_cpu + if ( self.g_darwin ): + self.SETUP_BIN_DIR = self.SETUP_DIR + '/bin/Darwin/ppc' + self.SETUP_TARGET = 'osx-radiant-%s.run' % self.line + else: + self.SETUP_BIN_DIR = self.SETUP_DIR + '/bin/Linux/x86' + self.SETUP_TARGET = 'linux-radiant-%s.run' % self.line + # TODO: eval a conf file instead + self.DO_CORE=1 + self.DO_GAME_Q3=1 + self.DO_GAME_WOLF=1 + self.DO_GAME_ET=1 + self.DO_GAME_Q2=1 + self.DO_GAME_HER2=1 + if ( self.g_darwin ): + self.DO_GAME_Q2=0 + self.DO_GAME_ET=0 + self.DO_GAME_HER2=0 + # verbose a bit + print 'version: %s major: %s minor: %s\neditor core: %d\nq3: %d\nwolf: %d\nq2: %d\nher2: %d' % (self.line, self.major, self.minor, self.DO_CORE, self.DO_GAME_Q3, self.DO_GAME_WOLF, self.DO_GAME_Q2, self.DO_GAME_HER2) + if (self.DO_CORE): + self.copy_core() + if (self.DO_GAME_Q3): + self.copy_q3() + if (self.DO_GAME_WOLF): + self.copy_wolf() + if (self.DO_GAME_ET): + self.copy_et() + if (self.DO_GAME_Q2): + self.copy_q2() + if (self.DO_GAME_HER2): + self.copy_her2() + self.build_setup() + return 0 + +def spawn_setup(env, target, source): + setup = setup_builder() + setup.spawn_setup(env, target, source) + +# NOTE: could modify g_env to add the deps auto when calling SharedLibrarySafe .. +if (SETUP == '1'): + g_env.Command('foo', INSTALL + '/radiant.' + g_cpu, [ spawn_setup ] ) + depends_list = [ + INSTALL + '/modules/entity.so', + INSTALL + '/modules/fgd.so', + INSTALL + '/modules/imagehl.so', + INSTALL + '/modules/image.so', + INSTALL + '/modules/imagepng.so', + INSTALL + '/modules/map.so', + INSTALL + '/modules/mapxml.so', + INSTALL + '/modules/model.so', + INSTALL + '/modules/shaders.so', + INSTALL + '/modules/surface.so', + INSTALL + '/modules/vfspk3.so', + INSTALL + '/modules/vfswad.so', + INSTALL + '/plugins/bobtoolz.so', + INSTALL + '/plugins/camera.so', + INSTALL + '/plugins/prtview.so', + INSTALL + '/plugins/gensurf.so', + INSTALL + '/plugins/bkgrnd2d.so', + INSTALL + '/q3map2.' + g_cpu, + INSTALL + '/radiant.' + g_cpu, + INSTALL + '/q3data.' + g_cpu ] + if ( OS != 'Darwin' ): + depends_list += [ + INSTALL + '/q2/modules/imagewal.so', + INSTALL + '/q2/modules/surface_quake2.so', + INSTALL + '/q2/modules/vfspak.so', + INSTALL + '/q2/q2map', + INSTALL + '/q2/qdata3', + INSTALL + '/heretic2/modules/imagem8.so', + INSTALL + '/heretic2/modules/surface_heretic2.so', + INSTALL + '/heretic2/modules/vfspak.so', + INSTALL + '/heretic2/qdata3', + INSTALL + '/heretic2/q2map' ] + g_env.Depends( 'foo', depends_list ) + +# end setup --------------------------------------------------------------------------------------- diff --git a/SConstruct b/SConstruct new file mode 100644 index 00000000..d5d6c824 --- /dev/null +++ b/SConstruct @@ -0,0 +1,291 @@ +# scons build script +# http://scons.sourceforge.net + +import commands, re, sys, os, pickle, string, popen2 +from makeversion import radiant_makeversion, get_version +from osx_setup import do_osx_setup + +# to access some internal stuff +import SCons + +conf_filename='site.conf' +# there is a default hardcoded value, you can override on command line, those are saved between runs +# we only handle strings +serialized=['CC', 'CXX', 'JOBS', 'BUILD', 'SETUP'] + +# help ------------------------------------------- + +Help(""" +Usage: scons [OPTIONS] [TARGET] [CONFIG] + +[OPTIONS] and [TARGET] are covered in command line options, use scons -H + +[CONFIG]: KEY="VALUE" [...] +a number of configuration options saved between runs in the """ + conf_filename + """ file +erase """ + conf_filename + """ to start with default settings again + +CC +CXX + Specify C and C++ compilers (defaults gcc and g++) + ex: CC="gcc-3.2" + You can use ccache and distcc, for instance: + CC="ccache distcc gcc" CXX="ccache distcc g++" + +JOBS + Parallel build + ex: JOBS="4" is a good setting on SMP machines + +BUILD + Use debug/release to select build settings + ex: BUILD="release" - default is debug + OSX: use BUILD="info" to generate the set of release files + +SETUP + Build a setup - default 0 +""" +) + +# end help --------------------------------------- + +# sanity ----------------------------------------- + +# use q decently recent python release +EnsurePythonVersion( 2, 1 ) +# above 0.90 +EnsureSConsVersion( 0, 95 ) +print 'SCons ' + SCons.__version__ + +# end sanity ------------------------------------- + +# system detection ------------------------------- + +# CPU type +g_cpu = commands.getoutput('uname -m') +exp = re.compile('.*i?86.*') +if (g_cpu == 'Power Macintosh'): + g_cpu = 'ppc' +elif exp.match(g_cpu): + g_cpu = 'x86' +else: + g_cpu = 'cpu' + +# OS +OS = commands.getoutput('uname') + +if (OS == 'Linux'): + # libc .. do the little magic! + # NOTE: this used to work fine up to libc 2.3 + libc = commands.getoutput('/lib/libc.so.6 |grep "GNU C "|grep version|awk -F "version " \'{ print $2 }\'|cut -b -3') + +# end system detection --------------------------- + +# default settings ------------------------------- + +CC='gcc' +CXX='g++' +JOBS='1' +BUILD='debug' +INSTALL='#install' +SETUP='0' +g_build_root = 'build' + +# end default settings --------------------------- + +# site settings ---------------------------------- + +site_dict = {} +if (os.path.exists(conf_filename)): + site_file = open(conf_filename, 'r') + p = pickle.Unpickler(site_file) + site_dict = p.load() + print 'Loading build configuration from ' + conf_filename + for k, v in site_dict.items(): + exec_cmd = k + '=\"' + v + '\"' + print exec_cmd + exec(exec_cmd) + +# end site settings ------------------------------ + +# command line settings -------------------------- + +for k in serialized: + if (ARGUMENTS.has_key(k)): + exec_cmd = k + '=\"' + ARGUMENTS[k] + '\"' + print 'Command line: ' + exec_cmd + exec(exec_cmd) + +# end command line settings ---------------------- + +# sanity check ----------------------------------- + +if (SETUP == '1' and BUILD != 'release' and BUILD != 'info'): + print 'Forcing release build for setup' + BUILD = 'release' + +def GetGCCVersion(name): + ret = commands.getstatusoutput('%s -dumpversion' % name) + if ( ret[0] != 0 ): + return None + vers = string.split(ret[1], '.') + if ( len(vers) == 2 ): + return [ vers[0], vers[1], 0 ] + elif ( len(vers) == 3 ): + return vers + return None + +ver_cc = GetGCCVersion(CC) +ver_cxx = GetGCCVersion(CXX) + +# end sanity check ------------------------------- + +# save site configuration ---------------------- + +for k in serialized: + exec_cmd = 'site_dict[\'' + k + '\'] = ' + k + exec(exec_cmd) + +site_file = open(conf_filename, 'w') +p = pickle.Pickler(site_file) +p.dump(site_dict) +site_file.close() + +# end save site configuration ------------------ + +# general configuration, target selection -------- + +SConsignFile( "scons.signatures" ) + +g_build = g_build_root + '/' + BUILD + +SetOption('num_jobs', JOBS) + +LINK = CXX +# common flags +CCFLAGS = '' +CXXFLAGS = '-pipe -DQ_NO_STLPORT ' +CPPPATH = [] +if (BUILD == 'debug'): + CXXFLAGS += '-g -D_DEBUG ' + CCFLAGS += '-g -D_DEBUG ' +elif (BUILD == 'release'): + CXXFLAGS += '-g -O2 ' + CCFLAGS += '-g -O2 ' +elif ( BUILD == 'info' ): + print 'Preparing OSX release' + ( line, major, minor ) = get_version() + do_osx_setup( major, minor, 'osx-radiant-%s.run' % line ) + sys.exit( 0 ) +else: + print 'Unknown build configuration ' + BUILD + sys.exit( 0 ) + +LINKFLAGS = '' +if ( OS == 'Linux' ): + LINKFLAGS += '-Wl,-fini,fini_stub ' +if ( OS == 'Darwin' ): + CCFLAGS += '-force_cpusubtype_ALL -fPIC ' + CXXFLAGS += '-force_cpusubtype_ALL -fPIC -fno-exceptions -fno-rtti ' + CPPPATH.append('/sw/include') + CPPPATH.append('/usr/X11R6/include') + LINKFLAGS += '-L/sw/lib -L/usr/lib -L/usr/X11R6/lib ' + +CPPPATH.append('libs') + +# extend the standard Environment a bit +class idEnvironment(Environment): + + def useGlib2(self): + self['CXXFLAGS'] += '`pkg-config glib-2.0 --cflags` ' + self['CCFLAGS'] += '`pkg-config glib-2.0 --cflags` ' + self['LINKFLAGS'] += '`pkg-config glib-2.0 --libs` ' + + def useXML2(self): + self['CXXFLAGS'] += '`xml2-config --cflags` ' + self['CCFLAGS'] += '`xml2-config --cflags` ' + self['LINKFLAGS'] += '`xml2-config --libs` ' + + def useGtk2(self): + self['CXXFLAGS'] += '`pkg-config gtk+-2.0 --cflags` ' + self['CCFLAGS'] += '`pkg-config gtk+-2.0 --cflags` ' + self['LINKFLAGS'] += '`pkg-config gtk+-2.0 --libs-only-L` `pkg-config gtk+-2.0 --libs-only-l` ' + + def useGtkGLExt(self): + self['CXXFLAGS'] += '`pkg-config gtkglext-1.0 --cflags` ' + self['CCFLAGS'] += '`pkg-config gtkglext-1.0 --cflags` ' + self['LINKFLAGS'] += '`pkg-config gtkglext-1.0 --libs-only-L` `pkg-config gtkglext-1.0 --libs-only-l` ' + + def usePNG(self): + self['CXXFLAGS'] += '`libpng-config --cflags` ' + self['CCFLAGS'] += '`libpng-config --cflags` ' + self['LINKFLAGS'] += '`libpng-config --ldflags` ' + + def usePThread(self): + if ( OS == 'Darwin' ): + self['LINKFLAGS'] += '-lpthread -Wl,-stack_size,0x400000 ' + else: + self['LINKFLAGS'] += '-lpthread ' + + def CheckLDD(self, target, source, env): + file = target[0] + if (not os.path.isfile(file.abspath)): + print('ERROR: CheckLDD: target %s not found\n' % target[0]) + Exit(1) + # not using os.popen3 as I want to check the return code + ldd = popen2.Popen3('`which ldd` -r %s' % target[0], 1) + stdout_lines = ldd.fromchild.readlines() + stderr_lines = ldd.childerr.readlines() + ldd_ret = ldd.wait() + del ldd + have_undef = 0 + if ( ldd_ret != 0 ): + print "ERROR: ldd command returned with exit code %d" % ldd_ret + os.system('rm %s' % target[0]) + Exit() + for i_line in stderr_lines: + print repr(i_line) + regex = re.compile('undefined symbol: (.*)\t\\((.*)\\)\n') + if ( regex.match(i_line) ): + symbol = regex.sub('\\1', i_line) + try: + env['ALLOWED_SYMBOLS'].index(symbol) + except: + have_undef = 1 + else: + print "ERROR: failed to parse ldd stderr line: %s" % i_line + os.system('rm %s' % target[0]) + Exit(1) + if ( have_undef ): + print "ERROR: undefined symbols" + os.system('rm %s' % target[0]) + Exit(1) + + def SharedLibrarySafe(self, target, source): + self.SharedLibrary(target, source) + if (OS != 'Darwin'): + AddPostAction(target + '.so', self.CheckLDD) + +g_env = idEnvironment(ENV = os.environ, + CC = CC, + CXX = CXX, + LINK = LINK, + CCFLAGS = CCFLAGS, + CXXFLAGS = CXXFLAGS, + CPPPATH = CPPPATH, + LINKFLAGS = LINKFLAGS) + +# export the globals +GLOBALS = 'g_env INSTALL SETUP g_cpu' + +radiant_makeversion('\\ngcc version: %s.%s.%s' % ( ver_cc[0], ver_cc[1], ver_cc[2] ) ) + +# end general configuration ---------------------- + +# targets ---------------------------------------- + +Default('.') + +Export('GLOBALS ' + GLOBALS) +BuildDir(g_build, '.', duplicate = 0) +SConscript(g_build + '/SConscript') + +# end targets ------------------------------------ diff --git a/contrib/bkgrnd2d/bitmaps/bkgrnd2d_conf.bmp b/contrib/bkgrnd2d/bitmaps/bkgrnd2d_conf.bmp new file mode 100644 index 00000000..bc307e26 Binary files /dev/null and b/contrib/bkgrnd2d/bitmaps/bkgrnd2d_conf.bmp differ diff --git a/contrib/bkgrnd2d/bitmaps/bkgrnd2d_xy_toggle.bmp b/contrib/bkgrnd2d/bitmaps/bkgrnd2d_xy_toggle.bmp new file mode 100644 index 00000000..d95fa284 Binary files /dev/null and b/contrib/bkgrnd2d/bitmaps/bkgrnd2d_xy_toggle.bmp differ diff --git a/contrib/bkgrnd2d/bitmaps/bkgrnd2d_xz_toggle.bmp b/contrib/bkgrnd2d/bitmaps/bkgrnd2d_xz_toggle.bmp new file mode 100644 index 00000000..6af8308d Binary files /dev/null and b/contrib/bkgrnd2d/bitmaps/bkgrnd2d_xz_toggle.bmp differ diff --git a/contrib/bkgrnd2d/bitmaps/bkgrnd2d_yz_toggle.bmp b/contrib/bkgrnd2d/bitmaps/bkgrnd2d_yz_toggle.bmp new file mode 100644 index 00000000..de9f4df9 Binary files /dev/null and b/contrib/bkgrnd2d/bitmaps/bkgrnd2d_yz_toggle.bmp differ diff --git a/contrib/bkgrnd2d/bkgrnd2d.cpp b/contrib/bkgrnd2d/bkgrnd2d.cpp new file mode 100644 index 00000000..b2f09ff9 --- /dev/null +++ b/contrib/bkgrnd2d/bkgrnd2d.cpp @@ -0,0 +1,319 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// bkgrnd2d Plugin +// +// Code by reyalP aka Reed Mideke +// +// Based on various other plugins +// + +#include "bkgrnd2d.h" + +CBackgroundRender render; + +CBackgroundImage backgroundXY(XY),backgroundXZ(XZ),backgroundYZ(YZ); + +CBackgroundRender::CBackgroundRender() +{ + refCount = 1; +} + +CBackgroundRender::~CBackgroundRender() +{ +} + +void CBackgroundRender::Register() +{ + g_QglTable.m_pfnHookGL2DWindow( this ); +} + +void CBackgroundRender::Draw2D( VIEWTYPE vt ) +{ + switch(vt) + { + case XY: + backgroundXY.Render(); + break; + case XZ: + backgroundXZ.Render(); + break; + case YZ: + backgroundYZ.Render(); + break; + } +} + + +CBackgroundImage::CBackgroundImage(VIEWTYPE vt) +{ + m_tex = NULL; + m_alpha = 0.5; + + // TODO, sensible defaults ? Or not show until we have extents ? + m_xmin = m_ymin = 0.0f; + m_xmax = m_ymax = 0.0f; + + m_bActive = false; + + m_vt = vt; + + switch(m_vt) + { + case XY: + m_ix = 0; + m_iy = 1; + break; + case XZ: + m_ix = 0; + m_iy = 2; + break; + case YZ: + m_ix = 1; + m_iy = 2; + break; + } +} + +/* + * should cleanup, but I don't think we can be sure it happens before our + * interfaces are gone +CBackgroundImage::~CBackgroundImage() +{ +} +*/ + +void CBackgroundImage::Cleanup() +{ + if(m_tex) { + g_QglTable.m_pfn_qglDeleteTextures(1,&m_tex->texture_number); + g_free(m_tex); + m_tex = NULL; + } +} + +void CBackgroundImage::Render() +{ + if (!m_bActive || !Valid()) + return; + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + g_QglTable.m_pfn_qglEnable(GL_TEXTURE_2D); + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_QglTable.m_pfn_qglTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + g_QglTable.m_pfn_qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); + g_QglTable.m_pfn_qglTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); + + g_QglTable.m_pfn_qglPolygonMode(GL_FRONT,GL_FILL); + // TODO, just so we can tell if we end up going the wrong way + // g_QglTable.m_pfn_qglPolygonMode(GL_BACK,GL_LINE); + // TODO any other state we should not assume ? + + g_QglTable.m_pfn_qglBindTexture(GL_TEXTURE_2D, m_tex->texture_number); + g_QglTable.m_pfn_qglBegin(GL_QUADS); + + g_QglTable.m_pfn_qglColor4f(1.0,1.0,1.0,m_alpha); + g_QglTable.m_pfn_qglTexCoord2f(0.0,1.0); + g_QglTable.m_pfn_qglVertex2f(m_xmin,m_ymin); + + g_QglTable.m_pfn_qglTexCoord2f(1.0,1.0); + g_QglTable.m_pfn_qglVertex2f(m_xmax,m_ymin); + + g_QglTable.m_pfn_qglTexCoord2f(1.0,0.0); + g_QglTable.m_pfn_qglVertex2f(m_xmax,m_ymax); + + g_QglTable.m_pfn_qglTexCoord2f(0.0,0.0); + g_QglTable.m_pfn_qglVertex2f(m_xmin,m_ymax); + + g_QglTable.m_pfn_qglEnd(); + g_QglTable.m_pfn_qglBindTexture(GL_TEXTURE_2D, 0); + + g_QglTable.m_pfn_qglPopAttrib(); +} + +bool CBackgroundImage::Load(const char *filename) +{ + qtexture_t *newtex; + + unsigned char *image = NULL; // gets allocated with what ? g_malloc + int width = 0, height = 0; + + g_FuncTable.m_pfnLoadImage(filename,&image,&width,&height); + + if(!image) { + Syn_Printf(MSG_WARN "load %s failed\n",filename); + return false; + } + +// just in case we want to build for an old version +// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=900 +#ifdef BKGRND2D_JPG_WORKAROUND + if ( strlen(filename) > 4 && !strcmp(".jpg",filename + strlen(filename) - 4)) { + Syn_Printf(MSG_PREFIX ".jpg workaround, clearing alpha channel\n"); + int size = width*height*4; + int i; + for (i = 3; i < size; i+=4) { + image[i] = 255; + } + } +#endif + + //TODO bug for stored texture size + //TODO whose gl context are we in, anyway ? + newtex = g_FuncTable.m_pfnLoadTextureRGBA(image,width,height); + + g_free(image); + + if(!newtex) { + Syn_Printf(MSG_WARN "image to texture failed\n"); + return false; + } + + Cleanup(); + m_tex = newtex; + + g_FuncTable.m_pfnSysUpdateWindows(W_XY); + + return true; +} + +bool CBackgroundImage::SetExtentsMM() +{ + entity_s *worldentity; + const char *val; + int xmin = 0, ymin = 0, xmax = 0, ymax = 0; + + worldentity = (entity_s *)g_FuncTable.m_pfnGetEntityHandle(0); + if(!worldentity) { + Syn_Printf(MSG_WARN "SetExtentsMM worldspawn not found\n"); + return false; + } + //TODO val is not NULL even if key does not exist + val = g_EntityTable.m_pfnValueForKey(worldentity,"mapcoordsmins"); + if(!val || !val[0]) { + Syn_Printf(MSG_WARN "SetExtentsMM mapcoordsmins not found\n"); + return false; + } +// we could be more robust +// note contortions due to splashs strange idea of min and max + if(sscanf(val, "%d %d",&xmin,&ymax) != 2) + { + Syn_Printf(MSG_WARN "SetExtentsMM mapcoordsmins malformed\n"); + return false; + } + + val = g_EntityTable.m_pfnValueForKey(worldentity,"mapcoordsmaxs"); + if(!val || !val[0]) { + Syn_Printf(MSG_WARN "SetExtentsMM mapcoordsmaxs not found\n"); + return false; + } + if(sscanf(val, "%d %d",&xmax,&ymin) != 2) + { + Syn_Printf(MSG_WARN "SetExtentsMM mapcoordsmaxs malformed\n"); + return false; + } + //might do sanity check before we commit + m_xmin = (float)xmin; + m_ymin = (float)ymin; + m_xmax = (float)xmax; + m_ymax = (float)ymax; + + g_FuncTable.m_pfnSysUpdateWindows(W_XY); + return true; +} + +// TODO, this should just be exported from core +// ripped directly from radiant/select.cpp:Select_GetBounds +// +static bool get_selection_bounds (vec3_t mins, vec3_t maxs) +{ + brush_t *b; + int i; + brush_t *selected_brushes = g_DataTable.m_pfnSelectedBrushes(); + //TODO should never happen + if(!selected_brushes) { + Sys_Printf (MSG_PREFIX "selected_brushes = NULL\n"); + return false; + } + // this should mean no selection + if(selected_brushes == selected_brushes->next) { + Sys_Printf (MSG_PREFIX "nothing selected\n"); + + return false; + } + + for (i=0 ; i<3 ; i++) + { + mins[i] = 99999; + maxs[i] = -99999; + } + + for (b=selected_brushes->next ; b != selected_brushes ; b=b->next) + { + if (b->owner->eclass->fixedsize) + { + for (i=0 ; i<3 ; i++) + { + if (b->owner->origin[i] < mins[i]) + mins[i] = b->owner->origin[i]; + if (b->owner->origin[i] > maxs[i]) + maxs[i] = b->owner->origin[i]; + } + } + else + { + for (i=0 ; i<3 ; i++) + { + if (b->mins[i] < mins[i]) + mins[i] = b->mins[i]; + if (b->maxs[i] > maxs[i]) + maxs[i] = b->maxs[i]; + } + } + } + return true; +} + +bool CBackgroundImage::SetExtentsSel() +{ + vec3_t mins,maxs; + + if(!get_selection_bounds(mins,maxs)) + return false; + + if(((int)mins[m_ix] == (int)maxs[m_ix]) || + ((int)mins[m_iy] == (int)maxs[m_iy])) { + Syn_Printf(MSG_PREFIX "tiny selection\n"); + return false; + } + + m_xmin = mins[m_ix]; + m_ymin = mins[m_iy]; + m_xmax = maxs[m_ix]; + m_ymax = maxs[m_iy]; + + g_FuncTable.m_pfnSysUpdateWindows(W_XY); + + return true; +} + diff --git a/contrib/bkgrnd2d/bkgrnd2d.def b/contrib/bkgrnd2d/bkgrnd2d.def new file mode 100644 index 00000000..36c4457f --- /dev/null +++ b/contrib/bkgrnd2d/bkgrnd2d.def @@ -0,0 +1,8 @@ +; bkgrnd2d.def : Declares the module parameters for the DLL. + +LIBRARY "BKGRND2D" +DESCRIPTION 'BKGRND2D Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + Synapse_EnumerateInterfaces @1 diff --git a/contrib/bkgrnd2d/bkgrnd2d.h b/contrib/bkgrnd2d/bkgrnd2d.h new file mode 100644 index 00000000..bee6e811 --- /dev/null +++ b/contrib/bkgrnd2d/bkgrnd2d.h @@ -0,0 +1,83 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// bkgrnd2d Plugin +// +// Code by reyalP aka Reed Mideke +// +// Based on spritemodel source code by hydra +// + +#include "plugin.h" + +class CBackgroundImage { +private: + qtexture_t *m_tex; + VIEWTYPE m_vt; + +// which components of a vec3_t correspond to x and y in the image + unsigned m_ix,m_iy; + +public: + CBackgroundImage(VIEWTYPE vt); +// ~CBackgroundImage(); + + float m_alpha; // vertex alpha + bool m_bActive; + +// x and y axis are in relation to the screen, not world, making rendering +// the same for each view type. Whoever sets them is responsible for +// shuffling. +// units are world units. +// TODO should be private + float m_xmin,m_ymin,m_xmax,m_ymax; + +// load file, create new tex, cleanup old tex, set new tex + bool Load(const char *filename); + void Cleanup(); // free texture, free tex, set make tex NULL + bool SetExtentsMM(); // set extents by ET mapcoordsmaxs/mapcoordsmins + bool SetExtentsSel(); // set extents by selection + void Render(); + bool Valid() { return (m_tex && (m_xmin != m_xmax) && (m_ymin != m_ymax)); } +}; + +class CBackgroundRender : public IGL2DWindow { +public: + + CBackgroundRender(); + virtual ~CBackgroundRender(); + +protected: + int refCount; + +public: + + // IGL2DWindow IGL3DWindow interface + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + void Draw2D( VIEWTYPE vt ); + void Register(); +}; + +extern CBackgroundImage backgroundXY,backgroundXZ,backgroundYZ; +extern CBackgroundRender render; + diff --git a/contrib/bkgrnd2d/bkgrnd2d.vcproj b/contrib/bkgrnd2d/bkgrnd2d.vcproj new file mode 100644 index 00000000..e4b59896 --- /dev/null +++ b/contrib/bkgrnd2d/bkgrnd2d.vcproj @@ -0,0 +1,75 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/bkgrnd2d/dialog.cpp b/contrib/bkgrnd2d/dialog.cpp new file mode 100644 index 00000000..43fe7717 --- /dev/null +++ b/contrib/bkgrnd2d/dialog.cpp @@ -0,0 +1,365 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// bkgrnd2d Plugin dialog +// +// Code by reyalP aka Reed Mideke +// +// Based on various other plugins +// + +#include + +#include "bkgrnd2d.h" +#include "dialog.h" + +// spaces to make label nice and big +#define NO_FILE_MSG " (no file loaded) " + +static GtkWidget *pDialogWnd; +static GtkWidget *pNotebook; +static GtkTooltips *pTooltips; + +class CBackgroundDialogPage +{ +private: + GtkWidget *m_pWidget; + GtkWidget *m_pTabLabel; + GtkWidget *m_pFileLabel; + GtkWidget *m_pPosLabel; + VIEWTYPE m_vt; + bool m_bValidFile; + +public: + CBackgroundImage *m_pImage; + CBackgroundDialogPage( VIEWTYPE vt ); + void Append(GtkWidget *notebook); + void Browse(); + void Reload(); + void SetPosLabel(); +// ~BackgroundDialogPage(); +}; + + +// dialog page callbacks +static void browse_callback( GtkWidget *widget, gpointer data ) +{ + ((CBackgroundDialogPage *)data)->Browse(); +} + +static void reload_callback( GtkWidget *widget, gpointer data ) +{ + ((CBackgroundDialogPage *)data)->Reload(); +} + +static void size_sel_callback( GtkWidget *widget, gpointer data ) +{ + CBackgroundDialogPage *pPage = (CBackgroundDialogPage *)data; + if (pPage->m_pImage->SetExtentsSel()) + pPage->SetPosLabel(); +} + +static void size_mm_callback( GtkWidget *widget, gpointer data ) +{ + CBackgroundDialogPage *pPage = (CBackgroundDialogPage *)data; + if(pPage->m_pImage->SetExtentsMM()) + pPage->SetPosLabel(); +} + +static void alpha_adjust_callback( GtkWidget *widget, gpointer data ) +{ + CBackgroundDialogPage *pPage = (CBackgroundDialogPage *)data; + pPage->m_pImage->m_alpha = (float)gtk_range_get_value (GTK_RANGE(widget)); + g_FuncTable.m_pfnSysUpdateWindows(W_XY); +} + +void CBackgroundDialogPage::Reload() +{ + if(m_bValidFile) + m_pImage->Load(gtk_label_get_text(GTK_LABEL(m_pFileLabel))); +} + +void CBackgroundDialogPage::Browse() +{ + char browsedir[PATH_MAX]; + const char *ct; + const char *newfile; + char *t; + + //TODO GetMapName saves the map. eeep! + //also with no map, returns unnamed.map, otherwise returns full path +// Syn_Printf(MSG_PREFIX "GetMapName() %s\n", +// g_FuncTable.m_pfnGetMapName()); + + ct = g_FuncTable.m_pfnReadProjectKey("basepath"); + // TODO shouldn't need this stuff + if(!ct || !strlen(ct)) { + Syn_Printf(MSG_PREFIX "basepath = NULL or empty\n"); + return; + } + Syn_Printf(MSG_PREFIX "basepath: %s\n",ct); + if(strlen(ct) >= PATH_MAX) { + Syn_Printf(MSG_PREFIX "base game dir too long\n"); + return; + } + + strcpy(browsedir,ct); + // make sure we have a trailing / + if(browsedir[strlen(browsedir) - 1] != '/') + strcat(browsedir,"/"); + + //if we dont have a file yet, don't try to use it for default dir + if(m_bValidFile) { + // filename should always be a nice clean unix style relative path + ct = gtk_label_get_text(GTK_LABEL(m_pFileLabel)); + strcat(browsedir,ct); + Syn_Printf(MSG_PREFIX "full path: %s\n",browsedir); + + // lop off the file part + t = browsedir + strlen(browsedir) - 1; + while (t != browsedir && *t != '/') + t--; + *t = 0; + } + Syn_Printf(MSG_PREFIX "browse directory %s\n",browsedir); + +//does NOT need freeing contrary to include/qerplugin.h comments +//TODO bug/patch for comments +//TODO patern gets fucked up sometimes if empty +//http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=915 + newfile = g_FuncTable.m_pfnFileDialog(pDialogWnd,TRUE, + "Load Background Image",browsedir,FILETYPE_KEY); + if(!newfile) { + Syn_Printf(MSG_PREFIX "newfile = NULL\n"); + return; + } + Syn_Printf(MSG_PREFIX "newfile: %s\n",newfile); + newfile = g_FileSystemTable.m_pfnExtractRelativePath(newfile); + + if(!newfile) { + Syn_Printf(MSG_PREFIX "newfile = NULL\n"); + return; + } + Syn_Printf(MSG_PREFIX "newfile: %s\n",newfile); + + if(m_pImage->Load(newfile)) { + m_bValidFile = true; + gtk_label_set_text(GTK_LABEL(m_pFileLabel),newfile); + } +} + +void CBackgroundDialogPage::SetPosLabel() +{ + char s[64]; + // TODO no snprintf ? + sprintf(s, "Size/Position (%d,%d) (%d,%d)",(int)(m_pImage->m_xmin), + (int)(m_pImage->m_ymin),(int)(m_pImage->m_xmax),(int)(m_pImage->m_ymax)); + gtk_label_set_text(GTK_LABEL(m_pPosLabel),s); +} + +CBackgroundDialogPage::CBackgroundDialogPage(VIEWTYPE vt ) +{ + GtkWidget *frame; + GtkWidget *hbox; + GtkWidget *w; + + m_vt = vt; + + m_bValidFile = false; + + switch(m_vt) + { + case XY: + m_pTabLabel = gtk_label_new("X/Y"); + m_pImage = &backgroundXY; + break; + case XZ: + m_pTabLabel = gtk_label_new("X/Z"); + m_pImage = &backgroundXZ; + break; + case YZ: + m_pTabLabel = gtk_label_new("Y/Z"); + m_pImage = &backgroundYZ; + break; + } +// A vbox to hold everything + m_pWidget = gtk_vbox_new(FALSE,0); +// Frame for file row + frame = gtk_frame_new("File"); + gtk_box_pack_start (GTK_BOX (m_pWidget),frame, FALSE, FALSE, 2); + +// hbox for first row + hbox = gtk_hbox_new(FALSE,5); + gtk_container_set_border_width(GTK_CONTAINER (hbox),4); + gtk_container_add (GTK_CONTAINER (frame), hbox); + +// label to display filename + m_pFileLabel = gtk_label_new(NO_FILE_MSG); + gtk_label_set_selectable(GTK_LABEL(m_pFileLabel),TRUE); +//TODO set min size ? done with spaces right now + gtk_box_pack_start (GTK_BOX (hbox),m_pFileLabel, TRUE, TRUE, 5); + + gtk_widget_show (m_pFileLabel); + + w = gtk_button_new_with_label ("Browse..."); + g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (browse_callback), + (gpointer)this); + gtk_box_pack_start (GTK_BOX (hbox),w, FALSE, FALSE, 5); + gtk_tooltips_set_tip (pTooltips, w, "Select a file", NULL); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Reload"); + g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (reload_callback), + (gpointer)this); + // TODO disable until we have file + // gtk_widget_set_sensitive(w,FALSE); + gtk_tooltips_set_tip (pTooltips, w, "Reload current file", NULL); + gtk_box_pack_start (GTK_BOX (hbox),w, FALSE, FALSE, 5); + gtk_widget_show (w); + + gtk_widget_show (hbox); + gtk_widget_show (frame); + +// second row (rendering options) + frame = gtk_frame_new("Rendering"); + gtk_box_pack_start (GTK_BOX (m_pWidget),frame, FALSE, FALSE, 2); + + hbox = gtk_hbox_new(FALSE,5); + gtk_container_set_border_width(GTK_CONTAINER (hbox),4); + gtk_container_add (GTK_CONTAINER (frame), hbox); + + w = gtk_label_new("Vertex alpha:"); + gtk_box_pack_start (GTK_BOX (hbox),w, FALSE, FALSE, 5); + gtk_widget_show (w); + + w = gtk_hscale_new_with_range(0.0,1.0,0.01); + gtk_range_set_value(GTK_RANGE(w),0.5); + gtk_scale_set_value_pos(GTK_SCALE(w),GTK_POS_LEFT); + g_signal_connect (G_OBJECT (w), "value-changed", + G_CALLBACK (alpha_adjust_callback), (gpointer)this); + gtk_box_pack_start (GTK_BOX (hbox),w, TRUE, TRUE, 5); + gtk_tooltips_set_tip (pTooltips, w, "Set image transparancy", NULL); + gtk_widget_show (w); + + gtk_widget_show (hbox); + gtk_widget_show (frame); +// Third row (size and position) + frame = gtk_frame_new("Size/Position (undefined)"); + m_pPosLabel = gtk_frame_get_label_widget (GTK_FRAME(frame)); + gtk_box_pack_start ( GTK_BOX (m_pWidget), frame, FALSE, FALSE, 2); + + hbox = gtk_hbox_new(FALSE,5); + gtk_container_add (GTK_CONTAINER (frame), hbox); + gtk_container_set_border_width(GTK_CONTAINER (hbox),4); + + w = gtk_button_new_with_label ("from selection"); + gtk_box_pack_start (GTK_BOX (hbox),w, TRUE, FALSE, 5); + g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (size_sel_callback), + (gpointer)this); + gtk_tooltips_set_tip (pTooltips, w, "Set the size of the image to the bounding rectangle of all selected brushes and entities", NULL); + gtk_widget_show (w); + + if(m_vt == XY) { + w = gtk_button_new_with_label ("from map mins/maxs"); + gtk_box_pack_start ( GTK_BOX (hbox),w, TRUE, FALSE, 2); + g_signal_connect (G_OBJECT (w), "clicked", G_CALLBACK (size_mm_callback), + (gpointer)this); + gtk_tooltips_set_tip (pTooltips, w, "Set the size of the image using the mapcoordsmins and mapcoordsmaxs keys of the worldspawn entity", NULL); + gtk_widget_show (w); + } + + gtk_widget_show (hbox); + gtk_widget_show (frame); + + gtk_widget_show ( m_pWidget ); +} + +void CBackgroundDialogPage::Append(GtkWidget *notebook) +{ + gtk_notebook_append_page( GTK_NOTEBOOK(notebook), m_pWidget, m_pTabLabel); +} + +// dialog global callbacks +/* +static gint expose_callback( GtkWidget *widget, gpointer data ) +{ + return FALSE; +} +*/ + +static void response_callback( GtkWidget *widget, gint response, gpointer data ) +{ + if( response == GTK_RESPONSE_CLOSE ) + gtk_widget_hide( pDialogWnd ); +} + +static gint close_callback( GtkWidget *widget, gpointer data ) +{ + gtk_widget_hide( pDialogWnd ); + return TRUE; +} + +void InitBackgroundDialog() +{ + CBackgroundDialogPage *pPage; + + pDialogWnd = gtk_dialog_new_with_buttons ("Background Images", + GTK_WINDOW(g_pMainWidget), + (GtkDialogFlags)(GTK_DIALOG_DESTROY_WITH_PARENT), + // TODO dialog with no buttons + // GTK_STOCK_CLOSE, + // GTK_RESPONSE_CLOSE, + NULL); + gtk_signal_connect( GTK_OBJECT (pDialogWnd), "delete_event", + GTK_SIGNAL_FUNC( close_callback ), NULL ); + gtk_signal_connect( GTK_OBJECT (pDialogWnd), "response", + GTK_SIGNAL_FUNC( response_callback ), NULL ); +// gtk_signal_connect( GTK_OBJECT (pDialogWnd), "expose_event", GTK_SIGNAL_FUNC( ci_expose ), NULL ); + + pTooltips = gtk_tooltips_new(); + + pNotebook = gtk_notebook_new(); + pPage = new CBackgroundDialogPage(XY); + pPage->Append(pNotebook); + pPage = new CBackgroundDialogPage(XZ); + pPage->Append(pNotebook); + pPage = new CBackgroundDialogPage(YZ); + pPage->Append(pNotebook); + + gtk_box_pack_start (GTK_BOX (GTK_DIALOG(pDialogWnd)->vbox), pNotebook, TRUE, TRUE, 0); + + gtk_widget_show ( pNotebook ); + + gtk_widget_realize( pDialogWnd ); +} + +void ShowBackgroundDialog() +{ + gtk_window_present( GTK_WINDOW(pDialogWnd) ); +} + +void ShowBackgroundDialogPG(int page) +{ + gtk_notebook_set_current_page(GTK_NOTEBOOK(pNotebook),page); + ShowBackgroundDialog(); +} + diff --git a/contrib/bkgrnd2d/dialog.h b/contrib/bkgrnd2d/dialog.h new file mode 100644 index 00000000..7a82cdd6 --- /dev/null +++ b/contrib/bkgrnd2d/dialog.h @@ -0,0 +1,36 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// bkgrnd2d Plugin dialog box +// +// Code by reyalP aka Reed Mideke +// +// + +#ifndef _BKGRND2D_DIALOG_H_ +#define _BKGRND2D_DIALOG_H_ + +void InitBackgroundDialog(); +void ShowBackgroundDialog(); +void ShowBackgroundDialogPG(int page); + +#endif // _BKGRND2D_DIALOG_H_ diff --git a/contrib/bkgrnd2d/plugin.cpp b/contrib/bkgrnd2d/plugin.cpp new file mode 100644 index 00000000..56150e37 --- /dev/null +++ b/contrib/bkgrnd2d/plugin.cpp @@ -0,0 +1,320 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// 2d background Plugin +// +// Code by reyalP aka Reed Mideke +// +// Based on +// + +/* + Overview + ======== + This little plugin allows you to display an image in the background of the + gtkradiant XY window. + + Version History + =============== + + v0.1 + - Initial version. + v0.2 + - three views, dialog box, toolbar + v0.25 + - tooltips, follow gtkradiant coding conventions + + Why ? + ----- + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=88 + + + How ? + ----- + - textures 'n widgets 'n stuff. +*/ + +//#include "plugin.h" +//TODO we just poke the objects directly +#include "bkgrnd2d.h" +#include "dialog.h" + +#define CMD_SEP "-" +#define CMD_CONFIG "Configure..." +#define CMD_ABOUT "About..." +// ============================================================================= +// Globals + +// function tables +_QERFuncTable_1 g_FuncTable; +_QERQglTable g_QglTable; +_QERFileSystemTable g_FileSystemTable; +_QEREntityTable g_EntityTable; +_QERAppDataTable g_DataTable; + +// for the file load dialog +void *g_pMainWidget; + +// ============================================================================= +// plugin implementation + +static const char *PLUGIN_NAME = "2d window background plugin"; + +//backwards for some reason +static const char *PLUGIN_COMMANDS = CMD_ABOUT ";" + CMD_SEP ";" + CMD_CONFIG + ; + +static const char *PLUGIN_ABOUT = "2d window background v0.25\n\n" + "By reyalP (hellsownpuppy@yahoo.com)"; + + + + +void DoBkgrndToggleXY(); +void DoBkgrndToggleXZ(); +void DoBkgrndToggleYZ(); + +#define NUM_TOOLBAR_BUTTONS 4 +struct toolbar_button_info_s +{ + char *image; + char *text; + char *tip; + void (*func)(); + IToolbarButton::EType type; +}; + +struct toolbar_button_info_s toolbar_buttons[NUM_TOOLBAR_BUTTONS] = +{ + { + "bkgrnd2d_xy_toggle.bmp", + "xy background", + "Toggle xy background image", + DoBkgrndToggleXY, + IToolbarButton::eToggleButton + }, + { + "bkgrnd2d_xz_toggle.bmp", + "xz background", + "Toggle xz background image", + DoBkgrndToggleXZ, + IToolbarButton::eToggleButton + }, + { + "bkgrnd2d_yz_toggle.bmp", + "yz background", + "Toggle yz background image", + DoBkgrndToggleYZ, + IToolbarButton::eToggleButton + }, + { + "bkgrnd2d_conf.bmp", + "Configure", + "Configure background images", + ShowBackgroundDialog, + IToolbarButton::eButton + }, +}; + +class Bkgrnd2dButton : public IToolbarButton +{ +public: + const toolbar_button_info_s *bi; + virtual const char* getImage() const + { + return bi->image; + } + virtual const char* getText() const + { + return bi->text; + } + virtual const char* getTooltip() const + { + return bi->tip; + } + virtual void activate() const + { + bi->func(); + return ; + } + virtual EType getType() const + { + return bi->type; + } +}; + +Bkgrnd2dButton g_bkgrnd2dbuttons[NUM_TOOLBAR_BUTTONS]; + +unsigned int ToolbarButtonCount() +{ + return NUM_TOOLBAR_BUTTONS; +} + +const IToolbarButton* GetToolbarButton(unsigned int index) +{ + g_bkgrnd2dbuttons[index].bi = &toolbar_buttons[index]; + return &g_bkgrnd2dbuttons[index]; +} + +extern "C" const char* QERPlug_Init (void *hApp, void* pMainWidget) +{ + g_pMainWidget = pMainWidget; + + InitBackgroundDialog(); + render.Register(); + +//TODO is it right ? is it wrong ? it works +//TODO figure out supported image types + GetFileTypeRegistry()->addType(FILETYPE_KEY, filetype_t("all files", "*.*")); + GetFileTypeRegistry()->addType(FILETYPE_KEY, filetype_t("jpeg files", "*.jpg")); + GetFileTypeRegistry()->addType(FILETYPE_KEY, filetype_t("targa files", "*.tga")); + return (char *) PLUGIN_NAME; +} + +extern "C" const char* QERPlug_GetName () +{ + return (char *) PLUGIN_NAME; +} + +extern "C" const char* QERPlug_GetCommandList () +{ + return (char *) PLUGIN_COMMANDS; +} + +extern "C" void QERPlug_Dispatch (const char *p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) +{ + Sys_Printf (MSG_PREFIX "Command \"%s\"\n",p); + if(!strcmp(p, CMD_ABOUT)) { + g_FuncTable.m_pfnMessageBox(NULL, PLUGIN_ABOUT, "About", MB_OK, NULL); + } + else if(!strcmp(p,CMD_CONFIG)) { + ShowBackgroundDialog(); + } +} + +//TODO these three suck +void DoBkgrndToggleXY() +{ + Sys_Printf (MSG_PREFIX "DoBkgrndToggleXY\n"); + // always toggle, since the buttons do + backgroundXY.m_bActive = (backgroundXY.m_bActive) ? false:true; + // if we don't have image or extents, and we activated, + // bring up the dialog with the corresponding page + // would be better to hide or grey out button, but we can't + if(backgroundXY.m_bActive && !backgroundXY.Valid()) + ShowBackgroundDialogPG(0); + else + g_FuncTable.m_pfnSysUpdateWindows(W_XY); +} + +void DoBkgrndToggleXZ() +{ + Sys_Printf (MSG_PREFIX "DoBkgrndToggleXZ\n"); + backgroundXZ.m_bActive = (backgroundXZ.m_bActive) ? false:true; + if(backgroundXZ.m_bActive && !backgroundXZ.Valid()) + ShowBackgroundDialogPG(1); + else + g_FuncTable.m_pfnSysUpdateWindows(W_XY); +} + +void DoBkgrndToggleYZ() +{ + Sys_Printf (MSG_PREFIX "DoBkgrndToggleYZ\n"); + backgroundYZ.m_bActive = (backgroundYZ.m_bActive) ? false:true; + if(backgroundYZ.m_bActive && !backgroundYZ.Valid()) + ShowBackgroundDialogPG(2); + else + g_FuncTable.m_pfnSysUpdateWindows(W_XY); +} + +// ============================================================================= +// SYNAPSE + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientBkgrnd2d g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + g_SynapseClient.AddAPI(TOOLBAR_MAJOR, BKGRND2D_MINOR, sizeof(_QERPlugToolbarTable)); + g_SynapseClient.AddAPI(PLUGIN_MAJOR, BKGRND2D_MINOR, sizeof( _QERPluginTable ) ); + + g_SynapseClient.AddAPI( RADIANT_MAJOR, NULL, sizeof( g_FuncTable ), SYN_REQUIRE, &g_FuncTable ); + g_SynapseClient.AddAPI( QGL_MAJOR, NULL, sizeof( g_QglTable ), SYN_REQUIRE, &g_QglTable ); +// TODO is this the right way to ask for 'whichever VFS we have loaded' ? Seems to work +// for misc filename functions + g_SynapseClient.AddAPI( VFS_MAJOR, "*", sizeof( g_FileSystemTable ), SYN_REQUIRE, &g_FileSystemTable ); +// get worldspawn + g_SynapseClient.AddAPI( ENTITY_MAJOR, NULL, sizeof( g_EntityTable ), SYN_REQUIRE, &g_EntityTable ); +// selected brushes + g_SynapseClient.AddAPI( DATA_MAJOR, NULL, sizeof( g_DataTable ), SYN_REQUIRE, &g_DataTable ); + + return &g_SynapseClient; +} + +bool CSynapseClientBkgrnd2d::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, PLUGIN_MAJOR)) + { + _QERPluginTable* pTable= static_cast<_QERPluginTable*>(pAPI->mpTable); + + pTable->m_pfnQERPlug_Init = QERPlug_Init; + pTable->m_pfnQERPlug_GetName = QERPlug_GetName; + pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList; + pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch; + return true; + } + if (!strcmp(pAPI->major_name, TOOLBAR_MAJOR)) + { + _QERPlugToolbarTable* pTable= static_cast<_QERPlugToolbarTable*>(pAPI->mpTable); + + pTable->m_pfnToolbarButtonCount = &ToolbarButtonCount; + pTable->m_pfnGetToolbarButton = &GetToolbarButton; + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientBkgrnd2d::GetInfo() +{ + return "2d Background plugin built " __DATE__ " " RADIANT_VERSION; +} + +const char* CSynapseClientBkgrnd2d::GetName() +{ + return "bkgrnd2d"; +} + diff --git a/contrib/bkgrnd2d/plugin.h b/contrib/bkgrnd2d/plugin.h new file mode 100644 index 00000000..84933ae0 --- /dev/null +++ b/contrib/bkgrnd2d/plugin.h @@ -0,0 +1,80 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// bkgrnd2d Plugin +// +// Code by reyalP aka Reed Mideke +// +// Based on spritemodel source code by hydra +// + +#ifndef _PLUGIN_H_ +#define _PLUGIN_H_ + +/*! +\todo need general notice about lib purpose etc. +and the external dependencies (such as GLib, STL, mathlib etc.) +*/ + +#include +// for CPtrArray for idata.h +#include "missing.h" + +#include "synapse.h" +#include "iplugin.h" +#include "itoolbar.h" +#define USE_QERTABLE_DEFINE +#include "qerplugin.h" +#include "igl.h" +#include "ifilesystem.h" +#include "ientity.h" +#include "idata.h" + +// verbose messages +#define BKGRND2D_DEBUG + +extern _QERFuncTable_1 g_FuncTable; +extern _QERQglTable g_QglTable; +extern _QERFileSystemTable g_FileSystemTable; +extern _QEREntityTable g_EntityTable; +extern _QERAppDataTable g_DataTable; +extern void *g_pMainWidget; + +extern CSynapseServer* g_pSynapseServer; + +class CSynapseClientBkgrnd2d : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + const char* GetName(); + + CSynapseClientBkgrnd2d() { } + virtual ~CSynapseClientBkgrnd2d() { } +}; +#define MSG_PREFIX "bkgrnd2d: " +#define MSG_WARN "bkgrnd2d WARNING: " +#define BKGRND2D_MINOR "bkgrnd2d" +#define FILETYPE_KEY "bkgrnd2d" + +#endif // _PLUGIN_H_ diff --git a/contrib/bkgrnd2d/readme_bkgrnd2d-b0.25.txt b/contrib/bkgrnd2d/readme_bkgrnd2d-b0.25.txt new file mode 100644 index 00000000..6184245e --- /dev/null +++ b/contrib/bkgrnd2d/readme_bkgrnd2d-b0.25.txt @@ -0,0 +1,131 @@ +November 25 2003 +bkgrnd2d v 0.25 beta for radiant 1.3.13 +by SCDS_reyalP (email hellsownpuppy@yahoo.com) + +WARNING: +This is an beta release. It is provided with absolutely NO WARRANTY. +If it turns your data to mush and melts your CPU, don't blame me. + +Overview: +This little plugin allows you to display an image in the the gtkradiant 2d +windows. This is useful for layout sketches, maps made from +existing plans, building geometry based on photgraphs, viewing terrain +alphamaps in relation to your terrain, and so on. + +Installation: +extract the .dll and bitmaps into your gtkradiant/plugins directory, and +restart radiant. Be sure to use directory names, to ensure the bitmaps go +in your plugins/bitmaps directory. + +Uninstallation: +Close radiant, delete the bkgrnd2d.dll from the plugins directory, and +delete the bkgrnd2*.bmp files from the plugins/bitmaps directory. + +User Interface: +- The plugin adds 4 buttons to the radiant plugin toolbar. The first 3 + toggle the display of a background image in the specified view. The fourth + brings up a configuration dialog. The configuration dialog can also be + opened from the plugins menu. + +- If an image has not been loaded, or it's display size and location have + not been set, pushing one of the toggle buttons will bring up the dialog + with the corresponding page selected. + +- The configuration dialog is non-modal, meaning that you can leave it open + while you work in radiant. If it gets lost behind another window, clicking + on the configuration button will bring it to the forground. + +Usage: +- bring up the configuration dialog. + +- Choose the "Browse..." button. This will prompt you for an image file. + The file *MUST* be inside your basegame directory (baseq3, main, etmain or + whatever your chosen game uses). The image must be in a format supported by + the game in use. For q3 based games this is truecolor .jpg, .tga and + sometimes .png. For q2 this is .wal + +- Use one of the following methods to set the size (in game units) that the + file is displayed. + 1) select 1 or more brushes or entities and choose "from selection" + This will use the total dimensions off all selected brushes and entities + to size the image. + 2) For the X/Y view only, choose 'Size to min/max keys' This will look in + the worldspawn entity for the keys mapcoordsmins and mapcoordsmaxs (also + used for ET tracemap generation and command map sizing) and use those + dimensions to size the image. + +- Use the toggle buttons to show or hide the loaded images. The buttons will + press or unpress whenever you click them, but an image will only be + displayed once you have successfully loaded a file and set its size/postion. + +- Set the opacity of the image using the slider in the configuration dialog. + +- If any of these commands do not produce the expected results, there may be + an information in the radiant console. Please include this when reporting + bugs. + + +Notes and limitations: +- This plugin is compiled for GtkRadiant 1.3.13. It may or may not work with + later versions. It will *NOT* work with version 1.3.12 and below. If you + build from source (see below) you can build it for other versions. + +- As mentioned above, the image *MUST* be inside your basegame directory, or + another directory in which radiant looks for game files. + +- To prevent the image from being distorted, you should size it to the + original images aspect ratio. mapcoordsmaxs/mapcoordsmins and command maps + should always be square. + +- If you want a specific pixel to world unit relationship, you must arrange + that yourself. + +- On load, the image is converted to a texture whose dimensions are powers + of 2. If the original image dimensions are not powers of 2, some detail will + be lost due to resampling. If it is too large to fit on a single texture, + resolution is reduced. + +- radiants gamma and mipmap options are applied to the image. + +- If the image has an alpha channel, it will be included in the blending + process. 0 is transparent, 255 is opaque. .tga images are recommended if + you want to have an alpha channel. + +- since the plugin will only use true color files, you cannot use a terrain + indexmap (aka alphamap) or heightmap directly. You can of course, save a + copy of your indexmap in a 32 bit format. + +- There is no unload command. + +- You put the plugin in a game specific plugin directory, rather than the + radiant plugin directory. + +- You cannot set the image size with sub-unit precision. + +- Only win32 binaries are included. The source is available from: + http://www.cyberonic.net/~gdevault/rfm/mapstuff/bkgrnd2d-b0.25-src.zip + If you want to use it on another platform you will need a buildable gtkradiant + source tree to build it. For any non-windows platform you will also have to + figure out the compile options. I suggest ripping those off from some other + plugin. + +TODO: +- make file selection paterns match supported filetypes +- large images without downsampling +- bitmap and pcx support for indexmaps +- automatic size from indexmapped entities +- render under the grid instead of blending +- mac/*nix support +- remember/save/restore settings +- texture options independant of radiant prefs +- clean up icky code + +Changes from 0.1 +- all 2d views supported +- new ui +- file selection patterns, default directory improved + +Changes from 0.2 +- tooltips in dialog +- various code cleanup + diff --git a/contrib/bobtoolz/CPortals.h b/contrib/bobtoolz/CPortals.h new file mode 100644 index 00000000..bc9d16ac --- /dev/null +++ b/contrib/bobtoolz/CPortals.h @@ -0,0 +1,63 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" // Added by ClassView + +class CBspPoint { +public: + float p[3]; +}; + +class CBspPortal { +public: + CBspPortal(); + ~CBspPortal(); + + unsigned point_count; + CBspPoint *point; + bool Build(char *def, unsigned int pointCnt, bool bInverse); +}; + + +class CBspNode { +public: + CBspPortal *portal; + unsigned int portal_count; + + bool AddPortal(char* def, unsigned int pointCnt, bool bInverse); + unsigned int portal_next; + CBspNode(); + ~CBspNode(); +}; + + +class CPortals { +public: + + CPortals(); + ~CPortals(); + + void Load(); // use filename in fn + void Purge(); + + char fn[PATH_MAX]; + CBspNode *node; + + unsigned int node_count; +}; diff --git a/contrib/bobtoolz/DBobView.cpp b/contrib/bobtoolz/DBobView.cpp new file mode 100644 index 00000000..74fdacd3 --- /dev/null +++ b/contrib/bobtoolz/DBobView.cpp @@ -0,0 +1,361 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// BobView.cpp: implementation of the DBobView class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DBobView.h" +#include "DListener.h" +#include "misc.h" +#include "funchandlers.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DBobView::DBobView() +{ + nPathCount = 0; + refCount = 1; + + m_bHooked = FALSE; + + path = NULL; + eyes = NULL; + + boundingShow = BOUNDS_APEX; +} + +DBobView::~DBobView() +{ + if(path) + delete[] path; + + // oops forgot to remove our eyes, was causing access violation when it tried + // to talk to it's parent + if(eyes) + delete eyes; + + if(m_bHooked) + UnRegister(); + + g_PathView = NULL; +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +void DBobView::Draw2D(VIEWTYPE vt) +{ + if(!path) + return; + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + g_QglTable.m_pfn_qglDisable(GL_BLEND); + g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH); + + g_QglTable.m_pfn_qglPushMatrix(); + + switch(vt) + { + case XY: + break; + case XZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + break; + case YZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + g_QglTable.m_pfn_qglRotatef(270.0f, 0.0f, 0.0f, 1.0f); + break; + } + + g_QglTable.m_pfn_qglLineWidth(1.0f); + g_QglTable.m_pfn_qglColor4f(1.0f, 0.0f, 0.0f, 1.0f); + + int i; + + g_QglTable.m_pfn_qglBegin(GL_LINE_STRIP); + + for(i = 0; i < nPathCount; i++) + g_QglTable.m_pfn_qglVertex3fv(path[i]); + + g_QglTable.m_pfn_qglEnd(); + + if(m_bShowExtra) + { + // +mars + // for the bounding box stuff + g_QglTable.m_pfn_qglColor4f(0.25f, 0.75f, 0.75f, 1.0f); + + g_QglTable.m_pfn_qglTranslatef( 16.0f, 16.0f, 28.0f ); + + g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP ); + + for ( i = 0; i < nPathCount; i++ ) + g_QglTable.m_pfn_qglVertex3fv( path[i] ); + + g_QglTable.m_pfn_qglEnd(); + + // --------------- + + g_QglTable.m_pfn_qglTranslatef( -16.0f, -16.0f, -28.0f ); // back to where we were + g_QglTable.m_pfn_qglTranslatef( -16.0f, 16.0f, 28.0f ); // move to new postion + + g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP ); + + for ( i = 0; i < nPathCount; i++ ) + g_QglTable.m_pfn_qglVertex3fv( path[i] ); + + g_QglTable.m_pfn_qglEnd(); + + // -------------- + + g_QglTable.m_pfn_qglTranslatef( 16.0f, -16.0f, -28.0f ); // back to where we were + g_QglTable.m_pfn_qglTranslatef( 16.0f, -16.0f, -28.0f ); // new pos + + g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP ); + + for ( i = 0; i < nPathCount; i++ ) + g_QglTable.m_pfn_qglVertex3fv( path[i] ); + + g_QglTable.m_pfn_qglEnd(); + + // ---------------- + + g_QglTable.m_pfn_qglTranslatef( -16.0f, 16.0f, 28.0f ); // back to where we were + +/* g_QglTable.m_pfn_qglTranslatef( -16.0f, -16.0f, -28.0f ); // new pos + + g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP ); + + if ( boundingShow == BOUNDS_ALL ) + { + for ( i = 0; i < nPathCount; i++ ) + g_QglTable.m_pfn_qglVertex3fv( path[i] ); + } + else if ( boundingShow == BOUNDS_APEX ) + { + for ( i = (nPathCount/4); i < (nPathCount/4) * 3; i++ ) + g_QglTable.m_pfn_qglVertex3fv( path[i] ); + } + + g_QglTable.m_pfn_qglEnd();*/ // djbob: er, um doesn't really seem to do anyhting + } + + // -mars + + g_QglTable.m_pfn_qglPopMatrix(); + + g_QglTable.m_pfn_qglPopAttrib(); +} + +void DBobView::Draw3D() +{ + if(!path) + return; + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + g_QglTable.m_pfn_qglDisable(GL_BLEND); + g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH); + + g_QglTable.m_pfn_qglLineWidth(1.0f); + g_QglTable.m_pfn_qglColor4f(1.0f, 0.0f, 0.0f, 1.0f); + + g_QglTable.m_pfn_qglBegin(GL_LINE_STRIP); + + for(int i = 0; i < nPathCount; i++) + g_QglTable.m_pfn_qglVertex3fv(path[i]); + + g_QglTable.m_pfn_qglEnd(); + + if(m_bShowExtra) + { + // +mars + // ahhh -- a nice C&P job :) + // for the bounding box stuff + g_QglTable.m_pfn_qglColor4f(0.25f, 0.75f, 0.75f, 1.0f); + + g_QglTable.m_pfn_qglTranslatef( 16.0f, 16.0f, 28.0f ); + + g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP ); + + int i; + for ( i = 0; i < nPathCount; i++ ) + g_QglTable.m_pfn_qglVertex3fv( path[i] ); + + g_QglTable.m_pfn_qglEnd(); + + // --------------- + + g_QglTable.m_pfn_qglTranslatef( -16.0f, -16.0f, -28.0f ); // back to where we were + g_QglTable.m_pfn_qglTranslatef( -16.0f, 16.0f, 28.0f ); // move to new postion + + g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP ); + + for ( i = 0; i < nPathCount; i++ ) + g_QglTable.m_pfn_qglVertex3fv( path[i] ); + + g_QglTable.m_pfn_qglEnd(); + + // -------------- + + g_QglTable.m_pfn_qglTranslatef( 16.0f, -16.0f, -28.0f ); // back to where we were + g_QglTable.m_pfn_qglTranslatef( 16.0f, -16.0f, -28.0f ); // new pos + + g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP ); + + for ( i = 0; i < nPathCount; i++ ) + g_QglTable.m_pfn_qglVertex3fv( path[i] ); + + g_QglTable.m_pfn_qglEnd(); + + // ---------------- + + g_QglTable.m_pfn_qglTranslatef( -16.0f, 16.0f, 28.0f ); // back to where we were + g_QglTable.m_pfn_qglTranslatef( -16.0f, -16.0f, -28.0f ); // new pos + + g_QglTable.m_pfn_qglBegin( GL_LINE_STRIP ); + + for ( i = 0; i < nPathCount; i++ ) + g_QglTable.m_pfn_qglVertex3fv( path[i] ); + + g_QglTable.m_pfn_qglEnd(); + } + // -mars + + g_QglTable.m_pfn_qglPopAttrib(); +} + +void DBobView::Register() +{ + g_QglTable.m_pfnHookGL2DWindow( this ); + g_QglTable.m_pfnHookGL3DWindow( this ); + m_bHooked = TRUE; +} + +void DBobView::UnRegister() +{ + g_QglTable.m_pfnUnHookGL2DWindow( this ); + g_QglTable.m_pfnUnHookGL3DWindow( this ); + m_bHooked = FALSE; +} + +void DBobView::SetPath(vec3_t *pPath) +{ + if(path) + delete[] path; + + path = pPath; +} + +#define LOCAL_GRAVITY -800.0f + +bool DBobView::CalculateTrajectory(vec3_t start, vec3_t apex, float multiplier, int points, float varGravity) +{ + if(apex[2] <= start[2]) + { + SetPath(NULL); + return FALSE; + } + // ----think q3a actually would allow these + //scrub that, coz the plugin wont :] + + vec3_t dist, speed; + VectorSubtract(apex, start, dist); + + vec_t speed_z = (float)sqrt(-2*LOCAL_GRAVITY*dist[2]); + float flight_time = -speed_z/LOCAL_GRAVITY; + + + VectorScale(dist, 1/flight_time, speed); + speed[2] = speed_z; + +// Sys_Printf("Speed: (%.4f %.4f %.4f)\n", speed[0], speed[1], speed[2]); + + vec3_t* pPath = new vec3_t[points]; + + float interval = multiplier*flight_time/points; + for(int i = 0; i < points; i++) + { + float ltime = interval*i; + + VectorScale(speed, ltime, pPath[i]); + VectorAdd(pPath[i], start, pPath[i]); + + // could do this all with vectors + // vGrav = {0, 0, -800.0f} + // VectorScale(vGrav, 0.5f*ltime*ltime, vAdd); + // VectorScale(speed, ltime, pPath[i]); + // _VectorAdd(pPath[i], start, pPath[i]) + // _VectorAdd(pPath[i], vAdd, pPath[i]) + + pPath[i][2] = start[2] + (speed_z*ltime) + (varGravity*0.5f*ltime*ltime); + } + + SetPath(pPath); + return TRUE; +} + +void DBobView::Begin(const char* trigger, const char *target, float multiplier, int points, float varGravity, bool bNoUpdate, bool bShowExtra) +{ + strcpy(entTrigger, trigger); + strcpy(entTarget, target); + + fMultiplier = multiplier; + fVarGravity = varGravity; + nPathCount = points; + m_bShowExtra = bShowExtra; + + Register(); + + if(UpdatePath()) + { + if(!bNoUpdate) + { + eyes = new DListener; + eyes->parent = this; + eyes->Register(); + } + } + else + { + Sys_ERROR("Initialization Failure in DBobView::Begin"); + delete this; + } +} + +bool DBobView::UpdatePath() +{ + vec3_t start, apex; + + if(GetEntityCentre(entTrigger, start)) + { + if(GetEntityCentre(entTarget, apex)) + { + CalculateTrajectory(start, apex, fMultiplier, nPathCount, fVarGravity); + return TRUE; + } + } + return FALSE; +} diff --git a/contrib/bobtoolz/DBobView.h b/contrib/bobtoolz/DBobView.h new file mode 100644 index 00000000..4259c97a --- /dev/null +++ b/contrib/bobtoolz/DBobView.h @@ -0,0 +1,72 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DBobView.h: interface for the DBobView class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_BOBVIEW_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_BOBVIEW_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_ + +class DListener; + +#define BOUNDS_ALL 0 +#define BOUNDS_APEX 1 + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DBobView : + public IGL2DWindow, + public IGL3DWindow +{ +public: + DBobView(); + virtual ~DBobView(); + +protected: + vec3_t* path; + int refCount; +public: + bool m_bShowExtra; + int boundingShow; + DListener* eyes; + float fVarGravity; + + bool UpdatePath(); + char entTarget[256]; + char entTrigger[256]; + void Begin(const char*, const char*, float, int, float, bool, bool); + bool CalculateTrajectory(vec3_t, vec3_t, float, int, float); + + void SetPath(vec3_t* pPath); + void UnRegister(); + void Register(); + void Draw3D(); + void Draw2D(VIEWTYPE vt); + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + + float fMultiplier; + bool m_bHooked; + int nPathCount; +}; + +#endif // !defined(AFX_BOBVIEW_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DBrush.cpp b/contrib/bobtoolz/DBrush.cpp new file mode 100644 index 00000000..e571a50a --- /dev/null +++ b/contrib/bobtoolz/DBrush.cpp @@ -0,0 +1,848 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DBrush.cpp: implementation of the DBrush class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" + +#ifdef _WIN32 +#pragma warning(disable : 4786) +#endif + +#include "DBrush.h" +#include "DWinding.h" +#include "dialogs-gtk.h" + +#include "misc.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DBrush::DBrush(int ID) +{ + m_nBrushID = ID; + bBoundsBuilt = FALSE; + QER_brush = NULL; +} + +DBrush::~DBrush() +{ + ClearFaces(); + ClearPoints(); +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +DPlane* DBrush::AddFace(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* texData) +{ +#ifdef _DEBUG +// Sys_Printf("(%f %f %f) (%f %f %f) (%f %f %f)\n", va[0], va[1], va[2], vb[0], vb[1], vb[2], vc[0], vc[1], vc[2]); +#endif + bBoundsBuilt = FALSE; + DPlane* newFace = new DPlane(va, vb, vc, texData); + faceList.push_back(newFace); + + return newFace; +} + +int DBrush::BuildPoints() +{ + ClearPoints(); + + if(faceList.size() <= 3) // if less than 3 faces, there can be no points + return 0; // with only 3 faces u can't have a bounded soild + + for(list::const_iterator p1=faceList.begin(); p1!=faceList.end(); p1++) + { + list::const_iterator p2=p1; + for(p2++; p2!=faceList.end(); p2++) + { + list::const_iterator p3=p2; + for(p3++; p3!=faceList.end(); p3++) + { + vec3_t pnt; + if((*p1)->PlaneIntersection(*p2, *p3, pnt)) + { + int pos = PointPosition(pnt); + + if(pos == POINT_IN_BRUSH) + { // ???? shouldn't happen here + Sys_Printf("ERROR:: Build Brush Points: Point IN brush!!!\n"); + } + else if(pos == POINT_ON_BRUSH) + { // normal point + if(!HasPoint(pnt)) + AddPoint(pnt); +/* else + Sys_Printf("Duplicate Point Found, pyramids ahoy!!!!!\n");*/ + // point lies on more that 3 planes + } + + // otherwise point is removed due to another plane.. + + // Sys_Printf("(%f, %f, %f)\n", pnt[0], pnt[1], pnt[2]); + } + } + } + } + +#ifdef _DEBUG +// Sys_Printf("%i points on brush\n", pointList.size()); +#endif + + return pointList.size(); +} + +void DBrush::LoadFromBrush_t(brush_t* brush, bool textured) +{ + ClearFaces(); + ClearPoints(); + + for(int i = g_FuncTable.m_pfnGetFaceCount(brush)-1; i >= 0 ; i--) + { // running backwards so i dont have to use the count function each time (OPT) + _QERFaceData* faceData = g_FuncTable.m_pfnGetFaceData(brush, i); + + if(faceData == NULL) + DoMessageBox("Null pointer returned", "WARNING!", MB_OK); + + if(textured) + AddFace(faceData->m_v1, faceData->m_v2, faceData->m_v3, faceData); + else + AddFace(faceData->m_v1, faceData->m_v2, faceData->m_v3, NULL); + } + + QER_brush = brush; +} + +int DBrush::PointPosition(vec3_t pnt) +{ + int state = POINT_IN_BRUSH; // if nothing happens point is inside brush + + for(list::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++) + { + float dist = (*chkPlane)->DistanceToPoint(pnt); + + if(dist > MAX_ROUND_ERROR) + return POINT_OUT_BRUSH; // if point is in front of plane, it CANT be in the brush + else if(fabs(dist) < MAX_ROUND_ERROR) + state = POINT_ON_BRUSH; // if point is ON plane point is either ON the brush + // or outside it, it can no longer be in it + } + + return state; +} + +void DBrush::ClearPoints() +{ + for(list::const_iterator deadPoint=pointList.begin(); deadPoint!=pointList.end(); deadPoint++) { + delete *deadPoint; + } + pointList.clear(); +} + +void DBrush::ClearFaces() +{ + bBoundsBuilt = FALSE; + for(list::const_iterator deadPlane=faceList.begin(); deadPlane!=faceList.end(); deadPlane++) + { + delete *deadPlane; + } + faceList.clear(); +} + +void DBrush::AddPoint(vec3_t pnt) +{ + DPoint* newPoint = new DPoint; + VectorCopy(pnt, newPoint->_pnt); + pointList.push_back(newPoint); +} + +bool DBrush::HasPoint(vec3_t pnt) +{ + for(list::const_iterator chkPoint=pointList.begin(); chkPoint!=pointList.end(); chkPoint++) + { + if(**chkPoint == pnt) + return TRUE; + } + + return FALSE; +} + +int DBrush::RemoveRedundantPlanes() +{ + int cnt = 0; + list::iterator chkPlane; + + // find duplicate planes + list::iterator p1=faceList.begin(); + + while( p1!=faceList.end() ) + { + list::iterator p2 = p1; + + for(p2++; p2!=faceList.end(); p2++) + { + if(**p1 == **p2) + { + if(!strcmp((*p1)->texInfo.m_TextureName, "textures/common/caulk")) + { + delete *p1; + p1 = faceList.erase(p1); // duplicate plane + } + else + { + delete *p2; + p2 = faceList.erase(p2); // duplicate plane + } + + cnt++; + break; + } + } + + if( p2 == faceList.end() ) + p1++; + } + + //+djbob kill planes with bad normal, they are more of a nuisance than losing a brush + chkPlane=faceList.begin(); + while( chkPlane!=faceList.end() ) + { + if(VectorLength((*chkPlane)->normal) == 0) // plane has bad normal + { + delete *chkPlane; + chkPlane = faceList.erase(chkPlane); + cnt++; + } else { + chkPlane++; + } + } + //-djbob + + if(pointList.size() == 0) // if points may not have been built, build them +/* if(BuildPoints() == 0) // just let the planes die if they are all bad + return cnt;*/ + BuildPoints(); + + chkPlane=faceList.begin(); + while(chkPlane != faceList.end()) + { + if((*chkPlane)->IsRedundant(pointList)) // checks that plane "0wnz" :), 3 or more points + { + delete *chkPlane; + chkPlane = faceList.erase(chkPlane); + cnt++; + } + else + chkPlane++; + } + + return cnt; +} + +bool DBrush::GetBounds(vec3_t min, vec3_t max) +{ + BuildBounds(); + + if(!bBoundsBuilt) + return FALSE; + + VectorCopy(bbox_min, min); + VectorCopy(bbox_max, max); + + return TRUE; +} + +bool DBrush::BBoxCollision(DBrush* chkBrush) +{ + vec3_t min1, min2; + vec3_t max1, max2; + + GetBounds(min1, max1); + chkBrush->GetBounds(min2, max2); + + if(min1[0] >= max2[0]) + return FALSE; + if(min1[1] >= max2[1]) + return FALSE; + if(min1[2] >= max2[2]) + return FALSE; + + if(max1[0] <= min2[0]) + return FALSE; + if(max1[1] <= min2[1]) + return FALSE; + if(max1[2] <= min2[2]) + return FALSE; + + return TRUE; +} + +DPlane* DBrush::HasPlane(DPlane* chkPlane) +{ + for(list::const_iterator brushPlane=faceList.begin(); brushPlane!=faceList.end(); brushPlane++) + { + if(**brushPlane == *chkPlane) + return *brushPlane; + } + return NULL; +} + +bool DBrush::IsCutByPlane(DPlane *cuttingPlane) +{ + bool isInFront; + + if(pointList.size() == 0) + if(BuildPoints() == 0) + return FALSE; + + list::const_iterator chkPnt = pointList.begin(); + + if(chkPnt == pointList.end()) + return FALSE; + + float dist = cuttingPlane->DistanceToPoint((*chkPnt)->_pnt); + + if(dist > MAX_ROUND_ERROR) + isInFront = FALSE; + else if(dist < MAX_ROUND_ERROR) + isInFront = TRUE; + else + return TRUE; + + for(chkPnt++=pointList.begin(); chkPnt!=pointList.end(); chkPnt++) + { + dist = cuttingPlane->DistanceToPoint((*chkPnt)->_pnt); + + if(dist > MAX_ROUND_ERROR) + { + if(isInFront) + return TRUE; + } + else if(dist < MAX_ROUND_ERROR) + { + if(!isInFront) + return TRUE; + } + else + return TRUE; + } + + return FALSE; +} + +brush_t* DBrush::BuildInRadiant(bool allowDestruction, int* changeCnt, entity_t* entity) +{ + if(allowDestruction) + { + bool kill = TRUE; + + for(list::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++) + { + if((*chkPlane)->m_bChkOk) + { + kill = FALSE; + break; + } + } + if(kill) + return NULL; + } + + //+djbob: fixed bug when brush had no faces "phantom brush" in radiant. + if(faceList.size() < 4) + { + Sys_Printf("Possible Phantom Brush Found, will not rebuild\n"); + return NULL; + } + //-djbob + + QER_brush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + + for(list::const_iterator buildPlane=faceList.begin(); buildPlane!=faceList.end(); buildPlane++) { + if((*buildPlane)->AddToBrush_t(QER_brush) && changeCnt) { + (*changeCnt)++; + } + } + + if(entity) { + g_FuncTable.m_pfnCommitBrushHandleToEntity(QER_brush, entity); + g_BrushTable.m_pfnBrush_Build(QER_brush); + g_BrushTable.m_pfnBrush_AddToList(QER_brush, g_AppDataTable.m_pfnSelectedBrushes()); + } else { + g_FuncTable.m_pfnCommitBrushHandle(QER_brush); + } + + return QER_brush; +} + +void DBrush::CutByPlane(DPlane *cutPlane, DBrush **newBrush1, DBrush **newBrush2) +{ + if(!IsCutByPlane(cutPlane)) + { + *newBrush1 = NULL; + *newBrush2 = NULL; + return; + } + + DBrush* b1 = new DBrush; + DBrush* b2 = new DBrush; + + for(list::const_iterator parsePlane=faceList.begin(); parsePlane!=faceList.end(); parsePlane++) + { + b1->AddFace((*parsePlane)->points[0], (*parsePlane)->points[1], (*parsePlane)->points[2], NULL); + b2->AddFace((*parsePlane)->points[0], (*parsePlane)->points[1], (*parsePlane)->points[2], NULL); + } + + b1->AddFace(cutPlane->points[0], cutPlane->points[1], cutPlane->points[2], NULL); + b2->AddFace(cutPlane->points[2], cutPlane->points[1], cutPlane->points[0], NULL); + + b1->RemoveRedundantPlanes(); + b2->RemoveRedundantPlanes(); + + *newBrush1 = b1; + *newBrush2 = b2; +} + +bool DBrush::IntersectsWith(DBrush *chkBrush) +{ + if(pointList.size() == 0) + if(BuildPoints() == 0) + return FALSE; // invalid brush!!!! + + if(chkBrush->pointList.size() == 0) + if(chkBrush->BuildPoints() == 0) + return FALSE; // invalid brush!!!! + + if(!BBoxCollision(chkBrush)) + return FALSE; + + list::const_iterator iplPlane; + + for( iplPlane=faceList.begin(); iplPlane!=faceList.end(); iplPlane++) + { + + bool allInFront = TRUE; + for(list::const_iterator iPoint=chkBrush->pointList.begin(); iPoint!=chkBrush->pointList.end(); iPoint++) + { + if((*iplPlane)->DistanceToPoint((*iPoint)->_pnt) < -MAX_ROUND_ERROR) + { + allInFront = FALSE; + break; + } + } + if(allInFront) + return FALSE; + } + + for( iplPlane=chkBrush->faceList.begin(); iplPlane!=chkBrush->faceList.end(); iplPlane++) + { + bool allInFront = TRUE; + for(list::const_iterator iPoint=pointList.begin(); iPoint!=pointList.end(); iPoint++) + { + if((*iplPlane)->DistanceToPoint((*iPoint)->_pnt) < -MAX_ROUND_ERROR) + { + allInFront = FALSE; + break; + } + } + if(allInFront) + return FALSE; + } + + return TRUE; +} + +bool DBrush::IntersectsWith(DPlane* p1, DPlane* p2, vec3_t v) { + vec3_t vDown = { 0, 0, -1 }; + + list::const_iterator iplPlane; + for( iplPlane = faceList.begin(); iplPlane != faceList.end(); iplPlane++) { + DPlane* p = (*iplPlane); + + vec_t d = DotProduct( p->normal, vDown ); + if( d >= 0 ) { + continue; + } + if(p->PlaneIntersection(p1, p2, v)) { + if(PointPosition( v ) != POINT_OUT_BRUSH) { + return TRUE; + } + } + } + + return FALSE; +} + +void DBrush::BuildBounds() +{ + if(!bBoundsBuilt) + { + if(pointList.size() == 0) // if points may not have been built, build them + if(BuildPoints() == 0) + return; + + list::const_iterator first = pointList.begin(); + VectorCopy((*first)->_pnt, bbox_min); + VectorCopy((*first)->_pnt, bbox_max); + + list::const_iterator point=pointList.begin(); + for( point++; point!=pointList.end(); point++) + { + if((*point)->_pnt[0] > bbox_max[0]) + bbox_max[0] = (*point)->_pnt[0]; + if((*point)->_pnt[1] > bbox_max[1]) + bbox_max[1] = (*point)->_pnt[1]; + if((*point)->_pnt[2] > bbox_max[2]) + bbox_max[2] = (*point)->_pnt[2]; + + if((*point)->_pnt[0] < bbox_min[0]) + bbox_min[0] = (*point)->_pnt[0]; + if((*point)->_pnt[1] < bbox_min[1]) + bbox_min[1] = (*point)->_pnt[1]; + if((*point)->_pnt[2] < bbox_min[2]) + bbox_min[2] = (*point)->_pnt[2]; + } + + bBoundsBuilt = TRUE; + } +} + +bool DBrush::BBoxTouch(DBrush *chkBrush) +{ + vec3_t min1, min2; + vec3_t max1, max2; + + GetBounds(min1, max1); + chkBrush->GetBounds(min2, max2); + + if((min1[0] - max2[0]) > MAX_ROUND_ERROR) + return FALSE; + if((min1[1] - max2[1]) > MAX_ROUND_ERROR) + return FALSE; + if((min1[2] - max2[2]) > MAX_ROUND_ERROR) + return FALSE; + + if((min2[0] - max1[0]) > MAX_ROUND_ERROR) + return FALSE; + if((min2[1] - max1[1]) > MAX_ROUND_ERROR) + return FALSE; + if((min2[2] - max1[2]) > MAX_ROUND_ERROR) + return FALSE; + + int cnt = 0; + + if((min2[0] - max1[0]) == 0) + cnt++; + + if((min2[1] - max1[1]) == 0) + cnt++; + + if((min2[2] - max1[2]) == 0) + cnt++; + + if((min1[0] - max2[0]) == 0) + cnt++; + + if((min1[1] - max2[1]) == 0) + cnt++; + + if((min1[2] - max2[2]) == 0) + cnt++; + + if(cnt > 1) + return FALSE; + + return TRUE; +} + +void DBrush::ResetChecks(list* exclusionList) +{ + for(list::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++) + { + bool set = FALSE; + + if(exclusionList) + { + for(list::iterator eTexture = exclusionList->begin(); eTexture != exclusionList->end(); eTexture++) + { + if(strstr((*resetPlane)->texInfo.m_TextureName, eTexture->GetBuffer())) + { + set = TRUE; + break; + } + } + } + + (*resetPlane)->m_bChkOk = set; + } +} + +DPlane* DBrush::HasPlaneInverted(DPlane *chkPlane) +{ + for(list::const_iterator brushPlane=faceList.begin(); brushPlane!=faceList.end(); brushPlane++) + { + if(**brushPlane != *chkPlane) + { + if(fabs((*brushPlane)->_d + chkPlane->_d) < 0.1) + return (*brushPlane); + } + } + return NULL; +} + +bool DBrush::HasTexture(const char *textureName) +{ + for(list::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++) + { + if(strstr((*chkPlane)->texInfo.m_TextureName, textureName)) + return TRUE; + + } + return FALSE; +} + +bool DBrush::IsDetail() +{ + for(list::const_iterator chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++) + { + if((*chkPlane)->texInfo.m_nContents & FACE_DETAIL) + return TRUE; + + } + return FALSE; +} + +void DBrush::BuildFromWinding(DWinding *w) +{ + if(w->numpoints < 3) + { + Sys_ERROR("Winding has invalid number of points"); + return; + } + + DPlane* wPlane = w->WindingPlane(); + + DWinding* w2; + w2 = w->CopyWinding(); + int i; + for(i = 0; i < w2->numpoints; i++) + VectorAdd(w2->p[i], wPlane->normal, w2->p[i]); + + AddFace(w2->p[0], w2->p[1], w2->p[2], NULL); + AddFace(w->p[2], w->p[1], w->p[0], NULL); + + for(i = 0; i < w->numpoints-1; i++) + AddFace(w2->p[i], w->p[i], w->p[i+1], NULL); + AddFace(w2->p[w->numpoints-1], w->p[w->numpoints-1], w->p[0], NULL); + + delete wPlane; + delete w2; +} + +void DBrush::SaveToFile(FILE *pFile) +{ + fprintf(pFile, "{\n"); + + for(list::const_iterator pp=faceList.begin(); pp!=faceList.end(); pp++) + { + char buffer[512]; + + sprintf(buffer, "( %.0f %.0f %.0f ) ( %.0f %.0f %.0f ) ( %.0f %.0f %.0f ) %s %.0f %.0f %f %f %.0f 0 0 0\n", + (*pp)->points[0][0], (*pp)->points[0][1], (*pp)->points[0][2], + (*pp)->points[1][0], (*pp)->points[1][1], (*pp)->points[1][2], + (*pp)->points[2][0], (*pp)->points[2][1], (*pp)->points[2][2], + (*pp)->texInfo.m_TextureName, + (*pp)->texInfo.m_fShift[0], (*pp)->texInfo.m_fShift[1], + (*pp)->texInfo.m_fScale[0], (*pp)->texInfo.m_fScale[0], + (*pp)->texInfo.m_fRotate); + + fprintf(pFile, buffer); + } + + fprintf(pFile, "}\n"); +} + +void DBrush::Rotate(vec3_t vOrigin, vec3_t vRotation) +{ + for(list::const_iterator rotPlane=faceList.begin(); rotPlane!=faceList.end(); rotPlane++) + { + for(int i = 0; i < 3; i++) + VectorRotate((*rotPlane)->points[i], vRotation, vOrigin); + + (*rotPlane)->Rebuild(); + } +} + +void DBrush::RotateAboutCentre(vec3_t vRotation) +{ + vec3_t min, max, centre; + GetBounds(min, max); + VectorAdd(min, max, centre); + VectorScale(centre, 0.5f, centre); + + Rotate(centre, vRotation); +} + +bool DBrush::ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, + int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation) +{ + if(textureName) + { + bool changed = FALSE; + for(list::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++) + { + if(!strcmp((*resetPlane)->texInfo.m_TextureName, textureName)) + { + if(bResetTextureName) + strcpy((*resetPlane)->texInfo.m_TextureName, newTextureName); + + if(bResetScale[0]) + (*resetPlane)->texInfo.m_fScale[0] = fScale[0]; + if(bResetScale[1]) + (*resetPlane)->texInfo.m_fScale[1] = fScale[1]; + + if(bResetShift[0]) + (*resetPlane)->texInfo.m_fShift[0] = fShift[0]; + if(bResetShift[1]) + (*resetPlane)->texInfo.m_fShift[1] = fShift[1]; + + if(bResetRotation) + (*resetPlane)->texInfo.m_fRotate = (float)rotation; + + changed = TRUE; + } + } + return changed; // no point rebuilding unless we need to, only slows things down + } + else + { + for(list::const_iterator resetPlane=faceList.begin(); resetPlane!=faceList.end(); resetPlane++) + { + if(bResetTextureName) + strcpy((*resetPlane)->texInfo.m_TextureName, newTextureName); + + if(bResetScale[0]) + (*resetPlane)->texInfo.m_fScale[0] = fScale[0]; + if(bResetScale[1]) + (*resetPlane)->texInfo.m_fScale[1] = fScale[1]; + + if(bResetShift[0]) + (*resetPlane)->texInfo.m_fShift[0] = fShift[0]; + if(bResetShift[1]) + (*resetPlane)->texInfo.m_fShift[1] = fShift[1]; + + if(bResetRotation) + (*resetPlane)->texInfo.m_fRotate = (float)rotation; + } + return TRUE; + } +} + +bool DBrush::operator ==(DBrush* other) +{ + list::const_iterator chkPlane; + + for(chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++) + { + if(!other->HasPlane((*chkPlane))) + return FALSE; + } + + for(chkPlane=faceList.begin(); chkPlane!=faceList.end(); chkPlane++) + { + if(!HasPlane((*chkPlane))) + return FALSE; + } + + return TRUE; +} + +DPlane* DBrush::AddFace(vec3_t va, vec3_t vb, vec3_t vc, const char *textureName, bool bDetail) +{ + bBoundsBuilt = FALSE; + DPlane* newFace = new DPlane(va, vb, vc, textureName, bDetail); + faceList.push_back(newFace); + + return newFace; +} + +DPlane* DBrush::FindPlaneWithClosestNormal( vec_t* normal ) { + vec_t bestDot = -2; + DPlane* bestDotPlane = NULL; + list::const_iterator chkPlane; + for( chkPlane = faceList.begin(); chkPlane != faceList.end(); chkPlane++ ) { + DPlane* pPlane = (*chkPlane); + + vec_t dot = DotProduct( pPlane->normal, normal ); + if( dot > bestDot ) { + bestDot = dot; + bestDotPlane = pPlane; + } + } + + return bestDotPlane; +} + +int DBrush::FindPointsForPlane( DPlane* plane, DPoint** pnts, int maxpnts ) { + int numpnts = 0; + + if(!maxpnts) { + return 0; + } + + BuildPoints(); + + for( list::const_iterator points = pointList.begin(); points != pointList.end(); points++ ) { + DPoint* point = (*points); + + if( fabs(plane->DistanceToPoint( point->_pnt )) < MAX_ROUND_ERROR ) { + pnts[numpnts] = point; + numpnts++; + + if(numpnts >= maxpnts) { + return numpnts; + } + + } + } + + return numpnts; +} + +void DBrush::RemovePlane( DPlane* plane ) { + bBoundsBuilt = FALSE; + for( list::const_iterator deadPlane = faceList.begin(); deadPlane != faceList.end(); deadPlane++ ) { + if(*deadPlane == plane) { + delete *deadPlane; + faceList.remove( plane ); + } + } +} + +void DBrush::RemoveFromRadiant( void ) { + if(QER_brush) { + g_FuncTable.m_pfnDeleteBrushHandle(QER_brush); + } +} diff --git a/contrib/bobtoolz/DBrush.h b/contrib/bobtoolz/DBrush.h new file mode 100644 index 00000000..7f2485cd --- /dev/null +++ b/contrib/bobtoolz/DBrush.h @@ -0,0 +1,101 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DBrush.h: interface for the DBrush class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DBRUSH_H__35B2C522_F0A7_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DBRUSH_H__35B2C522_F0A7_11D4_ACF7_004095A18133__INCLUDED_ + +#include "DPlane.h" + +#define POINT_IN_BRUSH 0 +#define POINT_ON_BRUSH 1 +#define POINT_OUT_BRUSH 2 + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DBrush +{ +public: + DPlane* AddFace(vec3_t va, vec3_t vb, vec3_t vc, const char* textureName, bool bDetail); + void SaveToFile(FILE* pFile); + + void Rotate(vec3_t vOrigin, vec3_t vRotation); + void RotateAboutCentre(vec3_t vRotation); + + DPlane* HasPlaneInverted(DPlane* chkPlane); + DPlane* HasPlane(DPlane* chkPlane); + DPlane* AddFace(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* texData); + + bool ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation); + bool IsDetail(); + bool HasTexture(const char* textureName); + bool IntersectsWith(DBrush *chkBrush); + bool IntersectsWith(DPlane* p1, DPlane* p2, vec3_t v); + bool IsCutByPlane(DPlane* cuttingPlane); + bool GetBounds(vec3_t min, vec3_t max); + bool HasPoint(vec3_t pnt); + bool BBoxCollision(DBrush* chkBrush); + bool BBoxTouch(DBrush* chkBrush); + + int BuildPoints(); + void BuildBounds(); + void BuildFromWinding(DWinding* w); + brush_t* BuildInRadiant(bool allowDestruction, int* changeCnt, entity_t* entity = NULL); + + void ResetChecks(list* exclusionList); + + void ClearFaces(); + void ClearPoints(); + + int RemoveRedundantPlanes( void ); + void RemovePlane( DPlane* plane ); + int PointPosition(vec3_t pnt); + void RemoveFromRadiant( void ); + + + void CutByPlane(DPlane* cutPlane, DBrush** newBrush1, DBrush** newBrush2); + + void LoadFromBrush_t(brush_t* brush, bool textured); + void AddPoint(vec3_t pnt); + + DPlane* FindPlaneWithClosestNormal( vec_t* normal ); + int FindPointsForPlane( DPlane* plane, DPoint** pnts, int maxpnts ); + + DBrush(int ID = -1); + virtual ~DBrush(); + + bool operator== (DBrush* other); + +// members + brush_t* QER_brush; + list faceList; + list pointList; + int m_nBrushID; + vec3_t bbox_min, bbox_max; + bool bBoundsBuilt; +}; + +//typedef CList DBrushList; + +#endif // !defined(AFX_DBRUSH_H__35B2C522_F0A7_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DEPair.cpp b/contrib/bobtoolz/DEPair.cpp new file mode 100644 index 00000000..b52ad5cb --- /dev/null +++ b/contrib/bobtoolz/DEPair.cpp @@ -0,0 +1,49 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DEPair.cpp: implementation of the DEPair class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DEPair.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DEPair::DEPair() +{ + +} + +DEPair::~DEPair() +{ + +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +void DEPair::Build(char *pKey, char *pValue) +{ + key = pKey; + value = pValue; +} diff --git a/contrib/bobtoolz/DEPair.h b/contrib/bobtoolz/DEPair.h new file mode 100644 index 00000000..e5438af4 --- /dev/null +++ b/contrib/bobtoolz/DEPair.h @@ -0,0 +1,45 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DEPair.h: interface for the DEPair class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DEPAIR_H__35B2C521_F0A7_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DEPAIR_H__35B2C521_F0A7_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DEPair +{ +public: + DEPair(); + virtual ~DEPair(); + + void Build(char* pKey, char* pValue); + + Str key; + Str value; +}; + +//typedef CList DEPairList; + +#endif // !defined(AFX_DEPAIR_H__35B2C521_F0A7_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DEntity.cpp b/contrib/bobtoolz/DEntity.cpp new file mode 100644 index 00000000..2c4e8a2f --- /dev/null +++ b/contrib/bobtoolz/DEntity.cpp @@ -0,0 +1,675 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DEntity.cpp: implementation of the DEntity class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" + +#ifdef _WIN32 +#pragma warning(disable : 4786) +#endif + +#include "DEntity.h" + +#include "dialogs-gtk.h" +#include "misc.h" +#include "CPortals.h" + +const char* brushEntityList[] = { + "worldspawn", + "trigger_always", + "trigger_hurt", + "trigger_multiple", + "trigger_push", + "trigger_teleport", + "func_bobbing", + "func_button", + "func_door", + "func_group", + "func_pendulum", + "func_plat", + "func_rotating", + "func_static", + "func_timer", + "func_train", + 0 +}; + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DEntity::DEntity(char *classname, int ID) +{ + SetClassname(classname); + m_nID = ID; + QER_Entity = NULL; +} + +DEntity::~DEntity() +{ + ClearPatches(); + ClearBrushes(); + ClearEPairs(); +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +void DEntity::ClearBrushes() +{ + for(list::const_iterator deadBrush=brushList.begin(); deadBrush!=brushList.end(); deadBrush++) + { + delete *deadBrush; + } + brushList.clear(); +} + +void DEntity::ClearPatches() +{ + for(list::const_iterator deadPatch=patchList.begin(); deadPatch!=patchList.end(); deadPatch++) + { + delete *deadPatch; + } + patchList.clear(); +} + +DPatch* DEntity::NewPatch() +{ + DPatch* newPatch = new DPatch; + + patchList.push_back(newPatch); + + return newPatch; +} + +DBrush* DEntity::NewBrush(int ID) +{ + DBrush* newBrush = new DBrush(ID); + + brushList.push_back(newBrush); + + return newBrush; +} + +char* getNextBracket(char* s) +{ + char* p = s; + while(*p) + { + p++; + if(*p == '(') + break; + } + + return p; +} + +bool DEntity::LoadFromPrt(char *filename) +{ + CPortals portals; + strcpy(portals.fn, filename); + portals.Load(); + + if(portals.node_count == 0) + return FALSE; + + ClearBrushes(); + ClearEPairs(); + + bool build = false; + for(unsigned int i = 0; i < portals.node_count; i++) + { + build = false; + DBrush* brush = NewBrush(); + + for(unsigned int j = 0; j < portals.node[i].portal_count; j++) + { + for(unsigned int k = 0; k < portals.node[i].portal[j].point_count-2; k++) + { + vec3_t v1, v2, normal, n; + VectorSubtract(portals.node[i].portal[j].point[k+2].p, portals.node[i].portal[j].point[k+1].p, v1); + VectorSubtract(portals.node[i].portal[j].point[k].p, portals.node[i].portal[j].point[k+1].p, v2); + CrossProduct(v1, v2, n); + VectorNormalize(n, v2); + + if(k == 0) + { + VectorCopy(v2, normal); + } + else + { + VectorSubtract(v2, normal, v1); + if(VectorLength(v1) > 0.01) + { + build = true; + break; + } + } + } + + if(!build) + brush->AddFace(portals.node[i].portal[j].point[2].p, portals.node[i].portal[j].point[1].p, portals.node[i].portal[j].point[0].p, "textures/common/caulk", FALSE); + else + brush->AddFace(portals.node[i].portal[j].point[0].p, portals.node[i].portal[j].point[1].p, portals.node[i].portal[j].point[2].p, "textures/common/caulk", FALSE); + } + if(build) + brush->BuildInRadiant(FALSE, NULL); + } + + return TRUE; +} + +DPlane* DEntity::AddFaceToBrush(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* faceData, int ID) +{ + DBrush* buildBrush = GetBrushForID(ID); + return buildBrush->AddFace(va, vb, vc, faceData); + // slow, dont use much +} + +DBrush* DEntity::GetBrushForID(int ID) +{ + DBrush* buildBrush = NULL; + + for(list::const_iterator chkBrush=brushList.begin(); chkBrush!=brushList.end(); chkBrush++) + { + if((*chkBrush)->m_nBrushID == ID) + { + buildBrush = (*chkBrush); + break; + } + } + + if(!buildBrush) + buildBrush = NewBrush(ID); + + return buildBrush; +} + +void DEntity::LoadSelectedBrushes() +{ + ClearBrushes(); + ClearEPairs(); + + int count = g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + for(int i = 0; i < count; i++) { + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i); + + if(brush->pPatch) + continue; + + DBrush* loadBrush = NewBrush(i); + loadBrush->LoadFromBrush_t(brush, TRUE); + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DEntity::LoadSelectedPatches() +{ + ClearPatches(); + ClearEPairs(); + + int count = g_FuncTable.m_pfnAllocateSelectedPatchHandles(); + + for(int i = 0; i < count; i++) + { + //$ FIXME: m_pfnGetPatchHandle + patchMesh_t *pmesh = (patchMesh_t*)g_FuncTable.m_pfnGetPatchData(i); + + DPatch* loadPatch = NewPatch(); + loadPatch->LoadFromBrush_t(pmesh->pSymbiot); + } + + g_FuncTable.m_pfnReleasePatchHandles(); +} + +bool* DEntity::BuildIntersectList() +{ + int max = GetIDMax(); + if(max == 0) + return NULL; + + bool* pbIntList = new bool[max]; + memset(pbIntList, 0, sizeof(bool)*(max)); + + for(list::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++) + { + list::const_iterator pB2=pB1; + for(pB2++; pB2!=brushList.end(); pB2++) + { + if((*pB1)->IntersectsWith((*pB2))) + { + pbIntList[(*pB1)->m_nBrushID] = TRUE; + pbIntList[(*pB2)->m_nBrushID] = TRUE; + } + } + } + + return pbIntList; +} + +bool* DEntity::BuildDuplicateList() +{ + int max = GetIDMax(); + if(max == 0) + return NULL; + + bool* pbDupList = new bool[max]; + memset(pbDupList, 0, sizeof(bool)*(max)); + + for(list::const_iterator pB1=brushList.begin(); pB1!=brushList.end(); pB1++) + { + list::const_iterator pB2=pB1; + for(pB2++; pB2!=brushList.end(); pB2++) + { + if(**pB1 == *pB2) + { + pbDupList[(*pB1)->m_nBrushID] = TRUE; + pbDupList[(*pB2)->m_nBrushID] = TRUE; + } + } + } + + return pbDupList; +} + +void DEntity::SelectBrushes(bool *selectList) +{ + if(selectList == NULL) + return; + + g_FuncTable.m_pfnDeselectAllBrushes(); + + g_FuncTable.m_pfnAllocateActiveBrushHandles(); + + for(std::list::const_iterator pBrush=brushList.begin(); pBrush!=brushList.end(); pBrush++) + { + if(selectList[(*pBrush)->m_nBrushID]) + g_FuncTable.m_pfnSelectBrush((*pBrush)->QER_brush); + } + g_FuncTable.m_pfnReleaseActiveBrushHandles(); +} + +bool DEntity::LoadFromEntity(int id, bool bLoadPatches) { + return LoadFromEntity((entity_t*)g_FuncTable.m_pfnGetEntityHandle(id), bLoadPatches); +} + +bool DEntity::LoadFromEntity(entity_t* ent, bool bLoadPatches) { + ClearPatches(); + ClearBrushes(); + ClearEPairs(); + + QER_Entity = ent; + + epair_t* epl = *g_EntityTable.m_pfnGetEntityKeyValList(QER_Entity); + LoadEPairList(epl); + + bool keep = FALSE; + int i; + for(i = 0; brushEntityList[i]; i++) + { + if(!stricmp(brushEntityList[i], m_Classname)) + { + keep = TRUE; + break; + } + } + + if(!keep) + return FALSE; + + int count = g_FuncTable.m_pfnAllocateEntityBrushHandles(QER_Entity); + + for(i = 0; i < count; i++) + { + + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetEntityBrushHandle(i); + + if(brush == NULL) { + DoMessageBox("GTKRadiant returned a NULL pointer, NOT a good sign", "WARNING!!!", MB_OK); + continue; + } + + if(brush->pPatch) + { + if(bLoadPatches) + { + DPatch* loadPatch = NewPatch(); + loadPatch->LoadFromBrush_t(brush); + } + } + else + { + DBrush* loadBrush = NewBrush(i); + loadBrush->LoadFromBrush_t(brush, TRUE); + } + } + + g_FuncTable.m_pfnReleaseEntityBrushHandles(); + + return TRUE; +} + +void DEntity::RemoveNonCheckBrushes(list* exclusionList, bool useDetail) +{ + list::iterator chkBrush=brushList.begin(); + + while( chkBrush!=brushList.end() ) + { + if(!useDetail) + { + if((*chkBrush)->IsDetail()) + { + delete *chkBrush; + chkBrush = brushList.erase(chkBrush); + continue; + } + } + + list::iterator eTexture; + + for( eTexture=exclusionList->begin(); eTexture!=exclusionList->end(); eTexture++ ) + { + if((*chkBrush)->HasTexture((*eTexture).GetBuffer())) + { + delete *chkBrush; + chkBrush = brushList.erase(chkBrush); + break; + } + } + + if( eTexture == exclusionList->end() ) + chkBrush++; + } +} + +void DEntity::ResetChecks(list* exclusionList) +{ + for(list::const_iterator resetBrush=brushList.begin(); resetBrush!=brushList.end(); resetBrush++) + { + (*resetBrush)->ResetChecks(exclusionList); + } +} + +int DEntity::FixBrushes(bool rebuild) +{ + g_FuncTable.m_pfnAllocateActiveBrushHandles(); + + int cnt = 0; + + for(list::const_iterator fixBrush=brushList.begin(); fixBrush!=brushList.end(); fixBrush++) + { + int count = (*fixBrush)->RemoveRedundantPlanes(); + if(count) + { + cnt += count; + if(rebuild) + { + g_FuncTable.m_pfnDeleteBrushHandle((*fixBrush)->QER_brush); + + (*fixBrush)->BuildInRadiant(FALSE, NULL); + } + } + } + + g_FuncTable.m_pfnReleaseActiveBrushHandles(); + + return cnt; +} + +void DEntity::BuildInRadiant(bool allowDestruction) +{ + bool makeEntity = strcmp(m_Classname, "worldspawn") ? true : false; + + if(makeEntity) + { + entity_t* pE = (entity_t*)g_FuncTable.m_pfnCreateEntityHandle(); + + epair_t* pEpS = GetNextChainItem(NULL, "classname", m_Classname); + + epair_t* pEp = pEpS; + + for(list::const_iterator buildEPair=epairList.begin(); buildEPair!=epairList.end(); buildEPair++) + { + pEp = GetNextChainItem(pEp, (*buildEPair)->key, (*buildEPair)->value); + } + + g_EntityTable.m_pfnSetEntityKeyValList(pE, pEpS); + + g_FuncTable.m_pfnCommitEntityHandleToMap(pE); + + for(list::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++) + (*buildBrush)->BuildInRadiant(allowDestruction, NULL, pE); + + for(list::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++) + (*buildPatch)->BuildInRadiant(pE); + + QER_Entity = pE; + } + else + { + for(list::const_iterator buildBrush=brushList.begin(); buildBrush!=brushList.end(); buildBrush++) + (*buildBrush)->BuildInRadiant(allowDestruction, NULL); + + for(list::const_iterator buildPatch=patchList.begin(); buildPatch!=patchList.end(); buildPatch++) + (*buildPatch)->BuildInRadiant(); + } +} + + + +int DEntity::GetIDMax( void ) { + int max = -1; + for(list::const_iterator cntBrush=brushList.begin(); cntBrush!=brushList.end(); cntBrush++) { + if((*cntBrush)->m_nBrushID > max) + max = (*cntBrush)->m_nBrushID; + } + return max+1; +} + +void DEntity::SetClassname( char *classname ) { + m_Classname = classname; +} + +void DEntity::SaveToFile(FILE *pFile) +{ + fprintf(pFile, "{\n"); + + fprintf(pFile, "\"classname\" \"%s\"\n", (const char *)m_Classname); + + for(list::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++) + { + fprintf(pFile, "\"%s\" \"%s\"\n", (const char *)(*ep)->key, (const char *)(*ep)->value); + } + + for(list::const_iterator bp=brushList.begin(); bp!=brushList.end(); bp++) + { + (*bp)->SaveToFile(pFile); + } + + fprintf(pFile, "}\n"); +} + +void DEntity::ClearEPairs() +{ + for(list::const_iterator deadEPair=epairList.begin(); deadEPair!=epairList.end(); deadEPair++) + { + delete (*deadEPair); + } + epairList.clear(); +} + +void DEntity::AddEPair(char *key, char *value) { + DEPair* newEPair; + newEPair = FindEPairByKey( key ); + if(!newEPair) { + newEPair = new DEPair; + newEPair->Build(key, value); + epairList.push_back(newEPair); + } else { + newEPair->Build(key, value); + } +} + +void DEntity::LoadEPairList(epair_t *epl) +{ + epair_t* ep = epl; + while(ep) + { + if(!strcmp(ep->key, "classname")) + SetClassname(ep->value); + else + AddEPair(ep->key, ep->value); + + ep = ep->next; + } +} + +bool DEntity::ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, + int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation, bool rebuild) +{ + g_FuncTable.m_pfnDeselectAllBrushes(); + + g_FuncTable.m_pfnAllocateActiveBrushHandles(); + + bool reset = FALSE; + + for(list::const_iterator resetBrush=brushList.begin(); resetBrush!=brushList.end(); resetBrush++) + { + bool tmp = (*resetBrush)->ResetTextures(textureName, fScale, fShift, rotation, newTextureName, + bResetTextureName, bResetScale, bResetShift, bResetRotation); + + if(tmp) + { + reset = TRUE; + + if(rebuild) + { + entity_t *pE = (*resetBrush)->QER_brush->owner; + g_FuncTable.m_pfnDeleteBrushHandle((*resetBrush)->QER_brush); + (*resetBrush)->BuildInRadiant(FALSE, NULL, pE->entityId == 0 ? NULL : pE); + + if( pE->entityId == 0 ? NULL : pE ) + { + } + } + } + } + + if(bResetTextureName) + { + for(list::const_iterator resetPatch=patchList.begin(); resetPatch!=patchList.end(); resetPatch++) + { + bool tmp = (*resetPatch)->ResetTextures(textureName, newTextureName); + + if(tmp) + { + reset = TRUE; + + if(rebuild) + { + entity_t *pE = (*resetPatch)->QER_brush->owner; + g_FuncTable.m_pfnDeleteBrushHandle((*resetPatch)->QER_brush); + (*resetPatch)->BuildInRadiant(pE->entityId == 0 ? NULL : pE); + } + } + } + } + + g_FuncTable.m_pfnReleaseActiveBrushHandles(); + + return reset; +} + +DEPair* DEntity::FindEPairByKey(const char* keyname) +{ + for(list::const_iterator ep=epairList.begin(); ep!=epairList.end(); ep++) + { + char* c = (*ep)->key; + if(!strcmp(c, keyname)) + return *ep; + } + return NULL; +} + +void DEntity::RemoveFromRadiant() +{ + g_EntityTable.m_pfnEntity_Free( (entity_t*)QER_Entity ); + + QER_Entity = NULL; +} + +void DEntity::SpawnString(const char* key, const char* defaultstring, const char** out) +{ + DEPair* pEP = FindEPairByKey(key); + if(pEP) { + *out = pEP->value; + } else { + *out = defaultstring; + } +} + +void DEntity::SpawnInt(const char* key, const char* defaultstring, int* out) +{ + DEPair* pEP = FindEPairByKey(key); + if(pEP) { + *out = atoi(pEP->value); + } else { + *out = atoi(defaultstring); + } +} + +void DEntity::SpawnFloat(const char* key, const char* defaultstring, float* out) +{ + DEPair* pEP = FindEPairByKey(key); + if(pEP) { + *out = static_cast< float >( atof( pEP->value ) ); + } else { + *out = static_cast< float >( atof(defaultstring) ); + } +} + +void DEntity::SpawnVector(const char* key, const char* defaultstring, vec_t* out) +{ + DEPair* pEP = FindEPairByKey(key); + if(pEP) { + sscanf(pEP->value, "%f %f %f", &out[0], &out[1], &out[2]); + } else { + sscanf(defaultstring, "%f %f %f", &out[0], &out[1], &out[2]); + } +} + +int DEntity::GetBrushCount( void ) { + return brushList.size(); +} + +DBrush* DEntity::FindBrushByPointer( brush_t* brush ) { + for(list::const_iterator listBrush = brushList.begin(); listBrush != brushList.end(); listBrush++) { + DBrush* pBrush = (*listBrush); + if(pBrush->QER_brush == brush) { + return pBrush; + } + } + return NULL; +} diff --git a/contrib/bobtoolz/DEntity.h b/contrib/bobtoolz/DEntity.h new file mode 100644 index 00000000..382e8a0f --- /dev/null +++ b/contrib/bobtoolz/DEntity.h @@ -0,0 +1,115 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DEntity.h: interface for the DEntity class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DENTITY_H__35B2C523_F0A7_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DENTITY_H__35B2C523_F0A7_11D4_ACF7_004095A18133__INCLUDED_ + +#include "DBrush.h" +#include "DEPair.h" +#include "DPatch.h" +#include "StdAfx.h" // Added by ClassView + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DEntity +{ +public: + void RemoveFromRadiant(); + entity_t* QER_Entity; + int m_nID; + +// Constrcution/Destruction + DEntity(char* classname = "worldspawn", int ID = -1); // sets classname + virtual ~DEntity(); +// --------------------------------------------- + +// epair functions........ + void LoadEPairList(epair_t* epl); + void AddEPair(char* key, char* value); + void ClearEPairs(); + DEPair* FindEPairByKey(const char* keyname); +// --------------------------------------------- + +// random functions........ + bool ResetTextures(const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation, bool rebuild); + void SaveToFile(FILE* pFile); + void SetClassname(char* classname); + int GetIDMax(); + + void BuildInRadiant(bool allowDestruction); + void ResetChecks(list* exclusionList); + void RemoveNonCheckBrushes(list* exclusionList, bool useDetail); + + DPlane* AddFaceToBrush(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* faceData, int ID); // slow, try not to use much + int GetBrushCount( void ); + DBrush* FindBrushByPointer( brush_t* brush ); +// --------------------------------------------- + + +// bool list functions + void SelectBrushes(bool* selectList); + bool* BuildDuplicateList(); + bool* BuildIntersectList(); +// --------------------------------------------- + + +// brush operations + void ClearBrushes(); // clears brush list and frees memory for brushes + + DBrush* GetBrushForID(int ID); + DBrush* NewBrush(int ID = -1); +// --------------------------------------------- + +// patch operations + void ClearPatches(); + + DPatch* NewPatch(); +// --------------------------------------------- + +// vars + list epairList; + list brushList; + // new patches, wahey!!! + list patchList; + Str m_Classname; +// --------------------------------------------- + + + int FixBrushes(bool rebuild); + + bool LoadFromEntity(int id, bool bLoadPatches = FALSE); + bool LoadFromEntity(entity_t* ent, bool bLoadPatches = FALSE); + void LoadSelectedBrushes(); + void LoadSelectedPatches(); + + bool LoadFromPrt(char* filename); +// --------------------------------------------- + void SpawnString(const char* key, const char* defaultstring, const char** out); + void SpawnInt(const char* key, const char* defaultstring, int* out); + void SpawnFloat(const char* key, const char* defaultstring, float* out); + void SpawnVector(const char* key, const char* defaultstring, vec_t* out); +}; + +#endif // !defined(AFX_DENTITY_H__35B2C523_F0A7_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DListener.cpp b/contrib/bobtoolz/DListener.cpp new file mode 100644 index 00000000..4927fe6e --- /dev/null +++ b/contrib/bobtoolz/DListener.cpp @@ -0,0 +1,93 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DListener.cpp: implementation of the DListener class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DListener.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DListener::DListener() +{ + refCount = 1; + m_bHooked = FALSE; +} + +DListener::~DListener() +{ + UnRegister(); +} + +void DListener::Register() +{ + g_MessageTable.m_pfnHookWindow( this ); + m_bHooked = TRUE; +} + +void DListener::UnRegister() +{ + if(m_bHooked) + { + g_MessageTable.m_pfnUnHookWindow( this ); + m_bHooked = FALSE; + } +} + +bool DListener::OnMouseMove(guint32 nFlags, gdouble x, gdouble y) +{ + if(!parent->UpdatePath()) + delete parent; + + return FALSE; +} + +bool DListener::OnLButtonDown(guint32 nFlags, gdouble x, gdouble y) +{ + return FALSE; +} + +bool DListener::OnLButtonUp(guint32 nFlags, gdouble x, gdouble y) +{ + return FALSE; +} + +bool DListener::OnRButtonDown(guint32 nFlags, gdouble x, gdouble y) +{ + return FALSE; +} + +bool DListener::OnRButtonUp(guint32 nFlags, gdouble x, gdouble y) +{ + return FALSE; +} + +bool DListener::OnMButtonDown(guint32 nFlags, gdouble x, gdouble y) +{ + return FALSE; +} + +bool DListener::OnMButtonUp(guint32 nFlags, gdouble x, gdouble y) +{ + return FALSE; +} diff --git a/contrib/bobtoolz/DListener.h b/contrib/bobtoolz/DListener.h new file mode 100644 index 00000000..0ef20577 --- /dev/null +++ b/contrib/bobtoolz/DListener.h @@ -0,0 +1,62 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DListener.h: interface for the DListener class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DLISTENER_H__53EBE342_F0B2_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DLISTENER_H__53EBE342_F0B2_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +#include "DBobView.h" + +class DListener : public IWindowListener +{ +public: + DBobView* parent; + + bool OnMouseMove(guint32 nFlags, gdouble x, gdouble y); + bool OnLButtonDown(guint32 nFlags, gdouble x, gdouble y); + bool OnMButtonDown(guint32 nFlags, gdouble x, gdouble y); + bool OnRButtonDown(guint32 nFlags, gdouble x, gdouble y); + bool OnLButtonUp(guint32 nFlags, gdouble x, gdouble y); + bool OnMButtonUp(guint32 nFlags, gdouble x, gdouble y); + bool OnRButtonUp(guint32 nFlags, gdouble x, gdouble y); + bool OnKeyPressed(char *s) { return false; } + bool Paint() { return true; } + void Close() { } + + void UnRegister(); + void Register(); + DListener(); + virtual ~DListener(); + + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + +private: + bool m_bHooked; + int refCount; +}; + +#endif // !defined(AFX_DLISTENER_H__53EBE342_F0B2_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DMap.cpp b/contrib/bobtoolz/DMap.cpp new file mode 100644 index 00000000..e827690f --- /dev/null +++ b/contrib/bobtoolz/DMap.cpp @@ -0,0 +1,166 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DMap.cpp: implementation of the DMap class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DMap.h" + + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DMap::DMap() +{ + m_nNextEntity = 1; + AddEntity("worldspawn", 0); +} + +DMap::~DMap() +{ + ClearEntities(); +} + +DEntity* DMap::AddEntity(char *classname, int ID) +{ + DEntity* newEntity; + if(ID == -1) + newEntity = new DEntity(classname, m_nNextEntity++); + else + newEntity = new DEntity(classname, ID); + + entityList.push_back(newEntity); + + return newEntity; +} + +void DMap::ClearEntities() +{ + m_nNextEntity = 1; + + for(list::const_iterator deadEntity=entityList.begin(); deadEntity!=entityList.end(); deadEntity++) + delete *deadEntity; + + entityList.clear(); +} + +DEntity* DMap::GetEntityForID(int ID) +{ + DEntity* findEntity = NULL; + + for(list::const_iterator chkEntity=entityList.begin(); chkEntity!=entityList.end(); chkEntity++) + { + if((*chkEntity)->m_nID == ID) + { + findEntity = (*chkEntity); + break; + } + } + + if(!findEntity) + findEntity = AddEntity("worldspawn", ID); + + return findEntity; +} + + +DEntity* DMap::GetWorldSpawn() +{ + return GetEntityForID(0); +} + +void DMap::BuildInRadiant(bool bAllowDestruction) +{ + for(list::const_iterator buildEntity=entityList.begin(); buildEntity!=entityList.end(); buildEntity++) + (*buildEntity)->BuildInRadiant(bAllowDestruction); +} + +void DMap::LoadAll(bool bLoadPatches) +{ + ClearEntities(); + + g_FuncTable.m_pfnDeselectAllBrushes(); + + int count = g_FuncTable.m_pfnGetEntityCount(); + + for(int i = 0; i < count; i++) + { + DEntity* loadEntity; + + if(i == 0) + loadEntity = GetWorldSpawn(); + else + loadEntity = AddEntity("", m_nNextEntity++); + + if(!loadEntity->LoadFromEntity(i, bLoadPatches)) + { + delete loadEntity; + entityList.pop_back(); + } + } +} + +int DMap::FixBrushes(bool rebuild) +{ + int count = 0; + for(list::const_iterator fixEntity=entityList.begin(); fixEntity!=entityList.end(); fixEntity++) + { + int cnt; + + if(!stricmp("worldspawn", (*fixEntity)->m_Classname)) + cnt = (*fixEntity)->FixBrushes(rebuild); + else + { + cnt = (*fixEntity)->FixBrushes(FALSE); + + if(cnt && rebuild) + RebuildEntity(*fixEntity); + } + + count += cnt; + } + + return count; +} + +void DMap::ResetTextures( const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, + int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation) +{ + for(list::const_iterator texEntity=entityList.begin(); texEntity!=entityList.end(); texEntity++) + { + if(!stricmp("worldspawn", (*texEntity)->m_Classname)) + (*texEntity)->ResetTextures(textureName, fScale, fShift, rotation, newTextureName, + bResetTextureName, bResetScale, bResetShift, bResetRotation, TRUE); + else + { + if((*texEntity)->ResetTextures( textureName, fScale, fShift, rotation, newTextureName, + bResetTextureName, bResetScale, bResetShift, bResetRotation, FALSE)) + RebuildEntity(*texEntity); + } + } +} + +void DMap::RebuildEntity(DEntity *ent) +{ + ent->RemoveFromRadiant(); + ent->BuildInRadiant(FALSE); +} diff --git a/contrib/bobtoolz/DMap.h b/contrib/bobtoolz/DMap.h new file mode 100644 index 00000000..1f814c23 --- /dev/null +++ b/contrib/bobtoolz/DMap.h @@ -0,0 +1,56 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DMap.h: interface for the DMap class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DMAP_H__ACAE597A_D26D_49AD_AA69_EDE743DB54FA__INCLUDED_) +#define AFX_DMAP_H__ACAE597A_D26D_49AD_AA69_EDE743DB54FA__INCLUDED_ + +#include "DEntity.h" + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DMap +{ +public: + static void RebuildEntity(DEntity* ent); + + void ResetTextures( const char* textureName, float fScale[2], float fShift[2], int rotation, const char* newTextureName, int bResetTextureName, int bResetScale[2], int bResetShift[2], int bResetRotation); + void LoadAll(bool bLoadPatches = FALSE); + void BuildInRadiant(bool bAllowDestruction); + int m_nNextEntity; + DEntity* GetWorldSpawn(); + void ClearEntities(); + + DEntity* DMap::GetEntityForID(int ID); + DEntity* AddEntity(char* classname = "worldspawn", int ID = -1); + + list entityList; + + DMap(); + virtual ~DMap(); + + int FixBrushes(bool rebuild); +}; + +#endif // !defined(AFX_DMAP_H__ACAE597A_D26D_49AD_AA69_EDE743DB54FA__INCLUDED_) diff --git a/contrib/bobtoolz/DPatch.cpp b/contrib/bobtoolz/DPatch.cpp new file mode 100644 index 00000000..161420f3 --- /dev/null +++ b/contrib/bobtoolz/DPatch.cpp @@ -0,0 +1,414 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DPatch.cpp: implementation of the DPatch class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DPatch.h" +#include "misc.h" +#include "./dialogs/dialogs-gtk.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +// Added patch merging, wahey! + +// +// problem is, you cant put patches into entities as yet :( +// + +DPatch::DPatch() +{ + width = MIN_PATCH_WIDTH; + height = MIN_PATCH_HEIGHT; + QER_patch = NULL; + QER_brush = NULL; +} + +DPatch::~DPatch() +{ + +} + +void DPatch::SetTexture(const char *textureName) +{ + strcpy(texture, textureName); +} + +void CopyDrawVert(const drawVert_t* in, drawVert_t* out) +{ + out->lightmap[0] = in->lightmap[0]; + out->lightmap[1] = in->lightmap[1]; + out->st[0] = in->st[0]; + out->st[1] = in->st[1]; + VectorCopy(in->normal, out->normal); + VectorCopy(in->xyz, out->xyz); +} + +void DPatch::BuildInRadiant(void* entity) +{ + int nIndex = g_FuncTable.m_pfnCreatePatchHandle(); + //$ FIXME: m_pfnGetPatchHandle + patchMesh_t* pm = g_FuncTable.m_pfnGetPatchData(nIndex); + + pm->height = height; + pm->width = width; + + for(int x = 0; x < width; x++) + for(int y = 0; y < height; y++) + CopyDrawVert(&points[x][y], &pm->ctrl[x][y]); + + QER_patch = pm; + +/* if(entity) + { +// strcpy(pm->d_texture->name, texture); + + brush_t* brush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + brush->patchBrush = TRUE; + brush->pPatch = pm; + + pm->pSymbiot = brush; + pm->bSelected = false; + pm->bOverlay = false; // bleh, f*cks up, just have to wait for a proper function + pm->bDirty = true; // or get my own patch out.... + pm->nListID = -1; + + g_FuncTable.m_pfnCommitBrushHandleToEntity(brush, entity); + } + else*/ // patch to entity just plain dont work atm + + if(entity) + g_FuncTable.m_pfnCommitPatchHandleToEntity(nIndex, pm, texture, entity); + else + g_FuncTable.m_pfnCommitPatchHandleToMap(nIndex, pm, texture); + + QER_brush = pm->pSymbiot; +} + +void DPatch::LoadFromBrush_t(brush_t* brush) +{ + QER_brush = brush; + QER_patch = brush->pPatch; + + SetTexture(QER_patch->pShader->getName()); + + for(int x = 0; x < QER_patch->width; x++) + for(int y = 0; y < QER_patch->height; y++) + CopyDrawVert(&QER_patch->ctrl[x][y], &points[x][y]); + + width = QER_patch->width; + height = QER_patch->height; +} + +void DPatch::RemoveFromRadiant() +{ + if(QER_brush) + g_FuncTable.m_pfnDeleteBrushHandle(QER_brush); +} + +bool DPatch::ResetTextures(const char *oldTextureName, const char *newTextureName) +{ + if( !oldTextureName || !strcmp(texture, oldTextureName)) + { + strcpy(texture, newTextureName); + return TRUE; + } + + return FALSE; +} + +void Build1dArray(vec3_t* array, drawVert_t points[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT], + int startX, int startY, int number, bool horizontal, bool inverse) +{ + int x = startX, y = startY, i, step; + + if(inverse) + step = -1; + else + step = 1; + + for(i = 0; i < number; i++) + { + VectorCopy(points[x][y].xyz, array[i]); + + if(horizontal) + x+=step; + else + y+=step; + } +} + +void Print1dArray(vec3_t* array, int size) +{ + for(int i = 0; i < size; i++) + Sys_Printf("(%.0f %.0f %.0f)\t", array[i][0], array[i][1], array[i][2]); + Sys_Printf("\n"); +} + +bool Compare1dArrays(vec3_t* a1, vec3_t* a2, int size) +{ + int i; + bool equal = true; + + for(i = 0; i < size; i++) + { + if(!VectorCompare(a1[i], a2[size-i-1])) + { + equal = false; + break; + } + } + return equal; +} + +patch_merge_t DPatch::IsMergable(DPatch *other) +{ + int i, j; + vec3_t p1Array[4][MAX_PATCH_HEIGHT]; + vec3_t p2Array[4][MAX_PATCH_HEIGHT]; + + int p1ArraySizes[4]; + int p2ArraySizes[4]; + + patch_merge_t merge_info; + + Build1dArray(p1Array[0], this->points, 0, 0, this->width, true, false); + Build1dArray(p1Array[1], this->points, this->width-1, 0, this->height, false, false); + Build1dArray(p1Array[2], this->points, this->width-1, this->height-1, this->width, true, true); + Build1dArray(p1Array[3], this->points, 0, this->height-1, this->height, false, true); + + Build1dArray(p2Array[0], other->points, 0, 0, other->width, true, false); + Build1dArray(p2Array[1], other->points, other->width-1, 0, other->height, false, false); + Build1dArray(p2Array[2], other->points, other->width-1, other->height-1, other->width, true, true); + Build1dArray(p2Array[3], other->points, 0, other->height-1, other->height, false, true); + + p1ArraySizes[0] = this->width; + p1ArraySizes[1] = this->height; + p1ArraySizes[2] = this->width; + p1ArraySizes[3] = this->height; + + p2ArraySizes[0] = other->width; + p2ArraySizes[1] = other->height; + p2ArraySizes[2] = other->width; + p2ArraySizes[3] = other->height; + + for(i = 0; i < 4; i++) + { + for(j = 0; j < 4; j++) + { + if(p1ArraySizes[i] == p2ArraySizes[j]) + { + if(Compare1dArrays(p1Array[i], p2Array[j], p1ArraySizes[i])) + { + merge_info.pos1 = i; + merge_info.pos2 = j; + merge_info.mergable = true; + return merge_info; + } + } + } + } + + merge_info.mergable = false; + return merge_info; +} + +DPatch* DPatch::MergePatches(patch_merge_t merge_info, DPatch *p1, DPatch *p2) +{ + while(merge_info.pos1 != 2) + { + p1->Transpose(); + merge_info.pos1--; + if(merge_info.pos1 < 0) + merge_info.pos1 += 4; + } + + while(merge_info.pos2 != 0) + { + p2->Transpose(); + merge_info.pos2--; + if(merge_info.pos2 < 0) + merge_info.pos2 += 3; + } + + int newHeight = p1->height + p2->height - 1; + if(newHeight > MAX_PATCH_HEIGHT) + return NULL; + + DPatch* newPatch = new DPatch(); + + newPatch->height = newHeight; + newPatch->width = p1->width; + newPatch->SetTexture(p1->texture); + + int y = 0; + int i; + for(i = 0; i < p1->height; i++, y++) + for(int x = 0; x < p1->width; x++) + memcpy(&newPatch->points[x][y], &p1->points[x][i], sizeof(drawVert_t)); + + for(i = 1; i < p2->height; i++, y++) + for(int x = 0; x < p2->width; x++) + memcpy(&newPatch->points[x][y], &p2->points[x][i], sizeof(drawVert_t)); + +// newPatch->Invert(); + + return newPatch; +} + +void DPatch::Invert() +{ + drawVert_t vertTemp; + int i, j; + + for(i = 0 ; i < width ; i++ ) + { + for(j = 0; j < height / 2; j++) + { + memcpy(&vertTemp, &points[i][height - 1- j], sizeof (drawVert_t)); + memcpy(&points[i][height - 1 - j], &points[i][j], sizeof(drawVert_t)); + memcpy(&points[i][j], &vertTemp, sizeof(drawVert_t)); + } + } +} + +void DPatch::Transpose() +{ + int i, j, w; + drawVert_t dv; + + if ( width > height ) + { + for ( i = 0 ; i < height ; i++ ) + { + for ( j = i + 1 ; j < width ; j++ ) + { + if ( j < height ) + { + // swap the value + memcpy(&dv, &points[j][i], sizeof(drawVert_t)); + memcpy(&points[j][i], &points[i][j], sizeof(drawVert_t)); + memcpy(&points[i][j], &dv, sizeof(drawVert_t)); + } + else + { + // just copy + memcpy(&points[i][j], &points[j][i], sizeof(drawVert_t)); + } + } + } + } + else + { + for ( i = 0 ; i < width ; i++ ) + { + for ( j = i + 1 ; j < height ; j++ ) + { + if ( j < width ) + { + // swap the value + memcpy(&dv, &points[i][j], sizeof(drawVert_t)); + memcpy(&points[i][j], &points[j][i], sizeof(drawVert_t)); + memcpy(&points[j][i], &dv, sizeof(drawVert_t)); + } + else + { + // just copy + memcpy(&points[j][i], &points[i][j], sizeof(drawVert_t)); + } + } + } + } + + w = width; + width = height; + height = w; + + Invert(); +} + +list DPatch::Split(bool rows, bool cols) +{ + list patchList; + int i; + int x, y; + + if(rows && height >= 5) + { + for(i = 0; i < (height-1)/2; i++) + { + DPatch p; + + p.width = width; + p.height = 3; + p.SetTexture(texture); + + for(y = 0; y < 3; y++) + { + for(x = 0; x < p.width; x++) + { + memcpy(&p.points[x][y], &points[x][(i*2)+y], sizeof(drawVert_t)); + } + } + patchList.push_back(p); + } + + if(cols && width >= 5) + { + list patchList2; + + for(list::iterator patches = patchList.begin(); patches != patchList.end(); patches++) + { + list patchList3 = (*patches).Split(false, true); + + for(list::iterator patches2 = patchList3.begin(); patches2 != patchList3.end(); patches2++) + patchList2.push_front(*patches2); + } + + return patchList2; + } + } + else if(cols && width >= 5) + { + for(i = 0; i < (width-1)/2; i++) + { + DPatch p; + + p.height = height; + p.width = 3; + p.SetTexture(texture); + + for(x = 0; x < 3; x++) + { + for(y = 0; y < p.height; y++) + { + memcpy(&p.points[x][y], &points[(i*2)+x][y], sizeof(drawVert_t)); + } + } + + patchList.push_back(p); + } + } + + return patchList; +} diff --git a/contrib/bobtoolz/DPatch.h b/contrib/bobtoolz/DPatch.h new file mode 100644 index 00000000..d04121ea --- /dev/null +++ b/contrib/bobtoolz/DPatch.h @@ -0,0 +1,62 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DPatch.h: interface for the DPatch class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DPATCH_H__26C6B083_CE5B_420B_836B_1DDA733C04CE__INCLUDED_) +#define AFX_DPATCH_H__26C6B083_CE5B_420B_836B_1DDA733C04CE__INCLUDED_ + +#include "StdAfx.h" // Added by ClassView +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +typedef struct +{ + bool mergable; + int pos1; + int pos2; +} patch_merge_t; + +class DPatch +{ +public: + list Split(bool rows, bool cols); + void Transpose(); + void Invert(); + DPatch* MergePatches(patch_merge_t merge_info, DPatch* p1, DPatch* p2); + patch_merge_t IsMergable(DPatch* other); + bool ResetTextures(const char *oldTextureName, const char *newTextureName); + void RemoveFromRadiant(void); + brush_t* QER_brush; + void LoadFromBrush_t(brush_t* brush); + patchMesh_t* QER_patch; + void BuildInRadiant(void* entity = NULL); + void SetTexture(const char* textureName); + char texture[256]; + int width, height; + drawVert_t points[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT]; + DPatch(); + virtual ~DPatch(); + +}; + +#endif // !defined(AFX_DPATCH_H__26C6B083_CE5B_420B_836B_1DDA733C04CE__INCLUDED_) diff --git a/contrib/bobtoolz/DPlane.cpp b/contrib/bobtoolz/DPlane.cpp new file mode 100644 index 00000000..2fe24ecf --- /dev/null +++ b/contrib/bobtoolz/DPlane.cpp @@ -0,0 +1,256 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DPlane.cpp: implementation of the DPlane class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DPlane.h" +#include "DWinding.h" +#include "misc.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DPlane::DPlane(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* texData) +{ + MakeNormal( va, vb, vc, normal ); + if(VectorNormalize(normal, normal) == 0) // normalizes and returns length + Sys_ERROR("DPlane::DPlane: Bad Normal.\n"); + + _d = (normal[0]*va[0]) + (normal[1]*va[1]) + (normal[2]*va[2]); + + VectorCopy(va, points[0]); + VectorCopy(vb, points[1]); + VectorCopy(vc, points[2]); + + m_bChkOk = TRUE; + + if(texData) + memcpy(&texInfo, texData, sizeof(_QERFaceData)); + else + FillDefaultTexture(&texInfo, points[0], points[1], points[2], "textures/common/caulk"); +} + +DPlane::~DPlane() +{ + +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +vec_t DPlane::DistanceToPoint(vec3_t pnt) +{ + vec3_t tmp; + VectorSubtract(pnt, points[0], tmp); + return DotProduct(tmp, normal); +} + +bool DPlane::PlaneIntersection(DPlane *pl1, DPlane *pl2, vec3_t out) +{ + float a1, a2, a3; + float b1, b2, b3; + float c1, c2, c3; + + a1 = normal[0]; a2 = normal[1]; a3 = normal[2]; + b1 = pl1->normal[0]; b2 = pl1->normal[1]; b3 = pl1->normal[2]; + c1 = pl2->normal[0]; c2 = pl2->normal[1]; c3 = pl2->normal[2]; + + float d = Determinant3x3(a1, a2, a3, b1, b2, b3, c1, c2, c3); + + if(d == 0) + return FALSE; + + float v1 = _d; + float v2 = pl1->_d; + float v3 = pl2->_d; + + float d1 = Determinant3x3(v1, a2, a3, v2, b2, b3, v3, c2, c3); + float d2 = Determinant3x3(a1, v1, a3, b1, v2, b3, c1, v3, c3); + float d3 = Determinant3x3(a1, a2, v1, b1, b2, v2, c1, c2, v3); + + out[0] = d1/d; + out[1] = d2/d; + out[2] = d3/d; + + return TRUE; +} + +bool DPlane::IsRedundant(list& pointList) +{ + int cnt = 0; + + //list::const_iterator point=pointList.begin(); + for(list::const_iterator point=pointList.begin(); point!=pointList.end(); point++) + { + if(fabs(DistanceToPoint((*point)->_pnt)) < MAX_ROUND_ERROR) + cnt++; + + if(cnt == 3) + return FALSE; + } + return TRUE; +} + +bool DPlane::operator == (DPlane& other) +{ + vec3_t chk; + VectorSubtract(other.normal, normal, chk); + if(fabs(VectorLength(chk)) > MAX_ROUND_ERROR) + return FALSE; + + if(fabs(other._d - _d) > MAX_ROUND_ERROR) + return FALSE; + + return TRUE; +} + +bool DPlane::operator != (DPlane& other) +{ + vec3_t chk; + VectorAdd(other.normal, normal, chk); + if(fabs(VectorLength(chk)) > MAX_ROUND_ERROR) + return FALSE; + + return TRUE; +} + +DWinding* DPlane::BaseWindingForPlane() +{ + int i, x; + vec_t max, v; + vec3_t org, vright, vup; + +// find the major axis + + max = -131072; + x = -1; + for (i=0 ; i<3; i++) + { + v = (float)fabs(normal[i]); + if (v > max) + { + x = i; + max = v; + } + } + if (x==-1) + Sys_Printf ("BaseWindingForPlane: no axis found"); + + VectorCopy (vec3_origin, vup); + switch (x) + { + case 0: + case 1: + vup[2] = 1; + break; + case 2: + vup[0] = 1; + break; + } + + v = DotProduct (vup, normal); + VectorMA (vup, -v, normal, vup); + VectorNormalize (vup, vup); + + VectorScale (normal, _d, org); + + CrossProduct (vup, normal, vright); + + VectorScale (vup, 131072, vup); + VectorScale (vright, 131072, vright); + +// project a really big axis aligned box onto the plane + DWinding* w = new DWinding; + w->AllocWinding(4); + + VectorSubtract (org, vright, w->p[0]); + VectorAdd (w->p[0], vup, w->p[0]); + + VectorAdd (org, vright, w->p[1]); + VectorAdd (w->p[1], vup, w->p[1]); + + VectorAdd (org, vright, w->p[2]); + VectorSubtract (w->p[2], vup, w->p[2]); + + VectorSubtract (org, vright, w->p[3]); + VectorSubtract (w->p[3], vup, w->p[3]); + + return w; +} + +void DPlane::Rebuild() +{ + vec3_t v1, v2; + VectorSubtract(points[0], points[1], v1); + VectorSubtract(points[2], points[1], v2); + CrossProduct(v1, v2, normal); + + if(VectorNormalize(normal, normal) == 0) // normalizes and returns length + Sys_ERROR("DPlane::Rebuild: Bad Normal.\n"); + + _d = (normal[0]*points[0][0]) + (normal[1]*points[0][1]) + (normal[2]*points[0][2]); + + VectorCopy(points[0], texInfo.m_v1); + VectorCopy(points[1], texInfo.m_v2); + VectorCopy(points[2], texInfo.m_v3); +} + +bool DPlane::AddToBrush_t(brush_t *brush) +{ + if(m_bChkOk || !strcmp(texInfo.m_TextureName, "textures/common/caulk")) + { + g_FuncTable.m_pfnAddFaceData(brush, &texInfo); + return FALSE; + } + + strcpy(texInfo.m_TextureName, "textures/common/caulk"); + g_FuncTable.m_pfnAddFaceData(brush, &texInfo); + return TRUE; +} + +void DPlane::ScaleTexture() +{ } + +DPlane::DPlane(vec3_t va, vec3_t vb, vec3_t vc, const char* textureName, bool bDetail) +{ + vec3_t v1, v2; + VectorSubtract(va, vb, v1); + VectorSubtract(vc, vb, v2); + CrossProduct(v1, v2, normal); + + if(VectorNormalize(normal, normal) == 0) // normalizes and returns length + Sys_ERROR("DPlane::DPlane: Bad Normal.\n"); + + _d = (normal[0]*va[0]) + (normal[1]*va[1]) + (normal[2]*va[2]); + + VectorCopy(va, points[0]); + VectorCopy(vb, points[1]); + VectorCopy(vc, points[2]); + + m_bChkOk = TRUE; + + FillDefaultTexture(&texInfo, points[0], points[1], points[2], textureName); + if(bDetail) + texInfo.m_nContents |= FACE_DETAIL; +} diff --git a/contrib/bobtoolz/DPlane.h b/contrib/bobtoolz/DPlane.h new file mode 100644 index 00000000..4399b841 --- /dev/null +++ b/contrib/bobtoolz/DPlane.h @@ -0,0 +1,67 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DPlane.h: interface for the DPlane class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DPLANE_H__FC37C021_F0A1_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DPLANE_H__FC37C021_F0A1_11D4_ACF7_004095A18133__INCLUDED_ + +#include "DPoint.h" + +#define FACE_DETAIL 0x8000000 + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DWinding; + +class DPlane +{ +public: + DPlane(vec3_t va, vec3_t vb, vec3_t vc, const char* textureName, bool bDetail); + void ScaleTexture(); + DWinding* BaseWindingForPlane(); + + void Rebuild(); + + bool AddToBrush_t(brush_t *brush); + bool operator != (DPlane& other); + bool operator == (DPlane& other); + + bool IsRedundant(list& pointList); + bool PlaneIntersection(DPlane* pl1, DPlane* pl2, vec3_t out);; + + vec_t DistanceToPoint(vec3_t pnt); + + DPlane(vec3_t va, vec3_t vb, vec3_t vc, _QERFaceData* texData); + DPlane() { } + virtual ~DPlane(); + + bool m_bChkOk; + _QERFaceData texInfo; + vec3_t points[3]; // djbob:do we really need these any more? + vec3_t normal; + float _d; +}; + +//typedef CList DPlaneList; +#endif // !defined(AFX_DPLANE_H__FC37C021_F0A1_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DPoint.cpp b/contrib/bobtoolz/DPoint.cpp new file mode 100644 index 00000000..e99911fd --- /dev/null +++ b/contrib/bobtoolz/DPoint.cpp @@ -0,0 +1,52 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DPoint.cpp: implementation of the DPoint class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DPoint.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DPoint::DPoint() +{ + +} + +DPoint::~DPoint() +{ + +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +bool DPoint::operator ==(vec3_t other) +{ + vec3_t test; + VectorSubtract(other, _pnt, test); + if(fabs(VectorLength(test)) > MAX_ROUND_ERROR) + return FALSE; + return TRUE; +} diff --git a/contrib/bobtoolz/DPoint.h b/contrib/bobtoolz/DPoint.h new file mode 100644 index 00000000..22ae70bc --- /dev/null +++ b/contrib/bobtoolz/DPoint.h @@ -0,0 +1,45 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DPoint.h: interface for the DPoint class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DPOINT_H__FC37C022_F0A1_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DPOINT_H__FC37C022_F0A1_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DPoint +{ +public: + DPoint(); + virtual ~DPoint(); + + bool operator ==(vec3_t other); + + vec3_t _pnt; + unsigned char m_uData; +}; + +//typedef CList DPointList; + +#endif // !defined(AFX_DPOINT_H__FC37C022_F0A1_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DShape.cpp b/contrib/bobtoolz/DShape.cpp new file mode 100644 index 00000000..83e68659 --- /dev/null +++ b/contrib/bobtoolz/DShape.cpp @@ -0,0 +1,459 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DShape.cpp: implementation of the DShape class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DShape.h" + +//#include "dialogs-gtk.h" + +#include "misc.h" +#include "shapes.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +bool bFacesAll[6] = {TRUE, TRUE, TRUE, TRUE, TRUE, TRUE}; + +DShape::DShape() +{ + m_nNextBrush = 0; +} + +DShape::~DShape() +{ + +} + +void DShape::BuildRegularPrism(vec3_t min, vec3_t max, int nSides, bool bAlignTop) +{ + vec3_t vc[MAX_POLYGON_FACES+2], vd[MAX_POLYGON_FACES+2]; + + vec3_t radius; + vec3_t origin; + + VectorSubtract(max, min, radius); + VectorScale(radius, 0.5f, radius); + // calc 3d radius and origin + VectorAdd(max, min, origin); + VectorScale(origin, 0.5f, origin); + + float phase = 0.0f; + + if(bAlignTop) + { + phase = -(Q_PI/nSides); + VectorScale(radius, static_cast< float >( 1/cos(phase) ), radius); + } + + //----- Build Polygon Vertices ----- + + int i; + for(i = 0; i < nSides; i++) + { + VectorCopy(origin, vc[i]); + VectorCopy(origin, vd[i]); + + vc[i][2] = min[2]; + vd[i][2] = max[2]; + + vc[i][0] += radius[0] * sinf( ( 2 * Q_PI * i / nSides ) + phase ); + vc[i][1] += radius[1] * cosf( ( 2 * Q_PI * i / nSides ) + phase ); + + vd[i][0] = vc[i][0]; + vd[i][1] = vc[i][1]; + } + + VectorCopy(vc[0], vc[nSides]); + VectorCopy(vd[0], vd[nSides]); + VectorCopy(vc[1], vc[nSides+1]); + VectorCopy(vd[1], vd[nSides+1]); + + //---------------------------------- + + DBrush* pB = m_Container.GetWorldSpawn()->NewBrush(m_nNextBrush++); + + for(i = 1; i <= nSides; i++) + pB->AddFace(vc[i-1], vc[i], vd[i], GetCurrentTexture(), FALSE); + + pB->AddFace(vc[2], vc[1], vc[0], "textures/common/caulk", FALSE); + pB->AddFace(vd[0], vd[1], vd[2], "textures/common/caulk", FALSE); +} + +void DShape::Commit() +{ + m_Container.GetWorldSpawn()->FixBrushes(FALSE); + m_Container.BuildInRadiant(TRUE); +} + +void DShape::BuildInversePrism(vec3_t min, vec3_t max, int nSides, bool bAlignTop) +{ + vec3_t va[MAX_POLYGON_FACES+1], vb[MAX_POLYGON_FACES+1]; + vec3_t radius; + vec3_t origin; + + VectorSubtract(max, min, radius); + VectorScale(radius, 0.5f, radius); + // calc 3d radius and origin + VectorAdd(max, min, origin); + VectorScale(origin, 0.5f, origin); + + float phase = 0.0f; + + if(bAlignTop) + { + phase = -(Q_PI/nSides); + VectorScale(radius, static_cast< float >( 1/cos(phase) ), radius); + } + + //----- Build Polygon Vertices ----- + + int i; + for(i = 0; i < nSides; i++) + { + VectorCopy(origin, va[i]); + VectorCopy(origin, vb[i]); + + va[i][2] = min[2]; + vb[i][2] = max[2]; + + va[i][0] += radius[0] * sinf( ( 2 * Q_PI * i / nSides ) + phase ); + va[i][1] += radius[1] * cosf( ( 2 * Q_PI * i / nSides ) + phase ); + + vb[i][0] = va[i][0]; + vb[i][1] = va[i][1]; + } + + VectorCopy(va[0], va[nSides]); + VectorCopy(vb[0], vb[nSides]); + + //---------------------------------- + + for(i = 1; i <= nSides; i++) + { + DBrush* pB = GetBoundingCube(min, max, "textures/common/caulk"); + + vec3_t top, bottom; + VectorCopy(va[i-1], top); + VectorCopy(va[i], bottom); + + if(va[i-1][1] > va[i][1]) + { + top[0] += 5; + bottom[0] += 5; + } + else // flip direction of plane on crossover + { + top[0] -= 5; + bottom[0] -= 5; + } + + if(top[1] != bottom[1]) // internal line is flat already if true + { + pB->AddFace(va[i-1], top, vb[i-1], "textures/common/caulk", FALSE); + pB->AddFace(va[i], vb[i], bottom, "textures/common/caulk", FALSE); + } // add cut-off planes + + pB->AddFace(va[i-1], vb[i-1], vb[i], GetCurrentTexture(), FALSE); + // add internal polygon plane + } +} + +void DShape::BuildBorderedPrism(vec3_t min, vec3_t max, int nSides, int nBorder, bool bAlignTop) +{ + vec3_t va[MAX_POLYGON_FACES+2], vb[MAX_POLYGON_FACES+2]; + vec3_t vc[MAX_POLYGON_FACES+2], vd[MAX_POLYGON_FACES+2]; + + vec3_t radius; + vec3_t origin; + + VectorSubtract(max, min, radius); + VectorScale(radius, 0.5f, radius); + // calc 3d radius and origin + VectorAdd(max, min, origin); + VectorScale(origin, 0.5f, origin); + + if(nBorder >= Min(radius[0], radius[1])) + { +// DoMessageBox("Border is too large", "Error", MB_OK); + return; + } + + float phase = 0.0f; + + if(bAlignTop) + { + phase = -(Q_PI/nSides); + VectorScale(radius, static_cast< float >( 1/cos(phase) ), radius); + } + + //----- Build Polygon Vertices ----- + + int i; + for(i = 0; i < nSides; i++) + { + VectorCopy(origin, va[i]); + VectorCopy(origin, vb[i]); + VectorCopy(origin, vc[i]); + VectorCopy(origin, vd[i]); + + va[i][2] = min[2]; + vb[i][2] = max[2]; + + va[i][0] += (radius[0] - nBorder) * sinf( ( 2 * Q_PI * i / nSides ) + phase ); + va[i][1] += (radius[1] - nBorder) * cosf( ( 2 * Q_PI * i / nSides ) + phase ); + + vb[i][0] = va[i][0]; + vb[i][1] = va[i][1]; + + + + vc[i][2] = min[2]; + vd[i][2] = max[2]; + + vc[i][0] += radius[0] * sinf( ( 2 * Q_PI * i / nSides ) + phase ); + vc[i][1] += radius[1] * cosf( ( 2 * Q_PI * i / nSides ) + phase ); + + vd[i][0] = vc[i][0]; + vd[i][1] = vc[i][1]; + } + + VectorCopy(va[0], va[nSides]); + VectorCopy(vb[0], vb[nSides]); + VectorCopy(va[1], va[nSides+1]); + VectorCopy(vb[1], vb[nSides+1]); + + VectorCopy(vc[0], vc[nSides]); + VectorCopy(vd[0], vd[nSides]); + VectorCopy(vc[1], vc[nSides+1]); + VectorCopy(vd[1], vd[nSides+1]); + + //---------------------------------- + + for(i = 1; i <= nSides; i++) + { + DBrush* pB = GetBoundingCube(min, max, "textures/common/caulk"); + + pB->AddFace(origin, vc[i-1], vd[i-1], "textures/common/caulk", FALSE); + pB->AddFace(origin, vd[i], vc[i], "textures/common/caulk", FALSE); + + pB->AddFace(vc[i-1], vc[i], vd[i], GetCurrentTexture(), FALSE); + pB->AddFace(vb[i], va[i], va[i-1], GetCurrentTexture(), FALSE); + } +} + +DBrush* DShape::GetBoundingCube_Ext(vec3_t min, vec3_t max, const char *textureName, bool* bUseFaces, bool detail) +{ + DBrush* pB = new DBrush; + //----- Build Outer Bounds --------- + + vec3_t v1, v2, v3, v5, v6, v7; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + + //---------------------------------- + + //----- Add Six Cube Faces --------- + + if(bUseFaces[0]) + pB->AddFace(v1, v2, v3, textureName, detail); + if(bUseFaces[1]) + pB->AddFace(v1, v3, v6, textureName, detail); + if(bUseFaces[2]) + pB->AddFace(v1, v7, v2, textureName, detail); + + if(bUseFaces[3]) + pB->AddFace(v5, v6, v3, textureName, detail); + if(bUseFaces[4]) + pB->AddFace(v5, v2, v7, textureName, detail); + if(bUseFaces[5]) + pB->AddFace(v5, v7, v6, textureName, detail); + + //---------------------------------- + + return pB; +} + +DBrush* DShape::GetBoundingCube(vec3_t min, vec3_t max, const char *textureName, DEntity* ent, bool* bUseFaces) +{ + DBrush* pB; + if(ent == NULL) + pB = m_Container.GetWorldSpawn()->NewBrush(m_nNextBrush++); + else + pB = ent->NewBrush(m_nNextBrush++); + + //----- Build Outer Bounds --------- + + vec3_t v1, v2, v3, v5, v6, v7; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + + //---------------------------------- + + //----- Add Six Cube Faces --------- + + if(bUseFaces[0]) + pB->AddFace(v1, v2, v3, textureName, FALSE); + if(bUseFaces[1]) + pB->AddFace(v1, v3, v6, textureName, FALSE); + if(bUseFaces[2]) + pB->AddFace(v1, v7, v2, textureName, FALSE); + + if(bUseFaces[3]) + pB->AddFace(v5, v6, v3, textureName, FALSE); + if(bUseFaces[4]) + pB->AddFace(v5, v2, v7, textureName, FALSE); + if(bUseFaces[5]) + pB->AddFace(v5, v7, v6, textureName, FALSE); + + //---------------------------------- + + return pB; +} + +bool DShape::BuildPit(vec3_t min, vec3_t max) +{ + if((max[2] - min[2]) < 196) + return FALSE; + + srand(time(NULL)); + + vec3_t centre; + VectorAdd(min, max, centre); + VectorScale(centre, 0.5f, centre); + + char buffer[256]; + + int team = (rand()%10000)+5000; + +// ************* SPEAKER *************** + sprintf(buffer, "t%i_1", team); + +// trigger for speaker + vec3_t triggerVoiceBtm; + VectorCopy(min, triggerVoiceBtm); + triggerVoiceBtm[2] = max[2] - 16; + + DEntity* triggerVoice = m_Container.AddEntity("trigger_multiple"); + GetBoundingCube(triggerVoiceBtm, max, "textures/common/trigger", triggerVoice); + triggerVoice->AddEPair("target", buffer); +//-------------------- + +// target for speaker + vec3_t voiceOrigin; + VectorCopy(centre, voiceOrigin); + voiceOrigin[2] = max[2]+16; + + + DEntity* targetVoice = m_Container.AddEntity("target_speaker"); + targetVoice->AddEPair("targetname", buffer); + + sprintf(buffer, "%f %f %f", voiceOrigin[0], voiceOrigin[1], voiceOrigin[2]); + targetVoice->AddEPair("origin", buffer); + targetVoice->AddEPair("spawnflags", "8"); + targetVoice->AddEPair("noise", "*falling1.wav"); +//-------------------- + +// *********** END SPEAKER ************* + +// ********* POWERUP REMOVAL *********** + sprintf(buffer, "t%i_2", team); + +// trigger for powerup removal + vec3_t triggerPwrRmvTop, triggerPwrRmvBtm; + VectorCopy(min, triggerPwrRmvBtm); + VectorCopy(max, triggerPwrRmvTop); + + triggerPwrRmvTop[2] = triggerVoiceBtm[2] - 64; + triggerPwrRmvBtm[2] = triggerPwrRmvTop[2] - 16; + + DEntity* triggerPwrRmv = m_Container.AddEntity("trigger_multiple"); + GetBoundingCube(triggerPwrRmvBtm, triggerPwrRmvTop, "textures/common/trigger", triggerPwrRmv); + triggerPwrRmv->AddEPair("target", buffer); +//-------------------- + +// target for powerup removal + vec3_t pwrRmvOrigin; + VectorCopy(centre, pwrRmvOrigin); + pwrRmvOrigin[2] = triggerPwrRmvTop[2]+16; + + DEntity* targetPwrRmv = m_Container.AddEntity("target_remove_powerups"); + targetPwrRmv->AddEPair("targetname", buffer); + + sprintf(buffer, "%f %f %f", pwrRmvOrigin[0], pwrRmvOrigin[1], pwrRmvOrigin[2]); + targetPwrRmv->AddEPair("origin", buffer); +//-------------------- + +// ****** END POWERUP REMOVAL ******** + +// ********* DAMAGE *********** + +// trigger for damage + vec3_t triggerDmgTop, triggerDmgBtm; + VectorCopy(min, triggerDmgBtm); + VectorCopy(max, triggerDmgTop); + + triggerDmgBtm[2] = min[2] + 64; + triggerDmgTop[2] = triggerDmgBtm[2] + 16; + + DEntity* triggerDmg = m_Container.AddEntity("trigger_hurt"); + GetBoundingCube(triggerDmgBtm, triggerDmgTop, "textures/common/trigger", triggerDmg); + triggerDmg->AddEPair("dmg", "9999"); + triggerDmg->AddEPair("spawnflags", "12"); +//-------------------- + +// ****** END DAMAGE ******** + +// ********* NODROP *********** + + vec3_t nodropTop; + VectorCopy(max, nodropTop); + + nodropTop[2] = min[2] + 64; + + GetBoundingCube(min, nodropTop, "textures/common/nodrop"); + +// ****** END NODROP ******** + + return TRUE; +} diff --git a/contrib/bobtoolz/DShape.h b/contrib/bobtoolz/DShape.h new file mode 100644 index 00000000..9564943d --- /dev/null +++ b/contrib/bobtoolz/DShape.h @@ -0,0 +1,60 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DShape.h: interface for the DShape class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DSHAPE_H__0B30B302_9D21_4C2D_836A_61F3C8D4244D__INCLUDED_) +#define AFX_DSHAPE_H__0B30B302_9D21_4C2D_836A_61F3C8D4244D__INCLUDED_ + +#include "DMap.h" // Added by ClassView +#include "StdAfx.h" // Added by ClassView + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +// defines for polygon stuff +#define MAX_POLYGON_FACES 128 + +extern bool bFacesAll[]; + +class DShape +{ +public: + bool BuildPit(vec3_t min, vec3_t max); + void BuildBorderedPrism(vec3_t min, vec3_t max, int nSides, int nBorder, bool bAlignTop); + void BuildInversePrism(vec3_t min, vec3_t max, int nSides, bool bAlignTop); + void BuildRegularPrism(vec3_t min, vec3_t max, int nSides, bool bAlignTop); + + int m_nNextBrush; + static DBrush* GetBoundingCube_Ext(vec3_t min, vec3_t max, const char* textureName, bool* bUseFaces = bFacesAll, bool detail = false); + + DShape(); + virtual ~DShape(); + + void Commit(); +private: + DBrush* GetBoundingCube(vec3_t min, vec3_t max, const char* textureName, DEntity* ent = NULL, bool* bUseFaces = bFacesAll); + + DMap m_Container; +}; + +#endif // !defined(AFX_DSHAPE_H__0B30B302_9D21_4C2D_836A_61F3C8D4244D__INCLUDED_) diff --git a/contrib/bobtoolz/DTrainDrawer.cpp b/contrib/bobtoolz/DTrainDrawer.cpp new file mode 100644 index 00000000..83ddc3ec --- /dev/null +++ b/contrib/bobtoolz/DTrainDrawer.cpp @@ -0,0 +1,358 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" +#include "DPoint.h" + +#include "DTrainDrawer.h" +#include "DEPair.h" + +#include "misc.h" +#include "funchandlers.h" + +#include "dialogs/dialogs-gtk.h" + +DTrainDrawer::DTrainDrawer() { + refCount = 1; + m_bHooked = FALSE; + m_bDisplay = FALSE; + + BuildPaths(); +} + +DTrainDrawer::~DTrainDrawer(void) { + if(m_bHooked) + UnRegister(); + + ClearPoints(); + ClearSplines(); +} + +void DTrainDrawer::ClearSplines() { + for(list::const_iterator deadSpline = m_splineList.begin(); deadSpline != m_splineList.end(); deadSpline++) { + (*deadSpline)->m_pointList.clear(); + (*deadSpline)->m_vertexList.clear(); + delete (*deadSpline); + } + + m_splineList.clear(); +} + +void DTrainDrawer::ClearPoints() { + for(list::const_iterator deadPoint = m_pointList.begin(); deadPoint != m_pointList.end(); deadPoint++) { + delete *deadPoint; + } + + m_pointList.clear(); +} + +void DTrainDrawer::Register() { + g_QglTable.m_pfnHookGL2DWindow( this ); + g_QglTable.m_pfnHookGL3DWindow( this ); + m_bHooked = TRUE; +} + +void DTrainDrawer::UnRegister() { + g_QglTable.m_pfnUnHookGL2DWindow( this ); + g_QglTable.m_pfnUnHookGL3DWindow( this ); + m_bHooked = FALSE; +} + +void CalculateSpline_r(vec3_t* v, int count, vec3_t out, float tension) { + vec3_t dist; + + if(count < 2) { + return; + } + + if(count == 2) { + VectorSubtract( v[1], v[0], dist ); + VectorMA(v[0], tension, dist, out); + return; + } + + vec3_t* v2 = new vec3_t[count-1]; + + for( int i = 0; i < count-1; i++ ) { + VectorSubtract( v[i+1], v[i], dist ); + VectorMA(v[i], tension, dist, v2[i]); + } + + CalculateSpline_r( v2, count-1, out, tension); + + delete[] v2; +} + +void DTrainDrawer::Draw3D() { + + if(!m_bDisplay) { + return; + } + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + g_QglTable.m_pfn_qglDisable(GL_BLEND); + g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); + + g_QglTable.m_pfn_qglPushMatrix(); + + g_QglTable.m_pfn_qglLineWidth(2.0f); + g_QglTable.m_pfn_qglColor4f(1.0f, 1.0f, 1.0f, 1.0f); + + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); + + g_QglTable.m_pfn_qglDepthFunc(GL_ALWAYS); + + for(list::const_iterator sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { + splinePoint_t* pSP = (*sp); + + g_QglTable.m_pfn_qglBegin(GL_LINE_STRIP); + for(list::const_iterator v = pSP->m_vertexList.begin(); v != pSP->m_vertexList.end(); v++) { + g_QglTable.m_pfn_qglVertex3fv((*v)._pnt); + } + g_QglTable.m_pfn_qglEnd(); + + } + + g_QglTable.m_pfn_qglPopMatrix(); + g_QglTable.m_pfn_qglPopAttrib(); +} + +void DTrainDrawer::Draw2D(VIEWTYPE vt) { + + if(!m_bDisplay) { + return; + } + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + g_QglTable.m_pfn_qglDisable(GL_BLEND); + g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); + + g_QglTable.m_pfn_qglPushMatrix(); + + switch(vt) + { + case XY: + break; + case XZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + break; + case YZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + g_QglTable.m_pfn_qglRotatef(270.0f, 0.0f, 0.0f, 1.0f); + break; + } + + g_QglTable.m_pfn_qglLineWidth(1.0f); + g_QglTable.m_pfn_qglColor4f(1.0f, 0.0f, 0.0f, 0.5f); + + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); + + g_QglTable.m_pfn_qglDepthFunc(GL_ALWAYS); + + g_QglTable.m_pfn_qglColor4f(1.f, 0.f, 0.f, 1.f); + + for(list::const_iterator sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { + splinePoint_t* pSP = (*sp); + + g_QglTable.m_pfn_qglBegin(GL_LINE_STRIP); + for(list::const_iterator v = pSP->m_vertexList.begin(); v != pSP->m_vertexList.end(); v++) { + g_QglTable.m_pfn_qglVertex3fv((*v)._pnt); + } + g_QglTable.m_pfn_qglEnd(); + + } + + g_QglTable.m_pfn_qglPopMatrix(); + g_QglTable.m_pfn_qglPopAttrib(); +} + +void AddSplineControl(const char* control, splinePoint_t* pSP) { + controlPoint_t cp; + strncpy(cp.strName, control, 64); + + pSP->m_pointList.push_front(cp); +} + +void DTrainDrawer::BuildPaths() { + int count = g_FuncTable.m_pfnGetEntityCount(); + + DEntity e; + + for(int i = 0; i < count; i++) { + entity_s* ent = (entity_s*)g_FuncTable.m_pfnGetEntityHandle(i); + e.ClearEPairs(); + e.LoadEPairList(*g_EntityTable.m_pfnGetEntityKeyValList(ent)); + + const char* classname = e.m_Classname.GetBuffer(); + const char* target; + const char* control; + const char* targetname; + vec3_t vOrigin; + + e.SpawnString("targetname", NULL, &targetname); + e.SpawnVector("origin", "0 0 0", vOrigin); + + if(!strcmp(classname, "info_train_spline_main")) { + if(!targetname) { + Sys_Printf( "info_train_spline_main with no targetname" ); + return; + } + + e.SpawnString("target", NULL, &target); + + if(!target) { + AddControlPoint( targetname, vOrigin ); + } else { + splinePoint_t* pSP = AddSplinePoint( targetname, target, vOrigin ); + + e.SpawnString("control", NULL, &control); + + if(control) { + AddSplineControl( control, pSP ); + + for(int j = 2;; j++) { + char buffer[16]; + sprintf(buffer, "control%i", j); + + e.SpawnString(buffer, NULL, &control); + if(!control) { + break; + } + + AddSplineControl( control, pSP ); + } + } + } + } else if(!strcmp(classname, "info_train_spline_control")) { + if(!targetname) { + Sys_Printf( "info_train_spline_control with no targetname" ); + return; + } + + AddControlPoint( targetname, vOrigin ); + } + } + + list::const_iterator sp; + for(sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { + splinePoint_t* pSP = (*sp); + + controlPoint_t* pTarget = FindControlPoint( pSP->strTarget ); + + if(!pTarget) { + Sys_Printf( "couldn't find target %s", pSP->strTarget ); + return; +// continue; + } + + pSP->pTarget = pTarget; + + + for(list::iterator cp = pSP->m_pointList.begin(); cp != pSP->m_pointList.end(); cp++) { + controlPoint_t* pControl = FindControlPoint( (*cp).strName ); + if(!pControl) { + Sys_Printf( "couldn't find control %s", (*cp).strName ); + return; + } + + VectorCopy(pControl->vOrigin, (*cp).vOrigin); + } + } + + m_bDisplay = TRUE; + Register(); + + for(sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { + splinePoint_t* pSP = (*sp); + DPoint out; + + if(!pSP->pTarget) { + continue; + } + + int count = pSP->m_pointList.size() + 2; + vec3_t* v = new vec3_t[count]; + + VectorCopy(pSP->point.vOrigin, v[0]); + + int i = 1; + for(list::reverse_iterator cp = pSP->m_pointList.rbegin(); cp != pSP->m_pointList.rend(); cp++) { + VectorCopy((*cp).vOrigin, v[i]); + i++; + } + VectorCopy(pSP->pTarget->vOrigin, v[i]); + + for (float tension = 0.0f; tension <= 1.f; tension += 0.01f) { + CalculateSpline_r(v, count, out._pnt, tension); + pSP->m_vertexList.push_front(out); + } + + delete[] v; + + VectorCopy(pSP->pTarget->vOrigin, out._pnt); + pSP->m_vertexList.push_front(out); + } + + +} + +void DTrainDrawer::AddControlPoint(const char* name, vec_t* origin) +{ + controlPoint_t* pCP = new controlPoint_t; + + strncpy(pCP->strName, name, 64); + VectorCopy( origin, pCP->vOrigin ); + + m_pointList.push_back( pCP ); +} + +splinePoint_t* DTrainDrawer::AddSplinePoint(const char* name, const char* target, vec_t* origin) +{ + splinePoint_t* pSP = new splinePoint_t; + + strncpy(pSP->point.strName, name, 64); + strncpy(pSP->strTarget, target, 64); + VectorCopy( origin, pSP->point.vOrigin ); + m_splineList.push_back( pSP ); + + return pSP; +} + +controlPoint_t* DTrainDrawer::FindControlPoint(const char* name) +{ + for(list::const_iterator cp = m_pointList.begin(); cp != m_pointList.end(); cp++) { + if(!strcmp(name, (*cp)->strName)) { + return (*cp); + } + } + + for(list::const_iterator sp = m_splineList.begin(); sp != m_splineList.end(); sp++) { + if(!strcmp(name, (*sp)->point.strName)) { + return &((*sp)->point); + } + } + + return NULL; +} diff --git a/contrib/bobtoolz/DTrainDrawer.h b/contrib/bobtoolz/DTrainDrawer.h new file mode 100644 index 00000000..5f424068 --- /dev/null +++ b/contrib/bobtoolz/DTrainDrawer.h @@ -0,0 +1,82 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DTrainDrawer.h: interface for the DTrainDrawer class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_TRAINDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_TRAINDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_ + +#include "DEntity.h" + +#if _MSC_VER > 1000 + +#pragma once +#endif // _MSC_VER > 1000 + +typedef struct { + char strName[64]; + + vec3_t vOrigin; +} controlPoint_t; + +typedef struct { + controlPoint_t point; + + char strControl[64]; + char strTarget[64]; + + list m_pointList; + list m_vertexList; + + controlPoint_t* pTarget; +} splinePoint_t; + +class DTrainDrawer : + public IGL2DWindow, + public IGL3DWindow +{ +private: + list m_splineList; + list m_pointList; + int refCount; + + bool m_bHooked; + bool m_bDisplay; +public: + void UnRegister(); + void Register(); + + DTrainDrawer(); + virtual ~DTrainDrawer(void); + + void Draw3D(); + void Draw2D(VIEWTYPE vt); + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + void ClearSplines(); + void ClearPoints(); + void BuildPaths(); + void AddControlPoint(const char* name, vec_t* origin); + splinePoint_t* AddSplinePoint(const char* name, const char* target, vec_t* origin); + controlPoint_t* FindControlPoint(const char* name); +}; + +#endif // !defined(AFX_TRAINDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DTreePlanter.cpp b/contrib/bobtoolz/DTreePlanter.cpp new file mode 100644 index 00000000..8655b36a --- /dev/null +++ b/contrib/bobtoolz/DTreePlanter.cpp @@ -0,0 +1,287 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" +#include "DTreePlanter.h" +#include "funchandlers.h" + +bool DTreePlanter::OnMouseMove(guint32 nFlags, gdouble x, gdouble y) { + return false; +} + +bool DTreePlanter::OnLButtonDown(guint32 nFlags, gdouble x, gdouble y) { + VIEWTYPE vt = m_XYWrapper->GetViewType(); + + switch(vt) { + case XY: + break; + case YZ: + case XZ: + default: + return false; + } + + vec3_t pt, vhit; + + m_XYWrapper->SnapToGrid( static_cast< int >( x ), static_cast< int >( y ), pt ); + + if(FindDropPoint(pt, vhit)) { + vhit[2] += m_offset; + + char buffer[128]; + DEntity e(m_entType); + + sprintf(buffer, "%i %i %i", (int)vhit[0], (int)vhit[1], (int)vhit[2]); + e.AddEPair("origin", buffer); + + if(m_autoLink) { + entity_t* pLastEntity = NULL; + entity_t* pThisEntity = NULL; + + int entNum = -1, lastEntNum = -1, entpos; + for(int i = 0; i < 256; i++) { + sprintf(buffer, m_linkName, i); + pThisEntity = FindEntityFromTargetname( buffer, &entNum ); + + if(pThisEntity) { + entpos = i; + lastEntNum = entNum; + pLastEntity = pThisEntity; + } + } + + if(!pLastEntity) { + sprintf(buffer, m_linkName, 0); + } else { + sprintf(buffer, m_linkName, entpos + 1); + } + + e.AddEPair( "targetname", buffer ); + + if(pLastEntity) { + DEntity e2; + e2.LoadFromEntity(lastEntNum, TRUE); + e2.AddEPair("target", buffer); + e2.RemoveFromRadiant(); + e2.BuildInRadiant(FALSE); + } + } + + if(m_setAngles) { + int angleYaw = (rand() % (m_maxYaw - m_minYaw + 1)) + m_minYaw; + int anglePitch = (rand() % (m_maxPitch - m_minPitch + 1)) + m_minPitch; + + sprintf(buffer, "%i %i 0", anglePitch, angleYaw); + e.AddEPair("angles", buffer); + } + + if(m_numModels) { + int treetype = rand() % m_numModels; + e.AddEPair("model", m_trees[treetype].name); + } + + if(m_useScale) { + float scale = (((rand()%1000)*0.001f) * (m_maxScale - m_minScale)) + m_minScale; + + sprintf(buffer, "%f", scale ); + e.AddEPair("modelscale", buffer); + } + + e.BuildInRadiant( FALSE ); + } + + if(m_autoLink) { + DoTrainPathPlot(); + } + + return true; +} + +bool DTreePlanter::OnLButtonUp(guint32 nFlags, gdouble x, gdouble y) { + return false; +} + +bool DTreePlanter::OnRButtonDown(guint32 nFlags, gdouble x, gdouble y) { + return false; +} + +bool DTreePlanter::OnRButtonUp(guint32 nFlags, gdouble x, gdouble y) { + return false; +} + +bool DTreePlanter::OnMButtonDown(guint32 nFlags, gdouble x, gdouble y) { + return false; +} + +bool DTreePlanter::OnMButtonUp(guint32 nFlags, gdouble x, gdouble y) { + return false; +} + +bool DTreePlanter::FindDropPoint(vec3_t in, vec3_t out) { + DPlane p1; + DPlane p2; + + vec3_t vUp = { 0, 0, 1 }; + vec3_t vForward = { 0, 1, 0 }; + vec3_t vLeft = { 1, 0, 0 }; + + in[2] = 65535; + + VectorCopy(in, p1.points[0]); + VectorCopy(in, p1.points[1]); + VectorCopy(in, p1.points[2]); + VectorMA(p1.points[1], 20, vUp, p1.points[1]); + VectorMA(p1.points[1], 20, vLeft, p1.points[2]); + + VectorCopy(in, p2.points[0]); + VectorCopy(in, p2.points[1]); + VectorCopy(in, p2.points[2]); + VectorMA(p1.points[1], 20, vUp, p2.points[1]); + VectorMA(p1.points[1], 20, vForward, p2.points[2]); + + p1.Rebuild(); + p2.Rebuild(); + + bool found = false; + vec3_t temp; + vec_t dist; + int cnt = m_world.GetIDMax(); + for(int i = 0; i < cnt; i++) { + DBrush* pBrush = m_world.GetBrushForID( i ); + + if(pBrush->IntersectsWith( &p1, &p2, temp )) { + vec3_t diff; + vec_t tempdist; + VectorSubtract(in, temp, diff); + tempdist = VectorLength( diff ); + if(!found || (tempdist < dist)) { + dist = tempdist; + VectorCopy( temp, out ); + found = true; + } + } + } + + return found; +} + +void DTreePlanter::DropEntsToGround( void ) { + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + DEntity ent; + + int cnt = g_FuncTable.m_pfnSelectedBrushCount(); + for(int i = 0; i < cnt; i++) { + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i); + + ent.LoadFromEntity(brush->owner, TRUE); + + DEPair* pEpair = ent.FindEPairByKey("origin"); + if(!pEpair) { + continue; + } + + vec3_t vec, out; + sscanf( pEpair->value.GetBuffer(), "%f %f %f", &vec[0], &vec[1], &vec[2]); + + FindDropPoint( vec, out ); + + char buffer[256]; + sprintf( buffer, "%f %f %f", out[0], out[1], out[2] ); + ent.AddEPair( "origin", buffer ); + ent.RemoveFromRadiant(); + ent.BuildInRadiant(FALSE); + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DTreePlanter::MakeChain( void ) { + char buffer[256]; + int i; + + for(i = 0; i < m_linkNum; i++) { + DEntity e("info_train_spline_main"); + + sprintf( buffer, "%s_pt%i", m_linkName, i ); + e.AddEPair( "targetname", buffer ); + + sprintf( buffer, "0 %i 0", i * 64 ); + e.AddEPair( "origin", buffer ); + + if(i != m_linkNum-1) { + sprintf( buffer, "%s_pt%i", m_linkName, i+1 ); + e.AddEPair( "target", buffer ); + + sprintf( buffer, "%s_ctl%i", m_linkName, i ); + e.AddEPair( "control", buffer ); + } + + e.BuildInRadiant( FALSE ); + } + + for(i = 0; i < m_linkNum-1; i++) { + DEntity e("info_train_spline_control"); + + sprintf( buffer, "%s_ctl%i", m_linkName, i ); + e.AddEPair( "targetname", buffer ); + + sprintf( buffer, "0 %i 0", (i * 64) + 32); + e.AddEPair( "origin", buffer ); + + e.BuildInRadiant( FALSE ); + } +} + +void DTreePlanter::SelectChain( void ) { +/* char buffer[256]; + + for(int i = 0; i < m_linkNum; i++) { + DEntity e("info_train_spline_main"); + + sprintf( buffer, "%s_pt%i", m_linkName, i ); + e.AddEPair( "targetname", buffer ); + + sprintf( buffer, "0 %i 0", i * 64 ); + e.AddEPair( "origin", buffer ); + + if(i != m_linkNum-1) { + sprintf( buffer, "%s_pt%i", m_linkName, i+1 ); + e.AddEPair( "target", buffer ); + + sprintf( buffer, "%s_ctl%i", m_linkName, i ); + e.AddEPair( "control", buffer ); + } + + e.BuildInRadiant( FALSE ); + } + + for(int i = 0; i < m_linkNum-1; i++) { + DEntity e("info_train_spline_control"); + + sprintf( buffer, "%s_ctl%i", m_linkName, i ); + e.AddEPair( "targetname", buffer ); + + sprintf( buffer, "0 %i 0", (i * 64) + 32); + e.AddEPair( "origin", buffer ); + + e.BuildInRadiant( FALSE ); + }*/ +} diff --git a/contrib/bobtoolz/DTreePlanter.h b/contrib/bobtoolz/DTreePlanter.h new file mode 100644 index 00000000..ab80abff --- /dev/null +++ b/contrib/bobtoolz/DTreePlanter.h @@ -0,0 +1,223 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __DTREE_H__ +#define __DTREE_H__ + +#include "../include/igl.h" +#include "DEntity.h" +#include "misc.h" +#include "ScriptParser.h" + +#define MAX_QPATH 64 + +typedef struct treeModel_s { + char name[MAX_QPATH]; +} treeModel_t; + +#define MAX_TP_MODELS 256 + +class DTreePlanter : public IWindowListener { +public: + virtual bool OnMouseMove(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnLButtonDown(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnMButtonDown(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnRButtonDown(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnLButtonUp(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnMButtonUp(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnRButtonUp(guint32 nFlags, gdouble x, gdouble y); + virtual bool OnKeyPressed(char *s) { return false; } + virtual bool Paint() { return true; } + virtual void Close() { } + + DTreePlanter() { + m_refCount = 1; + m_hooked = false; + m_XYWrapper = NULL; + m_numModels = 0; + m_offset = 0; + m_maxPitch = 0; + m_minPitch = 0; + m_maxYaw = 0; + m_minYaw = 0; + m_setAngles = false; + m_useScale = false; + m_autoLink = false; + m_linkNum = 0; + + Register(); + + m_world.LoadSelectedBrushes(); + + char buffer[256]; + GetFilename( buffer, "bt/tp_ent.txt" ); + + FILE* file = fopen( buffer, "rb" ); + if(file) { + fseek( file, 0, SEEK_END ); + int len = ftell( file ); + fseek( file, 0, SEEK_SET ); + + if(len) { + char* buf = new char[len+1]; + buf[len] = '\0'; + // parser will do the cleanup, dont delete. + + fread( buf, len, 1, file ); + + CScriptParser parser; + parser.SetScript( buf ); + + ReadConfig( &parser ); + } + + fclose( file ); + } + } + +#define MT(t) !stricmp( pToken, t ) +#define GT pToken = pScriptParser->GetToken( true ) +#define CT if(!*pToken) { return; } + + void ReadConfig( CScriptParser* pScriptParser ) { + const char* GT; + CT; + + do { + GT; + if(*pToken == '}') { + break; + } + + if(MT("model")) { + if(m_numModels >= MAX_TP_MODELS) { + return; + } + + GT; CT; + + strncpy( m_trees[m_numModels++].name, pToken, MAX_QPATH ); + } else if(MT("link")) { + GT; CT; + + strncpy( m_linkName, pToken, MAX_QPATH ); + + m_autoLink = true; + } else if(MT("entity")) { + GT; CT; + + strncpy( m_entType, pToken, MAX_QPATH ); + } else if(MT("offset")) { + GT; CT; + + m_offset = atoi(pToken); + } else if(MT("pitch")) { + GT; CT; + + m_minPitch = atoi(pToken); + + GT; CT; + + m_maxPitch = atoi(pToken); + + m_setAngles = true; + } else if(MT("yaw")) { + GT; CT; + + m_minYaw = atoi(pToken); + + GT; CT; + + m_maxYaw = atoi(pToken); + + m_setAngles = true; + } else if(MT("scale")) { + GT; CT; + + m_minScale = static_cast< float >( atof( pToken ) ); + + GT; CT; + + m_maxScale = static_cast< float >( atof( pToken ) ); + + m_useScale = true; + } else if(MT("numlinks")) { + GT; CT; + + m_linkNum = atoi( pToken ); + } + } while( true ); + } + + virtual ~DTreePlanter() { + UnRegister(); + } + + virtual void IncRef() { m_refCount++; } + virtual void DecRef() { m_refCount--; if (m_refCount <= 0) delete this; } + + void Register() { + if(!m_hooked) { + g_MessageTable.m_pfnHookWindow( this ); + m_XYWrapper = g_MessageTable.m_pfnGetXYWndWrapper(); + m_hooked = true; + } + } + + void UnRegister() { + if(m_hooked) { + g_MessageTable.m_pfnUnHookWindow( this ); + m_XYWrapper = NULL; + m_hooked = false; + } + } + + bool FindDropPoint(vec3_t in, vec3_t out); + void DropEntsToGround( void ); + void MakeChain( void ); + void SelectChain( void ); + +private: + IXYWndWrapper* m_XYWrapper; + DEntity m_world; + + treeModel_t m_trees[MAX_TP_MODELS]; + + int m_refCount; + int m_numModels; + int m_offset; + int m_maxPitch; + int m_minPitch; + int m_maxYaw; + int m_minYaw; + + char m_entType[MAX_QPATH]; + char m_linkName[MAX_QPATH]; + int m_linkNum; + + float m_minScale; + float m_maxScale; + + bool m_hooked; + bool m_useScale; + bool m_setAngles; + bool m_autoLink; +}; + +#endif diff --git a/contrib/bobtoolz/DVisDrawer.cpp b/contrib/bobtoolz/DVisDrawer.cpp new file mode 100644 index 00000000..b954268f --- /dev/null +++ b/contrib/bobtoolz/DVisDrawer.cpp @@ -0,0 +1,179 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// BobView.cpp: implementation of the DVisDrawer class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DPoint.h" +#include "DVisDrawer.h" +#include "misc.h" +#include "funchandlers.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DVisDrawer::DVisDrawer() +{ + refCount = 1; + m_bHooked = FALSE; + m_list = NULL; +} + +DVisDrawer::~DVisDrawer() +{ + if(m_bHooked) + UnRegister(); + + g_VisView = NULL; +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +void DVisDrawer::Draw2D(VIEWTYPE vt) +{ + if(!m_list) + return; + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + g_QglTable.m_pfn_qglDisable(GL_BLEND); + g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); + + g_QglTable.m_pfn_qglPushMatrix(); + + switch(vt) + { + case XY: + break; + case XZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + break; + case YZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + g_QglTable.m_pfn_qglRotatef(270.0f, 0.0f, 0.0f, 1.0f); + break; + } + + g_QglTable.m_pfn_qglLineWidth(1.0f); + g_QglTable.m_pfn_qglColor4f(1.0f, 0.0f, 0.0f, 0.5f); + + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); + + g_QglTable.m_pfn_qglDepthFunc(GL_ALWAYS); + + //bleh + list::const_iterator l=m_list->begin(); + + for(; l != m_list->end(); l++) + { + DWinding* w = *l; + + g_QglTable.m_pfn_qglColor4f(w->clr[0], w->clr[1], w->clr[2], 0.5f); + + g_QglTable.m_pfn_qglBegin(GL_POLYGON); + for(int i = 0; i < w->numpoints; i++) { + g_QglTable.m_pfn_qglVertex3f((w->p[i])[0], (w->p[i])[1], (w->p[i])[2]); + } + g_QglTable.m_pfn_qglEnd(); + } + + + g_QglTable.m_pfn_qglPopMatrix(); + + g_QglTable.m_pfn_qglPopAttrib(); +} + +void DVisDrawer::Draw3D() +{ + if(!m_list) + return; + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + g_QglTable.m_pfn_qglColor4f(1.0, 0.0, 0.0, 0.5f); + +// g_QglTable.m_pfn_qglHint(GL_FOG_HINT, GL_NICEST); + +// g_QglTable.m_pfn_qglDisable(GL_CULL_FACE); + g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); + +// g_QglTable.m_pfn_qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); +// g_QglTable.m_pfn_qglShadeModel(GL_SMOOTH); + + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); + + g_QglTable.m_pfn_qglDepthFunc(GL_ALWAYS); + + //bleh + list::const_iterator l=m_list->begin(); + + for(; l != m_list->end(); l++) + { + DWinding* w = *l; + + g_QglTable.m_pfn_qglColor4f(w->clr[0], w->clr[1], w->clr[2], 0.5f); + + g_QglTable.m_pfn_qglBegin(GL_POLYGON); + for(int i = 0; i < w->numpoints; i++) { + g_QglTable.m_pfn_qglVertex3f((w->p[i])[0], (w->p[i])[1], (w->p[i])[2]); + } + g_QglTable.m_pfn_qglEnd(); + } + + g_QglTable.m_pfn_qglPopAttrib(); +} + +void DVisDrawer::Register() +{ + g_QglTable.m_pfnHookGL2DWindow( this ); + g_QglTable.m_pfnHookGL3DWindow( this ); + m_bHooked = TRUE; +} + +void DVisDrawer::UnRegister() +{ + g_QglTable.m_pfnUnHookGL2DWindow( this ); + g_QglTable.m_pfnUnHookGL3DWindow( this ); + m_bHooked = FALSE; +} + +void DVisDrawer::SetList(std::list *pointList) +{ + if(m_list) + ClearPoints(); + + m_list = pointList; +} + +void DVisDrawer::ClearPoints() +{ + list::const_iterator deadPoint=m_list->begin(); + for(; deadPoint!=m_list->end(); deadPoint++) + delete *deadPoint; + m_list->clear(); +} diff --git a/contrib/bobtoolz/DVisDrawer.h b/contrib/bobtoolz/DVisDrawer.h new file mode 100644 index 00000000..c0ba1aa9 --- /dev/null +++ b/contrib/bobtoolz/DVisDrawer.h @@ -0,0 +1,58 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DBobView.h: interface for the DBobView class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_VISDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_VISDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_ + +#include "DWinding.h" + +#if _MSC_VER > 1000 + +#pragma once +#endif // _MSC_VER > 1000 + +class DVisDrawer : + public IGL2DWindow, + public IGL3DWindow +{ +public: + DVisDrawer(); + virtual ~DVisDrawer(); + +protected: + list* m_list; + int refCount; +public: + void ClearPoints(); + void SetList(list* pointList); + void UnRegister(); + void Register(); + void Draw3D(); + void Draw2D(VIEWTYPE vt); + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + + bool m_bHooked; +}; + +#endif // !defined(AFX_VISDRAWER_H__6E36062A_EF0B_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/DWinding.cpp b/contrib/bobtoolz/DWinding.cpp new file mode 100644 index 00000000..b99ede0a --- /dev/null +++ b/contrib/bobtoolz/DWinding.cpp @@ -0,0 +1,483 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DWinding.cpp: implementation of the DWinding class. +// +////////////////////////////////////////////////////////////////////// + +#include "StdAfx.h" +#include "DWinding.h" +#include "DPlane.h" +#include "misc.h" + +////////////////////////////////////////////////////////////////////// +// Construction/Destruction +////////////////////////////////////////////////////////////////////// + +DWinding::DWinding() +{ + numpoints = 0; + p = NULL; +} + +DWinding::~DWinding() +{ + if(p) + delete[] p; +} + +////////////////////////////////////////////////////////////////////// +// Implementation +////////////////////////////////////////////////////////////////////// + +#define BOGUS_RANGE 4096 + +void DWinding::AllocWinding(int points) +{ + numpoints = points; + if(p) + delete[] p; + p = new vec3_t[points]; +} + +vec_t DWinding::WindingArea() +{ + vec3_t d1, d2, cross; + vec_t total; + + total = 0; + for (int i = 2; i < numpoints ; i++) + { + VectorSubtract (p[i-1], p[0], d1); + VectorSubtract (p[i], p[0], d2); + + CrossProduct (d1, d2, cross); + + total += 0.5f * VectorLength ( cross ); + } + + return total; +} + +void DWinding::RemoveColinearPoints() +{ + vec3_t p2[MAX_POINTS_ON_WINDING]; + + int nump = 0; + for (int i = 0; i < numpoints; i++) + { + int j = (i+1)%numpoints; + int k = (i+numpoints-1)%numpoints; + + vec3_t v1, v2; + VectorSubtract (p[j], p[i], v1); + VectorSubtract (p[i], p[k], v2); + VectorNormalize(v1, v1); + VectorNormalize(v2, v2); + + if (DotProduct(v1, v2) < 0.999) + { + VectorCopy (p[i], p2[nump]); + nump++; + } + } + + if (nump == numpoints) + return; + + AllocWinding(nump); + memcpy (p, p2, nump*sizeof(vec3_t)); +} + +DPlane* DWinding::WindingPlane() +{ + DPlane* newPlane = new DPlane(p[0], p[1], p[2], NULL); + return newPlane; +} + +void DWinding::WindingBounds(vec3_t mins, vec3_t maxs) +{ + if(numpoints == 0) + return; + + VectorCopy(mins, p[0]); + VectorCopy(maxs, p[0]); + + for (int i = 1; i < numpoints ;i++) + { + for (int j = 0; j < 3; j++) + { + vec_t v = p[i][j]; + if (v < mins[j]) + mins[j] = v; + if (v > maxs[j]) + maxs[j] = v; + } + } +} + +void DWinding::WindingCentre(vec3_t centre) +{ + VectorCopy (vec3_origin, centre); + for (int i = 0; i < numpoints; i++) + VectorAdd (p[i], centre, centre); + + float scale = 1.0f/numpoints; + VectorScale (centre, scale, centre); +} + + +DWinding* DWinding::CopyWinding() +{ + DWinding* c = new DWinding; + c->AllocWinding(numpoints); + memcpy (c->p, p, numpoints*sizeof(vec3_t)); + return c; +} + + +int DWinding::WindingOnPlaneSide(vec3_t normal, vec_t dist) +{ + bool front = FALSE; + bool back = FALSE; + + for (int i = 0; i < numpoints; i++) + { + vec_t d = DotProduct (p[i], normal) - dist; + if (d < -ON_EPSILON) + { + if (front) + return SIDE_CROSS; + back = TRUE; + continue; + } + if (d > ON_EPSILON) + { + if (back) + return SIDE_CROSS; + front = TRUE; + continue; + } + } + + if (back) + return SIDE_BACK; + if (front) + return SIDE_FRONT; + return SIDE_ON; +} + +void DWinding::CheckWinding() +{ + vec_t *p1, *p2; + vec_t edgedist; + vec3_t dir, edgenormal; + + if (numpoints < 3) + Sys_Printf ("CheckWinding: %i points", numpoints); + + vec_t area = WindingArea(); + if (area < 1) + Sys_Printf ("CheckWinding: %f area", area); + + DPlane* wPlane = WindingPlane (); + int i; + for (i = 0; i < numpoints; i++) + { + p1 = p[i]; + + int j; + for (j = 0; j < 3; j++) + if (p1[j] > BOGUS_RANGE || p1[j] < -BOGUS_RANGE) + Sys_Printf ("CheckFace: BUGUS_RANGE: %f", p1[j]); + + j = i + 1 == numpoints ? 0 : i + 1; + + // check the point is on the face plane + vec_t d = DotProduct (p1, wPlane->normal) - wPlane->_d; + if (d < -ON_EPSILON || d > ON_EPSILON) + Sys_Printf ("CheckWinding: point off plane"); + + // check the edge isnt degenerate + p2 = p[j]; + VectorSubtract (p2, p1, dir); + + if (VectorLength (dir) < ON_EPSILON) + Sys_Printf ("CheckWinding: degenerate edge"); + + CrossProduct (wPlane->normal, dir, edgenormal); + VectorNormalize (edgenormal, edgenormal); + edgedist = DotProduct (p1, edgenormal); + + // all other points must be on front side + for (j = 0 ; j < numpoints ; j++) + { + if (j == i) + continue; + + d = DotProduct (p[j], edgenormal); + if (d > (edgedist + ON_EPSILON)) + Sys_Printf ("CheckWinding: non-convex"); + } + } + + delete wPlane; +} + +DWinding* DWinding::ReverseWinding() +{ + DWinding* c = new DWinding; + c->AllocWinding(numpoints); + + for (int i = 0; i < numpoints ; i++) + VectorCopy (p[numpoints-1-i], c->p[i]); + + return c; +} + +bool DWinding::ChopWindingInPlace(DPlane* chopPlane, vec_t epsilon) +{ + vec_t dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + vec_t *p1, *p2; + vec3_t mid; + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + int i; + for (i = 0; i < numpoints; i++) + { + vec_t dot = DotProduct (p[i], chopPlane->normal); + dot -= chopPlane->_d; + dists[i] = dot; + + if (dot > epsilon) + sides[i] = SIDE_FRONT; + else if (dot < -epsilon) + sides[i] = SIDE_BACK; + else + sides[i] = SIDE_ON; + + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + if (!counts[0]) + { + delete this; + return FALSE; + } + + if (!counts[1]) + return TRUE; + + int maxpts = numpoints+4; // cant use counts[0]+2 because + // of fp grouping errors + + DWinding* f = new DWinding; + f->AllocWinding(maxpts); + f->numpoints = 0; + + for (i = 0; i < numpoints; i++) + { + p1 = p[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = p[(i+1)%numpoints]; + + vec_t dot = dists[i] / (dists[i]-dists[i+1]); + for (int j = 0; j < 3; j++) + { + if (chopPlane->normal[j] == 1) + mid[j] = chopPlane->_d; + else if (chopPlane->normal[j] == -1) + mid[j] = -chopPlane->_d; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->p[f->numpoints]); + f->numpoints++; + } + + if (f->numpoints > maxpts) + Sys_Printf ("ClipWinding: points exceeded estimate"); + if (f->numpoints > MAX_POINTS_ON_WINDING) + Sys_Printf ("ClipWinding: MAX_POINTS_ON_WINDING"); + + delete[] p; + p = f->p; + f->p = NULL; + delete f; + return TRUE; +} + +void DWinding::ClipWindingEpsilon(DPlane* chopPlane, vec_t epsilon, DWinding **front, DWinding **back) +{ + vec_t dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + vec_t *p1, *p2; + vec3_t mid; + + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + int i; + for (i = 0; i < numpoints; i++) + { + vec_t dot = -chopPlane->DistanceToPoint(p[i]); + dists[i] = dot; + + if (dot > epsilon) + sides[i] = SIDE_FRONT; + else if (dot < -epsilon) + sides[i] = SIDE_BACK; + else + sides[i] = SIDE_ON; + + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + *front = *back = NULL; + + if (!counts[0]) + { + *back = CopyWinding(); + return; + } + if (!counts[1]) + { + *front = CopyWinding(); + return; + } + + int maxpts = numpoints+4; // cant use counts[0]+2 because + // of fp grouping errors + + DWinding* f = new DWinding; + DWinding* b = new DWinding; + + f->AllocWinding(maxpts); + f->numpoints = 0; + + b->AllocWinding(maxpts); + b->numpoints = 0; + + *front = f; + *back = b; + + for (i = 0; i < numpoints ; i++) + { + p1 = p[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + VectorCopy (p1, b->p[b->numpoints]); + b->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + } + if (sides[i] == SIDE_BACK) + { + VectorCopy (p1, b->p[b->numpoints]); + b->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = p[(i+1)%numpoints]; + + vec_t dot = dists[i] / (dists[i]-dists[i+1]); + for (int j = 0; j < 3; j++) + { + if (chopPlane->normal[j] == 1) + mid[j] = chopPlane->_d; + else if (chopPlane->normal[j] == -1) + mid[j] = -chopPlane->_d; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->p[f->numpoints]); + f->numpoints++; + VectorCopy (mid, b->p[b->numpoints]); + b->numpoints++; + } + + if (f->numpoints > maxpts || b->numpoints > maxpts) + Sys_Printf ("ClipWinding: points exceeded estimate"); + if (f->numpoints > MAX_POINTS_ON_WINDING || b->numpoints > MAX_POINTS_ON_WINDING) + Sys_Printf ("ClipWinding: MAX_POINTS_ON_WINDING"); +} + +bool DWinding::ChopWinding(DPlane* chopPlane) +{ + DWinding *f, *b; + + ClipWindingEpsilon (chopPlane, (float)ON_EPSILON, &f, &b); + + if (b) + delete (b); + + + if(!f) + { + delete this; + return FALSE; + } + + delete[] p; + p = f->p; + f->p = NULL; + numpoints = f->numpoints; + delete f; + + return TRUE; +} diff --git a/contrib/bobtoolz/DWinding.h b/contrib/bobtoolz/DWinding.h new file mode 100644 index 00000000..d173fbf6 --- /dev/null +++ b/contrib/bobtoolz/DWinding.h @@ -0,0 +1,68 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DWinding.h: interface for the DWinding class. +// +////////////////////////////////////////////////////////////////////// + +#if !defined(AFX_DWINDING_H__35B2C524_F0A7_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_DWINDING_H__35B2C524_F0A7_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + +class DPlane; + +class DWinding +{ +public: + DWinding(); + virtual ~DWinding(); + + void AllocWinding(int points); + + bool ChopWinding(DPlane* chopPlane); + bool ChopWindingInPlace(DPlane* chopPlane, vec_t ON_EPSILON); + void ClipWindingEpsilon(DPlane* chopPlane, vec_t epsilon, DWinding** front, DWinding** back); + + void CheckWinding(); + void WindingCentre(vec3_t centre); + void WindingBounds(vec3_t mins, vec3_t maxs); + void RemoveColinearPoints(); + + DWinding* ReverseWinding(); + DWinding* CopyWinding(); + DPlane* WindingPlane(); + + int WindingOnPlaneSide(vec3_t normal, vec_t dist); + + vec_t WindingArea(); + +// members + int numpoints; + vec3_t* p; + vec3_t clr; +}; + +#define MAX_POINTS_ON_WINDING 64 + +#define ON_EPSILON 0.01 + +#endif // !defined(AFX_DWINDING_H__35B2C524_F0A7_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/ScriptParser.cpp b/contrib/bobtoolz/ScriptParser.cpp new file mode 100644 index 00000000..c94175e1 --- /dev/null +++ b/contrib/bobtoolz/ScriptParser.cpp @@ -0,0 +1,267 @@ +#include "StdAfx.h" +#include "ScriptParser.h" + +CScriptParser::CScriptParser(void): + m_pScript(NULL), + m_pScriptSection(NULL), + m_pLastScriptSection(NULL), + m_pToken(NULL) { + ClearBuffer(); +} + +CScriptParser::~CScriptParser(void) { + ClearBuffer(); +} + +void CScriptParser::ClearBuffer(void) { + if(m_pScript) { + delete[] m_pScript; + m_pScript = NULL; + } + if(m_pToken) { + delete[] m_pToken; + m_pToken = NULL; + } + m_pScriptSection = NULL; + m_pLastScriptSection = NULL; + memset(m_breakChars, 0, sizeof(m_breakChars)); +} + +const char* CScriptParser::MakeToken(const char* pToken) { + if(m_pToken) { + delete[] m_pToken; + m_pToken = NULL; + } + + if(!pToken) { + pToken = ""; + } + + int len = static_cast(strlen(pToken)); + + m_pToken = new char[len + 1]; + m_pToken[len] = '\0'; + strcpy(m_pToken, pToken); + + return m_pToken; +} + +#define MAX_TOKEN_STRING 1024 +// Should NEVER return NULL +const char* CScriptParser::GetToken(bool bAllowLinebreaks) { + int c = 0, len; + char token[MAX_TOKEN_STRING]; + bool bNewLines = false; + + m_pLastScriptSection = m_pScriptSection; + + len = 0; + *token = '\0'; + + if(!m_pScript || !m_pScriptSection) { + return MakeToken(token); + } + + while ( true ) { + SkipWhitespace( &bNewLines ); + if ( !*m_pScriptSection ) { + return MakeToken(token); + } + if ( bNewLines && !bAllowLinebreaks ) { + return MakeToken(token); + } + + c = *m_pScriptSection; + + if ( c == '/' && m_pScriptSection[1] == '/' ) { // C style comments + m_pScriptSection += 2; + while (*m_pScriptSection && *m_pScriptSection != '\n') { + m_pScriptSection++; + } + } else if ( c=='/' && m_pScriptSection[1] == '*' ) { // C++ style comments + m_pScriptSection += 2; + while ( *m_pScriptSection && ( *m_pScriptSection != '*' || m_pScriptSection[1] != '/' ) ) { + m_pScriptSection++; + } + if ( *m_pScriptSection ) { + m_pScriptSection += 2; + } + } else { + break; + } + } + + if (c == '\"') { + m_pScriptSection++; + while ( true ) { + c = *m_pScriptSection++; + if (c=='\"' || !c) { + token[len] = 0; + return MakeToken(token); + } + if (len < MAX_TOKEN_STRING) { + token[len] = c; + len++; + } + } + } + + do { + if(len > 0 && IsBreakChar(*m_pScriptSection)) { + break; + } + + if (len < MAX_TOKEN_STRING) { + token[len] = c; + len++; + } + m_pScriptSection++; + + if(IsBreakChar(c)) { + break; + } + + c = *m_pScriptSection; + } while (c > 32); + + if (len == MAX_TOKEN_STRING) { + len = 0; + } + token[len] = 0; + + return MakeToken(token); +} + +void CScriptParser::SkipWhitespace(bool* pbNewLines) { + int c; + + if(!m_pScript || !m_pScriptSection) { + return; + } + + while( (c = *m_pScriptSection) <= ' ') { + if( !c ) { + return; + } + if( c == '\n' ) { + *pbNewLines = true; + } + m_pScriptSection++; + } +} + +void CScriptParser::SkipBracedSection(void) { + const char *token; + int depth; + + depth = 0; + do { + token = GetToken( true ); + if( token[1] == 0 ) { + if( *token == '{' ) { + depth++; + } else if( *token == '}' ) { + depth--; + } + } + } while( depth && *m_pScriptSection ); +} + +void CScriptParser::SkipRestOfLine(void) { + char *p; + int c; + + p = m_pScriptSection; + while ( (c = *p++) != 0 ) { + if ( c == '\n' ) { + break; + } + } + m_pScriptSection = p; +} + +void CScriptParser::UndoGetToken(void) { + if(!m_pLastScriptSection) { + return; + } + m_pScriptSection = m_pLastScriptSection; + m_pLastScriptSection = NULL; +} + +void CScriptParser::ResetParseSession(void) { + if(!m_pScript) { + return; + } + + m_pScriptSection = m_pScript; + m_pLastScriptSection = NULL; +} + +char* CScriptParser::GetBufferCopy(void) { + if(!m_pScript) { + return NULL; + } + + int len = static_cast(strlen(m_pScript)); + char* pBuffer = new char[len + 1]; + strcpy(pBuffer, m_pScript); + return pBuffer; +} + +int CScriptParser::GetTokenOffset(void) { + if(!m_pScript || !m_pScriptSection) { + return 0; + } + + return static_cast(m_pScriptSection - m_pScript); +} + +void CScriptParser::LoadScript(const char* pScript) { + ClearBuffer(); + + int len = static_cast(strlen(pScript)); + if(len <= 0) { + return; + } + + m_pScript = new char[len + 1]; + m_pScript[len] = '\0'; + + strcpy(m_pScript, pScript); + m_pScriptSection = m_pScript; +} + +void CScriptParser::AddBreakChar(char c) { + for(int i = 0; i < SP_MAX_BREAKCHARS; i++) { + if(!m_breakChars[i]) { + m_breakChars[i] = c; + return; + } + } + + // TODO: Error: max break chars hit +} + +bool CScriptParser::IsBreakChar(char c) { + for(int i = 0; i < SP_MAX_BREAKCHARS; i++) { + if(!m_breakChars[i]) { + return false; + } + if(m_breakChars[i] == c) { + return true; + } + } + return false; +} + +void CScriptParser::SetScript(char* pScript) { + ClearBuffer(); + + int len = static_cast(strlen(pScript)); + if(len <= 0) { + return; + } + + m_pScript = pScript; + m_pScriptSection = m_pScript; +} diff --git a/contrib/bobtoolz/ScriptParser.h b/contrib/bobtoolz/ScriptParser.h new file mode 100644 index 00000000..60c92f51 --- /dev/null +++ b/contrib/bobtoolz/ScriptParser.h @@ -0,0 +1,41 @@ + +#ifndef _SCRIPTPARSER_H_ +#define _SCRIPTPARSER_H_ + +#include "interfaces/IScriptParser.h" + +#define SP_MAX_BREAKCHARS 16 + +class CScriptParser: public IScriptParser { +public: + CScriptParser(void); + ~CScriptParser(void); +private: + char m_breakChars[SP_MAX_BREAKCHARS]; + char* m_pScript; + char* m_pScriptSection; + char* m_pLastScriptSection; + char* m_pToken; + + void SkipWhitespace(bool* pbNewLines); + void ClearBuffer(void); + const char* MakeToken(const char* pToken); + bool IsBreakChar(char c); +public: + const char* GetToken(bool bAllowLinebreaks); + void SkipBracedSection(void); + void SkipRestOfLine(void); + void UndoGetToken(void); + void ResetParseSession(void); + + char* GetBufferCopy(void); + int GetTokenOffset(void); + + void LoadScript(const char* pScript); + void SetScript(char* pScript); + + void AddBreakChar(char c); +private: +}; + +#endif diff --git a/contrib/bobtoolz/StdAfx.cpp b/contrib/bobtoolz/StdAfx.cpp new file mode 100644 index 00000000..eab4b5a5 --- /dev/null +++ b/contrib/bobtoolz/StdAfx.cpp @@ -0,0 +1,25 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// stdafx.cpp : source file that includes just the standard includes +// plugin.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "StdAfx.h" + diff --git a/contrib/bobtoolz/StdAfx.h b/contrib/bobtoolz/StdAfx.h new file mode 100644 index 00000000..88183232 --- /dev/null +++ b/contrib/bobtoolz/StdAfx.h @@ -0,0 +1,154 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __STDAFX_BOBTOOLZ__ +#define __STDAFX_BOBTOOLZ__ + +#define VC_EXTRALEAN + +#ifdef _WIN32 +#pragma warning(disable : 4786) +#endif + +#define BOBTOOLZ_MINOR "bobtoolz" + +#include +#include +#include +#include + +#include "time.h" + +#if defined (__linux__) || defined (__APPLE__) + +// Necessary for proper boolean type declaration +#include "qertypes.h" + +#include + +typedef void* HMODULE; +typedef void* LPVOID; +typedef char* LPCSTR; +//typedef int bool; + +#define MB_OK 0x00000000L +#define MB_OKCANCEL 0x00000001L +#define MB_ABORTRETRYIGNORE 0x00000002L +#define MB_YESNOCANCEL 0x00000003L +#define MB_YESNO 0x00000004L +#define MB_RETRYCANCEL 0x00000005L + + +#define MB_ICONHAND 0x00000010L +#define MB_ICONQUESTION 0x00000020L +#define MB_ICONEXCLAMATION 0x00000030L +#define MB_ICONASTERISK 0x00000040L + +#define MB_USERICON 0x00000080L +#define MB_ICONWARNING MB_ICONEXCLAMATION +#define MB_ICONERROR MB_ICONHAND +#define MB_ICONINFORMATION MB_ICONASTERISK +#define MB_ICONSTOP MB_ICONHAND + +#define MB_TYPEMASK 0x0000000FL +#define MB_ICONMASK 0x000000F0L +#define MB_DEFMASK 0x00000F00L +#define MB_MODEMASK 0x00003000L +#define MB_MISCMASK 0x0000C000L + +#define IDOK 1 +#define IDCANCEL 2 +#define IDABORT 3 +#define IDRETRY 4 +#define IDIGNORE 5 +#define IDYES 6 +#define IDNO 7 + +#define WINAPI +#define APIENTRY + +#ifndef GUID_DEFINED +#define GUID_DEFINED +typedef struct _GUID +{ + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[8]; +} GUID; + +#define stricmp strcasecmp + +#endif + +#if defined(__cplusplus) +#ifndef _REFGUID_DEFINED +#define _REFGUID_DEFINED +#define REFGUID const GUID & +#endif // !_REFGUID_DEFINED +#endif + +typedef struct tagRECT +{ + long left; + long top; + long right; + long bottom; +} RECT, *PRECT, *LPRECT; + +typedef uint UINT; + +#endif // __linux__ + +#include "synapse.h" +#include "iplugin.h" +#define USE_QERTABLE_DEFINE + +#include "missing.h" // temporary stuff, needs to be removed + +#include "str.h" +#include "qertypes.h" +#include "qerplugin.h" +#include "idata.h" +#include "ibrush.h" +#include "iselectedface.h" +#include "ishaders.h" +#include "ibspfrontend.h" +#include "iui.h" +#include "igl.h" +#include "itoolbar.h" +#include "ientity.h" + +#include "mathlib.h" + +extern _QERFuncTable_1 g_FuncTable; +extern _QERAppDataTable g_AppDataTable; +extern _QERBrushTable g_BrushTable; +extern _QERSelectedFaceTable g_SelectedFaceTable; +extern _QERShadersTable g_ShadersTable; +extern _QERQglTable g_QglTable; +extern _QERUITable g_MessageTable; +extern _QEREntityTable g_EntityTable; + + +#define MAX_ROUND_ERROR 0.05 + +#include "gtkr_list.h" + +#endif diff --git a/contrib/bobtoolz/bitmaps/bobtoolz_caulk.bmp b/contrib/bobtoolz/bitmaps/bobtoolz_caulk.bmp new file mode 100644 index 00000000..52239503 Binary files /dev/null and b/contrib/bobtoolz/bitmaps/bobtoolz_caulk.bmp differ diff --git a/contrib/bobtoolz/bitmaps/bobtoolz_cleanup.bmp b/contrib/bobtoolz/bitmaps/bobtoolz_cleanup.bmp new file mode 100644 index 00000000..33cc9490 Binary files /dev/null and b/contrib/bobtoolz/bitmaps/bobtoolz_cleanup.bmp differ diff --git a/contrib/bobtoolz/bitmaps/bobtoolz_dropent.bmp b/contrib/bobtoolz/bitmaps/bobtoolz_dropent.bmp new file mode 100644 index 00000000..2fcdcba3 Binary files /dev/null and b/contrib/bobtoolz/bitmaps/bobtoolz_dropent.bmp differ diff --git a/contrib/bobtoolz/bitmaps/bobtoolz_merge.bmp b/contrib/bobtoolz/bitmaps/bobtoolz_merge.bmp new file mode 100644 index 00000000..cc5e272c Binary files /dev/null and b/contrib/bobtoolz/bitmaps/bobtoolz_merge.bmp differ diff --git a/contrib/bobtoolz/bitmaps/bobtoolz_poly.bmp b/contrib/bobtoolz/bitmaps/bobtoolz_poly.bmp new file mode 100644 index 00000000..ed720e90 Binary files /dev/null and b/contrib/bobtoolz/bitmaps/bobtoolz_poly.bmp differ diff --git a/contrib/bobtoolz/bitmaps/bobtoolz_split.bmp b/contrib/bobtoolz/bitmaps/bobtoolz_split.bmp new file mode 100644 index 00000000..fbb1571c Binary files /dev/null and b/contrib/bobtoolz/bitmaps/bobtoolz_split.bmp differ diff --git a/contrib/bobtoolz/bitmaps/bobtoolz_trainpathplot.bmp b/contrib/bobtoolz/bitmaps/bobtoolz_trainpathplot.bmp new file mode 100644 index 00000000..66537dc1 Binary files /dev/null and b/contrib/bobtoolz/bitmaps/bobtoolz_trainpathplot.bmp differ diff --git a/contrib/bobtoolz/bitmaps/bobtoolz_treeplanter.bmp b/contrib/bobtoolz/bitmaps/bobtoolz_treeplanter.bmp new file mode 100644 index 00000000..08f55f3c Binary files /dev/null and b/contrib/bobtoolz/bitmaps/bobtoolz_treeplanter.bmp differ diff --git a/contrib/bobtoolz/bitmaps/bobtoolz_turnedge.bmp b/contrib/bobtoolz/bitmaps/bobtoolz_turnedge.bmp new file mode 100644 index 00000000..b72cb2aa Binary files /dev/null and b/contrib/bobtoolz/bitmaps/bobtoolz_turnedge.bmp differ diff --git a/contrib/bobtoolz/bobToolz-GTK.cpp b/contrib/bobtoolz/bobToolz-GTK.cpp new file mode 100644 index 00000000..3df73c4c --- /dev/null +++ b/contrib/bobtoolz/bobToolz-GTK.cpp @@ -0,0 +1,292 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" + +#include "funchandlers.h" +#include "misc.h" + +#include "dialogs/dialogs-gtk.h" +#include "../../libs/cmdlib.h" + +// Radiant function table +_QERFuncTable_1 g_FuncTable; +_QERAppDataTable g_AppDataTable; +_QERBrushTable g_BrushTable; +_QERShadersTable g_ShadersTable; // vvvvvvvvvvvvvvvvvvvv +_QERSelectedFaceTable g_SelectedFaceTable; // to get texture sizes +_QERQglTable g_QglTable; // for path plotting (hooking to DBobView) +_QERUITable g_MessageTable; // for path plotting (listening for update) +_QEREntityTable g_EntityTable; + +// plugin name +char* PLUGIN_NAME = "bobToolz"; + +// commands in the menu +static char* PLUGIN_COMMANDS = "About...,-,Reset Textures...,PitOMatic,-,Vis Viewer,Brush Cleanup,Polygon Builder,Caulk Selection,-,Tree Planter,Drop Entity,Plot Splines,-,Merge Patches,Split patches,Turn edge"; + +// globals +GtkWidget *g_pRadiantWnd = NULL; + +static const char *PLUGIN_ABOUT = "bobToolz for SDRadiant\n" + "by digibob (digibob@splashdamage.com)\n" + "http://www.splashdamage.com\n\n" + "Additional Contributors:\n" + "MarsMattel, RR2DO2\n"; + +extern "C" const char* QERPlug_Init( void* hApp, void* pMainWidget ) { + g_pRadiantWnd = (GtkWidget*)pMainWidget; + + return "bobToolz for GTKradiant"; +} + +extern "C" const char* QERPlug_GetName() { + return PLUGIN_NAME; +} + +extern "C" const char* QERPlug_GetCommandList() { + return PLUGIN_COMMANDS; +} + +extern "C" void QERPlug_Dispatch (const char *p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) { + LoadLists(); + + if( !stricmp( p, "brush cleanup" ) ) { + DoFixBrushes(); + } else if( !stricmp( p, "polygon builder" ) ) { + DoPolygonsTB(); + } else if( !stricmp( p, "caulk selection" ) ) { + DoCaulkSelection(); + } else if( !stricmp( p, "tree planter" ) ) { + DoTreePlanter(); + } else if( !stricmp( p, "plot splines" ) ) { + DoTrainPathPlot(); + } else if( !stricmp( p, "drop entity" ) ) { + DoDropEnts(); + } else if( !stricmp( p, "merge patches" ) ) { + DoMergePatches(); + } else if( !stricmp( p, "split patches" ) ) { + DoSplitPatch(); + } else if( !stricmp( p, "turn edge" ) ) { + DoFlipTerrain(); + } else if( !stricmp(p, "reset textures...") ) { + DoResetTextures(); + } else if( !stricmp(p, "pitomatic") ) { + DoPitBuilder(vMin, vMax); + } else if( !stricmp(p, "vis viewer") ) { + DoVisAnalyse(); + } else if( !stricmp(p, "about...") ) { + DoMessageBox(PLUGIN_ABOUT, "About", IDOK); + } +} + +#define NUM_TOOLBARBUTTONS 9 + +unsigned int ToolbarButtonCount( void ) { + return NUM_TOOLBARBUTTONS; +} + +// Load a xpm file and return a pixmap widget. +GtkWidget* new_pixmap (char* filename) { + GdkPixmap *gdkpixmap; + GdkBitmap *mask; + GtkWidget *pixmap; + + g_FuncTable.m_pfnLoadBitmap(filename, (void **)&gdkpixmap, (void **)&mask); + pixmap = gtk_pixmap_new (gdkpixmap, mask); + + gdk_pixmap_unref (gdkpixmap); + gdk_pixmap_unref (mask); + + return pixmap; +} + +class CBobtoolzToolbarButton : public IToolbarButton +{ +public: + virtual const char* getImage() const + { + switch( mIndex ) { + case 0: return "bobtoolz_cleanup.bmp"; + case 1: return "bobtoolz_poly.bmp"; + case 2: return "bobtoolz_caulk.bmp"; + case 3: return "bobtoolz_treeplanter.bmp"; + case 4: return "bobtoolz_trainpathplot.bmp"; + case 5: return "bobtoolz_dropent.bmp"; + case 6: return "bobtoolz_merge.bmp"; + case 7: return "bobtoolz_split.bmp"; + case 8: return "bobtoolz_turnedge.bmp"; + } + return NULL; + } + virtual EType getType() const + { + switch( mIndex ) { + case 3: return eToggleButton; + default: return eButton; + } + } + virtual const char* getText() const + { + switch( mIndex ) { + case 0: return "Cleanup"; + case 1: return "Polygons"; + case 2: return "Caulk"; + case 3: return "Tree Planter"; + case 4: return "Plot Splines"; + case 5: return "Drop Entity"; + case 6: return "Merge Patches"; + case 7: return "Split Patches"; + case 8: return "Flip Terrain"; + } + return NULL; + } + virtual const char* getTooltip() const + { + switch( mIndex ) { + case 0: return "Brush Cleanup"; + case 1: return "Polygons"; + case 2: return "Caulk selection"; + case 3: return "Tree Planter"; + case 4: return "Plot Splines"; + case 5: return "Drop Entity"; + case 6: return "Merge Patches"; + case 7: return "Split Patches"; + case 8: return "Flip Terrain"; + } + return NULL; + } + + virtual void activate() const + { + LoadLists(); + + switch( mIndex ) { + case 0: DoFixBrushes(); break; + case 1: DoPolygonsTB(); break; + case 2: DoCaulkSelection(); break; + case 3: DoTreePlanter(); break; + case 4: DoTrainPathPlot(); break; + case 5: DoDropEnts(); break; + case 6: DoMergePatches(); break; + case 7: DoSplitPatch(); break; + case 8: DoFlipTerrain(); break; + } + } + + int mIndex; +}; + +CBobtoolzToolbarButton g_bobtoolzToolbarButtons[NUM_TOOLBARBUTTONS]; + +const IToolbarButton* GetToolbarButton(unsigned int index) +{ + g_bobtoolzToolbarButtons[index].mIndex = index; + return &g_bobtoolzToolbarButtons[index]; +} + +// ============================================================================= +// SYNAPSE + +class CSynapseClientBobtoolz : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + CSynapseClientBobtoolz() { } + virtual ~CSynapseClientBobtoolz() { } +}; + + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientBobtoolz g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + g_SynapseClient.AddAPI(TOOLBAR_MAJOR, BOBTOOLZ_MINOR, sizeof(_QERPlugToolbarTable)); + g_SynapseClient.AddAPI(PLUGIN_MAJOR, BOBTOOLZ_MINOR, sizeof(_QERPluginTable)); + + g_SynapseClient.AddAPI(DATA_MAJOR, NULL, sizeof(g_AppDataTable), SYN_REQUIRE, &g_AppDataTable); + g_SynapseClient.AddAPI(BRUSH_MAJOR, NULL, sizeof(g_BrushTable), SYN_REQUIRE, &g_BrushTable); + g_SynapseClient.AddAPI(SHADERS_MAJOR, "*", sizeof(g_ShadersTable), SYN_REQUIRE, &g_ShadersTable); + g_SynapseClient.AddAPI(ENTITY_MAJOR, NULL, sizeof(g_EntityTable), SYN_REQUIRE, &g_EntityTable); + g_SynapseClient.AddAPI(SELECTEDFACE_MAJOR, NULL, sizeof(g_SelectedFaceTable), SYN_REQUIRE, &g_SelectedFaceTable); + g_SynapseClient.AddAPI(UI_MAJOR, NULL, sizeof(g_MessageTable), SYN_REQUIRE, &g_MessageTable); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(g_QglTable), SYN_REQUIRE, &g_QglTable); + + return &g_SynapseClient; +} + +bool CSynapseClientBobtoolz::RequestAPI(APIDescriptor_t *pAPI) +{ + if( !strcmp(pAPI->minor_name, BOBTOOLZ_MINOR) ) + { + if( !strcmp(pAPI->major_name, PLUGIN_MAJOR) ) + { + _QERPluginTable* pTable= static_cast<_QERPluginTable*>(pAPI->mpTable); + + pTable->m_pfnQERPlug_Init = QERPlug_Init; + pTable->m_pfnQERPlug_GetName = QERPlug_GetName; + pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList; + pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch; + + return true; + } + else if( !strcmp(pAPI->major_name, TOOLBAR_MAJOR) ) + { + _QERPlugToolbarTable* pTable= static_cast<_QERPlugToolbarTable*>(pAPI->mpTable); + + pTable->m_pfnToolbarButtonCount = &ToolbarButtonCount; + pTable->m_pfnGetToolbarButton = &GetToolbarButton; + + return true; + } + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientBobtoolz::GetInfo() +{ + return "bobToolz module built " __DATE__ " " RADIANT_VERSION; +} + +char* GetFilename(char* buffer, const char* filename) { + strcpy(buffer, g_pSynapseServer->GetModuleFilename(&g_SynapseClient)); + StripFilename( buffer ); + strcat(buffer, "/"); + strcat(buffer, filename); + buffer = UnixToDosPath(buffer); + return buffer; +} diff --git a/contrib/bobtoolz/bobToolz.def b/contrib/bobtoolz/bobToolz.def new file mode 100644 index 00000000..9ff9f292 --- /dev/null +++ b/contrib/bobtoolz/bobToolz.def @@ -0,0 +1,8 @@ +; plugin.def : Declares the module parameters for the DLL. + +LIBRARY "bobToolz" +; DESCRIPTION 'bobToolz Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + Synapse_EnumerateInterfaces @1 diff --git a/contrib/bobtoolz/bobToolz.h b/contrib/bobtoolz/bobToolz.h new file mode 100644 index 00000000..d4290099 --- /dev/null +++ b/contrib/bobtoolz/bobToolz.h @@ -0,0 +1,64 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// plugin.h : main header file for the PLUGIN DLL +// + +#if !defined(AFX_PLUGIN_H__3BA55F6A_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_) +#define AFX_PLUGIN_H__3BA55F6A_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 + +#ifndef __AFXWIN_H__ + #error include 'StdAfx.h' before including this file for PCH +#endif + +#include "resource.h" // main symbols + +///////////////////////////////////////////////////////////////////////////// +// CPluginApp +// See plugin.cpp for the implementation of this class +// + +class CPluginApp : public CWinApp +{ +public: + CPluginApp(); + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CPluginApp) + //}}AFX_VIRTUAL + + //{{AFX_MSG(CPluginApp) + // NOTE - the ClassWizard will add and remove member functions here. + // DO NOT EDIT what you see in these blocks of generated code ! + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + + +///////////////////////////////////////////////////////////////////////////// + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_PLUGIN_H__3BA55F6A_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_) diff --git a/contrib/bobtoolz/bobToolz.rc b/contrib/bobtoolz/bobToolz.rc new file mode 100644 index 00000000..1140cdd2 --- /dev/null +++ b/contrib/bobtoolz/bobToolz.rc @@ -0,0 +1,533 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "resource.h" +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,1,1,0 + PRODUCTVERSION 2,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080904b0" + BEGIN + VALUE "Comments", "by djbob :P and MarsMattel ~:]\0" + VALUE "CompanyName", "bobCo\0" + VALUE "FileDescription", "All your plugins are belong to us\0" + VALUE "FileVersion", "1, 1, 1, 0\0" + VALUE "InternalName", "bobToolz\0" + VALUE "LegalCopyright", "Copyright (C) y2k\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "bobToolz.DLL\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "\0" + VALUE "ProductVersion", "2, 0, 0, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x809, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// Neutral (Sys. Default) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_NEUSD) +#ifdef _WIN32 +LANGUAGE LANG_NEUTRAL, SUBLANG_SYS_DEFAULT +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUT DIALOG DISCARDABLE 0, 0, 361, 118 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About" +FONT 8, "Arial" +BEGIN + DEFPUSHBUTTON "OK",IDOK,305,100,50,14 + CTEXT "BobToolz - Q3radiant version by djbob &&&& Mars Mattel", + IDC_STATIC,5,5,350,14,SS_CENTERIMAGE + CTEXT "Latest Version Can Be Found At http://djbob.fortefide.com", + IDC_STATIC,5,20,350,15,SS_CENTERIMAGE + LTEXT "Random bobToolz comments:",IDC_STATIC,5,35,355,10 + CTEXT "Texture Alignments Are Irrelevant, You Will Be Caulked\n-QPSiren\nCaulk Me Baby One More Time\n-TTimo\nWe're Up The Creek Without A Penguin\n-Mars Mattel", + IDC_STATIC,5,45,355,50 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 354 + TOPMARGIN, 7 + BOTTOMMARGIN, 111 + END +END +#endif // APSTUDIO_INVOKED + +#endif // Neutral (Sys. Default) resources +///////////////////////////////////////////////////////////////////////////// + + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_STAIR_DIALOG DIALOG DISCARDABLE 0, 0, 246, 118 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Stair Designer" +FONT 8, "Arial" +BEGIN + DEFPUSHBUTTON "OK",IDOK,189,83,50,12 + PUSHBUTTON "Cancel",IDCANCEL,189,99,50,12 + EDITTEXT IDC_EDIT1,5,5,86,12,ES_AUTOHSCROLL + LTEXT "Stair Height",IDC_STATIC,95,5,42,15,SS_CENTERIMAGE + GROUPBOX "Direction",IDC_STATIC,7,26,85,64 + CONTROL "North",IDC_DIR_N_RADIO,"Button",BS_AUTORADIOBUTTON | + WS_GROUP,14,38,33,10 + CONTROL "South",IDC_DIR_S_RADIO,"Button",BS_AUTORADIOBUTTON,14, + 50,35,10 + CONTROL "East",IDC_DIR_E_RADIO,"Button",BS_AUTORADIOBUTTON,14,62, + 30,10 + CONTROL "West",IDC_DIR_W_RADIO,"Button",BS_AUTORADIOBUTTON,14,74, + 33,10 + GROUPBOX "Style",IDC_STATIC,97,26,82,49 + CONTROL "Original",IDC_STYLE_ORIG_RADIO,"Button", + BS_AUTORADIOBUTTON | WS_GROUP,105,35,39,10 + CONTROL "Bob's Style",IDC_STYLE_BOB_RADIO,"Button", + BS_AUTORADIOBUTTON,105,47,51,10 + CONTROL "Corner",IDC_STYLE_CORNER_RADIO,"Button", + BS_AUTORADIOBUTTON | WS_DISABLED,105,59,51,10 + EDITTEXT IDC_RISER_EDIT,7,99,85,12,ES_AUTOHSCROLL + LTEXT "Riser Texture",IDC_STATIC,95,100,60,11,SS_CENTERIMAGE + CONTROL "Use Detail Brushes",IDC_DETAIL_CHK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,100,80,75,10 +END + +IDD_POLYGON_DIALOG DIALOG DISCARDABLE 0, 0, 271, 68 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Polygon Builder" +FONT 8, "Arial" +BEGIN + PUSHBUTTON "OK",IDOK,150,50,50,14 + PUSHBUTTON "Cancel",IDCANCEL,215,50,50,14 + EDITTEXT IDC_EDIT1,7,7,76,13,ES_AUTOHSCROLL + LTEXT "Number Of Sides",IDC_STATIC,85,7,60,13,SS_CENTERIMAGE + CONTROL "Inverse Polygon",IDC_INVERSE_CHK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,149,21,75,10 + CONTROL "Use Border",IDC_BORDER_CHK,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,149,7,66,10 + EDITTEXT IDC_BORDER_EDIT,7,28,76,13,ES_AUTOHSCROLL + LTEXT "Border Size",IDC_STATIC,86,28,60,13,SS_CENTERIMAGE + CONTROL "Align Top Edge",IDC_ALIGN_CHK,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,149,35,75,10 +END + +IDD_DOOR_DIALOG DIALOG DISCARDABLE 0, 0, 327, 119 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Door Builder" +FONT 8, "Arial" +BEGIN + DEFPUSHBUTTON "OK",IDOK,270,7,50,14 + PUSHBUTTON "Cancel",IDCANCEL,270,24,50,14 + EDITTEXT IDC_FBTEXTURE_EDIT,7,7,125,14,ES_AUTOHSCROLL + LTEXT "Door Front/Back Texture",IDC_STATIC,137,7,86,14, + SS_CENTERIMAGE + EDITTEXT IDC_TRIMTEXTURE_EDIT,7,26,125,14,ES_AUTOHSCROLL + LTEXT "Door Trim Texture",IDC_STATIC,137,26,86,14, + SS_CENTERIMAGE + CONTROL "Scale Main Texture Horizontally",IDC_TEXSCALE1_CHECK, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,46,115,10 + CONTROL "Scale Main Texture Vertically",IDC_TEXSCALE2_CHECK, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,7,60,107,10 + CONTROL "Scale Trim Texture Horizontally",IDC_TEXSCALE3_CHECK, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,136,46,113,10 + CONTROL "Scale Trim Texture Vertically",IDC_TEXSCALE4_CHECK, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,136,60,105,10 + COMBOBOX IDC_MAINTEX_COMBO,7,76,126,30,CBS_DROPDOWN | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + COMBOBOX IDC_TRIMTEX_COMBO,7,99,126,30,CBS_DROPDOWN | CBS_SORT | + WS_VSCROLL | WS_TABSTOP + PUSHBUTTON "Set As Main Texture",IDC_SET_MAINTEX_BTN,139,76,82,14 + PUSHBUTTON "Set As Trim Texture",IDC_SET_TRIMTEX_BTN,139,98,82,14 + GROUPBOX "Orientation",IDC_DIR_GROUP,225,72,95,40 + CONTROL "North - South",IDC_DIR_NS_RADIO,"Button", + BS_AUTORADIOBUTTON | WS_GROUP,230,82,85,10 + CONTROL "East - West",IDC_DIR_EW_RADIO,"Button", + BS_AUTORADIOBUTTON,230,97,85,10 +END + +IDD_INTERSECT_DIALOG DIALOG DISCARDABLE 0, 0, 245, 58 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Intersecting Brush Finder" +FONT 8, "Arial" +BEGIN + DEFPUSHBUTTON "OK",IDOK,130,40,50,14 + PUSHBUTTON "Cancel",IDCANCEL,185,40,50,14 + CONTROL "Include Detail Brushes",IDC_DETAIL_INCLUDE_CHECK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,130,10,111,10 + GROUPBOX "Brush Options",IDC_STATIC,10,5,111,45 + CONTROL "Use Whole Map",IDC_WHOLEMAP_RADIO,"Button", + BS_AUTORADIOBUTTON | WS_GROUP,15,15,95,10 + CONTROL "Use Selected Brushes",IDC_SELECTED_RADIO,"Button", + BS_AUTORADIOBUTTON,15,30,95,10 + CONTROL "Only Select Duplicate Brushes",IDC_DUPLICATEONLY_CHECK, + "Button",BS_AUTOCHECKBOX | WS_TABSTOP,130,25,113,10 +END + +IDD_INTERSECT_INFO_DIALOG DIALOG DISCARDABLE 0, 0, 187, 33 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Progress1",IDC_PROGRESS1,"msctls_progress32",PBS_SMOOTH, + 5,15,175,10 + CTEXT "Brush Loading",IDC_STATIC,5,5,175,10,SS_CENTERIMAGE +END + +IDD_BRUSHCHECKER_DIALOG DIALOG DISCARDABLE 0, 0, 182, 38 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Progress1",IDC_PROGRESS1,"msctls_progress32",PBS_SMOOTH, + 5,21,172,10 + CTEXT "Checking Brushes",IDC_STATIC,5,5,170,15,SS_CENTERIMAGE +END + +IDD_AUTOCAULK_DIALOG DIALOG DISCARDABLE 0, 0, 187, 52 +STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE +FONT 8, "MS Sans Serif" +BEGIN + CONTROL "Progress1",IDC_PROGRESS1,"msctls_progress32",PBS_SMOOTH, + 5,15,175,10 + CTEXT "Loading Portal Data",IDC_STATIC,5,5,175,10, + SS_CENTERIMAGE + CONTROL "Progress1",IDC_PROGRESS2,"msctls_progress32",PBS_SMOOTH, + 5,35,175,10 + CTEXT "Auto Caulking",IDC_STATIC,5,25,175,10,SS_CENTERIMAGE +END + +IDD_AUTOCAULKSTART_DIALOG DIALOG DISCARDABLE 0, 0, 237, 83 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Auto Caulk" +FONT 8, "Arial" +BEGIN + DEFPUSHBUTTON "OK",IDOK,125,10,50,14 + PUSHBUTTON "Cancel",IDCANCEL,180,10,50,14 + CONTROL "Destroy Invisible Brushes",IDC_KILLBRUSHES_CHECK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,125,50,95,10 + LTEXT "",IDC_WARNING1_STATIC,5,65,223,11,NOT WS_GROUP + GROUPBOX "Static",IDC_STATIC,5,5,115,57 + CONTROL "Autocaulk",IDC_AC_NORMAL_RADIO,"Button", + BS_AUTORADIOBUTTON | WS_GROUP,10,15,48,10 + CONTROL "Build Mini Prt",IDC_AC_BUILD_MINI_PRT_RADIO,"Button", + BS_AUTORADIOBUTTON,10,30,56,10 + CONTROL "Autocaulk+ (Detail Brushes)",IDC_AC_SUPER_RADIO,"Button", + BS_AUTORADIOBUTTON,10,45,106,10 +END + +IDD_TEXTURE_RESET_DIALOG DIALOG DISCARDABLE 0, 0, 272, 107 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Texture Reset" +FONT 8, "Arial" +BEGIN + DEFPUSHBUTTON "OK",IDOK,160,85,50,14 + PUSHBUTTON "Cancel",IDCANCEL,215,85,50,14 + EDITTEXT IDC_RESET_TEXTURE_EDIT,5,5,118,14,ES_AUTOHSCROLL + EDITTEXT IDC_SCL_VERT_EDIT,85,45,40,14,ES_AUTOHSCROLL + EDITTEXT IDC_SCL_HOR_EDIT,85,65,40,14,ES_AUTOHSCROLL + EDITTEXT IDC_ROTATION_EDIT,85,85,40,14,ES_AUTOHSCROLL + EDITTEXT IDC_SHFT_VER_EDIT,225,45,40,14,ES_AUTOHSCROLL + EDITTEXT IDC_SHFT_HOR_EDIT,225,65,40,14,ES_AUTOHSCROLL + RTEXT "Scale::Vertical",IDC_STATIC,5,45,75,15,SS_CENTERIMAGE + RTEXT "Scale::Horizontal",IDC_STATIC,5,65,75,15,SS_CENTERIMAGE + RTEXT "Rotation",IDC_STATIC,5,85,75,15,SS_CENTERIMAGE + RTEXT "Shift::Horizontal",IDC_STATIC,160,65,60,15, + SS_CENTERIMAGE + RTEXT "Shift::Vertical",IDC_STATIC,160,45,60,15,SS_CENTERIMAGE + LTEXT "Texture To Reset",IDC_STATIC,128,5,62,15,SS_CENTERIMAGE + CONTROL "Reset All Textures",IDC_ALLTEXTURES_CHECK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,195,5,75,15 + EDITTEXT IDC_RESET_NEW_TEXTURE_EDIT,5,25,118,14,ES_AUTOHSCROLL + LTEXT "New Texture Name",IDC_STATIC,128,25,62,15, + SS_CENTERIMAGE + CONTROL "Reset Texture Only",IDC_ONLYTEXTURE_CHECK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,195,25,75,15 +END + +IDD_PATHPLOTTER_DIALOG DIALOG DISCARDABLE 0, 0, 172, 113 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Path Plotter" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "Enable",IDYES,5,92,50,14 + PUSHBUTTON "Cancel",IDCANCEL,115,92,50,14 + PUSHBUTTON "Disable",IDNO,60,92,50,14 + EDITTEXT IDC_POINTCOUNT_EDIT,5,5,80,14,ES_AUTOHSCROLL + EDITTEXT IDC_MULTIPLIER_EDIT,5,25,80,14,ES_AUTOHSCROLL + EDITTEXT IDC_GRAVITY_EDIT,5,45,80,14,ES_AUTOHSCROLL + LTEXT "Number Of Points",IDC_STATIC,90,5,60,15,SS_CENTERIMAGE + CONTROL "No Dynamic Update",IDC_NOUPDATE_CHECK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,65,80,10 + LTEXT "Multiplier",IDC_STATIC,90,25,60,15,SS_CENTERIMAGE + LTEXT "Gravity",IDC_STATIC,90,45,60,15,SS_CENTERIMAGE + CONTROL "Show Bounding Lines",IDC_SHOWEXTRA_CHECK,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,7,79,85,10 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_STAIR_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 239 + TOPMARGIN, 7 + BOTTOMMARGIN, 111 + END + + IDD_POLYGON_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 264 + TOPMARGIN, 7 + BOTTOMMARGIN, 61 + END + + IDD_DOOR_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 320 + TOPMARGIN, 7 + BOTTOMMARGIN, 112 + END + + IDD_INTERSECT_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 238 + TOPMARGIN, 7 + BOTTOMMARGIN, 51 + END + + IDD_INTERSECT_INFO_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 180 + TOPMARGIN, 7 + BOTTOMMARGIN, 25 + END + + IDD_BRUSHCHECKER_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 175 + TOPMARGIN, 7 + BOTTOMMARGIN, 31 + END + + IDD_AUTOCAULK_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 180 + TOPMARGIN, 7 + BOTTOMMARGIN, 45 + END + + IDD_AUTOCAULKSTART_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 230 + TOPMARGIN, 7 + BOTTOMMARGIN, 76 + END + + IDD_TEXTURE_RESET_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 265 + TOPMARGIN, 7 + BOTTOMMARGIN, 100 + END + + IDD_PATHPLOTTER_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 165 + TOPMARGIN, 7 + BOTTOMMARGIN, 106 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog Info +// + +IDD_DOOR_DIALOG DLGINIT +BEGIN + IDC_MAINTEX_COMBO, 0x403, 25, 0 +0x6162, 0x6573, 0x645f, 0x6f6f, 0x2f72, 0x6873, 0x6e69, 0x6d79, 0x7465, +0x6c61, 0x6f64, 0x726f, "\000" + IDC_MAINTEX_COMBO, 0x403, 33, 0 +0x6162, 0x6573, 0x645f, 0x6f6f, 0x2f72, 0x6873, 0x6e69, 0x6d79, 0x7465, +0x6c61, 0x6f64, 0x726f, 0x6f5f, 0x7475, 0x6973, 0x6564, "\000" + IDC_MAINTEX_COMBO, 0x403, 36, 0 +0x6162, 0x6573, 0x645f, 0x6f6f, 0x2f72, 0x6873, 0x6e69, 0x6d79, 0x7465, +0x6c61, 0x6f64, 0x726f, 0x6f5f, 0x7475, 0x6973, 0x6564, 0x6133, 0x0032, + + IDC_MAINTEX_COMBO, 0x403, 24, 0 +0x6f67, 0x6874, 0x6369, 0x645f, 0x6f6f, 0x2f72, 0x6f64, 0x726f, 0x3230, +0x625f, 0x6572, 0x0064, + IDC_MAINTEX_COMBO, 0x403, 31, 0 +0x6f67, 0x6874, 0x6369, 0x645f, 0x6f6f, 0x2f72, 0x6f64, 0x726f, 0x3230, +0x625f, 0x6572, 0x3264, 0x735f, 0x6968, 0x796e, "\000" + IDC_MAINTEX_COMBO, 0x403, 32, 0 +0x6f67, 0x6874, 0x6369, 0x645f, 0x6f6f, 0x2f72, 0x6f64, 0x726f, 0x3230, +0x655f, 0x6c62, 0x6575, 0x5f32, 0x6873, 0x6e69, 0x0079, + IDC_MAINTEX_COMBO, 0x403, 33, 0 +0x6f67, 0x6874, 0x6369, 0x645f, 0x6f6f, 0x2f72, 0x6f64, 0x726f, 0x3230, +0x695f, 0x6f5f, 0x6e72, 0x7461, 0x3565, 0x665f, 0x6e69, "\000" + IDC_MAINTEX_COMBO, 0x403, 21, 0 +0x6f67, 0x6874, 0x6369, 0x645f, 0x6f6f, 0x2f72, 0x6f64, 0x726f, 0x3230, +0x6a5f, "\000" + IDC_MAINTEX_COMBO, 0x403, 22, 0 +0x6f67, 0x6874, 0x6369, 0x645f, 0x6f6f, 0x2f72, 0x6f64, 0x726f, 0x3230, +0x6a5f, 0x0033, + IDC_MAINTEX_COMBO, 0x403, 22, 0 +0x6f67, 0x6874, 0x6369, 0x645f, 0x6f6f, 0x2f72, 0x6f64, 0x726f, 0x3230, +0x6a5f, 0x0034, + IDC_MAINTEX_COMBO, 0x403, 23, 0 +0x6f67, 0x6874, 0x6369, 0x645f, 0x6f6f, 0x2f72, 0x6f64, 0x726f, 0x3230, +0x6b5f, 0x6232, "\000" + IDC_TRIMTEX_COMBO, 0x403, 26, 0 +0x6162, 0x6573, 0x735f, 0x7075, 0x6f70, 0x7472, 0x732f, 0x7075, 0x6f70, +0x7472, 0x7231, 0x7375, 0x0074, + IDC_TRIMTEX_COMBO, 0x403, 27, 0 +0x6162, 0x6573, 0x735f, 0x7075, 0x6f70, 0x7472, 0x732f, 0x7075, 0x6f70, +0x7472, 0x7331, 0x6968, 0x796e, "\000" + IDC_TRIMTEX_COMBO, 0x403, 26, 0 +0x6162, 0x6573, 0x735f, 0x7075, 0x6f70, 0x7472, 0x732f, 0x7075, 0x6f70, +0x7472, 0x7232, 0x7375, 0x0074, + IDC_TRIMTEX_COMBO, 0x403, 22, 0 +0x6162, 0x6573, 0x735f, 0x7075, 0x6f70, 0x7472, 0x772f, 0x6c70, 0x7461, +0x5f31, 0x0031, + IDC_TRIMTEX_COMBO, 0x403, 22, 0 +0x6162, 0x6573, 0x735f, 0x7075, 0x6f70, 0x7472, 0x702f, 0x616c, 0x6574, +0x5f32, 0x0035, + 0 +END + + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""resource.h""\r\n" + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/contrib/bobtoolz/bobToolz_gtk.vcproj b/contrib/bobtoolz/bobToolz_gtk.vcproj new file mode 100644 index 00000000..08f32b5c --- /dev/null +++ b/contrib/bobtoolz/bobToolz_gtk.vcproj @@ -0,0 +1,177 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/bobtoolz/bobtoolz-gtk.rc b/contrib/bobtoolz/bobtoolz-gtk.rc new file mode 100644 index 00000000..d1ff0d2e --- /dev/null +++ b/contrib/bobtoolz/bobtoolz-gtk.rc @@ -0,0 +1,109 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource-gtk.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource-gtk.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,1,1,0 + PRODUCTVERSION 2,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080904b0" + BEGIN + VALUE "Comments", "by djbob :P and MarsMattel ~:)\0" + VALUE "CompanyName", "bobCo\0" + VALUE "FileDescription", "All your plugins are belong to us\0" + VALUE "FileVersion", "1, 1, 1, 0\0" + VALUE "InternalName", "bobToolz GTK\0" + VALUE "LegalCopyright", "Copyright © 2001\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "bobToolz.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "bobCo bobToolz\0" + VALUE "ProductVersion", "2, 0, 0, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x809, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/contrib/bobtoolz/bsploader.cpp b/contrib/bobtoolz/bsploader.cpp new file mode 100644 index 00000000..5c2ee582 --- /dev/null +++ b/contrib/bobtoolz/bsploader.cpp @@ -0,0 +1,258 @@ +#include "StdAfx.h" +#include "./dialogs/dialogs-gtk.h" +#include "bsploader.h" +#include "../../libs/cmdlib.h" + +int numnodes; +int numplanes; +int numleafs; +int numleafsurfaces; +int numVisBytes; +int numDrawVerts; +int numDrawSurfaces; +int numbrushes; +int numbrushsides; +int numleafbrushes; + +byte *visBytes = NULL; +dnode_t *dnodes = NULL; +dplane_t *dplanes = NULL; +dleaf_t *dleafs = NULL; +qdrawVert_t *drawVerts = NULL; +dsurface_t *drawSurfaces = NULL; +int *dleafsurfaces = NULL; +dbrush_t *dbrushes = NULL; +dbrushside_t *dbrushsides = NULL; +int *dleafbrushes = NULL; + +#define BSP_IDENT (('P'<<24)+('S'<<16)+('B'<<8)+'I') +#define Q3_BSP_VERSION 46 +#define WOLF_BSP_VERSION 47 + +/* +================ +FileLength +================ +*/ +int FileLength (FILE *f) +{ + int pos; + int end; + + pos = ftell (f); + fseek (f, 0, SEEK_END); + end = ftell (f); + fseek (f, pos, SEEK_SET); + + return end; +} + +/* +============== +LoadFile +============== +*/ +qboolean LoadFile( const char *filename, byte **bufferptr) +{ + FILE *f; + int length; + byte *buffer; + + f = fopen(filename, "rb"); + if(!f) + return false; + + length = FileLength (f); + buffer = new byte[length+1]; + buffer[length] = 0; + fread(buffer, 1, length, f); + fclose (f); + + *bufferptr = buffer; + return true; +} + +/*int LittleLong (int l) +{ + return l; +} + +float LittleFloat (float l) +{ + return l; +}*/ + +/* +============= +SwapBlock + +If all values are 32 bits, this can be used to swap everything +============= +*/ +void SwapBlock( int *block, int sizeOfBlock ) { + int i; + + sizeOfBlock >>= 2; + for ( i = 0 ; i < sizeOfBlock ; i++ ) { + block[i] = LittleLong( block[i] ); + } +} + +/* +============= +SwapBSPFile + +Byte swaps all data in a bsp file. +============= +*/ +void SwapBSPFile( void ) { + int i; + + // models +// SwapBlock( (int *)dmodels, nummodels * sizeof( dmodels[0] ) ); + + // shaders (don't swap the name) +// for ( i = 0 ; i < numShaders ; i++ ) { +// dshaders[i].contentFlags = LittleLong( dshaders[i].contentFlags ); +// dshaders[i].surfaceFlags = LittleLong( dshaders[i].surfaceFlags ); +// } + + // planes + SwapBlock( (int *)dplanes, numplanes * sizeof( dplanes[0] ) ); + + // nodes + SwapBlock( (int *)dnodes, numnodes * sizeof( dnodes[0] ) ); + + // leafs + SwapBlock( (int *)dleafs, numleafs * sizeof( dleafs[0] ) ); + + // leaffaces + SwapBlock( (int *)dleafsurfaces, numleafsurfaces * sizeof( dleafsurfaces[0] ) ); + + // leafbrushes + SwapBlock( (int *)dleafbrushes, numleafbrushes * sizeof( dleafbrushes[0] ) ); + + // brushes + SwapBlock( (int *)dbrushes, numbrushes * sizeof( dbrushes[0] ) ); + + // brushsides + SwapBlock( (int *)dbrushsides, numbrushsides * sizeof( dbrushsides[0] ) ); + + // vis + ((int *)&visBytes)[0] = LittleLong( ((int *)&visBytes)[0] ); + ((int *)&visBytes)[1] = LittleLong( ((int *)&visBytes)[1] ); + + // drawverts (don't swap colors ) + for ( i = 0 ; i < numDrawVerts ; i++ ) { + drawVerts[i].lightmap[0] = LittleFloat( drawVerts[i].lightmap[0] ); + drawVerts[i].lightmap[1] = LittleFloat( drawVerts[i].lightmap[1] ); + drawVerts[i].st[0] = LittleFloat( drawVerts[i].st[0] ); + drawVerts[i].st[1] = LittleFloat( drawVerts[i].st[1] ); + drawVerts[i].xyz[0] = LittleFloat( drawVerts[i].xyz[0] ); + drawVerts[i].xyz[1] = LittleFloat( drawVerts[i].xyz[1] ); + drawVerts[i].xyz[2] = LittleFloat( drawVerts[i].xyz[2] ); + drawVerts[i].normal[0] = LittleFloat( drawVerts[i].normal[0] ); + drawVerts[i].normal[1] = LittleFloat( drawVerts[i].normal[1] ); + drawVerts[i].normal[2] = LittleFloat( drawVerts[i].normal[2] ); + } + + // drawindexes +// SwapBlock( (int *)drawIndexes, numDrawIndexes * sizeof( drawIndexes[0] ) ); + + // drawsurfs + SwapBlock( (int *)drawSurfaces, numDrawSurfaces * sizeof( drawSurfaces[0] ) ); + + // fogs +// for ( i = 0 ; i < numFogs ; i++ ) { +// dfogs[i].brushNum = LittleLong( dfogs[i].brushNum ); +// dfogs[i].visibleSide = LittleLong( dfogs[i].visibleSide ); +// } +} + +/* +============= +CopyLump +============= +*/ +int CopyLump( dheader_t *header, int lump, void **dest, int size ) { + int length, ofs; + + length = header->lumps[lump].filelen; + ofs = header->lumps[lump].fileofs; + + if(length == 0) + return 0; + + *dest = new byte[length]; + memcpy( *dest, (byte *)header + ofs, length ); + + return length / size; +} + +/* +============= +LoadBSPFile +============= +*/ +qboolean LoadBSPFile( const char *filename ) { + dheader_t *header; + + // load the file header + if(!LoadFile (filename, (byte **)&header)) + return false; + + // swap the header + SwapBlock( (int *)header, sizeof(*header) ); + + if ( header->ident != BSP_IDENT ) { + DoMessageBox( "Cant find a valid IBSP file", "Error", MB_OK); + return false; + } + if ( (header->version != Q3_BSP_VERSION) && + (header->version != WOLF_BSP_VERSION) ) { + DoMessageBox( "File is incorrect version", "Error", MB_OK); + return false; + } + + numbrushsides = CopyLump( header, LUMP_BRUSHES, (void**)&dbrushsides, sizeof(dbrushside_t) ); + numbrushes = CopyLump( header, LUMP_BRUSHES, (void**)&dbrushes, sizeof(dbrush_t) ); + numplanes = CopyLump( header, LUMP_PLANES, (void**)&dplanes, sizeof(dplane_t) ); + numleafs = CopyLump( header, LUMP_LEAFS, (void**)&dleafs, sizeof(dleaf_t) ); + numnodes = CopyLump( header, LUMP_NODES, (void**)&dnodes, sizeof(dnode_t) ); + numDrawVerts = CopyLump( header, LUMP_DRAWVERTS, (void**)&drawVerts, sizeof(qdrawVert_t) ); + numDrawSurfaces = CopyLump( header, LUMP_SURFACES, (void**)&drawSurfaces, sizeof(dsurface_t) ); + numleafsurfaces = CopyLump( header, LUMP_LEAFSURFACES, (void**)&dleafsurfaces, sizeof(int) ); + numVisBytes = CopyLump( header, LUMP_VISIBILITY, (void**)&visBytes, 1 ); + numleafbrushes = CopyLump( header, LUMP_LEAFBRUSHES, (void**)&dleafbrushes, sizeof(int) ); + + delete header; // everything has been copied out + + // swap everything + SwapBSPFile(); + + return true; +} + +void FreeBSPData() +{ + if(visBytes) + delete visBytes; + if(dnodes) + delete dnodes; + if(dplanes) + delete dplanes; + if(dleafs) + delete dleafs; + if(drawVerts) + delete drawVerts; + if(drawSurfaces) + delete drawSurfaces; + if(dleafsurfaces) + delete dleafsurfaces; + if(dleafbrushes) + delete dleafbrushes; + if(dbrushes) + delete dbrushes; + if(dbrushsides) + delete dbrushsides; +} diff --git a/contrib/bobtoolz/bsploader.h b/contrib/bobtoolz/bsploader.h new file mode 100644 index 00000000..96f7c851 --- /dev/null +++ b/contrib/bobtoolz/bsploader.h @@ -0,0 +1,134 @@ +#define LUMP_ENTITIES 0 +#define LUMP_SHADERS 1 +#define LUMP_PLANES 2 +#define LUMP_NODES 3 +#define LUMP_LEAFS 4 +#define LUMP_LEAFSURFACES 5 +#define LUMP_LEAFBRUSHES 6 +#define LUMP_MODELS 7 +#define LUMP_BRUSHES 8 +#define LUMP_BRUSHSIDES 9 +#define LUMP_DRAWVERTS 10 +#define LUMP_DRAWINDEXES 11 +#define LUMP_FOGS 12 +#define LUMP_SURFACES 13 +#define LUMP_LIGHTMAPS 14 +#define LUMP_LIGHTGRID 15 +#define LUMP_VISIBILITY 16 +#define HEADER_LUMPS 17 + +typedef struct { + int fileofs, filelen; +} lump_t; + +typedef struct { + int ident; + int version; + + lump_t lumps[HEADER_LUMPS]; +} dheader_t; + +typedef struct { + float normal[3]; + float dist; +} dplane_t; + +typedef struct { + int planeNum; + int children[2]; // negative numbers are -(leafs+1), not nodes + int mins[3]; // for frustom culling + int maxs[3]; +} dnode_t; + +typedef struct { + int cluster; // -1 = opaque cluster (do I still store these?) + int area; + + int mins[3]; // for frustum culling + int maxs[3]; + + int firstLeafSurface; + int numLeafSurfaces; + + int firstLeafBrush; + int numLeafBrushes; +} dleaf_t; + +typedef struct { + vec3_t xyz; + float st[2]; + float lightmap[2]; + vec3_t normal; + byte color[4]; +} qdrawVert_t; + +typedef struct { + int shaderNum; + int fogNum; + int surfaceType; + + int firstVert; + int numVerts; + + int firstIndex; + int numIndexes; + + int lightmapNum; + int lightmapX, lightmapY; + int lightmapWidth, lightmapHeight; + + vec3_t lightmapOrigin; + vec3_t lightmapVecs[3]; // for patches, [0] and [1] are lodbounds + + int patchWidth; + int patchHeight; +} dsurface_t; + +typedef struct { + int planeNum; // positive plane side faces out of the leaf + int shaderNum; +} dbrushside_t; + +typedef struct { + int firstSide; + int numSides; + int shaderNum; // the shader that determines the contents flags +} dbrush_t; + +typedef enum { + MST_BAD, + MST_PLANAR, + MST_PATCH, + MST_TRIANGLE_SOUP, + MST_FLARE +} mapSurfaceType_t; + +#define MAX_MAP_VISIBILITY 0x200000 +#define MAX_MAP_NODES 0x20000 +#define MAX_MAP_PLANES 0x20000 +#define MAX_MAP_LEAFS 0x20000 + +extern int numVisBytes; +extern int numleafs; +extern int numplanes; +extern int numnodes; +extern int numDrawVerts; +extern int numDrawSurfaces; +extern int numleafsurfaces; +extern int numbrushes; +extern int numbrushsides; +extern int numleafbrushes; + +extern dnode_t *dnodes; +extern dplane_t *dplanes; +extern dleaf_t *dleafs; +extern byte *visBytes; +extern qdrawVert_t *drawVerts; +extern dsurface_t *drawSurfaces; +extern int *dleafsurfaces; +extern dbrush_t *dbrushes; +extern dbrushside_t *dbrushsides; +extern int *dleafbrushes; + +qboolean LoadBSPFile( const char *filename ); +void FreeBSPData(); diff --git a/contrib/bobtoolz/bt/bt-el1.txt b/contrib/bobtoolz/bt/bt-el1.txt new file mode 100644 index 00000000..ccac5e6e --- /dev/null +++ b/contrib/bobtoolz/bt/bt-el1.txt @@ -0,0 +1,17 @@ +common/areaportal +common/clip +common/clusterportal +common/cushion +common/donotenter +common/full_clip +common/hint +common/missileclip +common/nodraw +common/nodrawnonsolid +common/nodrop +common/noimpact +common/origin +common/trigger +common/weapclip +liquid +fog \ No newline at end of file diff --git a/contrib/bobtoolz/bt/bt-el2.txt b/contrib/bobtoolz/bt/bt-el2.txt new file mode 100644 index 00000000..e69de29b diff --git a/contrib/bobtoolz/bt/ctf-blue.txt b/contrib/bobtoolz/bt/ctf-blue.txt new file mode 100644 index 00000000..de5b0188 --- /dev/null +++ b/contrib/bobtoolz/bt/ctf-blue.txt @@ -0,0 +1,61 @@ +base_light/light1blue_2000 +base_light/light1blue_5000 +ctf/blue_telep +ctf/ctf_blueflag +ctf/ctf_tower_bluefin_shiny +gothic_door/door02_eblue2_shiny +gothic_light/ironcrossltblue_10000 +gothic_light/ironcrossltblue_2000 +gothic_light/ironcrossltblue_20000 +gothic_light/ironcrossltblue_3000 +gothic_light/ironcrossltblue_30000 +gothic_light/ironcrossltblue_4000 +gothic_light/ironcrossltblue_5000 +sfx/beam_blue +sfx/flameanim_blue +sfx/flameanim_blue_nolight +sfx/flameanim_blue_pj +sfx/mkc_fog_ctfblue +sfx/xbluefog +base_wall2/blue_metal +base_wall2/jumppad_blue_kc +base_wall2/blue_line +base_wall2/double_line_blue +base_wall2/blue_arrow_small +base_wall2/blue_circle +base_wall2/bluearrows +base_wall2/blue_solid +ctf2/blueteam01 +ctf2/blueteam02 +ctf2/xblueteam01 +ctf2/blue_banner02 +proto2/blueflag +proto2/blueob +proto2/marbledoor_blue +proto2/concrete_bluenfx +proto2/bluelight_on +proto2/bsbluelight_on +proto2/rsbluelight_off +proto2/bsbluelight_off +proto2/rsbluelight_on +proto2/bluetrim01 +proto2/blue_zot +proto2/blue_zot2 +proto2/bluea_dcl +proto2/concrete_blue +proto2/teamwerkz_blue1 +proto2/blueflare2 +proto2/blueflare +sfx2/flameanim_blue_lowlite +sfx2/blue_jumpad05 +sfx2/blue_launchpad +sfx2/blue_jumpad +sfx2/blue_jumpad2 +sfx2/blue_jumpad3 +sfx2/bluegoal2 +tim/blue_flagbase +team_icon/the fallen_blue +team_icon/intruders_blue +team_icon/crusaders_blue +team_icon/pagans_blue +team_icon/stroggs_blue \ No newline at end of file diff --git a/contrib/bobtoolz/bt/ctf-red.txt b/contrib/bobtoolz/bt/ctf-red.txt new file mode 100644 index 00000000..68c43dac --- /dev/null +++ b/contrib/bobtoolz/bt/ctf-red.txt @@ -0,0 +1,61 @@ +base_light/light1red_2000 +base_light/light1red_5000 +ctf/red_telep +ctf/ctf_redflag +ctf/ctf_tower_redfin_shiny +gothic_door/door02_bred2_shiny +gothic_light/ironcrossltred_10000 +gothic_light/ironcrossltred_2000 +gothic_light/ironcrossltred_20000 +gothic_light/ironcrossltred_3000 +gothic_light/ironcrossltred_30000 +gothic_light/ironcrossltred_4000 +gothic_light/ironcrossltred_5000 +sfx/beam_red +sfx/flameanim_red +sfx/flameanim_red_nolight +sfx/flameanim_red_pj +sfx/mkc_fog_ctfred +sfx/xredfog +base_wall2/red_metal +base_wall2/jumppad_red_kc +base_wall2/red_line +base_wall2/double_line_red +base_wall2/red_arrow_small +base_wall2/red_circle +base_wall2/redarrows +base_wall2/red_solid +ctf2/redteam01 +ctf2/redteam02 +ctf2/xredteam01x +ctf2/red_banner02 +proto2/redflag +proto2/redob +proto2/marbledoor_red +proto2/concrete_rednfx +proto2/redlight_on +proto2/bsredlight_on +proto2/rsredlight_off +proto2/bsredlight_off +proto2/rsredlight_on +proto2/redtrim01 +proto2/red_zot +proto2/red_zot2 +proto2/reda_dcl +proto2/concrete_red +proto2/teamwerkz_red1 +proto2/redflare2 +proto2/redflare +sfx2/flameanim_red_lowlite +sfx2/red_jumpad05 +sfx2/red_launchpad +sfx2/red_jumpad +sfx2/red_jumpad2 +sfx2/red_jumpad3 +sfx2/redgoal2 +tim/red_flagbase +team_icon/the fallen_red +team_icon/intruders_red +team_icon/crusaders_red +team_icon/pagans_red +team_icon/stroggs_red \ No newline at end of file diff --git a/contrib/bobtoolz/bt/door-tex-trim.txt b/contrib/bobtoolz/bt/door-tex-trim.txt new file mode 100644 index 00000000..5211a98c --- /dev/null +++ b/contrib/bobtoolz/bt/door-tex-trim.txt @@ -0,0 +1,5 @@ +base_support/support1rust +base_support/support1shiny +base_support/support2rust +base_support/wplat1_1 +base_support/plate2_5 \ No newline at end of file diff --git a/contrib/bobtoolz/bt/door-tex.txt b/contrib/bobtoolz/bt/door-tex.txt new file mode 100644 index 00000000..94b352f3 --- /dev/null +++ b/contrib/bobtoolz/bt/door-tex.txt @@ -0,0 +1,10 @@ +base_door/shinymetaldoor +base_door/shinymetaldoor_outside +gothic_door/door02_bred +gothic_door/door02_bred2_shiny +gothic_door/door02_eblue2_shiny +gothic_door/door02_i_ornate5_fin +gothic_door/door02_j +gothic_door/door02_j3 +gothic_door/door02_j4 +gothic_door/door02_k2b \ No newline at end of file diff --git a/contrib/bobtoolz/bt/tp_ent.txt b/contrib/bobtoolz/bt/tp_ent.txt new file mode 100644 index 00000000..09488da9 --- /dev/null +++ b/contrib/bobtoolz/bt/tp_ent.txt @@ -0,0 +1,14 @@ +{ + "entity" "misc_model" + + "offset" "-16" + + "model" "models/mapobjects/trees_sd/tree_a.md3" + "model" "models/mapobjects/trees_sd/tree_b.md3" + "model" "models/mapobjects/trees_sd/tree_c.md3" + "model" "models/mapobjects/trees_sd/tree_d.md3" + + "pitch" "-5" "5" + "yaw" "0" "360" + "scale" "1" "1.3" +} \ No newline at end of file diff --git a/contrib/bobtoolz/cportals.cpp b/contrib/bobtoolz/cportals.cpp new file mode 100644 index 00000000..d56c6b4c --- /dev/null +++ b/contrib/bobtoolz/cportals.cpp @@ -0,0 +1,340 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" +#include "CPortals.h" +#include "misc.h" + +#define LINE_BUF 1000 +#define MSG_PREFIX "bobToolz plugin: " + +// these classes are far less of a mess than my code was, +// thanq to G.DeWan 4 the prtview source on which it was based + +CBspPortal::CBspPortal() +{ + memset(this, 0, sizeof(CBspPortal)); +} + +CBspPortal::~CBspPortal() +{ + delete[] point; +} + +void ClampFloat(float* p) +{ + double i; + double frac = modf(*p, &i); + + if(!frac) + return; + + if(fabs(*p - ceil(*p)) < MAX_ROUND_ERROR) + *p = ceilf(*p); + + if(fabs(*p - floor(*p)) < MAX_ROUND_ERROR) + *p = floorf(*p); +} + +bool CBspPortal::Build(char *def, unsigned int pointCnt, bool bInverse) +{ + char *c = def; + unsigned int n; + + point_count = pointCnt; + + if(point_count < 3) + return FALSE; + + point = new CBspPoint[point_count]; + + for(n = 0; n < point_count; n++) + { + for(; *c != 0 && *c != '('; c++); + + if(*c == 0) + return FALSE; + + c++; + + int x; + if(bInverse) + x = point_count - n - 1; + else + x = n; + + sscanf(c, "%f %f %f", &point[x].p[0], &point[x].p[1], &point[x].p[2]); + + ClampFloat(&point[x].p[0]); + ClampFloat(&point[x].p[1]); + ClampFloat(&point[x].p[2]); + } + + return TRUE; +} + +CPortals::CPortals() +{ + memset(this, 0, sizeof(CPortals)); +} + +CPortals::~CPortals() +{ + Purge(); +} + +void CPortals::Purge() +{ + if(node) + delete[] node; + node = NULL; + node_count = 0; +} + +void CPortals::Load() +{ + char buf[LINE_BUF+1]; + + memset(buf, 0, LINE_BUF + 1); + + Purge(); + + Sys_Printf(MSG_PREFIX "Loading portal file %s.\n", fn); + + FILE *in; + + in = fopen(fn, "rt"); + + if(in == NULL) + { + Sys_Printf(" ERROR - could not open file.\n"); + + return; + } + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + if(strncmp("PRT1", buf, 4) != 0) + { + fclose(in); + + Sys_Printf(" ERROR - File header indicates wrong file type (should be \"PRT1\").\n"); + + return; + } + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + sscanf(buf, "%u", &node_count); + + if(node_count > 0xFFFF) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - Extreme number of nodes, aborting.\n"); + + return; + } + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + unsigned int p_count; + sscanf(buf, "%u", &p_count); + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + unsigned int p_count2; + sscanf(buf, "%u", &p_count2); + + node = new CBspNode[node_count]; + + unsigned int i; + for(i = 0; i < p_count; i++) + { + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + unsigned int dummy, node1, node2; + sscanf(buf, "%u %u %u", &dummy, &node1, &node2); + + node[node1].portal_count++; + node[node2].portal_count++; + } + + for(i = 0; i < p_count2; i++) + { + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + unsigned int dummy, node1; + sscanf(buf, "%u %u", &dummy, &node1); + + node[node1].portal_count++; + } + + for(i = 0; i < node_count; i++) + node[i].portal = new CBspPortal[node[i].portal_count]; + + fclose(in); + + in = fopen(fn, "rt"); + + fgets(buf, LINE_BUF, in); + fgets(buf, LINE_BUF, in); + fgets(buf, LINE_BUF, in); + fgets(buf, LINE_BUF, in); + + unsigned int n; + for(n = 0; n < p_count; n++) + { + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Could not find information for portal number %d of %d.\n", n + 1, p_count); + + return; + } + + unsigned int pCount, node1, node2; + sscanf(buf, "%u %u %u", &pCount, &node1, &node2); + + if(!node[node1].AddPortal(buf, pCount, FALSE)) + { + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Information for portal number %d of %d is not formatted correctly.\n", n + 1, p_count); + + return; + } + + if(!node[node2].AddPortal(buf, pCount, TRUE)) + { + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Information for portal number %d of %d is not formatted correctly.\n", n + 1, p_count); + + return; + } + } + + for(n = 0; n < p_count2; n++) + { + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Could not find information for portal number %d of %d.\n", n + 1, p_count); + + return; + } + + unsigned int pCount, node1; + sscanf(buf, "%u %u", &pCount, &node1); + + if(!node[node1].AddPortal(buf, pCount, FALSE)) + { + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Information for portal number %d of %d is not formatted correctly.\n", n + 1, p_count); + + return; + } + } + + fclose(in); +} + +CBspNode::CBspNode() +{ + portal = NULL; + portal_count = 0; + portal_next = 0; +} + +CBspNode::~CBspNode() +{ + if(portal != NULL) + delete[] portal; +} + +bool CBspNode::AddPortal(char *def, unsigned int pointCnt, bool bInverse) +{ + return portal[portal_next++].Build(def, pointCnt, bInverse); +} diff --git a/contrib/bobtoolz/ctfToolz-GTK.cpp b/contrib/bobtoolz/ctfToolz-GTK.cpp new file mode 100644 index 00000000..e73a27d0 --- /dev/null +++ b/contrib/bobtoolz/ctfToolz-GTK.cpp @@ -0,0 +1,97 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" + +#include "funchandlers.h" +#include "misc.h" + +#include "dialogs/dialogs-gtk.h" + +// Radiant function table +_QERFuncTable_1 g_FuncTable; +_QERAppBSPFrontendTable g_BSPTable; // for map name + +BOOL g_bBSPInitDone = FALSE; + +// plugin name +static const char *PLUGIN_NAME = "ctfToolz"; + +// commands in the menu +static const char *PLUGIN_COMMANDS = "About...,Colour Changer...,Swap Light Colours,Change Angles 180,Swap Spawn Points"; + +// globals +GtkWidget *g_pRadiantWnd=NULL; + +static const char *PLUGIN_ABOUT = "ctfToolz for GtkRadiant\n" + "by djbob\n" + "http://www.planetquake.com/toolz\n\n"; + +extern "C" LPVOID WINAPI QERPlug_GetFuncTable() +{ + return &g_FuncTable; +} + +extern "C" LPCSTR WINAPI QERPlug_Init(HMODULE hApp, GtkWidget* pMainWidget) +{ + g_pRadiantWnd = pMainWidget; + memset(&g_FuncTable, 0, sizeof(_QERFuncTable_1)); + g_FuncTable.m_fVersion = QER_PLUG_VERSION; + g_FuncTable.m_nSize = sizeof(_QERFuncTable_1); + + return "ctfToolz for GTKradiant"; +} + +extern "C" LPCSTR WINAPI QERPlug_GetName() +{ + return (char*)PLUGIN_NAME; +} + +extern "C" LPCSTR WINAPI QERPlug_GetCommandList() +{ + return (char*)PLUGIN_COMMANDS; +} + +extern "C" void WINAPI QERPlug_Dispatch (LPCSTR p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) +{ + LoadLists(); + + if (!g_bBSPInitDone) + { + g_BSPTable.m_nSize = sizeof(_QERAppBSPFrontendTable); + if ( g_FuncTable.m_pfnRequestInterface( QERAppBSPFrontendTable_GUID, static_cast(&g_BSPTable) ) ) + g_bBSPInitDone = TRUE; + else + { + Sys_ERROR("_QERAppBSPFrontendTable interface request failed\n"); + return; + } + } + + if(!strcmp(p, "About...")) + DoMessageBox(PLUGIN_ABOUT, "About", IDOK); + else if(!strcmp(p, "Colour Changer...")) + DoCTFColourChanger(); + else if(!strcmp(p, "Swap Light Colours")) + DoSwapLights(); + else if(!strcmp(p, "Change Angles 180")) + DoChangeAngles(); + else if(!strcmp(p, "Swap Spawn Points")) + DoSwapSpawns(); +} diff --git a/contrib/bobtoolz/ctfresource_gtk.h b/contrib/bobtoolz/ctfresource_gtk.h new file mode 100644 index 00000000..e0d51870 --- /dev/null +++ b/contrib/bobtoolz/ctfresource_gtk.h @@ -0,0 +1,34 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by ctfresource_gtk.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/contrib/bobtoolz/ctfresource_gtk.rc b/contrib/bobtoolz/ctfresource_gtk.rc new file mode 100644 index 00000000..c3e9d5d8 --- /dev/null +++ b/contrib/bobtoolz/ctfresource_gtk.rc @@ -0,0 +1,109 @@ +//Microsoft Developer Studio generated resource script. +// +#include "ctfresource_gtk.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.K.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENG) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_UK +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "ctfresource_gtk.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 1,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x40004L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "080904b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "bobCo\0" + VALUE "FileDescription", "All your plugins are belong to us\0" + VALUE "FileVersion", "1, 0, 0, 0\0" + VALUE "InternalName", "ctftoolz\0" + VALUE "LegalCopyright", "Copyright © 2001\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "ctftoolz.dll\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "bobCo ctftoolz\0" + VALUE "ProductVersion", "1, 0, 0, 0\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x809, 1200 + END +END + +#endif // !_MAC + +#endif // English (U.K.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/contrib/bobtoolz/ctftoolz.def b/contrib/bobtoolz/ctftoolz.def new file mode 100644 index 00000000..be5bab42 --- /dev/null +++ b/contrib/bobtoolz/ctftoolz.def @@ -0,0 +1,12 @@ +; plugin.def : Declares the module parameters for the DLL. + +LIBRARY "ctfToolz" +DESCRIPTION 'ctfToolz Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + QERPlug_Init @1 + QERPlug_GetName @2 + QERPlug_GetCommandList @3 + QERPlug_Dispatch @4 + QERPlug_GetFuncTable @5 diff --git a/contrib/bobtoolz/dialogs/AboutDialog.cpp b/contrib/bobtoolz/dialogs/AboutDialog.cpp new file mode 100644 index 00000000..250a231c --- /dev/null +++ b/contrib/bobtoolz/dialogs/AboutDialog.cpp @@ -0,0 +1,62 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// AboutDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "AboutDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +//static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CAboutDialog dialog + + +CAboutDialog::CAboutDialog(CWnd* pParent /*=NULL*/) + : CDialog(CAboutDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CAboutDialog) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + + +void CAboutDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAboutDialog) + // NOTE: the ClassWizard will add DDX and DDV calls here + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CAboutDialog, CDialog) + //{{AFX_MSG_MAP(CAboutDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CAboutDialog message handlers + diff --git a/contrib/bobtoolz/dialogs/AboutDialog.h b/contrib/bobtoolz/dialogs/AboutDialog.h new file mode 100644 index 00000000..6467b4a6 --- /dev/null +++ b/contrib/bobtoolz/dialogs/AboutDialog.h @@ -0,0 +1,64 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_ABOUTDIALOG_H__3BA55F71_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_) +#define AFX_ABOUTDIALOG_H__3BA55F71_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// AboutDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CAboutDialog dialog + +class CAboutDialog : public CDialog +{ +// Construction +public: + CAboutDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CAboutDialog) + enum { IDD = IDD_ABOUT }; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CAboutDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CAboutDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_ABOUTDIALOG_H__3BA55F71_1D27_11D3_BC7B_F7EFD9765E37__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/AutoCaulkDialog.cpp b/contrib/bobtoolz/dialogs/AutoCaulkDialog.cpp new file mode 100644 index 00000000..ba5f109c --- /dev/null +++ b/contrib/bobtoolz/dialogs/AutoCaulkDialog.cpp @@ -0,0 +1,63 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// AutoCaulkDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "../bobtoolz.h" +#include "AutoCaulkDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CAutoCaulkDialog dialog + + +CAutoCaulkDialog::CAutoCaulkDialog(CWnd* pParent /*=NULL*/) + : CDialog(CAutoCaulkDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CAutoCaulkDialog) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + + +void CAutoCaulkDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAutoCaulkDialog) + DDX_Control(pDX, IDC_PROGRESS2, m_prog2); + DDX_Control(pDX, IDC_PROGRESS1, m_prog1); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CAutoCaulkDialog, CDialog) + //{{AFX_MSG_MAP(CAutoCaulkDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CAutoCaulkDialog message handlers diff --git a/contrib/bobtoolz/dialogs/AutoCaulkDialog.h b/contrib/bobtoolz/dialogs/AutoCaulkDialog.h new file mode 100644 index 00000000..313a547b --- /dev/null +++ b/contrib/bobtoolz/dialogs/AutoCaulkDialog.h @@ -0,0 +1,66 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_AUTOCAULKDIALOG_H__C2783D61_DDEB_11D4_ACF6_004095A18133__INCLUDED_) +#define AFX_AUTOCAULKDIALOG_H__C2783D61_DDEB_11D4_ACF6_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// AutoCaulkDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CAutoCaulkDialog dialog + +class CAutoCaulkDialog : public CDialog +{ +// Construction +public: + CAutoCaulkDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CAutoCaulkDialog) + enum { IDD = IDD_AUTOCAULK_DIALOG }; + CProgressCtrl m_prog2; + CProgressCtrl m_prog1; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CAutoCaulkDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CAutoCaulkDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_AUTOCAULKDIALOG_H__C2783D61_DDEB_11D4_ACF6_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.cpp b/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.cpp new file mode 100644 index 00000000..3eca76f8 --- /dev/null +++ b/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.cpp @@ -0,0 +1,66 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// AutoCaulkStartDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "../bobtoolz.h" +#include "AutoCaulkStartDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CAutoCaulkStartDialog dialog + + +CAutoCaulkStartDialog::CAutoCaulkStartDialog(CWnd* pParent /*=NULL*/) + : CDialog(CAutoCaulkStartDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CAutoCaulkStartDialog) + m_bAllowDestruction = FALSE; + m_Warning1 = _T(""); + m_nMode = 0; + //}}AFX_DATA_INIT +} + + +void CAutoCaulkStartDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAutoCaulkStartDialog) + DDX_Check(pDX, IDC_KILLBRUSHES_CHECK, m_bAllowDestruction); + DDX_Text(pDX, IDC_WARNING1_STATIC, m_Warning1); + DDX_Radio(pDX, IDC_AC_NORMAL_RADIO, m_nMode); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CAutoCaulkStartDialog, CDialog) + //{{AFX_MSG_MAP(CAutoCaulkStartDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CAutoCaulkStartDialog message handlers diff --git a/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.h b/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.h new file mode 100644 index 00000000..753b068c --- /dev/null +++ b/contrib/bobtoolz/dialogs/AutoCaulkStartDialog.h @@ -0,0 +1,71 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_AUTOCAULKSTARTDIALOG_H__F3DE2E81_E73E_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_AUTOCAULKSTARTDIALOG_H__F3DE2E81_E73E_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// AutoCaulkStartDialog.h : header file +// + +#define MODE_AC_NORMAL 0 +#define MODE_AC_BUILD_MINI_PRT 1 +#define MODE_AC_SUPER 2 + +///////////////////////////////////////////////////////////////////////////// +// CAutoCaulkStartDialog dialog + +class CAutoCaulkStartDialog : public CDialog +{ +// Construction +public: + CAutoCaulkStartDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CAutoCaulkStartDialog) + enum { IDD = IDD_AUTOCAULKSTART_DIALOG }; + BOOL m_bAllowDestruction; + CString m_Warning1; + int m_nMode; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CAutoCaulkStartDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CAutoCaulkStartDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_AUTOCAULKSTARTDIALOG_H__F3DE2E81_E73E_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/BrushCheckDialog.h b/contrib/bobtoolz/dialogs/BrushCheckDialog.h new file mode 100644 index 00000000..776c6137 --- /dev/null +++ b/contrib/bobtoolz/dialogs/BrushCheckDialog.h @@ -0,0 +1,65 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_BRUSHCHECKDIALOG_H__4BF2C701_D9EF_11D4_ACF6_004095A18133__INCLUDED_) +#define AFX_BRUSHCHECKDIALOG_H__4BF2C701_D9EF_11D4_ACF6_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// BrushCheckDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CBrushCheckDialog dialog + +class CBrushCheckDialog : public CDialog +{ +// Construction +public: + CBrushCheckDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CBrushCheckDialog) + enum { IDD = IDD_BRUSHCHECKER_DIALOG }; + CProgressCtrl m_prog1; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CBrushCheckDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CBrushCheckDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_BRUSHCHECKDIALOG_H__4BF2C701_D9EF_11D4_ACF6_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/DoorDialog.cpp b/contrib/bobtoolz/dialogs/DoorDialog.cpp new file mode 100644 index 00000000..159d6e15 --- /dev/null +++ b/contrib/bobtoolz/dialogs/DoorDialog.cpp @@ -0,0 +1,92 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// DoorDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "DoorDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CDoorDialog dialog + + +CDoorDialog::CDoorDialog(CWnd* pParent /*=NULL*/) + : CDialog(CDoorDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CDoorDialog) + m_fbTextureName = _T(""); + m_bSclMainHor = TRUE; + m_bSclMainVert = TRUE; + m_bSclTrimHor = TRUE; + m_bSclTrimVert = FALSE; + m_trimTextureName = _T(""); + m_trimTexSetBox = _T(""); + m_mainTexSetBox = _T(""); + m_doorDirection = -1; + //}}AFX_DATA_INIT +} + + +void CDoorDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CDoorDialog) + DDX_Text(pDX, IDC_FBTEXTURE_EDIT, m_fbTextureName); + DDX_Check(pDX, IDC_TEXSCALE1_CHECK, m_bSclMainHor); + DDX_Check(pDX, IDC_TEXSCALE2_CHECK, m_bSclMainVert); + DDX_Check(pDX, IDC_TEXSCALE3_CHECK, m_bSclTrimHor); + DDX_Check(pDX, IDC_TEXSCALE4_CHECK, m_bSclTrimVert); + DDX_Text(pDX, IDC_TRIMTEXTURE_EDIT, m_trimTextureName); + DDX_CBString(pDX, IDC_TRIMTEX_COMBO, m_trimTexSetBox); + DDX_CBString(pDX, IDC_MAINTEX_COMBO, m_mainTexSetBox); + DDX_Radio(pDX, IDC_DIR_NS_RADIO, m_doorDirection); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CDoorDialog, CDialog) + //{{AFX_MSG_MAP(CDoorDialog) + ON_BN_CLICKED(IDC_SET_MAINTEX_BTN, OnSetMaintexBtn) + ON_BN_CLICKED(IDC_SET_TRIMTEX_BTN, OnSetTrimtexBtn) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CDoorDialog message handlers + +void CDoorDialog::OnSetMaintexBtn() +{ + UpdateData(TRUE); + m_fbTextureName = m_mainTexSetBox; + UpdateData(FALSE); +} + +void CDoorDialog::OnSetTrimtexBtn() +{ + UpdateData(TRUE); + m_trimTextureName = m_trimTexSetBox; + UpdateData(FALSE); +} diff --git a/contrib/bobtoolz/dialogs/DoorDialog.h b/contrib/bobtoolz/dialogs/DoorDialog.h new file mode 100644 index 00000000..a40fd5b6 --- /dev/null +++ b/contrib/bobtoolz/dialogs/DoorDialog.h @@ -0,0 +1,74 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_DOORDIALOG_H__F36CBE01_D2C4_11D4_AE97_004095A18133__INCLUDED_) +#define AFX_DOORDIALOG_H__F36CBE01_D2C4_11D4_AE97_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// DoorDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CDoorDialog dialog + +class CDoorDialog : public CDialog +{ +// Construction +public: + CDoorDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CDoorDialog) + enum { IDD = IDD_DOOR_DIALOG }; + CString m_fbTextureName; + BOOL m_bSclMainHor; + BOOL m_bSclMainVert; + BOOL m_bSclTrimHor; + BOOL m_bSclTrimVert; + CString m_trimTextureName; + CString m_trimTexSetBox; + CString m_mainTexSetBox; + int m_doorDirection; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CDoorDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CDoorDialog) + afx_msg void OnSetMaintexBtn(); + afx_msg void OnSetTrimtexBtn(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_DOORDIALOG_H__F36CBE01_D2C4_11D4_AE97_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/IntersectDialog.cpp b/contrib/bobtoolz/dialogs/IntersectDialog.cpp new file mode 100644 index 00000000..8ffc0fb3 --- /dev/null +++ b/contrib/bobtoolz/dialogs/IntersectDialog.cpp @@ -0,0 +1,65 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// IntersectDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "IntersectDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CIntersectDialog dialog + + +CIntersectDialog::CIntersectDialog(CWnd* pParent /*=NULL*/) + : CDialog(CIntersectDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CIntersectDialog) + m_nBrushOptions = 1; + m_bUseDetail = FALSE; + m_bDuplicateOnly = FALSE; + //}}AFX_DATA_INIT +} + + +void CIntersectDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CIntersectDialog) + DDX_Radio(pDX, IDC_WHOLEMAP_RADIO, m_nBrushOptions); + DDX_Check(pDX, IDC_DETAIL_INCLUDE_CHECK, m_bUseDetail); + DDX_Check(pDX, IDC_DUPLICATEONLY_CHECK, m_bDuplicateOnly); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CIntersectDialog, CDialog) + //{{AFX_MSG_MAP(CIntersectDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CIntersectDialog message handlers diff --git a/contrib/bobtoolz/dialogs/IntersectDialog.h b/contrib/bobtoolz/dialogs/IntersectDialog.h new file mode 100644 index 00000000..79a6e3cb --- /dev/null +++ b/contrib/bobtoolz/dialogs/IntersectDialog.h @@ -0,0 +1,70 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_INTERSECTDIALOG_H__03507C01_D3B3_11D4_AE97_004095A18133__INCLUDED_) +#define AFX_INTERSECTDIALOG_H__03507C01_D3B3_11D4_AE97_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// IntersectDialog.h : header file +// + +#define BRUSH_OPT_WHOLE_MAP 0 +#define BRUSH_OPT_SELECTED 1 + +///////////////////////////////////////////////////////////////////////////// +// CIntersectDialog dialog + +class CIntersectDialog : public CDialog +{ +// Construction +public: + CIntersectDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CIntersectDialog) + enum { IDD = IDD_INTERSECT_DIALOG }; + int m_nBrushOptions; + BOOL m_bUseDetail; + BOOL m_bDuplicateOnly; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CIntersectDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CIntersectDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_INTERSECTDIALOG_H__03507C01_D3B3_11D4_AE97_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/IntersectInfoDialog.cpp b/contrib/bobtoolz/dialogs/IntersectInfoDialog.cpp new file mode 100644 index 00000000..77a63985 --- /dev/null +++ b/contrib/bobtoolz/dialogs/IntersectInfoDialog.cpp @@ -0,0 +1,61 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// IntersectInfoDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "../bobtoolz.h" +#include "IntersectInfoDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CIntersectInfoDialog dialog + + +CIntersectInfoDialog::CIntersectInfoDialog(CWnd* pParent /*=NULL*/) + : CDialog(CIntersectInfoDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CIntersectInfoDialog) + //}}AFX_DATA_INIT +} + + +void CIntersectInfoDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CIntersectInfoDialog) + DDX_Control(pDX, IDC_PROGRESS1, m_prog1); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CIntersectInfoDialog, CDialog) + //{{AFX_MSG_MAP(CIntersectInfoDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CIntersectInfoDialog message handlers diff --git a/contrib/bobtoolz/dialogs/IntersectInfoDialog.h b/contrib/bobtoolz/dialogs/IntersectInfoDialog.h new file mode 100644 index 00000000..72709ab3 --- /dev/null +++ b/contrib/bobtoolz/dialogs/IntersectInfoDialog.h @@ -0,0 +1,65 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_INTERSECTINFODIALOG_H__62CDC8CD_D9D2_11D4_ACF6_004095A18133__INCLUDED_) +#define AFX_INTERSECTINFODIALOG_H__62CDC8CD_D9D2_11D4_ACF6_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// IntersectInfoDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CIntersectInfoDialog dialog + +class CIntersectInfoDialog : public CDialog +{ +// Construction +public: + CIntersectInfoDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CIntersectInfoDialog) + enum { IDD = IDD_INTERSECT_INFO_DIALOG }; + CProgressCtrl m_prog1; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CIntersectInfoDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CIntersectInfoDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_INTERSECTINFODIALOG_H__62CDC8CD_D9D2_11D4_ACF6_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/PolygonDialog.cpp b/contrib/bobtoolz/dialogs/PolygonDialog.cpp new file mode 100644 index 00000000..e4342192 --- /dev/null +++ b/contrib/bobtoolz/dialogs/PolygonDialog.cpp @@ -0,0 +1,116 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// PolygonDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "PolygonDialog.h" +#include "../shapes.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CPolygonDialog dialog + + +CPolygonDialog::CPolygonDialog(CWnd* pParent /*=NULL*/) + : CDialog(CPolygonDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CPolygonDialog) + m_nSideCount = 3; + m_bInverse = FALSE; + m_bBorder = FALSE; + m_nBorderSize = 8; + m_bAlignTop = FALSE; + //}}AFX_DATA_INIT +} + +void CPolygonDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CPolygonDialog) + DDX_Text(pDX, IDC_EDIT1, m_nSideCount); + DDV_MinMaxUInt(pDX, m_nSideCount, 3, MAX_POLYGON_FACES); + DDX_Check(pDX, IDC_INVERSE_CHK, m_bInverse); + DDX_Check(pDX, IDC_BORDER_CHK, m_bBorder); + DDX_Text(pDX, IDC_BORDER_EDIT, m_nBorderSize); + DDV_MinMaxUInt(pDX, m_nBorderSize, 1, 1024); + DDX_Check(pDX, IDC_ALIGN_CHK, m_bAlignTop); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CPolygonDialog, CDialog) + //{{AFX_MSG_MAP(CPolygonDialog) + ON_BN_CLICKED(IDC_BORDER_CHK, OnBorderChkClicked) + ON_BN_CLICKED(IDC_INVERSE_CHK, OnInverseChkClickrd) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CPolygonDialog message handlers + +BOOL CPolygonDialog::OnInitDialog() +{ + CDialog::OnInitDialog(); + + EnableBordered(!GetChkBool(IDC_INVERSE_CHK)); + EnableBorderEdit(!GetChkBool(IDC_INVERSE_CHK) && GetChkBool(IDC_BORDER_CHK)); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CPolygonDialog::EnableBordered(BOOL bEnable) +{ + CWnd* dtlChk = GetDlgItem(IDC_BORDER_CHK); + if(dtlChk) + dtlChk->EnableWindow(bEnable); +} + +void CPolygonDialog::EnableBorderEdit(BOOL bEnable) +{ + CWnd* dtlChk = GetDlgItem(IDC_BORDER_EDIT); + if(dtlChk) + dtlChk->EnableWindow(bEnable); +} + +void CPolygonDialog::OnBorderChkClicked() +{ + EnableBorderEdit(!GetChkBool(IDC_INVERSE_CHK) && GetChkBool(IDC_BORDER_CHK)); +} + +void CPolygonDialog::OnInverseChkClickrd() +{ + EnableBordered(!GetChkBool(IDC_INVERSE_CHK)); + EnableBorderEdit(!GetChkBool(IDC_INVERSE_CHK) && GetChkBool(IDC_BORDER_CHK)); +} + +BOOL CPolygonDialog::GetChkBool(int nID) +{ + CButton* btn = (CButton*)GetDlgItem(nID); + if(btn) + return btn->GetCheck(); + return FALSE; +} diff --git a/contrib/bobtoolz/dialogs/PolygonDialog.h b/contrib/bobtoolz/dialogs/PolygonDialog.h new file mode 100644 index 00000000..d556f500 --- /dev/null +++ b/contrib/bobtoolz/dialogs/PolygonDialog.h @@ -0,0 +1,74 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_POLYGONDIALOG_H__EF7FE400_628A_11D1_B66D_004095A18133__INCLUDED_) +#define AFX_POLYGONDIALOG_H__EF7FE400_628A_11D1_B66D_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// PolygonDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CPolygonDialog dialog + +class CPolygonDialog : public CDialog +{ +// Construction +public: + BOOL GetChkBool(int nID); + void EnableBorderEdit(BOOL bEnable); + void EnableBordered(BOOL bEnable); + CPolygonDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CPolygonDialog) + enum { IDD = IDD_POLYGON_DIALOG }; + UINT m_nSideCount; + BOOL m_bInverse; + BOOL m_bBorder; + UINT m_nBorderSize; + BOOL m_bAlignTop; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CPolygonDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CPolygonDialog) + virtual BOOL OnInitDialog(); + afx_msg void OnBorderChkClicked(); + afx_msg void OnInverseChkClickrd(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_POLYGONDIALOG_H__EF7FE400_628A_11D1_B66D_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/StairDialog.cpp b/contrib/bobtoolz/dialogs/StairDialog.cpp new file mode 100644 index 00000000..c8e60bc2 --- /dev/null +++ b/contrib/bobtoolz/dialogs/StairDialog.cpp @@ -0,0 +1,105 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// StairDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "StairDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CStairDialog dialog + + +CStairDialog::CStairDialog(CWnd* pParent /*=NULL*/) + : CDialog(CStairDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CStairDialog) + m_nStairHeight = 8; + m_StairDir = 0; + m_StairStyle = 0; + m_riserTexture = _T(""); + m_bDetail = TRUE; + //}}AFX_DATA_INIT +} + +void CStairDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CStairDialog) + DDX_Text(pDX, IDC_EDIT1, m_nStairHeight); + DDV_MinMaxUInt(pDX, m_nStairHeight, 1, 256); + DDX_Radio(pDX, IDC_DIR_N_RADIO, m_StairDir); + DDX_Radio(pDX, IDC_STYLE_ORIG_RADIO, m_StairStyle); + DDX_Text(pDX, IDC_RISER_EDIT, m_riserTexture); + DDV_MaxChars(pDX, m_riserTexture, 256); + DDX_Check(pDX, IDC_DETAIL_CHK, m_bDetail); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CStairDialog, CDialog) + //{{AFX_MSG_MAP(CStairDialog) + ON_BN_CLICKED(IDC_STYLE_BOB_RADIO, OnStyleBobClicked) + ON_BN_CLICKED(IDC_STYLE_ORIG_RADIO, OnStyleOrigClicked) + ON_BN_CLICKED(IDC_STYLE_CORNER_RADIO, OnStyleCornerClicked) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CStairDialog message handlers + +void CStairDialog::OnStyleBobClicked() +{ + EnableDetail(TRUE); +} + +void CStairDialog::OnStyleOrigClicked() +{ + EnableDetail(FALSE); +} + +void CStairDialog::EnableDetail(BOOL bEnable) +{ + CWnd* dtlChk = GetDlgItem(IDC_DETAIL_CHK); + if(dtlChk) + dtlChk->EnableWindow(bEnable); +} + + +BOOL CStairDialog::OnInitDialog() +{ + CDialog::OnInitDialog(); + + EnableDetail(m_StairStyle == 1); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CStairDialog::OnStyleCornerClicked() +{ + EnableDetail(FALSE); +} diff --git a/contrib/bobtoolz/dialogs/StairDialog.h b/contrib/bobtoolz/dialogs/StairDialog.h new file mode 100644 index 00000000..c42959af --- /dev/null +++ b/contrib/bobtoolz/dialogs/StairDialog.h @@ -0,0 +1,74 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_STAIRDIALOG_H__942FFF20_5F9E_11D1_B66D_004095A18133__INCLUDED_) +#define AFX_STAIRDIALOG_H__942FFF20_5F9E_11D1_B66D_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// StairDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CStairDialog dialog + +class CStairDialog : public CDialog +{ +// Construction +public: + CStairDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CStairDialog) + enum { IDD = IDD_STAIR_DIALOG }; + UINT m_nStairHeight; + int m_StairDir; + int m_StairStyle; + CString m_riserTexture; + BOOL m_bDetail; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CStairDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CStairDialog) + afx_msg void OnStyleBobClicked(); + afx_msg void OnStyleOrigClicked(); + virtual BOOL OnInitDialog(); + afx_msg void OnStyleCornerClicked(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +private: + void EnableDetail(BOOL bEnable); +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STAIRDIALOG_H__942FFF20_5F9E_11D1_B66D_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/TextureResetDialog.cpp b/contrib/bobtoolz/dialogs/TextureResetDialog.cpp new file mode 100644 index 00000000..10c57f1b --- /dev/null +++ b/contrib/bobtoolz/dialogs/TextureResetDialog.cpp @@ -0,0 +1,81 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// TextureResetDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "../bobtoolz.h" +#include "TextureResetDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CTextureResetDialog dialog + + +CTextureResetDialog::CTextureResetDialog(CWnd* pParent /*=NULL*/) + : CDialog(CTextureResetDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CTextureResetDialog) + m_bAllTextures = FALSE; + m_TextureName = _T(""); + m_nRotation = 0; + m_fScaleHorizontal = 0.5f; + m_fScaleVertical = 0.5f; + m_nShiftHorizontal = 0; + m_nShiftVertical = 0; + m_bOnlyTexture = FALSE; + m_NewTextureName = _T(""); + //}}AFX_DATA_INIT +} + + +void CTextureResetDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CTextureResetDialog) + DDX_Check(pDX, IDC_ALLTEXTURES_CHECK, m_bAllTextures); + DDX_Text(pDX, IDC_RESET_TEXTURE_EDIT, m_TextureName); + DDV_MaxChars(pDX, m_TextureName, 256); + DDX_Text(pDX, IDC_ROTATION_EDIT, m_nRotation); + DDV_MinMaxInt(pDX, m_nRotation, 0, 360); + DDX_Text(pDX, IDC_SCL_HOR_EDIT, m_fScaleHorizontal); + DDX_Text(pDX, IDC_SCL_VERT_EDIT, m_fScaleVertical); + DDX_Text(pDX, IDC_SHFT_HOR_EDIT, m_nShiftHorizontal); + DDX_Text(pDX, IDC_SHFT_VER_EDIT, m_nShiftVertical); + DDX_Check(pDX, IDC_ONLYTEXTURE_CHECK, m_bOnlyTexture); + DDX_Text(pDX, IDC_RESET_NEW_TEXTURE_EDIT, m_NewTextureName); + DDV_MaxChars(pDX, m_NewTextureName, 256); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CTextureResetDialog, CDialog) + //{{AFX_MSG_MAP(CTextureResetDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CTextureResetDialog message handlers diff --git a/contrib/bobtoolz/dialogs/TextureResetDialog.h b/contrib/bobtoolz/dialogs/TextureResetDialog.h new file mode 100644 index 00000000..e0843505 --- /dev/null +++ b/contrib/bobtoolz/dialogs/TextureResetDialog.h @@ -0,0 +1,73 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_TEXTURERESETDIALOG_H__42D665C1_ED84_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_TEXTURERESETDIALOG_H__42D665C1_ED84_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// TextureResetDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CTextureResetDialog dialog + +class CTextureResetDialog : public CDialog +{ +// Construction +public: + CTextureResetDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CTextureResetDialog) + enum { IDD = IDD_TEXTURE_RESET_DIALOG }; + BOOL m_bAllTextures; + CString m_TextureName; + int m_nRotation; + float m_fScaleHorizontal; + float m_fScaleVertical; + int m_nShiftHorizontal; + int m_nShiftVertical; + BOOL m_bOnlyTexture; + CString m_NewTextureName; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CTextureResetDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CTextureResetDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_TEXTURERESETDIALOG_H__42D665C1_ED84_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/dialogs/brushcheckdialog.cpp b/contrib/bobtoolz/dialogs/brushcheckdialog.cpp new file mode 100644 index 00000000..5082d8a5 --- /dev/null +++ b/contrib/bobtoolz/dialogs/brushcheckdialog.cpp @@ -0,0 +1,61 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// BrushCheckDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "../bobtoolz.h" +#include "BrushCheckDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CBrushCheckDialog dialog + + +CBrushCheckDialog::CBrushCheckDialog(CWnd* pParent /*=NULL*/) + : CDialog(CBrushCheckDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CBrushCheckDialog) + //}}AFX_DATA_INIT +} + + +void CBrushCheckDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CBrushCheckDialog) + DDX_Control(pDX, IDC_PROGRESS1, m_prog1); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CBrushCheckDialog, CDialog) + //{{AFX_MSG_MAP(CBrushCheckDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CBrushCheckDialog message handlers diff --git a/contrib/bobtoolz/dialogs/dialogs-gtk.cpp b/contrib/bobtoolz/dialogs/dialogs-gtk.cpp new file mode 100644 index 00000000..f59ff754 --- /dev/null +++ b/contrib/bobtoolz/dialogs/dialogs-gtk.cpp @@ -0,0 +1,1894 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "../StdAfx.h" +#include "dialogs-gtk.h" +#include "../funchandlers.h" +#include "../lists.h" +#include "../misc.h" + +/*-------------------------------- + Callback Functions +---------------------------------*/ + +typedef struct { + GtkWidget *cbTexChange; + GtkWidget *editTexOld, *editTexNew; + + GtkWidget *cbScaleHor, *cbScaleVert; + GtkWidget *editScaleHor, *editScaleVert; + + GtkWidget *cbShiftHor, *cbShiftVert; + GtkWidget *editShiftHor, *editShiftVert; + + GtkWidget *cbRotation; + GtkWidget *editRotation; +}dlg_texReset_t; + +dlg_texReset_t dlgTexReset; + +void Update_TextureReseter(); + +static void dialog_button_callback_texreset_update (GtkWidget *widget, gpointer data) +{ + Update_TextureReseter(); +} + +void Update_TextureReseter() +{ + gboolean check; + + check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbTexChange )); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editTexNew), check); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editTexOld), check); + + check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbScaleHor )); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editScaleHor), check); + + check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbScaleVert )); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editScaleVert), check); + + check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbShiftHor )); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editShiftHor), check); + + check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbShiftVert )); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editShiftVert), check); + + check = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbRotation )); + gtk_entry_set_editable (GTK_ENTRY (dlgTexReset.editRotation), check); +} + +static void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +static void dialog_button_callback_settex (GtkWidget *widget, gpointer data) +{ + TwinWidget* tw = (TwinWidget*)data; + + GtkEntry* entry = GTK_ENTRY( tw->one ); + GtkCombo* combo = GTK_COMBO( tw->two ); + + const gchar* tex = gtk_entry_get_text(GTK_ENTRY( combo->entry )); + gtk_entry_set_text( entry, tex); +} + +/*-------------------------------- + Data validation Routines +---------------------------------*/ + +bool ValidateTextFloat(const char* pData, char* error_title, float* value) +{ + if(pData) + { + float testNum = (float)atof(pData); + + if((testNum == 0.0f) && strcmp(pData, "0")) + { + DoMessageBox("Please Enter A Floating Point Number", error_title, MB_OK); + return FALSE; + } + else + { + *value = testNum; + return TRUE; + } + } + + DoMessageBox("Please Enter A Floating Point Number", error_title, MB_OK); + return FALSE; +} + +bool ValidateTextFloatRange(const char* pData, float min, float max, char* error_title, float* value) +{ + char error_buffer[256]; + sprintf(error_buffer, "Please Enter A Floating Point Number Between %.3f and %.3f", min, max); + + if(pData) + { + float testNum = (float)atof(pData); + + if((testNum < min) || (testNum > max)) + { + DoMessageBox(error_buffer, error_title, MB_OK); + return FALSE; + } + else + { + *value = testNum; + return TRUE; + } + } + + DoMessageBox(error_buffer, error_title, MB_OK); + return FALSE; +} + +bool ValidateTextIntRange(const char* pData, int min, int max, char* error_title, int* value) +{ + char error_buffer[256]; + sprintf(error_buffer, "Please Enter An Integer Between %i and %i", min, max); + + if(pData) + { + int testNum = atoi(pData); + + if((testNum < min) || (testNum > max)) + { + DoMessageBox(error_buffer, error_title, MB_OK); + return FALSE; + } + else + { + *value = testNum; + return TRUE; + } + } + + DoMessageBox(error_buffer, error_title, MB_OK); + return FALSE; +} + +bool ValidateTextInt(const char* pData, char* error_title, int* value) +{ + if(pData) + { + int testNum = atoi(pData); + + if((testNum == 0) && strcmp(pData, "0")) + { + DoMessageBox("Please Enter An Integer", error_title, MB_OK); + return FALSE; + } + else + { + *value = testNum; + return TRUE; + } + } + + DoMessageBox("Please Enter An Integer", error_title, MB_OK); + return FALSE; +} + +/*-------------------------------- + Modal Dialog Boxes +---------------------------------*/ + +/* + + Major clean up of variable names etc required, excluding Mars's ones, + which are nicely done :) + +*/ + +int DoMessageBox (const char* lpText, const char* lpCaption, guint32 uType) +{ + GtkWidget *window, *w, *vbox, *hbox; + int mode = (uType & MB_TYPEMASK), ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_window_set_title (GTK_WINDOW (window), lpCaption); + gtk_container_border_width (GTK_CONTAINER (window), 10); + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + gtk_widget_realize (window); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + w = gtk_label_new (lpText); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + if (mode == MB_OK) + { + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + ret = IDOK; + } + else if (mode == MB_OKCANCEL) + { + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + } + else if (mode == MB_YESNOCANCEL) + { + w = gtk_button_new_with_label ("Yes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("No"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + } + else /* if (mode == MB_YESNO) */ + { + w = gtk_button_new_with_label ("Yes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("No"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDNO)); + gtk_widget_show (w); + ret = IDNO; + } + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +int DoIntersectBox (IntersectRS* rs) +{ + GtkWidget *window, *w, *vbox, *hbox; + GtkWidget *radio1, *radio2; + GtkWidget *check1, *check2; + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "Intersect"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + // ---- vbox ---- + + radio1 = gtk_radio_button_new_with_label(NULL, "Use Whole Map"); + gtk_box_pack_start (GTK_BOX (vbox), radio1, FALSE, FALSE, 2); + gtk_widget_show (radio1); + + radio2 = gtk_radio_button_new_with_label(((GtkRadioButton*)radio1)->group, "Use Selected Brushes"); + gtk_box_pack_start (GTK_BOX (vbox), radio2, FALSE, FALSE, 2); + gtk_widget_show (radio2); + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + check1 = gtk_check_button_new_with_label("Include Detail Brushes"); + gtk_box_pack_start (GTK_BOX (vbox), check1, FALSE, FALSE, 0); + gtk_widget_show (check1); + + check2 = gtk_check_button_new_with_label("Select Duplicate Brushes Only"); + gtk_box_pack_start (GTK_BOX (vbox), check2, FALSE, FALSE, 0); + gtk_widget_show (check2); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- ok/cancel buttons + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // ---- /hbox ---- + + // ---- /vbox ---- + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + if(gtk_toggle_button_get_active((GtkToggleButton*)radio1)) + rs->nBrushOptions = BRUSH_OPT_WHOLE_MAP; + else if(gtk_toggle_button_get_active((GtkToggleButton*)radio2)) + rs->nBrushOptions = BRUSH_OPT_SELECTED; + + rs->bUseDetail = gtk_toggle_button_get_active((GtkToggleButton*)check1) ? true : false; + rs->bDuplicateOnly = gtk_toggle_button_get_active((GtkToggleButton*)check2) ? true : false; + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +int DoPolygonBox (PolygonRS* rs) +{ + GtkWidget *window, *w, *vbox, *hbox, *vbox2, *hbox2; + + GtkWidget *check1, *check2, *check3; + GtkWidget *text1, *text2; + + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "Polygon Builder"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + // ---- vbox ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + + vbox2 = gtk_vbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 2); + gtk_widget_show (vbox2); + + // ---- vbox2 ---- + + hbox2 = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 2); + gtk_widget_show (hbox2); + + // ---- hbox2 ---- + + text1 = gtk_entry_new_with_max_length(256); + gtk_entry_set_text((GtkEntry*)text1, "3"); + gtk_box_pack_start (GTK_BOX (hbox2), text1, FALSE, FALSE, 2); + gtk_widget_show (text1); + + w = gtk_label_new ("Number Of Sides"); + gtk_box_pack_start (GTK_BOX (hbox2), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + // ---- /hbox2 ---- + + hbox2 = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox2), hbox2, FALSE, FALSE, 2); + gtk_widget_show (hbox2); + + // ---- hbox2 ---- + + text2 = gtk_entry_new_with_max_length(256); + gtk_entry_set_text((GtkEntry*)text2, "8"); + gtk_box_pack_start (GTK_BOX (hbox2), text2, FALSE, FALSE, 2); + gtk_widget_show (text2); + + w = gtk_label_new ("Border Width"); + gtk_box_pack_start (GTK_BOX (hbox2), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + // ---- /hbox2 ---- + + // ---- /vbox2 ---- + + + + vbox2 = gtk_vbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (hbox), vbox2, FALSE, FALSE, 2); + gtk_widget_show (vbox2); + + // ---- vbox2 ---- + + check1 = gtk_check_button_new_with_label("Use Border"); + gtk_box_pack_start (GTK_BOX (vbox2), check1, FALSE, FALSE, 0); + gtk_widget_show (check1); + + + check2 = gtk_check_button_new_with_label("Inverse Polygon"); + gtk_box_pack_start (GTK_BOX (vbox2), check2, FALSE, FALSE, 0); + gtk_widget_show (check2); + + + check3 = gtk_check_button_new_with_label("Align Top Edge"); + gtk_box_pack_start (GTK_BOX (vbox2), check3, FALSE, FALSE, 0); + gtk_widget_show (check3); + + // ---- /vbox2 ---- + + // ---- /hbox ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // ---- /hbox ---- + + // ---- /vbox ---- + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) + { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if(ret == IDOK) + { + rs->bUseBorder = gtk_toggle_button_get_active((GtkToggleButton*)check1) ? true : false; + rs->bInverse = gtk_toggle_button_get_active((GtkToggleButton*)check2) ? true : false; + rs->bAlignTop = gtk_toggle_button_get_active((GtkToggleButton*)check3) ? true : false; + + if(!ValidateTextIntRange(gtk_entry_get_text((GtkEntry*)text1), 3, 32, "Number Of Sides", &rs->nSides)) + dialogError = TRUE; + + if(rs->bUseBorder) + { + if(!ValidateTextIntRange(gtk_entry_get_text((GtkEntry*)text2), 8, 256, "Border Width", &rs->nBorderWidth)) + dialogError = TRUE; + } + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +// mars +// for stair builder stuck as close as i could to the MFC version +// obviously feel free to change it at will :) +int DoBuildStairsBox(BuildStairsRS* rs) +{ + // i made widgets for just about everything ... i think that's what i need to do dunno tho + GtkWidget *window, *w, *vbox, *hbox; + GtkWidget *textStairHeight, *textRiserTex, *textMainTex; + GtkWidget *radioNorth, *radioSouth, *radioEast, *radioWest; // i'm guessing we can't just abuse 'w' for these if we're getting a value + GtkWidget *radioOldStyle, *radioBobStyle, *radioCornerStyle; + GtkWidget *checkUseDetail; + GSList *radioDirection, *radioStyle; + int ret, loop; + + loop = 1; + + char *text = "Please set a value in the boxes below and press 'OK' to build the stairs"; + + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title( GTK_WINDOW( window ), "Stair Builder" ); + + gtk_container_border_width( GTK_CONTAINER( window ), 10 ); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + // new vbox + vbox = gtk_vbox_new( FALSE, 10 ); + gtk_container_add( GTK_CONTAINER( window ), vbox ); + gtk_widget_show( vbox ); + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_container_add( GTK_CONTAINER( vbox ), hbox ); + gtk_widget_show( hbox ); + + // dunno if you want this text or not ... + w = gtk_label_new( text ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); // not entirely sure on all the parameters / what they do ... + gtk_widget_show( w ); + + w = gtk_hseparator_new(); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // ------------------------- // indenting == good way of keeping track of lines :) + + // new hbox + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + textStairHeight = gtk_entry_new_with_max_length( 256 ); + gtk_box_pack_start( GTK_BOX( hbox ), textStairHeight, FALSE, FALSE, 1 ); + gtk_widget_show( textStairHeight ); + + w = gtk_label_new( "Stair Height" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 1 ); + gtk_widget_show( w ); + + // ------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Direction:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 5 ); + gtk_widget_show( w ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + // radio buttons confuse me ... + // but this _looks_ right + + // djbob: actually it looks very nice :), slightly better than the way i did it + // edit: actually it doesn't work :P, you must pass the last radio item each time, ugh + + radioNorth = gtk_radio_button_new_with_label( NULL, "North" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioNorth, FALSE, FALSE, 3 ); + gtk_widget_show( radioNorth ); + + radioDirection = gtk_radio_button_group( GTK_RADIO_BUTTON( radioNorth ) ); + + radioSouth = gtk_radio_button_new_with_label( radioDirection, "South" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioSouth, FALSE, FALSE, 2 ); + gtk_widget_show( radioSouth ); + + radioDirection = gtk_radio_button_group( GTK_RADIO_BUTTON( radioSouth ) ); + + radioEast = gtk_radio_button_new_with_label( radioDirection, "East" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioEast, FALSE, FALSE, 1 ); + gtk_widget_show( radioEast ); + + radioDirection = gtk_radio_button_group( GTK_RADIO_BUTTON( radioEast ) ); + + radioWest = gtk_radio_button_new_with_label( radioDirection, "West" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioWest, FALSE, FALSE, 0 ); + gtk_widget_show( radioWest ); + + // --------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Style:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 5 ); + gtk_widget_show( w ); + + // --------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + radioOldStyle = gtk_radio_button_new_with_label( NULL, "Original" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioOldStyle, FALSE, FALSE, 0 ); + gtk_widget_show( radioOldStyle ); + + radioStyle = gtk_radio_button_group( GTK_RADIO_BUTTON( radioOldStyle ) ); + + radioBobStyle = gtk_radio_button_new_with_label( radioStyle, "Bob's Style" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioBobStyle, FALSE, FALSE, 0 ); + gtk_widget_show( radioBobStyle ); + + radioStyle = gtk_radio_button_group( GTK_RADIO_BUTTON( radioBobStyle ) ); + + radioCornerStyle = gtk_radio_button_new_with_label( radioStyle, "Corner Style" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioCornerStyle, FALSE, FALSE, 0 ); + gtk_widget_show( radioCornerStyle ); + + // err, the q3r has an if or something so you need bob style checked before this + // is "ungreyed out" but you'll need to do that, as i suck :) + + // djbob: er.... yeah um, im not at all sure how i'm gonna sort this + // djbob: think we need some button callback functions or smuffin + // FIXME: actually get around to doing what i suggested!!!! + + checkUseDetail = gtk_check_button_new_with_label( "Use Detail Brushes" ); + gtk_box_pack_start( GTK_BOX( hbox ), checkUseDetail, FALSE, FALSE, 0 ); + gtk_widget_show( checkUseDetail ); + + // --------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + textMainTex = gtk_entry_new_with_max_length( 512 ); + gtk_entry_set_text(GTK_ENTRY(textMainTex), rs->mainTexture); + gtk_box_pack_start( GTK_BOX( hbox ), textMainTex, FALSE, FALSE, 0 ); + gtk_widget_show( textMainTex ); + + w = gtk_label_new( "Main Texture" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 1 ); + gtk_widget_show( w ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + textRiserTex = gtk_entry_new_with_max_length( 512 ); + gtk_box_pack_start( GTK_BOX( hbox ), textRiserTex, FALSE, FALSE, 0 ); + gtk_widget_show( textRiserTex ); + + w = gtk_label_new( "Riser Texture" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 1 ); + gtk_widget_show( w ); + + // -------------------------- // + w = gtk_hseparator_new(); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label( "OK" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDOK ) ); + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Cancel" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDCANCEL ) ); + gtk_widget_show( w ); + + ret = IDCANCEL; + +// +djbob: need our "little" modal loop mars :P + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) + { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if(ret == IDOK) + { + rs->bUseDetail = gtk_toggle_button_get_active((GtkToggleButton*)checkUseDetail) ? true : false; + + strcpy(rs->riserTexture, gtk_entry_get_text((GtkEntry*)textRiserTex)); + strcpy(rs->mainTexture, gtk_entry_get_text((GtkEntry*)textMainTex)); + + if(gtk_toggle_button_get_active((GtkToggleButton*)radioNorth)) + rs->direction = MOVE_NORTH; + else if(gtk_toggle_button_get_active((GtkToggleButton*)radioSouth)) + rs->direction = MOVE_SOUTH; + else if(gtk_toggle_button_get_active((GtkToggleButton*)radioEast)) + rs->direction = MOVE_EAST; + else if(gtk_toggle_button_get_active((GtkToggleButton*)radioWest)) + rs->direction = MOVE_WEST; + + if(!ValidateTextInt(gtk_entry_get_text((GtkEntry*)textStairHeight), "Stair Height", &rs->stairHeight)) + dialogError = TRUE; + + if(gtk_toggle_button_get_active((GtkToggleButton*)radioOldStyle)) + rs->style = STYLE_ORIGINAL; + else if(gtk_toggle_button_get_active((GtkToggleButton*)radioBobStyle)) + rs->style = STYLE_BOB; + else if(gtk_toggle_button_get_active((GtkToggleButton*)radioCornerStyle)) + rs->style = STYLE_CORNER; + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +// -djbob + + // there we go, all done ... on my end at least, not bad for a night's work +} + +int DoDoorsBox(DoorRS* rs) +{ + GtkWidget *window, *hbox, *vbox, *w; + GtkWidget *textFrontBackTex, *textTrimTex; + GtkWidget *checkScaleMainH, *checkScaleMainV, *checkScaleTrimH, *checkScaleTrimV; + GtkWidget *comboMain, *comboTrim; + GtkWidget *buttonSetMain, *buttonSetTrim; + GtkWidget *radioNS, *radioEW; + GSList *radioOrientation; + TwinWidget tw1, tw2; + int ret, loop; + + loop = 1; + + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title( GTK_WINDOW( window ), "Door Builder" ); + + gtk_container_border_width( GTK_CONTAINER( window ), 10 ); + + g_object_set_data( G_OBJECT( window ), "loop", &loop ); + g_object_set_data( G_OBJECT( window ), "ret", &ret ); + + gtk_widget_realize (window); + + char buffer[256]; + GList *listMainTextures = NULL; + GList *listTrimTextures = NULL; + LoadGList(GetFilename(buffer, "plugins/bt/door-tex.txt"), &listMainTextures); + LoadGList(GetFilename(buffer, "plugins/bt/door-tex-trim.txt"), &listTrimTextures); + + vbox = gtk_vbox_new( FALSE, 10 ); + gtk_container_add( GTK_CONTAINER( window ), vbox ); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + textFrontBackTex = gtk_entry_new_with_max_length( 512 ); + gtk_entry_set_text( GTK_ENTRY( textFrontBackTex ), rs->mainTexture); + gtk_box_pack_start( GTK_BOX( hbox ), textFrontBackTex, FALSE, FALSE, 0 ); + gtk_widget_show( textFrontBackTex ); + + w = gtk_label_new( "Door Front/Back Texture" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // ------------------------ // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + textTrimTex = gtk_entry_new_with_max_length( 512 ); + gtk_box_pack_start( GTK_BOX( hbox ), textTrimTex, FALSE, FALSE, 0 ); + gtk_widget_show( textTrimTex ); + + w = gtk_label_new( "Door Trim Texture" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // ----------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + // sp: horizontally ???? + // djbob: yes mars, u can spell :] + checkScaleMainH = gtk_check_button_new_with_label( "Scale Main Texture Horizontally" ); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( checkScaleMainH ), TRUE); + gtk_box_pack_start( GTK_BOX( hbox ), checkScaleMainH, FALSE, FALSE, 0 ); + gtk_widget_show( checkScaleMainH ); + + checkScaleTrimH = gtk_check_button_new_with_label( "Scale Trim Texture Horizontally" ); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( checkScaleTrimH ), TRUE); + gtk_box_pack_start( GTK_BOX( hbox ), checkScaleTrimH, FALSE, FALSE, 0 ); + gtk_widget_show( checkScaleTrimH ); + + // ---------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + checkScaleMainV = gtk_check_button_new_with_label( "Scale Main Texture Vertically" ); + gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON( checkScaleMainV ), TRUE); + gtk_box_pack_start( GTK_BOX( hbox ), checkScaleMainV, FALSE, FALSE, 0 ); + gtk_widget_show( checkScaleMainV ); + + checkScaleTrimV = gtk_check_button_new_with_label( "Scale Trim Texture Vertically" ); + gtk_box_pack_start( GTK_BOX( hbox ), checkScaleTrimV, FALSE, FALSE, 0 ); + gtk_widget_show( checkScaleTrimV ); + + // --------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + // djbob: lists added + + comboMain = gtk_combo_new(); + gtk_box_pack_start( GTK_BOX( hbox ), comboMain, FALSE, FALSE, 0 ); + gtk_combo_set_popdown_strings( GTK_COMBO( comboMain ), listMainTextures ); + gtk_combo_set_use_arrows( GTK_COMBO( comboMain ), 1 ); + gtk_widget_show( comboMain ); + + tw1.one = textFrontBackTex; + tw1.two = comboMain; + + buttonSetMain = gtk_button_new_with_label( "Set As Main Texture" ); + gtk_signal_connect( GTK_OBJECT( buttonSetMain ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback_settex ), &tw1 ); + gtk_box_pack_start( GTK_BOX( hbox ), buttonSetMain, FALSE, FALSE, 0 ); + gtk_widget_show( buttonSetMain ); + + // ------------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + comboTrim = gtk_combo_new(); + gtk_box_pack_start( GTK_BOX( hbox ), comboTrim, FALSE, FALSE, 0 ); + gtk_combo_set_popdown_strings( GTK_COMBO( comboTrim ), listTrimTextures ); + gtk_combo_set_use_arrows( GTK_COMBO( comboMain ), 1 ); + gtk_widget_show( comboTrim ); + + tw2.one = textTrimTex; + tw2.two = comboTrim; + + buttonSetTrim = gtk_button_new_with_label( "Set As Trim Texture" ); + gtk_signal_connect( GTK_OBJECT( buttonSetTrim ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback_settex ), &tw2 ); + gtk_box_pack_start( GTK_BOX( hbox ), buttonSetTrim, FALSE, FALSE, 0 ); + gtk_widget_show( buttonSetTrim ); + + // ------------------ // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Orientation" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // argh more radio buttons! + radioNS = gtk_radio_button_new_with_label( NULL, "North - South" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioNS, FALSE, FALSE, 0 ); + gtk_widget_show( radioNS ); + + radioOrientation = gtk_radio_button_group( GTK_RADIO_BUTTON( radioNS ) ); + + radioEW = gtk_radio_button_new_with_label( radioOrientation, "East - West" ); + gtk_box_pack_start( GTK_BOX( hbox ), radioEW, FALSE, FALSE, 0 ); + gtk_widget_show( radioEW ); + + // ----------------- // + + w = gtk_hseparator_new(); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // ----------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label( "OK" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDOK ) ); + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Cancel" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDCANCEL ) ); + gtk_widget_show( w ); + ret = IDCANCEL; + + // ----------------- // + +//+djbob + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + strcpy(rs->mainTexture, gtk_entry_get_text( GTK_ENTRY( textFrontBackTex ) )); + strcpy(rs->trimTexture, gtk_entry_get_text( GTK_ENTRY( textTrimTex ) )); + + rs->bScaleMainH = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkScaleMainH)) ? true : false; + rs->bScaleMainV = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkScaleMainV)) ? true : false; + rs->bScaleTrimH = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkScaleTrimH)) ? true : false; + rs->bScaleTrimV = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(checkScaleTrimV)) ? true : false; + + if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioNS))) + rs->nOrientation = DIRECTION_NS; + else if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(radioEW))) + rs->nOrientation = DIRECTION_EW; + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +//-djbob +} + +int DoPathPlotterBox(PathPlotterRS* rs) +{ + GtkWidget *window, *w, *vbox, *hbox; + + GtkWidget *text1, *text2, *text3; + GtkWidget *check1, *check2; + + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "Texture Reset"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + // ---- vbox ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + text1 = gtk_entry_new_with_max_length(256); + gtk_entry_set_text((GtkEntry*)text1, "25"); + gtk_box_pack_start (GTK_BOX (hbox), text1, FALSE, FALSE, 2); + gtk_widget_show (text1); + + w = gtk_label_new ("Number Of Points"); + gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + // ---- /hbox ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + text2 = gtk_entry_new_with_max_length(256); + gtk_entry_set_text((GtkEntry*)text2, "3"); + gtk_box_pack_start (GTK_BOX (hbox), text2, FALSE, FALSE, 2); + gtk_widget_show (text2); + + w = gtk_label_new ("Multipler"); + gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + // ---- /hbox ---- + + w = gtk_label_new ("Path Distance = dist(start -> apex) * multiplier"); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 0); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + text3 = gtk_entry_new_with_max_length(256); + gtk_entry_set_text((GtkEntry*)text3, "-800"); + gtk_box_pack_start (GTK_BOX (hbox), text3, FALSE, FALSE, 2); + gtk_widget_show (text3); + + w = gtk_label_new ("Gravity"); + gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + // ---- /hbox ---- + + w = gtk_hseparator_new(); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + check1 = gtk_check_button_new_with_label( "No Dynamic Update" ); + gtk_box_pack_start( GTK_BOX( vbox ), check1, FALSE, FALSE, 0 ); + gtk_widget_show( check1 ); + + check2 = gtk_check_button_new_with_label( "Show Bounding Lines" ); + gtk_box_pack_start( GTK_BOX( vbox ), check2, FALSE, FALSE, 0 ); + gtk_widget_show( check2 ); + + // ---- /vbox ---- + + + // ----------------- // + + w = gtk_hseparator_new(); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // ----------------- // + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label( "Enable" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDYES ) ); + gtk_widget_show( w ); + + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + + w = gtk_button_new_with_label( "Disable" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDNO ) ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Cancel" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( dialog_button_callback ), GINT_TO_POINTER( IDCANCEL ) ); + gtk_widget_show( w ); + + ret = IDCANCEL; + + // ----------------- // + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) + { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if(ret == IDYES) + { + if(!ValidateTextIntRange(gtk_entry_get_text(GTK_ENTRY(text1)), 1, 200, "Number Of Points", &rs->nPoints)) + dialogError = TRUE; + + if(!ValidateTextFloatRange(gtk_entry_get_text(GTK_ENTRY(text2)), 1.0f, 10.0f, "Multiplier", &rs->fMultiplier)) + dialogError = TRUE; + + if(!ValidateTextFloatRange(gtk_entry_get_text(GTK_ENTRY(text3)), -10000.0f, -1.0f, "Gravity", &rs->fGravity)) + dialogError = TRUE; + + rs->bNoUpdate = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check1)) ? true : false; + rs->bShowExtra = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(check2)) ? true : false; + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +int DoCTFColourChangeBox () +{ + GtkWidget *window, *w, *vbox, *hbox; + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "CTF Colour Changer"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + // ---- vbox ---- + + hbox = gtk_hbox_new( FALSE, 10 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, TRUE, TRUE, 0 ); + gtk_widget_show( hbox ); + + // ---- hbox ---- ok/cancel buttons + + w = gtk_button_new_with_label ("Red->Blue"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Blue->Red"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // ---- /hbox ---- + + // ---- /vbox ---- + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +int DoResetTextureBox (ResetTextureRS* rs) +{ + Str texSelected; + + GtkWidget *window, *w, *vbox, *hbox, *frame, *table; + + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "Texture Reset"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + // ---- vbox ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + texSelected = "Currently Selected Face: "; + if(g_SelectedFaceTable.m_pfnGetSelectedFaceCount() == 1) { + texSelected += GetCurrentTexture(); + } + + w = gtk_label_new (texSelected); + gtk_box_pack_start (GTK_BOX (hbox), w, FALSE, FALSE, 2); + gtk_label_set_justify (GTK_LABEL (w), GTK_JUSTIFY_LEFT); + gtk_widget_show (w); + + // ---- /hbox ---- + + frame = gtk_frame_new ("Reset Texture Names"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + dlgTexReset.cbTexChange = gtk_check_button_new_with_label("Enabled"); + gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbTexChange), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); + gtk_widget_show (dlgTexReset.cbTexChange); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbTexChange, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + w = gtk_label_new ("Old Name: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editTexOld = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editTexOld), rs->textureName); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editTexOld, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editTexOld); + + w = gtk_label_new ("New Name: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editTexNew = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editTexNew), rs->textureName); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editTexNew, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editTexNew); + + // ---- /frame ---- + + frame = gtk_frame_new ("Reset Scales"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + dlgTexReset.cbScaleHor = gtk_check_button_new_with_label("Enabled"); + gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbScaleHor), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); + gtk_widget_show (dlgTexReset.cbScaleHor); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbScaleHor, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + w = gtk_label_new ("New Horizontal Scale: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editScaleHor = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editScaleHor), "0.5"); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editScaleHor, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editScaleHor); + + + dlgTexReset.cbScaleVert = gtk_check_button_new_with_label("Enabled"); + gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbScaleVert), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); + gtk_widget_show (dlgTexReset.cbScaleVert); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbScaleVert, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + w = gtk_label_new ("New Vertical Scale: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editScaleVert = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editScaleVert), "0.5"); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editScaleVert, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editScaleVert); + + // ---- /frame ---- + + frame = gtk_frame_new ("Reset Shift"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + dlgTexReset.cbShiftHor = gtk_check_button_new_with_label("Enabled"); + gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbShiftHor), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); + gtk_widget_show (dlgTexReset.cbShiftHor); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbShiftHor, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + w = gtk_label_new ("New Horizontal Shift: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editShiftHor = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editShiftHor), "0"); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editShiftHor, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editShiftHor); + + + dlgTexReset.cbShiftVert = gtk_check_button_new_with_label("Enabled"); + gtk_signal_connect (GTK_OBJECT (dlgTexReset.cbShiftVert), "toggled", GTK_SIGNAL_FUNC (dialog_button_callback_texreset_update), NULL); + gtk_widget_show (dlgTexReset.cbShiftVert); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbShiftVert, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + w = gtk_label_new ("New Vertical Shift: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editShiftVert = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editShiftVert), "0"); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editShiftVert, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editShiftVert); + + // ---- /frame ---- + + frame = gtk_frame_new ("Reset Rotation"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (1, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + dlgTexReset.cbRotation = gtk_check_button_new_with_label("Enabled"); + gtk_widget_show (dlgTexReset.cbRotation); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.cbRotation, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + + w = gtk_label_new ("New Rotation Value: "); + gtk_table_attach (GTK_TABLE (table), w, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + dlgTexReset.editRotation = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(dlgTexReset.editRotation), "0"); + gtk_table_attach (GTK_TABLE (table), dlgTexReset.editRotation, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (dlgTexReset.editRotation); + + // ---- /frame ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + w = gtk_button_new_with_label ("Use Selected Brushes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Use All Brushes"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDYES)); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // ---- /hbox ---- + + // ---- /vbox ---- + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + Update_TextureReseter(); + + bool dialogError = TRUE; + while (dialogError) + { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if(ret != IDCANCEL) + { + rs->bResetRotation = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbRotation )); + if(rs->bResetRotation) + if(!ValidateTextInt(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editRotation)), "Rotation", &rs->rotation)) + dialogError = TRUE; + + rs->bResetScale[0] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbScaleHor )); + if(rs->bResetScale[0]) + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editScaleHor)), "Horizontal Scale", &rs->fScale[0])) + dialogError = TRUE; + + rs->bResetScale[1] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbScaleVert )); + if(rs->bResetScale[1]) + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editScaleVert)), "Vertical Scale", &rs->fScale[1])) + dialogError = TRUE; + + rs->bResetShift[0] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbShiftHor )); + if(rs->bResetShift[0]) + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editShiftHor)), "Horizontal Shift", &rs->fShift[0])) + dialogError = TRUE; + + rs->bResetShift[1] = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbShiftVert )); + if(rs->bResetShift[1]) + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(dlgTexReset.editShiftVert)), "Vertical Shift", &rs->fShift[1])) + dialogError = TRUE; + + rs->bResetTextureName = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON( dlgTexReset.cbTexChange )); + if(rs->bResetTextureName) + { + strcpy(rs->textureName, gtk_entry_get_text(GTK_ENTRY( dlgTexReset.editTexOld ))); + strcpy(rs->newTextureName, gtk_entry_get_text(GTK_ENTRY( dlgTexReset.editTexNew ))); + } + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} + +int DoTrainThingBox (TrainThingRS* rs) +{ + Str texSelected; + + GtkWidget *window, *w, *vbox, *hbox, *frame, *table; + + GtkWidget *radiusX, *radiusY; + GtkWidget *angleStart, *angleEnd; + GtkWidget *heightStart, *heightEnd; + GtkWidget *numPoints; + + int ret, loop = 1; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + + gtk_window_set_title (GTK_WINDOW (window), "Train Thing"); + gtk_container_border_width (GTK_CONTAINER (window), 10); + + gtk_object_set_data (GTK_OBJECT (window), "loop", &loop); + gtk_object_set_data (GTK_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); + + // ---- vbox ---- + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- /hbox ---- + + frame = gtk_frame_new ("Radii"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + w = gtk_label_new ("X: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + radiusX = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(radiusX), "100"); + gtk_table_attach (GTK_TABLE (table), radiusX, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (radiusX); + + + + w = gtk_label_new ("Y: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + radiusY = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(radiusY), "100"); + gtk_table_attach (GTK_TABLE (table), radiusY, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (radiusY); + + + + frame = gtk_frame_new ("Angles"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + w = gtk_label_new ("Start: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + angleStart = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(angleStart), "0"); + gtk_table_attach (GTK_TABLE (table), angleStart, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (angleStart); + + + + w = gtk_label_new ("End: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + angleEnd = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(angleEnd), "90"); + gtk_table_attach (GTK_TABLE (table), angleEnd, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (angleEnd); + + + frame = gtk_frame_new ("Height"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + w = gtk_label_new ("Start: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + heightStart = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(heightStart), "0"); + gtk_table_attach (GTK_TABLE (table), heightStart, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (heightStart); + + + + w = gtk_label_new ("End: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + heightEnd = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(heightEnd), "0"); + gtk_table_attach (GTK_TABLE (table), heightEnd, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (heightEnd); + + + + frame = gtk_frame_new ("Points"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (2, 3, TRUE); + gtk_widget_show (table); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + + // ---- frame ---- + + w = gtk_label_new ("Number: "); + gtk_table_attach (GTK_TABLE (table), w, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (w); + + numPoints = gtk_entry_new_with_max_length(256); + gtk_entry_set_text(GTK_ENTRY(numPoints), "0"); + gtk_table_attach (GTK_TABLE (table), numPoints, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_widget_show (numPoints); + + + hbox = gtk_hbox_new (FALSE, 10); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 2); + gtk_widget_show (hbox); + + // ---- hbox ---- + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + + GTK_WIDGET_SET_FLAGS (w, GTK_CAN_DEFAULT); + gtk_widget_grab_default (w); + gtk_widget_show (w); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // ---- /hbox ---- + + + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) + { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if(ret != IDCANCEL) + { + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(radiusX)), "Radius (X)", &rs->fRadiusX)) + dialogError = TRUE; + + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(radiusY)), "Radius (Y)", &rs->fRadiusY)) + dialogError = TRUE; + + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(angleStart)), "Angle (Start)", &rs->fStartAngle)) + dialogError = TRUE; + + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(angleEnd)), "Angle (End)", &rs->fEndAngle)) + dialogError = TRUE; + + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(heightStart)), "Height (Start)", &rs->fStartHeight)) + dialogError = TRUE; + + if(!ValidateTextFloat(gtk_entry_get_text(GTK_ENTRY(heightEnd)), "Height (End)", &rs->fEndHeight)) + dialogError = TRUE; + + if(!ValidateTextInt(gtk_entry_get_text(GTK_ENTRY(numPoints)), "Num Points", &rs->iNumPoints)) + dialogError = TRUE; + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return ret; +} diff --git a/contrib/bobtoolz/dialogs/dialogs-gtk.h b/contrib/bobtoolz/dialogs/dialogs-gtk.h new file mode 100644 index 00000000..589b994e --- /dev/null +++ b/contrib/bobtoolz/dialogs/dialogs-gtk.h @@ -0,0 +1,98 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +struct BuildStairsRS{ + char mainTexture[256]; + char riserTexture[256]; + int direction; + int style; + int stairHeight; + qboolean bUseDetail; +}; + +struct ResetTextureRS { + int bResetTextureName; + char textureName[256]; + char newTextureName[256]; + + int bResetScale[2]; + float fScale[2]; + + int bResetShift[2]; + float fShift[2]; + + int bResetRotation; + int rotation; +}; + +struct TrainThingRS { + float fRadiusX, fRadiusY; + float fStartAngle, fEndAngle; + int iNumPoints; + float fStartHeight, fEndHeight; +}; + +struct IntersectRS{ + int nBrushOptions; + qboolean bUseDetail; + qboolean bDuplicateOnly; +}; + +struct PolygonRS{ + qboolean bUseBorder; + qboolean bInverse; + qboolean bAlignTop; + int nSides; + int nBorderWidth; +}; + +struct DoorRS{ + char mainTexture[256]; + char trimTexture[256]; + qboolean bScaleMainH; + qboolean bScaleMainV; + qboolean bScaleTrimH; + qboolean bScaleTrimV; + int nOrientation; +}; + +struct PathPlotterRS{ + int nPoints; + float fMultiplier; + float fGravity; + qboolean bNoUpdate; + qboolean bShowExtra; +}; + +struct TwinWidget{ + GtkWidget* one; + GtkWidget* two; +}; + +int DoMessageBox(const char* lpText, const char* lpCaption, guint32 uType); +int DoIntersectBox(IntersectRS* rs); +int DoPolygonBox(PolygonRS* rs); +int DoResetTextureBox (ResetTextureRS* rs); +int DoBuildStairsBox(BuildStairsRS* rs); +int DoDoorsBox(DoorRS* rs); +int DoPathPlotterBox(PathPlotterRS* rs); +int DoCTFColourChangeBox(); +int DoTrainThingBox (TrainThingRS* rs); + +//GtkWidget* GetProgressWindow(char* title, GtkProgressBar* feedback); diff --git a/contrib/bobtoolz/dialogs/pathplotterdialog.cpp b/contrib/bobtoolz/dialogs/pathplotterdialog.cpp new file mode 100644 index 00000000..2a77f984 --- /dev/null +++ b/contrib/bobtoolz/dialogs/pathplotterdialog.cpp @@ -0,0 +1,85 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// PathPlotterDialog.cpp : implementation file +// + +#include "../StdAfx.h" +#include "../bobtoolz.h" +#include "PathPlotterDialog.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CPathPlotterDialog dialog + + +CPathPlotterDialog::CPathPlotterDialog(CWnd* pParent /*=NULL*/) + : CDialog(CPathPlotterDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CPathPlotterDialog) + m_fGravity = -800.0f; + m_fMultiplier = 3.0f; + m_bNoUpdate = FALSE; + m_nPoints = 25; + m_bShowExtra = FALSE; + //}}AFX_DATA_INIT +} + + +void CPathPlotterDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CPathPlotterDialog) + DDX_Text(pDX, IDC_GRAVITY_EDIT, m_fGravity); + DDV_MinMaxFloat(pDX, m_fGravity, -10000.f, -1.f); + DDX_Text(pDX, IDC_MULTIPLIER_EDIT, m_fMultiplier); + DDV_MinMaxFloat(pDX, m_fMultiplier, 1.f, 10.f); + DDX_Check(pDX, IDC_NOUPDATE_CHECK, m_bNoUpdate); + DDX_Text(pDX, IDC_POINTCOUNT_EDIT, m_nPoints); + DDV_MinMaxInt(pDX, m_nPoints, 1, 1000); + DDX_Check(pDX, IDC_SHOWEXTRA_CHECK, m_bShowExtra); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CPathPlotterDialog, CDialog) + //{{AFX_MSG_MAP(CPathPlotterDialog) + ON_BN_CLICKED(IDYES, OnYes) + ON_BN_CLICKED(IDNO, OnNo) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CPathPlotterDialog message handlers + +void CPathPlotterDialog::OnYes() +{ + if(UpdateData()) + EndModalLoop(IDYES); +} + +void CPathPlotterDialog::OnNo() +{ + EndModalLoop(IDNO); +} diff --git a/contrib/bobtoolz/dialogs/pathplotterdialog.h b/contrib/bobtoolz/dialogs/pathplotterdialog.h new file mode 100644 index 00000000..749e4da3 --- /dev/null +++ b/contrib/bobtoolz/dialogs/pathplotterdialog.h @@ -0,0 +1,70 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_PATHPLOTTERDIALOG_H__A0516221_F19B_11D4_ACF7_004095A18133__INCLUDED_) +#define AFX_PATHPLOTTERDIALOG_H__A0516221_F19B_11D4_ACF7_004095A18133__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 +// PathPlotterDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CPathPlotterDialog dialog + +class CPathPlotterDialog : public CDialog +{ +// Construction +public: + CPathPlotterDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CPathPlotterDialog) + enum { IDD = IDD_PATHPLOTTER_DIALOG }; + float m_fGravity; + float m_fMultiplier; + BOOL m_bNoUpdate; + int m_nPoints; + BOOL m_bShowExtra; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CPathPlotterDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CPathPlotterDialog) + afx_msg void OnYes(); + afx_msg void OnNo(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_PATHPLOTTERDIALOG_H__A0516221_F19B_11D4_ACF7_004095A18133__INCLUDED_) diff --git a/contrib/bobtoolz/funchandlers-GTK.cpp b/contrib/bobtoolz/funchandlers-GTK.cpp new file mode 100644 index 00000000..57d06b18 --- /dev/null +++ b/contrib/bobtoolz/funchandlers-GTK.cpp @@ -0,0 +1,800 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" + +#ifdef _WIN32 +#pragma warning(disable : 4786) +#endif + +#include "dialogs/dialogs-gtk.h" + +#include "DEntity.h" +#include "DShape.h" +#include "DPatch.h" + +#include "misc.h" +#include "shapes.h" +#include "lists.h" +#include "funchandlers.h" +#include "visfind.h" + +// for autocaulk +list exclusionList; // whole brush exclusion +list exclusionList_Face; // single face exclusion + +bool el1Loaded = FALSE; +bool el2Loaded = FALSE; +bool clrLst1Loaded = FALSE; +bool clrLst2Loaded = FALSE; + +DBobView* g_PathView = NULL; +DVisDrawer* g_VisView = NULL; +DTrainDrawer* g_TrainView = NULL; +DTreePlanter* g_TreePlanter = NULL; +// ------------- + +//========================// +// Helper Functions // +//========================// + +void LoadLists() +{ + char buffer[256]; + + if(!el1Loaded) + el1Loaded = LoadExclusionList(GetFilename(buffer, "bt/bt-el1.txt"), &exclusionList); + if(!el2Loaded) + el2Loaded = LoadExclusionList(GetFilename(buffer, "bt/bt-el2.txt"), &exclusionList_Face); +} + + +//========================// +// Main Functions // +//========================// + +void DoIntersect() +{ + IntersectRS rs; + + if(DoIntersectBox(&rs) == IDCANCEL) + return; + + if(rs.nBrushOptions == BRUSH_OPT_SELECTED) + { + if( g_FuncTable.m_pfnSelectedBrushCount() < 2 ) + { + DoMessageBox("Invalid number of brushes selected, choose at least 2", "Error", MB_OK); + return; + } + } + + DEntity world; + + switch(rs.nBrushOptions) + { + case BRUSH_OPT_SELECTED: + { + world.LoadSelectedBrushes(); + break; + } + case BRUSH_OPT_WHOLE_MAP: + { + world.LoadFromEntity(0, FALSE); + break; + } + } + + world.RemoveNonCheckBrushes(&exclusionList, rs.bUseDetail); + + bool* pbSelectList; + if(rs.bDuplicateOnly) + pbSelectList = world.BuildDuplicateList(); + else + pbSelectList = world.BuildIntersectList(); + + world.SelectBrushes(pbSelectList); + + delete[] pbSelectList; +} + +void DoPolygonsTB() +{ + vec3_t vMin, vMax; + + // figure out vMin and vMax + g_FuncTable.m_pfnGetDispatchParams( vMin, vMax, NULL ); + + DoPolygons( vMin, vMax ); +} + +void DoPolygons(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + DoMessageBox("Invalid number of brushes selected, choose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + PolygonRS rs; + + // ask user for type, size, etc.... + if(DoPolygonBox(&rs) == IDOK) + { + g_FuncTable.m_pfnDeleteBrushHandle(brush); + + DShape poly; + + if(rs.bInverse) + poly.BuildInversePrism(vMin, vMax, rs.nSides, rs.bAlignTop); + else + { + if(rs.bUseBorder) + poly.BuildBorderedPrism(vMin, vMax, rs.nSides, rs.nBorderWidth, rs.bAlignTop); + else + poly.BuildRegularPrism(vMin, vMax, rs.nSides, rs.bAlignTop); + + } + + poly.Commit(); + } + + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoFixBrushes() +{ + DMap world; + world.LoadAll(); + + int count = world.FixBrushes(TRUE); + + Sys_Printf("%i invalid/duplicate planes removed\n", count); +} + +void DoResetTextures() +{ + static ResetTextureRS rs; + + const char* texName; + if(g_SelectedFaceTable.m_pfnGetSelectedFaceCount() != 1) + { + texName = NULL; + } + else + { + texName = GetCurrentTexture(); + strcpy(rs.textureName, GetCurrentTexture()); + } + + int ret; + if((ret = DoResetTextureBox(&rs)) == IDCANCEL) + return; + + if(rs.bResetTextureName) + texName = rs.textureName; + + if(ret == IDOK) + { + DEntity world; + world.LoadSelectedBrushes(); + world.ResetTextures(texName, rs.fScale, rs.fShift, rs.rotation, rs.newTextureName, + rs.bResetTextureName, rs.bResetScale, rs.bResetShift, rs.bResetRotation, TRUE); + } + else + { + DMap world; + world.LoadAll(TRUE); + world.ResetTextures(texName, rs.fScale, rs.fShift, rs.rotation, rs.newTextureName, + rs.bResetTextureName, rs.bResetScale, rs.bResetShift, rs.bResetRotation); + } +} + +void DoBuildStairs(vec3_t vMin, vec3_t vMax) +{ + BuildStairsRS rs; + + strcpy(rs.mainTexture, GetCurrentTexture()); + + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + + // ask user for type, size, etc.... + if(DoBuildStairsBox(&rs) == IDOK) + { + // calc brush size + vec3_t size; + VectorSubtract(vMax, vMin, size); + + if(((int)size[2] % rs.stairHeight) != 0) + { + // stairs must fit evenly into brush + DoMessageBox("Invalid stair height\nHeight of block must be divisable by stair height", "Error", MB_OK); + } + else + { + + // Remove Size Brush + g_FuncTable.m_pfnDeleteBrushHandle(brush); + + + // Get Step Count + int numSteps = (int)size[2] / rs.stairHeight; + + if(rs.style == STYLE_CORNER) + { + BuildCornerStairs(vMin, vMax, numSteps, rs.mainTexture, rs.riserTexture); + } + else + { + + // Get Step Dimensions + float stairHeight = (float)rs.stairHeight; + float stairWidth; + if((rs.direction == MOVE_EAST) || (rs.direction == MOVE_WEST)) + stairWidth = (size[0])/numSteps; + else + stairWidth = (size[1])/numSteps; + + + // Build Base For Stair (bob's style) + if(rs.style == STYLE_BOB) + Build_Wedge(rs.direction, vMin, vMax, TRUE); + + + // Set First Step Starting Position + vMax[2] = vMin[2] + stairHeight; + SetInitialStairPos(rs.direction, vMin, vMax, stairWidth); + + + // Build The Steps + for(int i = 0; i < numSteps; i++) + { + if(rs.style == STYLE_BOB) + Build_StairStep_Wedge(rs.direction, vMin, vMax, rs.mainTexture, rs.riserTexture, rs.bUseDetail); + else if(rs.style == STYLE_ORIGINAL) + Build_StairStep(vMin, vMax, rs.mainTexture, rs.riserTexture, rs.direction); + + // get step into next position + MoveBlock(rs.direction, vMin, vMax, stairWidth); + vMax[2] += stairHeight; + if(rs.style == STYLE_BOB) + vMin[2] += stairHeight; // wedge bottom must be raised + } + } + } + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoBuildDoors(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + DoorRS rs; + strcpy(rs.mainTexture, GetCurrentTexture()); + + if(DoDoorsBox(&rs) == IDOK) + { + g_FuncTable.m_pfnDeleteBrushHandle(brush); + + BuildDoorsX2(vMin, vMax, + rs.bScaleMainH, rs.bScaleMainV, + rs.bScaleTrimH, rs.bScaleTrimV, + rs.mainTexture, rs.trimTexture, + rs.nOrientation); // shapes.cpp + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoPathPlotter() +{ + PathPlotterRS rs; + int ret = DoPathPlotterBox(&rs); + if(ret == IDCANCEL) + return; + if(ret == IDNO) + { + if(g_PathView) + delete g_PathView; + return; + } + + if( g_FuncTable.m_pfnSelectedBrushCount() != 1) + { + DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // should be our trigger brush + + DEntity world; + world.LoadEPairList(*g_EntityTable.m_pfnGetEntityKeyValList(brush->owner)); + + DEPair* trigger_ep = world.FindEPairByKey("targetname"); + + if(trigger_ep) + { + if(!strcmp(world.m_Classname, "trigger_push")) + { + DEPair* target_ep = world.FindEPairByKey("target"); + if(target_ep) + { + entity_s* entTarget = FindEntityFromTargetname(target_ep->value, NULL); + if(entTarget) + { + if(g_PathView) + delete g_PathView; + g_PathView = new DBobView; + + g_PathView->Begin(trigger_ep->value, target_ep->value, rs.fMultiplier, rs.nPoints, rs.fGravity, rs.bNoUpdate, rs.bShowExtra); + } + else + DoMessageBox("trigger_push target could not be found.", "Error", MB_OK); + } + else + DoMessageBox("trigger_push has no target.", "Error", MB_OK); + } + else + DoMessageBox("You must select a 'trigger_push' entity.", "Error", MB_OK); + } + else + DoMessageBox("Entity must have a targetname", "Error", MB_OK); + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoPitBuilder(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + DoMessageBox("Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + DShape pit; + + if(pit.BuildPit(vMin, vMax)) + { + pit.Commit(); + + g_FuncTable.m_pfnDeleteBrushHandle(brush); + } + else + DoMessageBox("Failed To Make Pit\nTry Making The Brush Bigger", "Error", MB_OK); + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoMergePatches() +{ + patch_merge_t merge_info; + DPatch mrgPatches[2]; + int i; + + // ensure we have something selected + if ( g_FuncTable.m_pfnSelectedBrushCount() != 2 ) + { + DoMessageBox("Invalid number of objects selected, chose 2 only", "Error", MB_OK); + return; + } + + + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + for (i = 0; i < 2; i++) + { + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i); + + if (!brush->pPatch) + { + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + DoMessageBox("You must select ONLY patches", "Error", MB_OK); + return; + } + + mrgPatches[i].LoadFromBrush_t(brush); + } + + /* mrgPatches[0].Transpose(); + mrgPatches[0].RemoveFromRadiant(); + mrgPatches[0].BuildInRadiant();*/ + + merge_info = mrgPatches[0].IsMergable(&mrgPatches[1]); + + if (merge_info.mergable) + { + Sys_Printf("%i %i", merge_info.pos1, merge_info.pos2); + + Sys_Printf("Patches Mergable\n"); + DPatch* newPatch = mrgPatches[0].MergePatches(merge_info, &mrgPatches[0], &mrgPatches[1]); + + /* mrgPatches[0].RemoveFromRadiant(); + mrgPatches[0].BuildInRadiant(); + + mrgPatches[1].RemoveFromRadiant(); + mrgPatches[1].BuildInRadiant(); + + + delete newPatch;*/ + + if (!newPatch) + { + } else + { + mrgPatches[0].RemoveFromRadiant(); + mrgPatches[1].RemoveFromRadiant(); + + newPatch->BuildInRadiant(); + delete newPatch; + } + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoSplitPatch() { + DPatch patch; + + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) { + DoMessageBox("Invalid number of objects selected, select 1 patch only", "Error", MB_OK); + return; + } + + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + + if( !brush->pPatch ) { + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + DoMessageBox("You must select ONLY patches", "Error", MB_OK); + return; + } + + patch.LoadFromBrush_t(brush); + + list patchList = patch.Split( true, true ); + for(list::iterator patches = patchList.begin(); patches != patchList.end(); patches++) { + (*patches).BuildInRadiant(); + } + + patch.RemoveFromRadiant(); + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoVisAnalyse() +{ + char filename[1024]; + + if( g_FuncTable.m_pfnSelectedBrushCount() == 0 ) + { + if(g_VisView) + { + delete g_VisView; + return; + } + } + + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + DoMessageBox("Invalid number of objects selected, select 1 only", "Error", MB_OK); + return; + } + + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + + DBrush orgBrush; + orgBrush.LoadFromBrush_t(brush, false); + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + + orgBrush.BuildBounds(); + vec3_t origin; + origin[0] = (orgBrush.bbox_max[0] + orgBrush.bbox_min[0])/2.f; + origin[1] = (orgBrush.bbox_max[1] + orgBrush.bbox_min[1])/2.f; + origin[2] = (orgBrush.bbox_max[2] + orgBrush.bbox_min[2])/2.f; + + + char* rad_filename = g_FuncTable.m_pfnGetMapName(); + if(!rad_filename) + { + DoMessageBox("An Error Occurred While Trying\n To Get The Map Filename", "Error", MB_OK); + return; + } + + strcpy(filename, rad_filename); + + char* ext = strrchr(filename, '.')+1; + strcpy(ext, "bsp");// rename the extension + + list *pointList = BuildTrace(filename, origin); + + if(!g_VisView) + { + g_VisView = new DVisDrawer; + g_VisView->Register(); + } + + g_VisView->SetList(pointList); +} + +void DoTrainPathPlot() { + if(g_TrainView) { + delete g_TrainView; + g_TrainView = NULL; + } + + g_TrainView = new DTrainDrawer(); +} + +void DoCaulkSelection( void ) { + DEntity world; + + float fScale[2] = { 0.5f, 0.5f }; + float fShift[2] = { 0.0f, 0.0f }; + + int bResetScale[2] = { false, false }; + int bResetShift[2] = { false, false }; + + world.LoadSelectedBrushes(); + world.LoadSelectedPatches(); + world.ResetTextures( NULL, fScale, fShift, 0, "textures/common/caulk", true, bResetScale, bResetShift, false, true ); +} + +void DoTreePlanter( void ) { + if(g_TreePlanter) { + delete g_TreePlanter; + g_TreePlanter = NULL; + return; + } + + g_TreePlanter = new DTreePlanter(); +} + +void DoDropEnts( void ) { + if(g_TreePlanter) { + g_TreePlanter->DropEntsToGround(); + } +} + +void DoMakeChain( void ) { + DTreePlanter pl; + pl.MakeChain(); +} + +typedef DPoint* pntTripple[3]; + +bool bFacesNoTop[6] = {true, true, true, true, true, false}; + +void DoFlipTerrain( void ) { + vec3_t vUp = { 0.f, 0.f, 1.f }; + int i; + + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 2 ) { + DoMessageBox("Invalid number of objects selected, chose 2 only", "Error", MB_OK); + return; + } + + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + brush_t* brushes[2]; + for( i = 0; i < 2; i++ ) { + brushes[i] = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(i); + } + + DBrush Brushes[2]; + DPlane* Planes[2]; + pntTripple Points[2]; + for( i = 0; i < 2; i++ ) { + Brushes[i].LoadFromBrush_t( brushes[i], false ); + if(!(Planes[i] = Brushes[i].FindPlaneWithClosestNormal( vUp )) || Brushes[i].FindPointsForPlane( Planes[i], Points[i], 3 ) != 3) { + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + DoMessageBox("Error", "Error", MB_OK); + return; + } + } + + vec3_t mins1, mins2, maxs1, maxs2; + Brushes[0].GetBounds( mins1, maxs1 ); + Brushes[1].GetBounds( mins2, maxs2 ); + + entity_t* ents[2]; + for( i = 0; i < 2; i++ ) { + ents[i] = brushes[i]->owner; + Brushes[i].RemoveFromRadiant(); + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + + + + + int dontmatch[2] = { -1, -1 }; + bool found = false; + for( i = 0; i < 3; i++ ) { + for( int j = 0; j < 3 && !found; j++ ) { + if(VectorCompare( (Points[0])[i]->_pnt, (Points[1])[j]->_pnt )) { + found = true; + break; + } + } + if(!found) { + dontmatch[0] = i; + break; + } + found = false; + } + if(dontmatch[0] == -1) { + DoMessageBox("Error", "Error", MB_OK); + return; + } + + for( i = 0; i < 3; i++ ) { + for( int j = 0; j < 3 && !found; j++ ) { + if(VectorCompare( (Points[1])[i]->_pnt, (Points[0])[j]->_pnt )) { + found = true; + break; + } + } + if(!found) { + dontmatch[1] = i; + break; + } + found = false; + } + if(dontmatch[1] == -1) { + DoMessageBox("Error", "Error", MB_OK); + return; + } + + vec3_t plnpnts1[3]; + vec3_t plnpnts2[3]; + vec3_t plnpntsshr[3]; + + VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpnts1[0] ); + for( i = 0; i < 3; i++ ) { + if( dontmatch[0] != i ) { + VectorCopy( (Points[0])[i]->_pnt, plnpnts1[1] ); + break; + } + } + VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpnts1[2] ); + + VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpnts2[0] ); + for( i = 0; i < 3; i++ ) { + if( dontmatch[1] != i && !VectorCompare( (Points[1])[i]->_pnt, plnpnts1[1] )) { + VectorCopy( (Points[1])[i]->_pnt, plnpnts2[1] ); + break; + } + } + VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpnts2[2] ); + + VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpntsshr[0] ); + VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpntsshr[1] ); + if( (Points[1])[dontmatch[1]]->_pnt[2] < (Points[0])[dontmatch[0]]->_pnt[2] ) { + VectorCopy( (Points[1])[dontmatch[1]]->_pnt, plnpntsshr[2] ); + } else { + VectorCopy( (Points[0])[dontmatch[0]]->_pnt, plnpntsshr[2] ); + } + plnpntsshr[2][2] -= 16; + + for( i = 0; i < 3; i++ ) { + if( mins2[i] < mins1[i] ) { + mins1[i] = mins2[i]; + } + if( maxs2[i] > maxs1[i] ) { + maxs1[i] = maxs2[i]; + } + } + + DBrush* newBrushes[2]; + newBrushes[0] = DShape::GetBoundingCube_Ext( mins1, maxs1, "textures/common/caulk", bFacesAll, true); + newBrushes[1] = DShape::GetBoundingCube_Ext( mins1, maxs1, "textures/common/caulk", bFacesAll, true); + + vec3_t normal; + MakeNormal( plnpnts1[0], plnpnts1[1], plnpnts1[2], normal ); + if( normal[2] >= 0 ) { + newBrushes[0]->AddFace( plnpnts1[0], plnpnts1[1], plnpnts1[2], "textures/common/terrain", true ); + } else { + newBrushes[0]->AddFace( plnpnts1[2], plnpnts1[1], plnpnts1[0], "textures/common/terrain", true ); + } + + MakeNormal( plnpnts2[0], plnpnts2[1], plnpnts2[2], normal ); + if( normal[2] >= 0 ) { + newBrushes[1]->AddFace( plnpnts2[0], plnpnts2[1], plnpnts2[2], "textures/common/terrain", true ); + } else { + newBrushes[1]->AddFace( plnpnts2[2], plnpnts2[1], plnpnts2[0], "textures/common/terrain", true ); + } + + vec3_t vec; + MakeNormal( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], normal ); + + VectorSubtract( plnpnts1[2], plnpnts1[1], vec ); + if( DotProduct( vec, normal ) >= 0 ) { + newBrushes[0]->AddFace( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], "textures/common/caulk", true ); + } else { + newBrushes[0]->AddFace( plnpntsshr[2], plnpntsshr[1], plnpntsshr[0], "textures/common/caulk", true ); + } + + VectorSubtract( plnpnts2[2], plnpnts2[1], vec ); + if( DotProduct( vec, normal ) >= 0 ) { + newBrushes[1]->AddFace( plnpntsshr[0], plnpntsshr[1], plnpntsshr[2], "textures/common/caulk", true ); + } else { + newBrushes[1]->AddFace( plnpntsshr[2], plnpntsshr[1], plnpntsshr[0], "textures/common/caulk", true ); + } + + for( i = 0; i < 2; i++ ) { + newBrushes[i]->RemoveRedundantPlanes(); + newBrushes[i]->BuildInRadiant( false, NULL, ents[i] ); + delete newBrushes[i]; + } + +} diff --git a/contrib/bobtoolz/funchandlers-ctf-GTK.cpp b/contrib/bobtoolz/funchandlers-ctf-GTK.cpp new file mode 100644 index 00000000..e13b6400 --- /dev/null +++ b/contrib/bobtoolz/funchandlers-ctf-GTK.cpp @@ -0,0 +1,214 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" + +#include "dialogs/dialogs-gtk.h" + +#include "DEntity.h" +#include "DMap.h" + +#include "misc.h" +#include "lists.h" +#include "funchandlers.h" + +// for ctf texture changer +list clrList_Blue; +list clrList_Red; + +BOOL clrLst1Loaded = FALSE; +BOOL clrLst2Loaded = FALSE; + +// ------------- + +//========================// +// Helper Functions // +//========================// + +void LoadLists() +{ + char buffer[256]; + + if(!clrLst1Loaded) + { + clrLst1Loaded = LoadExclusionList(GetFilename(buffer, "plugins/bt/ctf-blue.txt"), &clrList_Blue); + LoadExclusionList(GetFilename(buffer, "plugins/bt/blue.txt"), &clrList_Blue); + } + if(!clrLst2Loaded) + { + clrLst2Loaded = LoadExclusionList(GetFilename(buffer, "plugins/bt/ctf-red.txt"), &clrList_Red); + LoadExclusionList(GetFilename(buffer, "plugins/bt/red.txt"), &clrList_Red); + } +} + + +//========================// +// Main Functions // +//========================// + +void DoCTFColourChanger() +{ + if(!clrLst1Loaded || !clrLst2Loaded) + { + DoMessageBox("CTF texture lists not found, this function will terminate.", "Error", MB_OK); + return; + } + + int ret = DoCTFColourChangeBox(); + if(ret == IDCANCEL) + return; + + int cnt = Min(clrList_Blue.size(), clrList_Red.size()); + + list::const_iterator Texture_change; + list::const_iterator Texture_new; + + float fDummy[2]; + + int eCnt = g_FuncTable.m_pfnGetEntityCount(); + + DMap world; + world.LoadAll(TRUE); + + if(ret == IDYES) + { + Texture_change = clrList_Blue.begin(); + Texture_new = clrList_Red.begin(); + } + else + { + Texture_change = clrList_Red.begin(); + Texture_new = clrList_Blue.begin(); + } + + for(int i = 0; i < cnt; i++) + { + world.ResetTextures((*Texture_change).c_str(), fDummy, fDummy, 0, (*Texture_new).c_str(), TRUE); + + Texture_change++; + Texture_new++; + } +} + +void DoSwapLights() +{ +/* DMap world; + world.LoadAll(); + + for(list::const_iterator loopEnt = world.entityList.begin(); loopEnt != world.entityList.end(); loopEnt++) + { + DEntity* e = (*loopEnt); + DEPair* epLightColour = e->FindEPairByKey("_color"); + if(epLightColour) + { + float r, g, b; + sscanf(epLightColour->value, "%f %f %f", &r, &g, &b); + sprintf(epLightColour->value, "%f %f %f", b, g, r); + DMap::RebuildEntity(e); + } + }*/ + + int cnt = g_FuncTable.m_pfnGetEntityCount(); + + for(int i = 0; i < cnt; i++) + { + void* ent = g_FuncTable.m_pfnGetEntityHandle(i); + + for(epair_t* epList = *g_FuncTable.m_pfnGetEntityKeyValList(ent); epList; epList= epList->next) + { + if(!stricmp("_color", epList->key)) + { + float r, g, b; + sscanf(epList->value, "%f %f %f", &r, &g, &b); + sprintf(epList->value, "%f %f %f", b, g, r); + } + } + } +} + +void DoChangeAngles() +{ + int cnt = g_FuncTable.m_pfnGetEntityCount(); + + for(int i = 0; i < cnt; i++) + { + void* ent = g_FuncTable.m_pfnGetEntityHandle(i); + + for(epair_t* epList = *g_FuncTable.m_pfnGetEntityKeyValList(ent); epList; epList= epList->next) + { + if(!stricmp("angle", epList->key)) + { + float angle; + sscanf(epList->value, "%f", &angle); + angle += 180; + while(angle > 360) + angle -= 360; + + sprintf(epList->value, "%f", angle); + } + } + } +} + +void DoSwapSpawns() +{ + int cnt = g_FuncTable.m_pfnGetEntityCount(); + + for(int i = 0; i < cnt; i++) + { + void* ent = g_FuncTable.m_pfnGetEntityHandle(i); + + for(epair_t* epList = *g_FuncTable.m_pfnGetEntityKeyValList(ent); epList; epList= epList->next) + { + if(!stricmp("classname", epList->key)) + { + if(!strcmp(epList->value, "team_CTF_redplayer")) + sprintf(epList->value, "team_CTF_blueplayer"); + else if(!strcmp(epList->value, "team_CTF_blueplayer")) + sprintf(epList->value, "team_CTF_redplayer"); + + if(!strcmp(epList->value, "team_CTF_redspawn")) + sprintf(epList->value, "team_CTF_bluespawn"); + else if(!strcmp(epList->value, "team_CTF_bluespawn")) + sprintf(epList->value, "team_CTF_redspawn"); + + if(!strcmp(epList->value, "team_CTF_redflag")) + sprintf(epList->value, "team_CTF_blueflag"); + else if(!strcmp(epList->value, "team_CTF_blueflag")) + sprintf(epList->value, "team_CTF_redflag") + ; + if(!strcmp(epList->value, "team_redobelisk")) + sprintf(epList->value, "team_blueobelisk"); + else if(!strcmp(epList->value, "team_blueobelisk")) + sprintf(epList->value, "team_redobelisk"); + } + } + } +} + +/*void test() +{ + DMap world; + world.LoadAll(); + + for(list::const_iterator ents = world.entityList.begin(); ents != world.entityList.end(); ents++) + { + (*ents)->RemoveFromRadiant(); + } +}*/ diff --git a/contrib/bobtoolz/funchandlers.cpp b/contrib/bobtoolz/funchandlers.cpp new file mode 100644 index 00000000..3dcd819a --- /dev/null +++ b/contrib/bobtoolz/funchandlers.cpp @@ -0,0 +1,503 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" + +#include "funchandlers.h" + +#include "IntersectDialog.h" +#include "PolygonDialog.h" +#include "StairDialog.h" +#include "DoorDialog.h" +#include "IntersectInfoDialog.h" +#include "BrushCheckDialog.h" +#include "AutoCaulkDialog.h" +#include "AutoCaulkStartDialog.h" +#include "TextureResetDialog.h" +#include "pathplotterdialog.h" + +#include "DEntity.h" +#include "shapes.h" +#include "lists.h" +#include "misc.h" +#include "DShape.h" + +// for autocaulk +list exclusionList; // whole brush exclusion +list exclusionList_Face; // single face exclusion + +BOOL el1Loaded; +BOOL el2Loaded; + +DBobView* g_PathView = NULL; +// ------------- + +/************************ + Global Variables +************************/ + +CPolygonDialog polygonDlg; +CIntersectDialog intrDlg; +CStairDialog stairDlg; +CDoorDialog doorDlg; +CAutoCaulkStartDialog autocaulkDlg; +CTextureResetDialog texRstDlg; +CPathPlotterDialog ppDlg; + +/************************ + --Main Functions-- +************************/ + +void LoadLists() +{ + char buffer[256]; + + if(!el1Loaded) + el1Loaded = LoadExclusionList(GetFilename(buffer, "bt\\bt-el1.txt"), &exclusionList); + if(!el2Loaded) + el2Loaded = LoadExclusionList(GetFilename(buffer, "bt\\bt-el2.txt"), &exclusionList); +} + +void PolygonBuilder(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + // ask user for type, size, etc.... + if(polygonDlg.DoModal() == IDOK) + { + DShape poly; + + g_FuncTable.m_pfnDeleteBrushHandle(brush); + + if(polygonDlg.m_bInverse) + poly.BuildInversePrism(vMin, vMax, polygonDlg.m_nSideCount, polygonDlg.m_bAlignTop); + else + { + if(polygonDlg.m_bBorder) + poly.BuildBorderedPrism(vMin, vMax, polygonDlg.m_nSideCount, polygonDlg.m_nBorderSize, polygonDlg.m_bAlignTop); + else + poly.BuildRegularPrism(vMin, vMax, polygonDlg.m_nSideCount, polygonDlg.m_bAlignTop); + } + + poly.Commit(); + } + + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + + +void IntersectionFinder() +{ + if(intrDlg.DoModal() == IDCANCEL) + return; + + if(intrDlg.m_nBrushOptions == BRUSH_OPT_SELECTED) + { + // ensure we have enough brushes selected + if( g_FuncTable.m_pfnSelectedBrushCount() < 2 ) + { + MessageBox(NULL, "Invalid number of brushes selected, choose at least 2", "Error", MB_OK); + return; + } + } + + CIntersectInfoDialog* intrInfoDlg = new CIntersectInfoDialog(); + intrInfoDlg->Create(IDD_INTERSECT_INFO_DIALOG); + + DEntity world; + + switch(intrDlg.m_nBrushOptions) + { + case BRUSH_OPT_SELECTED: + { + world.LoadSelectedBrushes(&intrInfoDlg->m_prog1); + break; + } + case BRUSH_OPT_WHOLE_MAP: + { + world.LoadFromEntity(0, &intrInfoDlg->m_prog1); + break; + } + } + + world.RemoveNonCheckBrushes(&exclusionList, intrDlg.m_bUseDetail); + BOOL* pbSelectList; + if(intrDlg.m_bDuplicateOnly) + pbSelectList = world.BuildDuplicateList(); + else + pbSelectList = world.BuildIntersectList(); + + world.SelectBrushes(pbSelectList); + + intrInfoDlg->DestroyWindow(); + delete[] pbSelectList; +} + +void StairBuilder(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + + // ask user for type, size, etc.... + if(stairDlg.DoModal() == IDOK) + { + + // calc brush size + vec3_t size; + _VectorSubtract(vMax, vMin, size); + + + if(((int)size[2] % stairDlg.m_nStairHeight) != 0) + { + // stairs must fit evenly into brush + MessageBox(NULL, "Invalid stair height\nHeight of block must be divisable by stair height", "Error", MB_OK); + } + else + { + + // Remove Size Brush + g_FuncTable.m_pfnDeleteBrushHandle(brush); + + + // Get Step Count, Direction of Stairs, Stair Style + int numSteps = (int)size[2] / stairDlg.m_nStairHeight; + int direction = stairDlg.m_StairDir; + int style = stairDlg.m_StairStyle; + + if(stairDlg.m_StairStyle == STYLE_CORNER) + { + BuildCornerStairs(vMin, vMax, numSteps, "textures/common/caulk", (LPCTSTR)stairDlg.m_riserTexture); + } + else + { + // Get Step Dimensions + float stairHeight = (float)stairDlg.m_nStairHeight; + float stairWidth; + if((direction == MOVE_EAST) || (direction == MOVE_WEST)) + stairWidth = (size[0])/numSteps; + else + stairWidth = (size[1])/numSteps; + + + // Build Base For Stair (bob's style) + if(style == STYLE_BOB) + Build_Wedge(direction, vMin, vMax, TRUE); + + + // Set First Step Starting Position + vMax[2] = vMin[2] + stairHeight; + SetInitialStairPos(direction, vMin, vMax, stairWidth); + + + // Build The Steps + for(int i = 0; i < numSteps; i++) + { + if(style == STYLE_BOB) + Build_StairStep_Wedge(direction, vMin, vMax, "textures/common/caulk", (LPCTSTR)stairDlg.m_riserTexture, stairDlg.m_bDetail); + else if(style == STYLE_ORIGINAL) + Build_StairStep(vMin, vMax, "textures/common/caulk", (LPCTSTR)stairDlg.m_riserTexture, direction); + + // get step into next position + MoveBlock(direction, vMin, vMax, stairWidth); + vMax[2] += stairHeight; + if(style == STYLE_BOB) + vMin[2] += stairHeight; // wedge bottom must be raised + } + } + } + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void DoorBuilder(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + + + strcpy(doorDlg.m_fbTextureName.GetBuffer(256), g_FuncTable.m_pfnGetCurrentTexture()); + + if(doorDlg.DoModal() == IDOK) + { + g_FuncTable.m_pfnDeleteBrushHandle(brush); + + BuildDoorsX2(vMin, vMax, + doorDlg.m_bSclMainHor, doorDlg.m_bSclMainVert, + doorDlg.m_bSclTrimHor, doorDlg.m_bSclTrimVert, + (LPCTSTR)doorDlg.m_fbTextureName, + (LPCTSTR)doorDlg.m_trimTextureName, + doorDlg.m_doorDirection); + } + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void FixBrushes() +{ + DEntity world; + + CIntersectInfoDialog* intrInfoDlg = new CIntersectInfoDialog(); + intrInfoDlg->Create(IDD_INTERSECT_INFO_DIALOG); + + world.LoadFromEntity(0, &intrInfoDlg->m_prog1); + + intrInfoDlg->DestroyWindow(); + + CBrushCheckDialog* chkDlg = new CBrushCheckDialog(); + chkDlg->Create(IDD_BRUSHCHECKER_DIALOG); + + int count = world.FixBrushes(TRUE, &chkDlg->m_prog1); + + chkDlg->DestroyWindow(); + + Sys_Printf("%i invalid/duplicate planes removed\n", count); +} + +void AutoCaulk() +{ + if(!el1Loaded) + autocaulkDlg.m_Warning1 = "WARNING: Brush exclusion list not found\n, ALL BRUSHES WILL BE USED"; + + if(autocaulkDlg.DoModal() == IDCANCEL) + return; + + if(autocaulkDlg.m_nMode == MODE_AC_BUILD_MINI_PRT) + { + BuildMiniPrt(&exclusionList); + return; + } + + CAutoCaulkDialog* acDlg = new CAutoCaulkDialog; + acDlg->Create(IDD_AUTOCAULK_DIALOG); + + char filename[1204]; + + if(autocaulkDlg.m_nMode == MODE_AC_NORMAL) + { + char* rad_filename = g_BSPTable.m_pfnGetMapName(); + if(!rad_filename) + { + MessageBox(NULL, "An Error Occurred While Trying To Get The Map Filename", "Error", MB_OK); + acDlg->DestroyWindow(); + return; + } + + strcpy(filename, rad_filename); + + char* ext = strrchr(filename, '.')+1; + strcpy(ext, "prt");// rename the extension + } + else + { + IEpair* pEp = g_EpairTable.m_pfnIEpairForProjectKeys(); + char *pn = pEp->ValueForKey("mapspath"); + pEp->DecRef(); + + strcpy( filename, pn ); + strcat( filename, "/ac_prt.prt" ); + } + + DEntity portals; + if(!portals.LoadFromPrt(filename, &acDlg->m_prog1)) + { + MessageBox(NULL, "Failed To Load Portal File", "Error", MB_OK); + acDlg->DestroyWindow(); + return; + } + // load portal file + + CIntersectInfoDialog* intrInfoDlg = new CIntersectInfoDialog(); + intrInfoDlg->Create(IDD_INTERSECT_INFO_DIALOG); + + DEntity world; + + world.LoadFromEntity(0, &intrInfoDlg->m_prog1); + intrInfoDlg->DestroyWindow(); + + if(autocaulkDlg.m_nMode == MODE_AC_NORMAL) + world.RemoveNonCheckBrushes(&exclusionList, FALSE); + else + world.RemoveNonCheckBrushes(&exclusionList, TRUE); + + world.ResetChecks(&exclusionList_Face); + + int caulkedCount = 0; + int killCnt = world.AutoCaulk(&portals, autocaulkDlg.m_bAllowDestruction, &caulkedCount, &acDlg->m_prog2); + + if(autocaulkDlg.m_bAllowDestruction) + Sys_Printf("%i unrequired brush(es) killed\n", killCnt); + Sys_Printf("%i face(s) caulked\n", caulkedCount); + + acDlg->DestroyWindow(); +} + +void ResetTextures() +{ + texRstDlg.m_TextureName = GetCurrentTexture(); + texRstDlg.m_NewTextureName = GetCurrentTexture(); + + if(texRstDlg.DoModal() == IDCANCEL) + return; + + float fScale[2]; + float fShift[2]; + fScale[1] = texRstDlg.m_fScaleVertical; + fScale[0] = texRstDlg.m_fScaleHorizontal; + + fShift[1] = (float)texRstDlg.m_nShiftVertical; + fShift[0] = (float)texRstDlg.m_nShiftHorizontal; + + DEntity world; + world.LoadFromEntity(0, NULL); + + if(texRstDlg.m_bAllTextures) + world.ResetTextures(NULL, fScale, fShift, texRstDlg.m_nRotation, texRstDlg.m_NewTextureName, texRstDlg.m_bOnlyTexture); + else + world.ResetTextures(texRstDlg.m_TextureName, fScale, fShift, texRstDlg.m_nRotation, texRstDlg.m_NewTextureName, texRstDlg.m_bOnlyTexture); +} + +void PathPlotter() +{ + int ret = ppDlg.DoModal(); + if(ret == IDCANCEL) + return; + if(ret == IDNO) + { + if(g_PathView) + delete g_PathView; + + return; + } + + if( g_FuncTable.m_pfnSelectedBrushCount() != 1) + { + MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + DEntity world; + world.LoadEPairList(*g_FuncTable.m_pfnGetEntityKeyValList(brush->owner)); + + DEPair* trigger_ep = world.FindEPairByKey("targetname"); + + if(trigger_ep) + { + if(!strcmp(world.m_Classname, "trigger_push")) + { + DEPair* target_ep = world.FindEPairByKey("target"); + if(target_ep) + { + entity_s* entTarget = FindEntityFromTargetname(target_ep->value); + if(entTarget) + { + if(g_PathView) + delete g_PathView; + g_PathView = new DBobView; + + g_PathView->Begin(trigger_ep->value, target_ep->value, ppDlg.m_fMultiplier, ppDlg.m_nPoints, ppDlg.m_fGravity, ppDlg.m_bNoUpdate, ppDlg.m_bShowExtra); + } + else + MessageBox(NULL, "trigger_push target could not be found.", "Error", MB_OK); + } + else + MessageBox(NULL, "trigger_push has no target.", "Error", MB_OK); + } + else + MessageBox(NULL, "You must select a 'trigger_push' entity.", "Error", MB_OK); + } + else + MessageBox(NULL, "Entity must have a targetname", "Error", MB_OK); + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} + +void PitBuilder(vec3_t vMin, vec3_t vMax) +{ + // ensure we have something selected + if( g_FuncTable.m_pfnSelectedBrushCount() != 1 ) + { + MessageBox(NULL, "Invalid number of brushes selected, chose 1 only", "Error", MB_OK); + return; + } + + // tell Radiant we want to access the selected brushes + g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + + // get handle to size definition brush + brush_t *brush = (brush_t*)g_FuncTable.m_pfnGetSelectedBrushHandle(0); + // cant release until we delete the brush, if we do... + + DShape pit; + + if(pit.BuildPit(vMin, vMax)) + { + pit.Commit(); + + g_FuncTable.m_pfnDeleteBrushHandle(brush); + } + else + MessageBox(NULL, "Failed To Make Pit\nTry Making The Brush Bigger", "Error", MB_OK); + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); +} diff --git a/contrib/bobtoolz/funchandlers.h b/contrib/bobtoolz/funchandlers.h new file mode 100644 index 00000000..d8c1e33c --- /dev/null +++ b/contrib/bobtoolz/funchandlers.h @@ -0,0 +1,72 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "DBobView.h" +#include "DVisDrawer.h" +#include "DTrainDrawer.h" +#include "DTreePlanter.h" + +extern DBobView* g_PathView; +extern DVisDrawer* g_VisView; +extern DTrainDrawer* g_TrainView; +extern DTreePlanter* g_TreePlanter; + +// intersect stuff +#define BRUSH_OPT_WHOLE_MAP 0 +#define BRUSH_OPT_SELECTED 1 + +// defines for stairs +#define MOVE_NORTH 0 +#define MOVE_SOUTH 1 +#define MOVE_EAST 2 +#define MOVE_WEST 3 + +#define STYLE_ORIGINAL 0 +#define STYLE_BOB 1 +#define STYLE_CORNER 2 + +// defines for doors +#define DIRECTION_NS 0 +#define DIRECTION_EW 1 + +// help +void LoadLists(); + + +// djbob +void DoIntersect( void ); +void DoPolygonsTB( void ); +void DoPolygons(vec3_t vMin, vec3_t vMax); +void DoFixBrushes( void ); +void DoResetTextures( void ); +void DoBuildStairs(vec3_t vMin, vec3_t vMax); +void DoBuildDoors(vec3_t vMin, vec3_t vMax); +void DoPathPlotter( void ); +void DoPitBuilder(vec3_t vMin, vec3_t vMax); +void DoCTFColourChanger( void ); +void DoMergePatches( void ); +void DoSplitPatch( void ); +void DoVisAnalyse( void ); +void DoTrainThing( void ); +void DoTrainPathPlot( void ); +void DoCaulkSelection( void ); +void DoTreePlanter( void ); +void DoDropEnts( void ); +void DoMakeChain( void ); +void DoFlipTerrain( void ); diff --git a/contrib/bobtoolz/interfaces/IScriptParser.h b/contrib/bobtoolz/interfaces/IScriptParser.h new file mode 100644 index 00000000..934a9671 --- /dev/null +++ b/contrib/bobtoolz/interfaces/IScriptParser.h @@ -0,0 +1,23 @@ +#ifndef _ISCRIPTPARSER_H_ +#define _ISCRIPTPARSER_H_ + +class IScriptParser { +public: + virtual ~IScriptParser() {}; + + virtual const char* GetToken ( bool ) = 0; + virtual char* GetBufferCopy ( void ) = 0; + virtual int GetTokenOffset ( void ) = 0; + + virtual void SkipBracedSection ( void ) = 0; + virtual void SkipRestOfLine ( void ) = 0; + virtual void UndoGetToken ( void ) = 0; + virtual void ResetParseSession ( void ) = 0; + + virtual void LoadScript ( const char* ) = 0; + virtual void SetScript ( char* ) = 0; + + virtual void AddBreakChar( char ) = 0; +}; + +#endif diff --git a/contrib/bobtoolz/lists.cpp b/contrib/bobtoolz/lists.cpp new file mode 100644 index 00000000..b4a97815 --- /dev/null +++ b/contrib/bobtoolz/lists.cpp @@ -0,0 +1,85 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" + +#ifdef _WIN32 +#pragma warning(disable : 4786) +#endif + +#include "lists.h" +#include "misc.h" + +bool LoadExclusionList(char* filename, list* exclusionList) +{ + FILE* eFile = fopen(filename, "r"); + if(eFile) + { + char buffer[256]; + int cnt = 0; + while(!feof(eFile)) + { + memset(buffer, 0, 256); + fscanf(eFile, "%s\n", buffer); + + if(strlen(buffer) > 0) + exclusionList->push_back(buffer); + else + cnt++; + } + + fclose(eFile); + + return TRUE; + } + + Sys_ERROR("Failed To Load Exclusion List: %s\n", filename); + return FALSE; +} + +bool LoadGList(char* filename, GList** loadlist) +{ + FILE* eFile = fopen(filename, "r"); + if(eFile) + { + char buffer[256]; + int cnt = 0; + while(!feof(eFile)) + { + memset(buffer, 0, 256); + fscanf(eFile, "%s\n", buffer); + + if(strlen(buffer) > 0) + { + char* buffer2 = new char[strlen(buffer) + 1]; + strcpy(buffer2, buffer); + *loadlist = g_list_append(*loadlist, buffer2); + } + else + cnt++; + } + + fclose(eFile); + + return TRUE; + } + + Sys_ERROR("Failed To Load GList: %s\n", filename); + return FALSE; +} diff --git a/contrib/bobtoolz/lists.h b/contrib/bobtoolz/lists.h new file mode 100644 index 00000000..d71e7594 --- /dev/null +++ b/contrib/bobtoolz/lists.h @@ -0,0 +1,21 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +bool LoadExclusionList(char* filename, list* exclusionList); +bool LoadGList(char* filename, GList** loadlist); diff --git a/contrib/bobtoolz/misc.cpp b/contrib/bobtoolz/misc.cpp new file mode 100644 index 00000000..bebc2b24 --- /dev/null +++ b/contrib/bobtoolz/misc.cpp @@ -0,0 +1,424 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "StdAfx.h" + +#include "DEntity.h" +#include "funchandlers.h" + +#ifdef __linux__ +#include +#include +#endif + +/*========================== + Global Vars +==========================*/ + +//HANDLE bsp_process; +char g_CurrentTexture[256] = ""; + +//============================================================= +//============================================================= + +void ReadCurrentTexture() +{ + const char* textureName = g_FuncTable.m_pfnGetCurrentTexture(); + strcpy(g_CurrentTexture, textureName); +} + +const char* GetCurrentTexture() +{ + ReadCurrentTexture(); + return g_CurrentTexture; +} + +epair_t* GetNextChainItem(epair_t* lastItem, char* key, char* value) +{ + epair_t* nextEPair = g_FuncTable.m_pfnAllocateEpair(key, value); + + if(lastItem != NULL) + lastItem->next = nextEPair; + + return nextEPair; +} + +void MoveBlock(int dir, vec3_t min, vec3_t max, float dist) +{ + switch(dir) + { + case MOVE_EAST: + { + min[0]+=dist; + max[0]+=dist; + break; + } + case MOVE_WEST: + { + min[0]-=dist; + max[0]-=dist; + break; + } + case MOVE_NORTH: + { + min[1]+=dist; + max[1]+=dist; + break; + } + case MOVE_SOUTH: + { + min[1]-=dist; + max[1]-=dist; + break; + } + } +} + +void SetInitialStairPos(int dir, vec3_t min, vec3_t max, float width) +{ + switch(dir) + { + case MOVE_EAST: + { + max[0] = min[0] + width; + break; + } + case MOVE_WEST: + { + min[0] = max[0] - width; + break; + } + case MOVE_NORTH: + { + max[1] = min[1] + width; + break; + } + case MOVE_SOUTH: + { + min[1] = max[1] - width; + break; + } + } +} + +char* TranslateString (char *buf) +{ + static char buf2[32768]; + int i, l; + char *out; + + l = strlen(buf); + out = buf2; + for (i=0 ; i%s", buf); +} + +/*void Sys_Printf (char *text, ...) +{ + va_list argptr; + char buf[32768]; + + va_start (argptr,text); + vsprintf (buf, text,argptr); + va_end (argptr); + + g_FuncTable.m_pfnSysMsg ( buf ); +}*/ + +char* UnixToDosPath(char* path) +{ +#ifndef _WIN32 + return path; +#else + for(char* p = path; *p; p++) + { + if(*p == '/') + *p = '\\'; + } + return path; +#endif +} + +const char* ExtractFilename(const char* path) +{ + char* p = strrchr(path, '/'); + if(!p) + { + p = strrchr(path, '\\'); + + if(!p) + return path; + } + return ++p; +} + +extern char* PLUGIN_NAME; +/*char* GetGameFilename(char* buffer, const char* filename) +{ + strcpy(buffer, g_FuncTable.m_pfnGetGamePath()); + char* p = strrchr(buffer, '/'); + *++p = '\0'; + strcat(buffer, filename); + buffer = UnixToDosPath(buffer); + return buffer; +}*/ + +#if defined (__linux__) || defined (__APPLE__) +// the bCreateConsole parameter is ignored on linux .. +bool Q_Exec( const char *pCmd, bool bCreateConsole ) +{ + switch (fork()) + { + case -1: + return false; +// Error ("CreateProcess failed"); + break; + case 0: +#ifdef _DEBUG + printf("Running system...\n"); + printf("Command: %s\n", pCmd); +#endif + // NOTE: we could use that to detect when a step finishes. But then it + // would not work for remote compiling stuff. +// execlp (pCmd, pCmd, NULL); + system( pCmd ); + printf ("system() returned"); + _exit (0); + break; + } + return true; +} +#endif + +#ifdef _WIN32 +bool Q_Exec( const char *pCmd, bool bCreateConsole ) +{ + // G_DeWan: Don't know if this is needed for linux version + + PROCESS_INFORMATION pi; + STARTUPINFO si = {0}; // Initialize all members to zero + si.cb = sizeof(STARTUPINFO); // Set byte count + DWORD dwCreationFlags; + + if (bCreateConsole) + dwCreationFlags = CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS; + else + dwCreationFlags = DETACHED_PROCESS | NORMAL_PRIORITY_CLASS; + + for(; *pCmd == ' '; pCmd++); + + if(!CreateProcess(NULL, (char *)pCmd, NULL, NULL, FALSE, dwCreationFlags, NULL, NULL, &si, &pi)) + return false; + + return true; +} +#endif + +void StartBSP() +{ + char exename[256]; + GetFilename(exename, "q3map"); + UnixToDosPath(exename); // do we want this done in linux version? + + char mapname[256]; + const char *pn = g_FuncTable.m_pfnReadProjectKey("mapspath"); + + strcpy( mapname, pn ); + strcat( mapname, "/ac_prt.map" ); + UnixToDosPath(mapname); + + char command[1024]; + sprintf(command, "%s -nowater -fulldetail %s", exename, mapname); + + Q_Exec( command, TRUE ); +} + +void BuildMiniPrt(list* exclusionList) +{ + // yes, we could just use -fulldetail option, but, as SPOG said + // it'd be faster without all the hint, donotenter etc textures and + // doors, etc + + DEntity world; + + char buffer[128]; + const char *pn = g_FuncTable.m_pfnReadProjectKey("mapspath"); + + strcpy( buffer, pn ); + strcat( buffer, "/ac_prt.map" ); + FILE* pFile = fopen(buffer, "w"); + + // ahem, thx rr2 + if(!pFile) + return; + + int count = g_FuncTable.m_pfnGetEntityCount(); + for(int i = 0; i < count; i++) + { + entity_t* ent = (entity_t*)g_FuncTable.m_pfnGetEntityHandle(i); + + epair_t* epl = *g_EntityTable.m_pfnGetEntityKeyValList(ent); + + epair_t* ep = epl; + while(ep) + { + if(!strcmp(ep->key, "classname")) + { + if(!strcmp(ep->value, "worldspawn")) + { + world.LoadFromEntity(i, FALSE); + world.RemoveNonCheckBrushes(exclusionList, TRUE); + world.SaveToFile(pFile); + } + else if(strstr(ep->value, "info_")) + { + world.ClearBrushes(); + world.ClearEPairs(); + world.LoadEPairList(epl); + world.SaveToFile(pFile); + } + break; + } + + ep = ep->next; + } + } + + fclose(pFile); + + StartBSP(); +} + +entity_s* FindEntityFromTargetname(const char* targetname, int* entNum) +{ + DEntity world; + + int count = g_FuncTable.m_pfnGetEntityCount(); + for(int i = 0; i < count; i++) + { + world.ClearEPairs(); + + entity_s* ent = (entity_s*)g_FuncTable.m_pfnGetEntityHandle(i); + + world.LoadEPairList(*g_EntityTable.m_pfnGetEntityKeyValList(ent)); + + DEPair* tn = world.FindEPairByKey("targetname"); + if(tn) + { + if(!stricmp(tn->value, targetname)) { + if(entNum) { + *entNum = i; + } + return ent; + } + } + } + return NULL; +} + +void FillDefaultTexture(_QERFaceData* faceData, vec3_t va, vec3_t vb, vec3_t vc, const char* texture) +{ + faceData->m_bBPrimit = FALSE; + faceData->m_fRotate = 0; + faceData->m_fScale[0] = 0.5; + faceData->m_fScale[1] = 0.5; + faceData->m_fShift[0] = 0; + faceData->m_fShift[1] = 0; + faceData->m_nContents = 0; + faceData->m_nFlags = 0; + faceData->m_nValue = 0; + if(*texture) + strcpy(faceData->m_TextureName, texture); + else + strcpy(faceData->m_TextureName, "textures/common/caulk"); + VectorCopy(va, faceData->m_v1); + VectorCopy(vb, faceData->m_v2); + VectorCopy(vc, faceData->m_v3); +} + +float Determinant3x3(float a1, float a2, float a3, + float b1, float b2, float b3, + float c1, float c2, float c3) +{ + return a1*(b2*c3-b3*c2) - a2*(b1*c3-b3*c1) + a3*(b1*c2-b2*c1); +} + +bool GetEntityCentre(const char* entity, vec3_t centre) +{ + entity_s* ent = FindEntityFromTargetname(entity, NULL); + if(!ent) + return FALSE; + + int cnt = g_FuncTable.m_pfnAllocateEntityBrushHandles(ent); + if(cnt == 0) + { + g_FuncTable.m_pfnReleaseEntityBrushHandles(); + return FALSE; + } + + brush_t* brush = (brush_t*)g_FuncTable.m_pfnGetEntityBrushHandle(0); + DBrush cBrush; + cBrush.LoadFromBrush_t(brush, FALSE); + + vec3_t min, max; + cBrush.GetBounds(min, max); + + VectorAdd(min, max, centre); + VectorScale(centre, 0.5f, centre); + + g_FuncTable.m_pfnReleaseEntityBrushHandles(); + return TRUE; +} + +vec_t Min(vec_t a, vec_t b) +{ + if(a < b) + return a; + return b; +} + +void MakeNormal( vec_t* va, vec_t* vb, vec_t* vc, vec_t* out ) { + vec3_t v1, v2; + VectorSubtract(va, vb, v1); + VectorSubtract(vc, vb, v2); + CrossProduct(v1, v2, out); +} diff --git a/contrib/bobtoolz/misc.h b/contrib/bobtoolz/misc.h new file mode 100644 index 00000000..c02a99e9 --- /dev/null +++ b/contrib/bobtoolz/misc.h @@ -0,0 +1,48 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +vec_t Min(vec_t a, vec_t b); + +epair_t* GetNextChainItem(epair_t* lastItem, char* key, char* value); + +// reads current texture into global, returns pointer to it +const char* GetCurrentTexture(); + +void FillDefaultTexture(_QERFaceData* faceData, vec3_t va, vec3_t vb, vec3_t vc, const char* texture); + +void Sys_ERROR (char* text, ...); + +void BuildMiniPrt(list* exclusionList); + +void MoveBlock(int dir, vec3_t min, vec3_t max, float dist); +void SetInitialStairPos(int dir, vec3_t min, vec3_t max, float width); + +entity_s* FindEntityFromTargetname(const char* targetname, int* entNum); + +char* UnixToDosPath(char* path); + +char* GetFilename(char* buffer, const char* filename); +char* GetGameFilename(char* buffer, const char* filename); + +float Determinant3x3(float a1, float a2, float a3, + float b1, float b2, float b3, + float c1, float c2, float c3); + +bool GetEntityCentre(const char* entity, vec3_t centre); +void MakeNormal( vec_t* va, vec_t* vb, vec_t* vc, vec_t* out ); diff --git a/contrib/bobtoolz/res/plugin.rc2 b/contrib/bobtoolz/res/plugin.rc2 new file mode 100644 index 00000000..2def5721 --- /dev/null +++ b/contrib/bobtoolz/res/plugin.rc2 @@ -0,0 +1,13 @@ +// +// SOUNDTEST.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/contrib/bobtoolz/resource-gtk.h b/contrib/bobtoolz/resource-gtk.h new file mode 100644 index 00000000..e4522dff --- /dev/null +++ b/contrib/bobtoolz/resource-gtk.h @@ -0,0 +1,15 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by bobtoolz-gtk.rc +// + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1000 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/contrib/bobtoolz/resource.h b/contrib/bobtoolz/resource.h new file mode 100644 index 00000000..999d639b --- /dev/null +++ b/contrib/bobtoolz/resource.h @@ -0,0 +1,115 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by bobToolz.rc +// +#define IDD_PATHPLOTTER_DIALOG 101 +#define IDD_ABOUT 129 +#define IDD_STAIR_DIALOG 130 +#define IDD_POLYGON_DIALOG 131 +#define IDB_BT_BITMAP 137 +#define IDI_ICON1 139 +#define IDD_POLYGON_BRD_DIALOG 141 +#define IDD_DOOR_DIALOG 141 +#define IDD_INTERSECT_DIALOG 143 +#define IDD_INTERSECT_INFO_DIALOG 144 +#define IDD_BRUSHCHECKER_DIALOG 146 +#define IDD_AUTOCAULK_DIALOG 147 +#define IDD_AUTOCAULKSTART_DIALOG 148 +#define IDD_TEXTURE_RESET_DIALOG 149 +#define IDC_EDIT1 1000 +#define IDC_DIR_N_RADIO 1001 +#define IDC_TRIMTEXTURE_EDIT 1001 +#define IDC_SCL_VERT_EDIT 1001 +#define IDC_DIR_S_RADIO 1002 +#define IDC_SCL_HOR_EDIT 1002 +#define IDC_POINTCOUNT_EDIT 1002 +#define IDC_DIR_E_RADIO 1003 +#define IDC_ROTATION_EDIT 1003 +#define IDC_MULTIPLIER_EDIT 1003 +#define IDC_DIR_W_RADIO 1004 +#define IDC_SHFT_VER_EDIT 1004 +#define IDC_GRAVITY_EDIT 1004 +#define IDC_STYLE_ORIG_RADIO 1005 +#define IDC_SHFT_HOR_EDIT 1005 +#define IDC_NOUPDATE_CHECK 1005 +#define IDC_STYLE_BOB_RADIO 1006 +#define IDC_SHOWEXTRA_CHECK 1006 +#define IDC_STYLE_CORNER_RADIO 1007 +#define IDC_RISER_EDIT 1011 +#define IDC_FLAT_EDIT 1012 +#define IDC_MAX_WALL_WIDTH 1013 +#define IDC_MIN_WALL_WIDTH 1014 +#define IDC_DETAIL_CHK 1014 +#define IDC_MAX_CLIFF_HEIGHT 1015 +#define IDC_INVERSE_CHK 1015 +#define IDC_MIN_CLIFF_HEIGHT 1016 +#define IDC_BORDER_CHK 1016 +#define IDC_ALIGN_CHK 1017 +#define IDC_BORDER_EDIT 1018 +#define IDC_MAX_CNR_SIZE 1019 +#define IDC_MIN_CNR_SIZE 1020 +#define IDC_FBTEXTURE_EDIT 1020 +#define IDC_GRID_SNAP 1021 +#define IDC_TEXSCALE1_CHECK 1021 +#define IDC_MAX_WALL_BREADTH 1022 +#define IDC_TEXSCALE2_CHECK 1022 +#define IDC_MIN_WALL_BREADTH 1023 +#define IDC_MAINTEX_COMBO 1023 +#define IDC_TEXSCALE3_CHECK 1024 +#define IDC_TEXSCALE4_CHECK 1025 +#define IDC_TRIMTEX_COMBO 1026 +#define IDC_SET_MAINTEX_BTN 1027 +#define IDC_SET_TRIMTEX_BTN 1028 +#define IDC_WHOLEMAP_CHECK 1030 +#define IDC_DETAIL_INCLUDE_CHECK 1031 +#define IDC_SKIPBOUNDS_CHECK 1032 +#define IDC_SKIPSIMPLE_CHECK 1033 +#define IDC_SKIPACCURATE_CHECK 1034 +#define IDC_PROGRESS1 1035 +#define IDC_INTR_PROG1 1035 +#define IDC_DIR_NS_RADIO 1036 +#define IDC_PROGRESS2 1036 +#define IDC_DIR_EW_RADIO 1037 +#define IDC_DIR_GROUP 1038 +#define IDC_WHOLEMAP_RADIO 1040 +#define IDC_SELECTED_RADIO 1041 +#define IDC_KILLBRUSHES_CHECK 1041 +#define IDC_WARNING1_STATIC 1042 +#define IDC_AC_NORMAL_RADIO 1043 +#define IDC_AC_BUILD_MINI_PRT_RADIO 1044 +#define IDC_AC_SUPER_RADIO 1045 +#define IDC_RESET_TEXTURE_EDIT 1046 +#define IDC_RESET_NEW_TEXTURE_EDIT 1047 +#define IDC_ONLYTEXTURE_CHECK 1048 +#define IDC_ALLTEXTURES_CHECK 1049 +#define IDC_DUPLICATEONLY_CHECK 1050 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 102 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1007 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/contrib/bobtoolz/shapes.cpp b/contrib/bobtoolz/shapes.cpp new file mode 100644 index 00000000..d69023ee --- /dev/null +++ b/contrib/bobtoolz/shapes.cpp @@ -0,0 +1,666 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + + +#include "StdAfx.h" + +#include "shapes.h" + +#include "DPlane.h" + +#include "misc.h" +#include "funchandlers.h" + +//#include "dialogs-gtk.h" + +/************************ + Cube Diagram +************************/ + +/* + + 7 ----- 5 + /| /| + / | / | + / | / | + 4 ----- 6 | + | 2|_|___|8 + | / | / + | / | / ----> WEST, definitely + |/ | / + 1|_____|/3 + +*/ + +/************************ + Global Variables +************************/ + +vec3_t g_Origin = {0.0f, 0.0f, 0.0f}; + +extern bool bFacesAll[]; + +/************************ + Helper Functions +************************/ + +float Deg2Rad(float angle) +{ + return (float)(angle*Q_PI/180); +} + +void AddFaceWithTexture(brush_t* brush, vec3_t va, vec3_t vb, vec3_t vc, const char* texture, bool detail) +{ + _QERFaceData faceData; + FillDefaultTexture(&faceData, va, vb, vc, texture); + if(detail) + faceData.m_nContents |= FACE_DETAIL; + + g_FuncTable.m_pfnAddFaceData(brush, &faceData); +} + +void AddFaceWithTextureScaled(brush_t* brush, vec3_t va, vec3_t vb, vec3_t vc, + const char* texture, bool bVertScale, bool bHorScale, + float minX, float minY, float maxX, float maxY) +{ + g_ShadersTable.m_pfnShader_ForName(texture); // need to call frist to load? + + qtexture_t* pqtTexInfo; + + // TTimo: there used to be a call to pfnHasShader here + // this was not necessary. In Radiant everything is shader. + // If a texture doesn't have a shader script, a default shader object is used. + // The IShader object was leaking also + // collect texture info: sizes, etc + IShader* i = g_ShadersTable.m_pfnShader_ForName(texture); + pqtTexInfo = i->getTexture(); // shader width/height doesn't come out properly + + if(pqtTexInfo) + { + float scale[2] = {0.5f, 0.5f}; + float shift[2] = {0, 0}; + + if(bHorScale) + { + int texWidth = pqtTexInfo->width; + float width = maxX - minX; + + scale[0] = width/texWidth; + shift[0] = -(float)((int)maxX%(int)width)/scale[0]; + } + + if(bVertScale) + { + int texHeight = pqtTexInfo->height; + float height = maxY - minY; + + scale[1] = height/texHeight; + shift[1] = (float)((int)minY%(int)height)/scale[1]; + } + + _QERFaceData addFace; + FillDefaultTexture(&addFace, va, vb, vc, texture); + addFace.m_fScale[0] = scale[0]; + addFace.m_fScale[1] = scale[1]; + addFace.m_fShift[0] = shift[0]; + addFace.m_fShift[1] = shift[1]; + + g_FuncTable.m_pfnAddFaceData(brush, &addFace); + } + else + { + // shouldn't even get here, as default missing texture should be returned if + // texture doesn't exist, but just in case + AddFaceWithTexture(brush, va, vb, vc, texture, FALSE); + Sys_ERROR("BobToolz::Invalid Texture Name-> %s", texture); + } + // the IShader is not kept referenced, DecRef it + i->DecRef(); +} + +/************************ + --Main Functions-- +************************/ + +void Build_Wedge(int dir, vec3_t min, vec3_t max, bool bUp) +{ + brush_t* newBrush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + + vec3_t v1, v2, v3, v5, v6, v7, v8; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + VectorCopy(max, v8); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + v8[2] = min[2]; + + if(bUp) + { + + if(dir != MOVE_EAST) + AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", FALSE); + + if(dir != MOVE_WEST) + AddFaceWithTexture(newBrush, v7, v5, v8, "textures/common/caulk", FALSE); + + if(dir != MOVE_NORTH) + AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", FALSE); + + if(dir != MOVE_SOUTH) + AddFaceWithTexture(newBrush, v3, v8, v6, "textures/common/caulk", FALSE); + + AddFaceWithTexture(newBrush, v1, v2, v3, "textures/common/caulk", FALSE); + + if(dir == MOVE_EAST) + AddFaceWithTexture(newBrush, v1, v3, v5, "textures/common/caulk", FALSE); + + if(dir == MOVE_WEST) + AddFaceWithTexture(newBrush, v2, v6, v8, "textures/common/caulk", FALSE); + + if(dir == MOVE_NORTH) + AddFaceWithTexture(newBrush, v1, v6, v5, "textures/common/caulk", FALSE); + + if(dir == MOVE_SOUTH) + AddFaceWithTexture(newBrush, v7, v3, v8, "textures/common/caulk", FALSE); + } + else + { + if(dir != MOVE_WEST) + AddFaceWithTexture(newBrush, v7, v5, v8, "textures/common/caulk", FALSE); + + if(dir != MOVE_EAST) + AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", FALSE); + + if(dir != MOVE_NORTH) + AddFaceWithTexture(newBrush, v3, v8, v6, "textures/common/caulk", FALSE); + + if(dir != MOVE_SOUTH) + AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", FALSE); + + + AddFaceWithTexture(newBrush, v6, v5, v7, "textures/common/caulk", FALSE); + + if(dir == MOVE_WEST) + AddFaceWithTexture(newBrush, v1, v5, v3, "textures/common/caulk", FALSE); + + if(dir == MOVE_EAST) + AddFaceWithTexture(newBrush, v2, v8, v6, "textures/common/caulk", FALSE); + + if(dir == MOVE_NORTH) + AddFaceWithTexture(newBrush, v1, v5, v6, "textures/common/caulk", FALSE); + + if(dir == MOVE_SOUTH) + AddFaceWithTexture(newBrush, v7, v8, v3, "textures/common/caulk", FALSE); + } + + g_FuncTable.m_pfnCommitBrushHandle(newBrush); +} + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +void Build_StairStep_Wedge(int dir, vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, bool detail) +{ + brush_t* newBrush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + + //----- Build Outer Bounds --------- + + vec3_t v1, v2, v3, v5, v6, v7, v8; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + VectorCopy(max, v8); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + + v8[2] = min[2]; + //v8 needed this time, becoz of sloping faces (2-4-6-8) + + //---------------------------------- + + AddFaceWithTexture(newBrush, v6, v5, v7, mainTexture, detail); + + if(dir != MOVE_EAST) + { + if(dir == MOVE_WEST) + AddFaceWithTexture(newBrush, v5, v2, v7, riserTexture, detail); + else + AddFaceWithTexture(newBrush, v5, v2, v7, "textures/common/caulk", detail); + } + + if(dir != MOVE_WEST) + { + if(dir == MOVE_EAST) + AddFaceWithTexture(newBrush, v1, v3, v6, riserTexture, detail); + else + AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", detail); + } + + if(dir != MOVE_NORTH) + { + if(dir == MOVE_SOUTH) + AddFaceWithTexture(newBrush, v3, v5, v6, riserTexture, detail); + else + AddFaceWithTexture(newBrush, v3, v5, v6, "textures/common/caulk", detail); + } + + if(dir != MOVE_SOUTH) + { + if(dir == MOVE_NORTH) + AddFaceWithTexture(newBrush, v1, v7, v2, riserTexture, detail); + else + AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", detail); + } + + + if(dir == MOVE_EAST) + AddFaceWithTexture(newBrush, v1, v5, v3, "textures/common/caulk", detail); + + if(dir == MOVE_WEST) + AddFaceWithTexture(newBrush, v2, v8, v6, "textures/common/caulk", detail); + + if(dir == MOVE_NORTH) + AddFaceWithTexture(newBrush, v1, v5, v6, "textures/common/caulk", detail); + + if(dir == MOVE_SOUTH) + AddFaceWithTexture(newBrush, v7, v8, v3, "textures/common/caulk", detail); + + g_FuncTable.m_pfnCommitBrushHandle(newBrush); +} + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +// internal use only, to get a box without finishing construction +brush_t* Build_Get_BoundingCube_Selective(vec3_t min, vec3_t max, char* texture, bool* useFaces) +{ + brush_t* newBrush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + + //----- Build Outer Bounds --------- + + vec3_t v1, v2, v3, v5, v6, v7; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + + //---------------------------------- + + //----- Add Six Cube Faces --------- + + if(useFaces[0]) + AddFaceWithTexture(newBrush, v1, v2, v3, texture, FALSE); + if(useFaces[1]) + AddFaceWithTexture(newBrush, v1, v3, v6, texture, FALSE); + if(useFaces[2]) + AddFaceWithTexture(newBrush, v1, v7, v2, texture, FALSE); + + if(useFaces[3]) + AddFaceWithTexture(newBrush, v5, v6, v3, texture, FALSE); + if(useFaces[4]) + AddFaceWithTexture(newBrush, v5, v2, v7, texture, FALSE); + if(useFaces[5]) + AddFaceWithTexture(newBrush, v5, v7, v6, texture, FALSE); + + //---------------------------------- + + return newBrush; +} + +brush_t* Build_Get_BoundingCube(vec3_t min, vec3_t max, char* texture) +{ + return Build_Get_BoundingCube_Selective(min, max, texture, bFacesAll); +} + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +void Build_StairStep(vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, int direction) +{ + brush_t* newBrush = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + + //----- Build Outer Bounds --------- + + vec3_t v1, v2, v3, v5, v6, v7; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + + //---------------------------------- + + AddFaceWithTexture(newBrush, v6, v5, v7, mainTexture, FALSE); + // top gets current texture + + + if(direction == MOVE_EAST) + AddFaceWithTexture(newBrush, v1, v3, v6, riserTexture, FALSE); + else + AddFaceWithTexture(newBrush, v1, v3, v6, "textures/common/caulk", FALSE); + // west facing side, etc... + + + if(direction == MOVE_NORTH) + AddFaceWithTexture(newBrush, v1, v7, v2, riserTexture, FALSE); + else + AddFaceWithTexture(newBrush, v1, v7, v2, "textures/common/caulk", FALSE); + + if(direction == MOVE_SOUTH) + AddFaceWithTexture(newBrush, v3, v5, v6, riserTexture, FALSE); + else + AddFaceWithTexture(newBrush, v3, v5, v6, "textures/common/caulk", FALSE); + + if(direction == MOVE_WEST) + AddFaceWithTexture(newBrush, v7, v5, v2, riserTexture, FALSE); + else + AddFaceWithTexture(newBrush, v7, v5, v2, "textures/common/caulk", FALSE); + + + AddFaceWithTexture(newBrush, v1, v2, v3, "textures/common/caulk", FALSE); + // base is caulked + + g_FuncTable.m_pfnCommitBrushHandle(newBrush); + // finish brush +} + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +void BuildDoorsX2(vec3_t min, vec3_t max, + bool bSclMainHor, bool bSclMainVert, + bool bSclTrimHor, bool bSclTrimVert, + const char* mainTexture, const char* trimTexture, + int direction) +{ + int xy; + if(direction == 0) + xy = 0; + else + xy = 1; + + //----- Build Outer Bounds --------- + + vec3_t v1, v2, v3, v5, v6, v7, ve_1, ve_2, ve_3; + VectorCopy(min, v1); + VectorCopy(min, v2); + VectorCopy(min, v3); + VectorCopy(max, v5); + VectorCopy(max, v6); + VectorCopy(max, v7); + + v2[0] = max[0]; + v3[1] = max[1]; + + v6[0] = min[0]; + v7[1] = min[1]; + + float width = (max[xy] - min[xy])/2; + + if(direction == 0) + { + VectorCopy(v1, ve_1); + VectorCopy(v3, ve_2); + VectorCopy(v6, ve_3); + } + else + { + VectorCopy(v7, ve_1); + VectorCopy(v1, ve_2); + VectorCopy(v2, ve_3); + } + + ve_1[xy] += width; + ve_2[xy] += width; + ve_3[xy] += width; + + //---------------------------------- + + brush_t* newBrush1 = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + brush_t* newBrush2 = (brush_t*)g_FuncTable.m_pfnCreateBrushHandle(); + + AddFaceWithTexture(newBrush1, v1, v2, v3, "textures/common/caulk", FALSE); + AddFaceWithTexture(newBrush1, v5, v7, v6, "textures/common/caulk", FALSE); + + AddFaceWithTexture(newBrush2, v1, v2, v3, "textures/common/caulk", FALSE); + AddFaceWithTexture(newBrush2, v5, v7, v6, "textures/common/caulk", FALSE); + + if(direction == 0) + { + AddFaceWithTexture(newBrush1, v1, v3, v6, "textures/common/caulk", FALSE); + AddFaceWithTexture(newBrush2, v5, v2, v7, "textures/common/caulk", FALSE); + } + else + { + AddFaceWithTexture(newBrush1, v1, v7, v2, "textures/common/caulk", FALSE); + AddFaceWithTexture(newBrush2, v5, v6, v3, "textures/common/caulk", FALSE); + } + + if(direction == 0) + { + AddFaceWithTextureScaled(newBrush1, v1, v7, v2, mainTexture, bSclMainVert, bSclMainHor, + min[0], min[2], max[0], max[2]); + AddFaceWithTextureScaled(newBrush1, v5, v6, v3, mainTexture, bSclMainVert, bSclMainHor, + max[0], min[2], min[0], max[2]); + + + AddFaceWithTextureScaled(newBrush2, v1, v7, v2, mainTexture, bSclMainVert, bSclMainHor, + min[0], min[2], max[0], max[2]); + AddFaceWithTextureScaled(newBrush2, v5, v6, v3, mainTexture, bSclMainVert, bSclMainHor, + max[0], min[2], min[0], max[2]); // flip max/min to reverse tex dir + + + + AddFaceWithTextureScaled(newBrush1, ve_3, ve_2, ve_1, trimTexture, bSclTrimVert, bSclTrimHor, + min[1], min[2], max[1], max[2]); + + AddFaceWithTextureScaled(newBrush2, ve_1, ve_2, ve_3, trimTexture, bSclTrimVert, bSclTrimHor, + max[1], min[2], min[1], max[2]); + } + else + { + AddFaceWithTextureScaled(newBrush1, v1, v3, v6, mainTexture, bSclMainVert, bSclMainHor, + min[1], min[2], max[1], max[2]); + AddFaceWithTextureScaled(newBrush1, v5, v2, v7, mainTexture, bSclMainVert, bSclMainHor, + max[1], min[2], min[1], max[2]); + + + AddFaceWithTextureScaled(newBrush2, v1, v3, v6, mainTexture, bSclMainVert, bSclMainHor, + min[1], min[2], max[1], max[2]); + AddFaceWithTextureScaled(newBrush2, v5, v2, v7, mainTexture, bSclMainVert, bSclMainHor, + max[1], min[2], min[1], max[2]); // flip max/min to reverse tex dir + + + AddFaceWithTextureScaled(newBrush1, ve_1, ve_2, ve_3, trimTexture, bSclTrimVert, bSclTrimHor, + min[0], min[2], max[0], max[2]); + + AddFaceWithTextureScaled(newBrush2, ve_3, ve_2, ve_1, trimTexture, bSclTrimVert, bSclTrimHor, + max[0], min[2], min[0], max[2]); + } + + //---------------------------------- + + + entity_t* pEDoor1 = (entity_t*)g_FuncTable.m_pfnCreateEntityHandle(); + entity_t* pEDoor2 = (entity_t*)g_FuncTable.m_pfnCreateEntityHandle(); + + epair_t* epDoor11 = GetNextChainItem(NULL, "classname", "func_door"); + epair_t* epDoor21 = GetNextChainItem(NULL, "classname", "func_door"); + + epair_t* epDoor12; + epair_t* epDoor22; + + if(direction == 0) + { + epDoor12 = GetNextChainItem(epDoor11, "angle", "180"); + epDoor22 = GetNextChainItem(epDoor21, "angle", "360"); + } + else + { + epDoor12 = GetNextChainItem(epDoor11, "angle", "270"); + epDoor22 = GetNextChainItem(epDoor21, "angle", "90"); + } + + srand((unsigned)time(NULL)); + + char teamname[256]; + sprintf(teamname, "t%i", rand()); + /*epair_t* epDoor13 = */ GetNextChainItem(epDoor12, "team", teamname); + /*epair_t* epDoor23 = */ GetNextChainItem(epDoor22, "team", teamname); + + g_FuncTable.m_pfnCommitBrushHandleToEntity(newBrush1, pEDoor1); + g_FuncTable.m_pfnCommitBrushHandleToEntity(newBrush2, pEDoor2); + + g_EntityTable.m_pfnSetEntityKeyValList(pEDoor1, epDoor11); + g_EntityTable.m_pfnSetEntityKeyValList(pEDoor2, epDoor21); + + g_FuncTable.m_pfnCommitEntityHandleToMap(pEDoor1); + g_FuncTable.m_pfnCommitEntityHandleToMap(pEDoor2); + +// ResetCurrentTexture(); +} + +//----------------------------------------------------------------------------------- +//----------------------------------------------------------------------------------- + +void MakeBevel(vec3_t vMin, vec3_t vMax) +{ + int nIndex = g_FuncTable.m_pfnCreatePatchHandle(); + //$ FIXME: m_pfnGetPatchHandle + patchMesh_t* pm = g_FuncTable.m_pfnGetPatchData(nIndex); + + pm->height = 3; + pm->width = 3; + + vec3_t x_3, y_3, z_3; + x_3[0] = vMin[0]; x_3[1] = vMin[0]; x_3[2] = vMax[0]; + y_3[0] = vMin[1]; y_3[1] = vMax[1]; y_3[2] = vMax[1]; + z_3[0] = vMin[2]; z_3[1] = (vMax[2] + vMin[2])/2; z_3[2] = vMax[2]; + +/* x_3[0] = 0; x_3[1] = 0; x_3[2] = 64; + y_3[0] = 0; y_3[1] = 64; y_3[2] = 64; + z_3[0] = 0; z_3[1] = 32; z_3[2] = 64;*/ + + for(int i = 0; i < 3; i++) + { + for(int j = 0; j < 3; j++) + { + pm->ctrl[i][j].xyz[0] = x_3[i]; + pm->ctrl[i][j].xyz[1] = y_3[i]; + pm->ctrl[i][j].xyz[2] = z_3[j]; + } + } + + + g_FuncTable.m_pfnCommitPatchHandleToMap(nIndex, pm, "textures/common/caulk"); +} + +void BuildCornerStairs(vec3_t vMin, vec3_t vMax, int nSteps, const char* mainTexture, const char* riserTex) +{ + vec3_t* topPoints = new vec3_t[nSteps+1]; + vec3_t* botPoints = new vec3_t[nSteps+1]; + + bool bFacesUse[6] = {TRUE, TRUE, FALSE, TRUE, FALSE, FALSE}; + + vec3_t centre; + VectorCopy(vMin, centre); + centre[0] = vMax[0]; + + int height = (int)(vMax[2] - vMin[2]) / nSteps; + + vec3_t vTop, vBot; + VectorCopy(vMax, vTop); + VectorCopy(vMin, vBot); + vTop[2] = vMin[2] + height; + + int i; + for(i = 0; i <= nSteps; i++) + { + VectorCopy(centre, topPoints[i]); + VectorCopy(centre, botPoints[i]); + + topPoints[i][2] = vMax[2]; + botPoints[i][2] = vMin[2]; + + topPoints[i][0] -= 10 * sinf( Q_PI * i / ( 2 * nSteps ) ); + topPoints[i][1] += 10 * cosf( Q_PI * i / ( 2 * nSteps ) ); + + botPoints[i][0] = topPoints[i][0]; + botPoints[i][1] = topPoints[i][1]; + } + + vec3_t tp[3]; + for(int j = 0; j < 3; j++) + VectorCopy(topPoints[j], tp[j]); + + for(i = 0; i < nSteps; i++) + { + brush_t* brush = Build_Get_BoundingCube_Selective(vBot, vTop, "textures/common/caulk", bFacesUse); + + for(int j = 0; j < 3; j++) + tp[j][2] = vTop[2]; + + AddFaceWithTexture(brush, tp[2], tp[1], tp[0], mainTexture, FALSE); + + AddFaceWithTexture(brush, centre, botPoints[i+1], topPoints[i+1], "textures/common/caulk", FALSE); + AddFaceWithTexture(brush, centre, topPoints[i], botPoints[i], riserTex, FALSE); + + g_FuncTable.m_pfnCommitBrushHandle(brush); + + vTop[2] += height; + vBot[2] += height; + } + + delete[] topPoints; + delete[] botPoints; + + vMin[2] += height; + vMax[2] += height; + MakeBevel(vMin, vMax); +} diff --git a/contrib/bobtoolz/shapes.h b/contrib/bobtoolz/shapes.h new file mode 100644 index 00000000..e5fccd9c --- /dev/null +++ b/contrib/bobtoolz/shapes.h @@ -0,0 +1,49 @@ +/* +BobToolz plugin for GtkRadiant +Copyright (C) 2001 Gordon Biggans + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// TODO: implement all this stuff via DBrush class. started with DShape +// TODO: Auto Face Scaling, no need to pass parms, calculated via brush. + +// Q3MAP stuff +#define FACE_DETAIL 0x8000000 + +// defines for polygon stuff +#define MAX_POLYGON_FACES 128 + +// generic (detail added 12/01/01, for AC+) +void AddFaceWithTexture(brush_t* brush, vec3_t va, vec3_t vb, vec3_t vc, const char* texture, bool detail); + +// ------------- +// ---caulked--- +// ------------- +void Build_Wedge(int dir, vec3_t min, vec3_t max, bool bUp); + +// -------------- +// ---textured--- +// -------------- +void BuildDoorsX2(vec3_t min, vec3_t max, bool bSclMainHor, bool bSclMainVert, bool bSclTrimHor, bool bSclTrimVert, const char* mainTexture, const char* trimTexture, int direction); +void Build_StairStep(vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, int direction); +void Build_StairStep_Wedge(int dir, vec3_t min, vec3_t max, const char* mainTexture, const char* riserTexture, bool detail); +void BuildCornerStairs(vec3_t vMin, vec3_t vMax, int nSteps, const char* mainTexture, const char* riserTex); +// stairs stuff. + +//void Build_Prism_Border(vec3_t min, vec3_t max, int nSides, int nBorder, bool bAlignTop = FALSE); //moved to DShape +//void Build_Prism_Ordinary(vec3_t min, vec3_t max, int nSides, bool bAlignTop = FALSE); //moved to DShape +//void Build_Prism_Efficient(vec3_t min, vec3_t max, int nSides, bool bAlignTop = FALSE); //moved to DShape +// polygon stuff. diff --git a/contrib/bobtoolz/txt/changelog.txt b/contrib/bobtoolz/txt/changelog.txt new file mode 100644 index 00000000..c7440a5e --- /dev/null +++ b/contrib/bobtoolz/txt/changelog.txt @@ -0,0 +1,96 @@ +BobToolz Changelog: +[=================] + +Changes in v1110 (GTK): +[=====================] + +djbob + +Added: +(16.05.01) + Impemented a little feature that highligths the q3map bug that is causing problems for autocaulk, (see readme) +(01.04.01) + Added DPatch class to implement patches, however radiant does not (currently) support adding patches to an entity via a plugin, so, its actually redundant atm, i was adding this to fix the patches being removed from entities probelm with dealing with entities outside of the worldspawn. + +Changes: +(02.04.01) + EPair keys and values can now be 128 characters long, not 64, happy now hydra? + Texture reseter works on patches now too. + +Removed: +(29.03.01) + Removed CTF colour changer, it is now in the ctftoolz. + +Fixed: +(02.04.01) + Worldspawn brushes are rebuilt per brush, rather than per entity in texture reseter. +(03.04.01) + Worldspawn brushes are rebuilt per brush, rather than per entity in brush cleanup. + +Changes in v1100 (GTK): +[=====================] + +djbob + +Added: +(24.03.01) + Added CTF colour changer for worldspawn+func_group. + +Changes: +(25.03.01) + Brought some functions over to using DMap class, allowing them to run on multiple entities, patches are still a no-no atm. + This includes: + + a) brush cleanup, will now fix problems on brushes that are not in the worldspawn, and rebuild the entitiy afterwards. + b) texture reseter will change textures on all brushes now, not just those in the worldspawn. + c) CTF colour changer will also work on brushes outside of the worldspawn entity. + +This introduces one prolem, patches in entities will no longer be part of the new entity, sorry for any trouble this causes, i will fix it soon hopefully. + +Fixes: +(25.03.01) + Fixed bug in DMap class that prevented it destroying brushes... thus enabling the class to work!!!! + +Changes in v1090 (GTK): +[=====================] + +djbob + +Added: +(22.03.01) + Added PitOMatic Function. + +Changes in v1080b (GTK): +[======================] + +djbob + +Fixes: + Removed some previously unnoticed porting introduced bugs. + +Added: + Polygon stuff now passes through my internal validation routines, no more phantom brushes will be made, or squiffy planes. + +Changes in v1080 (GTK): +[=====================] + +djbob + +Fixes: +(05.03.01) + Fixed line removed by rr2 in autocaulk. + Fixed Autocaulk not working with maps larger than the old grid. + +Added: +(04.03.01) + Added Changelog. + Added ability to align polygons so that top edge will be flat. (Request By Casey) +(05.03.01) + Added ability to change main texture for stairs. + +rr2do2 + +Changes: +(??.??.01) + Removed all traces of MFC from GTK version, the evil that it is ;] + diff --git a/contrib/bobtoolz/txt/readme.txt b/contrib/bobtoolz/txt/readme.txt new file mode 100644 index 00000000..d816b5b1 --- /dev/null +++ b/contrib/bobtoolz/txt/readme.txt @@ -0,0 +1,77 @@ +BobToolz GTK: v1100 +[=================] + +Date: +[===] +16.05.01 + +The multipurpose Quake3 Mappers Tool +[==================================] + +Author: djbob +Other work: q3terra, ctftoolz, EECA mod + +eMail: gbiggans@uglab.eee.strath.ac.uk (NO SPAM thank u very much :P) + +www: www.planetquake.com/toolz + www.planetquake.com/eeca + +IRC: #freepq irc.fdf.net + #qeradiant irc.telefragged.com + +Files Contained In This Package: +[==============================] + +Readme.txt --- This file. +Changelog.txt --- Version information. +bobToolz.dll --- The plugin itsself. +bt/*.txt --- A few text files required by the plugin. + + +What's a boy to do? +[=================] + +Put The plugin in your GTKRadiant plugins folder: +e.g. mine: c:\gamez\quake3\GTKRadiant\plugins + +Run Radiant, and select the toolz from the dropdown plugin menu. + +Help is available in the form of a manual on my site. + + + +For the new q3map bug highlighting feature, run autocaulk-build mini prt, then run autocaulk. +identify an area which has been caulked incorrectly, then reopen the map, select the q3map bug highlight option, and wait. +once the selected brushes appear, u have 2 choices, + +a) press i and remove all the original brushes, or +b) keep going with both sets (slower, but more useful) + +navigate to the problem region, you should find that the set of inverse brushes that has been built is missing a brush +at the problem area, i suppose the next problem is finding out why :] + +this function is mainly provided for other coders to show the problem, and is probably of little use to anyone else, +but u never know. + + +Coming Soon: +[==========] +Region area saving. perhaps, if i get the time to finish it. + + +Testing, Feedback & Ideas: +[========================] + + Akuma, Casey, Cartman2K, maverik, rayden, nephilim_goth and god knows who else. + Thx to you all. + +Thanx: +[====] + + ttimo, da man :] + spog, for his often baffling advice.... and questions.... + Thx to rr2do2, for his linux conversion, and removing the "evil" (his words :]) MFC code. + Thx to RKone, for improving my q3w sig. + Azr for giving me ops in #qeradiant, k3wl :] + Everyone at the Quake3World Forums, I think of you all as my little worshippers :P + id Software, of course. \ No newline at end of file diff --git a/contrib/bobtoolz/visfind.cpp b/contrib/bobtoolz/visfind.cpp new file mode 100644 index 00000000..28525ff9 --- /dev/null +++ b/contrib/bobtoolz/visfind.cpp @@ -0,0 +1,245 @@ +// Requries parts of the q3 tools source to compile +// Date: Oct 5, 2001 +// Written by: Brad Whitehead (whiteheb@gamerstv.net) + +#include "StdAfx.h" +#include "dialogs/dialogs-gtk.h" +#include "DWinding.h" +#include "bsploader.h" + +typedef struct { + int portalclusters; + int leafbytes; //leafbytes = ((portalclusters+63)&~63)>>3; +} vis_header; + +// added because int shift = 32; i = 0xFFFFFFFF >> shift; +// then i = 0xFFFFFFFF, when it should = 0 +const unsigned long bitmasks[33] = +{ + 0x00000000, + 0x00000001, 0x00000003, 0x00000007, 0x0000000F, + 0x0000001F, 0x0000003F, 0x0000007F, 0x000000FF, + 0x000001FF, 0x000003FF, 0x000007FF, 0x00000FFF, + 0x00001FFF, 0x00003FFF, 0x00007FFF, 0x0000FFFF, + 0x0001FFFF, 0x0003FFFF, 0x0007FFFF, 0x000FFFFF, + 0x001FFFFF, 0x003FFFFF, 0x007FFFFF, 0x00FFFFFF, + 0x01FFFFFF, 0x03FFFFFF, 0x07FFFFFF, 0x0FFFFFFF, + 0x1FFFFFFF, 0x3FFFFFFF, 0x7FFFFFFF, 0xFFFFFFFF +}; + +int bsp_leafnumfororigin(vec3_t origin) +{ + dnode_t *node; + dplane_t *plane; + float d; + + // TODO: check if origin is in the map?? + + node = dnodes; + while (true) + { + plane = &dplanes[node->planeNum]; + d = DotProduct (origin, plane->normal) - plane->dist; + if ( d >= 0 ) + if ( node->children[0] < 0 ) + return -(node->children[0]+1); + else + node = &dnodes[node->children[0]]; + else + if ( node->children[1] < 0 ) + return -(node->children[1]+1); + else + node = &dnodes[node->children[1]]; + } + return 0; +} + +int bsp_leafnumforcluster(int cluster) +{ + dleaf_t *l; + int i; + + for ( i = 0, l = dleafs; i < numleafs; i++, l++ ) + if ( l->cluster == cluster ) return(i); + return(0); +} + +// leaf1 = origin leaf +// leaf2 = leaf to test for +/*int bsp_InPVS(int cluster1, int cluster2) +{ + vis_header *vheader; + byte *visdata; + + vheader = (vis_header *) visBytes; + visdata = visBytes + VIS_HEADER_SIZE; + + return( *( visdata + ( cluster1 * vheader->leafbytes ) + (cluster2 / 8) ) & ( 1 << ( cluster2 % 8 ) ) ); +}*/ + +void bsp_setbitvectorlength( byte *v, int length_bits, int length_vector ) +{ + int i; + + i = length_bits/8; + + *(v+i) = (byte) bitmasks[length_bits % 8]; + + memset((v+i+1), 0, length_vector-i-1); +} + + +void bsp_bitvectorsubtract(byte *first, byte *second, byte *out, int length) +{ + + int i; + + for ( i = 0; i < length; i++ ) + *(out+i) = *(first+i) & ~(*(second+i)); +} + +int bsp_countclusters(byte *bitvector, int length) +{ + int i, j, c; + + c = 0; + for ( i = 0; i < length; i++ ) + for ( j = 0; j < 8; j++ ) + if ( (*(bitvector+i) & (1 << j)) ) c++; + return(c); +} + +int bsp_countclusters_mask(byte *bitvector, byte *maskvector, int length) +{ + int i, j, c; + + c = 0; + for ( i = 0; i < length; i++ ) + for ( j = 0; j < 8; j++ ) + if ( (*(bitvector+i) & (1 << j)) && (*(maskvector+i) & (1 << j)) ) c++; + return(c); +} + +void AddCluster(list *pointlist, dleaf_t *cl, qboolean* repeatlist, vec3_t clr) +{ + DWinding* w; + + int* leafsurf = &dleafsurfaces[cl->firstLeafSurface]; + for(int k = 0; k < cl->numLeafSurfaces; k++, leafsurf++) + { + if(repeatlist[*leafsurf]) + continue; + + dsurface_t* surf = &drawSurfaces[*leafsurf]; + if(surf->surfaceType != MST_PLANAR) + continue; + + qdrawVert_t* vert = &drawVerts[surf->firstVert]; + if(surf->firstVert + surf->numVerts > numDrawVerts) + DoMessageBox("Warning", "Warning", MB_OK); + + w = new DWinding(); + w->AllocWinding(surf->numVerts); + + for (int l = 0; l < surf->numVerts; l++, vert++) + { + (w->p[l])[0] = vert->xyz[0]; + (w->p[l])[1] = vert->xyz[1]; + (w->p[l])[2] = vert->xyz[2]; + + w->clr[0] = clr[0]; + w->clr[1] = clr[1]; + w->clr[2] = clr[2]; + } + pointlist->push_back(w); + + repeatlist[*leafsurf] = true; + } +} + +/* +============= +CreateTrace +============= +*/ +list *CreateTrace( dleaf_t *leaf, int c, vis_header *header, byte *visdata, byte *seen ) +{ + byte *vis; + int i, j, clusterNum; + list *pointlist = new list; + qboolean* repeatlist = new qboolean[numDrawSurfaces]; + dleaf_t *cl; + + vec3_t clrRnd[5] = { + {0.f, 0.f, 1.f}, + {0.f, 1.f, 1.f}, + {1.f, 0.f, 0.f}, + {1.f, 0.f, 1.f}, + {1.f, 1.f, 0.f}, + }; + + vec3_t clrGreen = {0.f, 1.f, 0.f}; + + memset(repeatlist, 0, sizeof(qboolean)*numDrawSurfaces); + + vis = visdata + ( c * header->leafbytes ); + + clusterNum = 0; + + AddCluster(pointlist, &(dleafs[bsp_leafnumforcluster( c )]), repeatlist, clrGreen); + + for ( i = 0; i < header->leafbytes; i++ ) + { + for ( j = 0; j < 8; j++ ) + { + cl = &(dleafs[bsp_leafnumforcluster( clusterNum )]); + + if ( ( *(vis + i) & (1 << j) ) && (*(seen+i) & (1 << j)) && (leaf->area == cl->area)) + AddCluster(pointlist, cl, repeatlist, clrRnd[rand()%5]); + clusterNum++; + } + } + + delete repeatlist; + + return pointlist; +} + +/* +============= +TraceCluster + +setup for CreateTrace +============= +*/ +list *TraceCluster (int leafnum) +{ + byte seen[(MAX_MAP_LEAFS/8) + 1]; + vis_header *vheader; + byte *visdata; + dleaf_t *leaf; + + vheader = (vis_header *) visBytes; + visdata = visBytes + sizeof(vis_header); + + memset(seen, 0xFF, sizeof(seen)); + bsp_setbitvectorlength(seen, vheader->portalclusters, sizeof(seen)); + + leaf = &(dleafs[leafnum]); + + return CreateTrace(leaf, leaf->cluster, vheader, visdata, seen); +} + +list* BuildTrace(char* filename, vec3_t v_origin) +{ + if(!LoadBSPFile(filename)) + return NULL; + + int leafnum = bsp_leafnumfororigin(v_origin); + + list *pointlist = TraceCluster(leafnum); + + FreeBSPData(); + + return pointlist; +} diff --git a/contrib/bobtoolz/visfind.h b/contrib/bobtoolz/visfind.h new file mode 100644 index 00000000..732f3b6c --- /dev/null +++ b/contrib/bobtoolz/visfind.h @@ -0,0 +1 @@ +list *BuildTrace(char* filename, vec3_t v_origin); diff --git a/contrib/camera/bitmaps/camera_insp.bmp b/contrib/camera/bitmaps/camera_insp.bmp new file mode 100644 index 00000000..1286716e Binary files /dev/null and b/contrib/camera/bitmaps/camera_insp.bmp differ diff --git a/contrib/camera/camera.cpp b/contrib/camera/camera.cpp new file mode 100644 index 00000000..9ac94f44 --- /dev/null +++ b/contrib/camera/camera.cpp @@ -0,0 +1,292 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +// Render view +CRenderer *Renderer = NULL; + +// Interaction +CListener *Listener = NULL; + +// plugin name +static const char *PLUGIN_NAME = "Camera"; + +// commands in the menu +static const char *PLUGIN_COMMANDS = "About...,-,Load Camera...,-,Preview Camera,-,Camera Inspector...,-,New Spline Camera,New Interpolated Camera,New Fixed Camera"; + +// globals +GtkWidget *g_pRadiantWnd = NULL; +GtkWidget *g_pCameraInspectorWnd = NULL; +CCamera *firstCam = NULL; // double linked list +CCamera *firstFreeCam = NULL; // single linked list +CCamera *currentCam = NULL; // single item +bool g_bEditOn = false; +int g_iEditMode = 0; // 0: editting points 1: adding points +int g_iActiveTarget = -1; +int g_iPreviewRunning = 0; // 0: no preview 1: start preview 2: preview in progress + +static const char *PLUGIN_ABOUT = "Camera v1.0 for GtkRadiant\n" + "by Arnout van Meer (rr2do2@splashdamage.com)\n\n" + "This product contains software technology\n" + "from id Software, Inc. ('id Technology').\n" + "id Technology (c) 2001, 2002 id Software, Inc."; + + +#include "iplugin.h" + +const char* QERPlug_Init(void* hApp, void* pMainWidget) +{ + g_pRadiantWnd = (GtkWidget*)pMainWidget; + + // initialize cams + for( int i = 0; i < MAX_CAMERAS; i++ ) { + if( i == 0 ) { + firstFreeCam = new CCamera( i ); + firstCam = firstFreeCam; + } else { + firstCam->SetNext( new CCamera( i ) ); + firstCam = firstCam->GetNext(); + } + } + firstCam = NULL; + + if( !Renderer ) + { + Renderer = new CRenderer; + } + + if( g_pCameraInspectorWnd == NULL ) + g_pCameraInspectorWnd = CreateCameraInspectorDialog(); + + InitIglToQgl(&g_QglTable); + + GetFileTypeRegistry()->addType("camera", filetype_t("Camera file", "*.camera")); + + return "Camera for GtkRadiant"; +} + +const char* QERPlug_GetName() +{ + return PLUGIN_NAME; +} + +const char* QERPlug_GetCommandList() +{ + return PLUGIN_COMMANDS; +} + +void QERPlug_Dispatch (const char* p, float* vMin, float* vMax, bool bSingleBrush) +{ + if( !strcmp( p, "New Fixed Camera" ) ) + DoNewFixedCamera(); + else if( !strcmp( p, "New Interpolated Camera" ) ) + DoNewInterpolatedCamera(); + else if( !strcmp( p, "New Spline Camera" ) ) + DoNewSplineCamera(); + else if( !strcmp( p, "Camera Inspector..." ) ) + DoCameraInspector(); + else if( !strcmp( p, "Preview Camera" ) ) + DoPreviewCamera(); + else if( !strcmp( p, "Load Camera..." ) ) + DoLoadCamera(); + else if( !strcmp( p, "About..." ) ) + g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, PLUGIN_ABOUT, "About", MB_OK, NULL ); +} + + +// toolbar + +#include "itoolbar.h" + +unsigned int ToolbarButtonCount() +{ + return 1; +} + +class CameraInspectorButton : public IToolbarButton +{ +public: + virtual const char* getImage() const + { + return "camera_insp.bmp"; + } + virtual const char* getText() const + { + return "Inspector"; + } + virtual const char* getTooltip() const + { + return "Camera Inspector"; + } + virtual void activate() const + { + DoCameraInspector(); + } + virtual EType getType() const + { + return eButton; + } +}; + +CameraInspectorButton g_camerainspectorbutton; + +const IToolbarButton* GetToolbarButton(unsigned int index) +{ + return &g_camerainspectorbutton; +} + + +_QERFuncTable_1 g_FuncTable; +_QERQglTable g_QglTable; +_QERUITable g_UITable; +_QERCameraTable g_CameraTable; + +// ============================================================================= +// SYNAPSE + +#include "synapse.h" + +class CameraSynapseClient : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + CameraSynapseClient() { } + virtual ~CameraSynapseClient() { } +}; + +CSynapseServer* g_pSynapseServer = NULL; +CameraSynapseClient g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + g_SynapseClient.AddAPI(TOOLBAR_MAJOR, "camera", sizeof(_QERPlugToolbarTable)); + g_SynapseClient.AddAPI(PLUGIN_MAJOR, "camera", sizeof(_QERPluginTable)); + + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(UI_MAJOR, NULL, sizeof(_QERUITable), SYN_REQUIRE, &g_UITable); + g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(_QERQglTable), SYN_REQUIRE, &g_QglTable); + g_SynapseClient.AddAPI(CAMERA_MAJOR, NULL, sizeof(_QERCameraTable), SYN_REQUIRE, &g_CameraTable); + + return &g_SynapseClient; +} + +bool CameraSynapseClient::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, TOOLBAR_MAJOR)) + { + _QERPlugToolbarTable* pTable= static_cast<_QERPlugToolbarTable*>(pAPI->mpTable); + + pTable->m_pfnToolbarButtonCount = &ToolbarButtonCount; + pTable->m_pfnGetToolbarButton = &GetToolbarButton; + return true; + } + else if (!strcmp(pAPI->major_name, PLUGIN_MAJOR)) + { + _QERPluginTable* pTable= static_cast<_QERPluginTable*>(pAPI->mpTable); + + pTable->m_pfnQERPlug_Init = QERPlug_Init; + pTable->m_pfnQERPlug_GetName = QERPlug_GetName; + pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList; + pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch; + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CameraSynapseClient::GetInfo() +{ + return "Camera plugin v1.0 - Arnout van Meer - built " __DATE__ " " RADIANT_VERSION; +} + + + +// +// CCamera +// +CCamera *AllocCam() { + if( !firstFreeCam ) + return( NULL ); + + CCamera *cam = firstFreeCam; + firstFreeCam = firstFreeCam->GetNext(); + cam->Init(); + if( firstCam ) { + cam->SetNext( firstCam ); + firstCam->SetPrev( cam ); + } + firstCam = cam; + + return( cam ); +} + +void FreeCam( CCamera *cam ) { + if( cam->GetPrev() ) { + if( cam->GetNext() ) { + cam->GetPrev()->SetNext( cam->GetNext() ); + cam->GetNext()->SetPrev( cam->GetPrev() ); + } else { + cam->GetPrev()->SetNext( NULL ); + } + } else if( cam->GetNext() ) { + cam->GetNext()->SetPrev( NULL ); + firstCam = cam->GetNext(); + } else { + firstCam = NULL; + } + + cam->GetCam()->clear(); + cam->Init(); + + if( firstFreeCam ) { + cam->SetNext( firstFreeCam ); + } + firstFreeCam = cam; +} + +void SetCurrentCam( CCamera *cam ) { + currentCam = cam; +} + +CCamera *GetCurrentCam() { + return( currentCam ); +} diff --git a/contrib/camera/camera.def b/contrib/camera/camera.def new file mode 100644 index 00000000..509df54a --- /dev/null +++ b/contrib/camera/camera.def @@ -0,0 +1,8 @@ +; camera.def : Declares the module parameters for the DLL. + +LIBRARY "CAMERA" +DESCRIPTION 'CAMERA Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + Synapse_EnumerateInterfaces @1 diff --git a/contrib/camera/camera.h b/contrib/camera/camera.h new file mode 100644 index 00000000..d60783a9 --- /dev/null +++ b/contrib/camera/camera.h @@ -0,0 +1,162 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#ifndef _CAMERA_H_ +#define _CAMERA_H_ + +#ifdef _WIN32 + #pragma warning(disable : 4267) +#else + typedef unsigned char byte; +#endif + +class CCamera; + +#include + +#include "str.h" + +#define USE_QERTABLE_DEFINE +#include "qerplugin.h" + +#include "igl.h" +#include "iui.h" +#include "icamera.h" + +#include "misc.h" +#include "dialogs.h" +#include "funchandlers.h" +#include "renderer.h" +#include "listener.h" + +extern _QERFuncTable_1 g_FuncTable; +extern _QERQglTable g_QglTable; +extern _QERUITable g_UITable; +extern _QERCameraTable g_CameraTable; + +extern CRenderer *Renderer; +extern CListener *Listener; + +// splinelib +#define CAMERA_PLUGIN +#define DotProduct(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2]) + +extern void ( APIENTRY * qglBegin )(GLenum mode); +extern void ( APIENTRY * qglEnd )(void); +extern void ( APIENTRY * qglVertex3fv )(const GLfloat *v); + +extern "C" void InitIglToQgl( _QERQglTable *g_QglTable ); + +#include "splines/splines.h" + +// this needs to match splines.cpp +#define MAX_CAMERAS 64 +extern idCameraDef camera[MAX_CAMERAS]; + +extern "C" qboolean loadCamera(int camNum, const char *name); + +// +// CCamera +// + +class CCamera { +public: + CCamera( int i ) { + cam = &camera[i]; + camnum = i; + Init(); + } + ~CCamera(); + + void Init() { + next = prev = NULL; + fileName[0] = '\0'; + hasbeensaved = 0; + } + + idCameraDef *GetCam() { + return( cam ); + } + int GetCamNum() { + return( camnum ); + } + + char *GetFileName() { + return( fileName ); + } + void SetFileName( const char *name, bool save ) { + strcpy( fileName, name ); + if( save ) + hasbeensaved = 1; + } + + CCamera *GetNext() { + return( next ); + } + + CCamera *GetPrev() { + return( prev ); + } + + void SetNext( CCamera *camera ) { + next = camera; + } + void SetPrev( CCamera *camera ) { + prev = camera; + } + + int HasBeenSaved() { + return( hasbeensaved ); + } + void HasBeenModified() { + if( hasbeensaved ) + hasbeensaved = 2; + } + +protected: + idCameraDef *cam; + int camnum; + CCamera *next, *prev; + char fileName[PATH_MAX]; + int hasbeensaved; // 0:never saved 1:saved 2:saved, but modified +}; + +CCamera *AllocCam(); +void FreeCam( CCamera *cam ); +void SetCurrentCam( CCamera *cam ); +CCamera *GetCurrentCam(); + +// globals +extern GtkWidget *g_pRadiantWnd; +extern GtkWidget *g_pCameraInspectorWnd; +extern CCamera *firstCam; +extern bool g_bEditOn; +extern int g_iEditMode; +extern int g_iActiveTarget; +extern int g_iPreviewRunning; +extern CCamera *g_pCurrentEditCam; + +#endif // _CAMERA_H_ diff --git a/contrib/camera/camera.vcproj b/contrib/camera/camera.vcproj new file mode 100644 index 00000000..5feead39 --- /dev/null +++ b/contrib/camera/camera.vcproj @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/camera/dialogs.cpp b/contrib/camera/dialogs.cpp new file mode 100644 index 00000000..2e8e5b0e --- /dev/null +++ b/contrib/camera/dialogs.cpp @@ -0,0 +1,1352 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +static GSList *g_pEditTypeRadio = NULL; +static GtkWidget *g_pEditModeEditRadioButton = NULL; +GtkWidget *g_pEditModeAddRadioButton = NULL; +static GtkWidget *g_pSecondsEntry = NULL; +static GtkWidget *g_pEventsList = NULL; +static GtkLabel *g_pCurrentTime = NULL; +static GtkLabel *g_pTotalTime = NULL; +static GtkAdjustment *g_pTimeLine = NULL; +static GtkWidget *g_pTrackCamera = NULL; +static GtkWidget *g_pCamName = NULL; +static char *g_cNull = '\0'; + +static gint ci_editmode_edit( GtkWidget *widget, gpointer data ) +{ + g_iEditMode = 0; + + return TRUE; +} + +static gint ci_editmode_add( GtkWidget *widget, gpointer data ) +{ + g_iEditMode = 1; + + return TRUE; +} + +/*static gint ci_delete_selected( GtkWidget *widget, gpointer data ) +{ + return TRUE; +} + +static gint ci_select_all( GtkWidget *widget, gpointer data ) +{ + return TRUE; +}*/ + +static gint ci_new( GtkWidget *widget, gpointer data ) +{ + GtkWidget *window, *w, *vbox, *vbox2, *hbox, *frame; //, *name; + GtkWidget *fixed, *interpolated, *spline; + int ret, loop = 1; + GSList *targetTypeRadio = NULL; +// char buf[128]; + + // create the window + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_title( GTK_WINDOW (window), "New Camera" ); + gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); + gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); + gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pCameraInspectorWnd ) ); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + // fill the window + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + frame = gtk_frame_new( "Type" ); + gtk_box_pack_start( GTK_BOX( hbox ), frame, TRUE, TRUE, 0 ); + gtk_widget_show( frame ); + + vbox2 = gtk_vbox_new( FALSE, 5 ); + gtk_container_add( GTK_CONTAINER( frame ), vbox2 ); + gtk_container_set_border_width( GTK_CONTAINER (vbox2), 5 ); + gtk_widget_show( vbox2 ); + + // -------------------------- // + + fixed = gtk_radio_button_new_with_label( targetTypeRadio, "Fixed" ); + gtk_box_pack_start( GTK_BOX( vbox2 ), fixed, FALSE, FALSE, 3 ); + gtk_widget_show( fixed ); + targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( fixed ) ); + + interpolated = gtk_radio_button_new_with_label( targetTypeRadio, "Interpolated" ); + gtk_box_pack_start( GTK_BOX( vbox2 ), interpolated, FALSE, FALSE, 3 ); + gtk_widget_show( interpolated ); + targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( interpolated ) ); + + spline = gtk_radio_button_new_with_label( targetTypeRadio, "Spline" ); + gtk_box_pack_start( GTK_BOX( vbox2 ), spline, FALSE, FALSE, 3 ); + gtk_widget_show( spline ); + targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( spline ) ); + + // -------------------------- // + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_show (w); + + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // -------------------------- // + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if( ret == IDOK ) { + if( gtk_toggle_button_get_active( (GtkToggleButton*)fixed ) ) + DoNewFixedCamera(); + else if( gtk_toggle_button_get_active( (GtkToggleButton*)interpolated ) ) + DoNewInterpolatedCamera(); + else if( gtk_toggle_button_get_active( (GtkToggleButton*)spline ) ) + DoNewSplineCamera(); + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return TRUE; +} + +static gint ci_load( GtkWidget *widget, gpointer data ) +{ + DoLoadCamera(); + + return TRUE; +} + +static gint ci_save( GtkWidget *widget, gpointer data ) +{ + DoSaveCamera(); + + return TRUE; +} + +static gint ci_unload( GtkWidget *widget, gpointer data ) +{ + DoUnloadCamera(); + + return TRUE; +} + +static gint ci_apply( GtkWidget *widget, gpointer data ) +{ + if( GetCurrentCam() ) { + const char *str; + char buf[128]; + bool build = false; + + str = gtk_entry_get_text( GTK_ENTRY(g_pCamName) ); + + if( str ) { + GetCurrentCam()->GetCam()->setName( str ); + build = true; + } + + str = gtk_entry_get_text( GTK_ENTRY(g_pSecondsEntry) ); + + if( str ) { + GetCurrentCam()->GetCam()->setBaseTime( atof( str ) ); + build = true; + } + + if( build ) { + GetCurrentCam()->GetCam()->buildCamera(); + } + + sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getBaseTime() ); + gtk_entry_set_text( GTK_ENTRY(g_pSecondsEntry), buf ); + + sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getTotalTime() ); + gtk_label_set_text( g_pCurrentTime, "0.00" ); + gtk_label_set_text( g_pTotalTime, buf ); + + gtk_adjustment_set_value( g_pTimeLine, 0.f ); + g_pTimeLine->upper = GetCurrentCam()->GetCam()->getTotalTime() * 1000; + + GetCurrentCam()->HasBeenModified(); + } + + return TRUE; +} + +static gint ci_preview( GtkWidget *widget, gpointer data ) +{ + if( GetCurrentCam() ) { + g_iPreviewRunning = 1; + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } + + return TRUE; +} + +static gint ci_expose( GtkWidget *widget, gpointer data ) +{ + // start edit mode + DoStartEdit( GetCurrentCam() ); + + return FALSE; +} + +static gint ci_close( GtkWidget *widget, gpointer data ) +{ + gtk_widget_hide( g_pCameraInspectorWnd ); + + // exit edit mode + DoStopEdit(); + + return TRUE; +} + +static GtkWidget *g_pPathListCombo = NULL; +static GtkLabel *g_pPathType = NULL; + +static void RefreshPathListCombo( void ) +{ + if( !g_pPathListCombo ) + return; + + GList *combo_list = (GList*)NULL; + + if( GetCurrentCam() ) { + combo_list = g_list_append( combo_list, (void *)GetCurrentCam()->GetCam()->getPositionObj()->getName() ); + for( int i = 0; i < GetCurrentCam()->GetCam()->numTargets(); i++ ) { + combo_list = g_list_append( combo_list, (void *)GetCurrentCam()->GetCam()->getActiveTarget( i )->getName() ); + } + } else { + // add one empty string make gtk be quiet + combo_list = g_list_append( combo_list, (gpointer)g_cNull ); + } + + gtk_combo_set_popdown_strings( GTK_COMBO( g_pPathListCombo ), combo_list ); + g_list_free( combo_list ); +} + +static gint ci_pathlist_changed( GtkWidget *widget, gpointer data ) +{ + const char *str = gtk_entry_get_text( GTK_ENTRY(widget) ); + + if( !str || !GetCurrentCam() ) + return TRUE; + + int i; + for( i = 0; i < GetCurrentCam()->GetCam()->numTargets(); i++ ) { + if( !strcmp( str, GetCurrentCam()->GetCam()->getActiveTarget( i )->getName() ) ) + break; + } + + if( i >= 0 && i < GetCurrentCam()->GetCam()->numTargets() ) { + GetCurrentCam()->GetCam()->setActiveTarget( i ); + + g_iActiveTarget = i; + if( g_pPathType ) + gtk_label_set_text( g_pPathType, GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->typeStr() ); + } else { + g_iActiveTarget = -1; + if( g_pPathType ) + gtk_label_set_text( g_pPathType, GetCurrentCam()->GetCam()->getPositionObj()->typeStr() ); + } + + // start edit mode + if( g_pCameraInspectorWnd && GTK_WIDGET_VISIBLE( g_pCameraInspectorWnd ) ) + DoStartEdit( GetCurrentCam() ); + + return TRUE; +} + +static void RefreshEventList( void ) +{ + int i; + char buf[128]; + + // Clear events list + gtk_clist_freeze( GTK_CLIST(g_pEventsList) ); + gtk_clist_clear( GTK_CLIST(g_pEventsList) ); + + if( GetCurrentCam() ) { + // Fill events list + for( i = 0; i < GetCurrentCam()->GetCam()->numEvents(); i++ ) { + char rowbuf[3][128], *row[3]; + // FIXME: sort by time? + sprintf( rowbuf[0], "%li", GetCurrentCam()->GetCam()->getEvent(i)->getTime() ); row[0] = rowbuf[0]; + strncpy( rowbuf[1], GetCurrentCam()->GetCam()->getEvent(i)->typeStr(), sizeof(rowbuf[0]) ); row[1] = rowbuf[1]; + strncpy( rowbuf[2], GetCurrentCam()->GetCam()->getEvent(i)->getParam(), sizeof(rowbuf[1]) ); row[2] = rowbuf[2]; + gtk_clist_append( GTK_CLIST(g_pEventsList), row ); + } + + // Total duration might have changed + sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getTotalTime() ); + gtk_label_set_text( g_pCurrentTime, "0.00" ); + gtk_label_set_text( g_pTotalTime, buf ); + + gtk_adjustment_set_value( g_pTimeLine, 0.f ); + g_pTimeLine->upper = ( GetCurrentCam()->GetCam()->getTotalTime() * 1000 ); + } + + gtk_clist_thaw( GTK_CLIST(g_pEventsList) ); +} + +static gint ci_rename( GtkWidget *widget, gpointer data ) +{ + GtkWidget *window, *w, *vbox, *hbox, *name; + int ret, loop = 1; + + if( !GetCurrentCam() ) + return TRUE; + + // create the window + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_title( GTK_WINDOW (window), "Rename Path" ); + gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); + gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); + gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pCameraInspectorWnd ) ); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize ( window ); + + // fill the window + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Name:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + name = gtk_entry_new(); + gtk_box_pack_start( GTK_BOX( hbox ), name, FALSE, FALSE, 0 ); + gtk_widget_show( name ); + + if( g_iActiveTarget < 0 ) + gtk_entry_set_text( GTK_ENTRY(name), GetCurrentCam()->GetCam()->getPositionObj()->getName() ); + else + gtk_entry_set_text( GTK_ENTRY(name), GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->getName() ); + + // -------------------------- // + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_show (w); + + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // -------------------------- // + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if( ret == IDOK ) { + const char *str = gtk_entry_get_text( GTK_ENTRY(name) ); + + if( str && str[0] ) { + // Update the path + if( g_iActiveTarget < 0 ) + GetCurrentCam()->GetCam()->getPositionObj()->setName( str ); + else + GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->setName( str ); + + GetCurrentCam()->GetCam()->buildCamera(); + + // Rebuild the listbox + RefreshPathListCombo(); + } else { + dialogError = TRUE; + } + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return TRUE; +} + +static gint ci_add_target( GtkWidget *widget, gpointer data ) +{ + GtkWidget *window, *w, *vbox, *vbox2, *hbox, *frame, *name; + GtkWidget *fixed, *interpolated, *spline; + int ret, loop = 1; + GSList *targetTypeRadio = NULL; + char buf[128]; + + if( !GetCurrentCam() ) + return TRUE; + + // create the window + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_title( GTK_WINDOW (window), "Add Target" ); + gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); + gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); + gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pCameraInspectorWnd ) ); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + // fill the window + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Name:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + name = gtk_entry_new(); + gtk_box_pack_start( GTK_BOX( hbox ), name, TRUE, TRUE, 0 ); + gtk_widget_show( name ); + + sprintf( buf, "target%i", GetCurrentCam()->GetCam()->numTargets() + 1 ); + gtk_entry_set_text( GTK_ENTRY(name), buf ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + frame = gtk_frame_new( "Type" ); + gtk_box_pack_start( GTK_BOX( hbox ), frame, TRUE, TRUE, 0 ); + gtk_widget_show( frame ); + + vbox2 = gtk_vbox_new( FALSE, 5 ); + gtk_container_add( GTK_CONTAINER( frame ), vbox2 ); + gtk_container_set_border_width( GTK_CONTAINER (vbox2), 5 ); + gtk_widget_show( vbox2 ); + + // -------------------------- // + + fixed = gtk_radio_button_new_with_label( targetTypeRadio, "Fixed" ); + gtk_box_pack_start( GTK_BOX( vbox2 ), fixed, FALSE, FALSE, 3 ); + gtk_widget_show( fixed ); + targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( fixed ) ); + + interpolated = gtk_radio_button_new_with_label( targetTypeRadio, "Interpolated" ); + gtk_box_pack_start( GTK_BOX( vbox2 ), interpolated, FALSE, FALSE, 3 ); + gtk_widget_show( interpolated ); + targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( interpolated ) ); + + spline = gtk_radio_button_new_with_label( targetTypeRadio, "Spline" ); + gtk_box_pack_start( GTK_BOX( vbox2 ), spline, FALSE, FALSE, 3 ); + gtk_widget_show( spline ); + targetTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( spline ) ); + + // -------------------------- // + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_show (w); + + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // -------------------------- // + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if( ret == IDOK ) { + const char *str = gtk_entry_get_text( GTK_ENTRY(name) ); + + if( str && str[0] ) { + int type; + GList *li; + + if( gtk_toggle_button_get_active( (GtkToggleButton*)fixed ) ) + type = 0; + else if( gtk_toggle_button_get_active( (GtkToggleButton*)interpolated ) ) + type = 1; + else if( gtk_toggle_button_get_active( (GtkToggleButton*)spline ) ) + type = 2; + + // Add the target + GetCurrentCam()->GetCam()->addTarget( str, static_cast(type) ); + + // Rebuild the listbox + RefreshPathListCombo(); + + // Select the last item in the listbox + li = g_list_last( GTK_LIST(GTK_COMBO(g_pPathListCombo)->list)->children ); + gtk_list_select_child( GTK_LIST(GTK_COMBO(g_pPathListCombo)->list), GTK_WIDGET (li->data) ); + + // If this was the first one, refresh the event list + if( GetCurrentCam()->GetCam()->numTargets() == 1 ) { + RefreshEventList(); + } + + // Go to editmode Add + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(g_pEditModeAddRadioButton), TRUE ); + + } else { + dialogError = TRUE; + } + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return TRUE; +} + +static GtkWidget *g_pCamListCombo = NULL; +static GtkLabel *g_pCamType = NULL; + +void RefreshCamListCombo( void ) +{ + if( !g_pCamListCombo ) + return; + + GList *combo_list = (GList*)NULL; + CCamera *combo_cam = firstCam; + if( combo_cam ) { + while( combo_cam ) { + //combo_list = g_list_append( combo_list, (void *)combo_cam->GetCam()->getName() ); + //if( combo_cam->HasBeenSaved() ) { + combo_list = g_list_append( combo_list, (void *)combo_cam->GetFileName() ); + /*} else { + char buf[128]; + sprintf( buf, "Unsaved Camera %i", combo_cam->GetCamNum() ); + combo_list = g_list_append( combo_list, (void *)buf ); + + //combo_list = g_list_append( combo_list, (void *)combo_cam->GetCam()->getName() ); // FIXME: this requires camera.dll to create unique names for new cams + }*/ + combo_cam = combo_cam->GetNext(); + } + }else { + // add one empty string make gtk be quiet + combo_list = g_list_append( combo_list, (gpointer)g_cNull ); + } + gtk_combo_set_popdown_strings( GTK_COMBO( g_pCamListCombo ), combo_list ); + g_list_free( combo_list ); + + // select our current entry in the list + if( GetCurrentCam() ) { + // stop editing on the current cam + //GetCurrentCam()->GetCam()->stopEdit(); // FIXME: this crashed on creating new cameras, why is it here? + + GList *li = GTK_LIST( GTK_COMBO(g_pCamListCombo)->list)->children; + combo_cam = firstCam; + while( li && combo_cam ) { + if( combo_cam == GetCurrentCam() ) { + gtk_list_select_child( GTK_LIST( GTK_COMBO(g_pCamListCombo)->list ), GTK_WIDGET( li->data ) ); + break; + } + li = li->next; + combo_cam = combo_cam->GetNext(); + } + } + + RefreshPathListCombo(); +} + +static gint ci_camlist_changed( GtkWidget *widget, gpointer data ) +{ + const char *str = gtk_entry_get_text( GTK_ENTRY(widget) ); + + CCamera *combo_cam = firstCam; + while( str && combo_cam ) { + //if( !strcmp( str, combo_cam->GetCam()->getName() ) ) + //if( combo_cam->HasBeenSaved() ) { + if( !strcmp( str, combo_cam->GetFileName() ) ) + break; + /*} else { + char buf[128]; + sprintf( buf, "Unsaved Camera %i", combo_cam->GetCamNum() ); + if( !strcmp( str, buf ) ) + //if( !strcmp( str, combo_cam->GetCam()->getName() ) ) + break; + }*/ + + combo_cam = combo_cam->GetNext(); + } + + SetCurrentCam( combo_cam ); + + if( g_pCamType ) { + if( GetCurrentCam() ) { + // Fill in our widgets fields for this camera + char buf[128]; + + // Set Name + gtk_entry_set_text( GTK_ENTRY(g_pCamName), GetCurrentCam()->GetCam()->getName() ); + + // Set type + gtk_label_set_text( g_pCamType, GetCurrentCam()->GetCam()->getPositionObj()->typeStr() ); + + // Set duration + sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getBaseTime() ); + gtk_entry_set_text( GTK_ENTRY(g_pSecondsEntry), buf ); + + sprintf( buf, "%.2f", GetCurrentCam()->GetCam()->getTotalTime() ); + gtk_label_set_text( g_pCurrentTime, "0.00" ); + gtk_label_set_text( g_pTotalTime, buf ); + + gtk_adjustment_set_value( g_pTimeLine, 0.f ); + g_pTimeLine->upper = GetCurrentCam()->GetCam()->getTotalTime() * 1000; + } else { + // Set Name + gtk_entry_set_text( GTK_ENTRY(g_pCamName), "" ); + + // Set type + gtk_label_set_text( g_pCamType, "" ); + + // Set duration + gtk_entry_set_text( GTK_ENTRY(g_pSecondsEntry), "30.00" ); + + gtk_label_set_text( g_pCurrentTime, "0.00" ); + gtk_label_set_text( g_pTotalTime, "30.00" ); + + gtk_adjustment_set_value( g_pTimeLine, 0.f ); + g_pTimeLine->upper = 30000; + } + + // Refresh event list + RefreshEventList(); + } + + RefreshPathListCombo(); + + // start edit mode + g_iActiveTarget = -1; + if( g_pCameraInspectorWnd && GTK_WIDGET_VISIBLE( g_pCameraInspectorWnd ) ) + DoStartEdit( GetCurrentCam() ); + + return TRUE; +} + +enum camEventType { + EVENT_NA = 0x00, + EVENT_WAIT, // + EVENT_TARGETWAIT, // + EVENT_SPEED, // + EVENT_TARGET, // char(name) + EVENT_SNAPTARGET, // + EVENT_FOV, // int(time), int(targetfov) + EVENT_CMD, // + EVENT_TRIGGER, // + EVENT_STOP, // + EVENT_CAMERA, // + EVENT_FADEOUT, // int(time) + EVENT_FADEIN, // int(time) + EVENT_FEATHER, // + EVENT_COUNT +}; + +// { requires parameters, enabled } +const bool camEventFlags[][2] = { + { false, false }, + { false, true }, + { false, false }, + { false, false }, + { true, true }, + { false, false }, + { true, true }, + { false, false }, + { false, false }, + { false, true }, + { true, true }, + { true, true }, + { true, true }, + { false, true }, +}; + +const char *camEventStr[] = { + "n/a", + "Wait", + "Target wait", + "Speed", + "Change Target ", + "Snap Target", + "FOV ", + "Run Script", + "Trigger", + "Stop", + "Change to Camera (or ", + "Fade Out ", + "Fade In ", + "Feather" +}; + +static gint ci_add( GtkWidget *widget, gpointer data ) +{ + GtkWidget *window, *w, *vbox, *vbox2, *hbox, *frame, *parameters; + GtkWidget *eventWidget[EVENT_COUNT]; + int i, ret, loop = 1; + GSList *eventTypeRadio = NULL; +// char buf[128]; + + if( !GetCurrentCam() ) + return TRUE; + + // create the window + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_title( GTK_WINDOW (window), "Add Event" ); + gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( dialog_delete_callback ), NULL ); + gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); + gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pCameraInspectorWnd ) ); + + g_object_set_data (G_OBJECT (window), "loop", &loop); + g_object_set_data (G_OBJECT (window), "ret", &ret); + + gtk_widget_realize (window); + + // fill the window + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + frame = gtk_frame_new( "Type" ); + gtk_box_pack_start( GTK_BOX( hbox ), frame, TRUE, TRUE, 0 ); + gtk_widget_show( frame ); + + vbox2 = gtk_vbox_new( FALSE, 5 ); + gtk_container_add( GTK_CONTAINER( frame ), vbox2 ); + gtk_container_set_border_width( GTK_CONTAINER (vbox2), 5 ); + gtk_widget_show( vbox2 ); + + // -------------------------- // + + for( i = 1; i < EVENT_COUNT; i++ ) { + eventWidget[i] = gtk_radio_button_new_with_label( eventTypeRadio, camEventStr[i] ); + gtk_box_pack_start( GTK_BOX( vbox2 ), eventWidget[i], FALSE, FALSE, 3 ); + gtk_widget_show( eventWidget[i] ); + eventTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( eventWidget[i] ) ); + if( camEventFlags[i][1] == false ) + gtk_widget_set_sensitive (eventWidget[i], FALSE); + } + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Parameters:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + parameters = gtk_entry_new(); + gtk_box_pack_start( GTK_BOX( hbox ), parameters, TRUE, TRUE, 0 ); + gtk_widget_show( parameters ); + + // -------------------------- // + + w = gtk_hseparator_new (); + gtk_box_pack_start (GTK_BOX (vbox), w, FALSE, FALSE, 2); + gtk_widget_show (w); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label ("Ok"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_show (w); + + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + + w = gtk_button_new_with_label ("Cancel"); + gtk_box_pack_start (GTK_BOX (hbox), w, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (w), "clicked", GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_show (w); + ret = IDCANCEL; + + // -------------------------- // + + gtk_window_set_position(GTK_WINDOW(window),GTK_WIN_POS_CENTER); + gtk_widget_show (window); + gtk_grab_add (window); + + bool dialogError = TRUE; + while (dialogError) { + loop = 1; + while (loop) + gtk_main_iteration (); + + dialogError = FALSE; + + if( ret == IDOK ) { + const char *str = gtk_entry_get_text( GTK_ENTRY(parameters) ); + + if( !camEventFlags[i][0] || ( str && str[0] ) ) { + int type = 0; +// GList *li; + + for( type = 1; type < EVENT_COUNT; type++ ) { + if( gtk_toggle_button_get_active( (GtkToggleButton*)eventWidget[type] ) ) + break; + } + + // Add the event + GetCurrentCam()->GetCam()->addEvent( static_cast(type), str, (long)(g_pTimeLine->value) ); + + // Refresh event list + RefreshEventList(); + } else { + dialogError = TRUE; + } + } + } + + gtk_grab_remove (window); + gtk_widget_destroy (window); + + return TRUE; +} + +static gint ci_del( GtkWidget *widget, gpointer data ) +{ + // TODO: add support to splines lib + if( GetCurrentCam() && GTK_CLIST(g_pEventsList)->focus_row >= 0 ) { + GetCurrentCam()->GetCam()->removeEvent( GTK_CLIST(g_pEventsList)->focus_row ); + // Refresh event list + RefreshEventList(); + } + + return TRUE; +} + +static gint ci_timeline_changed( GtkAdjustment *adjustment ) +{ + char buf[128]; + + sprintf( buf, "%.2f", adjustment->value / 1000.f ); + gtk_label_set_text( g_pCurrentTime, buf ); + + // FIXME: this will never work completely perfect. Startcamera calls buildcamera, which sets all events to 'nottriggered'. + // So if you have a wait at the end of the path, this will go to nontriggered immediately when you go over it and the camera + // will have no idea where on the track it should be. + if( GetCurrentCam() && gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(g_pTrackCamera) ) ) { + float fov; + vec3_t origin = { 0.0f, 0.0f, 0.0f }, dir = { 0.0f, 0.0f, 0.0f}, angles; + + GetCurrentCam()->GetCam()->startCamera( 0 ); + + GetCurrentCam()->GetCam()->getCameraInfo( (long)(adjustment->value), &origin[0], &dir[0], &fov ); + VectorSet( angles, asin (dir[2])*180/3.14159, atan2 (dir[1], dir[0])*180/3.14159, 0 ); + g_CameraTable.m_pfnSetCamera( origin, angles ); + } + + return TRUE; +} + +GtkWidget *CreateCameraInspectorDialog( void ) +{ + GtkWidget *window, *w, *vbox, *hbox, *table, *frame; + + // create the window + window = gtk_window_new( GTK_WINDOW_TOPLEVEL ); + gtk_window_set_title( GTK_WINDOW (window), "Camera Inspector" ); + gtk_signal_connect( GTK_OBJECT (window), "delete_event", GTK_SIGNAL_FUNC( ci_close ), NULL ); + gtk_signal_connect( GTK_OBJECT (window), "expose_event", GTK_SIGNAL_FUNC( ci_expose ), NULL ); + // gtk_signal_connect( GTK_OBJECT (window), "destroy", GTK_SIGNAL_FUNC( gtk_widget_destroy ), NULL ); + gtk_window_set_transient_for( GTK_WINDOW( window ), GTK_WINDOW( g_pRadiantWnd ) ); + + // don't use show, as you don't want to have it displayed on startup ;-) + gtk_widget_realize( window ); + + // fill the window + + // the table + // -------------------------- // + + table = gtk_table_new( 3, 2, FALSE ); + gtk_widget_show( table ); + gtk_container_add( GTK_CONTAINER( window ), table ); + gtk_container_set_border_width( GTK_CONTAINER( table ), 5 ); + gtk_table_set_row_spacings( GTK_TABLE( table ), 5 ); + gtk_table_set_col_spacings( GTK_TABLE( table ), 5 ); + + // the properties column + // -------------------------- // + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_widget_show( vbox ); + gtk_table_attach( GTK_TABLE( table ), vbox, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0 ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "File:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + g_pCamListCombo = gtk_combo_new(); + gtk_box_pack_start (GTK_BOX( hbox ), g_pCamListCombo, TRUE, TRUE, 0); + gtk_widget_show( g_pCamListCombo ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Name:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + g_pCamName = gtk_entry_new(); + gtk_box_pack_start( GTK_BOX( hbox ), g_pCamName, FALSE, FALSE, 0 ); + gtk_widget_show( g_pCamName ); + + w = gtk_label_new( "Type: " ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + w = gtk_label_new( "" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + g_pCamType = GTK_LABEL( w ); + + RefreshCamListCombo(); + + gtk_entry_set_editable( GTK_ENTRY( GTK_COMBO(g_pCamListCombo)->entry ), FALSE ); + gtk_signal_connect( GTK_OBJECT(GTK_COMBO(g_pCamListCombo)->entry), "changed", GTK_SIGNAL_FUNC( ci_camlist_changed ), NULL ); + + // -------------------------- // + + frame = gtk_frame_new( "Path and Target editing" ); + gtk_widget_show( frame ); + gtk_table_attach( GTK_TABLE( table ), frame, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0 ); + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_container_add( GTK_CONTAINER( frame ), vbox ); + gtk_container_set_border_width( GTK_CONTAINER (vbox), 5 ); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Edit:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + g_pPathListCombo = gtk_combo_new(); + gtk_box_pack_start (GTK_BOX( hbox ), g_pPathListCombo, TRUE, TRUE, 0); + gtk_widget_show( g_pPathListCombo ); + + RefreshPathListCombo(); + + gtk_entry_set_editable( GTK_ENTRY( GTK_COMBO(g_pPathListCombo)->entry ), FALSE ); + gtk_signal_connect( GTK_OBJECT(GTK_COMBO(g_pPathListCombo)->entry), "changed", GTK_SIGNAL_FUNC( ci_pathlist_changed ), NULL ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + g_pEditModeEditRadioButton = gtk_radio_button_new_with_label( g_pEditTypeRadio, "Edit Points" ); + gtk_box_pack_start( GTK_BOX( hbox ), g_pEditModeEditRadioButton, FALSE, FALSE, 3 ); + gtk_widget_show( g_pEditModeEditRadioButton ); + g_pEditTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( g_pEditModeEditRadioButton ) ); + + gtk_signal_connect( GTK_OBJECT( g_pEditModeEditRadioButton ), "clicked", GTK_SIGNAL_FUNC( ci_editmode_edit ), NULL ); + + g_pEditModeAddRadioButton = gtk_radio_button_new_with_label( g_pEditTypeRadio, "Add Points" ); + gtk_box_pack_start( GTK_BOX( hbox ), g_pEditModeAddRadioButton, FALSE, FALSE, 3 ); + gtk_widget_show( g_pEditModeAddRadioButton ); + g_pEditTypeRadio = gtk_radio_button_group( GTK_RADIO_BUTTON( g_pEditModeAddRadioButton ) ); + + gtk_signal_connect( GTK_OBJECT( g_pEditModeAddRadioButton ), "clicked", GTK_SIGNAL_FUNC( ci_editmode_add ), NULL ); + + // see if we should use a different default + if( g_iEditMode == 1 ) { + // Go to editmode Add + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(g_pEditModeAddRadioButton), TRUE ); + } + + w = gtk_label_new( "Type: " ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + w = gtk_label_new( "" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + g_pPathType = GTK_LABEL( w ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label( "Rename..." ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_rename ), NULL ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Add Target..." ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_add_target ), NULL ); + gtk_widget_show( w ); + + // not available in splines library + /*w = gtk_button_new_with_label( "Delete Selected" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_delete_selected ), NULL ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Select All" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, TRUE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_select_all ), NULL ); + gtk_widget_show( w );*/ + + // -------------------------- // + + frame = gtk_frame_new( "Time" ); + gtk_widget_show( frame ); + gtk_table_attach( GTK_TABLE( table ), frame, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0 ); + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_container_add( GTK_CONTAINER( frame ), vbox ); + gtk_container_set_border_width( GTK_CONTAINER (vbox), 5 ); + gtk_widget_show( vbox ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Length (seconds):" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + g_pSecondsEntry = gtk_entry_new(); + gtk_box_pack_start( GTK_BOX( hbox ), g_pSecondsEntry, FALSE, FALSE, 0 ); + gtk_widget_show( g_pSecondsEntry ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Current Time: " ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + w = gtk_label_new( "0.00" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + g_pCurrentTime = GTK_LABEL( w ); + + w = gtk_label_new( " of " ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + w = gtk_label_new( "0.00" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + g_pTotalTime = GTK_LABEL( w ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + g_pTimeLine = GTK_ADJUSTMENT( gtk_adjustment_new( 0, 0, 30000, 100, 250, 0 ) ); + gtk_signal_connect( GTK_OBJECT(g_pTimeLine), "value_changed", GTK_SIGNAL_FUNC( ci_timeline_changed ), NULL ); + w = gtk_hscale_new( g_pTimeLine ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); + gtk_widget_show( w ); + gtk_scale_set_draw_value( GTK_SCALE( w ), FALSE ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + g_pTrackCamera = gtk_check_button_new_with_label( "Track Camera" ); + gtk_box_pack_start( GTK_BOX( hbox ), g_pTrackCamera, FALSE, FALSE, 0 ); + gtk_widget_show( g_pTrackCamera ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_label_new( "Events:" ); + gtk_box_pack_start( GTK_BOX( hbox ), w, FALSE, FALSE, 0 ); + gtk_widget_show( w ); + + // -------------------------- // + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, FALSE, FALSE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_scrolled_window_new( NULL, NULL ); + gtk_widget_set_usize( w, 0, 150 ); + gtk_scrolled_window_set_policy( GTK_SCROLLED_WINDOW( w ), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC ); + gtk_box_pack_start( GTK_BOX( hbox ), w, TRUE, TRUE, 0 ); + gtk_widget_show( w ); + + g_pEventsList = gtk_clist_new( 3 ); + gtk_container_add( GTK_CONTAINER(w), g_pEventsList); + //gtk_signal_connect( GTK_OBJECT(g_pEventsList), "select_row", GTK_SIGNAL_FUNC (proplist_select_row), NULL); + gtk_clist_set_selection_mode( GTK_CLIST(g_pEventsList), GTK_SELECTION_BROWSE ); + gtk_clist_column_titles_hide( GTK_CLIST(g_pEventsList) ); + gtk_clist_set_column_auto_resize( GTK_CLIST(g_pEventsList), 0, TRUE ); + gtk_clist_set_column_auto_resize( GTK_CLIST(g_pEventsList), 1, TRUE ); + gtk_clist_set_column_auto_resize( GTK_CLIST(g_pEventsList), 2, TRUE ); + gtk_widget_show( g_pEventsList ); + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( hbox ), vbox, FALSE, FALSE, 0 ); + gtk_widget_show( vbox ); + + w = gtk_button_new_with_label( "Add..." ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_add ), NULL ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Del" ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_del ), NULL ); + gtk_widget_show( w ); + + // -------------------------- // + + /*/ + | + | + | + */ + + // the buttons column + // -------------------------- // + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_widget_show( vbox ); + gtk_table_attach( GTK_TABLE( table ), vbox, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0 ); + + w = gtk_button_new_with_label( "New..." ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_new ), NULL ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Load..." ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_load ), NULL ); + gtk_widget_show( w ); + + // -------------------------- // + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_widget_show( vbox ); + gtk_table_attach( GTK_TABLE( table ), vbox, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0 ); + + w = gtk_button_new_with_label( "Save..." ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_save ), NULL ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Unload" ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_unload ), NULL ); + gtk_widget_show( w ); + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, TRUE, TRUE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label( "Apply" ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_apply ), NULL ); + gtk_widget_show( w ); + + w = gtk_button_new_with_label( "Preview" ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_preview ), NULL ); + gtk_widget_show( w ); + + // -------------------------- // + + vbox = gtk_vbox_new( FALSE, 5 ); + gtk_widget_show( vbox ); + gtk_table_attach( GTK_TABLE( table ), vbox, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0 ); + + hbox = gtk_hbox_new( FALSE, 5 ); + gtk_box_pack_start( GTK_BOX( vbox ), hbox, TRUE, TRUE, 0 ); + gtk_widget_show( hbox ); + + w = gtk_button_new_with_label( "Close" ); + gtk_box_pack_start( GTK_BOX( vbox ), w, FALSE, FALSE, 0); + gtk_signal_connect( GTK_OBJECT( w ), "clicked", GTK_SIGNAL_FUNC( ci_close ), NULL ); + GTK_WIDGET_SET_FLAGS( w, GTK_CAN_DEFAULT ); + gtk_widget_grab_default( w ); + gtk_widget_show( w ); + + // -------------------------- // + + return window; +} diff --git a/contrib/camera/dialogs.h b/contrib/camera/dialogs.h new file mode 100644 index 00000000..5ba86c5a --- /dev/null +++ b/contrib/camera/dialogs.h @@ -0,0 +1,37 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +struct TwinWidget { + GtkWidget* one; + GtkWidget* two; +}; + +void dialog_button_callback (GtkWidget *widget, gpointer data); +gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data); +//void dialog_button_callback_settex (GtkWidget *widget, gpointer data); + +void RefreshCamListCombo( void ); +GtkWidget *CreateCameraInspectorDialog( void ); diff --git a/contrib/camera/dialogs_common.cpp b/contrib/camera/dialogs_common.cpp new file mode 100644 index 00000000..bebf5976 --- /dev/null +++ b/contrib/camera/dialogs_common.cpp @@ -0,0 +1,51 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} diff --git a/contrib/camera/funchandlers.cpp b/contrib/camera/funchandlers.cpp new file mode 100644 index 00000000..97e861eb --- /dev/null +++ b/contrib/camera/funchandlers.cpp @@ -0,0 +1,272 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +extern GtkWidget *g_pEditModeAddRadioButton; + +char* Q_realpath(const char *path, char *resolved_path, size_t size) +{ +#if defined (__linux__) || defined (__APPLE__) + return realpath(path, resolved_path); +#else + return _fullpath(resolved_path, path, size); +#endif +} + +static void DoNewCamera( idCameraPosition::positionType type ) +{ + CCamera *cam = AllocCam(); + + if( cam ) { + char buf[128]; + sprintf( buf, "camera%i", cam->GetCamNum() ); + + cam->GetCam()->startNewCamera( type ); + cam->GetCam()->setName( buf ); + cam->GetCam()->buildCamera(); + + sprintf( buf, "Unsaved Camera %i", cam->GetCamNum() ); + cam->SetFileName( buf, false ); + + SetCurrentCam( cam ); + RefreshCamListCombo(); + + // Go to editmode Add + gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(g_pEditModeAddRadioButton), TRUE ); + + // Show the camera inspector + DoCameraInspector(); + + // Start edit mode (if not initiated by DoCameraInspector) + if( !g_bEditOn ) + DoStartEdit( GetCurrentCam() ); + } else { + g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, "No free cameras available.", "Create Camera Error", MB_OK, NULL ); + } +} + +void DoNewFixedCamera() +{ + DoNewCamera( idCameraPosition::FIXED ); +} + +void DoNewInterpolatedCamera() +{ + DoNewCamera( idCameraPosition::INTERPOLATED ); +} + +void DoNewSplineCamera() +{ + DoNewCamera( idCameraPosition::SPLINE ); +} + +void DoCameraInspector() +{ + gtk_widget_show( g_pCameraInspectorWnd ); +} + +void DoPreviewCamera() +{ + if( GetCurrentCam() ) { + g_iPreviewRunning = 1; + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } +} + +void DoLoadCamera() +{ + char basepath[PATH_MAX]; + + if( firstCam && firstCam->HasBeenSaved() ) + ExtractFilePath( firstCam->GetFileName(), basepath ); + else + strcpy( basepath, g_FuncTable.m_pfnGetGamePath() ); + + const gchar *filename = g_FuncTable.m_pfnFileDialog( (GtkWidget *)g_pRadiantWnd, TRUE, "Open Camera File", basepath, "camera"); + + if( filename ) + { + CCamera *cam = AllocCam(); + char fullpathtofile[PATH_MAX]; + + if( cam ) { + Q_realpath(filename, fullpathtofile, PATH_MAX); + + // see if this camera file was already loaded + CCamera *checkCam = firstCam->GetNext(); // not the first one as we just allocated it + while( checkCam ) { + if( !strcmp( fullpathtofile, checkCam->GetFileName() ) ) { + char error[PATH_MAX+64]; + FreeCam( cam ); + sprintf( error, "Camera file \'%s\' is already loaded", fullpathtofile ); + g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, error, "Load error", MB_OK, NULL ); + //g_free( filename ); + return; + } + checkCam = checkCam->GetNext(); + } + + if( loadCamera( cam->GetCamNum(), fullpathtofile ) ) { + cam->GetCam()->buildCamera(); + cam->SetFileName( filename, true ); + SetCurrentCam( cam ); + RefreshCamListCombo(); + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } else { + char error[PATH_MAX+64]; + FreeCam( cam ); + sprintf( error, "An error occured during the loading of \'%s\'", fullpathtofile ); + g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, error, "Load error", MB_OK, NULL ); + } + + //g_free( filename ); + } else { + g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, "No free camera slots available", "Load error", MB_OK, NULL ); + } + } +} + +void DoSaveCamera() { + char basepath[PATH_MAX]; + + if( !GetCurrentCam() ) + return; + + if( GetCurrentCam()->GetFileName()[0] ) + ExtractFilePath( GetCurrentCam()->GetFileName(), basepath ); + else + strcpy( basepath, g_FuncTable.m_pfnGetGamePath() ); + + const gchar *filename = g_FuncTable.m_pfnFileDialog( (void *)g_pRadiantWnd, FALSE, "Save Camera File", basepath, "camera"); + + if( filename ) { + char fullpathtofile[PATH_MAX + 8]; + + Q_realpath(filename, fullpathtofile, PATH_MAX); + + // File dialog from windows (and maybe the gtk one from radiant) doesn't handle default extensions properly. + // Add extension and check again if file exists + if( strcmp( fullpathtofile + (strlen(fullpathtofile) - 7), ".camera" ) ) { + strcat( fullpathtofile, ".camera" ); + + if( FileExists( fullpathtofile ) ) { + if ( g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, "File already exists.\nOverwrite?", "Save Camera File", MB_YESNO, NULL ) == IDNO ) { + return; + } + } + } + + // see if this camera file was already loaded + CCamera *checkCam = firstCam; + while( checkCam ) { + if( checkCam == GetCurrentCam() ) { + checkCam = checkCam->GetNext(); + if( !checkCam ) // we only have one camera file opened so no need to check further + break; + } else if( !strcmp( fullpathtofile, checkCam->GetFileName() ) ) { + char error[PATH_MAX+64]; + sprintf( error, "Camera file \'%s\' is currently loaded by GtkRadiant.\nPlease select a different filename.", fullpathtofile ); + g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, error, "Save error", MB_OK, NULL ); + return; + } + checkCam = checkCam->GetNext(); + } + + // FIXME: check for existing directory + + GetCurrentCam()->GetCam()->save( fullpathtofile ); + GetCurrentCam()->SetFileName( fullpathtofile, true ); + RefreshCamListCombo(); + } +} + +void DoUnloadCamera() { + if( !GetCurrentCam() ) + return; + + if( !GetCurrentCam()->HasBeenSaved() ) { + char buf[PATH_MAX+64]; + sprintf( buf, "Do you want to save the changes for camera '%s'?", GetCurrentCam()->GetCam()->getName() ); + if ( g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, buf, "Warning", MB_YESNO, NULL ) == IDYES ) { + DoSaveCamera(); + } + } else if( GetCurrentCam()->HasBeenSaved() == 2 ) { + char buf[PATH_MAX+64]; + sprintf( buf, "Do you want to save the changes made to camera file '%s'?", GetCurrentCam()->GetFileName() ); + if( g_FuncTable.m_pfnMessageBox( (GtkWidget *)g_pRadiantWnd, buf, "Warning", MB_YESNO, NULL ) == IDYES ) { + DoSaveCamera(); + } + } + + if( g_pCurrentEditCam ) { + DoStopEdit(); + g_pCurrentEditCam = NULL; + } + + FreeCam( GetCurrentCam() ); + SetCurrentCam( NULL ); + RefreshCamListCombo(); +} + +CCamera *g_pCurrentEditCam = NULL; + +void DoStartEdit( CCamera *cam ) { + if( g_pCurrentEditCam ) { + DoStopEdit(); + g_pCurrentEditCam = NULL; + } + + if( cam ) { + g_bEditOn = true; + + if( !Listener ) + Listener = new CListener; + + cam->GetCam()->startEdit( g_iActiveTarget < 0 ? true : false ); + + g_pCurrentEditCam = cam; + + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } +} + +void DoStopEdit( void ) { + g_bEditOn = false; + + if( Listener ) { + delete Listener; + Listener = NULL; + } + + if( g_pCurrentEditCam ) { + // stop editing on the current cam + g_pCurrentEditCam->GetCam()->stopEdit(); + g_pCurrentEditCam = NULL; + + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } +} diff --git a/contrib/camera/funchandlers.h b/contrib/camera/funchandlers.h new file mode 100644 index 00000000..a9419062 --- /dev/null +++ b/contrib/camera/funchandlers.h @@ -0,0 +1,37 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +void DoNewFixedCamera(); +void DoNewInterpolatedCamera(); +void DoNewSplineCamera(); +void DoCameraInspector(); +void DoPreviewCamera(); +void DoLoadCamera(); +void DoSaveCamera(); +void DoUnloadCamera(); +void DoStartEdit( CCamera *cam ); +void DoStopEdit( void ); + diff --git a/contrib/camera/listener.cpp b/contrib/camera/listener.cpp new file mode 100644 index 00000000..c21e8715 --- /dev/null +++ b/contrib/camera/listener.cpp @@ -0,0 +1,234 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +CListener::CListener() +{ + refCount = 1; + + m_bHooked = FALSE; + + m_bLeftMBPressed = m_bRightMBPressed = m_bMiddleMBPressed = false; + + oldValid = false; + + Register(); +} + +CListener::~CListener() +{ + UnRegister(); +} + +void CListener::Register() +{ + g_UITable.m_pfnHookWindow( this ); + g_pXYWndWrapper = g_UITable.m_pfnGetXYWndWrapper(); + m_bHooked = TRUE; +} + +void CListener::UnRegister() +{ + if(m_bHooked) + { + g_UITable.m_pfnUnHookWindow( this ); + g_pXYWndWrapper= NULL; + m_bHooked = FALSE; + } +} + +bool CListener::OnMouseMove( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + if( m_bLeftMBPressed && oldValid && g_iEditMode == 0 ) { + vec3_t click, delta; + + g_pXYWndWrapper->SnapToGrid( (int)x, (int)y, click ); + + switch( m_vt ) { + case XY: + VectorSet( delta, click[0] - old_x, click[1] - old_y, 0 ); + old_x = click[0]; old_y = click[1]; + break; + case XZ: + VectorSet( delta, click[0] - old_x, 0, click[2] - old_y ); + old_x = click[0]; old_y = click[2]; + break; + case YZ: + VectorSet( delta, 0, click[1] - old_x, click[2] - old_y ); + old_x = click[1]; old_y = click[2]; + break; + } + + if( g_iActiveTarget < 0 ) + GetCurrentCam()->GetCam()->getPositionObj()->updateSelection( delta[0], delta[1], delta[2] ); + else + GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->updateSelection( delta[0], delta[1], delta[2] ); + + GetCurrentCam()->HasBeenModified(); + + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + + return true; + } + + return false; +} + +bool CListener::OnLButtonDown( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + m_bLeftMBPressed = true; + oldValid = true; + + vec3_t org, delta; + + g_pXYWndWrapper->SnapToGrid( (int)x, (int)y, org ); + + switch( m_vt ) { + case XY: + old_x = org[0]; old_y = org[1]; org[2] = 64*1024; + VectorSet( delta, 0, 0, -1 ); + break; + case XZ: + old_x = org[0]; old_y = org[2]; org[1] = 64*1024; + VectorSet( delta, 0, -1, 0 ); + break; + case YZ: + old_x = org[1]; old_y = org[2]; org[0] = 64*1024; + VectorSet( delta, -1, 0, 0 ); + break; + } + + if( g_iEditMode == 0 ) { + if( g_iActiveTarget < 0 ) + GetCurrentCam()->GetCam()->getPositionObj()->selectPointByRay( org[0], org[1], org[2], delta[0], delta[1], delta[2], true ); + else + GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->selectPointByRay( org[0], org[1], org[2], delta[0], delta[1], delta[2], true ); + } else if( g_iEditMode == 1 ) { + idVec3 *lastcoord; + idCameraPosition *camera; + + if( g_iActiveTarget < 0 ) { + camera = GetCurrentCam()->GetCam()->getPositionObj(); + } else { + camera = GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget); + } + + if( camera->numPoints() ) { + lastcoord = camera->getPoint( camera->numPoints() -1 ); + switch( m_vt ) { + case XY: + camera->addPoint( org[0], org[1], lastcoord->z ); + break; + case XZ: + camera->addPoint( org[0], lastcoord->y, org[2] ); + break; + case YZ: + camera->addPoint( lastcoord->x, org[1], org[2] ); + break; + } + } else { + switch( m_vt ) { + case XY: + camera->addPoint( org[0], org[1], 0 ); + break; + case XZ: + camera->addPoint( org[0], 0, org[2] ); + break; + case YZ: + camera->addPoint( 0, org[1], org[2] ); + break; + } + } + + GetCurrentCam()->HasBeenModified(); + } + + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + + return true; + + //return false; +} + +bool CListener::OnLButtonUp( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + m_bLeftMBPressed = false; + oldValid = false; + + if( g_iEditMode == 0 ) { + if( g_iActiveTarget < 0 ) + GetCurrentCam()->GetCam()->getPositionObj()->deselectAll(); + else + GetCurrentCam()->GetCam()->getActiveTarget(g_iActiveTarget)->deselectAll(); + + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } + + return false; +} + +bool CListener::OnRButtonDown( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + m_bRightMBPressed = true; + + return false; +} + +bool CListener::OnRButtonUp( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + m_bRightMBPressed = false; + + return false; +} + +bool CListener::OnMButtonDown( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + m_bMiddleMBPressed = true; + + return false; +} + +bool CListener::OnMButtonUp( guint32 nFlags, gdouble x, gdouble y ) +{ + SetViewType( g_pXYWndWrapper->GetViewType() ); + + m_bMiddleMBPressed = false; + + return false; +} diff --git a/contrib/camera/listener.h b/contrib/camera/listener.h new file mode 100644 index 00000000..13e14b71 --- /dev/null +++ b/contrib/camera/listener.h @@ -0,0 +1,64 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +class CListener : public IWindowListener +{ +public: + bool OnMouseMove(guint32 nFlags, gdouble x, gdouble y); + bool OnLButtonDown(guint32 nFlags, gdouble x, gdouble y); + bool OnMButtonDown(guint32 nFlags, gdouble x, gdouble y); + bool OnRButtonDown(guint32 nFlags, gdouble x, gdouble y); + bool OnLButtonUp(guint32 nFlags, gdouble x, gdouble y); + bool OnMButtonUp(guint32 nFlags, gdouble x, gdouble y); + bool OnRButtonUp(guint32 nFlags, gdouble x, gdouble y); + bool OnKeyPressed(char *s) { return false; } + bool Paint() { return true; } + void Close() { } + + void UnRegister(); + void Register(); + CListener(); + virtual ~CListener(); + + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + + void SetViewType( VIEWTYPE vt ) { if( m_vt != vt ) oldValid = false; m_vt = vt; } + +private: + IXYWndWrapper *g_pXYWndWrapper; + + bool m_bHooked; + int refCount; + VIEWTYPE m_vt; + + // mouse button status + bool m_bLeftMBPressed, m_bRightMBPressed, m_bMiddleMBPressed; + + // old mouse coordinates + bool oldValid; + gdouble old_x, old_y; +}; diff --git a/contrib/camera/misc.cpp b/contrib/camera/misc.cpp new file mode 100644 index 00000000..8f45d9b3 --- /dev/null +++ b/contrib/camera/misc.cpp @@ -0,0 +1,243 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +void Sys_ERROR( char* text, ... ) +{ + va_list argptr; + char buf[32768]; + + va_start (argptr,text); + vsprintf (buf, text,argptr); + va_end (argptr); + + Sys_Printf("Camera::ERROR->%s", buf); +} + +char* UnixToDosPath( char* path ) +{ +#ifndef _WIN32 + return path; +#else + for(char* p = path; *p; p++) + { + if(*p == '/') + *p = '\\'; + } + return path; +#endif +} + +void ExtractFilePath( const char *path, char *dest ) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' && *(src-1) != '\\') + src--; + + memcpy (dest, path, src-path); + dest[src-path] = 0; +} + +const char* ExtractFilename( const char* path ) +{ + char* p = (char *)strrchr(path, '/'); + if(!p) + { + p = (char *)strrchr(path, '\\'); + + if(!p) + return path; + } + return ++p; +} + +int Q_stricmp (const char *s1, const char *s2) { + return stricmp( s1, s2 ); +} + +/* +============== +FileExists +============== +*/ +bool FileExists (const char *filename) +{ + FILE *f; + + f = fopen( filename, "r" ); + if( !f ) + return false; + fclose( f ); + return true; +} + +// +// command buffer +// empty wrappers, don't really use them here +// +void Cbuf_AddText( const char *text ) {}; +void Cbuf_Execute (void) {}; + +// +// Common +// + +void CDECL Com_Error( int level, const char *error, ... ) +{ + va_list argptr; + char buf[32768]; + + va_start (argptr,error); + vsprintf (buf, error,argptr); + va_end (argptr); + + Sys_Printf("Camera::ERROR->%s", buf); +} + +void CDECL Com_Printf( const char* msg, ... ) +{ + va_list argptr; + char buf[32768]; + + va_start (argptr,msg); + vsprintf (buf, msg,argptr); + va_end (argptr); + + Sys_Printf("Camera::%s", buf); +} + +void CDECL Com_DPrintf( const char* msg, ... ) +{ +#ifdef _DEBUG + va_list argptr; + char buf[32768]; + + va_start (argptr,msg); + vsprintf (buf, msg,argptr); + va_end (argptr); + + Sys_Printf("Camera::%s", buf); +#endif +} + +void *Com_Allocate( int bytes ) { + return( malloc( bytes ) ); +} + +void Com_Dealloc( void *ptr ) { + free( ptr ); +} + +// +// Filesystem +// + +#ifdef _WIN32 + #pragma warning(disable : 4311) + #pragma warning(disable : 4312) +#endif + +int FS_Read( void *buffer, int len, fileHandle_t f ) { + return fread( buffer, len, 1, (FILE *)f ); +} + +int FS_Write( const void *buffer, int len, fileHandle_t h ) { + return fwrite( buffer, len, 1, (FILE *)h ); +} + +int FS_ReadFile( const char *qpath, void **buffer ) { + fileHandle_t h; + byte* buf; + int len; + + buf = NULL; + + len = FS_FOpenFileRead( qpath, &h, qfalse ); + + if( h == 0 ) { + if ( buffer ) { + *buffer = NULL; + } + + return -1; + } + + buf = (byte *)Com_Allocate( len + 1 ); + + *buffer = buf; + + FS_Read (buf, len, h); + + buf[len] = 0; + FS_FCloseFile( h ); + + return len; +} + +void FS_FreeFile( void *buffer ) { + Com_Dealloc( buffer ); +} + +int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueFILE ) { + FILE *fh; + long len; + + fh = fopen( filename, "rb" ); + *file = *(fileHandle_t *)&fh; + + if( file ) + { + fseek (fh, 0, SEEK_END); + len = ftell (fh); + rewind (fh); + return len; + } + else + return -1; +} + +fileHandle_t FS_FOpenFileWrite( const char *filename ) { + FILE *fh; + fileHandle_t f; + + memset( &f, 0, sizeof(f) ); + + fh = fopen( filename, "wb" ); + + f = (fileHandle_t)fh; + return f; +} + +void FS_FCloseFile( fileHandle_t f ) { + fclose( (FILE *)f ); +} diff --git a/contrib/camera/misc.h b/contrib/camera/misc.h new file mode 100644 index 00000000..6c56dc73 --- /dev/null +++ b/contrib/camera/misc.h @@ -0,0 +1,91 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +void Sys_ERROR( char* text, ... ); +char* UnixToDosPath( char* path ); +void ExtractFilePath( const char *path, char *dest ); +const char* ExtractFilename( const char* path ); +bool FileExists (const char *filename); +int Q_stricmp (const char *s1, const char *s2); + +typedef int fileHandle_t; + +#define qfalse false +#define qtrue true + +extern "C" { +// command buffer +void Cbuf_AddText( const char *text ); +void Cbuf_Execute (void); + +// common +#ifndef CDECL +#ifdef _WIN32 + #define CDECL __cdecl +#else + #define CDECL +#endif +#endif + +void CDECL Com_Error( int level, const char *error, ... ); +void CDECL Com_Printf( const char *msg, ... ); +void CDECL Com_DPrintf( const char *msg, ... ); +void *Com_Allocate( int bytes ); +void Com_Dealloc( void *ptr ); + +// filesystem +int FS_Read( void *buffer, int len, fileHandle_t f ); +int FS_Write( const void *buffer, int len, fileHandle_t h ); +int FS_ReadFile( const char *qpath, void **buffer ); +void FS_FreeFile( void *buffer ); +int FS_FOpenFileRead( const char *filename, fileHandle_t *file, qboolean uniqueFILE ); +fileHandle_t FS_FOpenFileWrite( const char *filename ); +void FS_FCloseFile( fileHandle_t f ); +} + +// vectors +#define DotProduct(a,b) ((a)[0]*(b)[0]+(a)[1]*(b)[1]+(a)[2]*(b)[2]) +#define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2]) +#define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2]) +#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2]) + +#define VectorScale(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s)) +#define VectorMA(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s)) +#define CrossProduct(a,b,c) ((c)[0]=(a)[1]*(b)[2]-(a)[2]*(b)[1],(c)[1]=(a)[2]*(b)[0]-(a)[0]*(b)[2],(c)[2]=(a)[0]*(b)[1]-(a)[1]*(b)[0]) + +#define DotProduct4(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]+(x)[3]*(y)[3]) +#define VectorSubtract4(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2],(c)[3]=(a)[3]-(b)[3]) +#define VectorAdd4(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2],(c)[3]=(a)[3]+(b)[3]) +#define VectorCopy4(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) +#define VectorScale4(v, s, o) ((o)[0]=(v)[0]*(s),(o)[1]=(v)[1]*(s),(o)[2]=(v)[2]*(s),(o)[3]=(v)[3]*(s)) +#define VectorMA4(v, s, b, o) ((o)[0]=(v)[0]+(b)[0]*(s),(o)[1]=(v)[1]+(b)[1]*(s),(o)[2]=(v)[2]+(b)[2]*(s),(o)[3]=(v)[3]+(b)[3]*(s)) + +#define VectorClear(a) ((a)[0]=(a)[1]=(a)[2]=0) +#define VectorNegate(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2]) +#define VectorSet(v, x, y, z) ((v)[0]=(x), (v)[1]=(y), (v)[2]=(z)) +#define Vector4Copy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2],(b)[3]=(a)[3]) + +#define SnapVector(v) {v[0]=(int)v[0];v[1]=(int)v[1];v[2]=(int)v[2];} diff --git a/contrib/camera/renderer.cpp b/contrib/camera/renderer.cpp new file mode 100644 index 00000000..9f44a37d --- /dev/null +++ b/contrib/camera/renderer.cpp @@ -0,0 +1,183 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#include "camera.h" + +CRenderer::CRenderer() { + + refCount = 1; + + m_bHooked = FALSE; + + Register(); + Initialize(); +} + +CRenderer::~CRenderer() { + if( m_bHooked ) + UnRegister(); +} + +void CRenderer::Register() { + g_QglTable.m_pfnHookGL2DWindow( this ); + g_QglTable.m_pfnHookGL3DWindow( this ); + m_bHooked = TRUE; +} + +void CRenderer::UnRegister() { + if( g_QglTable.m_nSize ) { + g_QglTable.m_pfnUnHookGL2DWindow( this ); + g_QglTable.m_pfnUnHookGL3DWindow( this ); + } + m_bHooked = FALSE; +} + +void CRenderer::Initialize() { + +} + +void CRenderer::Draw2D( VIEWTYPE vt ) { + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + g_QglTable.m_pfn_qglPushMatrix(); + + switch(vt) + { + case XY: + break; + case XZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + break; + case YZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + g_QglTable.m_pfn_qglRotatef(270.0f, 0.0f, 0.0f, 1.0f); + break; + } + + CCamera *cam = firstCam; + while( cam ) { + cam->GetCam()->draw( ((Listener && cam == g_pCurrentEditCam) ? true : false) ); + cam = cam->GetNext(); + } + + g_QglTable.m_pfn_qglPopMatrix(); + g_QglTable.m_pfn_qglPopAttrib(); +} + +void CRenderer::Draw3D() { + // FIXME: really need a mainloop callback from the editor core + static long start; + static float cycle; + static long msecs; + static long current; + + if( g_iPreviewRunning ) { + if( g_iPreviewRunning == 1 ) { + start = g_FuncTable.m_pfnQGetTickCount(); + GetCurrentCam()->GetCam()->startCamera( start ); + cycle = GetCurrentCam()->GetCam()->getTotalTime(); + msecs = (long)(cycle * 1000); + current = start; + g_iPreviewRunning = 2; + } + + if( current < start + msecs ) { + float fov; + vec3_t origin = {0.0f, 0.0f, 0.0f}, dir = {0.0f, 0.0f, 0.0f}, angles; + + GetCurrentCam()->GetCam()->getCameraInfo( current, &origin[0], &dir[0], &fov ); + VectorSet( angles, asin (dir[2])*180/3.14159, atan2 (dir[1], dir[0])*180/3.14159, 0 ); + g_CameraTable.m_pfnSetCamera( origin, angles ); + current = g_FuncTable.m_pfnQGetTickCount(); + } else { + g_iPreviewRunning = 0; + GetCurrentCam()->GetCam()->setRunning( false ); + g_FuncTable.m_pfnSysUpdateWindows( W_XY_OVERLAY | W_CAMERA ); + } + } + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + CCamera *cam = firstCam; + while( cam ) { + cam->GetCam()->draw( ((Listener && cam == g_pCurrentEditCam) ? true : false) ); + cam = cam->GetNext(); + } + + if( g_iPreviewRunning ) { + int x, y, width, height, i; + float degInRad; + + g_CameraTable.m_pfnGetCamWindowExtents( &x, &y, &width, &height ); + + // setup orthographic projection mode + g_QglTable.m_pfn_qglMatrixMode(GL_PROJECTION); + g_QglTable.m_pfn_qglLoadIdentity(); + g_QglTable.m_pfn_qglDisable( GL_DEPTH_TEST ); + g_QglTable.m_pfn_qglOrtho( 0, (float)width, 0, (float)height, -100, 100 ); + g_QglTable.m_pfn_qglMatrixMode( GL_MODELVIEW ); + + g_QglTable.m_pfn_qglLoadIdentity(); + g_QglTable.m_pfn_qglColor3f( 1.f, 1.f, 1.f ); + g_QglTable.m_pfn_qglBegin( GL_LINE_LOOP ); + g_QglTable.m_pfn_qglVertex2f( 10, 10 ); + g_QglTable.m_pfn_qglVertex2f( 40, 10 ); + g_QglTable.m_pfn_qglVertex2f( 40, 25 ); + g_QglTable.m_pfn_qglVertex2f( 10, 25 ); + g_QglTable.m_pfn_qglEnd(); + + g_QglTable.m_pfn_qglBegin( GL_LINE_LOOP ); + for( i = 0; i < 360; i += 60 ) { + degInRad = i * (3.14159265358979323846/180.f); + g_QglTable.m_pfn_qglVertex2f( 18 + cos(degInRad) * 5, 18 + sin(degInRad) * 5 ); + } + g_QglTable.m_pfn_qglEnd(); + + degInRad = (360-((current - start) % 360)) * (3.14159265358979323846/180.f); + g_QglTable.m_pfn_qglBegin( GL_LINES ); + g_QglTable.m_pfn_qglVertex2f( 18, 18 ); + g_QglTable.m_pfn_qglVertex2f( 18 + cos(degInRad) * 5, 18 + sin(degInRad) * 5 ); + g_QglTable.m_pfn_qglVertex2f( 32, 18 ); + g_QglTable.m_pfn_qglVertex2f( 32 + cos(degInRad) * 5, 18 + sin(degInRad) * 5 ); + g_QglTable.m_pfn_qglEnd(); + + g_QglTable.m_pfn_qglBegin( GL_LINE_LOOP ); + for( i = 0; i < 360; i += 60 ) { + degInRad = i * (3.14159265358979323846/180.f); + g_QglTable.m_pfn_qglVertex2f( 32 + cos(degInRad) * 5, 18 + sin(degInRad) * 5 ); + } + g_QglTable.m_pfn_qglEnd(); + + g_QglTable.m_pfn_qglBegin( GL_LINES ); + g_QglTable.m_pfn_qglVertex2f( 40, 22 ); + g_QglTable.m_pfn_qglVertex2f( 52, 31 ); + g_QglTable.m_pfn_qglVertex2f( 40, 13 ); + g_QglTable.m_pfn_qglVertex2f( 52, 4 ); + g_QglTable.m_pfn_qglEnd(); + } + + g_QglTable.m_pfn_qglPopAttrib(); +} diff --git a/contrib/camera/renderer.h b/contrib/camera/renderer.h new file mode 100644 index 00000000..c2ca93bd --- /dev/null +++ b/contrib/camera/renderer.h @@ -0,0 +1,46 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +Camera plugin for GtkRadiant +Copyright (C) 2002 Splash Damage Ltd. +*/ + +class CRenderer : public IGL2DWindow, public IGL3DWindow { +public: + CRenderer(); + virtual ~CRenderer(); + +protected: + int refCount; + +public: + void Register(); + void UnRegister(); + void Initialize(); + void Draw2D( VIEWTYPE vt ); + void Draw3D(); + + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + + bool m_bHooked; +}; diff --git a/contrib/gtkgensurf/.cvsignore b/contrib/gtkgensurf/.cvsignore new file mode 100644 index 00000000..7320b210 --- /dev/null +++ b/contrib/gtkgensurf/.cvsignore @@ -0,0 +1,4 @@ +Debug +*.plg +*.BAK +*.d diff --git a/contrib/gtkgensurf/CHANGES b/contrib/gtkgensurf/CHANGES new file mode 100644 index 00000000..3d916c71 --- /dev/null +++ b/contrib/gtkgensurf/CHANGES @@ -0,0 +1,73 @@ +05/14/2001 + ^Fishman +=============== +bitmap.cpp +Added Hydra's snap to grid code. +=============== +dec.cpp +Modified to support the new max size for the maps(Q3 1.27). +=============== +face.cpp +Modified to support the new max size for the maps(Q3 1.27). +=============== +font.cpp +Changed the fonts color to green, part of the new theme. +=============== +gendlgs.cpp +Added a label and textbox for the snap to grid feature. +Added a checkbox for adding terrain key to func_group. +Added a checkbox for antialiased lines in the preview window. +Modified a textbox to support the new max size for the maps(Q3 1.27). +Modified the About dialog. +=============== +genmap.cpp +Modified to support the new max size for the maps(Q3 1.27). +Added code for adding terrain key to func_group. +=============== +gensurf.cpp +Added code to save the settings of the antialiasing checkbox status and the terrain key checkbox status. +Modified version number. +=============== +view.cpp +Modified code for the new Green/Black theme. +Added code to antialiase lines in the preview window + +12/18/2000 + MrHyde +=============== +bitmap.cpp +Corrected a substitution error that would prevent code from reading a selected bitmap on the first pass, and possibly leave the bitmap file open. +Checks to ensure that main window has been created before updating the preview (which might be done if a bitmap filename was saved to ini file). Previous failure to do this resulted in Radiant console error messages. +=============== +gendlgs.cpp +One tooltip was goofed up ("preview" instead of "main_preview"), resulting in "invalid cast from (NULL) pointer to GtkObject" in Radiant console. +Tooltips - oops. Use wave_radios[] rather than string constants. +Moved check for game type from SetDlgValues to GenSurfInit in gensurf.cpp. Since the game type presumably won't change while GenSurf is active this only needs to be checked once (and if it IS possible to change the game while GenSurf is active then quite a bit more needs to be changed). +Worked around strange bug in SetDlgValues. In release dll (not debug), the 2nd pass through the set_sensitive loop for game_radios crashed. Since the state of those radio buttons won't ever change during a single session, the state is only set once now. Sure would like to know what's going on there, though. +=============== +view.cpp +Elevation and azimuth labels are right-justified. + +TODO: +Check out Fix Points on Voodoo2 again. Previous attempt caused entire preview to be redrawn when moving mouse (GL_SCISSOR_TEST failed?) + +12/17/2000 + MrHyde +- tooltips +- reformatted the source to use spaces instead of tabs +- fixes to update mechanism in bitmap tab + +12/13/2000 + MrHyde +=============== +gendlgs.cpp +In ReadDlgValues, reads wavelength, amplitude, and roughness text boxes (previously ignored). +In create_main_dialog, set a "focus_out_event" for the above and added a "value_changed" for RandomSeed. +In main_go, added call to WriteIni +=============== +gensurf.cpp +Set gszIni to "plugins/gensurf.ini" to get past assert error +ported WriteIni +=============== +view.cpp +In DrawPreview, changed 2 occurrences of GL_LINE_LOOP to GL_LINE_STRIP for patches diff --git a/contrib/gtkgensurf/bitmap.cpp b/contrib/gtkgensurf/bitmap.cpp new file mode 100644 index 00000000..93dcd282 --- /dev/null +++ b/contrib/gtkgensurf/bitmap.cpp @@ -0,0 +1,434 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include "gensurf.h" + +void GenerateBitmapMapping () +{ + double value; + double C0, C1; + double x, y; + int i, j; + int O00,O01,O10,O11; + int r0, r1, c0, c1; + int color; + unsigned char *colors; + + if (!gbmp.colors) + return; + + colors = gbmp.colors; + + for (j=0; j<=NV; j++) + { + y = (double)(j*(gbmp.height-1))/(double)NV; + r0 = (int)floor(y); + r1 = (int)ceil(y); + for (i=0; i<=NH; i++) + { + x = (double)(i*(gbmp.width-1))/(double)NH; + c0 = (int)floor(x); + c1 = (int)ceil(x); + O00 = r0*gbmp.width + c0; + O01 = r0*gbmp.width + c1; + O10 = r1*gbmp.width + c0; + O11 = r1*gbmp.width + c1; + C0 = (double)colors[O00] + (double)(colors[O01]-colors[O00])*(x-(double)c0); + C1 = (double)colors[O10] + (double)(colors[O11]-colors[O10])*(x-(double)c0); + color = (int)(C0 + (C1-C0)*(y-r0)); + + value = CalculateSnapValue(gbmp.black_value + color*((gbmp.white_value-gbmp.black_value)/255.)); + + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + xyz[i][j].p[1] = value; + break; + case PLANE_YZ0: + case PLANE_YZ1: + xyz[i][j].p[0] = value; + break; + default: + xyz[i][j].p[2] = value; + } + } + } +} + +static unsigned char* OpenBitmapFile () +{ + int bmWidth; + int bmHeight; + unsigned char bmPlanes; + unsigned char bmBitsPixel; + unsigned char m1,m2; + unsigned long sizeimage; + short res1,res2; + long filesize, pixoff; + long bmisize, compression; + long xscale, yscale; + long colors, impcol; + unsigned long m_bytesRead = 0; + unsigned char *image; + FILE *fp; + + fp = fopen (gbmp.name, "rb"); + if (fp == NULL) + return NULL; + + long rc; + rc = fread(&m1, 1, 1, fp); + m_bytesRead++; + if (rc == -1) + { + fclose(fp); + return NULL; + } + + rc = fread(&m2, 1, 1, fp); + m_bytesRead++; + if ((m1 != 'B') || (m2 != 'M')) + { + fclose(fp); + return NULL; + } + + rc = fread((long*)&(filesize),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((int*)&(res1),2,1,fp); m_bytesRead+=2; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((int*)&(res2),2,1,fp); m_bytesRead+=2; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(pixoff),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(bmisize),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long *)&(bmWidth),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(bmHeight),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((int*)&(bmPlanes),2,1,fp); m_bytesRead+=2; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((int*)&(bmBitsPixel),2,1,fp); m_bytesRead+=2; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(compression),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(sizeimage),4,1,fp); m_bytesRead+=4; + if (rc != 1) {fclose(fp); return NULL; } + + rc = fread((long*)&(xscale),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(yscale),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(colors),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + rc = fread((long*)&(impcol),4,1,fp); m_bytesRead+=4; + if (rc != 1) { fclose(fp); return NULL; } + + if (bmBitsPixel != 8) + { + g_FuncTable.m_pfnMessageBox (g_pWnd, "This is not an 8-bit image. GenSurf can't use it.", + "Bitmap", MB_ICONEXCLAMATION); + fclose(fp); + return NULL; + } + + if (colors == 0) + colors = 1 << bmBitsPixel; + + if (bmBitsPixel != 24) + { + int i; + for (i = 0; i < colors; i++) + { + unsigned char r ,g, b, dummy; + + rc = fread(&b, 1, 1, fp); + m_bytesRead++; + if (rc!=1) + { + fclose(fp); + return NULL; + } + + rc = fread(&g, 1, 1, fp); + m_bytesRead++; + if (rc!=1) + { + fclose(fp); + return NULL; + } + + rc = fread(&r, 1, 1, fp); + m_bytesRead++; + if (rc != 1) + { + fclose(fp); + return NULL; + } + + rc = fread(&dummy, 1, 1, fp); + m_bytesRead++; + if (rc != 1) + { + fclose(fp); + return NULL; + } + } + } + + if ((long)m_bytesRead > pixoff) + { + fclose(fp); + return NULL; + } + + while ((long)m_bytesRead < pixoff) + { + char dummy; + fread(&dummy,1,1,fp); + m_bytesRead++; + } + + int w = bmWidth; + int h = bmHeight; + + // set the output params + image = (unsigned char*)malloc(w*h); + + if (image != NULL) + { + gbmp.width = w; + gbmp.height = h; + unsigned char* outbuf = image; + long row = 0; + long rowOffset = 0; + + if (compression == 0) // BI_RGB + { + for (row = 0; row < bmHeight; row++) + { + // which row are we working on? + rowOffset = (long unsigned)row*w; + + { + // pixels are packed as 1 , 4 or 8 bit vals. need to unpack them + int bit_count = 0; + unsigned long mask = (1 << bmBitsPixel) - 1; + unsigned char inbyte = 0; + + for (int col=0;col> bit_count) & mask; + + // lookup the color from the colormap - stuff it in our buffer + // swap red and blue + *(outbuf + rowOffset + col) = pix; + } + + // read DWORD padding + while ((m_bytesRead-pixoff)&3) + { + char dummy; + if (fread(&dummy,1,1,fp)!=1) + { + free(image); + fclose(fp); + return NULL; + } + m_bytesRead++; + } + } + } + } + else // compression != 0 + { + int i, x = 0; + unsigned char c, c1 = 0, *pp; + row = 0; + pp = outbuf; + + if (bmBitsPixel == 8) + { + while (row < bmHeight) + { + c = getc(fp); + + if (c) + { + // encoded mode + c1 = getc(fp); + for (i = 0; i < c; x++, i++) + { + *pp = c1; pp++; + } + } + else + { + // c==0x00, escape codes + c = getc(fp); + + if (c == 0x00) // end of line + { + row++; + x = 0; + pp = outbuf + row*bmWidth; + } + else if (c == 0x01) + break; // end of pic + else if (c == 0x02) // delta + { + c = getc(fp); + x += c; + c = getc(fp); + row += c; + pp = outbuf + x + row*bmWidth; + } + else // absolute mode + { + for (i = 0; i < c; x++, i++) + { + c1 = getc(fp); + *pp = c1; pp++; + } + + if (c & 1) + getc(fp); // odd length run: read an extra pad byte + } + } + } + } + else if (bmBitsPixel == 4) + { + while (row < bmHeight) + { + c = getc(fp); + + if (c) + { + // encoded mode + c1 = getc(fp); + for (i = 0; i < c; x++, i++) + { + *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f); pp++; + } + } + else + { + // c==0x00, escape codes + c = getc(fp); + + if (c == 0x00) // end of line + { + row++; + x = 0; + pp = outbuf + bmHeight*bmWidth; + } + else if (c == 0x01) + break; // end of pic + else if (c == 0x02) // delta + { + c = getc(fp); + x += c; + c = getc(fp); + row += c; + pp = outbuf + x + row*bmWidth; + } + else // absolute mode + { + for (i = 0; i < c; x++, i++) + { + if ((i&1) == 0) + c1 = getc(fp); + *pp = (i&1) ? (c1 & 0x0f) : ((c1>>4)&0x0f); pp++; + } + + if (((c&3) == 1) || ((c&3) == 2)) + getc(fp); // odd length run: read an extra pad byte + } + } + } + } + } + } + fclose(fp); + return image; +} + +bool OpenBitmap () +{ + if (gbmp.colors) + free (gbmp.colors); + + gbmp.colors = OpenBitmapFile (); + + if (!gbmp.colors) + { + char Text[256]; + + sprintf (Text, "Error opening %s", gbmp.name); + g_FuncTable.m_pfnMessageBox (g_pWnd, Text, "Bitmap", MB_ICONEXCLAMATION); + strcpy (gbmp.name, ""); + } + + if (g_pWnd) + { + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file")), gbmp.name); + gtk_widget_set_sensitive (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_reload")), + strlen (gbmp.name) ? TRUE : FALSE); + + UpdatePreview (true); + } + + return (gbmp.colors != NULL); +} diff --git a/contrib/gtkgensurf/dec.cpp b/contrib/gtkgensurf/dec.cpp new file mode 100644 index 00000000..4dbedf8c --- /dev/null +++ b/contrib/gtkgensurf/dec.cpp @@ -0,0 +1,1328 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#define SINGLE +#ifdef SINGLE +#define REAL float +#else /* not SINGLE */ +#define REAL double +#endif /* not SINGLE */ + +#include +#include +#include +#include "gensurf.h" +#include "triangle.h" + +typedef struct +{ + float error; + int node; +} TRITABLE; + +double dh, dv; +int NVP1; + +#define Absolute(a) ((a) >= 0.0 ? (a) : -(a)) + +void MakeDecimatedMap(int *NumNodes, int *NumTris, NODE **pNode, TRI **pTri) +{ + int compare(TRITABLE *, TRITABLE *); + int Bisect(NODE *, int, int, int); + void CalcAngles(NODE *, int *, float *); + void EdgeOnSide(int *, int *, int *); + int tricall(int, NODE *, int *, TRI **, TRI **, char *); + int CheckBorders(int *,int,NODE *,int *,TRI **); + + float biggesterror; + int i, j, N; + int j0, j1, j2; + int NumNodesToSave; + int NumNodesUsed; + NODE *Node; + TRI *Tri; + TRITABLE *TriTable; + + if(Decimate <= 0) return; + /* + ghCursorCurrent = LoadCursor(NULL,IDC_WAIT); + SetCursor(ghCursorCurrent); + */ + dh = (Hur-Hll)/NH; + dv = (Vur-Vll)/NV; + NVP1 = NV+1; + + NumNodes[0] = (NH+1)*(NVP1); + *pNode = (NODE *) malloc(NumNodes[0] * sizeof(NODE)); + Node = *pNode; + memset(Node,0,NumNodes[0]*sizeof(NODE)); + + // Copy [NH][NV] vertex array to our working node array + for(i=0,N=0; i<=NH; i++) + { + for(j=0; j<=NV; j++, N++) + { + Node[N].p[0] = (float)xyz[i][j].p[0]; + Node[N].p[1] = (float)xyz[i][j].p[1]; + Node[N].p[2] = (float)xyz[i][j].p[2]; + Node[N].fixed = xyz[i][j].fixed; + } + } + // Start things off with the corner values + Node[ 0].used = 1; + Node[NV].used = 1; + Node[NH*NVP1].used = 1; + Node[NH*NVP1+NV].used = 1; + NumNodesUsed = 4; + tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY"); + Tri = *pTri; + + // Which coordinates are we triangulating on? + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + j0 = 1; + j1 = 0; + j2 = 2; + break; + case PLANE_YZ0: + case PLANE_YZ1: + j0 = 0; + j1 = 1; + j2 = 2; + break; + default: + j0 = 2; + j1 = 0; + j2 = 1; + } + + // TriTable stores the largest error in a triangle and the node where that + // error occurs + TriTable = (TRITABLE *) malloc(NH*NV*2 * sizeof(TRITABLE)); + NumNodesToSave = min(NumNodes[0], (int)(0.01*(100-Decimate)*(NumNodes[0]-NumNodesUsed)+NumNodesUsed)); + + while(NumNodesUsed < NumNodesToSave) + { + for(i=0; i TriTable[Node[i].tri].error) + { + TriTable[Node[i].tri].error = (float)(Absolute(Node[i].error)); + TriTable[Node[i].tri].node = i; + } + } + qsort( (void *)TriTable, (size_t)(NumTris[0]), sizeof(TRITABLE), (int (*)(const void *, const void *))compare ); + for(i=0; i 0.5*biggesterror; i++) + { + if(Node[TriTable[i].node].used) continue; // shouldn't happen + NumNodesUsed++; + Node[TriTable[i].node].used++; + } + free(Tri); + tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY"); + Tri = *pTri; + // Sliver-check along borders. Since borders are often linear, the errors + // along borders will often be zero, so no new points will be added. This + // tends to produce long, thin brushes. For all border triangles, check + // that minimum angle isn't less than SLIVER_ANGLE. If it is, add another + // vertex. + while(CheckBorders(&NumNodesUsed,NumNodes[0],Node,NumTris,pTri) > 0) + { + } + Tri = *pTri; + } + } + free(TriTable); + // One last time (because we're pessimistic), check border triangles +// CheckBorders(&NumNodesUsed,NumNodes[0],Node,NumTris,pTri); +// Tri = *pTri; + + // Check that all fixed points are exact. If not, add them to the mix. + // First check to see if we have any fixed points that aren't already used. + for(i=0, N=0; i 0.5) + { + NumNodesUsed++; + Node[i].used++; + free(Tri); + tricall(NumNodes[0], Node, NumTris, NULL, pTri, "cnzBNPY"); + Tri = *pTri; + } + } + } + + // Swap node orders for surfaces facing down, north or west so that + // they are counterclockwise when facing the surface + + if((Plane == PLANE_XY1) || (Plane == PLANE_XZ0) || (Plane == PLANE_YZ1) ) + { + for(i=0; i= R) && (v[1] >= R) ) + { + edge[0] = 0; + border[0] = 1; + } + if( (v[1] >= R) && (v[2] >= R) ) + { + edge[0] = 1; + border[0] = 1; + } + if( (v[2] >= R) && (v[0] >= R) ) + { + edge[0] = 2; + border[0] = 1; + } + + if(border[0] >= 0) + { + k0 = edge[0]; + k1 = (k0+1) % 3; + N = Absolute(v[k0] - v[k1]); + Ndv = (float)(N*dv); + } + if( ((v[0] % NVP1) == 0) && ((v[1] % NVP1) == 0) ) + { + if(border[0] >= 0) + if( Ndv > (Absolute(v[0] - v[1])*dh)) return; + edge[0] = 0; + border[0] = 2; + return; + } + if( ((v[1] % NVP1) == 0) && ((v[2] % NVP1) == 0) ) + { + if(border[0] >= 0) + if( Ndv > (Absolute(v[1] - v[2])*dh)) return; + edge[0] = 1; + border[0] = 2; + return; + } + if( ((v[2] % NVP1) == 0) && ((v[0] % NVP1) == 0) ) + { + if(border[0] >= 0) + if( Ndv > (Absolute(v[2] - v[0])*dh)) return; + edge[0] = 2; + border[0] = 2; + return; + } + + if( ((v[0] % NVP1) == NV) && ((v[1] % NVP1) == NV) ) + { + if(border[0] >= 0) + if( Ndv > (Absolute(v[0] - v[1])*dh)) return; + edge[0] = 0; + border[0] = 3; + return; + } + if( ((v[1] % NVP1) == NV) && ((v[2] % NVP1) == NV) ) + { + if(border[0] >= 0) + if( Ndv > (Absolute(v[1] - v[2])*dh)) return; + edge[0] = 1; + border[0] = 3; + return; + } + if( ((v[2] % NVP1) == NV) && ((v[0] % NVP1) == NV) ) + { + if(border[0] >= 0) + if( Ndv > (Absolute(v[2] - v[0])*dh)) return; + edge[0] = 2; + border[0] = 3; + return; + } + return; +} + +void CalcAngles(NODE *node, int *v, float *angle) +{ + int i, j, k; + vec l; + vec x0, x1, x2, y0, y1, y2; + vec2 vv[3]; + vec dot; + + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + i = 0; + j = 2; + break; + case PLANE_YZ0: + case PLANE_YZ1: + i = 1; + j = 2; + break; + default: + i = 0; + j = 1; + } + x0 = node[v[0]].p[i]; + x1 = node[v[1]].p[i]; + x2 = node[v[2]].p[i]; + y0 = node[v[0]].p[j]; + y1 = node[v[1]].p[j]; + y2 = node[v[2]].p[j]; + + vv[0][0] = x1-x0; + vv[0][1] = y1-y0; + vv[1][0] = x2-x1; + vv[1][1] = y2-y1; + vv[2][0] = x0-x2; + vv[2][1] = y0-y2; + + for(k=0; k<3; k++) + { + l = (vec)(sqrt( vv[k][0]*vv[k][0] + vv[k][1]*vv[k][1] )); + if(l > 0.) + { + vv[k][0] /= l; + vv[k][1] /= l; + } + } + + dot = -(vv[0][0]*vv[2][0] + vv[0][1]*vv[2][1]); + angle[0] = (float)(acos(dot)); + dot = -(vv[1][0]*vv[0][0] + vv[1][1]*vv[0][1]); + angle[1] = (float)(acos(dot)); + dot = -(vv[2][0]*vv[1][0] + vv[2][1]*vv[1][1]); + angle[2] = (float)(acos(dot)); +} +//================================================================= +int Bisect(NODE *node, int border, int j0, int j1) +{ + int k; + + switch(border) + { + case 0: + k = (j0+j1)/2; + break; + case 1: + k = (j0+j1)/2; + break; + case 2: + k = (int)((j0+j1)/(2*NVP1)) * NVP1; + break; + case 3: + k = (int)((j0+j1+2)/(2*NVP1)) * NVP1 - 1; + break; + } + return( ((k != j0) && (k != j1)) ? k : 0 ); +} +//================================================================= +int compare(TRITABLE *t1, TRITABLE *t2) +{ + if(t1->error > t2->error) return -1; + if(t1->error < t2->error) return 1; + return 0; +} + +void MakeBrushes(int NumTris, NODE *Node, TRI *Tri,bool surf, + int offset,char *texture0, char *texture1, char *texture2) +{ + extern double backface; + BRUSH brush; + int contents; + int i, j; + float Steep; + vec3_t PlaneNormal,SurfNormal; + bool CheckAngle; + vec3_t t[2]; + + // if texture2 is identical to texture0, there's no need to + // check surface angle + if(!g_strcasecmp(texture0,texture2) || !strlen(texture2)) + CheckAngle = FALSE; + else + { + CheckAngle = TRUE; + Steep = (float)cos((double)SlantAngle/57.2957795); + switch(Plane) + { + case PLANE_XY0: PlaneNormal[0]= 0.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break; + case PLANE_XY1: PlaneNormal[0]= 0.;PlaneNormal[1]= 0.;PlaneNormal[2]=-1.;break; + case PLANE_XZ0: PlaneNormal[0]= 0.;PlaneNormal[1]= 1.;PlaneNormal[2]= 1.;break; + case PLANE_XZ1: PlaneNormal[0]= 0.;PlaneNormal[1]=-1.;PlaneNormal[2]= 1.;break; + case PLANE_YZ0: PlaneNormal[0]= 1.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break; + case PLANE_YZ1: PlaneNormal[0]=-1.;PlaneNormal[1]= 0.;PlaneNormal[2]= 1.;break; + } + } + + contents = 0; + if(surf) + { + if(UseDetail) contents += CONTENTS_DETAIL; + if(UseLadder) contents += CONTENTS_LADDER; + } + + OpenFuncGroup(); + for(i=0; i= max(Node[q[0]].p[j1],Node[q[2]].p[j1])) continue; + if(Tri[k].min[j2] >= max(Node[q[0]].p[j2],Node[q[2]].p[j2])) continue; + if(Tri[k].max[j1] <= min(Node[q[0]].p[j1],Node[q[2]].p[j1])) continue; + if(Tri[k].max[j2] <= min(Node[q[0]].p[j2],Node[q[2]].p[j2])) continue; + + for(h0=0; h0<4 && OK; h0++) + { + h1 = (h0+1)%4; + for(t=0; t<3 && OK; t++) + { + s[t] = side(Node[q[h0]].p[j1],Node[q[h0]].p[j2], + Node[q[h1]].p[j1],Node[q[h1]].p[j2], + Node[Tri[k].v[t]].p[j1],Node[Tri[k].v[t]].p[j2]); + } + if((s[1] > 0 || s[2] > 0) && s[0] < 0) OK=0; + if((s[2] > 0 || s[0] > 0) && s[1] < 0) OK=0; + if((s[0] > 0 || s[1] > 0) && s[2] < 0) OK=0; + } + } + if(!OK) continue; + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + // front + brush.face[0].v[0][0] = Node[q[2]].p[0]; + brush.face[0].v[0][1] = (float)front; + brush.face[0].v[0][2] = Node[q[2]].p[2]; + + brush.face[0].v[1][0] = Node[q[1]].p[0]; + brush.face[0].v[1][1] = (float)front; + brush.face[0].v[1][2] = Node[q[1]].p[2]; + + brush.face[0].v[2][0] = Node[q[0]].p[0]; + brush.face[0].v[2][1] = (float)front; + brush.face[0].v[2][2] = Node[q[0]].p[2]; + + // back + brush.face[1].v[0][0] = Node[q[0]].p[0]; + brush.face[1].v[0][1] = (float)backface; + brush.face[1].v[0][2] = Node[q[0]].p[2]; + + brush.face[1].v[1][0] = Node[q[1]].p[0]; + brush.face[1].v[1][1] = (float)backface; + brush.face[1].v[1][2] = Node[q[1]].p[2]; + + brush.face[1].v[2][0] = Node[q[2]].p[0]; + brush.face[1].v[2][1] = (float)backface; + brush.face[1].v[2][2] = Node[q[2]].p[2]; + + for(k0=0; k0= 0) + { + if(!Node[j].used) // Shouldn't be used, but... + { + NumNodesUsed[0]++; + Node[j].used++; + } + } + } + } + if(NumNodesUsed[0] > N) + { + free(*pTri); + tricall(NumNodes, Node, NumTris, NULL, pTri, "cnzBNPY"); + Tri = *pTri; + } + return (NumNodesUsed[0] - N); +} diff --git a/contrib/gtkgensurf/face.cpp b/contrib/gtkgensurf/face.cpp new file mode 100644 index 00000000..6c43c677 --- /dev/null +++ b/contrib/gtkgensurf/face.cpp @@ -0,0 +1,450 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include "gensurf.h" + +#define MAX_FACES 128 // Maximum number of faces on a brush +#define MAX_POINTS_ON_WINDING 64 +#define SIDE_FRONT 0 +#define SIDE_ON 2 +#define SIDE_BACK 1 +#define SIDE_CROSS -2 + +vec3 vec3_origin = {0,0,0}; + +void PlaneFromPoints (float *p0, float *p1, float *p2, PLANE *plane) +{ + vec3 t1, t2; + vec length; + + VectorSubtract (p0, p1, t1); + VectorSubtract (p2, p1, t2); + plane->normal[0] = t1[1]*t2[2] - t1[2]*t2[1]; + plane->normal[1] = t1[2]*t2[0] - t1[0]*t2[2]; + plane->normal[2] = t1[0]*t2[1] - t1[1]*t2[0]; + + length = (vec)(sqrt(plane->normal[0]*plane->normal[0] + + plane->normal[1]*plane->normal[1] + + plane->normal[2]*plane->normal[2] )); + if (length == 0) + { + VectorClear(plane->normal); + } + else + { + plane->normal[0] /= length; + plane->normal[1] /= length; + plane->normal[2] /= length; + } + plane->dist = DotProduct (p0, plane->normal); +} + +void VectorMA (vec3 va, vec scale, vec3 vb, vec3 vc) +{ + vc[0] = va[0] + scale*vb[0]; + vc[1] = va[1] + scale*vb[1]; + vc[2] = va[2] + scale*vb[2]; +} + +void CrossProduct (vec3 v1, vec3 v2, vec3 cross) +{ + cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; + cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; + cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} + +/* +============= +AllocWinding +============= +*/ +MY_WINDING *AllocWinding (int points) +{ + MY_WINDING *w; + int s; + + s = sizeof(vec)*3*points + sizeof(int); + w = (MY_WINDING*)malloc (s); + memset (w, 0, s); + return w; +} + +vec VectorNormalize (vec3 in, vec3 out) +{ + vec length, ilength; + + length = (vec)(sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2])); + if (length == 0) + { + VectorClear (out); + return 0; + } + + ilength = (vec)1.0/length; + out[0] = in[0]*ilength; + out[1] = in[1]*ilength; + out[2] = in[2]*ilength; + + return length; +} + +/* +================= +BaseWindingForPlane +================= +*/ +MY_WINDING *BaseWindingForPlane (vec3 normal, vec dist) +{ + int i, x; + vec max, v; + vec3 org, vright, vup; + MY_WINDING *w; + +// find the major axis + + max = -BOGUS_RANGE; + x = -1; + for (i=0 ; i<3; i++) + { + v = (vec)(fabs(normal[i])); + if (v > max) + { + x = i; + max = v; + } + } + if (x==-1) x = 2; + + VectorCopy(vec3_origin,vup); + switch (x) + { + case 0: + case 1: + vup[2] = 1; + break; + case 2: + vup[0] = 1; + break; + } + + v = DotProduct (vup, normal); + VectorMA (vup, -v, normal, vup); + VectorNormalize (vup, vup); + + VectorScale (normal, dist, org); + + CrossProduct (vup, normal, vright); + + VectorScale (vup, 65536, vup); + VectorScale (vright, 65536, vright); + +// project a really big axis aligned box onto the plane + w = AllocWinding (4); + + VectorSubtract (org, vright, w->p[0]); + VectorAdd (w->p[0], vup, w->p[0]); + + VectorAdd (org, vright, w->p[1]); + VectorAdd (w->p[1], vup, w->p[1]); + + VectorAdd (org, vright, w->p[2]); + VectorSubtract (w->p[2], vup, w->p[2]); + + VectorSubtract (org, vright, w->p[3]); + VectorSubtract (w->p[3], vup, w->p[3]); + + w->numpoints = 4; + + return w; +} + +void FreeWinding (MY_WINDING *w) +{ + if (*(unsigned *)w == 0xdeaddead) +// Error ("FreeWinding: freed a freed winding"); + return; + *(unsigned *)w = 0xdeaddead; + + free (w); +} + +/* +============= +ChopWindingInPlace +============= +*/ +void ChopWindingInPlace (MY_WINDING **inout, vec3 normal, vec dist, vec epsilon) +{ + MY_WINDING *in; + vec dists[MAX_POINTS_ON_WINDING+4]; + int sides[MAX_POINTS_ON_WINDING+4]; + int counts[3]; + static vec dot; // VC 4.2 optimizer bug if not static + int i, j; + vec *p1, *p2; + vec3 mid; + MY_WINDING *f; + int maxpts; + + in = *inout; + counts[0] = counts[1] = counts[2] = 0; + +// determine sides for each point + for (i=0 ; inumpoints ; i++) + { + dot = DotProduct (in->p[i], normal); + dot -= dist; + dists[i] = dot; + if (dot > epsilon) + sides[i] = SIDE_FRONT; + else if (dot < -epsilon) + sides[i] = SIDE_BACK; + else + { + sides[i] = SIDE_ON; + } + counts[sides[i]]++; + } + sides[i] = sides[0]; + dists[i] = dists[0]; + + if (!counts[0]) + { + FreeWinding(in); + *inout = NULL; + return; + } + if (!counts[1]) + return; // inout stays the same + + maxpts = in->numpoints+4; // cant use counts[0]+2 because + // of fp grouping errors + + f = AllocWinding (maxpts); + + for (i=0 ; inumpoints ; i++) + { + p1 = in->p[i]; + + if (sides[i] == SIDE_ON) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + continue; + } + + if (sides[i] == SIDE_FRONT) + { + VectorCopy (p1, f->p[f->numpoints]); + f->numpoints++; + } + + if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i]) + continue; + + // generate a split point + p2 = in->p[(i+1)%in->numpoints]; + + dot = dists[i] / (dists[i]-dists[i+1]); + for (j=0 ; j<3 ; j++) + { // avoid round off error when possible + if (normal[j] == 1) + mid[j] = dist; + else if (normal[j] == -1) + mid[j] = -dist; + else + mid[j] = p1[j] + dot*(p2[j]-p1[j]); + } + + VectorCopy (mid, f->p[f->numpoints]); + f->numpoints++; + } + +// if (f->numpoints > maxpts) +// Error ("ClipWinding: points exceeded estimate"); +// if (f->numpoints > MAX_POINTS_ON_WINDING) +// Error ("ClipWinding: MAX_POINTS_ON_WINDING"); + + FreeWinding(in); + *inout = f; +} + +void UseFaceBounds() +{ + LPVOID vp; + float Dot, BestDot; + float planepts[3][3]; + int BestFace; + int i, j; + int NumFaces; + vec3 SurfNormal; + vec3 vmin,vmax; + _QERFaceData *QERFaceData; + PLANE plane[MAX_FACES*2]; + PLANE pface; + MY_WINDING *w; + + switch(Plane) + { + case PLANE_XY1: + SurfNormal[0] = 0.0; + SurfNormal[1] = 0.0; + SurfNormal[2] =-1.0; + break; + case PLANE_XZ0: + SurfNormal[0] = 0.0; + SurfNormal[1] = 1.0; + SurfNormal[2] = 0.0; + break; + case PLANE_XZ1: + SurfNormal[0] = 0.0; + SurfNormal[1] =-1.0; + SurfNormal[2] = 0.0; + break; + case PLANE_YZ0: + SurfNormal[0] = 1.0; + SurfNormal[1] = 0.0; + SurfNormal[2] = 0.0; + break; + case PLANE_YZ1: + SurfNormal[0] =-1.0; + SurfNormal[1] = 0.0; + SurfNormal[2] = 0.0; + break; + default: + SurfNormal[0] = 0.0; + SurfNormal[1] = 0.0; + SurfNormal[2] = 1.0; + } + + i = g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + vp = g_FuncTable.m_pfnGetSelectedBrushHandle(0); + NumFaces = g_FuncTable.m_pfnGetFaceCount(vp); + + BestFace = -1; + BestDot = 0.0; + + for(i=0; im_v1[0]; + planepts[0][1] = QERFaceData->m_v1[1]; + planepts[0][2] = QERFaceData->m_v1[2]; + planepts[1][0] = QERFaceData->m_v2[0]; + planepts[1][1] = QERFaceData->m_v2[1]; + planepts[1][2] = QERFaceData->m_v2[2]; + planepts[2][0] = QERFaceData->m_v3[0]; + planepts[2][1] = QERFaceData->m_v3[1]; + planepts[2][2] = QERFaceData->m_v3[2]; + + PlaneFromPoints (planepts[0], planepts[1], planepts[2], &plane[2*i]); + VectorSubtract (vec3_origin, plane[2*i].normal, plane[2*i+1].normal); + plane[2*i+1].dist = -plane[2*i].dist; + + Dot = DotProduct(plane[2*i].normal,SurfNormal); + if(Dot > BestDot) + { + BestDot = Dot; + BestFace = i; + if(strlen(QERFaceData->m_TextureName)) + strcpy(Texture[Game][0],QERFaceData->m_TextureName); + } + } + for(i=0; im_TextureName)) + { + if(strcmp(Texture[Game][0],QERFaceData->m_TextureName)) + strcpy(Texture[Game][1],QERFaceData->m_TextureName); + } + } + + + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + + w = BaseWindingForPlane (plane[BestFace*2].normal, plane[BestFace*2].dist); + + for (i=0 ; ip[0][0]; + vmin[1] = vmax[1] = w->p[0][1]; + vmin[2] = vmax[2] = w->p[0][2]; + for(j=1; jnumpoints; j++) + { + vmin[0] = min(vmin[0],w->p[j][0]); + vmin[1] = min(vmin[1],w->p[j][1]); + vmin[2] = min(vmin[2],w->p[j][2]); + vmax[0] = max(vmax[0],w->p[j][0]); + vmax[1] = max(vmax[1],w->p[j][1]); + vmax[2] = max(vmax[2],w->p[j][2]); + } + + FreeWinding(w); + + VectorCopy(plane[BestFace*2].normal,pface.normal); + pface.dist = plane[BestFace*2].dist; + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + if(pface.normal[1] == 0.) return; + Hll = vmin[0]; + Hur = vmax[0]; + Vll = vmin[2]; + Vur = vmax[2]; + Z00 = (pface.dist - pface.normal[0]*Hll - pface.normal[2]*Vll)/pface.normal[1]; + Z01 = (pface.dist - pface.normal[0]*Hll - pface.normal[2]*Vur)/pface.normal[1]; + Z10 = (pface.dist - pface.normal[0]*Hur - pface.normal[2]*Vll)/pface.normal[1]; + Z11 = (pface.dist - pface.normal[0]*Hur - pface.normal[2]*Vur)/pface.normal[1]; + break; + case PLANE_YZ0: + case PLANE_YZ1: + if(pface.normal[0] == 0.) return; + Hll = vmin[1]; + Hur = vmax[1]; + Vll = vmin[2]; + Vur = vmax[2]; + Z00 = (pface.dist - pface.normal[1]*Hll - pface.normal[2]*Vll)/pface.normal[0]; + Z01 = (pface.dist - pface.normal[1]*Hll - pface.normal[2]*Vur)/pface.normal[0]; + Z10 = (pface.dist - pface.normal[1]*Hur - pface.normal[2]*Vll)/pface.normal[0]; + Z11 = (pface.dist - pface.normal[1]*Hur - pface.normal[2]*Vur)/pface.normal[0]; + break; + default: + if(pface.normal[2] == 0.) return; + Hll = vmin[0]; + Hur = vmax[0]; + Vll = vmin[1]; + Vur = vmax[1]; + Z00 = (pface.dist - pface.normal[0]*Hll - pface.normal[1]*Vll)/pface.normal[2]; + Z01 = (pface.dist - pface.normal[0]*Hll - pface.normal[1]*Vur)/pface.normal[2]; + Z10 = (pface.dist - pface.normal[0]*Hur - pface.normal[1]*Vll)/pface.normal[2]; + Z11 = (pface.dist - pface.normal[0]*Hur - pface.normal[1]*Vur)/pface.normal[2]; + } +} diff --git a/contrib/gtkgensurf/font.cpp b/contrib/gtkgensurf/font.cpp new file mode 100644 index 00000000..bb3753f1 --- /dev/null +++ b/contrib/gtkgensurf/font.cpp @@ -0,0 +1,270 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// +// Texture Font +// +// Taken from LeoCAD (www.leocad.org) and used in GtkGenSurf +// with permission from the author. +// +// Leonardo Zide (leo@lokigames.com) +// + +#include +#include "gensurf.h" + +static const unsigned char data[2048] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 207, 255, 255, 159, 255, 31, 255, 231, 159, 153, 63, 255, 255, 255, 255, + 255, 207, 255, 255, 159, 255, 207, 255, 231, 159, 153, 63, 255, 255, 255, 255, + 255, 207, 255, 255, 159, 255, 207, 255, 231, 255, 159, 63, 255, 255, 255, 255, + 7, 78, 252, 240, 145, 135, 3, 71, 38, 158, 153, 51, 19, 227, 196, 255, + 243, 140, 121, 230, 140, 51, 207, 51, 198, 156, 153, 57, 99, 204, 152, 255, + 255, 204, 51, 111, 158, 121, 206, 121, 230, 153, 153, 60, 115, 206, 60, 255, + 31, 204, 51, 127, 158, 121, 206, 121, 230, 153, 25, 62, 115, 206, 60, 255, + 199, 204, 51, 127, 158, 1, 206, 121, 230, 153, 25, 62, 115, 206, 60, 255, + 243, 204, 51, 127, 158, 249, 207, 121, 230, 153, 153, 60, 115, 206, 60, 255, + 243, 204, 51, 111, 158, 249, 207, 121, 230, 153, 153, 57, 115, 206, 60, 255, + 243, 140, 121, 230, 140, 115, 206, 51, 230, 153, 153, 51, 115, 206, 60, 255, + 7, 73, 252, 240, 145, 7, 207, 71, 230, 153, 153, 39, 115, 206, 60, 255, + 255, 255, 255, 255, 255, 255, 255, 127, 254, 255, 249, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 127, 254, 255, 249, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 57, 255, 255, 249, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 131, 255, 255, 252, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, 255, 255, 255, 255, 227, 255, + 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, 255, 255, 255, 255, 201, 255, + 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, 255, 255, 255, 255, 156, 255, + 15, 79, 252, 200, 196, 96, 32, 79, 62, 252, 15, 15, 159, 192, 156, 255, + 103, 142, 121, 198, 112, 206, 57, 79, 62, 60, 15, 15, 159, 207, 156, 255, + 243, 204, 51, 207, 120, 254, 57, 207, 156, 57, 103, 102, 206, 231, 156, 255, + 243, 204, 51, 207, 124, 252, 57, 207, 156, 25, 230, 112, 206, 231, 156, 255, + 243, 204, 51, 207, 252, 224, 57, 207, 156, 25, 230, 121, 206, 243, 156, 255, + 243, 204, 51, 207, 252, 199, 57, 207, 201, 211, 242, 240, 228, 249, 156, 255, + 243, 204, 51, 207, 252, 207, 57, 207, 201, 195, 112, 230, 228, 249, 156, 255, + 103, 142, 121, 198, 124, 206, 121, 198, 227, 231, 57, 207, 241, 252, 201, 255, + 15, 79, 252, 200, 252, 224, 227, 200, 227, 231, 57, 207, 241, 192, 227, 255, + 255, 207, 255, 207, 255, 255, 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, + 255, 207, 255, 207, 255, 255, 255, 255, 255, 255, 255, 255, 249, 255, 255, 255, + 255, 207, 255, 207, 255, 255, 255, 255, 255, 255, 255, 255, 252, 255, 255, 255, + 255, 207, 255, 207, 255, 255, 255, 255, 255, 255, 255, 127, 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, + 159, 15, 30, 252, 57, 224, 225, 128, 131, 7, 255, 254, 128, 127, 240, 255, + 135, 231, 204, 249, 57, 255, 252, 159, 57, 115, 126, 252, 60, 63, 231, 255, + 159, 247, 236, 249, 56, 127, 254, 159, 57, 115, 126, 252, 124, 158, 207, 255, + 159, 255, 252, 249, 56, 127, 254, 207, 57, 115, 62, 249, 124, 158, 207, 255, + 159, 255, 252, 121, 56, 112, 254, 207, 57, 115, 62, 249, 60, 207, 255, 255, + 159, 127, 62, 60, 57, 103, 224, 231, 131, 115, 158, 243, 128, 207, 255, 255, + 159, 63, 255, 57, 249, 103, 206, 231, 57, 7, 158, 243, 60, 207, 255, 255, + 159, 159, 255, 153, 249, 103, 206, 231, 57, 127, 206, 231, 124, 206, 255, 255, + 159, 207, 255, 25, 240, 103, 206, 243, 57, 127, 14, 224, 124, 158, 207, 255, + 159, 231, 239, 249, 185, 103, 206, 243, 57, 127, 230, 207, 124, 158, 207, 255, + 159, 231, 207, 249, 57, 103, 206, 243, 57, 63, 231, 207, 60, 63, 231, 255, + 159, 7, 28, 252, 121, 240, 224, 243, 131, 135, 231, 207, 128, 127, 240, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 7, 126, 128, 3, 124, 240, 249, 156, 63, 231, 57, 255, 252, 57, 159, 255, + 231, 124, 254, 243, 63, 231, 249, 156, 63, 231, 60, 255, 252, 57, 159, 255, + 231, 121, 254, 243, 159, 207, 249, 156, 63, 103, 62, 255, 248, 56, 158, 255, + 231, 121, 254, 243, 159, 207, 249, 156, 63, 39, 63, 255, 248, 56, 156, 255, + 231, 115, 254, 243, 207, 255, 249, 156, 63, 135, 63, 255, 112, 56, 152, 255, + 231, 115, 192, 3, 206, 255, 1, 156, 63, 199, 63, 255, 112, 56, 153, 255, + 231, 115, 254, 243, 207, 193, 249, 156, 63, 135, 63, 255, 36, 57, 147, 255, + 231, 115, 254, 243, 207, 207, 249, 156, 63, 39, 63, 255, 36, 57, 131, 255, + 231, 121, 254, 243, 159, 207, 249, 156, 57, 103, 62, 255, 140, 57, 135, 255, + 231, 121, 254, 243, 159, 199, 249, 156, 57, 231, 60, 255, 140, 57, 143, 255, + 231, 124, 254, 243, 63, 199, 249, 156, 147, 231, 57, 255, 220, 57, 159, 255, + 7, 126, 128, 243, 127, 208, 249, 156, 199, 231, 51, 192, 220, 57, 159, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 63, 252, 128, 63, 252, 128, 63, 28, 128, 249, 204, 79, 254, 39, 63, 255, + 159, 249, 60, 159, 249, 60, 159, 249, 249, 249, 204, 79, 158, 39, 63, 255, + 207, 243, 124, 206, 243, 124, 206, 243, 249, 249, 156, 103, 158, 103, 158, 255, + 207, 243, 124, 206, 243, 124, 206, 255, 249, 249, 156, 231, 156, 243, 204, 255, + 231, 231, 124, 230, 231, 124, 158, 255, 249, 249, 156, 231, 12, 243, 225, 255, + 231, 231, 60, 231, 231, 60, 63, 252, 249, 249, 60, 243, 12, 243, 243, 255, + 231, 231, 128, 231, 231, 128, 255, 249, 249, 249, 60, 243, 105, 249, 243, 255, + 231, 231, 252, 103, 230, 60, 255, 243, 249, 249, 124, 251, 97, 248, 225, 255, + 207, 243, 252, 207, 240, 124, 254, 243, 249, 249, 124, 248, 97, 248, 204, 255, + 207, 243, 252, 207, 241, 124, 206, 243, 249, 249, 124, 248, 243, 124, 158, 255, + 159, 249, 252, 159, 241, 124, 158, 249, 249, 115, 254, 252, 243, 60, 63, 255, + 63, 252, 252, 63, 228, 252, 60, 252, 249, 7, 255, 252, 243, 60, 63, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 243, 19, 192, 255, 252, 255, 255, 127, 14, 127, 248, 15, 252, 247, 227, 231, + 243, 243, 207, 255, 252, 255, 153, 127, 102, 62, 243, 227, 241, 193, 201, 243, + 231, 249, 231, 255, 252, 255, 60, 127, 242, 156, 231, 249, 231, 148, 201, 249, + 207, 252, 243, 255, 204, 124, 126, 126, 254, 156, 231, 57, 230, 148, 201, 252, + 207, 252, 243, 255, 204, 60, 255, 60, 255, 156, 231, 156, 204, 244, 99, 254, + 31, 254, 249, 255, 252, 159, 255, 57, 127, 158, 231, 204, 204, 244, 63, 255, + 31, 254, 252, 255, 252, 207, 255, 51, 63, 159, 231, 204, 204, 193, 159, 255, + 63, 127, 254, 255, 252, 159, 255, 57, 159, 207, 207, 204, 204, 151, 207, 248, + 63, 127, 254, 255, 252, 63, 255, 156, 159, 159, 231, 204, 228, 151, 103, 242, + 63, 63, 255, 255, 255, 127, 126, 158, 255, 159, 231, 25, 241, 148, 115, 242, + 63, 159, 127, 230, 204, 252, 60, 159, 159, 159, 231, 249, 255, 148, 121, 242, + 63, 31, 64, 230, 204, 252, 153, 159, 159, 159, 231, 227, 255, 193, 252, 248, + 255, 255, 63, 255, 231, 255, 255, 255, 255, 159, 231, 15, 252, 247, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 63, 243, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 127, 248, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 63, 254, 255, 195, 255, 255, 255, 255, 3, 252, 147, 255, 255, 255, 255, 255, + 159, 252, 255, 153, 255, 255, 255, 255, 243, 252, 147, 255, 255, 255, 255, 255, + 159, 252, 255, 153, 255, 243, 255, 255, 243, 252, 147, 255, 255, 255, 255, 255, + 159, 252, 204, 60, 255, 243, 255, 255, 243, 252, 0, 255, 255, 255, 255, 255, + 63, 254, 204, 60, 255, 243, 128, 255, 243, 252, 201, 255, 255, 255, 255, 255, + 63, 254, 225, 60, 255, 243, 255, 255, 243, 252, 201, 255, 255, 255, 255, 255, + 31, 126, 128, 60, 127, 128, 255, 255, 243, 252, 201, 255, 255, 255, 255, 255, + 159, 228, 225, 60, 193, 243, 128, 255, 243, 252, 201, 255, 255, 255, 255, 255, + 207, 240, 204, 60, 255, 243, 255, 255, 243, 124, 128, 255, 255, 255, 255, 255, + 207, 249, 204, 60, 255, 243, 255, 255, 243, 252, 228, 255, 255, 255, 255, 255, + 207, 240, 255, 60, 255, 243, 255, 255, 243, 252, 228, 255, 255, 255, 255, 255, + 31, 242, 255, 60, 255, 255, 255, 255, 243, 252, 228, 255, 255, 255, 255, 255, + 255, 255, 255, 60, 255, 255, 255, 255, 243, 252, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 153, 255, 255, 255, 0, 242, 252, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 153, 255, 255, 255, 255, 243, 252, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 195, 255, 255, 255, 255, 3, 252, 255, 255, 255, 255, 255, 255 +}; + +typedef struct +{ + unsigned char width; + float left, right, top, bottom; +} LC_TXFVERT; + +static LC_TXFVERT glyphs[93]; +static GLuint texture; + +void texfont_init () +{ + if (texture != 0) + return; + + int i, j, x, y; + float inv = 1.0f/128; + char *charlines[16] = { + "abcdefghijklmn", "opqrstuvwxyz0", "123456789ABC", "DEFGHIJKLMN", + "OPQRSTUVWX", "YZ,.!;:<>/?{}@$%", "&*()-+=_[] #" }; + unsigned char lefts[7][17] = { + { 1, 11, 21, 30, 40, 50, 56, 66, 76, 80, 84, 93, 97, 111, 121 }, + { 1, 11, 21, 31, 38, 47, 53, 63, 72, 86, 94, 103, 111, 120 }, + { 1, 10, 19, 28, 37, 46, 55, 64, 73, 82, 94, 106, 118, }, + { 1, 13, 24, 34, 47, 59, 64, 73, 84, 94, 108, 120 }, + { 1, 14, 25, 38, 50, 61, 71, 83, 94, 109, 120 }, + { 1, 12, 22, 26, 30, 35, 39, 43, 52, 61, 65, 75, 81, 87, 103, 112, 125 }, + { 3, 14, 23, 28, 33, 38, 47, 56, 65, 70, 75, 79, 88 } }; + // tops = 1 20 39 58 77 96 112 (+16) + memset(glyphs, 0, sizeof(glyphs)); + + // ASCII 32-125 + for (i = 32; i < 126; i++) + for (x = 0; x < 7; x++) + for (y = 0; charlines[x][y]; y++) + if (charlines[x][y] == i) + { + glyphs[i-32].width = lefts[x][y+1] - lefts[x][y]; + glyphs[i-32].left = (float)lefts[x][y]*inv; + glyphs[i-32].right = (float)(lefts[x][y+1])*inv; + + if (x != 6) + glyphs[i-32].top = (float)(1 + 19*x); + else + glyphs[i-32].top = 112; + glyphs[i-32].bottom = glyphs[i-32].top + 16; + glyphs[i-32].top *= inv; + glyphs[i-32].bottom *= inv; + } + + g_GLTable.m_pfn_qglGenTextures (1, &texture); + g_GLTable.m_pfn_qglBindTexture (GL_TEXTURE_2D, texture); + g_GLTable.m_pfn_qglDisable (GL_TEXTURE_GEN_S); + g_GLTable.m_pfn_qglDisable (GL_TEXTURE_GEN_T); + g_GLTable.m_pfn_qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + g_GLTable.m_pfn_qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + g_GLTable.m_pfn_qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + g_GLTable.m_pfn_qglTexParameteri (GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // g_GLTable.m_pfn_qglPixelStorei (GL_UNPACK_ALIGNMENT, 1); + + unsigned char *buf = (unsigned char*)malloc (128*128); + memset (buf, 255, 128*128); + + for (i = 0; i < 2048; i++) + for (j = 0; j < 8; j++) + if ((data[i] & (1 << j)) != 0) + buf[i*8+j] = 0; + + g_GLTable.m_pfn_qglTexImage2D (GL_TEXTURE_2D, 0, GL_INTENSITY4, 128, 128, 0, + GL_LUMINANCE, GL_UNSIGNED_BYTE, buf); + free (buf); +} + +void texfont_write (const char *text, float l, float t) +{ + if (texture == 0) + return; + + g_GLTable.m_pfn_qglColor3f (0, 1, 0); + g_GLTable.m_pfn_qglBindTexture (GL_TEXTURE_2D, texture); + g_GLTable.m_pfn_qglEnable (GL_TEXTURE_2D); + // g_GLTable.m_pfn_qglTexEnvi (GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); + g_GLTable.m_pfn_qglAlphaFunc (GL_GREATER, 0.0625); + g_GLTable.m_pfn_qglEnable (GL_ALPHA_TEST); + + g_GLTable.m_pfn_qglBegin (GL_QUADS); + for (const char* p = text; *p; p++) + { + if (*p < 32 || *p > 125) + continue; + if (glyphs[*p-32].width == 0) + continue; + + g_GLTable.m_pfn_qglTexCoord2f (glyphs[*p-32].left, glyphs[*p-32].top); + g_GLTable.m_pfn_qglVertex2f (l, t); + g_GLTable.m_pfn_qglTexCoord2f (glyphs[*p-32].left, glyphs[*p-32].bottom); + g_GLTable.m_pfn_qglVertex2f (l, t-16); + g_GLTable.m_pfn_qglTexCoord2f (glyphs[*p-32].right, glyphs[*p-32].bottom); + g_GLTable.m_pfn_qglVertex2f (l + glyphs[*p-32].width, t-16); + g_GLTable.m_pfn_qglTexCoord2f (glyphs[*p-32].right, glyphs[*p-32].top); + g_GLTable.m_pfn_qglVertex2f (l + glyphs[*p-32].width, t); + l += glyphs[*p-32].width; + } + g_GLTable.m_pfn_qglEnd (); + + g_GLTable.m_pfn_qglDisable (GL_ALPHA_TEST); + g_GLTable.m_pfn_qglDisable (GL_TEXTURE_2D); + g_GLTable.m_pfn_qglBindTexture (GL_TEXTURE_2D, 0); +} diff --git a/contrib/gtkgensurf/gendlgs.cpp b/contrib/gtkgensurf/gendlgs.cpp new file mode 100644 index 00000000..3faf2707 --- /dev/null +++ b/contrib/gtkgensurf/gendlgs.cpp @@ -0,0 +1,2364 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include +#include +#include "gensurf.h" + +#define GENERAL_TAB 0 +#define EXTENTS_TAB 1 +#define BITMAP_TAB 2 +#define FIXPOINTS_TAB 3 +#define TEXTURE_TAB 4 +//#define BUFF_SIZE 32768 + +#define ENABLE_WIDGET(name,enable) \ + gtk_widget_set_sensitive (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), (name))), (enable)) +#define CHECK_WIDGET(name,check) \ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), name)), check) + +static GtkWidget *game_radios[NUMGAMES]; +static GtkWidget *wave_radios[5]; +static GtkWidget *plane_radios[6]; +static guint current_tab; +static int OldPreview; +static int WasDetail; +static GtkTooltips *tooltips; +static int FirstPassComplete = 0; + +void About (GtkWidget *parent) +{ +/* + char *icon_xpm[] = { +"32 32 4 1", +" c None", +". c #000000", +"+ c #FFFFFF", +"@ c #838183", +"................................", +"................................", +"................................", +"................................", +"................................", +"................................", +"................................", +"...............++...............", +".............++++++.............", +"............++@+++@+............", +"..........+++..++..+++..........", +"........++.+.++..++.+.@+........", +".......+..+..+.++.+..+..++......", +".....++..++.+..++..+.++..++.....", +"...++..++...+.+..+.++..++..++...", +"..++.+.++....++..++....++.+..+..", +".+.+..+..++....++....++..++.+.+.", +"..+++....+.++++++++++.+....+++..", +"....++.@@+++++.++.++++@++.++....", +"......+++++++......++@+++++.....", +".......+++.+.++..++.+..++.......", +".........++..+.++.+..++.........", +"...........++..++..++...........", +".............++..+.+............", +"..............+..+@.............", +"...............@@...............", +"................................", +"................................", +"................................", +"................................", +"................................", +"................................" +}; +*/ + // leo: I'm too lazy to create a nice about box + // ^Fishman - I am lazy too :P. + g_FuncTable.m_pfnMessageBox (parent, "GtkGenSurf 1.05\n\n" + "Original version\n" + "David Hyde (rascal@vicksburg.com)\n\n" + "Porting\n" + "Leonardo Zide (leo@lokigames.com)\n\n" + "Enhancements\n" + "Pablo Zurita (pablo@qeradiant.com)\n" + "Hydra (hydra@hydras-world.com)", + "About GtkGenSurf", MB_OK); +} + +// ============================================================================= +// main dialog + +static void SetupControls () +{ + switch (current_tab) + { + case GENERAL_TAB: + break; + + case EXTENTS_TAB: + if (Game != QUAKE3) + { + gtk_widget_hide (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "use_patches"))); + ENABLE_WIDGET ("use_patches", FALSE); + } + else + { + gtk_widget_show (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "use_patches"))); + ENABLE_WIDGET ("use_patches", TRUE); + } + + if (Game == QUAKE3 && UsePatches != 0) + { + ENABLE_WIDGET ("decimate", FALSE); + } + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "snap_text")), "Snap to grid:"); // ^Fishman - Snap to grid. + break; + + case BITMAP_TAB: + if (WaveType != WAVE_BITMAP) + { + ENABLE_WIDGET ("bmp_file", FALSE); + ENABLE_WIDGET ("bmp_file_browse", FALSE); + ENABLE_WIDGET ("bmp_black", FALSE); + ENABLE_WIDGET ("bmp_white", FALSE); + ENABLE_WIDGET ("bmp_text1", FALSE); + ENABLE_WIDGET ("bmp_text2", FALSE); + ENABLE_WIDGET ("bmp_text3", FALSE); + ENABLE_WIDGET ("bmp_reload", FALSE); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "bmp_note")), + "These options are disabled unless \"From Bitmap\"\n" + "is selected as the Waveform on the General tab."); + } + else + { + ENABLE_WIDGET ("bmp_file", TRUE); + ENABLE_WIDGET ("bmp_file_browse", TRUE); + ENABLE_WIDGET ("bmp_black", TRUE); + ENABLE_WIDGET ("bmp_white", TRUE); + ENABLE_WIDGET ("bmp_text1", TRUE); + ENABLE_WIDGET ("bmp_text2", TRUE); + ENABLE_WIDGET ("bmp_text3", TRUE); + ENABLE_WIDGET ("bmp_reload", strlen(gbmp.name) != 0); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "bmp_note")), + "GenSurf works only with 8-bit bitmaps. Color indices are\n" + "mapped to values for each vertex. Generally, gray scale\n" + "images are stored with black as color 0, white as color 255."); + } + break; + + case FIXPOINTS_TAB: + ENABLE_WIDGET ("fix_value", (NumVerticesSelected != 0)); + ENABLE_WIDGET ("fix_value_text", (NumVerticesSelected != 0)); + ENABLE_WIDGET ("fix_free", (NumVerticesSelected != 0)); + ENABLE_WIDGET ("fix_range", ((NumVerticesSelected != 0) && (WaveType != WAVE_ROUGH_ONLY))); + ENABLE_WIDGET ("fix_range_text", ((NumVerticesSelected != 0) && (WaveType != WAVE_ROUGH_ONLY))); + ENABLE_WIDGET ("fix_rate", ((NumVerticesSelected != 0) && (WaveType != WAVE_ROUGH_ONLY))); + ENABLE_WIDGET ("fix_rate_text", ((NumVerticesSelected != 0) && (WaveType != WAVE_ROUGH_ONLY))); + break; + + case TEXTURE_TAB: + ENABLE_WIDGET ("texture2", (UsePatches == 0)); + ENABLE_WIDGET ("texture3", (UsePatches == 0)); + ENABLE_WIDGET ("tex_slant", (UsePatches == 0)); + ENABLE_WIDGET ("detail", (UsePatches == 0)); + if (Game != QUAKE3 ) + { + ENABLE_WIDGET ("terrain_ent", FALSE); // ^Fishman - Adds terrain key to func_group. + ENABLE_WIDGET ("hint", (UsePatches == 0)); + } + break; + } + + switch (WaveType) + { + case WAVE_HCYLINDER: + case WAVE_VCYLINDER: + ENABLE_WIDGET ("amplitude", TRUE); + ENABLE_WIDGET ("wavelength", TRUE); + ENABLE_WIDGET ("z00", TRUE); + ENABLE_WIDGET ("z01", TRUE); + ENABLE_WIDGET ("z10", TRUE); + ENABLE_WIDGET ("z11", TRUE); + ENABLE_WIDGET ("linearborder", TRUE); + ENABLE_WIDGET ("go", TRUE); + break; + case WAVE_BITMAP: + ENABLE_WIDGET ("amplitude", FALSE); + ENABLE_WIDGET ("wavelength", FALSE); + ENABLE_WIDGET ("z00", FALSE); + ENABLE_WIDGET ("z01", FALSE); + ENABLE_WIDGET ("z10", FALSE); + ENABLE_WIDGET ("z11", FALSE); + ENABLE_WIDGET ("linearborder", FALSE); + ENABLE_WIDGET ("go", (gbmp.colors != NULL ? TRUE : FALSE)); + break; + case WAVE_ROUGH_ONLY: + ENABLE_WIDGET ("amplitude", FALSE); + ENABLE_WIDGET ("wavelength", FALSE); + ENABLE_WIDGET ("z00", TRUE); + ENABLE_WIDGET ("z01", TRUE); + ENABLE_WIDGET ("z10", TRUE); + ENABLE_WIDGET ("z11", TRUE); + ENABLE_WIDGET ("linearborder", TRUE); + ENABLE_WIDGET ("go", TRUE); + break; + default: + ENABLE_WIDGET ("amplitude", TRUE); + ENABLE_WIDGET ("wavelength", TRUE); + ENABLE_WIDGET ("z00", TRUE); + ENABLE_WIDGET ("z01", TRUE); + ENABLE_WIDGET ("z10", TRUE); + ENABLE_WIDGET ("z11", TRUE); + ENABLE_WIDGET ("linearborder", TRUE); + ENABLE_WIDGET ("go", TRUE); + } + + switch (Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmin_text")), "X:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmax_text")), "X:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmin_text")), "Z:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmax_text")), "Z:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nh_text")), "X:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nv_text")), "Z:"); + break; + case PLANE_YZ0: + case PLANE_YZ1: + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmin_text")), "Y:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmax_text")), "Y:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmin_text")), "Z:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmax_text")), "Z:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nh_text")), "Y:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nv_text")), "Z:"); + break; + default: + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmin_text")), "X:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "hmax_text")), "X:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmin_text")), "Y:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "vmax_text")), "Y:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nh_text")), "X:"); + gtk_label_set_text (GTK_LABEL (g_object_get_data (G_OBJECT (g_pWnd), "nv_text")), "Y:"); + break; + } +} + +// SetDlgValues fills in text boxes and initializes other input controls +static void SetDlgValues (int tab) +{ + char Text[256]; + char RForm[16] = "%.5g"; + int i; + + switch (tab) + { + case GENERAL_TAB: + // Hell if I know why, but in the release build the 2nd pass thru the + // set_sensitive loop for game_radios crashes. No need to do this more + // than once anyhow. + if (!FirstPassComplete) + { + for (i = 0; i < NUMGAMES; i++) + gtk_widget_set_sensitive (game_radios[i], (i == Game ? TRUE : FALSE)); + for (i = 0; i < 6; i++) + gtk_widget_set_sensitive (plane_radios[i], (i == Plane ? TRUE : FALSE)); + } + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (game_radios[Game]), TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (plane_radios[Plane]), TRUE); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (wave_radios[WaveType]), TRUE); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "random")), + RandomSeed); + sprintf (Text, RForm, WaveLength); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "wavelength")), Text); + sprintf (Text, RForm, Amplitude); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "amplitude")), Text); + sprintf (Text, RForm, Roughness); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "roughness")), Text); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data + (G_OBJECT (g_pWnd), "main_antialiasing")), Antialiasing); + break; + + case EXTENTS_TAB: + sprintf (Text,RForm,Hll); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "hmin")), Text); + sprintf (Text,RForm,Vll); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "vmin")), Text); + sprintf (Text,RForm,Hur); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "hmax")), Text); + sprintf (Text,RForm,Vur); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "vmax")), Text); + sprintf (Text,RForm,Z00); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "z00")), Text); + sprintf (Text,RForm,Z01); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "z01")), Text); + sprintf (Text,RForm,Z10); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "z10")), Text); + sprintf (Text,RForm,Z11); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "z11")), Text); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "nh")), NH); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "nv")), NV); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "sp")), SP); // ^Fishman - Snap to grid. + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data + (G_OBJECT (g_pWnd), "linearborder")), FixBorders); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data + (G_OBJECT (g_pWnd), "use_patches")), UsePatches); + gtk_adjustment_set_value (GTK_ADJUSTMENT (g_object_get_data (G_OBJECT (g_pWnd), "decimate_adj")), + Decimate); + + if (Game == QUAKE3 && UsePatches) + { + gtk_widget_set_sensitive (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "decimate")), FALSE); + + if (NH % 2) + { + NH++; + if (NH > MAX_ROWS) NH -= 2; + SetDlgValues (current_tab); + } + + if (NV % 2) + { + NV++; + if (NV > MAX_ROWS) NV -= 2; + SetDlgValues (current_tab); + } + if (NH % 2 ) NH++; + if (NH < 2 ) NH = 2; + if (NH > MAX_ROWS) NH = MAX_ROWS; + if (NV % 2 ) NV++; + if (NV < 2 ) NV = 2; + if (NV > MAX_ROWS) NV = MAX_ROWS; + + gpointer spin = g_object_get_data (G_OBJECT (g_pWnd), "nh"); + GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adj->lower = 2; + gtk_adjustment_changed (adj); + spin = g_object_get_data (G_OBJECT (g_pWnd), "nv"); + adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adj->lower = 2; + gtk_adjustment_changed (adj); + } + else + { + gtk_widget_set_sensitive (GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "decimate")), TRUE); + + gpointer spin = g_object_get_data (G_OBJECT (g_pWnd), "nh"); + GtkAdjustment *adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adj->lower = 1; + gtk_adjustment_changed (adj); + spin = g_object_get_data (G_OBJECT (g_pWnd), "nv"); + adj = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (spin)); + adj->lower = 1; + gtk_adjustment_changed (adj); + } + + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "nh")), NH); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "nv")), NV); + + break; + + case BITMAP_TAB: + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file")), gbmp.name); + sprintf(Text,"%g",gbmp.black_value); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_black")), Text); + sprintf(Text,"%g",gbmp.white_value); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_white")), Text); + break; + + case FIXPOINTS_TAB: + break; + + case TEXTURE_TAB: + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texture1")), Texture[Game][0]); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texture2")), Texture[Game][1]); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texture3")), Texture[Game][2]); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "tex_slant")), + SlantAngle); + sprintf(Text,RForm,TexOffset[0]); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texoffsetx")), Text); + sprintf(Text,RForm,TexOffset[1]); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texoffsety")), Text); + sprintf(Text,RForm,TexScale[0]); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texscalex")), Text); + sprintf(Text,RForm,TexScale[1]); + gtk_entry_set_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "texscaley")), Text); + CHECK_WIDGET ("detail", UseDetail); + + if (Game==QUAKE3) + { + ENABLE_WIDGET ("hint", FALSE); + AddHints=0; + } + else + ENABLE_WIDGET ("hint", TRUE); + CHECK_WIDGET ("hint", AddHints); + + /* + if (Game==SIN) + { + // ArghRad doesn't currently support SiN + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); + SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use sin file"); + SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"Sin:"); + } + */ + + if(Game==QUAKE3) + { + /* + // ArghRad sun is inapplicable (so far) + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); + // No ladders in Q3 + EnableWindow(GetDlgItem(hwndDisplay,DLG_LADDER), 0); + ShowWindow(GetDlgItem(hwndDisplay,DLG_LADDER), SW_HIDE); + SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use pk3 file"); + SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"PK3:"); + */ + } + +/*trix if(Game==HERETIC2) + { + // ArghRad doesn't currently support Heretic2 + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); + + SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use pak file"); + SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"Pak:"); + } */ + /* + if(Game==HALFLIFE) + { + // A bunch of controls aren't applicable to HL + EnableWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE_BROWSE), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE2_BROWSE),0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE3_BROWSE),0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_DETAIL), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_LADDER), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); + ShowWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE_BROWSE), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE2_BROWSE),SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_TEXTURE3_BROWSE),SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_DETAIL), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_LADDER), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); + + SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use wad file"); + SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"Wad:"); + SetDlgItemText(hwndDisplay,DLG_HINT,"Hint brushes"); + } + + if(Game==GENESIS3D) + { + // No Q2-type compilers support Genesis3D (including ArghRad) + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), 0); + EnableWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), 0); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_TEXT), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2), SW_HIDE); + ShowWindow(GetDlgItem(hwndDisplay,DLG_ARGHRAD2_SPIN), SW_HIDE); + + SetDlgItemText(hwndDisplay,DLG_TEX_USEPAK,"Use sin file"); + SetDlgItemText(hwndDisplay,DLG_TEX_PAK_TEXT,"Sin:"); + } + */ + break; + } + SetupControls (); +} + +static void ReadDlgValues (int tab) +{ + // char Text[256]; + // int i; + + switch (tab) + { + case GENERAL_TAB: + gpointer spin; + Roughness = atof ( gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "roughness")))); + WaveLength = atof ( gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "wavelength")))); + Amplitude = atof ( gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "amplitude")))); + spin = g_object_get_data (G_OBJECT (g_pWnd), "random"); + RandomSeed = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (spin)); + break; + + case EXTENTS_TAB: + SP = atoi (gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "sp")))); + NH = atoi (gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "nh")))); + NV = atoi (gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "nv")))); + + if (Game == QUAKE3 && UsePatches != 0) + { + if (NH % 2 ) NH++; + if (NH < 2 ) NH = 2; + if (NH > MAX_ROWS) NH = MAX_ROWS; + if (NV % 2 ) NV++; + if (NV < 2 ) NV = 2; + if (NV > MAX_ROWS) NV = MAX_ROWS; + } + break; + +#if 0 + case BITMAP_TAB: + + if (WaveType == WAVE_BITMAP) + { + GetDlgItemText(hwnd,DLG_BMP_FILE,gbmp.name,sizeof(gbmp.name)); + CheckValidDIB(hwnd); + GetDlgItemText(hwnd,DLG_BMP_BLACK,Text,sizeof(Text)); + gbmp.black_value = atof(Text); + GetDlgItemText(hwnd,DLG_BMP_WHITE,Text,sizeof(Text)); + gbmp.white_value = atof(Text); + UpdatePreview(TRUE); + } + break; + + case FIXPOINTS_TAB: + GetDlgItemText(hwnd,DLG_FIX_VALUE,Text,sizeof(Text)); + temp.fixed_value = atoi(Text); + GetDlgItemText(hwnd,DLG_FIX_RANGE,Text,sizeof(Text)); + temp.range = atoi(Text); + GetDlgItemText(hwnd,DLG_FIX_RATE, Text,sizeof(Text)); + temp.rate = atof(Text); + for(k=0; k MAX_ROWS) + { + sprintf (Text, "The number of divisions must be > 0 and no greater than %d.", MAX_ROWS); + g_FuncTable.m_pfnMessageBox (g_pWnd, Text, "GenSurf", MB_ICONEXCLAMATION); + gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); + return; + } + + if (NV < 1 || NV > MAX_ROWS) + { + sprintf (Text, "The number of divisions must be > 0 and no greater than %d.", MAX_ROWS); + g_FuncTable.m_pfnMessageBox (g_pWnd, Text, "GenSurf", MB_ICONEXCLAMATION); + gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); + return; + } + + if (Hll >= Hur) + { + g_FuncTable.m_pfnMessageBox (g_pWnd, "The \"lower-left\" values must be less than " + "the corresponding \"upper-right\" values in " + "the \"Extent\" box.","GenSurf", MB_OK | MB_ICONEXCLAMATION); + gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); + return; + } + + if (Vll >= Vur) + { + g_FuncTable.m_pfnMessageBox (g_pWnd,"The \"lower-left\" values must be less than " + "the corresponding \"upper-right\" values in " + "the \"Extent\" box.","GenSurf", MB_OK | MB_ICONEXCLAMATION); + gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); + return; + } + + if (!strlen (Texture[Game][0])) + { + g_FuncTable.m_pfnMessageBox (g_pWnd, "You must supply a texture name.", "GenSurf", MB_ICONEXCLAMATION); + gtk_notebook_set_page (GTK_NOTEBOOK (notebook), EXTENTS_TAB); + return; + } + +/* if (Decimate>0 && GimpHints!=0) + { + MessageBox(hwnd,"You've elected to use a decimated grid and gimp's non-detail hint brushes. " + "This combination usually produces bizarre visual errors in the game, " + "so GenSurf has turned off the hint brush option.", + "GenSurf",MB_ICONEXCLAMATION); + GimpHints = 0; + } */ + + gtk_widget_hide (g_pWnd); + if (g_pWndPreview) + gtk_widget_hide (g_pWndPreview); + + GenerateMap(); + WriteIniFile(gszIni); +} + +// ============================================================================= +// general tab callbacks + +static void general_game (GtkToggleButton *widget, gpointer data) +{ + if (gtk_toggle_button_get_active (widget)) + { + Game = GPOINTER_TO_INT (data); + UpdatePreview (TRUE); + } +} + +static void general_plane (GtkToggleButton *widget, gpointer data) +{ + if (gtk_toggle_button_get_active (widget)) + { + Plane = GPOINTER_TO_INT (data); + SetupControls (); + UpdatePreview (TRUE); + } +} + +static void general_wave (GtkToggleButton *widget, gpointer data) +{ + if (gtk_toggle_button_get_active (widget)) + { + WaveType = GPOINTER_TO_INT (data); + SetupControls (); + UpdatePreview (TRUE); + } +} + +static void general_random (GtkAdjustment *adj, gpointer data) +{ + int nPos = (int)adj->value; + + if (RandomSeed != nPos) + { + RandomSeed = nPos; + UpdatePreview (true); + } +} + +// ============================================================================= +// extents tab callbacks + +static void extents_linearborder (GtkToggleButton *check, gpointer data) +{ + FixBorders = gtk_toggle_button_get_active (check); + UpdatePreview (true); +} + +static void extents_use_patches (GtkToggleButton *check, gpointer data) +{ + if (Game != QUAKE3) + return; + + UsePatches = gtk_toggle_button_get_active (check); + SetDlgValues (current_tab); + SetupControls (); + UpdatePreview (true); +} + +static void extents_nhnv_spin (GtkAdjustment *adj, int *data) +{ + int nPos = (int)adj->value; + + if (*data != nPos) + { + if (Game==QUAKE3 && UsePatches && (nPos % 2)) + { + if (*data < nPos) + *data += 2; + else + *data -= 2; + gtk_adjustment_set_value (adj, *data); + } + else + *data = nPos; + UpdatePreview (true); + } +} + +static void extents_decimate (GtkAdjustment *adj, gpointer data) +{ + int nPos = (int)adj->value; + + Decimate = nPos; + UpdatePreview (true); +} + +// Hydra : snap to grid begin +/*static void extents_snaptogrid (GtkAdjustment *adj, gpointer data) +{ + int nPos = (int)adj->value; + + SnapToGrid = nPos; + UpdatePreview (true); +}*/ + +// ^Fishman - Modified version of Hydra's snap to grid code. +static void extents_snaptogrid_spin (GtkAdjustment *adj, int *data) +{ + int nPos = (int)adj->value; + SnapToGrid = nPos; + UpdatePreview (true); +} + +// ============================================================================= +// bitmap tab callbacks + +static gint bitmap_file_entryfocusout(GtkWidget* widget, GdkEventFocus* event, gpointer data) +{ + char filename[NAME_MAX]; + + strcpy (filename, gtk_entry_get_text (GTK_ENTRY(widget))); + if(strcmp (filename,gbmp.name)) + { + if (gbmp.colors) + { + free(gbmp.colors); + gbmp.colors=NULL; + } + strcpy (gbmp.name,filename); + if (strlen(gbmp.name) ) + OpenBitmap (); + ENABLE_WIDGET ("go", (gbmp.colors != NULL ? TRUE : FALSE)); + } + return FALSE; +} + +static void bitmap_browse (GtkWidget *widget, gpointer data) +{ + const char *filename; + char *ptr; + + filename = g_FuncTable.m_pfnFileDialog (g_pWnd, TRUE, "Bitmap File", gbmp.defpath); + + if (filename != NULL) + { + strcpy (gbmp.name, filename); + + ptr = strrchr (filename, G_DIR_SEPARATOR); + if (ptr != NULL) + { + *(ptr+1) = '\0'; + strcpy (gbmp.defpath, filename); + } + + OpenBitmap (); + ENABLE_WIDGET ("go", (gbmp.colors != NULL ? TRUE : FALSE)); + } +} + +static void bitmap_reload (GtkWidget *widget, gpointer data) +{ + strcpy (gbmp.name, gtk_entry_get_text (GTK_ENTRY (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file")))); + if(strlen (gbmp.name) ) + { + OpenBitmap (); + ENABLE_WIDGET ("go", (gbmp.colors != NULL ? TRUE : FALSE)); + } + else + ENABLE_WIDGET ("go", FALSE ); +} + +// ============================================================================= +// fix points tab callbacks + +static gint fix_value_entryfocusout (GtkWidget* widget, GdkEventFocus *event, gpointer data) +{ + int i = atoi (gtk_entry_get_text (GTK_ENTRY(widget))), k; + char Text[32]; + + if (i < -65536 || i > 65536) + { + gdk_beep (); + g_FuncTable.m_pfnMessageBox (g_pWnd, "The value must be between -65536 and 65536, inclusive.", + "GenSurf", MB_OK | MB_ICONEXCLAMATION); + sprintf (Text, "%d", (int)xyz[Vertex[0].i][Vertex[0].j].fixed_value); + gtk_entry_set_text (GTK_ENTRY(widget), Text); + gtk_window_set_focus (GTK_WINDOW (gtk_widget_get_toplevel (widget)), widget); + } + else if (i != xyz[Vertex[0].i][Vertex[0].j].fixed_value) + { + for(k=0; kvalue; + + if (xyz[Vertex[0].i][Vertex[0].j].fixed_value != i) + { + for(k=0; k(data)); + return FALSE; +} + +// ============================================================================= +// create tooltips + +void create_tooltips () +{ + tooltips = gtk_tooltips_new (); + + // Main + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "go")), + "Accept all input and generate a surface in Q3Radiant", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "open")), + "Open a previously saved GenSurf settings file.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "save")), + "Save all settings to a file.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "defaults")), + "Restore default values from DEFAULTS.SRF. If this file does not exist, GenSurf " + "initializes all input parameters to reasonable values. You can create your own " + "default surface by setting all parameters to your liking, then saving a settings " + "file as DEFAULTS.SRF with the Save As button.", + ""); + + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "main_preview")), + "View a wire-frame representation of the surface", + ""); + + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "main_antialiasing")), + "The lines in the preview window are antialiased for better quality", + ""); + + // General tab + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (wave_radios[0]), + "Builds a surface with alternating hills and valleys. Uses the general form Z=cos(X) " + "x sin(Y)", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (wave_radios[1]), + "Builds a surface with ridges parallel to the vertical axis.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (wave_radios[2]), + "Builds a surface with ridges parallel to the horizontal axis.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (wave_radios[3]), + "Builds a map from a bitmap image representing a contour plot. Click the \"Bitmap\" " + "tab to select the image. GenSurf only supports 256-color (8 bit) " + "bitmaps. GenSurf will work with any 256-color bitmap, but gray scale bitmaps are a bit " + "more intuitive.", + "" ); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (wave_radios[4]), + "Builds a random surface using the Plasma Cloud technique. Variance is controlled " + "by the Roughness input. To build a surface with completely random values not " + "dependent on neighboring vertices, use one of the other waveforms with 0 amplitude.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "wavelength")), + "Enter the wavelength (distance between crests). NOTE: Wavelengths equal to the grid " + "size or 2 times the grid size will result in 0 amplitudes. For best results, the " + "wavelength value should be at least 4 times the grid size (extents divided by the " + "number of divisions", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "amplitude")), + "Enter the height of hills/ridges.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "roughness")), + "Enter the roughness value (noise) for the surface. For fractal surfaces, this value " + "is used as a variance in the fractal calculations.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "random")), + "Seed value for the pseudo-random number generator.", + ""); + // Extents tab + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "hmin")), + "Minimum horizontal coordinate of the surface, i.e. X for a surface parallel to " + "the XY or XZ planes, Y for a surface parallel to the YZ plane. For best results, " + "the extents (maximum-minimum values) in a given direction should be evenly " + "divisible by the number of divisions in that direction.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "hmax")), + "Maximum horizontal coordinate of the surface, i.e. X for a surface parallel to " + "the XY or XZ planes, Y for a surface parallel to the YZ plane. For best results, " + "the extents (maximum-minimum values) in a given direction should be evenly " + "divisible by the number of divisions in that direction.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "vmin")), + "Minimum vertical coordinate of the surface, i.e. Y for a surface parallel to " + "the XY plane, Z for a surface parallel to the XZ or YZ planes. For best results, " + "the extents (maximum-minimum values) in a given direction should be evenly " + "divisible by the number of divisions in that direction.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "vmax")), + "Maximum vertical coordinate of the surface, i.e. Y for a surface parallel to " + "the XY plane, Z for a surface parallel to the XZ or YZ planes. For best results, " + "the extents (maximum-minimum values) in a given direction should be evenly " + "divisible by the number of divisions in that direction.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "nh")), + "Number of divisions in the horizontal direction. For best results, the extents " + "in a given direction should be evenly divisible by the number of divisions in " + "that direction.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "nv")), + "Number of divisions in the vertical direction. For best results, the extents " + "in a given direction should be evenly divisible by the number of divisions in " + "that direction.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "use_patches")), + "Produce one or more curved patches in the shape of your selected surface rather " + "than producing solid brushes. Depending on the size of your surface (and the " + "user's graphic detail settings, which you cannot control), curved surfaces will " + "be represented in the game by a very large number of polygons. Read the warnings " + "concerning curved surfaces on the GenSurf web page before using this feature.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "decimate")), + "Use the slider to control the number of vertices discarded by GenSurf. For many " + "surfaces, you can produce roughly the same shape surface with a high decimation " + "value. This will generally result in a map with lower polygon counts (and better " + "in-game performance). However, this feature should NOT be used for large terrain " + "surfaces in Q3", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "z00")), + "Enter the height of the surface at the lower left corner. This value will likely " + "be modified unless \"Linear Borders\" is checked.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "z01")), + "Enter the height of the surface at the upper left corner. This value will likely " + "be modified unless \"Linear Borders\" is checked.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "z10")), + "Enter the height of the surface at the lower right corner. This value will likely " + "be modified unless \"Linear Borders\" is checked.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "z11")), + "Enter the height of the surface at the upper right corner. This value will likely " + "be modified unless \"Linear Borders\" is checked.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "linearborder")), + "Restrict the edges of the surface to a straight line. This will help match up " + "brush edges if you drop this surface into another map.", + ""); + // Bitmap tab + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file")), + "Type the name of an 8-bit bitmap image file, or click Browse to select an image " + "from a list of those available on your system.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_file_browse")), + "Select a bitmap image file from a list of those available on your system.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_reload")), + "Reload the selected bitmap file after making changes in an external image editor.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_black")), + "Enter the value corresponding to color index 0 in the bitmap file. For gray scale " + "images, color 0 is normally black.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "bmp_white")), + "Enter the value corresponding to color index 255 in the bitmap file. For gray scale " + "images, color 255 is normally white.", + ""); + // Fixpoints tab + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_value")), + "Enter a value for the selected vertex. This value will not be adjusted when applying " + "a waveform or roughness to the surface. Unlock this vertex (so that it will be " + "adjusted normally) by clicking \"Free\". This vertex will influence vertices within " + "the \"Range affected\" of this vertex.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_range")), + "Enter the range away from the selected vertex that other vertices will be affected. " + "Use 0 if you don't want other vertices to be influenced by the currently selected " + "one. Note: this box is disabled if you've chosen the fractal generator, as it uses " + "a completely different method for determining values.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_rate")), + "Enter a rate of change for the surface affected by the fixed value. 0 gives a smooth " + "sinusoidal curve, values less than 0 give progressively sharper spikes, and values " + "greater than 0 take on a square shape. Values less than -30 or greater than 30 are " + "set to -30 and 30, respectively. Note that this entry will have no effect unless " + "you also specify a \"range affected\".", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_free")), + "Click this to free (unlock the value of) the currently selected vertex.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "fix_freeall")), + "Click this to free (unlock the values of) all vertices.", + ""); + // Texture tab + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "texture1")), + "Enter the name of the texture or shader used for the surface faces.", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "texture2")), + "Enter the name of the texture or shader used for faces other than the surface. Under " + "normal circumstances this should be \"common/caulk\"", + ""); + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "texture3")), + "Enter the name of the texture or shader used for \"steep\" surface faces, where \"steep\" " + "is the angle specified below. If this entry is left blank or if the \"steep\" angle is 0, " + "all surface faces will use the texture specified by \"Surface\".", + ""); + + gtk_tooltips_set_tip(GTK_TOOLTIPS (tooltips), + GTK_WIDGET (g_object_get_data (G_OBJECT (g_pWnd), "detail")), + "Check this box to use the detail content property on the generated brushes. Compile " + "times will be considerably shorter if the detail property is used, though the surface " + "will not block visibility at all. If you use the detail property, you should make sure " + "that \"common/caulk\" is used for the non-surface faces, or the polygon count will be " + "much higher than necessary.", + ""); +} + +// ============================================================================= +// create main dialog + +GtkWidget* create_main_dialog () +{ + GtkWidget *dlg, *vbox, *hbox, *hbox2, *button, *notebook, *frame, *table, *table2; + GtkWidget *check, *spin, *radio, *label, *entry, *scale; + GtkObject *adj; + GSList *group; + int i; + char *games[] = { "Quake 2", "Half-Life", "SiN", "Heretic 2", "Kingpin", "Genesis3D", "Quake 3 Arena" }; + char *waveforms[] = { "Alternating hill/valley", "Cylindrical left-to-right", "Cylindrical top-to-bottom", + "From bitmap", "Fractal" }; + char *orientations[] = { "Ground surface", "Ceiling", "Wall facing 0", "Wall facing 90", + "Wall facing 180","Wall facing 270" }; + + g_pWnd = dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), gszCaption); + g_signal_connect (G_OBJECT (dlg), "delete_event", G_CALLBACK (main_close), NULL); + // g_signal_connect (G_OBJECT (dlg), "destroy", G_CALLBACK (gtk_widget_destroy), NULL); + gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pRadiantWnd)); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 5); + + notebook = gtk_notebook_new (); + gtk_widget_show (notebook); + gtk_box_pack_start (GTK_BOX (hbox), notebook, TRUE, TRUE, 0); + g_signal_connect (G_OBJECT (notebook), "switch_page", + G_CALLBACK (switch_page), NULL); + gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP); + g_object_set_data (G_OBJECT (dlg), "notebook", notebook); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("General"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), table, label); + + frame = gtk_frame_new ("Game"); + gtk_widget_show (frame); + gtk_table_attach (GTK_TABLE (table), frame, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + vbox = gtk_vbox_new (TRUE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (frame), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + for (i = 0, group = NULL; i < NUMGAMES; i++) + { + radio = gtk_radio_button_new_with_label (group, games[i]); + gtk_widget_show (radio); + gtk_box_pack_start (GTK_BOX (vbox), radio, TRUE, TRUE, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio)); + game_radios[i] = radio; + g_signal_connect (G_OBJECT (radio), "toggled", G_CALLBACK (general_game), GINT_TO_POINTER (i)); + } + + frame = gtk_frame_new ("Waveform"); + gtk_widget_show (frame); + gtk_table_attach (GTK_TABLE (table), frame, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + vbox = gtk_vbox_new (TRUE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (frame), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + for (i = 0, group = NULL; i < 5; i++) + { + radio = gtk_radio_button_new_with_label (group, waveforms[i]); + gtk_widget_show (radio); + gtk_box_pack_start (GTK_BOX (vbox), radio, TRUE, TRUE, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio)); + wave_radios[i] = radio; + g_signal_connect (G_OBJECT (radio), "toggled", G_CALLBACK (general_wave), GINT_TO_POINTER (i)); + } + + frame = gtk_frame_new ("Orientation"); + gtk_widget_show (frame); + gtk_table_attach (GTK_TABLE (table), frame, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + vbox = gtk_vbox_new (TRUE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (frame), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + for (i = 0, group = NULL; i < 6; i++) + { + radio = gtk_radio_button_new_with_label (group, orientations[i]); + gtk_widget_show (radio); + gtk_box_pack_start (GTK_BOX (vbox), radio, TRUE, TRUE, 0); + group = gtk_radio_button_group (GTK_RADIO_BUTTON (radio)); + plane_radios[i] = radio; + g_signal_connect (G_OBJECT (radio), "toggled", G_CALLBACK (general_plane), GINT_TO_POINTER (i)); + } + + table2 = gtk_table_new (4, 2, FALSE); + gtk_widget_show (table2); + gtk_table_set_row_spacings (GTK_TABLE (table2), 5); + gtk_table_set_col_spacings (GTK_TABLE (table2), 5); + gtk_table_attach (GTK_TABLE (table), table2, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + label = gtk_label_new ("Wavelength:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + + label = gtk_label_new ("Max. amplitude:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + + label = gtk_label_new ("Roughness:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + + label = gtk_label_new ("Random seed:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table2), label, 0, 1, 3, 4, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table2), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "wavelength", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &WaveLength); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table2), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "amplitude", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Amplitude); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table2), entry, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "roughness", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Roughness); + + adj = gtk_adjustment_new (1, 1, 32767, 1, 10, 10); + g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (general_random), NULL); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table2), spin, 1, 2, 3, 4, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + g_object_set_data (G_OBJECT (dlg), "random", spin); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + label = gtk_label_new ("Extents"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, TRUE, 0); + + frame = gtk_frame_new ("Extents"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox2), frame, TRUE, TRUE, 0); + + table = gtk_table_new (3, 4, FALSE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("X:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "hmin_text", label); + + label = gtk_label_new ("X:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "hmax_text", label); + + label = gtk_label_new ("Y:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "vmin_text", label); + + label = gtk_label_new ("Y:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "vmax_text", label); + + label = gtk_label_new ("Lower-left"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Upper-right"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "hmin", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Hll); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "hmax", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Hur); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "vmin", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Vll); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "vmax", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Vur); + + frame = gtk_frame_new ("Divisions"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (hbox2), frame, TRUE, TRUE, 0); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("X:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "nh_text", label); + + label = gtk_label_new ("Y:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "nv_text", label); + + adj = gtk_adjustment_new (8, 1, MAX_ROWS, 1, 10, 10); + g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (extents_nhnv_spin), &NH); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + g_object_set_data (G_OBJECT (dlg), "nh", spin); + + adj = gtk_adjustment_new (8, 1, MAX_ROWS, 1, 10, 10); + g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (extents_nhnv_spin), &NV); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + g_object_set_data (G_OBJECT (dlg), "nv", spin); + + check = gtk_check_button_new_with_label ("Use Bezier patches"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "use_patches", check); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (extents_use_patches), NULL); + + // ^Fishman - Snap to grid, replaced scroll bar with a texbox. + label = gtk_label_new ("Snap to grid:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); + gtk_object_set_data (GTK_OBJECT (dlg), "snap_text", label); + + adj = gtk_adjustment_new (8, 0, 256, 1, 10, 10); + g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (extents_snaptogrid_spin), &SP); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_box_pack_start (GTK_BOX (vbox), spin, FALSE, TRUE, 0); + gtk_widget_set_usize (spin, 60, -2); + g_object_set_data (G_OBJECT (dlg), "sp", spin); + // ^Fishman - End of Snap to grid code. + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, TRUE, 10); + + label = gtk_label_new ("Decimate:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 0); + + adj = gtk_adjustment_new (0, 0, 110, 1, 10, 10); + g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (extents_decimate), NULL); + g_object_set_data (G_OBJECT (dlg), "decimate_adj", adj); + scale = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (scale); + gtk_box_pack_start (GTK_BOX (hbox2), scale, TRUE, TRUE, 0); + gtk_scale_set_value_pos (GTK_SCALE (scale), GTK_POS_RIGHT); + gtk_scale_set_digits (GTK_SCALE (scale), 0); + g_object_set_data (G_OBJECT (dlg), "decimate", scale); + + frame = gtk_frame_new ("Corner values"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, FALSE, TRUE, 0); + + table = gtk_table_new (3, 4, FALSE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_container_add (GTK_CONTAINER (frame), table); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Upper-left:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Lower-left:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Upper-right:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Lower-right:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "z01", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Z01); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "z00", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Z00); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "z11", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Z11); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "z10", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &Z10); + + check = gtk_check_button_new_with_label ("Linear borders"); + gtk_widget_show (check); + gtk_table_attach (GTK_TABLE (table), check, 0, 4, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "linearborder", check); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (extents_linearborder), NULL); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_widget_show (vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + label = gtk_label_new ("Bitmap"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + + label = gtk_label_new (""); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "bmp_note", label); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Filename:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "bmp_text1", label); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "bmp_file", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (bitmap_file_entryfocusout), NULL); + + hbox2 = gtk_hbox_new (TRUE, 5); + gtk_widget_show (hbox2); + gtk_table_attach (GTK_TABLE (table), hbox2, 1, 2, 1, 2, + (GtkAttachOptions) (0), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + button = gtk_button_new_with_label ("Browse..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); + gtk_widget_set_usize (button, 60, -2); + g_object_set_data (G_OBJECT (dlg), "bmp_file_browse", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (bitmap_browse), NULL); + + button = gtk_button_new_with_label ("Reload"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox2), button, FALSE, FALSE, 0); + gtk_widget_set_usize (button, 60, -2); + g_object_set_data (G_OBJECT (dlg), "bmp_reload", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (bitmap_reload), NULL); + + table = gtk_table_new (2, 2, TRUE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Map color 0 to:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "bmp_text2", label); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + + label = gtk_label_new ("Map color 255 to:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL|GTK_EXPAND), + (GtkAttachOptions) (GTK_FILL), 0, 0); + g_object_set_data (G_OBJECT (dlg), "bmp_text3", label); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_RIGHT); + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_table_attach (GTK_TABLE (table), hbox2, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (hbox2), entry, FALSE, FALSE, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "bmp_black", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &gbmp.black_value); + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_table_attach (GTK_TABLE (table), hbox2, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), 0, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_box_pack_start (GTK_BOX (hbox2), entry, FALSE, FALSE, 0); + gtk_widget_set_usize (entry, 50, -2); + g_object_set_data (G_OBJECT (dlg), "bmp_white", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (doublevariable_entryfocusout), &gbmp.white_value); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_widget_show (vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + label = gtk_label_new ("Fix Points"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + + label = gtk_label_new ("Click on a vertex in the lower half of the preview window,\n" + "then use the arrow keys or text box to assign a value.\n" + "Use Ctrl+Click to select multiple vertices/toggle a\n" + "selection. Use Shift+Click to select a range of vertices.\n\n" + "Click \"Free\" to unlock a vertex. Vertices within \"Range\n" + "affected\" will be influenced by this vertex."); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); + + table = gtk_table_new (3, 3, FALSE); + gtk_widget_show (table); + gtk_container_set_border_width (GTK_CONTAINER (table), 5); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Value:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + g_object_set_data (G_OBJECT (dlg), "fix_value_text", label); + + label = gtk_label_new ("Range affected:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + g_object_set_data (G_OBJECT (dlg), "fix_range_text", label); + + label = gtk_label_new ("Rate of change:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + g_object_set_data (G_OBJECT (dlg), "fix_rate_text", label); + + adj = gtk_adjustment_new (0, -65536, 65536, 1, 16, 16); + g_signal_connect (G_OBJECT (adj), "value_changed", G_CALLBACK (fix_value_changed), NULL); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_table_attach (GTK_TABLE (table), spin, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (GTK_EXPAND), 0, 0); + gtk_widget_set_usize (spin, 60, -2); + g_object_set_data (G_OBJECT (dlg), "fix_value", spin); + g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (fix_value_entryfocusout), NULL); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "fix_range", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (fix_range_entryfocusout), NULL); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "fix_rate", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK (fix_rate_entryfocusout), NULL); + + button = gtk_button_new_with_label ("Free"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 0, 1, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (button, 60, -2); + g_object_set_data (G_OBJECT (dlg), "fix_free", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (fix_free), NULL); + + button = gtk_button_new_with_label ("Free All"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (button, 60, -2); + g_object_set_data (G_OBJECT (dlg), "fix_freeall", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (fix_freeall), NULL); + + vbox = gtk_vbox_new (FALSE, 10); + gtk_widget_show (vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + label = gtk_label_new ("Texture"); + gtk_widget_show (label); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), vbox, label); + + // ^Fishman - Modified to add more labels and textboxes. + table = gtk_table_new (5, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Surface:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + label = gtk_label_new ("Other:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + label = gtk_label_new ("Steep:"); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 1, 2, 3, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texture1", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK(texture_entryfocusout), GINT_TO_POINTER (0)); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texture2", entry); + g_signal_connect (G_OBJECT (entry), "focus_out_event", G_CALLBACK(texture_entryfocusout), GINT_TO_POINTER (1)); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 2, 3, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texture3", entry); + + hbox2 = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox2); + gtk_box_pack_start (GTK_BOX (vbox), hbox2, FALSE, TRUE, 0); + + label = gtk_label_new ("\"Steep\" angle:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox2), label, FALSE, TRUE, 0); + + adj = gtk_adjustment_new (60, 0, 90, 1, 10, 10); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_box_pack_start (GTK_BOX (hbox2), spin, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "tex_slant", spin); + + table = gtk_table_new (2, 4, TRUE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox), table, FALSE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + label = gtk_label_new ("Offset "); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 0, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + label = gtk_label_new ("Scale "); + gtk_widget_show (label); + gtk_table_attach (GTK_TABLE (table), label, 2, 4, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texoffsetx", entry); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texoffsety", entry); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texscalex", entry); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_table_attach (GTK_TABLE (table), entry, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (GTK_FILL), 0, 0); + gtk_widget_set_usize (entry, 60, -2); + g_object_set_data (G_OBJECT (dlg), "texscaley", entry); + + + + check = gtk_check_button_new_with_label ("Use detail brushes"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "detail", check); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (texture_detail), NULL); + + check = gtk_check_button_new_with_label ("Detail hint brushes"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "hint", check); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (texture_hint), NULL); + + // ^Fishman - Add terrain key to func_group. + check = gtk_check_button_new_with_label ("Add terrain key"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "terrain_ent", check); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (texture_terrainent), NULL); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); + gtk_widget_set_usize (button, 60, -2); + g_object_set_data (G_OBJECT (dlg), "go", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_go), NULL); + + label = gtk_label_new ("Settings:"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (vbox), label, FALSE, TRUE, 0); + + button = gtk_button_new_with_label ("Open..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "open", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_open), NULL); + + button = gtk_button_new_with_label ("Save as..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "save", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_save), NULL); + + button = gtk_button_new_with_label ("Defaults"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "defaults", button); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_defaults), NULL); + + button = gtk_button_new_with_label ("About..."); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, TRUE, 0); + g_signal_connect (G_OBJECT (button), "clicked", G_CALLBACK (main_about), NULL); + + check = gtk_check_button_new_with_label ("Preview"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (main_preview), NULL); + g_object_set_data (G_OBJECT (dlg), "main_preview", check); + + // ^Fishman - Antializing for the preview window. + check = gtk_check_button_new_with_label ("Antialised lines"); + gtk_widget_show (check); + gtk_box_pack_start (GTK_BOX (vbox), check, FALSE, TRUE, 0); + g_object_set_data (G_OBJECT (dlg), "main_antialiasing", check); + g_signal_connect (G_OBJECT (check), "toggled", G_CALLBACK (main_antialiasing), NULL); + + for (i = 0; i < 5; i++) + SetDlgValues (i); + + CreateViewWindow (); + + create_tooltips(); + + FirstPassComplete = 1; + + return dlg; +} + + +#if 0 + +HWND hwndDisplay = (HWND)NULL; +HWND ghwndTab = (HWND)NULL; +int iTab=0; +RECT rcTab; +FILE *ftex; + +char GenSurfURL[40] = {"http://tarot.telefragged.com/gensurf"}; +char GenSurfBoard[40]={"http://tarot.telefragged.com/board"}; + +/* +* AboutDlgProc - processes messages for the about dialog. +*/ + +qboolean CALLBACK AboutDlgProc( HWND hwnd, unsigned msg, UINT wparam, LONG lparam ) +{ + char szText[256]; + DRAWITEMSTRUCT *dis; + HDC hdc; + HPEN hpen; + HWND hwndURL; + RECT rc; + SIZE size; + + lparam = lparam; /* turn off warning */ + + switch( msg ) { + case WM_INITDIALOG: + strcpy(szText,"About " ); + strcat(szText,gszCaption); + SetWindowText(hwnd,gszCaption); + SetDlgItemText(hwnd,DLG_ABOUT_APP,szText); + /* Application icon: */ + SendDlgItemMessage( hwnd, DLG_ABOUT_ICON, + STM_SETICON, (WPARAM)(HICON)LoadIcon(ghInst,"GENSURF"), + (LPARAM) NULL); + + hwndURL = GetDlgItem(hwnd,DLG_ABOUT_URL); + hdc = GetDC(hwndURL); + GetTextExtentPoint(hdc,GenSurfURL,strlen(GenSurfURL),&size); + ReleaseDC(hwndURL,hdc); + GetWindowRect(hwndURL,&rc); + SetWindowPos(hwndURL,(HWND)NULL,0,0,size.cx,size.cy+2, + SWP_NOMOVE | SWP_NOZORDER); + + hwndURL = GetDlgItem(hwnd,DLG_ABOUT_BOARD); + hdc = GetDC(hwndURL); + GetTextExtentPoint(hdc,GenSurfBoard,strlen(GenSurfBoard),&size); + ReleaseDC(hwndURL,hdc); + GetWindowRect(hwndURL,&rc); + SetWindowPos(hwndURL,(HWND)NULL,0,0,size.cx,size.cy+2, + SWP_NOMOVE | SWP_NOZORDER); + + return TRUE; + + case WM_COMMAND: + switch(LOWORD(wparam)) + { + case DLG_ABOUT_URL: + HTTP(GenSurfURL); + break; + case DLG_ABOUT_BOARD: + HTTP(GenSurfBoard); + break; + case IDOK: + EndDialog(hwnd,1); + return TRUE; + } + break; + + case WM_DRAWITEM: + if(wparam == DLG_ABOUT_URL) + { + dis = (LPDRAWITEMSTRUCT)lparam; + SetTextColor(dis->hDC,RGB(0,0,255)); + TextOut(dis->hDC,0,0,GenSurfURL,strlen(GenSurfURL)); + GetWindowRect(dis->hwndItem,&rc); + GetTextExtentPoint(dis->hDC,GenSurfURL,strlen(GenSurfURL),&size); + hpen = CreatePen(PS_SOLID,0,RGB(0,0,255)); + SelectObject(dis->hDC,hpen); + MoveToEx(dis->hDC,0,size.cy,NULL); + LineTo(dis->hDC,size.cx,size.cy); + SelectObject(dis->hDC,GetStockObject(BLACK_PEN)); + DeleteObject(hpen); + } + else if(wparam==DLG_ABOUT_BOARD) + { + dis = (LPDRAWITEMSTRUCT)lparam; + SetTextColor(dis->hDC,RGB(0,0,255)); + TextOut(dis->hDC,0,0,GenSurfBoard,strlen(GenSurfBoard)); + GetWindowRect(dis->hwndItem,&rc); + GetTextExtentPoint(dis->hDC,GenSurfBoard,strlen(GenSurfBoard),&size); + hpen = CreatePen(PS_SOLID,0,RGB(0,0,255)); + SelectObject(dis->hDC,hpen); + MoveToEx(dis->hDC,0,size.cy,NULL); + LineTo(dis->hDC,size.cx,size.cy); + SelectObject(dis->hDC,GetStockObject(BLACK_PEN)); + DeleteObject(hpen); + } + break; + + case WM_CLOSE: + EndDialog(hwnd,1); + return TRUE; + + default: + return FALSE; + } + return FALSE; + +} /* AboutDlgProc */ + +void About() +{ + if( DialogBox( ghInst,"About", ghwnd_main, (DLGPROC)AboutDlgProc ) < 0) + { + char Text[256]; + sprintf(Text,"In About(), GetLastError()=0x%08x",GetLastError()); + MessageBox(ghwnd_main,Text,"GenSurf",MB_ICONEXCLAMATION); + } +} + +#endif diff --git a/contrib/gtkgensurf/gendlgs.h b/contrib/gtkgensurf/gendlgs.h new file mode 100644 index 00000000..c6df4866 --- /dev/null +++ b/contrib/gtkgensurf/gendlgs.h @@ -0,0 +1,151 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#define DLG_PLANE_XY0 100 +#define DLG_PLANE_XY1 101 +#define DLG_PLANE_YZ0 102 +#define DLG_PLANE_XZ0 103 +#define DLG_PLANE_YZ1 104 +#define DLG_PLANE_XZ1 105 +#define DLG_WAVE_01 106 +#define DLG_WAVE_02 107 +#define DLG_WAVE_03 108 +#define DLG_WAVE_04 109 +#define DLG_WAVE_05 110 +#define DLG_WAVE_06 111 +#define DLG_LAMBDA 112 +#define DLG_LAMBDA_TEXT 113 +#define DLG_AMP 114 +#define DLG_AMP_TEXT 115 +#define DLG_ROUGH 116 +#define DLG_ROUGH_TEXT 117 +#define DLG_LINEARBORDER 118 +#define DLG_FILE 119 +#define DLG_FILE_BROWSE 120 +#define DLG_PREVIEW 121 +#define DLG_GO 122 +#define DLG_ABOUT 123 +#define DLG_NH_TEXT 124 +#define DLG_NH 125 +#define DLG_NH_SPIN 126 +#define DLG_NV_TEXT 127 +#define DLG_NV 128 +#define DLG_NV_SPIN 129 +#define DLG_HMIN_TEXT 130 +#define DLG_HMIN 131 +#define DLG_HMAX_TEXT 132 +#define DLG_HMAX 133 +#define DLG_VMIN_TEXT 134 +#define DLG_VMIN 135 +#define DLG_VMAX_TEXT 136 +#define DLG_VMAX 137 +#define DLG_Z00_TEXT 138 +#define DLG_Z00 139 +#define DLG_Z01_TEXT 140 +#define DLG_Z01 141 +#define DLG_Z10_TEXT 142 +#define DLG_Z10 143 +#define DLG_Z11_TEXT 144 +#define DLG_Z11 145 +#define DLG_TEXTURE 146 +#define DLG_SKYBOX 147 +#define DLG_AUTOOVERWRITE 148 +#define DLG_DETAIL 149 +#define DLG_ARGHRAD2 150 +#define DLG_ARGHRAD2_SPIN 151 +#define DLG_APPEND 152 +#define DLG_REFRESH 153 +#define DLG_TEXOFFSETX 154 +#define DLG_TEXOFFSETY 155 +#define DLG_TEXSCALEX 156 +#define DLG_TEXSCALEY 157 +#define DLG_FIXPOINTS 158 +#define DLG_TEXTURE_BROWSE 159 +#define DLG_AZIMUTH 162 +#define DLG_AZIMUTH_SPIN 163 +#define DLG_ELEVATION 164 +#define DLG_ELEVATION_SPIN 165 +#define DLG_RANDOMSEED 166 +#define DLG_RANDOMSEED_SPIN 167 +#define DLG_BITMAP 168 +#define DLG_SAVE 169 +#define DLG_OPEN 170 +#define DLG_TAB 171 +#define DLG_TEXTURE2 172 +#define DLG_TEXTURE2_BROWSE 173 +#define DLG_LADDER 174 +#define DLG_ARGHRAD2_TEXT 175 +#define DLG_FILE_TEXT 176 +#define DLG_DECIMATE 177 +#define DLG_DECIMATE_TEXT 178 +#define DLG_HIDEBACKFACES 179 +#define DLG_DEFAULTS 180 +#define DLG_ABOUT_APP 200 +#define DLG_ABOUT_ICON 201 +#define DLG_BMP_FILE 202 +#define DLG_BMP_FILE_BROWSE 203 +#define DLG_BMP_BLACK 204 +#define DLG_BMP_WHITE 205 +#define DLG_BMP_TEXT1 206 +#define DLG_BMP_TEXT2 207 +#define DLG_BMP_TEXT3 208 +#define DLG_BMP_NOTE 209 +#define DLG_BMP_RELOAD 210 +#define DLG_ABOUT_URL 211 +#define DLG_ABOUT_BOARD 212 +#define DLG_FIX_FREE 300 +#define DLG_FIX_FREEALL 301 +#define DLG_FIX_VALUE_TEXT 302 +#define DLG_FIX_VALUE 303 +#define DLG_FIX_VALUE_SPIN 304 +#define DLG_FIX_DONE 305 +#define DLG_FIX_RANGE_TEXT 306 +#define DLG_FIX_RANGE 307 +#define DLG_FIX_NOTE 308 +#define DLG_FIX_RATE_TEXT 309 +#define DLG_FIX_RATE 310 +#define DLG_USE_PATCHES 311 +#define DLG_DECIMATE_LABEL 312 +#define DLG_HINT 350 +#define DLG_GAME_00 400 +#define DLG_GAME_01 401 +#define DLG_GAME_02 402 +#define DLG_GAME_03 403 +#define DLG_GAME_04 404 +#define DLG_GAME_05 405 +#define DLG_GAME_06 406 +#define DLG_GAME_07 407 +#define DLG_GAME_08 408 +#define DLG_GAME_09 409 +#define DLG_TEX_USEPAK 420 +#define DLG_TEX_PAK_TEXT 421 +#define DLG_TEX_PAKFILE 422 +#define DLG_TEX_PAK_BROWSE 423 +#define DLG_TEX_LIST1 424 +#define DLG_TEX_LIST2 425 +#define DLG_TEX_LIST3 426 +#define DLG_TEXTURE3 427 +#define DLG_TEXTURE3_BROWSE 428 +#define DLG_TEX_SLANT_TEXT 429 +#define DLG_TEX_SLANT 430 +#define DLG_TEX_SLANT_SPIN 431 +#define DLG_EXCEL_FUNC 500 +#define DLG_EXCEL_FUNC_TEXT 501 +#define DLG_PREVIEW_ANTIALIASING 502 // ^Fishman - Antializing for the preview window. +#define DLG_SNAP_TO_GRID 503 // Hydra : snap to grid diff --git a/contrib/gtkgensurf/genmap.cpp b/contrib/gtkgensurf/genmap.cpp new file mode 100644 index 00000000..ace97b68 --- /dev/null +++ b/contrib/gtkgensurf/genmap.cpp @@ -0,0 +1,2056 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include "gensurf.h" + +double xmin,xmax,ymin,ymax,zmin,zmax; +double backface; +extern double dh, dv; +FILE *fmap; +XYZ xyz[MAX_ROWS+1][MAX_ROWS+1]; +int contents; +int surface[3]; +LPVOID h_func_group; +LPVOID terrainkey; // ^Fishman - Add terrain key to func_group. + +//============================================================= +// Hydra : snap-to-grid begin +double CalculateSnapValue(double value) +{ + long snapvalue; + + // simple uncomplicated snapping, rounding both UP and DOWN to the nearest + // grid unit. + if (SnapToGrid >0) + { + snapvalue = (int)value / SnapToGrid; + if ((long)value % SnapToGrid < (SnapToGrid / 2)) // Snap Downwards if less than halfway between to grid units + value = snapvalue * SnapToGrid; + else // Snap Upwards if more than halfway between to grid units + value = (snapvalue+1) * SnapToGrid; + } + return value; +} +// Hydra : snap-to-grid end + +//============================================================= +bool ValidSurface() +{ + if(WaveType == WAVE_BITMAP && !gbmp.colors) return FALSE; + if(NH < 1) return FALSE; + if(NH > MAX_ROWS) return FALSE; + if(NV < 1) return FALSE; + if(NV > MAX_ROWS) return FALSE; + if(Hll >= Hur) return FALSE; + if(Vll >= Vur) return FALSE; + return TRUE; +} + +//============================================================= +int MapPatches() +{ + int NH_remain; + int NV_remain; + int NH_patch; + int NV_patch; + int BrushNum = 0; + int i, j, k1, k2, k3; + int i0, j0, ii; + char szOops[128]; + patchMesh_t p; + + dh = (Hur-Hll)/NH; + dv = (Vur-Vll)/NV; + memset(&p,0,sizeof(patchMesh_t)); + + // Generate control points in pp array to give desired values currently + // in p array. + switch(Plane) + { + case PLANE_XY0: + case PLANE_XY1: + k1 = 0; + k2 = 1; + k3 = 2; + break; + case PLANE_XZ0: + case PLANE_XZ1: + k1 = 0; + k2 = 2; + k3 = 1; + break; + case PLANE_YZ0: + case PLANE_YZ1: + k1 = 1; + k2 = 2; + k3 = 0; + break; + } + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + xyz[i][j].pp[k1] = xyz[i][j].p[k1]; + xyz[i][j].pp[k2] = xyz[i][j].p[k2]; + } + } + for(i=0; i<=NH; i+=2) + { + for(j=0; j<=NV; j+=2) + xyz[i][j].pp[k3] = xyz[i][j].p[k3]; + } + for(i=1; i 1) + { + if(( (NH_remain-1) % 14) == 0) + NH_patch = 15; + else if(( (NH_remain-1) % 12) == 0) + NH_patch = 13; + else if(( (NH_remain-1) % 10) == 0) + NH_patch = 11; + else if(( (NH_remain-1) % 8) == 0) + NH_patch = 9; + else if(( (NH_remain-1) % 6) == 0) + NH_patch = 7; + else if(( (NH_remain-1) % 4) == 0) + NH_patch = 5; + else if(( (NH_remain-1) % 2) == 0) + NH_patch = 3; + else if(NH_remain > 16) + NH_patch = 7; + else if(NH_remain > 4) + NH_patch = 5; + else + NH_patch = 3; + while( NH_patch > 3 && (NH_patch-1)*dh > 512 ) + NH_patch -= 2; + NH_remain -= (NH_patch-1); + if(NH_remain < 0) + { + sprintf(szOops,"Oops... screwed up with NH=%d",NH); + g_FuncTable.m_pfnMessageBox(NULL,szOops,"Uh oh"); + } + NV_remain = NV+1; + j0 = 0; + while(NV_remain > 1) + { + if(( (NV_remain-1) % 14) == 0) + NV_patch = 15; + else if(( (NV_remain-1) % 12) == 0) + NV_patch = 13; + else if(( (NV_remain-1) % 10) == 0) + NV_patch = 11; + else if(( (NV_remain-1) % 8) == 0) + NV_patch = 9; + else if(( (NV_remain-1) % 6) == 0) + NV_patch = 7; + else if(( (NV_remain-1) % 4) == 0) + NV_patch = 5; + else if(( (NV_remain-1) % 2) == 0) + NV_patch = 3; + else if(NV_remain > 16) + NV_patch = 7; + else if(NV_remain > 4) + NV_patch = 5; + else + NV_patch = 3; + while( NV_patch > 3 && (NV_patch-1)*dh > 512 ) + NV_patch -= 2; + NV_remain -= (NV_patch-1); + if(NV_remain < 0) + { + sprintf(szOops,"Oops... screwed up with NV=%d",NV); + g_FuncTable.m_pfnMessageBox(NULL,szOops,"Uh oh"); + } + + p.width = NH_patch; + p.height = NV_patch; + p.type = PATCH_GENERIC; + for(i=0; i 0 && (Game != QUAKE3 || UsePatches==0) ) + { + MapOut(gNumNodes,gNumTris,gNode,gTri); + /* + ghCursorCurrent = ghCursorDefault; + SetCursor(ghCursorCurrent); + */ + return; + } + + contents = 0; + // HL doesn't have detail property + if((Game != HALFLIFE) && UseDetail) contents += CONTENTS_DETAIL; + // HL and Q3 don't have ladder property + if((Game != HALFLIFE && Game != QUAKE3) && UseLadder) contents += CONTENTS_LADDER; + // Genesis requires solid property to be set explicitly + if(Game == GENESIS3D) contents |= CONTENTS_SOLID; + // Heretic 2 uses different sounds (in surface props) for different texture types + if(Game == HERETIC2) + { + surface[0] = GetDefSurfaceProps(Texture[Game][0]); + surface[1] = GetDefSurfaceProps(Texture[Game][1]); + surface[2] = GetDefSurfaceProps(Texture[Game][2]); + } + else + { + surface[0] = 0; + surface[1] = 0; + surface[2] = 0; + } + if(Game!=QUAKE3 || UsePatches == 0) + MapBrushes(); + + /* + ghCursorCurrent = ghCursorDefault; + SetCursor(ghCursorCurrent); + */ +} + +//============================================================= +void GenerateXYZ() +{ + extern void MakeDecimatedMap(int *, int *, NODE **, TRI **); + double zl, zu; + double wh, wv; + int NHalfcycles; + double a,v,h,ha,va; + double delta, dr, rate; + double range, maxrange; + double r; + int i, j, k, N; + int i0, i1, j0, j1; + int ii, jj; + +// FILE *f; +// char CSV[64]; + + if(!ValidSurface()) return; + + srand(1); + srand(RandomSeed); + + dh = (Hur-Hll)/NH; + dv = (Vur-Vll)/NV; + + // H & V + for(i=0; i<=NH; i++) + { + for(j=0;j<=NV;j++) + { + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + xyz[i][j].p[0] = Hll + i*dh; + xyz[i][j].p[2] = Vll + j*dv; + break; + case PLANE_YZ0: + case PLANE_YZ1: + xyz[i][j].p[1] = Hll + i*dh; + xyz[i][j].p[2] = Vll + j*dv; + break; + default: + xyz[i][j].p[0] = Hll + i*dh; + xyz[i][j].p[1] = Vll + j*dv; + } + } + } + + if(WaveType == WAVE_BITMAP) + GenerateBitmapMapping(); + /* + else if(WaveType == WAVE_FORMULA) + DoFormula(); + */ + else + { + // Initialize Z values using bilinear interpolation + for(i=0; i<=NH; i++) + { + zl = Z00 + i*(Z10 - Z00)/NH; + zu = Z01 + i*(Z11 - Z01)/NH; + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + for(j=0; j<=NV; j++) + xyz[i][j].p[1] = zl + j*(zu-zl)/NV; + break; + case PLANE_YZ0: + case PLANE_YZ1: + for(j=0; j<=NV; j++) + xyz[i][j].p[0] = zl + j*(zu-zl)/NV; + break; + default: + for(j=0; j<=NV; j++) + xyz[i][j].p[2] = zl + j*(zu-zl)/NV; + } + } + } + + switch(WaveType) + { + case WAVE_COS_SIN: + if(FixBorders) + { + NHalfcycles = (int)((Hur-Hll)/(WaveLength/2.)); + NHalfcycles = max(NHalfcycles,1); + wh = 2.*(Hur-Hll)/NHalfcycles; + NHalfcycles = (int)((Vur-Vll)/(WaveLength/2.)); + wv = 2.*(Vur-Vll)/NHalfcycles; + NHalfcycles = max(NHalfcycles,1); + i0 = 1; + i1 = NH-1; + j0 = 1; + j1 = NV-1; + } + else + { + wh = WaveLength; + wv = WaveLength; + i0 = 0; + i1 = NH; + j0 = 0; + j1 = NV; + } + + for(i=i0; i<=i1; i++) + { + h = Hll + i*dh; + ha = ((h-Hll)/wh)*2.*PI - PI/2.; + for(j=j0; j<=j1; j++) + { + v = Vll + j*dv; + va = ((v-Vll)/wv)*2.*PI; + a = Amplitude * cos( ha ) * sin( va ); + switch(Plane) + { + case PLANE_XY1: + xyz[i][j].p[2] -= a; + break; + case PLANE_XZ0: + xyz[i][j].p[1] += a; + break; + case PLANE_XZ1: + xyz[i][j].p[1] -= a; + break; + case PLANE_YZ0: + xyz[i][j].p[0] += a; + break; + case PLANE_YZ1: + xyz[i][j].p[0] -= a; + break; + default: + xyz[i][j].p[2] += a; + } + } + } + break; + case WAVE_HCYLINDER: + for(i=0; i<=NH; i++) + { + h = Hll + i*dh; + ha = ((h-Hll)/WaveLength)*2.*PI - PI/2.; + for(j=0; j<=NV; j++) + { + a = Amplitude * cos( ha ); + switch(Plane) + { + case PLANE_XY1: + xyz[i][j].p[2] -= a; + break; + case PLANE_XZ0: + xyz[i][j].p[1] += a; + break; + case PLANE_XZ1: + xyz[i][j].p[1] -= a; + break; + case PLANE_YZ0: + xyz[i][j].p[0] += a; + break; + case PLANE_YZ1: + xyz[i][j].p[0] -= a; + break; + default: + xyz[i][j].p[2] += a; + } + } + } + break; + case WAVE_VCYLINDER: + for(i=0; i<=NH; i++) + { + h = Hll + i*dh; + for(j=0; j<=NV; j++) + { + v = Vll + j*dv; + va = ((v-Vll)/WaveLength)*2.*PI; + a = Amplitude * sin( va ); + switch(Plane) + { + case PLANE_XY1: + xyz[i][j].p[2] -= a; + break; + case PLANE_XZ0: + xyz[i][j].p[1] += a; + break; + case PLANE_XZ1: + xyz[i][j].p[1] -= a; + break; + case PLANE_YZ0: + xyz[i][j].p[0] += a; + break; + case PLANE_YZ1: + xyz[i][j].p[0] -= a; + break; + default: + xyz[i][j].p[2] += a; + } + } + } + break; + case WAVE_ROUGH_ONLY: + PlasmaCloud(); + break; + } + + if(WaveType != WAVE_ROUGH_ONLY) + { + // Fixed values + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(xyz[i][j].fixed) + { + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + xyz[i][j].p[1] = xyz[i][j].fixed_value; + break; + case PLANE_YZ0: + case PLANE_YZ1: + xyz[i][j].p[0] = xyz[i][j].fixed_value; + break; + default: + xyz[i][j].p[2] = xyz[i][j].fixed_value; + } + + if(xyz[i][j].range > 0) + { + maxrange = pow(xyz[i][j].range,2); // so we don't have to do sqrt's + i0 = i - (int)( floor(xyz[i][j].range/dh - 0.5) + 1 ); + i1 = i + i - i0; + j0 = j - (int)( floor(xyz[i][j].range/dv - 0.5) + 1 ); + j1 = j + j - j0; + if(FixBorders) + { + i0 = max(i0,1); + i1 = min(i1,NH-1); + j0 = max(j0,1); + j1 = min(j1,NV-1); + } + else + { + i0 = max(i0,0); + i1 = min(i1,NH); + j0 = max(j0,0); + j1 = min(j1,NV); + } + for(ii=i0; ii<=i1; ii++) + { + for(jj=j0; jj<=j1; jj++) + { + if(ii==i && jj==j) continue; + range = pow( dh*(i-ii), 2) + pow( dv*(j-jj), 2); + if(range > maxrange) continue; + dr = sqrt(range/maxrange); + rate = max(-30.,min(xyz[i][j].rate,30.)); + if(rate < -1.) + { + delta = pow((1.-dr),-rate+1.); + } + else if(rate < 0.) + { + delta = (1+rate)*0.5*(cos(dr*PI)+1.0) - + rate*pow((1.-dr),2); + } + else if(rate == 0.) + { + delta = 0.5*(cos(dr*PI)+1.0); + } + else if(rate <= 1.) + { + delta = (1.-rate)*0.5*(cos(dr*PI)+1.0) + + rate*(1.-pow(dr,2)); + } + else + { + delta = 1.-pow(dr,rate+1); + } + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + xyz[ii][jj].p[1] += (xyz[i][j].p[1] - xyz[ii][jj].p[1])*delta; + break; + case PLANE_YZ0: + case PLANE_YZ1: + xyz[ii][jj].p[0] += (xyz[i][j].p[0] - xyz[ii][jj].p[0])*delta; + break; + default: + xyz[ii][jj].p[2] += (xyz[i][j].p[2] - xyz[ii][jj].p[2])*delta; + } + } + } + } + } + } + } + } + + if((Roughness > 0.) && (WaveType != WAVE_ROUGH_ONLY) ) + { + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(CanEdit(i,j) && !xyz[i][j].fixed) + { + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + xyz[i][j].p[1] += -Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX); + break; + case PLANE_YZ0: + case PLANE_YZ1: + xyz[i][j].p[0] += -Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX); + break; + default: + xyz[i][j].p[2] += -Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX); + } + } + else + r = rand(); // We still get a random number, so that fixing points + // doesn't change the sequence. + + } + } + } + + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + for(k=0; k<3; k++) + { + xyz[i][j].p[k] = Nearest(xyz[i][j].p[k],2.0); + } + } + } + + // Find minima and maxima + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + xmin = Hll; + xmax = Hur; + zmin = Vll; + zmax = Vur; + ymin = xyz[0][0].p[1]; + ymax = ymin; + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + ymin = min(ymin,xyz[i][j].p[1]); + ymax = max(ymax,xyz[i][j].p[1]); + } + } + break; + case PLANE_YZ0: + case PLANE_YZ1: + ymin = Hll; + ymax = Hur; + zmin = Vll; + zmax = Vur; + xmin = xyz[0][0].p[0]; + xmax = ymin; + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + xmin = min(xmin,xyz[i][j].p[0]); + xmax = max(xmax,xyz[i][j].p[0]); + } + } + break; + break; + default: + xmin = Hll; + xmax = Hur; + ymin = Vll; + ymax = Vur; + zmin = xyz[0][0].p[2]; + zmax = zmin; + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + zmin = min(zmin,xyz[i][j].p[2]); + zmax = max(zmax,xyz[i][j].p[2]); + } + } + } + + xmin = Nearest(xmin,2.); + xmax = Nearest(xmax,2.); + ymin = Nearest(ymin,2.); + ymax = Nearest(ymax,2.); + zmin = Nearest(zmin,2.); + zmax = Nearest(zmax,2.); + + switch(Plane) + { + case PLANE_XY1: + backface = AtLeast(zmax+32.,32.); + break; + case PLANE_XZ0: + backface = NoMoreThan(ymin-32.,32.); + break; + case PLANE_XZ1: + backface = AtLeast(ymax+32.,32.); + break; + case PLANE_YZ0: + backface = NoMoreThan(xmin-32.,32.); + break; + case PLANE_YZ1: + backface = AtLeast(xmax+32.,32.); + break; + default: + backface = NoMoreThan(zmin-32.,32.); + } + + if(gNode) + { + free(gNode); + free(gTri); + gNode = (NODE *)NULL; + gTri = (TRI *)NULL; + } + if(Decimate > 0 && (Game != QUAKE3 || UsePatches==0) ) + { + MakeDecimatedMap(&gNumNodes,&gNumTris,&gNode,&gTri); + } + else + { + gNumNodes = (NH+1)*(NV+1); + gNumTris = NH*NV*2; + gNode = (NODE *) malloc(gNumNodes * sizeof(NODE)); + gTri = (TRI *) malloc(gNumTris * sizeof(TRI)); + + for(i=0,N=0; i<=NH; i++) + { + for(j=0; j<=NV; j++, N++) + { + gNode[N].used = 1; + gNode[N].p[0] = (float)xyz[i][j].p[0]; + gNode[N].p[1] = (float)xyz[i][j].p[1]; + gNode[N].p[2] = (float)xyz[i][j].p[2]; + } + } + + for(i=0; i 0) + { + for(i=0; i x) xx -= dx; + return xx; +} +//============================================================= +double AtLeast(double x, double dx) +{ + double xx; + + xx = (double)(floor(x/dx - 0.5)+1.)*dx; + if(xx < x) xx += dx; + return xx; +} +//============================================================= +double LessThan(double x,double dx) +{ + double xx; + + xx = (double)(floor(x/dx - 0.5)+1.)*dx; + if(xx >= x) xx -= dx; + return xx; +} +//============================================================= +double MoreThan(double x,double dx) +{ + double xx; + + xx = (double)(floor(x/dx - 0.5)+1.)*dx; + while(xx <= x) + xx += dx; + return xx; +} +//============================================================= +void SubdividePlasma(int i0,int j0,int i1,int j1) +{ + int i, j; + double z1, z2; + double r; // NOTE: This is used to keep the random number sequence the same + // when we fix a point. If we did NOT do this, then simply + // fixing a point at its current value would change the entire + // surface. + + i = (i0+i1)/2; + j = (j0+j1)/2; + if(i1 > i0+1) + { + if(!xyz[i][j0].done) + { + xyz[i][j0].pp[2] = xyz[i0][j0].pp[2] + + (xyz[i1][j0].pp[2] - xyz[i0][j0].pp[2])*(double)(i-i0)/(double)(i1-i0) + + ((double)(i-i0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); + xyz[i][j0].done = 1; + } + else + r = rand(); + if((j1 > j0) && (!xyz[i][j1].done) ) + { + xyz[i][j1].pp[2] = xyz[i0][j1].pp[2] + + (xyz[i1][j1].pp[2] - xyz[i0][j1].pp[2])*(double)(i-i0)/(double)(i1-i0) + + ((double)(i-i0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); + xyz[i][j1].done = 1; + } + else + r = rand(); + } + if(j1 > j0 + 1) + { + if(!xyz[i0][j].done) + { + xyz[i0][j].pp[2] = xyz[i0][j0].pp[2] + + (xyz[i0][j1].pp[2] - xyz[i0][j0].pp[2])*(double)(j-j0)/(double)(j1-j0) + + ((double)(j-j0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); + xyz[i0][j].done = 1; + } + else + r = rand(); + if((i1 > i0) && (!xyz[i1][j].done)) + { + xyz[i1][j].pp[2] = xyz[i1][j0].pp[2] + + (xyz[i1][j1].pp[2] - xyz[i1][j0].pp[2])*(double)(j-j0)/(double)(j1-j0) + + ((double)(j-j0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); + xyz[i1][j].done = 1; + } + else + r = rand(); + } + if((i1 > i0+1) && (j1 > j0+1)) + { + if(!xyz[i][j].done) + { + z1 = xyz[i0][j].pp[2] + + (xyz[i1][j].pp[2] - xyz[i0][j].pp[2])*(double)(i-i0)/(double)(i1-i0); + z2 = xyz[i][j0].pp[2] + + (xyz[i][j1].pp[2] - xyz[i][j0].pp[2])*(double)(j-j0)/(double)(j1-j0); + xyz[i][j].pp[2] = (z1+z2)/2. + + ((double)(i-i0))*(-Roughness/2. + Roughness*((double)rand()/(double)RAND_MAX)); + xyz[i][j].done = 1; + } + else + r = rand(); + } + if(i > i0+1 || j > j0+1) + SubdividePlasma(i0,j0,i,j); + if(i1 > i+1 || j > j0+1) + SubdividePlasma(i,j0,i1,j); + if(i > i0+1 || j1 > j0+1) + SubdividePlasma(i0,j,i,j1); + if(i1 > i+1 || j1 > j0+1) + SubdividePlasma(i,j,i1,j1); +} +//================================================================================== +void PlasmaCloud() +{ + int i, j; + /* use pp[2] values until done to avoid messing with a bunch of + switch statements */ + + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(FixedPoint(i,j)) + xyz[i][j].done = 1; + else + xyz[i][j].done = 0; + } + } + + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(xyz[i][j].fixed) + xyz[i][j].pp[2] = xyz[i][j].fixed_value; + else + xyz[i][j].pp[2] = xyz[i][j].p[1]; + } + } + break; + case PLANE_YZ0: + case PLANE_YZ1: + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(xyz[i][j].fixed) + xyz[i][j].pp[2] = xyz[i][j].fixed_value; + else + xyz[i][j].pp[2] = xyz[i][j].p[0]; + } + } + break; + default: + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(xyz[i][j].fixed) + xyz[i][j].pp[2] = xyz[i][j].fixed_value; + else + xyz[i][j].pp[2] = xyz[i][j].p[2]; + } + } + break; + } + SubdividePlasma(0,0,NH,NV); + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + xyz[i][j].p[1] = xyz[i][j].pp[2]; + } + } + break; + case PLANE_YZ0: + case PLANE_YZ1: + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + xyz[i][j].p[0] = xyz[i][j].pp[2]; + } + } + break; + default: + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + xyz[i][j].p[2] = xyz[i][j].pp[2]; + } + } + break; + } +} +//=========================================================================== +bool FixedPoint(int i, int j) +{ + if(xyz[i][j].fixed) return TRUE; + return !CanEdit(i,j); +} +//=========================================================================== +bool CanEdit(int i, int j) +{ + if(FixBorders && ( (WaveType==WAVE_COS_SIN) || (WaveType==WAVE_ROUGH_ONLY) ) ) + { + if(i== 0) return FALSE; + if(i==NH) return FALSE; + if(j== 0) return FALSE; + if(j==NV) return FALSE; + } + if(i== 0 && j== 0) return FALSE; + if(i==NH && j== 0) return FALSE; + if(i== 0 && j==NV) return FALSE; + if(i==NH && j==NV) return FALSE; + return TRUE; +} +/*============================================================================ + TriangleFromPoint + Determines which triangle in the gTri array bounds the input point. Doesn't + do anything special with border points. +*/ +int TriangleFromPoint(double x, double y) +{ + int j, tri; + + if(!gTri) return -1; + + for(j=0, tri=-1; jp[0],2.); + v[0][1] = (vec)Nearest(xyz->p[1],2.); + v[0][2] = (vec)Nearest(xyz->p[2],2.); +} + +//============================================================= +void MakePatch(patchMesh_t *p) +{ + int ret; + char shadername[64+9]; + + ret = g_FuncTable.m_pfnCreatePatchHandle(); + // strcpy(shadername, "textures/"); + // strcpy(shadername+9, Texture[Game][0]); + strcpy(shadername, Texture[Game][0]); + g_FuncTable.m_pfnCommitPatchHandleToMap(ret,p,shadername); + g_FuncTable.m_pfnReleasePatchHandles(); +} + +//============================================================= +void MakeBrush(BRUSH *brush) +{ + LPVOID vp; + int i; + _QERFaceData QERFaceData; + + if(g_FuncTable.m_pfnCreateBrushHandle==NULL) + { + g_FuncTable.m_pfnMessageBox(g_pRadiantWnd,"m_pfnCreateBrushHandle==NULL","Aw damn",0); + return; + } + vp=(g_FuncTable.m_pfnCreateBrushHandle)(); + if(!vp) return; + for(i=0; iNumFaces; i++) + { + if(!strncmp(brush->face[i].texture, "textures/", 9)) + strcpy(QERFaceData.m_TextureName,brush->face[i].texture); + else + { + strcpy(QERFaceData.m_TextureName,"textures/"); + strcpy(QERFaceData.m_TextureName+9,brush->face[i].texture); + } + QERFaceData.m_nContents = brush->face[i].Contents; + QERFaceData.m_nFlags = brush->face[i].Surface; + QERFaceData.m_nValue = brush->face[i].Value; + QERFaceData.m_fShift[0] = brush->face[i].Shift[0]; + QERFaceData.m_fShift[1] = brush->face[i].Shift[1]; + QERFaceData.m_fRotate = brush->face[i].Rotate; + QERFaceData.m_fScale[0] = brush->face[i].Scale[0]; + QERFaceData.m_fScale[1] = brush->face[i].Scale[1]; + QERFaceData.m_v1[0] = brush->face[i].v[0][0]; + QERFaceData.m_v1[1] = brush->face[i].v[0][1]; + QERFaceData.m_v1[2] = brush->face[i].v[0][2]; + QERFaceData.m_v2[0] = brush->face[i].v[1][0]; + QERFaceData.m_v2[1] = brush->face[i].v[1][1]; + QERFaceData.m_v2[2] = brush->face[i].v[1][2]; + QERFaceData.m_v3[0] = brush->face[i].v[2][0]; + QERFaceData.m_v3[1] = brush->face[i].v[2][1]; + QERFaceData.m_v3[2] = brush->face[i].v[2][2]; + QERFaceData.m_bBPrimit = false; + (g_FuncTable.m_pfnAddFaceData)(vp,&QERFaceData); + } + if(g_FuncTable.m_pfnCommitBrushHandle!=NULL) + { + if(h_func_group) + g_FuncTable.m_pfnCommitBrushHandleToEntity(vp,h_func_group); + else + g_FuncTable.m_pfnCommitBrushHandle(vp); + } +} +//============================================================= +void OpenFuncGroup() +{ + if (g_FuncTable.m_pfnAllocateEpair!=NULL) + { + epair_t *ep; + + h_func_group = g_FuncTable.m_pfnCreateEntityHandle(); + ep = g_EntityTable.m_pfnAllocateEpair("classname","func_group"); + g_EntityTable.m_pfnSetEntityKeyValList((entity_t *)h_func_group,ep); + + if (AddTerrainKey) // ^Fishman - Add terrain key to func_group. + { + epair_t *ep2; + terrainkey = g_FuncTable.m_pfnCreateEntityHandle(); + ep2 = g_EntityTable.m_pfnAllocateEpair("terrain","1"); + ep->next = ep2; + g_EntityTable.m_pfnSetEntityKeyValList((entity_t *)h_func_group,ep); + } + } + else + h_func_group = NULL; +} +//============================================================= +void CloseFuncGroup() +{ + if (h_func_group) + g_FuncTable.m_pfnCommitEntityHandleToMap (h_func_group); + if (g_FuncTable.m_pfnSysUpdateWindows != NULL) + g_FuncTable.m_pfnSysUpdateWindows (W_ALL); +} diff --git a/contrib/gtkgensurf/gensurf.cpp b/contrib/gtkgensurf/gensurf.cpp new file mode 100644 index 00000000..b9ff7d47 --- /dev/null +++ b/contrib/gtkgensurf/gensurf.cpp @@ -0,0 +1,467 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +/* +#include +#include +#include +*/ +#include "gensurf.h" + +char gszAppDir[NAME_MAX]; +char gszCaption[64]; +char gszIni[NAME_MAX]; +char gszHelpFile[NAME_MAX]; +char gszMapFile[NAME_MAX]; +char gszVersion[64]; +double Amplitude; +double Roughness; +double TexOffset[2]; +double TexScale[2]; +double WaveLength; +double Hll, Hur, Vll, Vur; +double Z00, Z01, Z10, Z11; +ELEMENT Vertex[(MAX_ROWS+1)*(MAX_ROWS+1)]; +int AddHints; +int ArghRad2; +int AutoOverwrite; +int Decimate=0; +int SnapToGrid=0; // 0, or the grid size to snap to. // Hydra : snap to grid +int FileAppend=0; +int FixBorders; +int HideBackFaces=0; +int NH, NV; +int NumVerticesSelected; +int Plane; +int Preview; +int RandomSeed=1; +int Skybox; +int UseDetail; +int UseLadder; +int VertexMode=0; +int WaveType; +int gNumNodes=0; +int gNumTris=0; +int vid_x, vid_y; +int view_x, view_y; +int view_cx, view_cy; +int UsePatches; +int SlantAngle; +int GimpHints; +int Antialiasing; // ^Fishman - Antializing for the preview window. +int AddTerrainKey; // ^Fishman - Add terrain key to func_group. +int SP; // ^Fishman - Snap to grid. + +GtkWidget *g_pWnd; // ghwnd; +GtkWidget *g_pRadiantWnd; // ghwnd_main; +/*HWND ghwndAngles; +*/GtkWidget *g_pWndPreview; +GtkWidget *g_pPreviewWidget; +MYBITMAP gbmp; +NODE *gNode=(NODE *)NULL; +TRI *gTri=(TRI *)NULL; + +int Game; +bounding_box PlayerBox[NUMGAMES] = { {{-16., 16.}, {-16., 16.}, {-24., 32.}}, // Quake2 + {{-16., 16.}, {-16., 16.}, {-36., 36.}}, // Half-Life + {{-16., 16.}, {-16., 16.}, {-32., 32.}}, // SiN + {{-16., 16.}, {-16., 16.}, {-24., 32.}}, // Heretic2 (guess) + {{-16., 16.}, {-16., 16.}, {-24., 32.}}, // KingPin (guess) + {{-30., 30.}, {-30., 30.}, {-10.,160.}}, // Genesis3D (no idea) + {{-16., 16.}, {-16., 16.}, {-24., 32.}}}; // Quake3 (not sure) +//char gszOutputDir[NUMGAMES][NAME_MAX]; +//char gszTextureDir[NUMGAMES][NAME_MAX]; +char Texture[NUMGAMES][3][64]; +//char pakfile[NUMGAMES][NAME_MAX]; +//char lastpakfile[NUMGAMES][NAME_MAX]; +//int UsePak[NUMGAMES]; +//char GameDir[NUMGAMES][NAME_MAX]; + +char GameName[NUMGAMES][16] = {"Quake2", "Half-Life", "SiN", "Heretic2", "Kingpin", "Genesis3D", "Quake3" }; + + +bool GenSurfInit () +{ + strcpy (gszVersion, "1.05"); + strcpy (gszCaption, "GtkGenSurf"); + if (strlen (gszVersion)) + { + strcat (gszCaption, " v"); + strcat (gszCaption, gszVersion); + } + + strcpy (gszIni, g_FuncTable.m_pfnProfileGetDirectory ()); + strcat (gszIni, "gensurf.ini"); + +/*if (g_FuncTable.m_pfnReadProjectKey != NULL) + { + char *basepath; + + basepath = g_FuncTable.m_pfnReadProjectKey("basepath"); + if (basepath) + { + g_strdown (basepath); + if (strstr(basepath,"baseq3")) + Game = QUAKE3; + else if (strstr (basepath,"baseq2")) + Game = QUAKE2; + else // Gotta have a game, might as well be Quake3 + Game = QUAKE3; + } + else + Game = QUAKE3; + } + else */ + Game = QUAKE3; + + ReadIniFile (gszIni); + + if (g_pWnd == NULL) + g_pWnd = create_main_dialog (); + + return true; +} + +// Reads default values + +#define OPTS_SECTION "Options" + +void ReadIniFile (const char *file) +{ + char *Text; + float x1,x2,x3,x4; + int i; + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "Amplitude", ""); + if (strlen (Text)) + Amplitude = atof (Text); + else + Amplitude = 128; + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "Roughness", ""); + if (strlen (Text)) + Roughness = atof (Text); + else + Roughness = 16; + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "WaveLength", ""); + if (strlen (Text)) + WaveLength = atof (Text); + else + WaveLength = 1024; + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "Extents", ""); + if (strlen (Text)) + { + sscanf(Text,"%f,%f,%f,%f",&x1,&x2,&x3,&x4); + Hll = x1; + Vll = x2; + Hur = x3; + Vur = x4; + } + else + { + Hll = -512; + Vll = -512; + Hur = 512; + Vur = 512; + } + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "CornerValues", ""); + if (strlen (Text)) + { + sscanf(Text,"%f,%f,%f,%f",&x1,&x2,&x3,&x4); + Z00 = x1; + Z01 = x2; + Z10 = x3; + Z11 = x4; + } + else + { + Z00 = 0.; + Z01 = 0.; + Z10 = 0.; + Z11 = 0.; + } + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION, "TextureOffset", ""); + if (strlen (Text)) + { + sscanf(Text,"%f,%f",&x1,&x2); + TexOffset[0] = x1; + TexOffset[1] = x2; + } + else + { + TexOffset[0] = 0.; + TexOffset[1] = 0.; + } + + Text = g_FuncTable.m_pfnProfileLoadString (file, OPTS_SECTION,"TextureScale",""); + if (strlen (Text)) + { + sscanf(Text,"%f,%f",&x1,&x2); + TexScale[0] = x1; + TexScale[1] = x2; + if(TexScale[0] == 0.) TexScale[0] = 1.0; + if(TexScale[1] == 0.) TexScale[1] = 1.0; + } + else + { + TexScale[0] = 1.; + TexScale[1] = 1.; + } + + NH = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"NH",8); + NH = max(1,min(NH,MAX_ROWS)); + NV = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"NV",8); + NV = max(1,min(NV,MAX_ROWS)); + +// Decimate = GetPrivateProfileInt(OPTS_SECTION,"Decimate",0,file); +// Decimate = max(0,min(Decimate,100)); + + AddHints = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"AddHints",0); + ArghRad2 = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"ArghRad2",0); + AutoOverwrite = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"AutoOverwrite",0); + FixBorders = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"FixBorders",1); + HideBackFaces = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"HideBackFaces",0); + Plane = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Plane",0); + Preview = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Preview", 0); + Antialiasing = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Antialiasing",0); // ^Fishman - Antializing for the preview window. + RandomSeed = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"RandomSeed",1); + Skybox = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"Skybox",0); + UseDetail = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"UseDetail",0); + AddTerrainKey = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"AddTerrainKey",0); // ^Fishman - Add terrain key to func_group. + UseLadder = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"UseLadder",0); + WaveType = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"WaveType",0); + vid_x = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"vid_x", 0); + vid_y = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"vid_y", 0); + view_x = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_x",0); + view_y = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_y",0); + view_cx = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_cx",0); + view_cy = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"view_cy",0); + + UsePatches = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"UsePatches",0); + + SlantAngle = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"SlantAngle",60); + GimpHints = g_FuncTable.m_pfnProfileLoadInt (file, OPTS_SECTION,"GimpHints",0); + + for(i=0; i + +#include "qerplugin.h" +//#include "qertypes.h" + +#include "igl.h" +#include "iui_gtk.h" +#include "ientity.h" + +#include "gendlgs.h" + +#define PLUGIN +#define Q3RADIANT + +#if defined(__linux__) || defined(__APPLE__) +template +inline T min (T x, T y) { return (x < y) ? x : y; } +template +inline T max (T x, T y) { return (x > y) ? x : y; } + +typedef struct { long x, y; } POINT; +typedef struct { long left, top, right, bottom; } RECT; +#endif +inline bool PtInRect (RECT *rc, POINT pt) +{ + if (pt.x < rc->left) return false; + if (pt.x > rc->right) return false; + if (pt.y < rc->bottom) return false; + if (pt.y > rc->top) return false; + return true; +} + +#define NUMGAMES 7 + +#define CONTENTS_SOLID 0x00000001 +#define CONTENTS_DETAIL 0x08000000 // brushes to be added after vis leafs +#define CONTENTS_LADDER 0x20000000 +#define SURF_HINT 0x100 // make a primary bsp splitter +#define SURF_SKIP 0x200 // completely ignore, allowing non-closed brushes +#define HINT_OFFSET 96 + +#define PI 3.14159265358979224 +#define RadiansToDegrees(a) (floor(a*57.2957795 - 0.5)+1.) +#define DegreesToRadians(a) (a/57.2957795) + +#define BOGUS_RANGE 65536 +#define DotProduct(x,y) (x[0]*y[0]+x[1]*y[1]+x[2]*y[2]) +#define VectorAdd(a,b,c) {c[0]=a[0]+b[0];c[1]=a[1]+b[1];c[2]=a[2]+b[2];} +#define VectorClear(x) {x[0] = x[1] = x[2] = 0;} +#define VectorCopy(a,b) {b[0]=a[0];b[1]=a[1];b[2]=a[2];} +#define VectorScale(a,b,c) {c[0]=b*a[0];c[1]=b*a[1];c[2]=b*a[2];} +#define VectorSubtract(a,b,c) {c[0]=a[0]-b[0];c[1]=a[1]-b[1];c[2]=a[2]-b[2];} +#define XYZVectorSubtract(a,b,c) {c[0]=(float)a[0]-(float)b[0];c[1]=(float)a[1]-(float)b[1];c[2]=(float)a[2]-(float)b[2];} +#define side(u1,v1,u2,v2,u3,v3) (v3-v1)*(u2-u1) - (u3-u1)*(v2-v1) + +#define QUAKE2 0 +#define HALFLIFE 1 +#define SIN 2 +#define HERETIC2 3 +#define KINGPIN 4 +#define GENESIS3D 5 +#define QUAKE3 6 + +#define MAX_FACES_PER_BRUSH 6 +#define SLIVER_ANGLE DegreesToRadians(20) +#define MAX_NODES (MAX_ROWS+1)*(MAX_ROWS+1) +#define MAX_TRIS (MAX_ROWS)*(MAX_ROWS) + +typedef float vec; +typedef vec vec3[3]; +typedef vec vec2[2]; + +typedef struct +{ + vec3 v[3]; + char texture[64]; + float Shift[2]; + float Rotate; + float Scale[2]; + int Contents; + int Surface; + int Value; +} FACE; + +typedef struct +{ + vec3 normal; + vec dist; +} PLANE; + +typedef struct +{ + int numpoints; + vec3 p[4]; // variable sized +} MY_WINDING; + +typedef struct +{ + int Number; + int NumFaces; + FACE face[MAX_FACES_PER_BRUSH]; +} BRUSH; + +typedef struct tagXYZ +{ + int fixed; + int done; + double p[3]; + double pp[3]; // these used only for general 3D projection (not isometric) + double fixed_value; + double range; + double rate; +} XYZ; + +// Q2 PAK file structures +typedef struct +{ + char id[4]; // Should be 'PACK' + int dstart; // Offest in the file to the directory + int dsize; // Size in bytes of the directory, same as num_items*64 +} pak_header_t; + +typedef struct +{ + char name[56]; // The name of the item, normal C string + int start; // Offset in .pak file to start of item + int size; // Size of item in bytes +} pak_item_t; + +// SiN .SIN structures +#define SINPAKHEADER (('K'<<24)+('A'<<16)+('P'<<8)+'S') +#define MAX_PAK_FILENAME_LENGTH 120 + +typedef struct +{ + char name[MAX_PAK_FILENAME_LENGTH]; + int filepos, filelen; +} dpackfile_t; + +typedef struct +{ + int ident; // == IDPAKHEADER + int dirofs; + int dirlen; +} dpackheader_t; + +// Half-Life WAD file structures +typedef struct +{ + char identification[4]; // should be WAD2 or 2DAW + int numlumps; + int infotableofs; +} wadinfo_t; + +typedef struct +{ + int filepos; + int disksize; + int size; // uncompressed + char type; + char compression; + char pad1, pad2; + char name[16]; // must be null terminated +} lumpinfo_t; + +typedef struct +{ + int signature; + short version; + short bitflag; + short compression_method; + short modfiletime; + short modfiledate; + int crc; + int compressed_size; + int uncompressed_size; + short filename_size; + short extra_size; +} zipheader_t; + +typedef struct +{ + double x[2]; + double y[2]; + double z[2]; +} bounding_box; + +typedef struct +{ + float p[3]; + int used; + int tri; + float error; + int fixed; +} NODE; + +typedef struct +{ + int v[3]; + int n[3]; // indices of neighboring triangles + PLANE plane; + int flag; + float min[3]; + float max[3]; +} TRI; + +//--------------- bitmap.c ----------------------------- +bool OpenBitmap (); +void GenerateBitmapMapping (); +//--------------- face.c ------------------------------- +void PlaneFromPoints (float *, float *, float *, PLANE *); +void CrossProduct (vec3 v1, vec3 v2, vec3 cross); +vec VectorNormalize (vec3 in, vec3 out); +//--------------- gendlg.c ----------------------------- +GtkWidget* create_main_dialog (); +void About (GtkWidget *parent); +//--------------- genmap.c ----------------------------- +double AtLeast(double,double); +bool CanEdit(int, int); +void CloseFuncGroup(); +bool FixedPoint(int,int); +void GenerateMap(); +void GenerateXYZ(); +double LessThan(double,double); +void MakeBrush(BRUSH *); +double MoreThan(double,double); +double Nearest(double,double); +double NoMoreThan(double,double); +void OpenFuncGroup(); +void PlasmaCloud(); +int PlayerStartZ(double,double); +void SubdividePlasma(int,int,int,int); +bool ValidSurface(); +void XYZtoV(XYZ *, vec3 *); +void MakePatch(patchMesh_t *); +double CalculateSnapValue(double value); + +//---------------- gensurf.c --------------------------- +bool GenSurfInit (); +void ReadIniFile (const char *); +void WriteIniFile (const char *); +void OpenSetup (GtkWidget*,int); +void SaveSetup (GtkWidget*); +//---------------- heretic.c --------------------------- +int GetDefSurfaceProps(char *); +//---------------- view.c ------------------------------ +void CreateViewWindow (); +void DrawGrid(RECT); +void DrawPreview(RECT); +void evaluate(); +void GetScaleFactor(RECT); +void project(XYZ *); +void Scale(RECT,XYZ,POINT *); +void ShowPreview (); +void UpdatePreview (bool); + +//---------------- plugin.c ----------------------------- +void UseFaceBounds(); + +extern _QERFuncTable_1 g_FuncTable; +extern _QERQglTable g_GLTable; +extern _QERUIGtkTable g_UIGtkTable; +extern _QEREntityTable g_EntityTable; +//#define MAX_ROWS 64 +#define MAX_ROWS 128 + +#define PLANE_XY0 0 +#define PLANE_XY1 1 +#define PLANE_YZ0 2 +#define PLANE_XZ0 3 +#define PLANE_YZ1 4 +#define PLANE_XZ1 5 + +#define WAVE_COS_SIN 0 +#define WAVE_HCYLINDER 1 +#define WAVE_VCYLINDER 2 +#define WAVE_BITMAP 3 +#define WAVE_ROUGH_ONLY 4 +#define WAVE_FORMULA 5 +#define WAVE_FIRST WAVE_COS_SIN +#define WAVE_LAST WAVE_FORMULA +#define DLG_WAVE_LAST DLG_WAVE_01+WAVE_LAST-WAVE_FIRST + +#define MSG_VERTEX_SELECTED WM_USER+1 + +typedef struct tagMYBITMAP +{ + char name[NAME_MAX]; + char defpath[NAME_MAX]; + double black_value; + double white_value; + int width, height; + unsigned char* colors; +} MYBITMAP; + +typedef struct tagELEMENT { + int i; + int j; +} ELEMENT; + +extern char gszAppDir[NAME_MAX]; +extern char gszCaption[64]; +extern char gszHelpFile[NAME_MAX]; +extern char gszIni[NAME_MAX]; +extern char gszMapFile[NAME_MAX]; +extern char gszVersion[64]; +extern double Amplitude; +extern double Roughness; +extern double TexOffset[2]; +extern double TexScale[2]; +extern double WaveLength; +extern double Hll, Hur, Vll, Vur; +extern double Z00, Z01, Z10, Z11; +extern double yaw, pitch, roll; +extern ELEMENT Vertex[(MAX_ROWS+1)*(MAX_ROWS+1)]; +extern int AddHints; +extern int ArghRad2; +extern int AutoOverwrite; +extern int Decimate; +extern int FileAppend; +extern int FixBorders; +extern int HideBackFaces; +extern int NH, NV; +extern int NumVerticesSelected; +extern int Plane; +extern int Preview; +extern int RandomSeed; +extern int Skybox; +extern int UseDetail; +extern int UseLadder; +extern int VertexMode; +extern int vid_x, vid_y; +extern int WaveType; +extern int gNumNodes; +extern int gNumTris; +extern int view_x, view_y; +extern int view_cx, view_cy; +extern int UsePatches; +extern int SlantAngle; +extern int GimpHints; +extern int Antialiasing; // ^Fishman - Antializing for the preview window. +extern int AddTerrainKey; // ^Fishman - Add terrain key to func_group. +extern int SnapToGrid; // Hydra : snap to grid +extern int SP; // ^Fishman - Snap to grid. + +/*extern HCURSOR ghCursorCurrent; +extern HCURSOR ghCursorDefault; +extern HCURSOR ghCursorVertex; +extern HINSTANCE ghInst;*/ +extern GtkWidget *g_pRadiantWnd; +extern GtkWidget *g_pWnd; +/*extern HWND ghwndAngles; +extern HWND ghwndFix; +*/extern GtkWidget *g_pWndPreview; +extern GtkWidget *g_pPreviewWidget; +extern MYBITMAP gbmp; +extern NODE *gNode; +extern TRI *gTri; +extern XYZ xyz[MAX_ROWS+1][MAX_ROWS+1]; + +extern int Game; +extern bounding_box PlayerBox[NUMGAMES]; +//extern char gszOutputDir[NUMGAMES][NAME_MAX]; +extern char Texture[NUMGAMES][3][64]; +//extern char gszTextureDir[NUMGAMES][NAME_MAX]; +extern char GameName[NUMGAMES][16]; +//extern char pakfile[NUMGAMES][NAME_MAX]; +//extern char lastpakfile[NUMGAMES][NAME_MAX]; +//extern int UsePak[NUMGAMES]; +//extern char GameDir[NUMGAMES][NAME_MAX]; +//extern char ExcelFunc[1024]; + +#endif // _GENSURF_H_ diff --git a/contrib/gtkgensurf/gtkgensurf.vcproj b/contrib/gtkgensurf/gtkgensurf.vcproj new file mode 100644 index 00000000..eeadd58e --- /dev/null +++ b/contrib/gtkgensurf/gtkgensurf.vcproj @@ -0,0 +1,91 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/gtkgensurf/heretic.cpp b/contrib/gtkgensurf/heretic.cpp new file mode 100644 index 00000000..7c5bcc03 --- /dev/null +++ b/contrib/gtkgensurf/heretic.cpp @@ -0,0 +1,150 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include "gensurf.h" + +// Heretic 2 - specific routines + +typedef struct palette_s +{ + guint8 r,g,b; +} palette_t; + +#define MIP_VERSION 2 +#define PAL_SIZE 256 +#define MIPLEVELS 16 + +typedef struct miptex_s +{ + int version; + char name[32]; + unsigned width[MIPLEVELS], height[MIPLEVELS]; + unsigned offsets[MIPLEVELS]; // four mip maps stored + char animname[32]; // next frame in animation chain + palette_t palette[PAL_SIZE]; + int flags; + int contents; + int value; +} miptex_t; + +//============================================================= +int GetDefSurfaceProps(char *Tex) +{ + return 0; // leo: only used for Heretic 2, fix later + /* + char path[NAME_MAX]; + char *p; + int flags; + miptex_t *mt; + FILE *f; + int length; + int pos; + + if(Game != HERETIC2) return 0; + if(!strlen(Tex)) return 0; + + mt = NULL; + flags = 0; + if(UsePak[Game]) + { + FILE *fpak; + pak_header_t pakheader; + pak_item_t pakitem; + int i; + int num; + int numitems; + + if (NULL != (fpak = fopen(pakfile[Game], "rb"))) + { + sprintf(path,"textures/%s.m8",Tex); + g_strdown(path); + num=fread(&pakheader,1,sizeof(pak_header_t),fpak); + if((size_t)num < sizeof(pak_header_t)) + { + fclose(fpak); + return 0; + } + if(strncmp(pakheader.id,"PACK",4)) + { + fclose(fpak); + return 0; + } + numitems = pakheader.dsize/sizeof(pak_item_t); + fseek(fpak,pakheader.dstart,SEEK_SET); + for(i=0; iflags; + free(mt); + } + } + } + fclose(fpak); + } + } + else + { + // Assume .map will be output to gamedir/maps, then back up + // to the gamedir and append /textures. Ugly but it should work + strcpy(path,gszMapFile); + g_strdown(path); + p = strstr(path,"maps"); + if(!p) return 0; + p[0] = '\0'; + strcat(path,"textures/"); + strcat(path,Tex); + strcat(path,".m8"); + f = fopen (path, "rb"); + if (!f) + flags = 0; + else + { + pos = ftell (f); + fseek (f, 0, SEEK_END); + length = ftell (f); + fseek (f, pos, SEEK_SET); + if((mt = (miptex_t*)malloc(length+1))==NULL) + flags = 0; + else + { + ((char *)mt)[length] = 0; + fread(mt, 1, length, f); + fclose (f); + flags = mt->flags; + free(mt); + } + } + } + return flags; + */ +} diff --git a/contrib/gtkgensurf/plugin.cpp b/contrib/gtkgensurf/plugin.cpp new file mode 100644 index 00000000..d7825cc2 --- /dev/null +++ b/contrib/gtkgensurf/plugin.cpp @@ -0,0 +1,227 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "gensurf.h" + +// Global plugin FuncTable +_QERFuncTable_1 g_FuncTable; +_QERQglTable g_GLTable; +_QERUIGtkTable g_UIGtkTable; +_QEREntityTable g_EntityTable; +bool SingleBrushSelected; +bool g_bInitDone; + +#include "iplugin.h" + +const char* QERPlug_Init(void* hApp, void* pMainWidget) +{ + g_pRadiantWnd = (GtkWidget*)pMainWidget; + + return "GenSurf for Q3Radiant"; +} + +const char* QERPlug_GetName () +{ + return "GtkGenSurf"; +} + +const char* QERPlug_GetCommandList () +{ + return "Wall facing 270...;Wall facing 180...;Wall facing 90...;Wall facing 0...;" + "Ceiling...;Ground surface...;-;About..."; +} + +// vMin/vMax provide the bounds of the selection, they are zero if there is no selection +// if there is a selection, bSingleBrush will be true if a single brush is selected +// if so, typical plugin behaviour (such as primitive creation) would use the bounds as +// a rule to create the primitive, then delete the selection +void QERPlug_Dispatch (const char *p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) +{ + bool Generate = false; + + if (!g_bInitDone) + { + if (GenSurfInit ()) + g_bInitDone = true; + } + + if (!strcmp (p, "Ground surface...")) + { + SingleBrushSelected = bSingleBrush; + Plane = PLANE_XY0; + if (SingleBrushSelected) + { + Hll = vMin[0]; + Vll = vMin[1]; + Hur = vMax[0]; + Vur = vMax[1]; + Z00 = Z01 = Z10 = Z11 = vMax[2]; + } + Generate = true; + } + else if (!strcmp (p, "Ceiling...")) + { + SingleBrushSelected = bSingleBrush; + Plane = PLANE_XY1; + if(SingleBrushSelected) + { + Hll = vMin[0]; + Vll = vMin[1]; + Hur = vMax[0]; + Vur = vMax[1]; + Z00 = Z01 = Z10 = Z11 = vMin[2]; + } + Generate = true; + } + else if (!strcmp (p, "Wall facing 0...")) + { + SingleBrushSelected = bSingleBrush; + Plane = PLANE_YZ0; + if (SingleBrushSelected) + { + Hll = vMin[1]; + Vll = vMin[2]; + Hur = vMax[1]; + Vur = vMax[2]; + Z00 = Z01 = Z10 = Z11 = vMax[0]; + } + Generate = true; + } + else if (!strcmp (p, "Wall facing 90...")) + { + SingleBrushSelected = bSingleBrush; + Plane = PLANE_XZ0; + if (SingleBrushSelected) + { + Hll = vMin[0]; + Vll = vMin[2]; + Hur = vMax[0]; + Vur = vMax[2]; + Z00 = Z01 = Z10 = Z11 = vMax[1]; + } + Generate = true; + } + else if (!strcmp (p, "Wall facing 180...")) + { + SingleBrushSelected = bSingleBrush; + Plane = PLANE_YZ1; + if (SingleBrushSelected) + { + Hll = vMin[1]; + Vll = vMin[2]; + Hur = vMax[1]; + Vur = vMax[2]; + Z00 = Z01 = Z10 = Z11 = vMin[0]; + } + Generate = true; + } + else if (!strcmp (p, "Wall facing 270...")) + { + SingleBrushSelected = bSingleBrush; + Plane = PLANE_XZ1; + if (SingleBrushSelected) + { + Hll = vMin[0]; + Vll = vMin[2]; + Hur = vMax[0]; + Vur = vMax[2]; + Z00 = Z01 = Z10 = Z11 = vMin[1]; + } + Generate = true; + } + else if (!strcmp(p,"About...")) + About (g_pRadiantWnd); + + if (Generate) + { + if (SingleBrushSelected) + UseFaceBounds (); + + gtk_widget_show (g_pWnd); + } +} + +extern "C" LPVOID WINAPI QERPlug_GetFuncTable() +{ + return &g_FuncTable; +} + +// ============================================================================= +// SYNAPSE + +#include "synapse.h" + +class GenSurfSynapseClient : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + GenSurfSynapseClient() { } + virtual ~GenSurfSynapseClient() { } +}; + +CSynapseServer* g_pSynapseServer = NULL; +GenSurfSynapseClient g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + g_SynapseClient.AddAPI(PLUGIN_MAJOR, "gtkgensurf", sizeof(_QERPluginTable)); + + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(_QERFuncTable_1), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(UIGTK_MAJOR, NULL, sizeof(_QERUIGtkTable), SYN_REQUIRE, &g_UIGtkTable); + g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(_QERQglTable), SYN_REQUIRE, &g_GLTable); + g_SynapseClient.AddAPI(ENTITY_MAJOR, NULL, sizeof(_QEREntityTable), SYN_REQUIRE, &g_EntityTable); + + return &g_SynapseClient; +} + +bool GenSurfSynapseClient::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, PLUGIN_MAJOR)) + { + _QERPluginTable* pTable= static_cast<_QERPluginTable*>(pAPI->mpTable); + + pTable->m_pfnQERPlug_Init = QERPlug_Init; + pTable->m_pfnQERPlug_GetName = QERPlug_GetName; + pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList; + pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch; + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* GenSurfSynapseClient::GetInfo() +{ + return "GtkGenSurf - built " __DATE__ " " RADIANT_VERSION; +} diff --git a/contrib/gtkgensurf/triangle.c b/contrib/gtkgensurf/triangle.c new file mode 100644 index 00000000..1462499f --- /dev/null +++ b/contrib/gtkgensurf/triangle.c @@ -0,0 +1,13236 @@ +#define ANSI_DECLARATORS +/*****************************************************************************/ +/* */ +/* 888888888 ,o, / 888 */ +/* 888 88o88o " o8888o 88o8888o o88888o 888 o88888o */ +/* 888 888 888 88b 888 888 888 888 888 d888 88b */ +/* 888 888 888 o88^o888 888 888 "88888" 888 8888oo888 */ +/* 888 888 888 C888 888 888 888 / 888 q888 */ +/* 888 888 888 "88o^888 888 888 Cb 888 "88oooo" */ +/* "8oo8D */ +/* */ +/* A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator. */ +/* (triangle.c) */ +/* */ +/* Version 1.3 */ +/* July 19, 1996 */ +/* */ +/* Copyright 1996 */ +/* Jonathan Richard Shewchuk */ +/* School of Computer Science */ +/* Carnegie Mellon University */ +/* 5000 Forbes Avenue */ +/* Pittsburgh, Pennsylvania 15213-3891 */ +/* jrs@cs.cmu.edu */ +/* */ +/* This program may be freely redistributed under the condition that the */ +/* copyright notices (including this entire header and the copyright */ +/* notice printed when the `-h' switch is selected) are not removed, and */ +/* no compensation is received. Private, research, and institutional */ +/* use is free. You may distribute modified versions of this code UNDER */ +/* THE CONDITION THAT THIS CODE AND ANY MODIFICATIONS MADE TO IT IN THE */ +/* SAME FILE REMAIN UNDER COPYRIGHT OF THE ORIGINAL AUTHOR, BOTH SOURCE */ +/* AND OBJECT CODE ARE MADE FREELY AVAILABLE WITHOUT CHARGE, AND CLEAR */ +/* NOTICE IS GIVEN OF THE MODIFICATIONS. Distribution of this code as */ +/* part of a commercial system is permissible ONLY BY DIRECT ARRANGEMENT */ +/* WITH THE AUTHOR. (If you are not directly supplying this code to a */ +/* customer, and you are instead telling them how they can obtain it for */ +/* free, then you are not required to make any arrangement with me.) */ +/* */ +/* Hypertext instructions for Triangle are available on the Web at */ +/* */ +/* http://www.cs.cmu.edu/~quake/triangle.html */ +/* */ +/* Some of the references listed below are marked [*]. These are available */ +/* for downloading from the Web page */ +/* */ +/* http://www.cs.cmu.edu/~quake/triangle.research.html */ +/* */ +/* A paper discussing some aspects of Triangle is available. See Jonathan */ +/* Richard Shewchuk, "Triangle: Engineering a 2D Quality Mesh Generator */ +/* and Delaunay Triangulator," First Workshop on Applied Computational */ +/* Geometry, ACM, May 1996. [*] */ +/* */ +/* Triangle was created as part of the Archimedes project in the School of */ +/* Computer Science at Carnegie Mellon University. Archimedes is a */ +/* system for compiling parallel finite element solvers. For further */ +/* information, see Anja Feldmann, Omar Ghattas, John R. Gilbert, Gary L. */ +/* Miller, David R. O'Hallaron, Eric J. Schwabe, Jonathan R. Shewchuk, */ +/* and Shang-Hua Teng, "Automated Parallel Solution of Unstructured PDE */ +/* Problems." To appear in Communications of the ACM, we hope. */ +/* */ +/* The quality mesh generation algorithm is due to Jim Ruppert, "A */ +/* Delaunay Refinement Algorithm for Quality 2-Dimensional Mesh */ +/* Generation," Journal of Algorithms 18(3):548-585, May 1995. [*] */ +/* */ +/* My implementation of the divide-and-conquer and incremental Delaunay */ +/* triangulation algorithms follows closely the presentation of Guibas */ +/* and Stolfi, even though I use a triangle-based data structure instead */ +/* of their quad-edge data structure. (In fact, I originally implemented */ +/* Triangle using the quad-edge data structure, but switching to a */ +/* triangle-based data structure sped Triangle by a factor of two.) The */ +/* mesh manipulation primitives and the two aforementioned Delaunay */ +/* triangulation algorithms are described by Leonidas J. Guibas and Jorge */ +/* Stolfi, "Primitives for the Manipulation of General Subdivisions and */ +/* the Computation of Voronoi Diagrams," ACM Transactions on Graphics */ +/* 4(2):74-123, April 1985. */ +/* */ +/* Their O(n log n) divide-and-conquer algorithm is adapted from Der-Tsai */ +/* Lee and Bruce J. Schachter, "Two Algorithms for Constructing the */ +/* Delaunay Triangulation," International Journal of Computer and */ +/* Information Science 9(3):219-242, 1980. The idea to improve the */ +/* divide-and-conquer algorithm by alternating between vertical and */ +/* horizontal cuts was introduced by Rex A. Dwyer, "A Faster Divide-and- */ +/* Conquer Algorithm for Constructing Delaunay Triangulations," */ +/* Algorithmica 2(2):137-151, 1987. */ +/* */ +/* The incremental insertion algorithm was first proposed by C. L. Lawson, */ +/* "Software for C1 Surface Interpolation," in Mathematical Software III, */ +/* John R. Rice, editor, Academic Press, New York, pp. 161-194, 1977. */ +/* For point location, I use the algorithm of Ernst P. Mucke, Isaac */ +/* Saias, and Binhai Zhu, "Fast Randomized Point Location Without */ +/* Preprocessing in Two- and Three-dimensional Delaunay Triangulations," */ +/* Proceedings of the Twelfth Annual Symposium on Computational Geometry, */ +/* ACM, May 1996. [*] If I were to randomize the order of point */ +/* insertion (I currently don't bother), their result combined with the */ +/* result of Leonidas J. Guibas, Donald E. Knuth, and Micha Sharir, */ +/* "Randomized Incremental Construction of Delaunay and Voronoi */ +/* Diagrams," Algorithmica 7(4):381-413, 1992, would yield an expected */ +/* O(n^{4/3}) bound on running time. */ +/* */ +/* The O(n log n) sweepline Delaunay triangulation algorithm is taken from */ +/* Steven Fortune, "A Sweepline Algorithm for Voronoi Diagrams", */ +/* Algorithmica 2(2):153-174, 1987. A random sample of edges on the */ +/* boundary of the triangulation are maintained in a splay tree for the */ +/* purpose of point location. Splay trees are described by Daniel */ +/* Dominic Sleator and Robert Endre Tarjan, "Self-Adjusting Binary Search */ +/* Trees," Journal of the ACM 32(3):652-686, July 1985. */ +/* */ +/* The algorithms for exact computation of the signs of determinants are */ +/* described in Jonathan Richard Shewchuk, "Adaptive Precision Floating- */ +/* Point Arithmetic and Fast Robust Geometric Predicates," Technical */ +/* Report CMU-CS-96-140, School of Computer Science, Carnegie Mellon */ +/* University, Pittsburgh, Pennsylvania, May 1996. [*] (Submitted to */ +/* Discrete & Computational Geometry.) An abbreviated version appears as */ +/* Jonathan Richard Shewchuk, "Robust Adaptive Floating-Point Geometric */ +/* Predicates," Proceedings of the Twelfth Annual Symposium on Computa- */ +/* tional Geometry, ACM, May 1996. [*] Many of the ideas for my exact */ +/* arithmetic routines originate with Douglas M. Priest, "Algorithms for */ +/* Arbitrary Precision Floating Point Arithmetic," Tenth Symposium on */ +/* Computer Arithmetic, 132-143, IEEE Computer Society Press, 1991. [*] */ +/* Many of the ideas for the correct evaluation of the signs of */ +/* determinants are taken from Steven Fortune and Christopher J. Van Wyk, */ +/* "Efficient Exact Arithmetic for Computational Geometry," Proceedings */ +/* of the Ninth Annual Symposium on Computational Geometry, ACM, */ +/* pp. 163-172, May 1993, and from Steven Fortune, "Numerical Stability */ +/* of Algorithms for 2D Delaunay Triangulations," International Journal */ +/* of Computational Geometry & Applications 5(1-2):193-213, March-June */ +/* 1995. */ +/* */ +/* For definitions of and results involving Delaunay triangulations, */ +/* constrained and conforming versions thereof, and other aspects of */ +/* triangular mesh generation, see the excellent survey by Marshall Bern */ +/* and David Eppstein, "Mesh Generation and Optimal Triangulation," in */ +/* Computing and Euclidean Geometry, Ding-Zhu Du and Frank Hwang, */ +/* editors, World Scientific, Singapore, pp. 23-90, 1992. */ +/* */ +/* The time for incrementally adding PSLG (planar straight line graph) */ +/* segments to create a constrained Delaunay triangulation is probably */ +/* O(n^2) per segment in the worst case and O(n) per edge in the common */ +/* case, where n is the number of triangles that intersect the segment */ +/* before it is inserted. This doesn't count point location, which can */ +/* be much more expensive. (This note does not apply to conforming */ +/* Delaunay triangulations, for which a different method is used to */ +/* insert segments.) */ +/* */ +/* The time for adding segments to a conforming Delaunay triangulation is */ +/* not clear, but does not depend upon n alone. In some cases, very */ +/* small features (like a point lying next to a segment) can cause a */ +/* single segment to be split an arbitrary number of times. Of course, */ +/* floating-point precision is a practical barrier to how much this can */ +/* happen. */ +/* */ +/* The time for deleting a point from a Delaunay triangulation is O(n^2) in */ +/* the worst case and O(n) in the common case, where n is the degree of */ +/* the point being deleted. I could improve this to expected O(n) time */ +/* by "inserting" the neighboring vertices in random order, but n is */ +/* usually quite small, so it's not worth the bother. (The O(n) time */ +/* for random insertion follows from L. Paul Chew, "Building Voronoi */ +/* Diagrams for Convex Polygons in Linear Expected Time," Technical */ +/* Report PCS-TR90-147, Department of Mathematics and Computer Science, */ +/* Dartmouth College, 1990. */ +/* */ +/* Ruppert's Delaunay refinement algorithm typically generates triangles */ +/* at a linear rate (constant time per triangle) after the initial */ +/* triangulation is formed. There may be pathological cases where more */ +/* time is required, but these never arise in practice. */ +/* */ +/* The segment intersection formulae are straightforward. If you want to */ +/* see them derived, see Franklin Antonio. "Faster Line Segment */ +/* Intersection." In Graphics Gems III (David Kirk, editor), pp. 199- */ +/* 202. Academic Press, Boston, 1992. */ +/* */ +/* If you make any improvements to this code, please please please let me */ +/* know, so that I may obtain the improvements. Even if you don't change */ +/* the code, I'd still love to hear what it's being used for. */ +/* */ +/* Disclaimer: Neither I nor Carnegie Mellon warrant this code in any way */ +/* whatsoever. This code is provided "as-is". Use at your own risk. */ +/* */ +/*****************************************************************************/ + +/* For single precision (which will save some memory and reduce paging), */ +/* define the symbol SINGLE by using the -DSINGLE compiler switch or by */ +/* writing "#define SINGLE" below. */ +/* */ +/* For double precision (which will allow you to refine meshes to a smaller */ +/* edge length), leave SINGLE undefined. */ +/* */ +/* Double precision uses more memory, but improves the resolution of the */ +/* meshes you can generate with Triangle. It also reduces the likelihood */ +/* of a floating exception due to overflow. Finally, it is much faster */ +/* than single precision on 64-bit architectures like the DEC Alpha. I */ +/* recommend double precision unless you want to generate a mesh for which */ +/* you do not have enough memory. */ + +#define SINGLE + +#ifdef SINGLE +#define REAL float +#else /* not SINGLE */ +#define REAL double +#endif /* not SINGLE */ + +/* If yours is not a Unix system, define the NO_TIMER compiler switch to */ +/* remove the Unix-specific timing code. */ + +#define NO_TIMER + +/* To insert lots of self-checks for internal errors, define the SELF_CHECK */ +/* symbol. This will slow down the program significantly. It is best to */ +/* define the symbol using the -DSELF_CHECK compiler switch, but you could */ +/* write "#define SELF_CHECK" below. If you are modifying this code, I */ +/* recommend you turn self-checks on. */ + +/* #define SELF_CHECK */ + +/* To compile Triangle as a callable object library (triangle.o), define the */ +/* TRILIBRARY symbol. Read the file triangle.h for details on how to call */ +/* the procedure triangulate() that results. */ + +#define TRILIBRARY + +/* It is possible to generate a smaller version of Triangle using one or */ +/* both of the following symbols. Define the REDUCED symbol to eliminate */ +/* all features that are primarily of research interest; specifically, the */ +/* -i, -F, -s, and -C switches. Define the CDT_ONLY symbol to eliminate */ +/* all meshing algorithms above and beyond constrained Delaunay */ +/* triangulation; specifically, the -r, -q, -a, -S, and -s switches. */ +/* These reductions are most likely to be useful when generating an object */ +/* library (triangle.o) by defining the TRILIBRARY symbol. */ + +#define REDUCED +#define CDT_ONLY + +/* On some machines, the exact arithmetic routines might be defeated by the */ +/* use of internal extended precision floating-point registers. Sometimes */ +/* this problem can be fixed by defining certain values to be volatile, */ +/* thus forcing them to be stored to memory and rounded off. This isn't */ +/* a great solution, though, as it slows Triangle down. */ +/* */ +/* To try this out, write "#define INEXACT volatile" below. Normally, */ +/* however, INEXACT should be defined to be nothing. ("#define INEXACT".) */ + +#define INEXACT /* Nothing */ +/* #define INEXACT volatile */ + +/* Maximum number of characters in a file name (including the null). */ + +#define FILENAMESIZE 512 + +/* Maximum number of characters in a line read from a file (including the */ +/* null). */ + +#define INPUTLINESIZE 512 + +/* For efficiency, a variety of data structures are allocated in bulk. The */ +/* following constants determine how many of each structure is allocated */ +/* at once. */ + +#define TRIPERBLOCK 4092 /* Number of triangles allocated at once. */ +#define SHELLEPERBLOCK 508 /* Number of shell edges allocated at once. */ +#define POINTPERBLOCK 4092 /* Number of points allocated at once. */ +#define VIRUSPERBLOCK 1020 /* Number of virus triangles allocated at once. */ +/* Number of encroached segments allocated at once. */ +#define BADSEGMENTPERBLOCK 252 +/* Number of skinny triangles allocated at once. */ +#define BADTRIPERBLOCK 4092 +/* Number of splay tree nodes allocated at once. */ +#define SPLAYNODEPERBLOCK 508 + +/* The point marker DEADPOINT is an arbitrary number chosen large enough to */ +/* (hopefully) not conflict with user boundary markers. Make sure that it */ +/* is small enough to fit into your machine's integer size. */ + +#define DEADPOINT -1073741824 + +/* The next line is used to outsmart some very stupid compilers. If your */ +/* compiler is smarter, feel free to replace the "int" with "void". */ +/* Not that it matters. */ + +#define VOID int + +/* Two constants for algorithms based on random sampling. Both constants */ +/* have been chosen empirically to optimize their respective algorithms. */ + +/* Used for the point location scheme of Mucke, Saias, and Zhu, to decide */ +/* how large a random sample of triangles to inspect. */ +#define SAMPLEFACTOR 11 +/* Used in Fortune's sweepline Delaunay algorithm to determine what fraction */ +/* of boundary edges should be maintained in the splay tree for point */ +/* location on the front. */ +#define SAMPLERATE 10 + +/* A number that speaks for itself, every kissable digit. */ + +#define PI 3.141592653589793238462643383279502884197169399375105820974944592308 + +/* Another fave. */ + +#define SQUAREROOTTWO 1.4142135623730950488016887242096980785696718753769480732 + +/* And here's one for those of you who are intimidated by math. */ + +#define ONETHIRD 0.333333333333333333333333333333333333333333333333333333333333 + +#include +#include +#include +#ifndef NO_TIMER +#include +#endif /* NO_TIMER */ +#ifdef TRILIBRARY +#include "triangle.h" +#endif /* TRILIBRARY */ + +/* The following obscenity seems to be necessary to ensure that this program */ +/* will port to Dec Alphas running OSF/1, because their stdio.h file commits */ +/* the unpardonable sin of including stdlib.h. Hence, malloc(), free(), and */ +/* exit() may or may not already be defined at this point. I declare these */ +/* functions explicitly because some non-ANSI C compilers lack stdlib.h. */ + +#ifndef _STDLIB_H_ +extern void *malloc(); +extern void free(); +extern void exit(); +extern double strtod(); +extern long strtol(); +#endif /* _STDLIB_H_ */ + +/* A few forward declarations. */ + +void poolrestart(); +#ifndef TRILIBRARY +char *readline(); +char *findfield(); +#endif /* not TRILIBRARY */ + +/* Labels that signify whether a record consists primarily of pointers or of */ +/* floating-point words. Used to make decisions about data alignment. */ + +enum wordtype {POINTER, FLOATINGPOINT}; + +/* Labels that signify the result of point location. The result of a */ +/* search indicates that the point falls in the interior of a triangle, on */ +/* an edge, on a vertex, or outside the mesh. */ + +enum locateresult {INTRIANGLE, ONEDGE, ONVERTEX, OUTSIDE}; + +/* Labels that signify the result of site insertion. The result indicates */ +/* that the point was inserted with complete success, was inserted but */ +/* encroaches on a segment, was not inserted because it lies on a segment, */ +/* or was not inserted because another point occupies the same location. */ + +enum insertsiteresult {SUCCESSFULPOINT, ENCROACHINGPOINT, VIOLATINGPOINT, + DUPLICATEPOINT}; + +/* Labels that signify the result of direction finding. The result */ +/* indicates that a segment connecting the two query points falls within */ +/* the direction triangle, along the left edge of the direction triangle, */ +/* or along the right edge of the direction triangle. */ + +enum finddirectionresult {WITHIN, LEFTCOLLINEAR, RIGHTCOLLINEAR}; + +/* Labels that signify the result of the circumcenter computation routine. */ +/* The return value indicates which edge of the triangle is shortest. */ + +enum circumcenterresult {OPPOSITEORG, OPPOSITEDEST, OPPOSITEAPEX}; + +/*****************************************************************************/ +/* */ +/* The basic mesh data structures */ +/* */ +/* There are three: points, triangles, and shell edges (abbreviated */ +/* `shelle'). These three data structures, linked by pointers, comprise */ +/* the mesh. A point simply represents a point in space and its properties.*/ +/* A triangle is a triangle. A shell edge is a special data structure used */ +/* to represent impenetrable segments in the mesh (including the outer */ +/* boundary, boundaries of holes, and internal boundaries separating two */ +/* triangulated regions). Shell edges represent boundaries defined by the */ +/* user that triangles may not lie across. */ +/* */ +/* A triangle consists of a list of three vertices, a list of three */ +/* adjoining triangles, a list of three adjoining shell edges (when shell */ +/* edges are used), an arbitrary number of optional user-defined floating- */ +/* point attributes, and an optional area constraint. The latter is an */ +/* upper bound on the permissible area of each triangle in a region, used */ +/* for mesh refinement. */ +/* */ +/* For a triangle on a boundary of the mesh, some or all of the neighboring */ +/* triangles may not be present. For a triangle in the interior of the */ +/* mesh, often no neighboring shell edges are present. Such absent */ +/* triangles and shell edges are never represented by NULL pointers; they */ +/* are represented by two special records: `dummytri', the triangle that */ +/* fills "outer space", and `dummysh', the omnipresent shell edge. */ +/* `dummytri' and `dummysh' are used for several reasons; for instance, */ +/* they can be dereferenced and their contents examined without causing the */ +/* memory protection exception that would occur if NULL were dereferenced. */ +/* */ +/* However, it is important to understand that a triangle includes other */ +/* information as well. The pointers to adjoining vertices, triangles, and */ +/* shell edges are ordered in a way that indicates their geometric relation */ +/* to each other. Furthermore, each of these pointers contains orientation */ +/* information. Each pointer to an adjoining triangle indicates which face */ +/* of that triangle is contacted. Similarly, each pointer to an adjoining */ +/* shell edge indicates which side of that shell edge is contacted, and how */ +/* the shell edge is oriented relative to the triangle. */ +/* */ +/* Shell edges are found abutting edges of triangles; either sandwiched */ +/* between two triangles, or resting against one triangle on an exterior */ +/* boundary or hole boundary. */ +/* */ +/* A shell edge consists of a list of two vertices, a list of two */ +/* adjoining shell edges, and a list of two adjoining triangles. One of */ +/* the two adjoining triangles may not be present (though there should */ +/* always be one), and neighboring shell edges might not be present. */ +/* Shell edges also store a user-defined integer "boundary marker". */ +/* Typically, this integer is used to indicate what sort of boundary */ +/* conditions are to be applied at that location in a finite element */ +/* simulation. */ +/* */ +/* Like triangles, shell edges maintain information about the relative */ +/* orientation of neighboring objects. */ +/* */ +/* Points are relatively simple. A point is a list of floating point */ +/* numbers, starting with the x, and y coordinates, followed by an */ +/* arbitrary number of optional user-defined floating-point attributes, */ +/* followed by an integer boundary marker. During the segment insertion */ +/* phase, there is also a pointer from each point to a triangle that may */ +/* contain it. Each pointer is not always correct, but when one is, it */ +/* speeds up segment insertion. These pointers are assigned values once */ +/* at the beginning of the segment insertion phase, and are not used or */ +/* updated at any other time. Edge swapping during segment insertion will */ +/* render some of them incorrect. Hence, don't rely upon them for */ +/* anything. For the most part, points do not have any information about */ +/* what triangles or shell edges they are linked to. */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* Handles */ +/* */ +/* The oriented triangle (`triedge') and oriented shell edge (`edge') data */ +/* structures defined below do not themselves store any part of the mesh. */ +/* The mesh itself is made of `triangle's, `shelle's, and `point's. */ +/* */ +/* Oriented triangles and oriented shell edges will usually be referred to */ +/* as "handles". A handle is essentially a pointer into the mesh; it */ +/* allows you to "hold" one particular part of the mesh. Handles are used */ +/* to specify the regions in which one is traversing and modifying the mesh.*/ +/* A single `triangle' may be held by many handles, or none at all. (The */ +/* latter case is not a memory leak, because the triangle is still */ +/* connected to other triangles in the mesh.) */ +/* */ +/* A `triedge' is a handle that holds a triangle. It holds a specific side */ +/* of the triangle. An `edge' is a handle that holds a shell edge. It */ +/* holds either the left or right side of the edge. */ +/* */ +/* Navigation about the mesh is accomplished through a set of mesh */ +/* manipulation primitives, further below. Many of these primitives take */ +/* a handle and produce a new handle that holds the mesh near the first */ +/* handle. Other primitives take two handles and glue the corresponding */ +/* parts of the mesh together. The exact position of the handles is */ +/* important. For instance, when two triangles are glued together by the */ +/* bond() primitive, they are glued by the sides on which the handles lie. */ +/* */ +/* Because points have no information about which triangles they are */ +/* attached to, I commonly represent a point by use of a handle whose */ +/* origin is the point. A single handle can simultaneously represent a */ +/* triangle, an edge, and a point. */ +/* */ +/*****************************************************************************/ + +/* The triangle data structure. Each triangle contains three pointers to */ +/* adjoining triangles, plus three pointers to vertex points, plus three */ +/* pointers to shell edges (defined below; these pointers are usually */ +/* `dummysh'). It may or may not also contain user-defined attributes */ +/* and/or a floating-point "area constraint". It may also contain extra */ +/* pointers for nodes, when the user asks for high-order elements. */ +/* Because the size and structure of a `triangle' is not decided until */ +/* runtime, I haven't simply defined the type `triangle' to be a struct. */ + +typedef REAL **triangle; /* Really: typedef triangle *triangle */ + +/* An oriented triangle: includes a pointer to a triangle and orientation. */ +/* The orientation denotes an edge of the triangle. Hence, there are */ +/* three possible orientations. By convention, each edge is always */ +/* directed to point counterclockwise about the corresponding triangle. */ + +struct triedge { + triangle *tri; + int orient; /* Ranges from 0 to 2. */ +}; + +/* The shell data structure. Each shell edge contains two pointers to */ +/* adjoining shell edges, plus two pointers to vertex points, plus two */ +/* pointers to adjoining triangles, plus one shell marker. */ + +typedef REAL **shelle; /* Really: typedef shelle *shelle */ + +/* An oriented shell edge: includes a pointer to a shell edge and an */ +/* orientation. The orientation denotes a side of the edge. Hence, there */ +/* are two possible orientations. By convention, the edge is always */ +/* directed so that the "side" denoted is the right side of the edge. */ + +struct edge { + shelle *sh; + int shorient; /* Ranges from 0 to 1. */ +}; + +/* The point data structure. Each point is actually an array of REALs. */ +/* The number of REALs is unknown until runtime. An integer boundary */ +/* marker, and sometimes a pointer to a triangle, is appended after the */ +/* REALs. */ + +typedef REAL *point; + +/* A queue used to store encroached segments. Each segment's vertices are */ +/* stored so that one can check whether a segment is still the same. */ + +struct badsegment { + struct edge encsegment; /* An encroached segment. */ + point segorg, segdest; /* The two vertices. */ + struct badsegment *nextsegment; /* Pointer to next encroached segment. */ +}; + +/* A queue used to store bad triangles. The key is the square of the cosine */ +/* of the smallest angle of the triangle. Each triangle's vertices are */ +/* stored so that one can check whether a triangle is still the same. */ + +struct badface { + struct triedge badfacetri; /* A bad triangle. */ + REAL key; /* cos^2 of smallest (apical) angle. */ + point faceorg, facedest, faceapex; /* The three vertices. */ + struct badface *nextface; /* Pointer to next bad triangle. */ +}; + +/* A node in a heap used to store events for the sweepline Delaunay */ +/* algorithm. Nodes do not point directly to their parents or children in */ +/* the heap. Instead, each node knows its position in the heap, and can */ +/* look up its parent and children in a separate array. The `eventptr' */ +/* points either to a `point' or to a triangle (in encoded format, so that */ +/* an orientation is included). In the latter case, the origin of the */ +/* oriented triangle is the apex of a "circle event" of the sweepline */ +/* algorithm. To distinguish site events from circle events, all circle */ +/* events are given an invalid (smaller than `xmin') x-coordinate `xkey'. */ + +struct event { + REAL xkey, ykey; /* Coordinates of the event. */ + VOID *eventptr; /* Can be a point or the location of a circle event. */ + int heapposition; /* Marks this event's position in the heap. */ +}; + +/* A node in the splay tree. Each node holds an oriented ghost triangle */ +/* that represents a boundary edge of the growing triangulation. When a */ +/* circle event covers two boundary edges with a triangle, so that they */ +/* are no longer boundary edges, those edges are not immediately deleted */ +/* from the tree; rather, they are lazily deleted when they are next */ +/* encountered. (Since only a random sample of boundary edges are kept */ +/* in the tree, lazy deletion is faster.) `keydest' is used to verify */ +/* that a triangle is still the same as when it entered the splay tree; if */ +/* it has been rotated (due to a circle event), it no longer represents a */ +/* boundary edge and should be deleted. */ + +struct splaynode { + struct triedge keyedge; /* Lprev of an edge on the front. */ + point keydest; /* Used to verify that splay node is still live. */ + struct splaynode *lchild, *rchild; /* Children in splay tree. */ +}; + +/* A type used to allocate memory. firstblock is the first block of items. */ +/* nowblock is the block from which items are currently being allocated. */ +/* nextitem points to the next slab of free memory for an item. */ +/* deaditemstack is the head of a linked list (stack) of deallocated items */ +/* that can be recycled. unallocateditems is the number of items that */ +/* remain to be allocated from nowblock. */ +/* */ +/* Traversal is the process of walking through the entire list of items, and */ +/* is separate from allocation. Note that a traversal will visit items on */ +/* the "deaditemstack" stack as well as live items. pathblock points to */ +/* the block currently being traversed. pathitem points to the next item */ +/* to be traversed. pathitemsleft is the number of items that remain to */ +/* be traversed in pathblock. */ +/* */ +/* itemwordtype is set to POINTER or FLOATINGPOINT, and is used to suggest */ +/* what sort of word the record is primarily made up of. alignbytes */ +/* determines how new records should be aligned in memory. itembytes and */ +/* itemwords are the length of a record in bytes (after rounding up) and */ +/* words. itemsperblock is the number of items allocated at once in a */ +/* single block. items is the number of currently allocated items. */ +/* maxitems is the maximum number of items that have been allocated at */ +/* once; it is the current number of items plus the number of records kept */ +/* on deaditemstack. */ + +struct memorypool { + VOID **firstblock, **nowblock; + VOID *nextitem; + VOID *deaditemstack; + VOID **pathblock; + VOID *pathitem; + enum wordtype itemwordtype; + int alignbytes; + int itembytes, itemwords; + int itemsperblock; + long items, maxitems; + int unallocateditems; + int pathitemsleft; +}; + +/* Variables used to allocate memory for triangles, shell edges, points, */ +/* viri (triangles being eaten), bad (encroached) segments, bad (skinny */ +/* or too large) triangles, and splay tree nodes. */ + +static struct memorypool triangles; +static struct memorypool shelles; +static struct memorypool points; +static struct memorypool viri; +static struct memorypool badsegments; +static struct memorypool badtriangles; +static struct memorypool splaynodes; + +/* Variables that maintain the bad triangle queues. The tails are pointers */ +/* to the pointers that have to be filled in to enqueue an item. */ + +static struct badface *queuefront[64]; +static struct badface **queuetail[64]; + +static REAL xmin, xmax, ymin, ymax; /* x and y bounds. */ +static REAL xminextreme; /* Nonexistent x value used as a flag in sweepline. */ +static int inpoints; /* Number of input points. */ +static int inelements; /* Number of input triangles. */ +static int insegments; /* Number of input segments. */ +static int holes; /* Number of input holes. */ +static int regions; /* Number of input regions. */ +static long edges; /* Number of output edges. */ +static int mesh_dim; /* Dimension (ought to be 2). */ +static int nextras; /* Number of attributes per point. */ +static int eextras; /* Number of attributes per triangle. */ +static long hullsize; /* Number of edges of convex hull. */ +static int triwords; /* Total words per triangle. */ +static int shwords; /* Total words per shell edge. */ +static int pointmarkindex; /* Index to find boundary marker of a point. */ +static int point2triindex; /* Index to find a triangle adjacent to a point. */ +static int highorderindex; /* Index to find extra nodes for high-order elements. */ +static int elemattribindex; /* Index to find attributes of a triangle. */ +static int areaboundindex; /* Index to find area bound of a triangle. */ +static int checksegments; /* Are there segments in the triangulation yet? */ +static int readnodefile; /* Has a .node file been read? */ +static long samples; /* Number of random samples for point location. */ +static unsigned long randomseed; /* Current random number seed. */ + +static REAL splitter; /* Used to split REAL factors for exact multiplication. */ +static REAL epsilon; /* Floating-point machine epsilon. */ +static REAL resulterrbound; +static REAL ccwerrboundA, ccwerrboundB, ccwerrboundC; +static REAL iccerrboundA, iccerrboundB, iccerrboundC; + +static long incirclecount; /* Number of incircle tests performed. */ +static long counterclockcount; /* Number of counterclockwise tests performed. */ +static long hyperbolacount; /* Number of right-of-hyperbola tests performed. */ +static long circumcentercount; /* Number of circumcenter calculations performed. */ +static long circletopcount; /* Number of circle top calculations performed. */ + +/* Switches for the triangulator. */ +/* poly: -p switch. refine: -r switch. */ +/* quality: -q switch. */ +/* minangle: minimum angle bound, specified after -q switch. */ +/* goodangle: cosine squared of minangle. */ +/* vararea: -a switch without number. */ +/* fixedarea: -a switch with number. */ +/* maxarea: maximum area bound, specified after -a switch. */ +/* regionattrib: -A switch. convex: -c switch. */ +/* firstnumber: inverse of -z switch. All items are numbered starting */ +/* from firstnumber. */ +/* edgesout: -e switch. voronoi: -v switch. */ +/* neighbors: -n switch. geomview: -g switch. */ +/* nobound: -B switch. nopolywritten: -P switch. */ +/* nonodewritten: -N switch. noelewritten: -E switch. */ +/* noiterationnum: -I switch. noholes: -O switch. */ +/* noexact: -X switch. */ +/* order: element order, specified after -o switch. */ +/* nobisect: count of how often -Y switch is selected. */ +/* steiner: maximum number of Steiner points, specified after -S switch. */ +/* steinerleft: number of Steiner points not yet used. */ +/* incremental: -i switch. sweepline: -F switch. */ +/* dwyer: inverse of -l switch. */ +/* splitseg: -s switch. */ +/* docheck: -C switch. */ +/* quiet: -Q switch. verbose: count of how often -V switch is selected. */ +/* useshelles: -p, -r, -q, or -c switch; determines whether shell edges */ +/* are used at all. */ +/* */ +/* Read the instructions to find out the meaning of these switches. */ + +static int poly, refine, quality, vararea, fixedarea, regionattrib, convex; +static int firstnumber; +static int edgesout, voronoi, neighbors, geomview; +static int nobound, nopolywritten, nonodewritten, noelewritten, noiterationnum; +static int noholes, noexact; +static int incremental, sweepline, dwyer; +static int splitseg; +static int docheck; +static int quiet, verbose; +static int useshelles; +static int order; +static int nobisect; +static int steiner, steinerleft; +static REAL minangle, goodangle; +static REAL maxarea; + +/* Variables for file names. */ + +#ifndef TRILIBRARY +char innodefilename[FILENAMESIZE]; +char inelefilename[FILENAMESIZE]; +char inpolyfilename[FILENAMESIZE]; +char areafilename[FILENAMESIZE]; +char outnodefilename[FILENAMESIZE]; +char outelefilename[FILENAMESIZE]; +char outpolyfilename[FILENAMESIZE]; +char edgefilename[FILENAMESIZE]; +char vnodefilename[FILENAMESIZE]; +char vedgefilename[FILENAMESIZE]; +char neighborfilename[FILENAMESIZE]; +char offfilename[FILENAMESIZE]; +#endif /* not TRILIBRARY */ + +/* Triangular bounding box points. */ + +static point infpoint1, infpoint2, infpoint3; + +/* Pointer to the `triangle' that occupies all of "outer space". */ + +static triangle *dummytri; +static triangle *dummytribase; /* Keep base address so we can free() it later. */ + +/* Pointer to the omnipresent shell edge. Referenced by any triangle or */ +/* shell edge that isn't really connected to a shell edge at that */ +/* location. */ + +static shelle *dummysh; +static shelle *dummyshbase; /* Keep base address so we can free() it later. */ + +/* Pointer to a recently visited triangle. Improves point location if */ +/* proximate points are inserted sequentially. */ + +static struct triedge recenttri; + +/*****************************************************************************/ +/* */ +/* Mesh manipulation primitives. Each triangle contains three pointers to */ +/* other triangles, with orientations. Each pointer points not to the */ +/* first byte of a triangle, but to one of the first three bytes of a */ +/* triangle. It is necessary to extract both the triangle itself and the */ +/* orientation. To save memory, I keep both pieces of information in one */ +/* pointer. To make this possible, I assume that all triangles are aligned */ +/* to four-byte boundaries. The `decode' routine below decodes a pointer, */ +/* extracting an orientation (in the range 0 to 2) and a pointer to the */ +/* beginning of a triangle. The `encode' routine compresses a pointer to a */ +/* triangle and an orientation into a single pointer. My assumptions that */ +/* triangles are four-byte-aligned and that the `unsigned long' type is */ +/* long enough to hold a pointer are two of the few kludges in this program.*/ +/* */ +/* Shell edges are manipulated similarly. A pointer to a shell edge */ +/* carries both an address and an orientation in the range 0 to 1. */ +/* */ +/* The other primitives take an oriented triangle or oriented shell edge, */ +/* and return an oriented triangle or oriented shell edge or point; or they */ +/* change the connections in the data structure. */ +/* */ +/*****************************************************************************/ + +/********* Mesh manipulation primitives begin here *********/ +/** **/ +/** **/ + +/* Fast lookup arrays to speed some of the mesh manipulation primitives. */ + +int plus1mod3[3] = {1, 2, 0}; +int minus1mod3[3] = {2, 0, 1}; + +/********* Primitives for triangles *********/ +/* */ +/* */ + +/* decode() converts a pointer to an oriented triangle. The orientation is */ +/* extracted from the two least significant bits of the pointer. */ + +#define decode(ptr, triedge) \ + (triedge).orient = (int) ((unsigned long) (ptr) & (unsigned long) 3l); \ + (triedge).tri = (triangle *) \ + ((unsigned long) (ptr) ^ (unsigned long) (triedge).orient) + +/* encode() compresses an oriented triangle into a single pointer. It */ +/* relies on the assumption that all triangles are aligned to four-byte */ +/* boundaries, so the two least significant bits of (triedge).tri are zero.*/ + +#define encode(triedge) \ + (triangle) ((unsigned long) (triedge).tri | (unsigned long) (triedge).orient) + +/* The following edge manipulation primitives are all described by Guibas */ +/* and Stolfi. However, they use an edge-based data structure, whereas I */ +/* am using a triangle-based data structure. */ + +/* sym() finds the abutting triangle, on the same edge. Note that the */ +/* edge direction is necessarily reversed, because triangle/edge handles */ +/* are always directed counterclockwise around the triangle. */ + +#define sym(triedge1, triedge2) \ + ptr = (triedge1).tri[(triedge1).orient]; \ + decode(ptr, triedge2); + +#define symself(triedge) \ + ptr = (triedge).tri[(triedge).orient]; \ + decode(ptr, triedge); + +/* lnext() finds the next edge (counterclockwise) of a triangle. */ + +#define lnext(triedge1, triedge2) \ + (triedge2).tri = (triedge1).tri; \ + (triedge2).orient = plus1mod3[(triedge1).orient] + +#define lnextself(triedge) \ + (triedge).orient = plus1mod3[(triedge).orient] + +/* lprev() finds the previous edge (clockwise) of a triangle. */ + +#define lprev(triedge1, triedge2) \ + (triedge2).tri = (triedge1).tri; \ + (triedge2).orient = minus1mod3[(triedge1).orient] + +#define lprevself(triedge) \ + (triedge).orient = minus1mod3[(triedge).orient] + +/* onext() spins counterclockwise around a point; that is, it finds the next */ +/* edge with the same origin in the counterclockwise direction. This edge */ +/* will be part of a different triangle. */ + +#define onext(triedge1, triedge2) \ + lprev(triedge1, triedge2); \ + symself(triedge2); + +#define onextself(triedge) \ + lprevself(triedge); \ + symself(triedge); + +/* oprev() spins clockwise around a point; that is, it finds the next edge */ +/* with the same origin in the clockwise direction. This edge will be */ +/* part of a different triangle. */ + +#define oprev(triedge1, triedge2) \ + sym(triedge1, triedge2); \ + lnextself(triedge2); + +#define oprevself(triedge) \ + symself(triedge); \ + lnextself(triedge); + +/* dnext() spins counterclockwise around a point; that is, it finds the next */ +/* edge with the same destination in the counterclockwise direction. This */ +/* edge will be part of a different triangle. */ + +#define dnext(triedge1, triedge2) \ + sym(triedge1, triedge2); \ + lprevself(triedge2); + +#define dnextself(triedge) \ + symself(triedge); \ + lprevself(triedge); + +/* dprev() spins clockwise around a point; that is, it finds the next edge */ +/* with the same destination in the clockwise direction. This edge will */ +/* be part of a different triangle. */ + +#define dprev(triedge1, triedge2) \ + lnext(triedge1, triedge2); \ + symself(triedge2); + +#define dprevself(triedge) \ + lnextself(triedge); \ + symself(triedge); + +/* rnext() moves one edge counterclockwise about the adjacent triangle. */ +/* (It's best understood by reading Guibas and Stolfi. It involves */ +/* changing triangles twice.) */ + +#define rnext(triedge1, triedge2) \ + sym(triedge1, triedge2); \ + lnextself(triedge2); \ + symself(triedge2); + +#define rnextself(triedge) \ + symself(triedge); \ + lnextself(triedge); \ + symself(triedge); + +/* rnext() moves one edge clockwise about the adjacent triangle. */ +/* (It's best understood by reading Guibas and Stolfi. It involves */ +/* changing triangles twice.) */ + +#define rprev(triedge1, triedge2) \ + sym(triedge1, triedge2); \ + lprevself(triedge2); \ + symself(triedge2); + +#define rprevself(triedge) \ + symself(triedge); \ + lprevself(triedge); \ + symself(triedge); + +/* These primitives determine or set the origin, destination, or apex of a */ +/* triangle. */ + +#define org(triedge, pointptr) \ + pointptr = (point) (triedge).tri[plus1mod3[(triedge).orient] + 3] + +#define dest(triedge, pointptr) \ + pointptr = (point) (triedge).tri[minus1mod3[(triedge).orient] + 3] + +#define apex(triedge, pointptr) \ + pointptr = (point) (triedge).tri[(triedge).orient + 3] + +#define setorg(triedge, pointptr) \ + (triedge).tri[plus1mod3[(triedge).orient] + 3] = (triangle) pointptr + +#define setdest(triedge, pointptr) \ + (triedge).tri[minus1mod3[(triedge).orient] + 3] = (triangle) pointptr + +#define setapex(triedge, pointptr) \ + (triedge).tri[(triedge).orient + 3] = (triangle) pointptr + +#define setvertices2null(triedge) \ + (triedge).tri[3] = (triangle) NULL; \ + (triedge).tri[4] = (triangle) NULL; \ + (triedge).tri[5] = (triangle) NULL; + +/* Bond two triangles together. */ + +#define bond(triedge1, triedge2) \ + (triedge1).tri[(triedge1).orient] = encode(triedge2); \ + (triedge2).tri[(triedge2).orient] = encode(triedge1) + +/* Dissolve a bond (from one side). Note that the other triangle will still */ +/* think it's connected to this triangle. Usually, however, the other */ +/* triangle is being deleted entirely, or bonded to another triangle, so */ +/* it doesn't matter. */ + +#define dissolve(triedge) \ + (triedge).tri[(triedge).orient] = (triangle) dummytri + +/* Copy a triangle/edge handle. */ + +#define triedgecopy(triedge1, triedge2) \ + (triedge2).tri = (triedge1).tri; \ + (triedge2).orient = (triedge1).orient + +/* Test for equality of triangle/edge handles. */ + +#define triedgeequal(triedge1, triedge2) \ + (((triedge1).tri == (triedge2).tri) && \ + ((triedge1).orient == (triedge2).orient)) + +/* Primitives to infect or cure a triangle with the virus. These rely on */ +/* the assumption that all shell edges are aligned to four-byte boundaries.*/ + +#define infect(triedge) \ + (triedge).tri[6] = (triangle) \ + ((unsigned long) (triedge).tri[6] | (unsigned long) 2l) + +#define uninfect(triedge) \ + (triedge).tri[6] = (triangle) \ + ((unsigned long) (triedge).tri[6] & ~ (unsigned long) 2l) + +/* Test a triangle for viral infection. */ + +#define infected(triedge) \ + (((unsigned long) (triedge).tri[6] & (unsigned long) 2l) != 0) + +/* Check or set a triangle's attributes. */ + +#define elemattribute(triedge, attnum) \ + ((REAL *) (triedge).tri)[elemattribindex + (attnum)] + +#define setelemattribute(triedge, attnum, value) \ + ((REAL *) (triedge).tri)[elemattribindex + (attnum)] = (REAL)value + +/* Check or set a triangle's maximum area bound. */ + +#define areabound(triedge) ((REAL *) (triedge).tri)[areaboundindex] + +#define setareabound(triedge, value) \ + ((REAL *) (triedge).tri)[areaboundindex] = (REAL)value + +/********* Primitives for shell edges *********/ +/* */ +/* */ + +/* sdecode() converts a pointer to an oriented shell edge. The orientation */ +/* is extracted from the least significant bit of the pointer. The two */ +/* least significant bits (one for orientation, one for viral infection) */ +/* are masked out to produce the real pointer. */ + +#define sdecode(sptr, edge) \ + (edge).shorient = (int) ((unsigned long) (sptr) & (unsigned long) 1l); \ + (edge).sh = (shelle *) \ + ((unsigned long) (sptr) & ~ (unsigned long) 3l) + +/* sencode() compresses an oriented shell edge into a single pointer. It */ +/* relies on the assumption that all shell edges are aligned to two-byte */ +/* boundaries, so the least significant bit of (edge).sh is zero. */ + +#define sencode(edge) \ + (shelle) ((unsigned long) (edge).sh | (unsigned long) (edge).shorient) + +/* ssym() toggles the orientation of a shell edge. */ + +#define ssym(edge1, edge2) \ + (edge2).sh = (edge1).sh; \ + (edge2).shorient = 1 - (edge1).shorient + +#define ssymself(edge) \ + (edge).shorient = 1 - (edge).shorient + +/* spivot() finds the other shell edge (from the same segment) that shares */ +/* the same origin. */ + +#define spivot(edge1, edge2) \ + sptr = (edge1).sh[(edge1).shorient]; \ + sdecode(sptr, edge2) + +#define spivotself(edge) \ + sptr = (edge).sh[(edge).shorient]; \ + sdecode(sptr, edge) + +/* snext() finds the next shell edge (from the same segment) in sequence; */ +/* one whose origin is the input shell edge's destination. */ + +#define snext(edge1, edge2) \ + sptr = (edge1).sh[1 - (edge1).shorient]; \ + sdecode(sptr, edge2) + +#define snextself(edge) \ + sptr = (edge).sh[1 - (edge).shorient]; \ + sdecode(sptr, edge) + +/* These primitives determine or set the origin or destination of a shell */ +/* edge. */ + +#define sorg(edge, pointptr) \ + pointptr = (point) (edge).sh[2 + (edge).shorient] + +#define sdest(edge, pointptr) \ + pointptr = (point) (edge).sh[3 - (edge).shorient] + +#define setsorg(edge, pointptr) \ + (edge).sh[2 + (edge).shorient] = (shelle) pointptr + +#define setsdest(edge, pointptr) \ + (edge).sh[3 - (edge).shorient] = (shelle) pointptr + +/* These primitives read or set a shell marker. Shell markers are used to */ +/* hold user boundary information. */ + +#define mark(edge) (* (int *) ((edge).sh + 6)) + +#define setmark(edge, value) \ + * (int *) ((edge).sh + 6) = value + +/* Bond two shell edges together. */ + +#define sbond(edge1, edge2) \ + (edge1).sh[(edge1).shorient] = sencode(edge2); \ + (edge2).sh[(edge2).shorient] = sencode(edge1) + +/* Dissolve a shell edge bond (from one side). Note that the other shell */ +/* edge will still think it's connected to this shell edge. */ + +#define sdissolve(edge) \ + (edge).sh[(edge).shorient] = (shelle) dummysh + +/* Copy a shell edge. */ + +#define shellecopy(edge1, edge2) \ + (edge2).sh = (edge1).sh; \ + (edge2).shorient = (edge1).shorient + +/* Test for equality of shell edges. */ + +#define shelleequal(edge1, edge2) \ + (((edge1).sh == (edge2).sh) && \ + ((edge1).shorient == (edge2).shorient)) + +/********* Primitives for interacting triangles and shell edges *********/ +/* */ +/* */ + +/* tspivot() finds a shell edge abutting a triangle. */ + +#define tspivot(triedge, edge) \ + sptr = (shelle) (triedge).tri[6 + (triedge).orient]; \ + sdecode(sptr, edge) + +/* stpivot() finds a triangle abutting a shell edge. It requires that the */ +/* variable `ptr' of type `triangle' be defined. */ + +#define stpivot(edge, triedge) \ + ptr = (triangle) (edge).sh[4 + (edge).shorient]; \ + decode(ptr, triedge) + +/* Bond a triangle to a shell edge. */ + +#define tsbond(triedge, edge) \ + (triedge).tri[6 + (triedge).orient] = (triangle) sencode(edge); \ + (edge).sh[4 + (edge).shorient] = (shelle) encode(triedge) + +/* Dissolve a bond (from the triangle side). */ + +#define tsdissolve(triedge) \ + (triedge).tri[6 + (triedge).orient] = (triangle) dummysh + +/* Dissolve a bond (from the shell edge side). */ + +#define stdissolve(edge) \ + (edge).sh[4 + (edge).shorient] = (shelle) dummytri + +/********* Primitives for points *********/ +/* */ +/* */ + +#define pointmark(pt) ((int *) (pt))[pointmarkindex] + +#define setpointmark(pt, value) \ + ((int *) (pt))[pointmarkindex] = value + +#define point2tri(pt) ((triangle *) (pt))[point2triindex] + +#define setpoint2tri(pt, value) \ + ((triangle *) (pt))[point2triindex] = value + +/** **/ +/** **/ +/********* Mesh manipulation primitives end here *********/ + +/********* User interaction routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* syntax() Print list of command line switches. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void syntax() +{ +#ifdef CDT_ONLY +#ifdef REDUCED + printf("triangle [-pAcevngBPNEIOXzo_lQVh] input_file\n"); +#else /* not REDUCED */ + printf("triangle [-pAcevngBPNEIOXzo_iFlCQVh] input_file\n"); +#endif /* not REDUCED */ +#else /* not CDT_ONLY */ +#ifdef REDUCED + printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__lQVh] input_file\n"); +#else /* not REDUCED */ + printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__iFlsCQVh] input_file\n"); +#endif /* not REDUCED */ +#endif /* not CDT_ONLY */ + + printf(" -p Triangulates a Planar Straight Line Graph (.poly file).\n"); +#ifndef CDT_ONLY + printf(" -r Refines a previously generated mesh.\n"); + printf( + " -q Quality mesh generation. A minimum angle may be specified.\n"); + printf(" -a Applies a maximum triangle area constraint.\n"); +#endif /* not CDT_ONLY */ + printf( + " -A Applies attributes to identify elements in certain regions.\n"); + printf(" -c Encloses the convex hull with segments.\n"); + printf(" -e Generates an edge list.\n"); + printf(" -v Generates a Voronoi diagram.\n"); + printf(" -n Generates a list of triangle neighbors.\n"); + printf(" -g Generates an .off file for Geomview.\n"); + printf(" -B Suppresses output of boundary information.\n"); + printf(" -P Suppresses output of .poly file.\n"); + printf(" -N Suppresses output of .node file.\n"); + printf(" -E Suppresses output of .ele file.\n"); + printf(" -I Suppresses mesh iteration numbers.\n"); + printf(" -O Ignores holes in .poly file.\n"); + printf(" -X Suppresses use of exact arithmetic.\n"); + printf(" -z Numbers all items starting from zero (rather than one).\n"); + printf(" -o2 Generates second-order subparametric elements.\n"); +#ifndef CDT_ONLY + printf(" -Y Suppresses boundary segment splitting.\n"); + printf(" -S Specifies maximum number of added Steiner points.\n"); +#endif /* not CDT_ONLY */ +#ifndef REDUCED + printf(" -i Uses incremental method, rather than divide-and-conquer.\n"); + printf(" -F Uses Fortune's sweepline algorithm, rather than d-and-c.\n"); +#endif /* not REDUCED */ + printf(" -l Uses vertical cuts only, rather than alternating cuts.\n"); +#ifndef REDUCED +#ifndef CDT_ONLY + printf( + " -s Force segments into mesh by splitting (instead of using CDT).\n"); +#endif /* not CDT_ONLY */ + printf(" -C Check consistency of final mesh.\n"); +#endif /* not REDUCED */ + printf(" -Q Quiet: No terminal output except errors.\n"); + printf(" -V Verbose: Detailed information on what I'm doing.\n"); + printf(" -h Help: Detailed instructions for Triangle.\n"); + exit(0); +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* info() Print out complete instructions. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void info() +{ + printf("Triangle\n"); + printf( +"A Two-Dimensional Quality Mesh Generator and Delaunay Triangulator.\n"); + printf("Version 1.3\n\n"); + printf( +"Copyright 1996 Jonathan Richard Shewchuk (bugs/comments to jrs@cs.cmu.edu)\n" +); + printf("School of Computer Science / Carnegie Mellon University\n"); + printf("5000 Forbes Avenue / Pittsburgh, Pennsylvania 15213-3891\n"); + printf( +"Created as part of the Archimedes project (tools for parallel FEM).\n"); + printf( +"Supported in part by NSF Grant CMS-9318163 and an NSERC 1967 Scholarship.\n"); + printf("There is no warranty whatsoever. Use at your own risk.\n"); +#ifdef SINGLE + printf("This executable is compiled for single precision arithmetic.\n\n\n"); +#else /* not SINGLE */ + printf("This executable is compiled for double precision arithmetic.\n\n\n"); +#endif /* not SINGLE */ + printf( +"Triangle generates exact Delaunay triangulations, constrained Delaunay\n"); + printf( +"triangulations, and quality conforming Delaunay triangulations. The latter\n" +); + printf( +"can be generated with no small angles, and are thus suitable for finite\n"); + printf( +"element analysis. If no command line switches are specified, your .node\n"); + printf( +"input file will be read, and the Delaunay triangulation will be returned in\n" +); + printf(".node and .ele output files. The command syntax is:\n\n"); +#ifdef CDT_ONLY +#ifdef REDUCED + printf("triangle [-pAcevngBPNEIOXzo_lQVh] input_file\n\n"); +#else /* not REDUCED */ + printf("triangle [-pAcevngBPNEIOXzo_iFlCQVh] input_file\n\n"); +#endif /* not REDUCED */ +#else /* not CDT_ONLY */ +#ifdef REDUCED + printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__lQVh] input_file\n\n"); +#else /* not REDUCED */ + printf("triangle [-prq__a__AcevngBPNEIOXzo_YS__iFlsCQVh] input_file\n\n"); +#endif /* not REDUCED */ +#endif /* not CDT_ONLY */ + printf( +"Underscores indicate that numbers may optionally follow certain switches;\n"); + printf( +"do not leave any space between a switch and its numeric parameter.\n"); + printf( +"input_file must be a file with extension .node, or extension .poly if the\n"); + printf( +"-p switch is used. If -r is used, you must supply .node and .ele files,\n"); + printf( +"and possibly a .poly file and .area file as well. The formats of these\n"); + printf("files are described below.\n\n"); + printf("Command Line Switches:\n\n"); + printf( +" -p Reads a Planar Straight Line Graph (.poly file), which can specify\n" +); + printf( +" points, segments, holes, and regional attributes and area\n"); + printf( +" constraints. Will generate a constrained Delaunay triangulation\n"); + printf( +" fitting the input; or, if -s, -q, or -a is used, a conforming\n"); + printf( +" Delaunay triangulation. If -p is not used, Triangle reads a .node\n" +); + printf(" file by default.\n"); + printf( +" -r Refines a previously generated mesh. The mesh is read from a .node\n" +); + printf( +" file and an .ele file. If -p is also used, a .poly file is read\n"); + printf( +" and used to constrain edges in the mesh. Further details on\n"); + printf(" refinement are given below.\n"); + printf( +" -q Quality mesh generation by Jim Ruppert's Delaunay refinement\n"); + printf( +" algorithm. Adds points to the mesh to ensure that no angles\n"); + printf( +" smaller than 20 degrees occur. An alternative minimum angle may be\n" +); + printf( +" specified after the `q'. If the minimum angle is 20.7 degrees or\n"); + printf( +" smaller, the triangulation algorithm is theoretically guaranteed to\n" +); + printf( +" terminate (assuming infinite precision arithmetic - Triangle may\n"); + printf( +" fail to terminate if you run out of precision). In practice, the\n"); + printf( +" algorithm often succeeds for minimum angles up to 33.8 degrees.\n"); + printf( +" For highly refined meshes, however, it may be necessary to reduce\n"); + printf( +" the minimum angle to well below 20 to avoid problems associated\n"); + printf( +" with insufficient floating-point precision. The specified angle\n"); + printf(" may include a decimal point.\n"); + printf( +" -a Imposes a maximum triangle area. If a number follows the `a', no\n"); + printf( +" triangle will be generated whose area is larger than that number.\n"); + printf( +" If no number is specified, an .area file (if -r is used) or .poly\n"); + printf( +" file (if -r is not used) specifies a number of maximum area\n"); + printf( +" constraints. An .area file contains a separate area constraint for\n" +); + printf( +" each triangle, and is useful for refining a finite element mesh\n"); + printf( +" based on a posteriori error estimates. A .poly file can optionally\n" +); + printf( +" contain an area constraint for each segment-bounded region, thereby\n" +); + printf( +" enforcing triangle densities in a first triangulation. You can\n"); + printf( +" impose both a fixed area constraint and a varying area constraint\n"); + printf( +" by invoking the -a switch twice, once with and once without a\n"); + printf( +" number following. Each area specified may include a decimal point.\n" +); + printf( +" -A Assigns an additional attribute to each triangle that identifies\n"); + printf( +" what segment-bounded region each triangle belongs to. Attributes\n"); + printf( +" are assigned to regions by the .poly file. If a region is not\n"); + printf( +" explicitly marked by the .poly file, triangles in that region are\n"); + printf( +" assigned an attribute of zero. The -A switch has an effect only\n"); + printf(" when the -p switch is used and the -r switch is not.\n"); + printf( +" -c Creates segments on the convex hull of the triangulation. If you\n"); + printf( +" are triangulating a point set, this switch causes a .poly file to\n"); + printf( +" be written, containing all edges in the convex hull. (By default,\n" +); + printf( +" a .poly file is written only if a .poly file is read.) If you are\n" +); + printf( +" triangulating a PSLG, this switch specifies that the interior of\n"); + printf( +" the convex hull of the PSLG should be triangulated. If you do not\n" +); + printf( +" use this switch when triangulating a PSLG, it is assumed that you\n"); + printf( +" have identified the region to be triangulated by surrounding it\n"); + printf( +" with segments of the input PSLG. Beware: if you are not careful,\n" +); + printf( +" this switch can cause the introduction of an extremely thin angle\n"); + printf( +" between a PSLG segment and a convex hull segment, which can cause\n"); + printf( +" overrefinement or failure if Triangle runs out of precision. If\n"); + printf( +" you are refining a mesh, the -c switch works differently; it\n"); + printf( +" generates the set of boundary edges of the mesh, rather than the\n"); + printf(" convex hull.\n"); + printf( +" -e Outputs (to an .edge file) a list of edges of the triangulation.\n"); + printf( +" -v Outputs the Voronoi diagram associated with the triangulation.\n"); + printf(" Does not attempt to detect degeneracies.\n"); + printf( +" -n Outputs (to a .neigh file) a list of triangles neighboring each\n"); + printf(" triangle.\n"); + printf( +" -g Outputs the mesh to an Object File Format (.off) file, suitable for\n" +); + printf(" viewing with the Geometry Center's Geomview package.\n"); + printf( +" -B No boundary markers in the output .node, .poly, and .edge output\n"); + printf( +" files. See the detailed discussion of boundary markers below.\n"); + printf( +" -P No output .poly file. Saves disk space, but you lose the ability\n"); + printf( +" to impose segment constraints on later refinements of the mesh.\n"); + printf(" -N No output .node file.\n"); + printf(" -E No output .ele file.\n"); + printf( +" -I No iteration numbers. Suppresses the output of .node and .poly\n"); + printf( +" files, so your input files won't be overwritten. (If your input is\n" +); + printf( +" a .poly file only, a .node file will be written.) Cannot be used\n"); + printf( +" with the -r switch, because that would overwrite your input .ele\n"); + printf( +" file. Shouldn't be used with the -s, -q, or -a switch if you are\n"); + printf( +" using a .node file for input, because no .node file will be\n"); + printf(" written, so there will be no record of any added points.\n"); + printf(" -O No holes. Ignores the holes in the .poly file.\n"); + printf( +" -X No exact arithmetic. Normally, Triangle uses exact floating-point\n" +); + printf( +" arithmetic for certain tests if it thinks the inexact tests are not\n" +); + printf( +" accurate enough. Exact arithmetic ensures the robustness of the\n"); + printf( +" triangulation algorithms, despite floating-point roundoff error.\n"); + printf( +" Disabling exact arithmetic with the -X switch will cause a small\n"); + printf( +" improvement in speed and create the possibility (albeit small) that\n" +); + printf( +" Triangle will fail to produce a valid mesh. Not recommended.\n"); + printf( +" -z Numbers all items starting from zero (rather than one). Note that\n" +); + printf( +" this switch is normally overrided by the value used to number the\n"); + printf( +" first point of the input .node or .poly file. However, this switch\n" +); + printf(" is useful when calling Triangle from another program.\n"); + printf( +" -o2 Generates second-order subparametric elements with six nodes each.\n" +); + printf( +" -Y No new points on the boundary. This switch is useful when the mesh\n" +); + printf( +" boundary must be preserved so that it conforms to some adjacent\n"); + printf( +" mesh. Be forewarned that you will probably sacrifice some of the\n"); + printf( +" quality of the mesh; Triangle will try, but the resulting mesh may\n" +); + printf( +" contain triangles of poor aspect ratio. Works well if all the\n"); + printf( +" boundary points are closely spaced. Specify this switch twice\n"); + printf( +" (`-YY') to prevent all segment splitting, including internal\n"); + printf(" boundaries.\n"); + printf( +" -S Specifies the maximum number of Steiner points (points that are not\n" +); + printf( +" in the input, but are added to meet the constraints of minimum\n"); + printf( +" angle and maximum area). The default is to allow an unlimited\n"); + printf( +" number. If you specify this switch with no number after it,\n"); + printf( +" the limit is set to zero. Triangle always adds points at segment\n"); + printf( +" intersections, even if it needs to use more points than the limit\n"); + printf( +" you set. When Triangle inserts segments by splitting (-s), it\n"); + printf( +" always adds enough points to ensure that all the segments appear in\n" +); + printf( +" the triangulation, again ignoring the limit. Be forewarned that\n"); + printf( +" the -S switch may result in a conforming triangulation that is not\n" +); + printf( +" truly Delaunay, because Triangle may be forced to stop adding\n"); + printf( +" points when the mesh is in a state where a segment is non-Delaunay\n" +); + printf( +" and needs to be split. If so, Triangle will print a warning.\n"); + printf( +" -i Uses an incremental rather than divide-and-conquer algorithm to\n"); + printf( +" form a Delaunay triangulation. Try it if the divide-and-conquer\n"); + printf(" algorithm fails.\n"); + printf( +" -F Uses Steven Fortune's sweepline algorithm to form a Delaunay\n"); + printf( +" triangulation. Warning: does not use exact arithmetic for all\n"); + printf(" calculations. An exact result is not guaranteed.\n"); + printf( +" -l Uses only vertical cuts in the divide-and-conquer algorithm. By\n"); + printf( +" default, Triangle uses alternating vertical and horizontal cuts,\n"); + printf( +" which usually improve the speed except with point sets that are\n"); + printf( +" small or short and wide. This switch is primarily of theoretical\n"); + printf(" interest.\n"); + printf( +" -s Specifies that segments should be forced into the triangulation by\n" +); + printf( +" recursively splitting them at their midpoints, rather than by\n"); + printf( +" generating a constrained Delaunay triangulation. Segment splitting\n" +); + printf( +" is true to Ruppert's original algorithm, but can create needlessly\n" +); + printf(" small triangles near external small features.\n"); + printf( +" -C Check the consistency of the final mesh. Uses exact arithmetic for\n" +); + printf( +" checking, even if the -X switch is used. Useful if you suspect\n"); + printf(" Triangle is buggy.\n"); + printf( +" -Q Quiet: Suppresses all explanation of what Triangle is doing, unless\n" +); + printf(" an error occurs.\n"); + printf( +" -V Verbose: Gives detailed information about what Triangle is doing.\n"); + printf( +" Add more `V's for increasing amount of detail. `-V' gives\n"); + printf( +" information on algorithmic progress and more detailed statistics.\n"); + printf( +" `-VV' gives point-by-point details, and will print so much that\n"); + printf( +" Triangle will run much more slowly. `-VVV' gives information only\n" +); + printf(" a debugger could love.\n"); + printf(" -h Help: Displays these instructions.\n"); + printf("\n"); + printf("Definitions:\n"); + printf("\n"); + printf( +" A Delaunay triangulation of a point set is a triangulation whose vertices\n" +); + printf( +" are the point set, having the property that no point in the point set\n"); + printf( +" falls in the interior of the circumcircle (circle that passes through all\n" +); + printf(" three vertices) of any triangle in the triangulation.\n\n"); + printf( +" A Voronoi diagram of a point set is a subdivision of the plane into\n"); + printf( +" polygonal regions (some of which may be infinite), where each region is\n"); + printf( +" the set of points in the plane that are closer to some input point than\n"); + printf( +" to any other input point. (The Voronoi diagram is the geometric dual of\n" +); + printf(" the Delaunay triangulation.)\n\n"); + printf( +" A Planar Straight Line Graph (PSLG) is a collection of points and\n"); + printf( +" segments. Segments are simply edges, whose endpoints are points in the\n"); + printf( +" PSLG. The file format for PSLGs (.poly files) is described below.\n"); + printf("\n"); + printf( +" A constrained Delaunay triangulation of a PSLG is similar to a Delaunay\n"); + printf( +" triangulation, but each PSLG segment is present as a single edge in the\n"); + printf( +" triangulation. (A constrained Delaunay triangulation is not truly a\n"); + printf(" Delaunay triangulation.)\n\n"); + printf( +" A conforming Delaunay triangulation of a PSLG is a true Delaunay\n"); + printf( +" triangulation in which each PSLG segment may have been subdivided into\n"); + printf( +" several edges by the insertion of additional points. These inserted\n"); + printf( +" points are necessary to allow the segments to exist in the mesh while\n"); + printf(" maintaining the Delaunay property.\n\n"); + printf("File Formats:\n\n"); + printf( +" All files may contain comments prefixed by the character '#'. Points,\n"); + printf( +" triangles, edges, holes, and maximum area constraints must be numbered\n"); + printf( +" consecutively, starting from either 1 or 0. Whichever you choose, all\n"); + printf( +" input files must be consistent; if the nodes are numbered from 1, so must\n" +); + printf( +" be all other objects. Triangle automatically detects your choice while\n"); + printf( +" reading the .node (or .poly) file. (When calling Triangle from another\n"); + printf( +" program, use the -z switch if you wish to number objects from zero.)\n"); + printf(" Examples of these file formats are given below.\n\n"); + printf(" .node files:\n"); + printf( +" First line: <# of points> <# of attributes>\n"); + printf( +" <# of boundary markers (0 or 1)>\n" +); + printf( +" Remaining lines: [attributes] [boundary marker]\n"); + printf("\n"); + printf( +" The attributes, which are typically floating-point values of physical\n"); + printf( +" quantities (such as mass or conductivity) associated with the nodes of\n" +); + printf( +" a finite element mesh, are copied unchanged to the output mesh. If -s,\n" +); + printf( +" -q, or -a is selected, each new Steiner point added to the mesh will\n"); + printf(" have attributes assigned to it by linear interpolation.\n\n"); + printf( +" If the fourth entry of the first line is `1', the last column of the\n"); + printf( +" remainder of the file is assumed to contain boundary markers. Boundary\n" +); + printf( +" markers are used to identify boundary points and points resting on PSLG\n" +); + printf( +" segments; a complete description appears in a section below. The .node\n" +); + printf( +" file produced by Triangle will contain boundary markers in the last\n"); + printf(" column unless they are suppressed by the -B switch.\n\n"); + printf(" .ele files:\n"); + printf( +" First line: <# of triangles> <# of attributes>\n"); + printf( +" Remaining lines: ... [attributes]\n" +); + printf("\n"); + printf( +" Points are indices into the corresponding .node file. The first three\n" +); + printf( +" points are the corners, and are listed in counterclockwise order around\n" +); + printf( +" each triangle. (The remaining points, if any, depend on the type of\n"); + printf( +" finite element used.) The attributes are just like those of .node\n"); + printf( +" files. Because there is no simple mapping from input to output\n"); + printf( +" triangles, an attempt is made to interpolate attributes, which may\n"); + printf( +" result in a good deal of diffusion of attributes among nearby triangles\n" +); + printf( +" as the triangulation is refined. Diffusion does not occur across\n"); + printf( +" segments, so attributes used to identify segment-bounded regions remain\n" +); + printf( +" intact. In output .ele files, all triangles have three points each\n"); + printf( +" unless the -o2 switch is used, in which case they have six, and the\n"); + printf( +" fourth, fifth, and sixth points lie on the midpoints of the edges\n"); + printf(" opposite the first, second, and third corners.\n\n"); + printf(" .poly files:\n"); + printf( +" First line: <# of points> <# of attributes>\n"); + printf( +" <# of boundary markers (0 or 1)>\n" +); + printf( +" Following lines: [attributes] [boundary marker]\n"); + printf(" One line: <# of segments> <# of boundary markers (0 or 1)>\n"); + printf( +" Following lines: [boundary marker]\n"); + printf(" One line: <# of holes>\n"); + printf(" Following lines: \n"); + printf( +" Optional line: <# of regional attributes and/or area constraints>\n"); + printf( +" Optional following lines: \n"); + printf("\n"); + printf( +" A .poly file represents a PSLG, as well as some additional information.\n" +); + printf( +" The first section lists all the points, and is identical to the format\n" +); + printf( +" of .node files. <# of points> may be set to zero to indicate that the\n" +); + printf( +" points are listed in a separate .node file; .poly files produced by\n"); + printf( +" Triangle always have this format. This has the advantage that a point\n" +); + printf( +" set may easily be triangulated with or without segments. (The same\n"); + printf( +" effect can be achieved, albeit using more disk space, by making a copy\n" +); + printf( +" of the .poly file with the extension .node; all sections of the file\n"); + printf(" but the first are ignored.)\n\n"); + printf( +" The second section lists the segments. Segments are edges whose\n"); + printf( +" presence in the triangulation is enforced. Each segment is specified\n"); + printf( +" by listing the indices of its two endpoints. This means that you must\n" +); + printf( +" include its endpoints in the point list. If -s, -q, and -a are not\n"); + printf( +" selected, Triangle will produce a constrained Delaunay triangulation,\n"); + printf( +" in which each segment appears as a single edge in the triangulation.\n"); + printf( +" If -q or -a is selected, Triangle will produce a conforming Delaunay\n"); + printf( +" triangulation, in which segments may be subdivided into smaller edges.\n" +); + printf(" Each segment, like each point, may have a boundary marker.\n\n"); + printf( +" The third section lists holes (and concavities, if -c is selected) in\n"); + printf( +" the triangulation. Holes are specified by identifying a point inside\n"); + printf( +" each hole. After the triangulation is formed, Triangle creates holes\n"); + printf( +" by eating triangles, spreading out from each hole point until its\n"); + printf( +" progress is blocked by PSLG segments; you must be careful to enclose\n"); + printf( +" each hole in segments, or your whole triangulation may be eaten away.\n"); + printf( +" If the two triangles abutting a segment are eaten, the segment itself\n"); + printf( +" is also eaten. Do not place a hole directly on a segment; if you do,\n"); + printf(" Triangle will choose one side of the segment arbitrarily.\n\n"); + printf( +" The optional fourth section lists regional attributes (to be assigned\n"); + printf( +" to all triangles in a region) and regional constraints on the maximum\n"); + printf( +" triangle area. Triangle will read this section only if the -A switch\n"); + printf( +" is used or the -a switch is used without a number following it, and the\n" +); + printf( +" -r switch is not used. Regional attributes and area constraints are\n"); + printf( +" propagated in the same manner as holes; you specify a point for each\n"); + printf( +" attribute and/or constraint, and the attribute and/or constraint will\n"); + printf( +" affect the whole region (bounded by segments) containing the point. If\n" +); + printf( +" two values are written on a line after the x and y coordinate, the\n"); + printf( +" former is assumed to be a regional attribute (but will only be applied\n" +); + printf( +" if the -A switch is selected), and the latter is assumed to be a\n"); + printf( +" regional area constraint (but will only be applied if the -a switch is\n" +); + printf( +" selected). You may also specify just one value after the coordinates,\n" +); + printf( +" which can serve as both an attribute and an area constraint, depending\n" +); + printf( +" on the choice of switches. If you are using the -A and -a switches\n"); + printf( +" simultaneously and wish to assign an attribute to some region without\n"); + printf(" imposing an area constraint, use a negative maximum area.\n\n"); + printf( +" When a triangulation is created from a .poly file, you must either\n"); + printf( +" enclose the entire region to be triangulated in PSLG segments, or\n"); + printf( +" use the -c switch, which encloses the convex hull of the input point\n"); + printf( +" set. If you do not use the -c switch, Triangle will eat all triangles\n" +); + printf( +" on the outer boundary that are not protected by segments; if you are\n"); + printf( +" not careful, your whole triangulation may be eaten away. If you do\n"); + printf( +" use the -c switch, you can still produce concavities by appropriate\n"); + printf(" placement of holes just inside the convex hull.\n\n"); + printf( +" An ideal PSLG has no intersecting segments, nor any points that lie\n"); + printf( +" upon segments (except, of course, the endpoints of each segment.) You\n" +); + printf( +" aren't required to make your .poly files ideal, but you should be aware\n" +); + printf( +" of what can go wrong. Segment intersections are relatively safe -\n"); + printf( +" Triangle will calculate the intersection points for you and add them to\n" +); + printf( +" the triangulation - as long as your machine's floating-point precision\n" +); + printf( +" doesn't become a problem. You are tempting the fates if you have three\n" +); + printf( +" segments that cross at the same location, and expect Triangle to figure\n" +); + printf( +" out where the intersection point is. Thanks to floating-point roundoff\n" +); + printf( +" error, Triangle will probably decide that the three segments intersect\n" +); + printf( +" at three different points, and you will find a minuscule triangle in\n"); + printf( +" your output - unless Triangle tries to refine the tiny triangle, uses\n"); + printf( +" up the last bit of machine precision, and fails to terminate at all.\n"); + printf( +" You're better off putting the intersection point in the input files,\n"); + printf( +" and manually breaking up each segment into two. Similarly, if you\n"); + printf( +" place a point at the middle of a segment, and hope that Triangle will\n"); + printf( +" break up the segment at that point, you might get lucky. On the other\n" +); + printf( +" hand, Triangle might decide that the point doesn't lie precisely on the\n" +); + printf( +" line, and you'll have a needle-sharp triangle in your output - or a lot\n" +); + printf(" of tiny triangles if you're generating a quality mesh.\n\n"); + printf( +" When Triangle reads a .poly file, it also writes a .poly file, which\n"); + printf( +" includes all edges that are part of input segments. If the -c switch\n"); + printf( +" is used, the output .poly file will also include all of the edges on\n"); + printf( +" the convex hull. Hence, the output .poly file is useful for finding\n"); + printf( +" edges associated with input segments and setting boundary conditions in\n" +); + printf( +" finite element simulations. More importantly, you will need it if you\n" +); + printf( +" plan to refine the output mesh, and don't want segments to be missing\n"); + printf(" in later triangulations.\n\n"); + printf(" .area files:\n"); + printf(" First line: <# of triangles>\n"); + printf(" Following lines: \n\n"); + printf( +" An .area file associates with each triangle a maximum area that is used\n" +); + printf( +" for mesh refinement. As with other file formats, every triangle must\n"); + printf( +" be represented, and they must be numbered consecutively. A triangle\n"); + printf( +" may be left unconstrained by assigning it a negative maximum area.\n"); + printf("\n"); + printf(" .edge files:\n"); + printf(" First line: <# of edges> <# of boundary markers (0 or 1)>\n"); + printf( +" Following lines: [boundary marker]\n"); + printf("\n"); + printf( +" Endpoints are indices into the corresponding .node file. Triangle can\n" +); + printf( +" produce .edge files (use the -e switch), but cannot read them. The\n"); + printf( +" optional column of boundary markers is suppressed by the -B switch.\n"); + printf("\n"); + printf( +" In Voronoi diagrams, one also finds a special kind of edge that is an\n"); + printf( +" infinite ray with only one endpoint. For these edges, a different\n"); + printf(" format is used:\n\n"); + printf(" -1 \n\n"); + printf( +" The `direction' is a floating-point vector that indicates the direction\n" +); + printf(" of the infinite ray.\n\n"); + printf(" .neigh files:\n"); + printf( +" First line: <# of triangles> <# of neighbors per triangle (always 3)>\n" +); + printf( +" Following lines: \n"); + printf("\n"); + printf( +" Neighbors are indices into the corresponding .ele file. An index of -1\n" +); + printf( +" indicates a mesh boundary, and therefore no neighbor. Triangle can\n"); + printf( +" produce .neigh files (use the -n switch), but cannot read them.\n"); + printf("\n"); + printf( +" The first neighbor of triangle i is opposite the first corner of\n"); + printf(" triangle i, and so on.\n\n"); + printf("Boundary Markers:\n\n"); + printf( +" Boundary markers are tags used mainly to identify which output points and\n" +); + printf( +" edges are associated with which PSLG segment, and to identify which\n"); + printf( +" points and edges occur on a boundary of the triangulation. A common use\n" +); + printf( +" is to determine where boundary conditions should be applied to a finite\n"); + printf( +" element mesh. You can prevent boundary markers from being written into\n"); + printf(" files produced by Triangle by using the -B switch.\n\n"); + printf( +" The boundary marker associated with each segment in an output .poly file\n" +); + printf(" or edge in an output .edge file is chosen as follows:\n"); + printf( +" - If an output edge is part or all of a PSLG segment with a nonzero\n"); + printf( +" boundary marker, then the edge is assigned the same marker.\n"); + printf( +" - Otherwise, if the edge occurs on a boundary of the triangulation\n"); + printf( +" (including boundaries of holes), then the edge is assigned the marker\n" +); + printf(" one (1).\n"); + printf(" - Otherwise, the edge is assigned the marker zero (0).\n"); + printf( +" The boundary marker associated with each point in an output .node file is\n" +); + printf(" chosen as follows:\n"); + printf( +" - If a point is assigned a nonzero boundary marker in the input file,\n"); + printf( +" then it is assigned the same marker in the output .node file.\n"); + printf( +" - Otherwise, if the point lies on a PSLG segment (including the\n"); + printf( +" segment's endpoints) with a nonzero boundary marker, then the point\n"); + printf( +" is assigned the same marker. If the point lies on several such\n"); + printf(" segments, one of the markers is chosen arbitrarily.\n"); + printf( +" - Otherwise, if the point occurs on a boundary of the triangulation,\n"); + printf(" then the point is assigned the marker one (1).\n"); + printf(" - Otherwise, the point is assigned the marker zero (0).\n"); + printf("\n"); + printf( +" If you want Triangle to determine for you which points and edges are on\n"); + printf( +" the boundary, assign them the boundary marker zero (or use no markers at\n" +); + printf( +" all) in your input files. Alternatively, you can mark some of them and\n"); + printf(" leave others marked zero, allowing Triangle to label them.\n\n"); + printf("Triangulation Iteration Numbers:\n\n"); + printf( +" Because Triangle can read and refine its own triangulations, input\n"); + printf( +" and output files have iteration numbers. For instance, Triangle might\n"); + printf( +" read the files mesh.3.node, mesh.3.ele, and mesh.3.poly, refine the\n"); + printf( +" triangulation, and output the files mesh.4.node, mesh.4.ele, and\n"); + printf(" mesh.4.poly. Files with no iteration number are treated as if\n"); + printf( +" their iteration number is zero; hence, Triangle might read the file\n"); + printf( +" points.node, triangulate it, and produce the files points.1.node and\n"); + printf(" points.1.ele.\n\n"); + printf( +" Iteration numbers allow you to create a sequence of successively finer\n"); + printf( +" meshes suitable for multigrid methods. They also allow you to produce a\n" +); + printf( +" sequence of meshes using error estimate-driven mesh refinement.\n"); + printf("\n"); + printf( +" If you're not using refinement or quality meshing, and you don't like\n"); + printf( +" iteration numbers, use the -I switch to disable them. This switch will\n"); + printf( +" also disable output of .node and .poly files to prevent your input files\n" +); + printf( +" from being overwritten. (If the input is a .poly file that contains its\n" +); + printf(" own points, a .node file will be written.)\n\n"); + printf("Examples of How to Use Triangle:\n\n"); + printf( +" `triangle dots' will read points from dots.node, and write their Delaunay\n" +); + printf( +" triangulation to dots.1.node and dots.1.ele. (dots.1.node will be\n"); + printf( +" identical to dots.node.) `triangle -I dots' writes the triangulation to\n" +); + printf( +" dots.ele instead. (No additional .node file is needed, so none is\n"); + printf(" written.)\n\n"); + printf( +" `triangle -pe object.1' will read a PSLG from object.1.poly (and possibly\n" +); + printf( +" object.1.node, if the points are omitted from object.1.poly) and write\n"); + printf(" their constrained Delaunay triangulation to object.2.node and\n"); + printf( +" object.2.ele. The segments will be copied to object.2.poly, and all\n"); + printf(" edges will be written to object.2.edge.\n\n"); + printf( +" `triangle -pq31.5a.1 object' will read a PSLG from object.poly (and\n"); + printf( +" possibly object.node), generate a mesh whose angles are all greater than\n" +); + printf( +" 31.5 degrees and whose triangles all have area smaller than 0.1, and\n"); + printf( +" write the mesh to object.1.node and object.1.ele. Each segment may have\n" +); + printf( +" been broken up into multiple edges; the resulting constrained edges are\n"); + printf(" written to object.1.poly.\n\n"); + printf( +" Here is a sample file `box.poly' describing a square with a square hole:\n" +); + printf("\n"); + printf( +" # A box with eight points in 2D, no attributes, one boundary marker.\n"); + printf(" 8 2 0 1\n"); + printf(" # Outer box has these vertices:\n"); + printf(" 1 0 0 0\n"); + printf(" 2 0 3 0\n"); + printf(" 3 3 0 0\n"); + printf(" 4 3 3 33 # A special marker for this point.\n"); + printf(" # Inner square has these vertices:\n"); + printf(" 5 1 1 0\n"); + printf(" 6 1 2 0\n"); + printf(" 7 2 1 0\n"); + printf(" 8 2 2 0\n"); + printf(" # Five segments with boundary markers.\n"); + printf(" 5 1\n"); + printf(" 1 1 2 5 # Left side of outer box.\n"); + printf(" 2 5 7 0 # Segments 2 through 5 enclose the hole.\n"); + printf(" 3 7 8 0\n"); + printf(" 4 8 6 10\n"); + printf(" 5 6 5 0\n"); + printf(" # One hole in the middle of the inner square.\n"); + printf(" 1\n"); + printf(" 1 1.5 1.5\n\n"); + printf( +" Note that some segments are missing from the outer square, so one must\n"); + printf( +" use the `-c' switch. After `triangle -pqc box.poly', here is the output\n" +); + printf( +" file `box.1.node', with twelve points. The last four points were added\n"); + printf( +" to meet the angle constraint. Points 1, 2, and 9 have markers from\n"); + printf( +" segment 1. Points 6 and 8 have markers from segment 4. All the other\n"); + printf( +" points but 4 have been marked to indicate that they lie on a boundary.\n"); + printf("\n"); + printf(" 12 2 0 1\n"); + printf(" 1 0 0 5\n"); + printf(" 2 0 3 5\n"); + printf(" 3 3 0 1\n"); + printf(" 4 3 3 33\n"); + printf(" 5 1 1 1\n"); + printf(" 6 1 2 10\n"); + printf(" 7 2 1 1\n"); + printf(" 8 2 2 10\n"); + printf(" 9 0 1.5 5\n"); + printf(" 10 1.5 0 1\n"); + printf(" 11 3 1.5 1\n"); + printf(" 12 1.5 3 1\n"); + printf(" # Generated by triangle -pqc box.poly\n\n"); + printf(" Here is the output file `box.1.ele', with twelve triangles.\n\n"); + printf(" 12 3 0\n"); + printf(" 1 5 6 9\n"); + printf(" 2 10 3 7\n"); + printf(" 3 6 8 12\n"); + printf(" 4 9 1 5\n"); + printf(" 5 6 2 9\n"); + printf(" 6 7 3 11\n"); + printf(" 7 11 4 8\n"); + printf(" 8 7 5 10\n"); + printf(" 9 12 2 6\n"); + printf(" 10 8 7 11\n"); + printf(" 11 5 1 10\n"); + printf(" 12 8 4 12\n"); + printf(" # Generated by triangle -pqc box.poly\n\n"); + printf( +" Here is the output file `box.1.poly'. Note that segments have been added\n" +); + printf( +" to represent the convex hull, and some segments have been split by newly\n" +); + printf( +" added points. Note also that <# of points> is set to zero to indicate\n"); + printf(" that the points should be read from the .node file.\n\n"); + printf(" 0 2 0 1\n"); + printf(" 12 1\n"); + printf(" 1 1 9 5\n"); + printf(" 2 5 7 1\n"); + printf(" 3 8 7 1\n"); + printf(" 4 6 8 10\n"); + printf(" 5 5 6 1\n"); + printf(" 6 3 10 1\n"); + printf(" 7 4 11 1\n"); + printf(" 8 2 12 1\n"); + printf(" 9 9 2 5\n"); + printf(" 10 10 1 1\n"); + printf(" 11 11 3 1\n"); + printf(" 12 12 4 1\n"); + printf(" 1\n"); + printf(" 1 1.5 1.5\n"); + printf(" # Generated by triangle -pqc box.poly\n\n"); + printf("Refinement and Area Constraints:\n\n"); + printf( +" The -r switch causes a mesh (.node and .ele files) to be read and\n"); + printf( +" refined. If the -p switch is also used, a .poly file is read and used to\n" +); + printf( +" specify edges that are constrained and cannot be eliminated (although\n"); + printf( +" they can be divided into smaller edges) by the refinement process.\n"); + printf("\n"); + printf( +" When you refine a mesh, you generally want to impose tighter quality\n"); + printf( +" constraints. One way to accomplish this is to use -q with a larger\n"); + printf( +" angle, or -a followed by a smaller area than you used to generate the\n"); + printf( +" mesh you are refining. Another way to do this is to create an .area\n"); + printf( +" file, which specifies a maximum area for each triangle, and use the -a\n"); + printf( +" switch (without a number following). Each triangle's area constraint is\n" +); + printf( +" applied to that triangle. Area constraints tend to diffuse as the mesh\n"); + printf( +" is refined, so if there are large variations in area constraint between\n"); + printf(" adjacent triangles, you may not get the results you want.\n\n"); + printf( +" If you are refining a mesh composed of linear (three-node) elements, the\n" +); + printf( +" output mesh will contain all the nodes present in the input mesh, in the\n" +); + printf( +" same order, with new nodes added at the end of the .node file. However,\n" +); + printf( +" there is no guarantee that each output element is contained in a single\n"); + printf( +" input element. Often, output elements will overlap two input elements,\n"); + printf( +" and input edges are not present in the output mesh. Hence, a sequence of\n" +); + printf( +" refined meshes will form a hierarchy of nodes, but not a hierarchy of\n"); + printf( +" elements. If you a refining a mesh of higher-order elements, the\n"); + printf( +" hierarchical property applies only to the nodes at the corners of an\n"); + printf(" element; other nodes may not be present in the refined mesh.\n\n"); + printf( +" It is important to understand that maximum area constraints in .poly\n"); + printf( +" files are handled differently from those in .area files. A maximum area\n" +); + printf( +" in a .poly file applies to the whole (segment-bounded) region in which a\n" +); + printf( +" point falls, whereas a maximum area in an .area file applies to only one\n" +); + printf( +" triangle. Area constraints in .poly files are used only when a mesh is\n"); + printf( +" first generated, whereas area constraints in .area files are used only to\n" +); + printf( +" refine an existing mesh, and are typically based on a posteriori error\n"); + printf( +" estimates resulting from a finite element simulation on that mesh.\n"); + printf("\n"); + printf( +" `triangle -rq25 object.1' will read object.1.node and object.1.ele, then\n" +); + printf( +" refine the triangulation to enforce a 25 degree minimum angle, and then\n"); + printf( +" write the refined triangulation to object.2.node and object.2.ele.\n"); + printf("\n"); + printf( +" `triangle -rpaa6.2 z.3' will read z.3.node, z.3.ele, z.3.poly, and\n"); + printf( +" z.3.area. After reconstructing the mesh and its segments, Triangle will\n" +); + printf( +" refine the mesh so that no triangle has area greater than 6.2, and\n"); + printf( +" furthermore the triangles satisfy the maximum area constraints in\n"); + printf( +" z.3.area. The output is written to z.4.node, z.4.ele, and z.4.poly.\n"); + printf("\n"); + printf( +" The sequence `triangle -qa1 x', `triangle -rqa.3 x.1', `triangle -rqa.1\n"); + printf( +" x.2' creates a sequence of successively finer meshes x.1, x.2, and x.3,\n"); + printf(" suitable for multigrid.\n\n"); + printf("Convex Hulls and Mesh Boundaries:\n\n"); + printf( +" If the input is a point set (rather than a PSLG), Triangle produces its\n"); + printf( +" convex hull as a by-product in the output .poly file if you use the -c\n"); + printf( +" switch. There are faster algorithms for finding a two-dimensional convex\n" +); + printf( +" hull than triangulation, of course, but this one comes for free. If the\n" +); + printf( +" input is an unconstrained mesh (you are using the -r switch but not the\n"); + printf( +" -p switch), Triangle produces a list of its boundary edges (including\n"); + printf(" hole boundaries) as a by-product if you use the -c switch.\n\n"); + printf("Voronoi Diagrams:\n\n"); + printf( +" The -v switch produces a Voronoi diagram, in files suffixed .v.node and\n"); + printf( +" .v.edge. For example, `triangle -v points' will read points.node,\n"); + printf( +" produce its Delaunay triangulation in points.1.node and points.1.ele,\n"); + printf( +" and produce its Voronoi diagram in points.1.v.node and points.1.v.edge.\n"); + printf( +" The .v.node file contains a list of all Voronoi vertices, and the .v.edge\n" +); + printf( +" file contains a list of all Voronoi edges, some of which may be infinite\n" +); + printf( +" rays. (The choice of filenames makes it easy to run the set of Voronoi\n"); + printf(" vertices through Triangle, if so desired.)\n\n"); + printf( +" This implementation does not use exact arithmetic to compute the Voronoi\n" +); + printf( +" vertices, and does not check whether neighboring vertices are identical.\n" +); + printf( +" Be forewarned that if the Delaunay triangulation is degenerate or\n"); + printf( +" near-degenerate, the Voronoi diagram may have duplicate points, crossing\n" +); + printf( +" edges, or infinite rays whose direction vector is zero. Also, if you\n"); + printf( +" generate a constrained (as opposed to conforming) Delaunay triangulation,\n" +); + printf( +" or if the triangulation has holes, the corresponding Voronoi diagram is\n"); + printf(" likely to have crossing edges and unlikely to make sense.\n\n"); + printf("Mesh Topology:\n\n"); + printf( +" You may wish to know which triangles are adjacent to a certain Delaunay\n"); + printf( +" edge in an .edge file, which Voronoi regions are adjacent to a certain\n"); + printf( +" Voronoi edge in a .v.edge file, or which Voronoi regions are adjacent to\n" +); + printf( +" each other. All of this information can be found by cross-referencing\n"); + printf( +" output files with the recollection that the Delaunay triangulation and\n"); + printf(" the Voronoi diagrams are planar duals.\n\n"); + printf( +" Specifically, edge i of an .edge file is the dual of Voronoi edge i of\n"); + printf( +" the corresponding .v.edge file, and is rotated 90 degrees counterclock-\n"); + printf( +" wise from the Voronoi edge. Triangle j of an .ele file is the dual of\n"); + printf( +" vertex j of the corresponding .v.node file; and Voronoi region k is the\n"); + printf(" dual of point k of the corresponding .node file.\n\n"); + printf( +" Hence, to find the triangles adjacent to a Delaunay edge, look at the\n"); + printf( +" vertices of the corresponding Voronoi edge; their dual triangles are on\n"); + printf( +" the left and right of the Delaunay edge, respectively. To find the\n"); + printf( +" Voronoi regions adjacent to a Voronoi edge, look at the endpoints of the\n" +); + printf( +" corresponding Delaunay edge; their dual regions are on the right and left\n" +); + printf( +" of the Voronoi edge, respectively. To find which Voronoi regions are\n"); + printf(" adjacent to each other, just read the list of Delaunay edges.\n"); + printf("\n"); + printf("Statistics:\n"); + printf("\n"); + printf( +" After generating a mesh, Triangle prints a count of the number of points,\n" +); + printf( +" triangles, edges, boundary edges, and segments in the output mesh. If\n"); + printf( +" you've forgotten the statistics for an existing mesh, the -rNEP switches\n" +); + printf( +" (or -rpNEP if you've got a .poly file for the existing mesh) will\n"); + printf(" regenerate these statistics without writing any output.\n\n"); + printf( +" The -V switch produces extended statistics, including a rough estimate\n"); + printf( +" of memory use and a histogram of triangle aspect ratios and angles in the\n" +); + printf(" mesh.\n\n"); + printf("Exact Arithmetic:\n\n"); + printf( +" Triangle uses adaptive exact arithmetic to perform what computational\n"); + printf( +" geometers call the `orientation' and `incircle' tests. If the floating-\n" +); + printf( +" point arithmetic of your machine conforms to the IEEE 754 standard (as\n"); + printf( +" most workstations do), and does not use extended precision internal\n"); + printf( +" registers, then your output is guaranteed to be an absolutely true\n"); + printf(" Delaunay or conforming Delaunay triangulation, roundoff error\n"); + printf( +" notwithstanding. The word `adaptive' implies that these arithmetic\n"); + printf( +" routines compute the result only to the precision necessary to guarantee\n" +); + printf( +" correctness, so they are usually nearly as fast as their approximate\n"); + printf( +" counterparts. The exact tests can be disabled with the -X switch. On\n"); + printf( +" most inputs, this switch will reduce the computation time by about eight\n" +); + printf( +" percent - it's not worth the risk. There are rare difficult inputs\n"); + printf( +" (having many collinear and cocircular points), however, for which the\n"); + printf( +" difference could be a factor of two. These are precisely the inputs most\n" +); + printf(" likely to cause errors if you use the -X switch.\n\n"); + printf( +" Unfortunately, these routines don't solve every numerical problem. Exact\n" +); + printf( +" arithmetic is not used to compute the positions of points, because the\n"); + printf( +" bit complexity of point coordinates would grow without bound. Hence,\n"); + printf( +" segment intersections aren't computed exactly; in very unusual cases,\n"); + printf( +" roundoff error in computing an intersection point might actually lead to\n" +); + printf( +" an inverted triangle and an invalid triangulation. (This is one reason\n"); + printf( +" to compute your own intersection points in your .poly files.) Similarly,\n" +); + printf( +" exact arithmetic is not used to compute the vertices of the Voronoi\n"); + printf(" diagram.\n\n"); + printf( +" Underflow and overflow can also cause difficulties; the exact arithmetic\n" +); + printf( +" routines do not ameliorate out-of-bounds exponents, which can arise\n"); + printf( +" during the orientation and incircle tests. As a rule of thumb, you\n"); + printf( +" should ensure that your input values are within a range such that their\n"); + printf( +" third powers can be taken without underflow or overflow. Underflow can\n"); + printf( +" silently prevent the tests from being performed exactly, while overflow\n"); + printf(" will typically cause a floating exception.\n\n"); + printf("Calling Triangle from Another Program:\n\n"); + printf(" Read the file triangle.h for details.\n\n"); + printf("Troubleshooting:\n\n"); + printf(" Please read this section before mailing me bugs.\n\n"); + printf(" `My output mesh has no triangles!'\n\n"); + printf( +" If you're using a PSLG, you've probably failed to specify a proper set\n" +); + printf( +" of bounding segments, or forgotten to use the -c switch. Or you may\n"); + printf( +" have placed a hole badly. To test these possibilities, try again with\n" +); + printf( +" the -c and -O switches. Alternatively, all your input points may be\n"); + printf( +" collinear, in which case you can hardly expect to triangulate them.\n"); + printf("\n"); + printf(" `Triangle doesn't terminate, or just crashes.'\n"); + printf("\n"); + printf( +" Bad things can happen when triangles get so small that the distance\n"); + printf( +" between their vertices isn't much larger than the precision of your\n"); + printf( +" machine's arithmetic. If you've compiled Triangle for single-precision\n" +); + printf( +" arithmetic, you might do better by recompiling it for double-precision.\n" +); + printf( +" Then again, you might just have to settle for more lenient constraints\n" +); + printf( +" on the minimum angle and the maximum area than you had planned.\n"); + printf("\n"); + printf( +" You can minimize precision problems by ensuring that the origin lies\n"); + printf( +" inside your point set, or even inside the densest part of your\n"); + printf( +" mesh. On the other hand, if you're triangulating an object whose x\n"); + printf( +" coordinates all fall between 6247133 and 6247134, you're not leaving\n"); + printf(" much floating-point precision for Triangle to work with.\n\n"); + printf( +" Precision problems can occur covertly if the input PSLG contains two\n"); + printf( +" segments that meet (or intersect) at a very small angle, or if such an\n" +); + printf( +" angle is introduced by the -c switch, which may occur if a point lies\n"); + printf( +" ever-so-slightly inside the convex hull, and is connected by a PSLG\n"); + printf( +" segment to a point on the convex hull. If you don't realize that a\n"); + printf( +" small angle is being formed, you might never discover why Triangle is\n"); + printf( +" crashing. To check for this possibility, use the -S switch (with an\n"); + printf( +" appropriate limit on the number of Steiner points, found by trial-and-\n" +); + printf( +" error) to stop Triangle early, and view the output .poly file with\n"); + printf( +" Show Me (described below). Look carefully for small angles between\n"); + printf( +" segments; zoom in closely, as such segments might look like a single\n"); + printf(" segment from a distance.\n\n"); + printf( +" If some of the input values are too large, Triangle may suffer a\n"); + printf( +" floating exception due to overflow when attempting to perform an\n"); + printf( +" orientation or incircle test. (Read the section on exact arithmetic\n"); + printf( +" above.) Again, I recommend compiling Triangle for double (rather\n"); + printf(" than single) precision arithmetic.\n\n"); + printf( +" `The numbering of the output points doesn't match the input points.'\n"); + printf("\n"); + printf( +" You may have eaten some of your input points with a hole, or by placing\n" +); + printf(" them outside the area enclosed by segments.\n\n"); + printf( +" `Triangle executes without incident, but when I look at the resulting\n"); + printf( +" mesh, it has overlapping triangles or other geometric inconsistencies.'\n"); + printf("\n"); + printf( +" If you select the -X switch, Triangle's divide-and-conquer Delaunay\n"); + printf( +" triangulation algorithm occasionally makes mistakes due to floating-\n"); + printf( +" point roundoff error. Although these errors are rare, don't use the -X\n" +); + printf(" switch. If you still have problems, please report the bug.\n"); + printf("\n"); + printf( +" Strange things can happen if you've taken liberties with your PSLG. Do\n"); + printf( +" you have a point lying in the middle of a segment? Triangle sometimes\n"); + printf( +" copes poorly with that sort of thing. Do you want to lay out a collinear\n" +); + printf( +" row of evenly spaced, segment-connected points? Have you simply defined\n" +); + printf( +" one long segment connecting the leftmost point to the rightmost point,\n"); + printf( +" and a bunch of points lying along it? This method occasionally works,\n"); + printf( +" especially with horizontal and vertical lines, but often it doesn't, and\n" +); + printf( +" you'll have to connect each adjacent pair of points with a separate\n"); + printf(" segment. If you don't like it, tough.\n\n"); + printf( +" Furthermore, if you have segments that intersect other than at their\n"); + printf( +" endpoints, try not to let the intersections fall extremely close to PSLG\n" +); + printf(" points or each other.\n\n"); + printf( +" If you have problems refining a triangulation not produced by Triangle:\n"); + printf( +" Are you sure the triangulation is geometrically valid? Is it formatted\n"); + printf( +" correctly for Triangle? Are the triangles all listed so the first three\n" +); + printf(" points are their corners in counterclockwise order?\n\n"); + printf("Show Me:\n\n"); + printf( +" Triangle comes with a separate program named `Show Me', whose primary\n"); + printf( +" purpose is to draw meshes on your screen or in PostScript. Its secondary\n" +); + printf( +" purpose is to check the validity of your input files, and do so more\n"); + printf( +" thoroughly than Triangle does. Show Me requires that you have the X\n"); + printf( +" Windows system. If you didn't receive Show Me with Triangle, complain to\n" +); + printf(" whomever you obtained Triangle from, then send me mail.\n\n"); + printf("Triangle on the Web:\n\n"); + printf( +" To see an illustrated, updated version of these instructions, check out\n"); + printf("\n"); + printf(" http://www.cs.cmu.edu/~quake/triangle.html\n"); + printf("\n"); + printf("A Brief Plea:\n"); + printf("\n"); + printf( +" If you use Triangle, and especially if you use it to accomplish real\n"); + printf( +" work, I would like very much to hear from you. A short letter or email\n"); + printf( +" (to jrs@cs.cmu.edu) describing how you use Triangle will mean a lot to\n"); + printf( +" me. The more people I know are using this program, the more easily I can\n" +); + printf( +" justify spending time on improvements and on the three-dimensional\n"); + printf( +" successor to Triangle, which in turn will benefit you. Also, I can put\n"); + printf( +" you on a list to receive email whenever a new version of Triangle is\n"); + printf(" available.\n\n"); + printf( +" If you use a mesh generated by Triangle in a publication, please include\n" +); + printf(" an acknowledgment as well.\n\n"); + printf("Research credit:\n\n"); + printf( +" Of course, I can take credit for only a fraction of the ideas that made\n"); + printf( +" this mesh generator possible. Triangle owes its existence to the efforts\n" +); + printf( +" of many fine computational geometers and other researchers, including\n"); + printf( +" Marshall Bern, L. Paul Chew, Boris Delaunay, Rex A. Dwyer, David\n"); + printf( +" Eppstein, Steven Fortune, Leonidas J. Guibas, Donald E. Knuth, C. L.\n"); + printf( +" Lawson, Der-Tsai Lee, Ernst P. Mucke, Douglas M. Priest, Jim Ruppert,\n"); + printf( +" Isaac Saias, Bruce J. Schachter, Micha Sharir, Jorge Stolfi, Christopher\n" +); + printf( +" J. Van Wyk, David F. Watson, and Binhai Zhu. See the comments at the\n"); + printf(" beginning of the source code for references.\n\n"); + exit(0); +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* internalerror() Ask the user to send me the defective product. Exit. */ +/* */ +/*****************************************************************************/ + +void internalerror() +{ + printf(" Please report this bug to jrs@cs.cmu.edu\n"); + printf(" Include the message above, your input data set, and the exact\n"); + printf(" command line you used to run Triangle.\n"); + exit(1); +} + +/*****************************************************************************/ +/* */ +/* parsecommandline() Read the command line, identify switches, and set */ +/* up options and file names. */ +/* */ +/* The effects of this routine are felt entirely through global variables. */ +/* */ +/*****************************************************************************/ + +void parsecommandline(argc, argv) +int argc; +char **argv; +{ +#ifdef TRILIBRARY +#define STARTINDEX 0 +#else /* not TRILIBRARY */ +#define STARTINDEX 1 + int increment; + int meshnumber; +#endif /* not TRILIBRARY */ + int i, j; +#ifndef CDT_ONLY + int k; + char workstring[FILENAMESIZE]; +#endif + + poly = refine = quality = vararea = fixedarea = regionattrib = convex = 0; + firstnumber = 1; + edgesout = voronoi = neighbors = geomview = 0; + nobound = nopolywritten = nonodewritten = noelewritten = noiterationnum = 0; + noholes = noexact = 0; + incremental = sweepline = 0; + dwyer = 1; + splitseg = 0; + docheck = 0; + nobisect = 0; + steiner = -1; + order = 1; + minangle = 0.0; + maxarea = -1.0; + quiet = verbose = 0; +#ifndef TRILIBRARY + innodefilename[0] = '\0'; +#endif /* not TRILIBRARY */ + + for (i = STARTINDEX; i < argc; i++) { +#ifndef TRILIBRARY + if (argv[i][0] == '-') { +#endif /* not TRILIBRARY */ + for (j = STARTINDEX; argv[i][j] != '\0'; j++) { + if (argv[i][j] == 'p') { + poly = 1; + } +#ifndef CDT_ONLY + if (argv[i][j] == 'r') { + refine = 1; + } + if (argv[i][j] == 'q') { + quality = 1; + if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + k = 0; + while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + j++; + workstring[k] = argv[i][j]; + k++; + } + workstring[k] = '\0'; + minangle = (REAL) strtod(workstring, (char **) NULL); + } else { + minangle = 20.0; + } + } + if (argv[i][j] == 'a') { + quality = 1; + if (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + fixedarea = 1; + k = 0; + while (((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) || + (argv[i][j + 1] == '.')) { + j++; + workstring[k] = argv[i][j]; + k++; + } + workstring[k] = '\0'; + maxarea = (REAL) strtod(workstring, (char **) NULL); + if (maxarea <= 0.0) { + printf("Error: Maximum area must be greater than zero.\n"); + exit(1); + } + } else { + vararea = 1; + } + } +#endif /* not CDT_ONLY */ + if (argv[i][j] == 'A') { + regionattrib = 1; + } + if (argv[i][j] == 'c') { + convex = 1; + } + if (argv[i][j] == 'z') { + firstnumber = 0; + } + if (argv[i][j] == 'e') { + edgesout = 1; + } + if (argv[i][j] == 'v') { + voronoi = 1; + } + if (argv[i][j] == 'n') { + neighbors = 1; + } + if (argv[i][j] == 'g') { + geomview = 1; + } + if (argv[i][j] == 'B') { + nobound = 1; + } + if (argv[i][j] == 'P') { + nopolywritten = 1; + } + if (argv[i][j] == 'N') { + nonodewritten = 1; + } + if (argv[i][j] == 'E') { + noelewritten = 1; + } +#ifndef TRILIBRARY + if (argv[i][j] == 'I') { + noiterationnum = 1; + } +#endif /* not TRILIBRARY */ + if (argv[i][j] == 'O') { + noholes = 1; + } + if (argv[i][j] == 'X') { + noexact = 1; + } + if (argv[i][j] == 'o') { + if (argv[i][j + 1] == '2') { + j++; + order = 2; + } + } +#ifndef CDT_ONLY + if (argv[i][j] == 'Y') { + nobisect++; + } + if (argv[i][j] == 'S') { + steiner = 0; + while ((argv[i][j + 1] >= '0') && (argv[i][j + 1] <= '9')) { + j++; + steiner = steiner * 10 + (int) (argv[i][j] - '0'); + } + } +#endif /* not CDT_ONLY */ +#ifndef REDUCED + if (argv[i][j] == 'i') { + incremental = 1; + } + if (argv[i][j] == 'F') { + sweepline = 1; + } +#endif /* not REDUCED */ + if (argv[i][j] == 'l') { + dwyer = 0; + } +#ifndef REDUCED +#ifndef CDT_ONLY + if (argv[i][j] == 's') { + splitseg = 1; + } +#endif /* not CDT_ONLY */ + if (argv[i][j] == 'C') { + docheck = 1; + } +#endif /* not REDUCED */ + if (argv[i][j] == 'Q') { + quiet = 1; + } + if (argv[i][j] == 'V') { + verbose++; + } +#ifndef TRILIBRARY + if ((argv[i][j] == 'h') || (argv[i][j] == 'H') || + (argv[i][j] == '?')) { + info(); + } +#endif /* not TRILIBRARY */ + } +#ifndef TRILIBRARY + } else { + strncpy(innodefilename, argv[i], FILENAMESIZE - 1); + innodefilename[FILENAMESIZE - 1] = '\0'; + } +#endif /* not TRILIBRARY */ + } +#ifndef TRILIBRARY + if (innodefilename[0] == '\0') { + syntax(); + } + if (!strcmp(&innodefilename[strlen(innodefilename) - 5], ".node")) { + innodefilename[strlen(innodefilename) - 5] = '\0'; + } + if (!strcmp(&innodefilename[strlen(innodefilename) - 5], ".poly")) { + innodefilename[strlen(innodefilename) - 5] = '\0'; + poly = 1; + } +#ifndef CDT_ONLY + if (!strcmp(&innodefilename[strlen(innodefilename) - 4], ".ele")) { + innodefilename[strlen(innodefilename) - 4] = '\0'; + refine = 1; + } + if (!strcmp(&innodefilename[strlen(innodefilename) - 5], ".area")) { + innodefilename[strlen(innodefilename) - 5] = '\0'; + refine = 1; + quality = 1; + vararea = 1; + } +#endif /* not CDT_ONLY */ +#endif /* not TRILIBRARY */ + steinerleft = steiner; + useshelles = poly || refine || quality || convex; + goodangle = (REAL)cos(minangle * PI / 180.0); + goodangle *= goodangle; + if (refine && noiterationnum) { + printf( + "Error: You cannot use the -I switch when refining a triangulation.\n"); + exit(1); + } + /* Be careful not to allocate space for element area constraints that */ + /* will never be assigned any value (other than the default -1.0). */ + if (!refine && !poly) { + vararea = 0; + } + /* Be careful not to add an extra attribute to each element unless the */ + /* input supports it (PSLG in, but not refining a preexisting mesh). */ + if (refine || !poly) { + regionattrib = 0; + } + +#ifndef TRILIBRARY + strcpy(inpolyfilename, innodefilename); + strcpy(inelefilename, innodefilename); + strcpy(areafilename, innodefilename); + increment = 0; + strcpy(workstring, innodefilename); + j = 1; + while (workstring[j] != '\0') { + if ((workstring[j] == '.') && (workstring[j + 1] != '\0')) { + increment = j + 1; + } + j++; + } + meshnumber = 0; + if (increment > 0) { + j = increment; + do { + if ((workstring[j] >= '0') && (workstring[j] <= '9')) { + meshnumber = meshnumber * 10 + (int) (workstring[j] - '0'); + } else { + increment = 0; + } + j++; + } while (workstring[j] != '\0'); + } + if (noiterationnum) { + strcpy(outnodefilename, innodefilename); + strcpy(outelefilename, innodefilename); + strcpy(edgefilename, innodefilename); + strcpy(vnodefilename, innodefilename); + strcpy(vedgefilename, innodefilename); + strcpy(neighborfilename, innodefilename); + strcpy(offfilename, innodefilename); + strcat(outnodefilename, ".node"); + strcat(outelefilename, ".ele"); + strcat(edgefilename, ".edge"); + strcat(vnodefilename, ".v.node"); + strcat(vedgefilename, ".v.edge"); + strcat(neighborfilename, ".neigh"); + strcat(offfilename, ".off"); + } else if (increment == 0) { + strcpy(outnodefilename, innodefilename); + strcpy(outpolyfilename, innodefilename); + strcpy(outelefilename, innodefilename); + strcpy(edgefilename, innodefilename); + strcpy(vnodefilename, innodefilename); + strcpy(vedgefilename, innodefilename); + strcpy(neighborfilename, innodefilename); + strcpy(offfilename, innodefilename); + strcat(outnodefilename, ".1.node"); + strcat(outpolyfilename, ".1.poly"); + strcat(outelefilename, ".1.ele"); + strcat(edgefilename, ".1.edge"); + strcat(vnodefilename, ".1.v.node"); + strcat(vedgefilename, ".1.v.edge"); + strcat(neighborfilename, ".1.neigh"); + strcat(offfilename, ".1.off"); + } else { + workstring[increment] = '%'; + workstring[increment + 1] = 'd'; + workstring[increment + 2] = '\0'; + sprintf(outnodefilename, workstring, meshnumber + 1); + strcpy(outpolyfilename, outnodefilename); + strcpy(outelefilename, outnodefilename); + strcpy(edgefilename, outnodefilename); + strcpy(vnodefilename, outnodefilename); + strcpy(vedgefilename, outnodefilename); + strcpy(neighborfilename, outnodefilename); + strcpy(offfilename, outnodefilename); + strcat(outnodefilename, ".node"); + strcat(outpolyfilename, ".poly"); + strcat(outelefilename, ".ele"); + strcat(edgefilename, ".edge"); + strcat(vnodefilename, ".v.node"); + strcat(vedgefilename, ".v.edge"); + strcat(neighborfilename, ".neigh"); + strcat(offfilename, ".off"); + } + strcat(innodefilename, ".node"); + strcat(inpolyfilename, ".poly"); + strcat(inelefilename, ".ele"); + strcat(areafilename, ".area"); +#endif /* not TRILIBRARY */ +} + +/** **/ +/** **/ +/********* User interaction routines begin here *********/ + +/********* Debugging routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* printtriangle() Print out the details of a triangle/edge handle. */ +/* */ +/* I originally wrote this procedure to simplify debugging; it can be */ +/* called directly from the debugger, and presents information about a */ +/* triangle/edge handle in digestible form. It's also used when the */ +/* highest level of verbosity (`-VVV') is specified. */ +/* */ +/*****************************************************************************/ + +void printtriangle(t) +struct triedge *t; +{ + struct triedge printtri; + struct edge printsh; + point printpoint; + + printf("triangle x%lx with orientation %d:\n", (unsigned long) t->tri, + t->orient); + decode(t->tri[0], printtri); + if (printtri.tri == dummytri) { + printf(" [0] = Outer space\n"); + } else { + printf(" [0] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } + decode(t->tri[1], printtri); + if (printtri.tri == dummytri) { + printf(" [1] = Outer space\n"); + } else { + printf(" [1] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } + decode(t->tri[2], printtri); + if (printtri.tri == dummytri) { + printf(" [2] = Outer space\n"); + } else { + printf(" [2] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } + org(*t, printpoint); + if (printpoint == (point) NULL) + printf(" Origin[%d] = NULL\n", (t->orient + 1) % 3 + 3); + else + printf(" Origin[%d] = x%lx (%.12g, %.12g)\n", + (t->orient + 1) % 3 + 3, (unsigned long) printpoint, + printpoint[0], printpoint[1]); + dest(*t, printpoint); + if (printpoint == (point) NULL) + printf(" Dest [%d] = NULL\n", (t->orient + 2) % 3 + 3); + else + printf(" Dest [%d] = x%lx (%.12g, %.12g)\n", + (t->orient + 2) % 3 + 3, (unsigned long) printpoint, + printpoint[0], printpoint[1]); + apex(*t, printpoint); + if (printpoint == (point) NULL) + printf(" Apex [%d] = NULL\n", t->orient + 3); + else + printf(" Apex [%d] = x%lx (%.12g, %.12g)\n", + t->orient + 3, (unsigned long) printpoint, + printpoint[0], printpoint[1]); + if (useshelles) { + sdecode(t->tri[6], printsh); + if (printsh.sh != dummysh) { + printf(" [6] = x%lx %d\n", (unsigned long) printsh.sh, + printsh.shorient); + } + sdecode(t->tri[7], printsh); + if (printsh.sh != dummysh) { + printf(" [7] = x%lx %d\n", (unsigned long) printsh.sh, + printsh.shorient); + } + sdecode(t->tri[8], printsh); + if (printsh.sh != dummysh) { + printf(" [8] = x%lx %d\n", (unsigned long) printsh.sh, + printsh.shorient); + } + } + if (vararea) { + printf(" Area constraint: %.4g\n", areabound(*t)); + } +} + +/*****************************************************************************/ +/* */ +/* printshelle() Print out the details of a shell edge handle. */ +/* */ +/* I originally wrote this procedure to simplify debugging; it can be */ +/* called directly from the debugger, and presents information about a */ +/* shell edge handle in digestible form. It's also used when the highest */ +/* level of verbosity (`-VVV') is specified. */ +/* */ +/*****************************************************************************/ + +void printshelle(s) +struct edge *s; +{ + struct edge printsh; + struct triedge printtri; + point printpoint; + + printf("shell edge x%lx with orientation %d and mark %d:\n", + (unsigned long) s->sh, s->shorient, mark(*s)); + sdecode(s->sh[0], printsh); + if (printsh.sh == dummysh) { + printf(" [0] = No shell\n"); + } else { + printf(" [0] = x%lx %d\n", (unsigned long) printsh.sh, + printsh.shorient); + } + sdecode(s->sh[1], printsh); + if (printsh.sh == dummysh) { + printf(" [1] = No shell\n"); + } else { + printf(" [1] = x%lx %d\n", (unsigned long) printsh.sh, + printsh.shorient); + } + sorg(*s, printpoint); + if (printpoint == (point) NULL) + printf(" Origin[%d] = NULL\n", 2 + s->shorient); + else + printf(" Origin[%d] = x%lx (%.12g, %.12g)\n", + 2 + s->shorient, (unsigned long) printpoint, + printpoint[0], printpoint[1]); + sdest(*s, printpoint); + if (printpoint == (point) NULL) + printf(" Dest [%d] = NULL\n", 3 - s->shorient); + else + printf(" Dest [%d] = x%lx (%.12g, %.12g)\n", + 3 - s->shorient, (unsigned long) printpoint, + printpoint[0], printpoint[1]); + decode(s->sh[4], printtri); + if (printtri.tri == dummytri) { + printf(" [4] = Outer space\n"); + } else { + printf(" [4] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } + decode(s->sh[5], printtri); + if (printtri.tri == dummytri) { + printf(" [5] = Outer space\n"); + } else { + printf(" [5] = x%lx %d\n", (unsigned long) printtri.tri, + printtri.orient); + } +} + +/** **/ +/** **/ +/********* Debugging routines end here *********/ + +/********* Memory management routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* poolinit() Initialize a pool of memory for allocation of items. */ +/* */ +/* This routine initializes the machinery for allocating items. A `pool' */ +/* is created whose records have size at least `bytecount'. Items will be */ +/* allocated in `itemcount'-item blocks. Each item is assumed to be a */ +/* collection of words, and either pointers or floating-point values are */ +/* assumed to be the "primary" word type. (The "primary" word type is used */ +/* to determine alignment of items.) If `alignment' isn't zero, all items */ +/* will be `alignment'-byte aligned in memory. `alignment' must be either */ +/* a multiple or a factor of the primary word size; powers of two are safe. */ +/* `alignment' is normally used to create a few unused bits at the bottom */ +/* of each item's pointer, in which information may be stored. */ +/* */ +/* Don't change this routine unless you understand it. */ +/* */ +/*****************************************************************************/ + +void poolinit(pool, bytecount, itemcount, wtype, alignment) +struct memorypool *pool; +int bytecount; +int itemcount; +enum wordtype wtype; +int alignment; +{ + int wordsize; + + /* Initialize values in the pool. */ + pool->itemwordtype = wtype; + wordsize = (pool->itemwordtype == POINTER) ? sizeof(VOID *) : sizeof(REAL); + /* Find the proper alignment, which must be at least as large as: */ + /* - The parameter `alignment'. */ + /* - The primary word type, to avoid unaligned accesses. */ + /* - sizeof(VOID *), so the stack of dead items can be maintained */ + /* without unaligned accesses. */ + if (alignment > wordsize) { + pool->alignbytes = alignment; + } else { + pool->alignbytes = wordsize; + } + if (sizeof(VOID *) > pool->alignbytes) { + pool->alignbytes = sizeof(VOID *); + } + pool->itemwords = ((bytecount + pool->alignbytes - 1) / pool->alignbytes) + * (pool->alignbytes / wordsize); + pool->itembytes = pool->itemwords * wordsize; + pool->itemsperblock = itemcount; + + /* Allocate a block of items. Space for `itemsperblock' items and one */ + /* pointer (to point to the next block) are allocated, as well as space */ + /* to ensure alignment of the items. */ + pool->firstblock = (VOID **) malloc(pool->itemsperblock * pool->itembytes + + sizeof(VOID *) + pool->alignbytes); + if (pool->firstblock == (VOID **) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + /* Set the next block pointer to NULL. */ + *(pool->firstblock) = (VOID *) NULL; + poolrestart(pool); +} + +/*****************************************************************************/ +/* */ +/* poolrestart() Deallocate all items in a pool. */ +/* */ +/* The pool is returned to its starting state, except that no memory is */ +/* freed to the operating system. Rather, the previously allocated blocks */ +/* are ready to be reused. */ +/* */ +/*****************************************************************************/ + +void poolrestart(pool) +struct memorypool *pool; +{ + unsigned long alignptr; + + pool->items = 0; + pool->maxitems = 0; + + /* Set the currently active block. */ + pool->nowblock = pool->firstblock; + /* Find the first item in the pool. Increment by the size of (VOID *). */ + alignptr = (unsigned long) (pool->nowblock + 1); + /* Align the item on an `alignbytes'-byte boundary. */ + pool->nextitem = (VOID *) + (alignptr + (unsigned long) pool->alignbytes + - (alignptr % (unsigned long) pool->alignbytes)); + /* There are lots of unallocated items left in this block. */ + pool->unallocateditems = pool->itemsperblock; + /* The stack of deallocated items is empty. */ + pool->deaditemstack = (VOID *) NULL; +} + +/*****************************************************************************/ +/* */ +/* pooldeinit() Free to the operating system all memory taken by a pool. */ +/* */ +/*****************************************************************************/ + +void pooldeinit(pool) +struct memorypool *pool; +{ + while (pool->firstblock != (VOID **) NULL) { + pool->nowblock = (VOID **) *(pool->firstblock); + free(pool->firstblock); + pool->firstblock = pool->nowblock; + } +} + +/*****************************************************************************/ +/* */ +/* poolalloc() Allocate space for an item. */ +/* */ +/*****************************************************************************/ + +VOID *poolalloc(pool) +struct memorypool *pool; +{ + VOID *newitem; + VOID **newblock; + unsigned long alignptr; + + /* First check the linked list of dead items. If the list is not */ + /* empty, allocate an item from the list rather than a fresh one. */ + if (pool->deaditemstack != (VOID *) NULL) { + newitem = pool->deaditemstack; /* Take first item in list. */ + pool->deaditemstack = * (VOID **) pool->deaditemstack; + } else { + /* Check if there are any free items left in the current block. */ + if (pool->unallocateditems == 0) { + /* Check if another block must be allocated. */ + if (*(pool->nowblock) == (VOID *) NULL) { + /* Allocate a new block of items, pointed to by the previous block. */ + newblock = (VOID **) malloc(pool->itemsperblock * pool->itembytes + + sizeof(VOID *) + pool->alignbytes); + if (newblock == (VOID **) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + *(pool->nowblock) = (VOID *) newblock; + /* The next block pointer is NULL. */ + *newblock = (VOID *) NULL; + } + /* Move to the new block. */ + pool->nowblock = (VOID **) *(pool->nowblock); + /* Find the first item in the block. */ + /* Increment by the size of (VOID *). */ + alignptr = (unsigned long) (pool->nowblock + 1); + /* Align the item on an `alignbytes'-byte boundary. */ + pool->nextitem = (VOID *) + (alignptr + (unsigned long) pool->alignbytes + - (alignptr % (unsigned long) pool->alignbytes)); + /* There are lots of unallocated items left in this block. */ + pool->unallocateditems = pool->itemsperblock; + } + /* Allocate a new item. */ + newitem = pool->nextitem; + /* Advance `nextitem' pointer to next free item in block. */ + if (pool->itemwordtype == POINTER) { + pool->nextitem = (VOID *) ((VOID **) pool->nextitem + pool->itemwords); + } else { + pool->nextitem = (VOID *) ((REAL *) pool->nextitem + pool->itemwords); + } + pool->unallocateditems--; + pool->maxitems++; + } + pool->items++; + return newitem; +} + +/*****************************************************************************/ +/* */ +/* pooldealloc() Deallocate space for an item. */ +/* */ +/* The deallocated space is stored in a queue for later reuse. */ +/* */ +/*****************************************************************************/ + +void pooldealloc(pool, dyingitem) +struct memorypool *pool; +VOID *dyingitem; +{ + /* Push freshly killed item onto stack. */ + *((VOID **) dyingitem) = pool->deaditemstack; + pool->deaditemstack = dyingitem; + pool->items--; +} + +/*****************************************************************************/ +/* */ +/* traversalinit() Prepare to traverse the entire list of items. */ +/* */ +/* This routine is used in conjunction with traverse(). */ +/* */ +/*****************************************************************************/ + +void traversalinit(pool) +struct memorypool *pool; +{ + unsigned long alignptr; + + /* Begin the traversal in the first block. */ + pool->pathblock = pool->firstblock; + /* Find the first item in the block. Increment by the size of (VOID *). */ + alignptr = (unsigned long) (pool->pathblock + 1); + /* Align with item on an `alignbytes'-byte boundary. */ + pool->pathitem = (VOID *) + (alignptr + (unsigned long) pool->alignbytes + - (alignptr % (unsigned long) pool->alignbytes)); + /* Set the number of items left in the current block. */ + pool->pathitemsleft = pool->itemsperblock; +} + +/*****************************************************************************/ +/* */ +/* traverse() Find the next item in the list. */ +/* */ +/* This routine is used in conjunction with traversalinit(). Be forewarned */ +/* that this routine successively returns all items in the list, including */ +/* deallocated ones on the deaditemqueue. It's up to you to figure out */ +/* which ones are actually dead. Why? I don't want to allocate extra */ +/* space just to demarcate dead items. It can usually be done more */ +/* space-efficiently by a routine that knows something about the structure */ +/* of the item. */ +/* */ +/*****************************************************************************/ + +VOID *traverse(pool) +struct memorypool *pool; +{ + VOID *newitem; + unsigned long alignptr; + + /* Stop upon exhausting the list of items. */ + if (pool->pathitem == pool->nextitem) { + return (VOID *) NULL; + } + /* Check whether any untraversed items remain in the current block. */ + if (pool->pathitemsleft == 0) { + /* Find the next block. */ + pool->pathblock = (VOID **) *(pool->pathblock); + /* Find the first item in the block. Increment by the size of (VOID *). */ + alignptr = (unsigned long) (pool->pathblock + 1); + /* Align with item on an `alignbytes'-byte boundary. */ + pool->pathitem = (VOID *) + (alignptr + (unsigned long) pool->alignbytes + - (alignptr % (unsigned long) pool->alignbytes)); + /* Set the number of items left in the current block. */ + pool->pathitemsleft = pool->itemsperblock; + } + newitem = pool->pathitem; + /* Find the next item in the block. */ + if (pool->itemwordtype == POINTER) { + pool->pathitem = (VOID *) ((VOID **) pool->pathitem + pool->itemwords); + } else { + pool->pathitem = (VOID *) ((REAL *) pool->pathitem + pool->itemwords); + } + pool->pathitemsleft--; + return newitem; +} + +/*****************************************************************************/ +/* */ +/* dummyinit() Initialize the triangle that fills "outer space" and the */ +/* omnipresent shell edge. */ +/* */ +/* The triangle that fills "outer space", called `dummytri', is pointed to */ +/* by every triangle and shell edge on a boundary (be it outer or inner) of */ +/* the triangulation. Also, `dummytri' points to one of the triangles on */ +/* the convex hull (until the holes and concavities are carved), making it */ +/* possible to find a starting triangle for point location. */ +/* */ +/* The omnipresent shell edge, `dummysh', is pointed to by every triangle */ +/* or shell edge that doesn't have a full complement of real shell edges */ +/* to point to. */ +/* */ +/*****************************************************************************/ + +void dummyinit(trianglewords, shellewords) +int trianglewords; +int shellewords; +{ + unsigned long alignptr; + + /* `triwords' and `shwords' are used by the mesh manipulation primitives */ + /* to extract orientations of triangles and shell edges from pointers. */ + triwords = trianglewords; /* Initialize `triwords' once and for all. */ + shwords = shellewords; /* Initialize `shwords' once and for all. */ + + /* Set up `dummytri', the `triangle' that occupies "outer space". */ + dummytribase = (triangle *) malloc(triwords * sizeof(triangle) + + triangles.alignbytes); + if (dummytribase == (triangle *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + /* Align `dummytri' on a `triangles.alignbytes'-byte boundary. */ + alignptr = (unsigned long) dummytribase; + dummytri = (triangle *) + (alignptr + (unsigned long) triangles.alignbytes + - (alignptr % (unsigned long) triangles.alignbytes)); + /* Initialize the three adjoining triangles to be "outer space". These */ + /* will eventually be changed by various bonding operations, but their */ + /* values don't really matter, as long as they can legally be */ + /* dereferenced. */ + dummytri[0] = (triangle) dummytri; + dummytri[1] = (triangle) dummytri; + dummytri[2] = (triangle) dummytri; + /* Three NULL vertex points. */ + dummytri[3] = (triangle) NULL; + dummytri[4] = (triangle) NULL; + dummytri[5] = (triangle) NULL; + + if (useshelles) { + /* Set up `dummysh', the omnipresent "shell edge" pointed to by any */ + /* triangle side or shell edge end that isn't attached to a real shell */ + /* edge. */ + dummyshbase = (shelle *) malloc(shwords * sizeof(shelle) + + shelles.alignbytes); + if (dummyshbase == (shelle *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + /* Align `dummysh' on a `shelles.alignbytes'-byte boundary. */ + alignptr = (unsigned long) dummyshbase; + dummysh = (shelle *) + (alignptr + (unsigned long) shelles.alignbytes + - (alignptr % (unsigned long) shelles.alignbytes)); + /* Initialize the two adjoining shell edges to be the omnipresent shell */ + /* edge. These will eventually be changed by various bonding */ + /* operations, but their values don't really matter, as long as they */ + /* can legally be dereferenced. */ + dummysh[0] = (shelle) dummysh; + dummysh[1] = (shelle) dummysh; + /* Two NULL vertex points. */ + dummysh[2] = (shelle) NULL; + dummysh[3] = (shelle) NULL; + /* Initialize the two adjoining triangles to be "outer space". */ + dummysh[4] = (shelle) dummytri; + dummysh[5] = (shelle) dummytri; + /* Set the boundary marker to zero. */ + * (int *) (dummysh + 6) = 0; + + /* Initialize the three adjoining shell edges of `dummytri' to be */ + /* the omnipresent shell edge. */ + dummytri[6] = (triangle) dummysh; + dummytri[7] = (triangle) dummysh; + dummytri[8] = (triangle) dummysh; + } +} + +/*****************************************************************************/ +/* */ +/* initializepointpool() Calculate the size of the point data structure */ +/* and initialize its memory pool. */ +/* */ +/* This routine also computes the `pointmarkindex' and `point2triindex' */ +/* indices used to find values within each point. */ +/* */ +/*****************************************************************************/ + +void initializepointpool() +{ + int pointsize; + + /* The index within each point at which the boundary marker is found. */ + /* Ensure the point marker is aligned to a sizeof(int)-byte address. */ + pointmarkindex = ((mesh_dim + nextras) * sizeof(REAL) + sizeof(int) - 1) + / sizeof(int); + pointsize = (pointmarkindex + 1) * sizeof(int); + if (poly) { + /* The index within each point at which a triangle pointer is found. */ + /* Ensure the pointer is aligned to a sizeof(triangle)-byte address. */ + point2triindex = (pointsize + sizeof(triangle) - 1) / sizeof(triangle); + pointsize = (point2triindex + 1) * sizeof(triangle); + } + /* Initialize the pool of points. */ + poolinit(&points, pointsize, POINTPERBLOCK, + (sizeof(REAL) >= sizeof(triangle)) ? FLOATINGPOINT : POINTER, 0); +} + +/*****************************************************************************/ +/* */ +/* initializetrisegpools() Calculate the sizes of the triangle and shell */ +/* edge data structures and initialize their */ +/* memory pools. */ +/* */ +/* This routine also computes the `highorderindex', `elemattribindex', and */ +/* `areaboundindex' indices used to find values within each triangle. */ +/* */ +/*****************************************************************************/ + +void initializetrisegpools() +{ + int trisize; + + /* The index within each triangle at which the extra nodes (above three) */ + /* associated with high order elements are found. There are three */ + /* pointers to other triangles, three pointers to corners, and possibly */ + /* three pointers to shell edges before the extra nodes. */ + highorderindex = 6 + (useshelles * 3); + /* The number of bytes occupied by a triangle. */ + trisize = ((order + 1) * (order + 2) / 2 + (highorderindex - 3)) * + sizeof(triangle); + /* The index within each triangle at which its attributes are found, */ + /* where the index is measured in REALs. */ + elemattribindex = (trisize + sizeof(REAL) - 1) / sizeof(REAL); + /* The index within each triangle at which the maximum area constraint */ + /* is found, where the index is measured in REALs. Note that if the */ + /* `regionattrib' flag is set, an additional attribute will be added. */ + areaboundindex = elemattribindex + eextras + regionattrib; + /* If triangle attributes or an area bound are needed, increase the number */ + /* of bytes occupied by a triangle. */ + if (vararea) { + trisize = (areaboundindex + 1) * sizeof(REAL); + } else if (eextras + regionattrib > 0) { + trisize = areaboundindex * sizeof(REAL); + } + /* If a Voronoi diagram or triangle neighbor graph is requested, make */ + /* sure there's room to store an integer index in each triangle. This */ + /* integer index can occupy the same space as the shell edges or */ + /* attributes or area constraint or extra nodes. */ + if ((voronoi || neighbors) && + (trisize < 6 * sizeof(triangle) + sizeof(int))) { + trisize = 6 * sizeof(triangle) + sizeof(int); + } + /* Having determined the memory size of a triangle, initialize the pool. */ + poolinit(&triangles, trisize, TRIPERBLOCK, POINTER, 4); + + if (useshelles) { + /* Initialize the pool of shell edges. */ + poolinit(&shelles, 6 * sizeof(triangle) + sizeof(int), SHELLEPERBLOCK, + POINTER, 4); + + /* Initialize the "outer space" triangle and omnipresent shell edge. */ + dummyinit(triangles.itemwords, shelles.itemwords); + } else { + /* Initialize the "outer space" triangle. */ + dummyinit(triangles.itemwords, 0); + } +} + +/*****************************************************************************/ +/* */ +/* triangledealloc() Deallocate space for a triangle, marking it dead. */ +/* */ +/*****************************************************************************/ + +void triangledealloc(dyingtriangle) +triangle *dyingtriangle; +{ + /* Set triangle's vertices to NULL. This makes it possible to */ + /* detect dead triangles when traversing the list of all triangles. */ + dyingtriangle[3] = (triangle) NULL; + dyingtriangle[4] = (triangle) NULL; + dyingtriangle[5] = (triangle) NULL; + pooldealloc(&triangles, (VOID *) dyingtriangle); +} + +/*****************************************************************************/ +/* */ +/* triangletraverse() Traverse the triangles, skipping dead ones. */ +/* */ +/*****************************************************************************/ + +triangle *triangletraverse() +{ + triangle *newtriangle; + + do { + newtriangle = (triangle *) traverse(&triangles); + if (newtriangle == (triangle *) NULL) { + return (triangle *) NULL; + } + } while (newtriangle[3] == (triangle) NULL); /* Skip dead ones. */ + return newtriangle; +} + +/*****************************************************************************/ +/* */ +/* shelledealloc() Deallocate space for a shell edge, marking it dead. */ +/* */ +/*****************************************************************************/ + +void shelledealloc(dyingshelle) +shelle *dyingshelle; +{ + /* Set shell edge's vertices to NULL. This makes it possible to */ + /* detect dead shells when traversing the list of all shells. */ + dyingshelle[2] = (shelle) NULL; + dyingshelle[3] = (shelle) NULL; + pooldealloc(&shelles, (VOID *) dyingshelle); +} + +/*****************************************************************************/ +/* */ +/* shelletraverse() Traverse the shell edges, skipping dead ones. */ +/* */ +/*****************************************************************************/ + +shelle *shelletraverse() +{ + shelle *newshelle; + + do { + newshelle = (shelle *) traverse(&shelles); + if (newshelle == (shelle *) NULL) { + return (shelle *) NULL; + } + } while (newshelle[2] == (shelle) NULL); /* Skip dead ones. */ + return newshelle; +} + +/*****************************************************************************/ +/* */ +/* pointdealloc() Deallocate space for a point, marking it dead. */ +/* */ +/*****************************************************************************/ + +void pointdealloc(dyingpoint) +point dyingpoint; +{ + /* Mark the point as dead. This makes it possible to detect dead points */ + /* when traversing the list of all points. */ + setpointmark(dyingpoint, DEADPOINT); + pooldealloc(&points, (VOID *) dyingpoint); +} + +/*****************************************************************************/ +/* */ +/* pointtraverse() Traverse the points, skipping dead ones. */ +/* */ +/*****************************************************************************/ + +point pointtraverse() +{ + point newpoint; + + do { + newpoint = (point) traverse(&points); + if (newpoint == (point) NULL) { + return (point) NULL; + } + } while (pointmark(newpoint) == DEADPOINT); /* Skip dead ones. */ + return newpoint; +} + +/*****************************************************************************/ +/* */ +/* badsegmentdealloc() Deallocate space for a bad segment, marking it */ +/* dead. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void badsegmentdealloc(dyingseg) +struct edge *dyingseg; +{ + /* Set segment's orientation to -1. This makes it possible to */ + /* detect dead segments when traversing the list of all segments. */ + dyingseg->shorient = -1; + pooldealloc(&badsegments, (VOID *) dyingseg); +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* badsegmenttraverse() Traverse the bad segments, skipping dead ones. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +struct edge *badsegmenttraverse() +{ + struct edge *newseg; + + do { + newseg = (struct edge *) traverse(&badsegments); + if (newseg == (struct edge *) NULL) { + return (struct edge *) NULL; + } + } while (newseg->shorient == -1); /* Skip dead ones. */ + return newseg; +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* getpoint() Get a specific point, by number, from the list. */ +/* */ +/* The first point is number 'firstnumber'. */ +/* */ +/* Note that this takes O(n) time (with a small constant, if POINTPERBLOCK */ +/* is large). I don't care to take the trouble to make it work in constant */ +/* time. */ +/* */ +/*****************************************************************************/ + +point getpoint(number) +int number; +{ + VOID **getblock; + point foundpoint; + unsigned long alignptr; + int current; + + getblock = points.firstblock; + current = firstnumber; + /* Find the right block. */ + while (current + points.itemsperblock <= number) { + getblock = (VOID **) *getblock; + current += points.itemsperblock; + } + /* Now find the right point. */ + alignptr = (unsigned long) (getblock + 1); + foundpoint = (point) (alignptr + (unsigned long) points.alignbytes + - (alignptr % (unsigned long) points.alignbytes)); + while (current < number) { + foundpoint += points.itemwords; + current++; + } + return foundpoint; +} + +/*****************************************************************************/ +/* */ +/* triangledeinit() Free all remaining allocated memory. */ +/* */ +/*****************************************************************************/ + +void triangledeinit() +{ + pooldeinit(&triangles); + free(dummytribase); + if (useshelles) { + pooldeinit(&shelles); + free(dummyshbase); + } + pooldeinit(&points); +#ifndef CDT_ONLY + if (quality) { + pooldeinit(&badsegments); + if ((minangle > 0.0) || vararea || fixedarea) { + pooldeinit(&badtriangles); + } + } +#endif /* not CDT_ONLY */ +} + +/** **/ +/** **/ +/********* Memory management routines end here *********/ + +/********* Constructors begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* maketriangle() Create a new triangle with orientation zero. */ +/* */ +/*****************************************************************************/ + +void maketriangle(newtriedge) +struct triedge *newtriedge; +{ + int i; + + newtriedge->tri = (triangle *) poolalloc(&triangles); + /* Initialize the three adjoining triangles to be "outer space". */ + newtriedge->tri[0] = (triangle) dummytri; + newtriedge->tri[1] = (triangle) dummytri; + newtriedge->tri[2] = (triangle) dummytri; + /* Three NULL vertex points. */ + newtriedge->tri[3] = (triangle) NULL; + newtriedge->tri[4] = (triangle) NULL; + newtriedge->tri[5] = (triangle) NULL; + /* Initialize the three adjoining shell edges to be the omnipresent */ + /* shell edge. */ + if (useshelles) { + newtriedge->tri[6] = (triangle) dummysh; + newtriedge->tri[7] = (triangle) dummysh; + newtriedge->tri[8] = (triangle) dummysh; + } + for (i = 0; i < eextras; i++) { + setelemattribute(*newtriedge, i, 0.0); + } + if (vararea) { + setareabound(*newtriedge, -1.0); + } + + newtriedge->orient = 0; +} + +/*****************************************************************************/ +/* */ +/* makeshelle() Create a new shell edge with orientation zero. */ +/* */ +/*****************************************************************************/ + +void makeshelle(newedge) +struct edge *newedge; +{ + newedge->sh = (shelle *) poolalloc(&shelles); + /* Initialize the two adjoining shell edges to be the omnipresent */ + /* shell edge. */ + newedge->sh[0] = (shelle) dummysh; + newedge->sh[1] = (shelle) dummysh; + /* Two NULL vertex points. */ + newedge->sh[2] = (shelle) NULL; + newedge->sh[3] = (shelle) NULL; + /* Initialize the two adjoining triangles to be "outer space". */ + newedge->sh[4] = (shelle) dummytri; + newedge->sh[5] = (shelle) dummytri; + /* Set the boundary marker to zero. */ + setmark(*newedge, 0); + + newedge->shorient = 0; +} + +/** **/ +/** **/ +/********* Constructors end here *********/ + +/********* Determinant evaluation routines begin here *********/ +/** **/ +/** **/ + +/* The adaptive exact arithmetic geometric predicates implemented herein are */ +/* described in detail in my Technical Report CMU-CS-96-140. The complete */ +/* reference is given in the header. */ + +/* Which of the following two methods of finding the absolute values is */ +/* fastest is compiler-dependent. A few compilers can inline and optimize */ +/* the fabs() call; but most will incur the overhead of a function call, */ +/* which is disastrously slow. A faster way on IEEE machines might be to */ +/* mask the appropriate bit, but that's difficult to do in C. */ + +#define Absolute(a) ((a) >= 0.0 ? (a) : -(a)) +/* #define Absolute(a) fabs(a) */ + +/* Many of the operations are broken up into two pieces, a main part that */ +/* performs an approximate operation, and a "tail" that computes the */ +/* roundoff error of that operation. */ +/* */ +/* The operations Fast_Two_Sum(), Fast_Two_Diff(), Two_Sum(), Two_Diff(), */ +/* Split(), and Two_Product() are all implemented as described in the */ +/* reference. Each of these macros requires certain variables to be */ +/* defined in the calling routine. The variables `bvirt', `c', `abig', */ +/* `_i', `_j', `_k', `_l', `_m', and `_n' are declared `INEXACT' because */ +/* they store the result of an operation that may incur roundoff error. */ +/* The input parameter `x' (or the highest numbered `x_' parameter) must */ +/* also be declared `INEXACT'. */ + +#define Fast_Two_Sum_Tail(a, b, x, y) \ + bvirt = x - a; \ + y = b - bvirt + +#define Fast_Two_Sum(a, b, x, y) \ + x = (REAL) (a + b); \ + Fast_Two_Sum_Tail(a, b, x, y) + +#define Two_Sum_Tail(a, b, x, y) \ + bvirt = (REAL) (x - a); \ + avirt = x - bvirt; \ + bround = b - bvirt; \ + around = a - avirt; \ + y = around + bround + +#define Two_Sum(a, b, x, y) \ + x = (REAL) (a + b); \ + Two_Sum_Tail(a, b, x, y) + +#define Two_Diff_Tail(a, b, x, y) \ + bvirt = (REAL) (a - x); \ + avirt = x + bvirt; \ + bround = bvirt - b; \ + around = a - avirt; \ + y = around + bround + +#define Two_Diff(a, b, x, y) \ + x = (REAL) (a - b); \ + Two_Diff_Tail(a, b, x, y) + +#define Split(a, ahi, alo) \ + c = (REAL) (splitter * a); \ + abig = (REAL) (c - a); \ + ahi = (REAL)(c - abig); \ + alo = (REAL)(a - ahi) + +#define Two_Product_Tail(a, b, x, y) \ + Split(a, ahi, alo); \ + Split(b, bhi, blo); \ + err1 = x - (ahi * bhi); \ + err2 = err1 - (alo * bhi); \ + err3 = err2 - (ahi * blo); \ + y = (alo * blo) - err3 + +#define Two_Product(a, b, x, y) \ + x = (REAL) (a * b); \ + Two_Product_Tail(a, b, x, y) + +/* Two_Product_Presplit() is Two_Product() where one of the inputs has */ +/* already been split. Avoids redundant splitting. */ + +#define Two_Product_Presplit(a, b, bhi, blo, x, y) \ + x = (REAL) (a * b); \ + Split(a, ahi, alo); \ + err1 = x - (ahi * bhi); \ + err2 = err1 - (alo * bhi); \ + err3 = err2 - (ahi * blo); \ + y = (alo * blo) - err3 + +/* Square() can be done more quickly than Two_Product(). */ + +#define Square_Tail(a, x, y) \ + Split(a, ahi, alo); \ + err1 = x - (ahi * ahi); \ + err3 = err1 - ((ahi + ahi) * alo); \ + y = (alo * alo) - err3 + +#define Square(a, x, y) \ + x = (REAL) (a * a); \ + Square_Tail(a, x, y) + +/* Macros for summing expansions of various fixed lengths. These are all */ +/* unrolled versions of Expansion_Sum(). */ + +#define Two_One_Sum(a1, a0, b, x2, x1, x0) \ + Two_Sum(a0, b , _i, x0); \ + Two_Sum(a1, _i, x2, x1) + +#define Two_One_Diff(a1, a0, b, x2, x1, x0) \ + Two_Diff(a0, b , _i, x0); \ + Two_Sum( a1, _i, x2, x1) + +#define Two_Two_Sum(a1, a0, b1, b0, x3, x2, x1, x0) \ + Two_One_Sum(a1, a0, b0, _j, _0, x0); \ + Two_One_Sum(_j, _0, b1, x3, x2, x1) + +#define Two_Two_Diff(a1, a0, b1, b0, x3, x2, x1, x0) \ + Two_One_Diff(a1, a0, b0, _j, _0, x0); \ + Two_One_Diff(_j, _0, b1, x3, x2, x1) + +/*****************************************************************************/ +/* */ +/* exactinit() Initialize the variables used for exact arithmetic. */ +/* */ +/* `epsilon' is the largest power of two such that 1.0 + epsilon = 1.0 in */ +/* floating-point arithmetic. `epsilon' bounds the relative roundoff */ +/* error. It is used for floating-point error analysis. */ +/* */ +/* `splitter' is used to split floating-point numbers into two half- */ +/* length significands for exact multiplication. */ +/* */ +/* I imagine that a highly optimizing compiler might be too smart for its */ +/* own good, and somehow cause this routine to fail, if it pretends that */ +/* floating-point arithmetic is too much like real arithmetic. */ +/* */ +/* Don't change this routine unless you fully understand it. */ +/* */ +/*****************************************************************************/ + +void exactinit() +{ + REAL half; + REAL check, lastcheck; + int every_other; + + every_other = 1; + half = 0.5; + epsilon = 1.0; + splitter = 1.0; + check = 1.0; + /* Repeatedly divide `epsilon' by two until it is too small to add to */ + /* one without causing roundoff. (Also check if the sum is equal to */ + /* the previous sum, for machines that round up instead of using exact */ + /* rounding. Not that these routines will work on such machines anyway. */ + do { + lastcheck = check; + epsilon *= half; + if (every_other) { + splitter *= 2.0; + } + every_other = !every_other; + check = (REAL)(1.0 + epsilon); + } while ((check != 1.0) && (check != lastcheck)); + splitter += 1.0; + if (verbose > 1) { + printf("Floating point roundoff is of magnitude %.17g\n", epsilon); + printf("Floating point splitter is %.17g\n", splitter); + } + /* Error bounds for orientation and incircle tests. */ + resulterrbound = (REAL)((3.0 + 8.0 * epsilon) * epsilon); + ccwerrboundA = (REAL)((3.0 + 16.0 * epsilon) * epsilon); + ccwerrboundB = (REAL)((2.0 + 12.0 * epsilon) * epsilon); + ccwerrboundC = (REAL)((9.0 + 64.0 * epsilon) * epsilon * epsilon); + iccerrboundA = (REAL)((10.0 + 96.0 * epsilon) * epsilon); + iccerrboundB = (REAL)((4.0 + 48.0 * epsilon) * epsilon); + iccerrboundC = (REAL)((44.0 + 576.0 * epsilon) * epsilon * epsilon); +} + +/*****************************************************************************/ +/* */ +/* fast_expansion_sum_zeroelim() Sum two expansions, eliminating zero */ +/* components from the output expansion. */ +/* */ +/* Sets h = e + f. See my Robust Predicates paper for details. */ +/* */ +/* If round-to-even is used (as with IEEE 754), maintains the strongly */ +/* nonoverlapping property. (That is, if e is strongly nonoverlapping, h */ +/* will be also.) Does NOT maintain the nonoverlapping or nonadjacent */ +/* properties. */ +/* */ +/*****************************************************************************/ + +int fast_expansion_sum_zeroelim(elen, e, flen, f, h) /* h cannot be e or f. */ +int elen; +REAL *e; +int flen; +REAL *f; +REAL *h; +{ + REAL Q; + INEXACT REAL Qnew; + INEXACT REAL hh; + INEXACT REAL bvirt; + REAL avirt, bround, around; + int eindex, findex, hindex; + REAL enow, fnow; + + enow = e[0]; + fnow = f[0]; + eindex = findex = 0; + if ((fnow > enow) == (fnow > -enow)) { + Q = enow; + enow = e[++eindex]; + } else { + Q = fnow; + fnow = f[++findex]; + } + hindex = 0; + if ((eindex < elen) && (findex < flen)) { + if ((fnow > enow) == (fnow > -enow)) { + Fast_Two_Sum(enow, Q, Qnew, hh); + enow = e[++eindex]; + } else { + Fast_Two_Sum(fnow, Q, Qnew, hh); + fnow = f[++findex]; + } + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + while ((eindex < elen) && (findex < flen)) { + if ((fnow > enow) == (fnow > -enow)) { + Two_Sum(Q, enow, Qnew, hh); + enow = e[++eindex]; + } else { + Two_Sum(Q, fnow, Qnew, hh); + fnow = f[++findex]; + } + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + } + while (eindex < elen) { + Two_Sum(Q, enow, Qnew, hh); + enow = e[++eindex]; + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + while (findex < flen) { + Two_Sum(Q, fnow, Qnew, hh); + fnow = f[++findex]; + Q = Qnew; + if (hh != 0.0) { + h[hindex++] = hh; + } + } + if ((Q != 0.0) || (hindex == 0)) { + h[hindex++] = Q; + } + return hindex; +} + +/*****************************************************************************/ +/* */ +/* scale_expansion_zeroelim() Multiply an expansion by a scalar, */ +/* eliminating zero components from the */ +/* output expansion. */ +/* */ +/* Sets h = be. See my Robust Predicates paper for details. */ +/* */ +/* Maintains the nonoverlapping property. If round-to-even is used (as */ +/* with IEEE 754), maintains the strongly nonoverlapping and nonadjacent */ +/* properties as well. (That is, if e has one of these properties, so */ +/* will h.) */ +/* */ +/*****************************************************************************/ + +int scale_expansion_zeroelim(elen, e, b, h) /* e and h cannot be the same. */ +int elen; +REAL *e; +REAL b; +REAL *h; +{ + INEXACT REAL Q, sum; + REAL hh; + INEXACT REAL product1; + REAL product0; + int eindex, hindex; + REAL enow; + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + + Split(b, bhi, blo); + Two_Product_Presplit(e[0], b, bhi, blo, Q, hh); + hindex = 0; + if (hh != 0) { + h[hindex++] = hh; + } + for (eindex = 1; eindex < elen; eindex++) { + enow = e[eindex]; + Two_Product_Presplit(enow, b, bhi, blo, product1, product0); + Two_Sum(Q, product0, sum, hh); + if (hh != 0) { + h[hindex++] = hh; + } + Fast_Two_Sum(product1, sum, Q, hh); + if (hh != 0) { + h[hindex++] = hh; + } + } + if ((Q != 0.0) || (hindex == 0)) { + h[hindex++] = Q; + } + return hindex; +} + +/*****************************************************************************/ +/* */ +/* estimate() Produce a one-word estimate of an expansion's value. */ +/* */ +/* See my Robust Predicates paper for details. */ +/* */ +/*****************************************************************************/ + +REAL estimate(elen, e) +int elen; +REAL *e; +{ + REAL Q; + int eindex; + + Q = e[0]; + for (eindex = 1; eindex < elen; eindex++) { + Q += e[eindex]; + } + return Q; +} + +/*****************************************************************************/ +/* */ +/* counterclockwise() Return a positive value if the points pa, pb, and */ +/* pc occur in counterclockwise order; a negative */ +/* value if they occur in clockwise order; and zero */ +/* if they are collinear. The result is also a rough */ +/* approximation of twice the signed area of the */ +/* triangle defined by the three points. */ +/* */ +/* Uses exact arithmetic if necessary to ensure a correct answer. The */ +/* result returned is the determinant of a matrix. This determinant is */ +/* computed adaptively, in the sense that exact arithmetic is used only to */ +/* the degree it is needed to ensure that the returned value has the */ +/* correct sign. Hence, this function is usually quite fast, but will run */ +/* more slowly when the input points are collinear or nearly so. */ +/* */ +/* See my Robust Predicates paper for details. */ +/* */ +/*****************************************************************************/ + +REAL counterclockwiseadapt(pa, pb, pc, detsum) +point pa; +point pb; +point pc; +REAL detsum; +{ + INEXACT REAL acx, acy, bcx, bcy; + REAL acxtail, acytail, bcxtail, bcytail; + INEXACT REAL detleft, detright; + REAL detlefttail, detrighttail; + REAL det, errbound; + REAL B[4], C1[8], C2[12], D[16]; + INEXACT REAL B3; + int C1length, C2length, Dlength; + REAL u[4]; + INEXACT REAL u3; + INEXACT REAL s1, t1; + REAL s0, t0; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j; + REAL _0; + + acx = (REAL) (pa[0] - pc[0]); + bcx = (REAL) (pb[0] - pc[0]); + acy = (REAL) (pa[1] - pc[1]); + bcy = (REAL) (pb[1] - pc[1]); + + Two_Product(acx, bcy, detleft, detlefttail); + Two_Product(acy, bcx, detright, detrighttail); + + Two_Two_Diff(detleft, detlefttail, detright, detrighttail, + B3, B[2], B[1], B[0]); + B[3] = B3; + + det = estimate(4, B); + errbound = (REAL)(ccwerrboundB * detsum); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Diff_Tail(pa[0], pc[0], acx, acxtail); + Two_Diff_Tail(pb[0], pc[0], bcx, bcxtail); + Two_Diff_Tail(pa[1], pc[1], acy, acytail); + Two_Diff_Tail(pb[1], pc[1], bcy, bcytail); + + if ((acxtail == 0.0) && (acytail == 0.0) + && (bcxtail == 0.0) && (bcytail == 0.0)) { + return det; + } + + errbound = (REAL)(ccwerrboundC * detsum + resulterrbound * Absolute(det)); + det += (acx * bcytail + bcy * acxtail) + - (acy * bcxtail + bcx * acytail); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Product(acxtail, bcy, s1, s0); + Two_Product(acytail, bcx, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + C1length = fast_expansion_sum_zeroelim(4, B, 4, u, C1); + + Two_Product(acx, bcytail, s1, s0); + Two_Product(acy, bcxtail, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + C2length = fast_expansion_sum_zeroelim(C1length, C1, 4, u, C2); + + Two_Product(acxtail, bcytail, s1, s0); + Two_Product(acytail, bcxtail, t1, t0); + Two_Two_Diff(s1, s0, t1, t0, u3, u[2], u[1], u[0]); + u[3] = u3; + Dlength = fast_expansion_sum_zeroelim(C2length, C2, 4, u, D); + + return(D[Dlength - 1]); +} + +REAL counterclockwise(pa, pb, pc) +point pa; +point pb; +point pc; +{ + REAL detleft, detright, det; + REAL detsum, errbound; + + counterclockcount++; + + detleft = (pa[0] - pc[0]) * (pb[1] - pc[1]); + detright = (pa[1] - pc[1]) * (pb[0] - pc[0]); + det = detleft - detright; + + if (noexact) { + return det; + } + + if (detleft > 0.0) { + if (detright <= 0.0) { + return det; + } else { + detsum = detleft + detright; + } + } else if (detleft < 0.0) { + if (detright >= 0.0) { + return det; + } else { + detsum = -detleft - detright; + } + } else { + return det; + } + + errbound = ccwerrboundA * detsum; + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + return counterclockwiseadapt(pa, pb, pc, detsum); +} + +/*****************************************************************************/ +/* */ +/* incircle() Return a positive value if the point pd lies inside the */ +/* circle passing through pa, pb, and pc; a negative value if */ +/* it lies outside; and zero if the four points are cocircular.*/ +/* The points pa, pb, and pc must be in counterclockwise */ +/* order, or the sign of the result will be reversed. */ +/* */ +/* Uses exact arithmetic if necessary to ensure a correct answer. The */ +/* result returned is the determinant of a matrix. This determinant is */ +/* computed adaptively, in the sense that exact arithmetic is used only to */ +/* the degree it is needed to ensure that the returned value has the */ +/* correct sign. Hence, this function is usually quite fast, but will run */ +/* more slowly when the input points are cocircular or nearly so. */ +/* */ +/* See my Robust Predicates paper for details. */ +/* */ +/*****************************************************************************/ + +REAL incircleadapt(pa, pb, pc, pd, permanent) +point pa; +point pb; +point pc; +point pd; +REAL permanent; +{ + INEXACT REAL adx, bdx, cdx, ady, bdy, cdy; + REAL det, errbound; + + INEXACT REAL bdxcdy1, cdxbdy1, cdxady1, adxcdy1, adxbdy1, bdxady1; + REAL bdxcdy0, cdxbdy0, cdxady0, adxcdy0, adxbdy0, bdxady0; + REAL bc[4], ca[4], ab[4]; + INEXACT REAL bc3, ca3, ab3; + REAL axbc[8], axxbc[16], aybc[8], ayybc[16], adet[32]; + int axbclen, axxbclen, aybclen, ayybclen, alen; + REAL bxca[8], bxxca[16], byca[8], byyca[16], bdet[32]; + int bxcalen, bxxcalen, bycalen, byycalen, blen; + REAL cxab[8], cxxab[16], cyab[8], cyyab[16], cdet[32]; + int cxablen, cxxablen, cyablen, cyyablen, clen; + REAL abdet[64]; + int ablen; + REAL fin1[1152], fin2[1152]; + REAL *finnow, *finother, *finswap; + int finlength; + + REAL adxtail, bdxtail, cdxtail, adytail, bdytail, cdytail; + INEXACT REAL adxadx1, adyady1, bdxbdx1, bdybdy1, cdxcdx1, cdycdy1; + REAL adxadx0, adyady0, bdxbdx0, bdybdy0, cdxcdx0, cdycdy0; + REAL aa[4], bb[4], cc[4]; + INEXACT REAL aa3, bb3, cc3; + INEXACT REAL ti1, tj1; + REAL ti0, tj0; + REAL u[4], v[4]; + INEXACT REAL u3, v3; + REAL temp8[8], temp16a[16], temp16b[16], temp16c[16]; + REAL temp32a[32], temp32b[32], temp48[48], temp64[64]; + int temp8len, temp16alen, temp16blen, temp16clen; + int temp32alen, temp32blen, temp48len, temp64len; + REAL axtbb[8], axtcc[8], aytbb[8], aytcc[8]; + int axtbblen, axtcclen, aytbblen, aytcclen; + REAL bxtaa[8], bxtcc[8], bytaa[8], bytcc[8]; + int bxtaalen, bxtcclen, bytaalen, bytcclen; + REAL cxtaa[8], cxtbb[8], cytaa[8], cytbb[8]; + int cxtaalen, cxtbblen, cytaalen, cytbblen; + REAL axtbc[8], aytbc[8], bxtca[8], bytca[8], cxtab[8], cytab[8]; + int axtbclen, aytbclen, bxtcalen, bytcalen, cxtablen, cytablen; + REAL axtbct[16], aytbct[16], bxtcat[16], bytcat[16], cxtabt[16], cytabt[16]; + int axtbctlen, aytbctlen, bxtcatlen, bytcatlen, cxtabtlen, cytabtlen; + REAL axtbctt[8], aytbctt[8], bxtcatt[8]; + REAL bytcatt[8], cxtabtt[8], cytabtt[8]; + int axtbcttlen, aytbcttlen, bxtcattlen, bytcattlen, cxtabttlen, cytabttlen; + REAL abt[8], bct[8], cat[8]; + int abtlen, bctlen, catlen; + REAL abtt[4], bctt[4], catt[4]; + int abttlen, bcttlen, cattlen; + INEXACT REAL abtt3, bctt3, catt3; + REAL negate; + + INEXACT REAL bvirt; + REAL avirt, bround, around; + INEXACT REAL c; + INEXACT REAL abig; + REAL ahi, alo, bhi, blo; + REAL err1, err2, err3; + INEXACT REAL _i, _j; + REAL _0; + + adx = (REAL) (pa[0] - pd[0]); + bdx = (REAL) (pb[0] - pd[0]); + cdx = (REAL) (pc[0] - pd[0]); + ady = (REAL) (pa[1] - pd[1]); + bdy = (REAL) (pb[1] - pd[1]); + cdy = (REAL) (pc[1] - pd[1]); + + Two_Product(bdx, cdy, bdxcdy1, bdxcdy0); + Two_Product(cdx, bdy, cdxbdy1, cdxbdy0); + Two_Two_Diff(bdxcdy1, bdxcdy0, cdxbdy1, cdxbdy0, bc3, bc[2], bc[1], bc[0]); + bc[3] = bc3; + axbclen = scale_expansion_zeroelim(4, bc, adx, axbc); + axxbclen = scale_expansion_zeroelim(axbclen, axbc, adx, axxbc); + aybclen = scale_expansion_zeroelim(4, bc, ady, aybc); + ayybclen = scale_expansion_zeroelim(aybclen, aybc, ady, ayybc); + alen = fast_expansion_sum_zeroelim(axxbclen, axxbc, ayybclen, ayybc, adet); + + Two_Product(cdx, ady, cdxady1, cdxady0); + Two_Product(adx, cdy, adxcdy1, adxcdy0); + Two_Two_Diff(cdxady1, cdxady0, adxcdy1, adxcdy0, ca3, ca[2], ca[1], ca[0]); + ca[3] = ca3; + bxcalen = scale_expansion_zeroelim(4, ca, bdx, bxca); + bxxcalen = scale_expansion_zeroelim(bxcalen, bxca, bdx, bxxca); + bycalen = scale_expansion_zeroelim(4, ca, bdy, byca); + byycalen = scale_expansion_zeroelim(bycalen, byca, bdy, byyca); + blen = fast_expansion_sum_zeroelim(bxxcalen, bxxca, byycalen, byyca, bdet); + + Two_Product(adx, bdy, adxbdy1, adxbdy0); + Two_Product(bdx, ady, bdxady1, bdxady0); + Two_Two_Diff(adxbdy1, adxbdy0, bdxady1, bdxady0, ab3, ab[2], ab[1], ab[0]); + ab[3] = ab3; + cxablen = scale_expansion_zeroelim(4, ab, cdx, cxab); + cxxablen = scale_expansion_zeroelim(cxablen, cxab, cdx, cxxab); + cyablen = scale_expansion_zeroelim(4, ab, cdy, cyab); + cyyablen = scale_expansion_zeroelim(cyablen, cyab, cdy, cyyab); + clen = fast_expansion_sum_zeroelim(cxxablen, cxxab, cyyablen, cyyab, cdet); + + ablen = fast_expansion_sum_zeroelim(alen, adet, blen, bdet, abdet); + finlength = fast_expansion_sum_zeroelim(ablen, abdet, clen, cdet, fin1); + + det = estimate(finlength, fin1); + errbound = (REAL)(iccerrboundB * permanent); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + Two_Diff_Tail(pa[0], pd[0], adx, adxtail); + Two_Diff_Tail(pa[1], pd[1], ady, adytail); + Two_Diff_Tail(pb[0], pd[0], bdx, bdxtail); + Two_Diff_Tail(pb[1], pd[1], bdy, bdytail); + Two_Diff_Tail(pc[0], pd[0], cdx, cdxtail); + Two_Diff_Tail(pc[1], pd[1], cdy, cdytail); + if ((adxtail == 0.0) && (bdxtail == 0.0) && (cdxtail == 0.0) + && (adytail == 0.0) && (bdytail == 0.0) && (cdytail == 0.0)) { + return det; + } + + errbound = (REAL)(iccerrboundC * permanent + resulterrbound * Absolute(det)); + det += (REAL)(((adx * adx + ady * ady) * ((bdx * cdytail + cdy * bdxtail) + - (bdy * cdxtail + cdx * bdytail)) + + 2.0 * (adx * adxtail + ady * adytail) * (bdx * cdy - bdy * cdx)) + + ((bdx * bdx + bdy * bdy) * ((cdx * adytail + ady * cdxtail) + - (cdy * adxtail + adx * cdytail)) + + 2.0 * (bdx * bdxtail + bdy * bdytail) * (cdx * ady - cdy * adx)) + + ((cdx * cdx + cdy * cdy) * ((adx * bdytail + bdy * adxtail) + - (ady * bdxtail + bdx * adytail)) + + 2.0 * (cdx * cdxtail + cdy * cdytail) * (adx * bdy - ady * bdx))); + if ((det >= errbound) || (-det >= errbound)) { + return det; + } + + finnow = fin1; + finother = fin2; + + if ((bdxtail != 0.0) || (bdytail != 0.0) + || (cdxtail != 0.0) || (cdytail != 0.0)) { + Square(adx, adxadx1, adxadx0); + Square(ady, adyady1, adyady0); + Two_Two_Sum(adxadx1, adxadx0, adyady1, adyady0, aa3, aa[2], aa[1], aa[0]); + aa[3] = aa3; + } + if ((cdxtail != 0.0) || (cdytail != 0.0) + || (adxtail != 0.0) || (adytail != 0.0)) { + Square(bdx, bdxbdx1, bdxbdx0); + Square(bdy, bdybdy1, bdybdy0); + Two_Two_Sum(bdxbdx1, bdxbdx0, bdybdy1, bdybdy0, bb3, bb[2], bb[1], bb[0]); + bb[3] = bb3; + } + if ((adxtail != 0.0) || (adytail != 0.0) + || (bdxtail != 0.0) || (bdytail != 0.0)) { + Square(cdx, cdxcdx1, cdxcdx0); + Square(cdy, cdycdy1, cdycdy0); + Two_Two_Sum(cdxcdx1, cdxcdx0, cdycdy1, cdycdy0, cc3, cc[2], cc[1], cc[0]); + cc[3] = cc3; + } + + if (adxtail != 0.0) { + axtbclen = scale_expansion_zeroelim(4, bc, adxtail, axtbc); + temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, 2.0 * adx, + temp16a); + + axtcclen = scale_expansion_zeroelim(4, cc, adxtail, axtcc); + temp16blen = scale_expansion_zeroelim(axtcclen, axtcc, bdy, temp16b); + + axtbblen = scale_expansion_zeroelim(4, bb, adxtail, axtbb); + temp16clen = scale_expansion_zeroelim(axtbblen, axtbb, -cdy, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (adytail != 0.0) { + aytbclen = scale_expansion_zeroelim(4, bc, adytail, aytbc); + temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, 2.0 * ady, + temp16a); + + aytbblen = scale_expansion_zeroelim(4, bb, adytail, aytbb); + temp16blen = scale_expansion_zeroelim(aytbblen, aytbb, cdx, temp16b); + + aytcclen = scale_expansion_zeroelim(4, cc, adytail, aytcc); + temp16clen = scale_expansion_zeroelim(aytcclen, aytcc, -bdx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdxtail != 0.0) { + bxtcalen = scale_expansion_zeroelim(4, ca, bdxtail, bxtca); + temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, 2.0 * bdx, + temp16a); + + bxtaalen = scale_expansion_zeroelim(4, aa, bdxtail, bxtaa); + temp16blen = scale_expansion_zeroelim(bxtaalen, bxtaa, cdy, temp16b); + + bxtcclen = scale_expansion_zeroelim(4, cc, bdxtail, bxtcc); + temp16clen = scale_expansion_zeroelim(bxtcclen, bxtcc, -ady, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdytail != 0.0) { + bytcalen = scale_expansion_zeroelim(4, ca, bdytail, bytca); + temp16alen = scale_expansion_zeroelim(bytcalen, bytca, 2.0 * bdy, + temp16a); + + bytcclen = scale_expansion_zeroelim(4, cc, bdytail, bytcc); + temp16blen = scale_expansion_zeroelim(bytcclen, bytcc, adx, temp16b); + + bytaalen = scale_expansion_zeroelim(4, aa, bdytail, bytaa); + temp16clen = scale_expansion_zeroelim(bytaalen, bytaa, -cdx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdxtail != 0.0) { + cxtablen = scale_expansion_zeroelim(4, ab, cdxtail, cxtab); + temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, 2.0 * cdx, + temp16a); + + cxtbblen = scale_expansion_zeroelim(4, bb, cdxtail, cxtbb); + temp16blen = scale_expansion_zeroelim(cxtbblen, cxtbb, ady, temp16b); + + cxtaalen = scale_expansion_zeroelim(4, aa, cdxtail, cxtaa); + temp16clen = scale_expansion_zeroelim(cxtaalen, cxtaa, -bdy, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdytail != 0.0) { + cytablen = scale_expansion_zeroelim(4, ab, cdytail, cytab); + temp16alen = scale_expansion_zeroelim(cytablen, cytab, 2.0 * cdy, + temp16a); + + cytaalen = scale_expansion_zeroelim(4, aa, cdytail, cytaa); + temp16blen = scale_expansion_zeroelim(cytaalen, cytaa, bdx, temp16b); + + cytbblen = scale_expansion_zeroelim(4, bb, cdytail, cytbb); + temp16clen = scale_expansion_zeroelim(cytbblen, cytbb, -adx, temp16c); + + temp32alen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16clen, temp16c, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + if ((adxtail != 0.0) || (adytail != 0.0)) { + if ((bdxtail != 0.0) || (bdytail != 0.0) + || (cdxtail != 0.0) || (cdytail != 0.0)) { + Two_Product(bdxtail, cdy, ti1, ti0); + Two_Product(bdx, cdytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -bdy; + Two_Product(cdxtail, negate, ti1, ti0); + negate = -bdytail; + Two_Product(cdx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + bctlen = fast_expansion_sum_zeroelim(4, u, 4, v, bct); + + Two_Product(bdxtail, cdytail, ti1, ti0); + Two_Product(cdxtail, bdytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, bctt3, bctt[2], bctt[1], bctt[0]); + bctt[3] = bctt3; + bcttlen = 4; + } else { + bct[0] = 0.0; + bctlen = 1; + bctt[0] = 0.0; + bcttlen = 1; + } + + if (adxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(axtbclen, axtbc, adxtail, temp16a); + axtbctlen = scale_expansion_zeroelim(bctlen, bct, adxtail, axtbct); + temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, 2.0 * adx, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + if (bdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, cc, adxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, bb, -adxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(axtbctlen, axtbct, adxtail, + temp32a); + axtbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adxtail, axtbctt); + temp16alen = scale_expansion_zeroelim(axtbcttlen, axtbctt, 2.0 * adx, + temp16a); + temp16blen = scale_expansion_zeroelim(axtbcttlen, axtbctt, adxtail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (adytail != 0.0) { + temp16alen = scale_expansion_zeroelim(aytbclen, aytbc, adytail, temp16a); + aytbctlen = scale_expansion_zeroelim(bctlen, bct, adytail, aytbct); + temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, 2.0 * ady, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + + + temp32alen = scale_expansion_zeroelim(aytbctlen, aytbct, adytail, + temp32a); + aytbcttlen = scale_expansion_zeroelim(bcttlen, bctt, adytail, aytbctt); + temp16alen = scale_expansion_zeroelim(aytbcttlen, aytbctt, 2.0 * ady, + temp16a); + temp16blen = scale_expansion_zeroelim(aytbcttlen, aytbctt, adytail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if ((bdxtail != 0.0) || (bdytail != 0.0)) { + if ((cdxtail != 0.0) || (cdytail != 0.0) + || (adxtail != 0.0) || (adytail != 0.0)) { + Two_Product(cdxtail, ady, ti1, ti0); + Two_Product(cdx, adytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -cdy; + Two_Product(adxtail, negate, ti1, ti0); + negate = -cdytail; + Two_Product(adx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + catlen = fast_expansion_sum_zeroelim(4, u, 4, v, cat); + + Two_Product(cdxtail, adytail, ti1, ti0); + Two_Product(adxtail, cdytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, catt3, catt[2], catt[1], catt[0]); + catt[3] = catt3; + cattlen = 4; + } else { + cat[0] = 0.0; + catlen = 1; + catt[0] = 0.0; + cattlen = 1; + } + + if (bdxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(bxtcalen, bxtca, bdxtail, temp16a); + bxtcatlen = scale_expansion_zeroelim(catlen, cat, bdxtail, bxtcat); + temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, 2.0 * bdx, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + if (cdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, aa, bdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, cdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (adytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, cc, -bdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(bxtcatlen, bxtcat, bdxtail, + temp32a); + bxtcattlen = scale_expansion_zeroelim(cattlen, catt, bdxtail, bxtcatt); + temp16alen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, 2.0 * bdx, + temp16a); + temp16blen = scale_expansion_zeroelim(bxtcattlen, bxtcatt, bdxtail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdytail != 0.0) { + temp16alen = scale_expansion_zeroelim(bytcalen, bytca, bdytail, temp16a); + bytcatlen = scale_expansion_zeroelim(catlen, cat, bdytail, bytcat); + temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, 2.0 * bdy, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + + + temp32alen = scale_expansion_zeroelim(bytcatlen, bytcat, bdytail, + temp32a); + bytcattlen = scale_expansion_zeroelim(cattlen, catt, bdytail, bytcatt); + temp16alen = scale_expansion_zeroelim(bytcattlen, bytcatt, 2.0 * bdy, + temp16a); + temp16blen = scale_expansion_zeroelim(bytcattlen, bytcatt, bdytail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + if ((cdxtail != 0.0) || (cdytail != 0.0)) { + if ((adxtail != 0.0) || (adytail != 0.0) + || (bdxtail != 0.0) || (bdytail != 0.0)) { + Two_Product(adxtail, bdy, ti1, ti0); + Two_Product(adx, bdytail, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, u3, u[2], u[1], u[0]); + u[3] = u3; + negate = -ady; + Two_Product(bdxtail, negate, ti1, ti0); + negate = -adytail; + Two_Product(bdx, negate, tj1, tj0); + Two_Two_Sum(ti1, ti0, tj1, tj0, v3, v[2], v[1], v[0]); + v[3] = v3; + abtlen = fast_expansion_sum_zeroelim(4, u, 4, v, abt); + + Two_Product(adxtail, bdytail, ti1, ti0); + Two_Product(bdxtail, adytail, tj1, tj0); + Two_Two_Diff(ti1, ti0, tj1, tj0, abtt3, abtt[2], abtt[1], abtt[0]); + abtt[3] = abtt3; + abttlen = 4; + } else { + abt[0] = 0.0; + abtlen = 1; + abtt[0] = 0.0; + abttlen = 1; + } + + if (cdxtail != 0.0) { + temp16alen = scale_expansion_zeroelim(cxtablen, cxtab, cdxtail, temp16a); + cxtabtlen = scale_expansion_zeroelim(abtlen, abt, cdxtail, cxtabt); + temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, 2.0 * cdx, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + if (adytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, bb, cdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, adytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (bdytail != 0.0) { + temp8len = scale_expansion_zeroelim(4, aa, -cdxtail, temp8); + temp16alen = scale_expansion_zeroelim(temp8len, temp8, bdytail, + temp16a); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp16alen, + temp16a, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + + temp32alen = scale_expansion_zeroelim(cxtabtlen, cxtabt, cdxtail, + temp32a); + cxtabttlen = scale_expansion_zeroelim(abttlen, abtt, cdxtail, cxtabtt); + temp16alen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, 2.0 * cdx, + temp16a); + temp16blen = scale_expansion_zeroelim(cxtabttlen, cxtabtt, cdxtail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + if (cdytail != 0.0) { + temp16alen = scale_expansion_zeroelim(cytablen, cytab, cdytail, temp16a); + cytabtlen = scale_expansion_zeroelim(abtlen, abt, cdytail, cytabt); + temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, 2.0 * cdy, + temp32a); + temp48len = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp32alen, temp32a, temp48); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp48len, + temp48, finother); + finswap = finnow; finnow = finother; finother = finswap; + + + temp32alen = scale_expansion_zeroelim(cytabtlen, cytabt, cdytail, + temp32a); + cytabttlen = scale_expansion_zeroelim(abttlen, abtt, cdytail, cytabtt); + temp16alen = scale_expansion_zeroelim(cytabttlen, cytabtt, 2.0 * cdy, + temp16a); + temp16blen = scale_expansion_zeroelim(cytabttlen, cytabtt, cdytail, + temp16b); + temp32blen = fast_expansion_sum_zeroelim(temp16alen, temp16a, + temp16blen, temp16b, temp32b); + temp64len = fast_expansion_sum_zeroelim(temp32alen, temp32a, + temp32blen, temp32b, temp64); + finlength = fast_expansion_sum_zeroelim(finlength, finnow, temp64len, + temp64, finother); + finswap = finnow; finnow = finother; finother = finswap; + } + } + + return finnow[finlength - 1]; +} + +REAL incircle(pa, pb, pc, pd) +point pa; +point pb; +point pc; +point pd; +{ + REAL adx, bdx, cdx, ady, bdy, cdy; + REAL bdxcdy, cdxbdy, cdxady, adxcdy, adxbdy, bdxady; + REAL alift, blift, clift; + REAL det; + REAL permanent, errbound; + + incirclecount++; + + adx = pa[0] - pd[0]; + bdx = pb[0] - pd[0]; + cdx = pc[0] - pd[0]; + ady = pa[1] - pd[1]; + bdy = pb[1] - pd[1]; + cdy = pc[1] - pd[1]; + + bdxcdy = bdx * cdy; + cdxbdy = cdx * bdy; + alift = adx * adx + ady * ady; + + cdxady = cdx * ady; + adxcdy = adx * cdy; + blift = bdx * bdx + bdy * bdy; + + adxbdy = adx * bdy; + bdxady = bdx * ady; + clift = cdx * cdx + cdy * cdy; + + det = alift * (bdxcdy - cdxbdy) + + blift * (cdxady - adxcdy) + + clift * (adxbdy - bdxady); + + if (noexact) { + return det; + } + + permanent = (Absolute(bdxcdy) + Absolute(cdxbdy)) * alift + + (Absolute(cdxady) + Absolute(adxcdy)) * blift + + (Absolute(adxbdy) + Absolute(bdxady)) * clift; + errbound = iccerrboundA * permanent; + if ((det > errbound) || (-det > errbound)) { + return det; + } + + return incircleadapt(pa, pb, pc, pd, permanent); +} + +/** **/ +/** **/ +/********* Determinant evaluation routines end here *********/ + +/*****************************************************************************/ +/* */ +/* triangleinit() Initialize some variables. */ +/* */ +/*****************************************************************************/ + +void triangleinit() +{ + points.maxitems = triangles.maxitems = shelles.maxitems = viri.maxitems = + badsegments.maxitems = badtriangles.maxitems = splaynodes.maxitems = 0l; + points.itembytes = triangles.itembytes = shelles.itembytes = viri.itembytes = + badsegments.itembytes = badtriangles.itembytes = splaynodes.itembytes = 0; + recenttri.tri = (triangle *) NULL; /* No triangle has been visited yet. */ + samples = 1; /* Point location should take at least one sample. */ + checksegments = 0; /* There are no segments in the triangulation yet. */ + incirclecount = counterclockcount = hyperbolacount = 0; + circumcentercount = circletopcount = 0; + randomseed = 1; + + exactinit(); /* Initialize exact arithmetic constants. */ +} + +/*****************************************************************************/ +/* */ +/* randomnation() Generate a random number between 0 and `choices' - 1. */ +/* */ +/* This is a simple linear congruential random number generator. Hence, it */ +/* is a bad random number generator, but good enough for most randomized */ +/* geometric algorithms. */ +/* */ +/*****************************************************************************/ + +unsigned long randomnation(choices) +unsigned int choices; +{ + randomseed = (randomseed * 1366l + 150889l) % 714025l; + return randomseed / (714025l / choices + 1); +} + +/********* Mesh quality testing routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* checkmesh() Test the mesh for topological consistency. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +void checkmesh() +{ + struct triedge triangleloop; + struct triedge oppotri, oppooppotri; + point triorg, tridest, triapex; + point oppoorg, oppodest; + int horrors; + int saveexact; + triangle ptr; /* Temporary variable used by sym(). */ + + /* Temporarily turn on exact arithmetic if it's off. */ + saveexact = noexact; + noexact = 0; + if (!quiet) { + printf(" Checking consistency of mesh...\n"); + } + horrors = 0; + /* Run through the list of triangles, checking each one. */ + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + while (triangleloop.tri != (triangle *) NULL) { + /* Check all three edges of the triangle. */ + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + org(triangleloop, triorg); + dest(triangleloop, tridest); + if (triangleloop.orient == 0) { /* Only test for inversion once. */ + /* Test if the triangle is flat or inverted. */ + apex(triangleloop, triapex); + if (counterclockwise(triorg, tridest, triapex) <= 0.0) { + printf(" !! !! Inverted "); + printtriangle(&triangleloop); + horrors++; + } + } + /* Find the neighboring triangle on this edge. */ + sym(triangleloop, oppotri); + if (oppotri.tri != dummytri) { + /* Check that the triangle's neighbor knows it's a neighbor. */ + sym(oppotri, oppooppotri); + if ((triangleloop.tri != oppooppotri.tri) + || (triangleloop.orient != oppooppotri.orient)) { + printf(" !! !! Asymmetric triangle-triangle bond:\n"); + if (triangleloop.tri == oppooppotri.tri) { + printf(" (Right triangle, wrong orientation)\n"); + } + printf(" First "); + printtriangle(&triangleloop); + printf(" Second (nonreciprocating) "); + printtriangle(&oppotri); + horrors++; + } + /* Check that both triangles agree on the identities */ + /* of their shared vertices. */ + org(oppotri, oppoorg); + dest(oppotri, oppodest); + if ((triorg != oppodest) || (tridest != oppoorg)) { + printf(" !! !! Mismatched edge coordinates between two triangles:\n" + ); + printf(" First mismatched "); + printtriangle(&triangleloop); + printf(" Second mismatched "); + printtriangle(&oppotri); + horrors++; + } + } + } + triangleloop.tri = triangletraverse(); + } + if (horrors == 0) { + if (!quiet) { + printf(" In my studied opinion, the mesh appears to be consistent.\n"); + } + } else if (horrors == 1) { + printf(" !! !! !! !! Precisely one festering wound discovered.\n"); + } else { + printf(" !! !! !! !! %d abominations witnessed.\n", horrors); + } + /* Restore the status of exact arithmetic. */ + noexact = saveexact; +} + +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* checkdelaunay() Ensure that the mesh is (constrained) Delaunay. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +void checkdelaunay() +{ + struct triedge triangleloop; + struct triedge oppotri; + struct edge opposhelle; + point triorg, tridest, triapex; + point oppoapex; + int shouldbedelaunay; + int horrors; + int saveexact; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + /* Temporarily turn on exact arithmetic if it's off. */ + saveexact = noexact; + noexact = 0; + if (!quiet) { + printf(" Checking Delaunay property of mesh...\n"); + } + horrors = 0; + /* Run through the list of triangles, checking each one. */ + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + while (triangleloop.tri != (triangle *) NULL) { + /* Check all three edges of the triangle. */ + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + org(triangleloop, triorg); + dest(triangleloop, tridest); + apex(triangleloop, triapex); + sym(triangleloop, oppotri); + apex(oppotri, oppoapex); + /* Only test that the edge is locally Delaunay if there is an */ + /* adjoining triangle whose pointer is larger (to ensure that */ + /* each pair isn't tested twice). */ + shouldbedelaunay = (oppotri.tri != dummytri) + && (triapex != (point) NULL) && (oppoapex != (point) NULL) + && (triangleloop.tri < oppotri.tri); + if (checksegments && shouldbedelaunay) { + /* If a shell edge separates the triangles, then the edge is */ + /* constrained, so no local Delaunay test should be done. */ + tspivot(triangleloop, opposhelle); + if (opposhelle.sh != dummysh){ + shouldbedelaunay = 0; + } + } + if (shouldbedelaunay) { + if (incircle(triorg, tridest, triapex, oppoapex) > 0.0) { + printf(" !! !! Non-Delaunay pair of triangles:\n"); + printf(" First non-Delaunay "); + printtriangle(&triangleloop); + printf(" Second non-Delaunay "); + printtriangle(&oppotri); + horrors++; + } + } + } + triangleloop.tri = triangletraverse(); + } + if (horrors == 0) { + if (!quiet) { + printf( + " By virtue of my perceptive intelligence, I declare the mesh Delaunay.\n"); + } + } else if (horrors == 1) { + printf( + " !! !! !! !! Precisely one terrifying transgression identified.\n"); + } else { + printf(" !! !! !! !! %d obscenities viewed with horror.\n", horrors); + } + /* Restore the status of exact arithmetic. */ + noexact = saveexact; +} + +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* enqueuebadtri() Add a bad triangle to the end of a queue. */ +/* */ +/* The queue is actually a set of 64 queues. I use multiple queues to give */ +/* priority to smaller angles. I originally implemented a heap, but the */ +/* queues are (to my surprise) much faster. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void enqueuebadtri(instri, angle, insapex, insorg, insdest) +struct triedge *instri; +REAL angle; +point insapex; +point insorg; +point insdest; +{ + struct badface *newface; + int queuenumber; + + if (verbose > 2) { + printf(" Queueing bad triangle:\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", insorg[0], + insorg[1], insdest[0], insdest[1], insapex[0], insapex[1]); + } + /* Allocate space for the bad triangle. */ + newface = (struct badface *) poolalloc(&badtriangles); + triedgecopy(*instri, newface->badfacetri); + newface->key = angle; + newface->faceapex = insapex; + newface->faceorg = insorg; + newface->facedest = insdest; + newface->nextface = (struct badface *) NULL; + /* Determine the appropriate queue to put the bad triangle into. */ + if (angle > 0.6) { + queuenumber = (int) (160.0 * (angle - 0.6)); + if (queuenumber > 63) { + queuenumber = 63; + } + } else { + /* It's not a bad angle; put the triangle in the lowest-priority queue. */ + queuenumber = 0; + } + /* Add the triangle to the end of a queue. */ + *queuetail[queuenumber] = newface; + /* Maintain a pointer to the NULL pointer at the end of the queue. */ + queuetail[queuenumber] = &newface->nextface; +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* dequeuebadtri() Remove a triangle from the front of the queue. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +struct badface *dequeuebadtri() +{ + struct badface *result; + int queuenumber; + + /* Look for a nonempty queue. */ + for (queuenumber = 63; queuenumber >= 0; queuenumber--) { + result = queuefront[queuenumber]; + if (result != (struct badface *) NULL) { + /* Remove the triangle from the queue. */ + queuefront[queuenumber] = result->nextface; + /* Maintain a pointer to the NULL pointer at the end of the queue. */ + if (queuefront[queuenumber] == (struct badface *) NULL) { + queuetail[queuenumber] = &queuefront[queuenumber]; + } + return result; + } + } + return (struct badface *) NULL; +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* checkedge4encroach() Check a segment to see if it is encroached; add */ +/* it to the list if it is. */ +/* */ +/* An encroached segment is an unflippable edge that has a point in its */ +/* diametral circle (that is, it faces an angle greater than 90 degrees). */ +/* This definition is due to Ruppert. */ +/* */ +/* Returns a nonzero value if the edge is encroached. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +int checkedge4encroach(testedge) +struct edge *testedge; +{ + struct triedge neighbortri; + struct edge testsym; + struct edge *badedge; + int addtolist; + int sides; + point eorg, edest, eapex; + triangle ptr; /* Temporary variable used by stpivot(). */ + + addtolist = 0; + sides = 0; + + sorg(*testedge, eorg); + sdest(*testedge, edest); + /* Check one neighbor of the shell edge. */ + stpivot(*testedge, neighbortri); + /* Does the neighbor exist, or is this a boundary edge? */ + if (neighbortri.tri != dummytri) { + sides++; + /* Find a vertex opposite this edge. */ + apex(neighbortri, eapex); + /* Check whether the vertex is inside the diametral circle of the */ + /* shell edge. Pythagoras' Theorem is used to check whether the */ + /* angle at the vertex is greater than 90 degrees. */ + if (eapex[0] * (eorg[0] + edest[0]) + eapex[1] * (eorg[1] + edest[1]) > + eapex[0] * eapex[0] + eorg[0] * edest[0] + + eapex[1] * eapex[1] + eorg[1] * edest[1]) { + addtolist = 1; + } + } + /* Check the other neighbor of the shell edge. */ + ssym(*testedge, testsym); + stpivot(testsym, neighbortri); + /* Does the neighbor exist, or is this a boundary edge? */ + if (neighbortri.tri != dummytri) { + sides++; + /* Find the other vertex opposite this edge. */ + apex(neighbortri, eapex); + /* Check whether the vertex is inside the diametral circle of the */ + /* shell edge. Pythagoras' Theorem is used to check whether the */ + /* angle at the vertex is greater than 90 degrees. */ + if (eapex[0] * (eorg[0] + edest[0]) + + eapex[1] * (eorg[1] + edest[1]) > + eapex[0] * eapex[0] + eorg[0] * edest[0] + + eapex[1] * eapex[1] + eorg[1] * edest[1]) { + addtolist += 2; + } + } + + if (addtolist && (!nobisect || ((nobisect == 1) && (sides == 2)))) { + if (verbose > 2) { + printf(" Queueing encroached segment (%.12g, %.12g) (%.12g, %.12g).\n", + eorg[0], eorg[1], edest[0], edest[1]); + } + /* Add the shell edge to the list of encroached segments. */ + /* Be sure to get the orientation right. */ + badedge = (struct edge *) poolalloc(&badsegments); + if (addtolist == 1) { + shellecopy(*testedge, *badedge); + } else { + shellecopy(testsym, *badedge); + } + } + return addtolist; +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* testtriangle() Test a face for quality measures. */ +/* */ +/* Tests a triangle to see if it satisfies the minimum angle condition and */ +/* the maximum area condition. Triangles that aren't up to spec are added */ +/* to the bad triangle queue. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void testtriangle(testtri) +struct triedge *testtri; +{ + struct triedge sametesttri; + struct edge edge1, edge2; + point torg, tdest, tapex; + point anglevertex; + REAL dxod, dyod, dxda, dyda, dxao, dyao; + REAL dxod2, dyod2, dxda2, dyda2, dxao2, dyao2; + REAL apexlen, orglen, destlen; + REAL angle; + REAL area; + shelle sptr; /* Temporary variable used by tspivot(). */ + + org(*testtri, torg); + dest(*testtri, tdest); + apex(*testtri, tapex); + dxod = torg[0] - tdest[0]; + dyod = torg[1] - tdest[1]; + dxda = tdest[0] - tapex[0]; + dyda = tdest[1] - tapex[1]; + dxao = tapex[0] - torg[0]; + dyao = tapex[1] - torg[1]; + dxod2 = dxod * dxod; + dyod2 = dyod * dyod; + dxda2 = dxda * dxda; + dyda2 = dyda * dyda; + dxao2 = dxao * dxao; + dyao2 = dyao * dyao; + /* Find the lengths of the triangle's three edges. */ + apexlen = dxod2 + dyod2; + orglen = dxda2 + dyda2; + destlen = dxao2 + dyao2; + if ((apexlen < orglen) && (apexlen < destlen)) { + /* The edge opposite the apex is shortest. */ + /* Find the square of the cosine of the angle at the apex. */ + angle = dxda * dxao + dyda * dyao; + angle = angle * angle / (orglen * destlen); + anglevertex = tapex; + lnext(*testtri, sametesttri); + tspivot(sametesttri, edge1); + lnextself(sametesttri); + tspivot(sametesttri, edge2); + } else if (orglen < destlen) { + /* The edge opposite the origin is shortest. */ + /* Find the square of the cosine of the angle at the origin. */ + angle = dxod * dxao + dyod * dyao; + angle = angle * angle / (apexlen * destlen); + anglevertex = torg; + tspivot(*testtri, edge1); + lprev(*testtri, sametesttri); + tspivot(sametesttri, edge2); + } else { + /* The edge opposite the destination is shortest. */ + /* Find the square of the cosine of the angle at the destination. */ + angle = dxod * dxda + dyod * dyda; + angle = angle * angle / (apexlen * orglen); + anglevertex = tdest; + tspivot(*testtri, edge1); + lnext(*testtri, sametesttri); + tspivot(sametesttri, edge2); + } + /* Check if both edges that form the angle are segments. */ + if ((edge1.sh != dummysh) && (edge2.sh != dummysh)) { + /* The angle is a segment intersection. */ + if ((angle > 0.9924) && !quiet) { /* Roughly 5 degrees. */ + if (angle > 1.0) { + /* Beware of a floating exception in acos(). */ + angle = 1.0; + } + /* Find the actual angle in degrees, for printing. */ + angle = acos(sqrt(angle)) * (180.0 / PI); + printf( + "Warning: Small angle (%.4g degrees) between segments at point\n", + angle); + printf(" (%.12g, %.12g)\n", anglevertex[0], anglevertex[1]); + } + /* Don't add this bad triangle to the list; there's nothing that */ + /* can be done about a small angle between two segments. */ + angle = 0.0; + } + /* Check whether the angle is smaller than permitted. */ + if (angle > goodangle) { + /* Add this triangle to the list of bad triangles. */ + enqueuebadtri(testtri, angle, tapex, torg, tdest); + return; + } + if (vararea || fixedarea) { + /* Check whether the area is larger than permitted. */ + area = 0.5 * (dxod * dyda - dyod * dxda); + if (fixedarea && (area > maxarea)) { + /* Add this triangle to the list of bad triangles. */ + enqueuebadtri(testtri, angle, tapex, torg, tdest); + } else if (vararea) { + /* Nonpositive area constraints are treated as unconstrained. */ + if ((area > areabound(*testtri)) && (areabound(*testtri) > 0.0)) { + /* Add this triangle to the list of bad triangles. */ + enqueuebadtri(testtri, angle, tapex, torg, tdest); + } + } + } +} + +#endif /* not CDT_ONLY */ + +/** **/ +/** **/ +/********* Mesh quality testing routines end here *********/ + +/********* Point location routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* makepointmap() Construct a mapping from points to triangles to improve */ +/* the speed of point location for segment insertion. */ +/* */ +/* Traverses all the triangles, and provides each corner of each triangle */ +/* with a pointer to that triangle. Of course, pointers will be */ +/* overwritten by other pointers because (almost) each point is a corner */ +/* of several triangles, but in the end every point will point to some */ +/* triangle that contains it. */ +/* */ +/*****************************************************************************/ + +void makepointmap() +{ + struct triedge triangleloop; + point triorg; + + if (verbose) { + printf(" Constructing mapping from points to triangles.\n"); + } + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + while (triangleloop.tri != (triangle *) NULL) { + /* Check all three points of the triangle. */ + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + org(triangleloop, triorg); + setpoint2tri(triorg, encode(triangleloop)); + } + triangleloop.tri = triangletraverse(); + } +} + +/*****************************************************************************/ +/* */ +/* preciselocate() Find a triangle or edge containing a given point. */ +/* */ +/* Begins its search from `searchtri'. It is important that `searchtri' */ +/* be a handle with the property that `searchpoint' is strictly to the left */ +/* of the edge denoted by `searchtri', or is collinear with that edge and */ +/* does not intersect that edge. (In particular, `searchpoint' should not */ +/* be the origin or destination of that edge.) */ +/* */ +/* These conditions are imposed because preciselocate() is normally used in */ +/* one of two situations: */ +/* */ +/* (1) To try to find the location to insert a new point. Normally, we */ +/* know an edge that the point is strictly to the left of. In the */ +/* incremental Delaunay algorithm, that edge is a bounding box edge. */ +/* In Ruppert's Delaunay refinement algorithm for quality meshing, */ +/* that edge is the shortest edge of the triangle whose circumcenter */ +/* is being inserted. */ +/* */ +/* (2) To try to find an existing point. In this case, any edge on the */ +/* convex hull is a good starting edge. The possibility that the */ +/* vertex one seeks is an endpoint of the starting edge must be */ +/* screened out before preciselocate() is called. */ +/* */ +/* On completion, `searchtri' is a triangle that contains `searchpoint'. */ +/* */ +/* This implementation differs from that given by Guibas and Stolfi. It */ +/* walks from triangle to triangle, crossing an edge only if `searchpoint' */ +/* is on the other side of the line containing that edge. After entering */ +/* a triangle, there are two edges by which one can leave that triangle. */ +/* If both edges are valid (`searchpoint' is on the other side of both */ +/* edges), one of the two is chosen by drawing a line perpendicular to */ +/* the entry edge (whose endpoints are `forg' and `fdest') passing through */ +/* `fapex'. Depending on which side of this perpendicular `searchpoint' */ +/* falls on, an exit edge is chosen. */ +/* */ +/* This implementation is empirically faster than the Guibas and Stolfi */ +/* point location routine (which I originally used), which tends to spiral */ +/* in toward its target. */ +/* */ +/* Returns ONVERTEX if the point lies on an existing vertex. `searchtri' */ +/* is a handle whose origin is the existing vertex. */ +/* */ +/* Returns ONEDGE if the point lies on a mesh edge. `searchtri' is a */ +/* handle whose primary edge is the edge on which the point lies. */ +/* */ +/* Returns INTRIANGLE if the point lies strictly within a triangle. */ +/* `searchtri' is a handle on the triangle that contains the point. */ +/* */ +/* Returns OUTSIDE if the point lies outside the mesh. `searchtri' is a */ +/* handle whose primary edge the point is to the right of. This might */ +/* occur when the circumcenter of a triangle falls just slightly outside */ +/* the mesh due to floating-point roundoff error. It also occurs when */ +/* seeking a hole or region point that a foolish user has placed outside */ +/* the mesh. */ +/* */ +/* WARNING: This routine is designed for convex triangulations, and will */ +/* not generally work after the holes and concavities have been carved. */ +/* However, it can still be used to find the circumcenter of a triangle, as */ +/* long as the search is begun from the triangle in question. */ +/* */ +/*****************************************************************************/ + +enum locateresult preciselocate(searchpoint, searchtri) +point searchpoint; +struct triedge *searchtri; +{ + struct triedge backtracktri; + point forg, fdest, fapex; + point swappoint; + REAL orgorient, destorient; + int moveleft; + triangle ptr; /* Temporary variable used by sym(). */ + + if (verbose > 2) { + printf(" Searching for point (%.12g, %.12g).\n", + searchpoint[0], searchpoint[1]); + } + /* Where are we? */ + org(*searchtri, forg); + dest(*searchtri, fdest); + apex(*searchtri, fapex); + while (1) { + if (verbose > 2) { + printf(" At (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + forg[0], forg[1], fdest[0], fdest[1], fapex[0], fapex[1]); + } + /* Check whether the apex is the point we seek. */ + if ((fapex[0] == searchpoint[0]) && (fapex[1] == searchpoint[1])) { + lprevself(*searchtri); + return ONVERTEX; + } + /* Does the point lie on the other side of the line defined by the */ + /* triangle edge opposite the triangle's destination? */ + destorient = counterclockwise(forg, fapex, searchpoint); + /* Does the point lie on the other side of the line defined by the */ + /* triangle edge opposite the triangle's origin? */ + orgorient = counterclockwise(fapex, fdest, searchpoint); + if (destorient > 0.0) { + if (orgorient > 0.0) { + /* Move left if the inner product of (fapex - searchpoint) and */ + /* (fdest - forg) is positive. This is equivalent to drawing */ + /* a line perpendicular to the line (forg, fdest) passing */ + /* through `fapex', and determining which side of this line */ + /* `searchpoint' falls on. */ + moveleft = (fapex[0] - searchpoint[0]) * (fdest[0] - forg[0]) + + (fapex[1] - searchpoint[1]) * (fdest[1] - forg[1]) > 0.0; + } else { + moveleft = 1; + } + } else { + if (orgorient > 0.0) { + moveleft = 0; + } else { + /* The point we seek must be on the boundary of or inside this */ + /* triangle. */ + if (destorient == 0.0) { + lprevself(*searchtri); + return ONEDGE; + } + if (orgorient == 0.0) { + lnextself(*searchtri); + return ONEDGE; + } + return INTRIANGLE; + } + } + + /* Move to another triangle. Leave a trace `backtracktri' in case */ + /* floating-point roundoff or some such bogey causes us to walk */ + /* off a boundary of the triangulation. We can just bounce off */ + /* the boundary as if it were an elastic band. */ + if (moveleft) { + lprev(*searchtri, backtracktri); + fdest = fapex; + } else { + lnext(*searchtri, backtracktri); + forg = fapex; + } + sym(backtracktri, *searchtri); + + /* Check for walking off the edge. */ + if (searchtri->tri == dummytri) { + /* Turn around. */ + triedgecopy(backtracktri, *searchtri); + swappoint = forg; + forg = fdest; + fdest = swappoint; + apex(*searchtri, fapex); + /* Check if the point really is beyond the triangulation boundary. */ + destorient = counterclockwise(forg, fapex, searchpoint); + orgorient = counterclockwise(fapex, fdest, searchpoint); + if ((orgorient < 0.0) && (destorient < 0.0)) { + return OUTSIDE; + } + } else { + apex(*searchtri, fapex); + } + } +} + +/*****************************************************************************/ +/* */ +/* locate() Find a triangle or edge containing a given point. */ +/* */ +/* Searching begins from one of: the input `searchtri', a recently */ +/* encountered triangle `recenttri', or from a triangle chosen from a */ +/* random sample. The choice is made by determining which triangle's */ +/* origin is closest to the point we are searcing for. Normally, */ +/* `searchtri' should be a handle on the convex hull of the triangulation. */ +/* */ +/* Details on the random sampling method can be found in the Mucke, Saias, */ +/* and Zhu paper cited in the header of this code. */ +/* */ +/* On completion, `searchtri' is a triangle that contains `searchpoint'. */ +/* */ +/* Returns ONVERTEX if the point lies on an existing vertex. `searchtri' */ +/* is a handle whose origin is the existing vertex. */ +/* */ +/* Returns ONEDGE if the point lies on a mesh edge. `searchtri' is a */ +/* handle whose primary edge is the edge on which the point lies. */ +/* */ +/* Returns INTRIANGLE if the point lies strictly within a triangle. */ +/* `searchtri' is a handle on the triangle that contains the point. */ +/* */ +/* Returns OUTSIDE if the point lies outside the mesh. `searchtri' is a */ +/* handle whose primary edge the point is to the right of. This might */ +/* occur when the circumcenter of a triangle falls just slightly outside */ +/* the mesh due to floating-point roundoff error. It also occurs when */ +/* seeking a hole or region point that a foolish user has placed outside */ +/* the mesh. */ +/* */ +/* WARNING: This routine is designed for convex triangulations, and will */ +/* not generally work after the holes and concavities have been carved. */ +/* */ +/*****************************************************************************/ + +enum locateresult locate(searchpoint, searchtri) +point searchpoint; +struct triedge *searchtri; +{ + VOID **sampleblock; + triangle *firsttri; + struct triedge sampletri; + point torg, tdest; + unsigned long alignptr; + REAL searchdist, dist; + REAL ahead; + long sampleblocks, samplesperblock, samplenum; + long triblocks; + long i, j; + triangle ptr; /* Temporary variable used by sym(). */ + + if (verbose > 2) { + printf(" Randomly sampling for a triangle near point (%.12g, %.12g).\n", + searchpoint[0], searchpoint[1]); + } + /* Record the distance from the suggested starting triangle to the */ + /* point we seek. */ + org(*searchtri, torg); + searchdist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0]) + + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]); + if (verbose > 2) { + printf(" Boundary triangle has origin (%.12g, %.12g).\n", + torg[0], torg[1]); + } + + /* If a recently encountered triangle has been recorded and has not been */ + /* deallocated, test it as a good starting point. */ + if (recenttri.tri != (triangle *) NULL) { + if (recenttri.tri[3] != (triangle) NULL) { + org(recenttri, torg); + if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) { + triedgecopy(recenttri, *searchtri); + return ONVERTEX; + } + dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0]) + + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]); + if (dist < searchdist) { + triedgecopy(recenttri, *searchtri); + searchdist = dist; + if (verbose > 2) { + printf(" Choosing recent triangle with origin (%.12g, %.12g).\n", + torg[0], torg[1]); + } + } + } + } + + /* The number of random samples taken is proportional to the cube root of */ + /* the number of triangles in the mesh. The next bit of code assumes */ + /* that the number of triangles increases monotonically. */ + while (SAMPLEFACTOR * samples * samples * samples < triangles.items) { + samples++; + } + triblocks = (triangles.maxitems + TRIPERBLOCK - 1) / TRIPERBLOCK; + samplesperblock = 1 + (samples / triblocks); + sampleblocks = samples / samplesperblock; + sampleblock = triangles.firstblock; + sampletri.orient = 0; + for (i = 0; i < sampleblocks; i++) { + alignptr = (unsigned long) (sampleblock + 1); + firsttri = (triangle *) (alignptr + (unsigned long) triangles.alignbytes + - (alignptr % (unsigned long) triangles.alignbytes)); + for (j = 0; j < samplesperblock; j++) { + if (i == triblocks - 1) { + samplenum = randomnation((int) + (triangles.maxitems - (i * TRIPERBLOCK))); + } else { + samplenum = randomnation(TRIPERBLOCK); + } + sampletri.tri = (triangle *) + (firsttri + (samplenum * triangles.itemwords)); + if (sampletri.tri[3] != (triangle) NULL) { + org(sampletri, torg); + dist = (searchpoint[0] - torg[0]) * (searchpoint[0] - torg[0]) + + (searchpoint[1] - torg[1]) * (searchpoint[1] - torg[1]); + if (dist < searchdist) { + triedgecopy(sampletri, *searchtri); + searchdist = dist; + if (verbose > 2) { + printf(" Choosing triangle with origin (%.12g, %.12g).\n", + torg[0], torg[1]); + } + } + } + } + sampleblock = (VOID **) *sampleblock; + } + /* Where are we? */ + org(*searchtri, torg); + dest(*searchtri, tdest); + /* Check the starting triangle's vertices. */ + if ((torg[0] == searchpoint[0]) && (torg[1] == searchpoint[1])) { + return ONVERTEX; + } + if ((tdest[0] == searchpoint[0]) && (tdest[1] == searchpoint[1])) { + lnextself(*searchtri); + return ONVERTEX; + } + /* Orient `searchtri' to fit the preconditions of calling preciselocate(). */ + ahead = counterclockwise(torg, tdest, searchpoint); + if (ahead < 0.0) { + /* Turn around so that `searchpoint' is to the left of the */ + /* edge specified by `searchtri'. */ + symself(*searchtri); + } else if (ahead == 0.0) { + /* Check if `searchpoint' is between `torg' and `tdest'. */ + if (((torg[0] < searchpoint[0]) == (searchpoint[0] < tdest[0])) + && ((torg[1] < searchpoint[1]) == (searchpoint[1] < tdest[1]))) { + return ONEDGE; + } + } + return preciselocate(searchpoint, searchtri); +} + +/** **/ +/** **/ +/********* Point location routines end here *********/ + +/********* Mesh transformation routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* insertshelle() Create a new shell edge and insert it between two */ +/* triangles. */ +/* */ +/* The new shell edge is inserted at the edge described by the handle */ +/* `tri'. Its vertices are properly initialized. The marker `shellemark' */ +/* is applied to the shell edge and, if appropriate, its vertices. */ +/* */ +/*****************************************************************************/ + +void insertshelle(tri, shellemark) +struct triedge *tri; /* Edge at which to insert the new shell edge. */ +int shellemark; /* Marker for the new shell edge. */ +{ + struct triedge oppotri; + struct edge newshelle; + point triorg, tridest; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + /* Mark points if possible. */ + org(*tri, triorg); + dest(*tri, tridest); + if (pointmark(triorg) == 0) { + setpointmark(triorg, shellemark); + } + if (pointmark(tridest) == 0) { + setpointmark(tridest, shellemark); + } + /* Check if there's already a shell edge here. */ + tspivot(*tri, newshelle); + if (newshelle.sh == dummysh) { + /* Make new shell edge and initialize its vertices. */ + makeshelle(&newshelle); + setsorg(newshelle, tridest); + setsdest(newshelle, triorg); + /* Bond new shell edge to the two triangles it is sandwiched between. */ + /* Note that the facing triangle `oppotri' might be equal to */ + /* `dummytri' (outer space), but the new shell edge is bonded to it */ + /* all the same. */ + tsbond(*tri, newshelle); + sym(*tri, oppotri); + ssymself(newshelle); + tsbond(oppotri, newshelle); + setmark(newshelle, shellemark); + if (verbose > 2) { + printf(" Inserting new "); + printshelle(&newshelle); + } + } else { + if (mark(newshelle) == 0) { + setmark(newshelle, shellemark); + } + } +} + +/*****************************************************************************/ +/* */ +/* Terminology */ +/* */ +/* A "local transformation" replaces a small set of triangles with another */ +/* set of triangles. This may or may not involve inserting or deleting a */ +/* point. */ +/* */ +/* The term "casing" is used to describe the set of triangles that are */ +/* attached to the triangles being transformed, but are not transformed */ +/* themselves. Think of the casing as a fixed hollow structure inside */ +/* which all the action happens. A "casing" is only defined relative to */ +/* a single transformation; each occurrence of a transformation will */ +/* involve a different casing. */ +/* */ +/* A "shell" is similar to a "casing". The term "shell" describes the set */ +/* of shell edges (if any) that are attached to the triangles being */ +/* transformed. However, I sometimes use "shell" to refer to a single */ +/* shell edge, so don't get confused. */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* flip() Transform two triangles to two different triangles by flipping */ +/* an edge within a quadrilateral. */ +/* */ +/* Imagine the original triangles, abc and bad, oriented so that the */ +/* shared edge ab lies in a horizontal plane, with the point b on the left */ +/* and the point a on the right. The point c lies below the edge, and the */ +/* point d lies above the edge. The `flipedge' handle holds the edge ab */ +/* of triangle abc, and is directed left, from vertex a to vertex b. */ +/* */ +/* The triangles abc and bad are deleted and replaced by the triangles cdb */ +/* and dca. The triangles that represent abc and bad are NOT deallocated; */ +/* they are reused for dca and cdb, respectively. Hence, any handles that */ +/* may have held the original triangles are still valid, although not */ +/* directed as they were before. */ +/* */ +/* Upon completion of this routine, the `flipedge' handle holds the edge */ +/* dc of triangle dca, and is directed down, from vertex d to vertex c. */ +/* (Hence, the two triangles have rotated counterclockwise.) */ +/* */ +/* WARNING: This transformation is geometrically valid only if the */ +/* quadrilateral adbc is convex. Furthermore, this transformation is */ +/* valid only if there is not a shell edge between the triangles abc and */ +/* bad. This routine does not check either of these preconditions, and */ +/* it is the responsibility of the calling routine to ensure that they are */ +/* met. If they are not, the streets shall be filled with wailing and */ +/* gnashing of teeth. */ +/* */ +/*****************************************************************************/ + +void flip(flipedge) +struct triedge *flipedge; /* Handle for the triangle abc. */ +{ + struct triedge botleft, botright; + struct triedge topleft, topright; + struct triedge top; + struct triedge botlcasing, botrcasing; + struct triedge toplcasing, toprcasing; + struct edge botlshelle, botrshelle; + struct edge toplshelle, toprshelle; + point leftpoint, rightpoint, botpoint; + point farpoint; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + /* Identify the vertices of the quadrilateral. */ + org(*flipedge, rightpoint); + dest(*flipedge, leftpoint); + apex(*flipedge, botpoint); + sym(*flipedge, top); +#ifdef SELF_CHECK + if (top.tri == dummytri) { + printf("Internal error in flip(): Attempt to flip on boundary.\n"); + lnextself(*flipedge); + return; + } + if (checksegments) { + tspivot(*flipedge, toplshelle); + if (toplshelle.sh != dummysh) { + printf("Internal error in flip(): Attempt to flip a segment.\n"); + lnextself(*flipedge); + return; + } + } +#endif /* SELF_CHECK */ + apex(top, farpoint); + + /* Identify the casing of the quadrilateral. */ + lprev(top, topleft); + sym(topleft, toplcasing); + lnext(top, topright); + sym(topright, toprcasing); + lnext(*flipedge, botleft); + sym(botleft, botlcasing); + lprev(*flipedge, botright); + sym(botright, botrcasing); + /* Rotate the quadrilateral one-quarter turn counterclockwise. */ + bond(topleft, botlcasing); + bond(botleft, botrcasing); + bond(botright, toprcasing); + bond(topright, toplcasing); + + if (checksegments) { + /* Check for shell edges and rebond them to the quadrilateral. */ + tspivot(topleft, toplshelle); + tspivot(botleft, botlshelle); + tspivot(botright, botrshelle); + tspivot(topright, toprshelle); + if (toplshelle.sh == dummysh) { + tsdissolve(topright); + } else { + tsbond(topright, toplshelle); + } + if (botlshelle.sh == dummysh) { + tsdissolve(topleft); + } else { + tsbond(topleft, botlshelle); + } + if (botrshelle.sh == dummysh) { + tsdissolve(botleft); + } else { + tsbond(botleft, botrshelle); + } + if (toprshelle.sh == dummysh) { + tsdissolve(botright); + } else { + tsbond(botright, toprshelle); + } + } + + /* New point assignments for the rotated quadrilateral. */ + setorg(*flipedge, farpoint); + setdest(*flipedge, botpoint); + setapex(*flipedge, rightpoint); + setorg(top, botpoint); + setdest(top, farpoint); + setapex(top, leftpoint); + if (verbose > 2) { + printf(" Edge flip results in left "); + lnextself(topleft); + printtriangle(&topleft); + printf(" and right "); + printtriangle(flipedge); + } +} + +/*****************************************************************************/ +/* */ +/* insertsite() Insert a vertex into a Delaunay triangulation, */ +/* performing flips as necessary to maintain the Delaunay */ +/* property. */ +/* */ +/* The point `insertpoint' is located. If `searchtri.tri' is not NULL, */ +/* the search for the containing triangle begins from `searchtri'. If */ +/* `searchtri.tri' is NULL, a full point location procedure is called. */ +/* If `insertpoint' is found inside a triangle, the triangle is split into */ +/* three; if `insertpoint' lies on an edge, the edge is split in two, */ +/* thereby splitting the two adjacent triangles into four. Edge flips are */ +/* used to restore the Delaunay property. If `insertpoint' lies on an */ +/* existing vertex, no action is taken, and the value DUPLICATEPOINT is */ +/* returned. On return, `searchtri' is set to a handle whose origin is the */ +/* existing vertex. */ +/* */ +/* Normally, the parameter `splitedge' is set to NULL, implying that no */ +/* segment should be split. In this case, if `insertpoint' is found to */ +/* lie on a segment, no action is taken, and the value VIOLATINGPOINT is */ +/* returned. On return, `searchtri' is set to a handle whose primary edge */ +/* is the violated segment. */ +/* */ +/* If the calling routine wishes to split a segment by inserting a point in */ +/* it, the parameter `splitedge' should be that segment. In this case, */ +/* `searchtri' MUST be the triangle handle reached by pivoting from that */ +/* segment; no point location is done. */ +/* */ +/* `segmentflaws' and `triflaws' are flags that indicate whether or not */ +/* there should be checks for the creation of encroached segments or bad */ +/* quality faces. If a newly inserted point encroaches upon segments, */ +/* these segments are added to the list of segments to be split if */ +/* `segmentflaws' is set. If bad triangles are created, these are added */ +/* to the queue if `triflaws' is set. */ +/* */ +/* If a duplicate point or violated segment does not prevent the point */ +/* from being inserted, the return value will be ENCROACHINGPOINT if the */ +/* point encroaches upon a segment (and checking is enabled), or */ +/* SUCCESSFULPOINT otherwise. In either case, `searchtri' is set to a */ +/* handle whose origin is the newly inserted vertex. */ +/* */ +/* insertsite() does not use flip() for reasons of speed; some */ +/* information can be reused from edge flip to edge flip, like the */ +/* locations of shell edges. */ +/* */ +/*****************************************************************************/ + +enum insertsiteresult insertsite(insertpoint, searchtri, splitedge, + segmentflaws, triflaws) +point insertpoint; +struct triedge *searchtri; +struct edge *splitedge; +int segmentflaws; +int triflaws; +{ + struct triedge horiz; + struct triedge top; + struct triedge botleft, botright; + struct triedge topleft, topright; + struct triedge newbotleft, newbotright; + struct triedge newtopright; + struct triedge botlcasing, botrcasing; + struct triedge toplcasing, toprcasing; + struct triedge testtri; + struct edge botlshelle, botrshelle; + struct edge toplshelle, toprshelle; + struct edge brokenshelle; + struct edge checkshelle; + struct edge rightedge; + struct edge newedge; + struct edge *encroached; + point first; + point leftpoint, rightpoint, botpoint, toppoint, farpoint; + REAL attrib; + REAL area; + enum insertsiteresult success; + enum locateresult intersect; + int doflip; + int mirrorflag; + int i; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by spivot() and tspivot(). */ + + if (verbose > 1) { + printf(" Inserting (%.12g, %.12g).\n", insertpoint[0], insertpoint[1]); + } + if (splitedge == (struct edge *) NULL) { + /* Find the location of the point to be inserted. Check if a good */ + /* starting triangle has already been provided by the caller. */ + if (searchtri->tri == (triangle *) NULL) { + /* Find a boundary triangle. */ + horiz.tri = dummytri; + horiz.orient = 0; + symself(horiz); + /* Search for a triangle containing `insertpoint'. */ + intersect = locate(insertpoint, &horiz); + } else { + /* Start searching from the triangle provided by the caller. */ + triedgecopy(*searchtri, horiz); + intersect = preciselocate(insertpoint, &horiz); + } + } else { + /* The calling routine provides the edge in which the point is inserted. */ + triedgecopy(*searchtri, horiz); + intersect = ONEDGE; + } + if (intersect == ONVERTEX) { + /* There's already a vertex there. Return in `searchtri' a triangle */ + /* whose origin is the existing vertex. */ + triedgecopy(horiz, *searchtri); + triedgecopy(horiz, recenttri); + return DUPLICATEPOINT; + } + if ((intersect == ONEDGE) || (intersect == OUTSIDE)) { + /* The vertex falls on an edge or boundary. */ + if (checksegments && (splitedge == (struct edge *) NULL)) { + /* Check whether the vertex falls on a shell edge. */ + tspivot(horiz, brokenshelle); + if (brokenshelle.sh != dummysh) { + /* The vertex falls on a shell edge. */ + if (segmentflaws) { + if (nobisect == 0) { + /* Add the shell edge to the list of encroached segments. */ + encroached = (struct edge *) poolalloc(&badsegments); + shellecopy(brokenshelle, *encroached); + } else if ((nobisect == 1) && (intersect == ONEDGE)) { + /* This segment may be split only if it is an internal boundary. */ + sym(horiz, testtri); + if (testtri.tri != dummytri) { + /* Add the shell edge to the list of encroached segments. */ + encroached = (struct edge *) poolalloc(&badsegments); + shellecopy(brokenshelle, *encroached); + } + } + } + /* Return a handle whose primary edge contains the point, */ + /* which has not been inserted. */ + triedgecopy(horiz, *searchtri); + triedgecopy(horiz, recenttri); + return VIOLATINGPOINT; + } + } + /* Insert the point on an edge, dividing one triangle into two (if */ + /* the edge lies on a boundary) or two triangles into four. */ + lprev(horiz, botright); + sym(botright, botrcasing); + sym(horiz, topright); + /* Is there a second triangle? (Or does this edge lie on a boundary?) */ + mirrorflag = topright.tri != dummytri; + if (mirrorflag) { + lnextself(topright); + sym(topright, toprcasing); + maketriangle(&newtopright); + } else { + /* Splitting the boundary edge increases the number of boundary edges. */ + hullsize++; + } + maketriangle(&newbotright); + + /* Set the vertices of changed and new triangles. */ + org(horiz, rightpoint); + dest(horiz, leftpoint); + apex(horiz, botpoint); + setorg(newbotright, botpoint); + setdest(newbotright, rightpoint); + setapex(newbotright, insertpoint); + setorg(horiz, insertpoint); + for (i = 0; i < eextras; i++) { + /* Set the element attributes of a new triangle. */ + setelemattribute(newbotright, i, elemattribute(botright, i)); + } + if (vararea) { + /* Set the area constraint of a new triangle. */ + setareabound(newbotright, areabound(botright)); + } + if (mirrorflag) { + dest(topright, toppoint); + setorg(newtopright, rightpoint); + setdest(newtopright, toppoint); + setapex(newtopright, insertpoint); + setorg(topright, insertpoint); + for (i = 0; i < eextras; i++) { + /* Set the element attributes of another new triangle. */ + setelemattribute(newtopright, i, elemattribute(topright, i)); + } + if (vararea) { + /* Set the area constraint of another new triangle. */ + setareabound(newtopright, areabound(topright)); + } + } + + /* There may be shell edges that need to be bonded */ + /* to the new triangle(s). */ + if (checksegments) { + tspivot(botright, botrshelle); + if (botrshelle.sh != dummysh) { + tsdissolve(botright); + tsbond(newbotright, botrshelle); + } + if (mirrorflag) { + tspivot(topright, toprshelle); + if (toprshelle.sh != dummysh) { + tsdissolve(topright); + tsbond(newtopright, toprshelle); + } + } + } + + /* Bond the new triangle(s) to the surrounding triangles. */ + bond(newbotright, botrcasing); + lprevself(newbotright); + bond(newbotright, botright); + lprevself(newbotright); + if (mirrorflag) { + bond(newtopright, toprcasing); + lnextself(newtopright); + bond(newtopright, topright); + lnextself(newtopright); + bond(newtopright, newbotright); + } + + if (splitedge != (struct edge *) NULL) { + /* Split the shell edge into two. */ + setsdest(*splitedge, insertpoint); + ssymself(*splitedge); + spivot(*splitedge, rightedge); + insertshelle(&newbotright, mark(*splitedge)); + tspivot(newbotright, newedge); + sbond(*splitedge, newedge); + ssymself(newedge); + sbond(newedge, rightedge); + ssymself(*splitedge); + } + +#ifdef SELF_CHECK + if (counterclockwise(rightpoint, leftpoint, botpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle prior to edge point insertion (bottom).\n"); + } + if (mirrorflag) { + if (counterclockwise(leftpoint, rightpoint, toppoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle prior to edge point insertion (top).\n"); + } + if (counterclockwise(rightpoint, toppoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after edge point insertion (top right).\n" + ); + } + if (counterclockwise(toppoint, leftpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after edge point insertion (top left).\n" + ); + } + } + if (counterclockwise(leftpoint, botpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after edge point insertion (bottom left).\n" + ); + } + if (counterclockwise(botpoint, rightpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf( + " Clockwise triangle after edge point insertion (bottom right).\n"); + } +#endif /* SELF_CHECK */ + if (verbose > 2) { + printf(" Updating bottom left "); + printtriangle(&botright); + if (mirrorflag) { + printf(" Updating top left "); + printtriangle(&topright); + printf(" Creating top right "); + printtriangle(&newtopright); + } + printf(" Creating bottom right "); + printtriangle(&newbotright); + } + + /* Position `horiz' on the first edge to check for */ + /* the Delaunay property. */ + lnextself(horiz); + } else { + /* Insert the point in a triangle, splitting it into three. */ + lnext(horiz, botleft); + lprev(horiz, botright); + sym(botleft, botlcasing); + sym(botright, botrcasing); + maketriangle(&newbotleft); + maketriangle(&newbotright); + + /* Set the vertices of changed and new triangles. */ + org(horiz, rightpoint); + dest(horiz, leftpoint); + apex(horiz, botpoint); + setorg(newbotleft, leftpoint); + setdest(newbotleft, botpoint); + setapex(newbotleft, insertpoint); + setorg(newbotright, botpoint); + setdest(newbotright, rightpoint); + setapex(newbotright, insertpoint); + setapex(horiz, insertpoint); + for (i = 0; i < eextras; i++) { + /* Set the element attributes of the new triangles. */ + attrib = elemattribute(horiz, i); + setelemattribute(newbotleft, i, attrib); + setelemattribute(newbotright, i, attrib); + } + if (vararea) { + /* Set the area constraint of the new triangles. */ + area = areabound(horiz); + setareabound(newbotleft, area); + setareabound(newbotright, area); + } + + /* There may be shell edges that need to be bonded */ + /* to the new triangles. */ + if (checksegments) { + tspivot(botleft, botlshelle); + if (botlshelle.sh != dummysh) { + tsdissolve(botleft); + tsbond(newbotleft, botlshelle); + } + tspivot(botright, botrshelle); + if (botrshelle.sh != dummysh) { + tsdissolve(botright); + tsbond(newbotright, botrshelle); + } + } + + /* Bond the new triangles to the surrounding triangles. */ + bond(newbotleft, botlcasing); + bond(newbotright, botrcasing); + lnextself(newbotleft); + lprevself(newbotright); + bond(newbotleft, newbotright); + lnextself(newbotleft); + bond(botleft, newbotleft); + lprevself(newbotright); + bond(botright, newbotright); + +#ifdef SELF_CHECK + if (counterclockwise(rightpoint, leftpoint, botpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle prior to point insertion.\n"); + } + if (counterclockwise(rightpoint, leftpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after point insertion (top).\n"); + } + if (counterclockwise(leftpoint, botpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after point insertion (left).\n"); + } + if (counterclockwise(botpoint, rightpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after point insertion (right).\n"); + } +#endif /* SELF_CHECK */ + if (verbose > 2) { + printf(" Updating top "); + printtriangle(&horiz); + printf(" Creating left "); + printtriangle(&newbotleft); + printf(" Creating right "); + printtriangle(&newbotright); + } + } + + /* The insertion is successful by default, unless an encroached */ + /* edge is found. */ + success = SUCCESSFULPOINT; + /* Circle around the newly inserted vertex, checking each edge opposite */ + /* it for the Delaunay property. Non-Delaunay edges are flipped. */ + /* `horiz' is always the edge being checked. `first' marks where to */ + /* stop circling. */ + org(horiz, first); + rightpoint = first; + dest(horiz, leftpoint); + /* Circle until finished. */ + while (1) { + /* By default, the edge will be flipped. */ + doflip = 1; + if (checksegments) { + /* Check for a segment, which cannot be flipped. */ + tspivot(horiz, checkshelle); + if (checkshelle.sh != dummysh) { + /* The edge is a segment and cannot be flipped. */ + doflip = 0; +#ifndef CDT_ONLY + if (segmentflaws) { + /* Does the new point encroach upon this segment? */ + if (checkedge4encroach(&checkshelle)) { + success = ENCROACHINGPOINT; + } + } +#endif /* not CDT_ONLY */ + } + } + if (doflip) { + /* Check if the edge is a boundary edge. */ + sym(horiz, top); + if (top.tri == dummytri) { + /* The edge is a boundary edge and cannot be flipped. */ + doflip = 0; + } else { + /* Find the point on the other side of the edge. */ + apex(top, farpoint); + /* In the incremental Delaunay triangulation algorithm, any of */ + /* `leftpoint', `rightpoint', and `farpoint' could be vertices */ + /* of the triangular bounding box. These vertices must be */ + /* treated as if they are infinitely distant, even though their */ + /* "coordinates" are not. */ + if ((leftpoint == infpoint1) || (leftpoint == infpoint2) + || (leftpoint == infpoint3)) { + /* `leftpoint' is infinitely distant. Check the convexity of */ + /* the boundary of the triangulation. 'farpoint' might be */ + /* infinite as well, but trust me, this same condition */ + /* should be applied. */ + doflip = counterclockwise(insertpoint, rightpoint, farpoint) > 0.0; + } else if ((rightpoint == infpoint1) || (rightpoint == infpoint2) + || (rightpoint == infpoint3)) { + /* `rightpoint' is infinitely distant. Check the convexity of */ + /* the boundary of the triangulation. 'farpoint' might be */ + /* infinite as well, but trust me, this same condition */ + /* should be applied. */ + doflip = counterclockwise(farpoint, leftpoint, insertpoint) > 0.0; + } else if ((farpoint == infpoint1) || (farpoint == infpoint2) + || (farpoint == infpoint3)) { + /* `farpoint' is infinitely distant and cannot be inside */ + /* the circumcircle of the triangle `horiz'. */ + doflip = 0; + } else { + /* Test whether the edge is locally Delaunay. */ + doflip = incircle(leftpoint, insertpoint, rightpoint, farpoint) + > 0.0; + } + if (doflip) { + /* We made it! Flip the edge `horiz' by rotating its containing */ + /* quadrilateral (the two triangles adjacent to `horiz'). */ + /* Identify the casing of the quadrilateral. */ + lprev(top, topleft); + sym(topleft, toplcasing); + lnext(top, topright); + sym(topright, toprcasing); + lnext(horiz, botleft); + sym(botleft, botlcasing); + lprev(horiz, botright); + sym(botright, botrcasing); + /* Rotate the quadrilateral one-quarter turn counterclockwise. */ + bond(topleft, botlcasing); + bond(botleft, botrcasing); + bond(botright, toprcasing); + bond(topright, toplcasing); + if (checksegments) { + /* Check for shell edges and rebond them to the quadrilateral. */ + tspivot(topleft, toplshelle); + tspivot(botleft, botlshelle); + tspivot(botright, botrshelle); + tspivot(topright, toprshelle); + if (toplshelle.sh == dummysh) { + tsdissolve(topright); + } else { + tsbond(topright, toplshelle); + } + if (botlshelle.sh == dummysh) { + tsdissolve(topleft); + } else { + tsbond(topleft, botlshelle); + } + if (botrshelle.sh == dummysh) { + tsdissolve(botleft); + } else { + tsbond(botleft, botrshelle); + } + if (toprshelle.sh == dummysh) { + tsdissolve(botright); + } else { + tsbond(botright, toprshelle); + } + } + /* New point assignments for the rotated quadrilateral. */ + setorg(horiz, farpoint); + setdest(horiz, insertpoint); + setapex(horiz, rightpoint); + setorg(top, insertpoint); + setdest(top, farpoint); + setapex(top, leftpoint); + for (i = 0; i < eextras; i++) { + /* Take the average of the two triangles' attributes. */ + attrib = (REAL)(0.5 * (elemattribute(top, i) + elemattribute(horiz, i))); + setelemattribute(top, i, attrib); + setelemattribute(horiz, i, attrib); + } + if (vararea) { + if ((areabound(top) <= 0.0) || (areabound(horiz) <= 0.0)) { + area = -1.0; + } else { + /* Take the average of the two triangles' area constraints. */ + /* This prevents small area constraints from migrating a */ + /* long, long way from their original location due to flips. */ + area = (REAL)(0.5 * (areabound(top) + areabound(horiz))); + } + setareabound(top, area); + setareabound(horiz, area); + } +#ifdef SELF_CHECK + if (insertpoint != (point) NULL) { + if (counterclockwise(leftpoint, insertpoint, rightpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle prior to edge flip (bottom).\n"); + } + /* The following test has been removed because constrainededge() */ + /* sometimes generates inverted triangles that insertsite() */ + /* removes. */ +/* + if (counterclockwise(rightpoint, farpoint, leftpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle prior to edge flip (top).\n"); + } +*/ + if (counterclockwise(farpoint, leftpoint, insertpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after edge flip (left).\n"); + } + if (counterclockwise(insertpoint, rightpoint, farpoint) < 0.0) { + printf("Internal error in insertsite():\n"); + printf(" Clockwise triangle after edge flip (right).\n"); + } + } +#endif /* SELF_CHECK */ + if (verbose > 2) { + printf(" Edge flip results in left "); + lnextself(topleft); + printtriangle(&topleft); + printf(" and right "); + printtriangle(&horiz); + } + /* On the next iterations, consider the two edges that were */ + /* exposed (this is, are now visible to the newly inserted */ + /* point) by the edge flip. */ + lprevself(horiz); + leftpoint = farpoint; + } + } + } + if (!doflip) { + /* The handle `horiz' is accepted as locally Delaunay. */ +#ifndef CDT_ONLY + if (triflaws) { + /* Check the triangle `horiz' for quality. */ + testtriangle(&horiz); + } +#endif /* not CDT_ONLY */ + /* Look for the next edge around the newly inserted point. */ + lnextself(horiz); + sym(horiz, testtri); + /* Check for finishing a complete revolution about the new point, or */ + /* falling off the edge of the triangulation. The latter will */ + /* happen when a point is inserted at a boundary. */ + if ((leftpoint == first) || (testtri.tri == dummytri)) { + /* We're done. Return a triangle whose origin is the new point. */ + lnext(horiz, *searchtri); + lnext(horiz, recenttri); + return success; + } + /* Finish finding the next edge around the newly inserted point. */ + lnext(testtri, horiz); + rightpoint = leftpoint; + dest(horiz, leftpoint); + } + } +} + +/*****************************************************************************/ +/* */ +/* triangulatepolygon() Find the Delaunay triangulation of a polygon that */ +/* has a certain "nice" shape. This includes the */ +/* polygons that result from deletion of a point or */ +/* insertion of a segment. */ +/* */ +/* This is a conceptually difficult routine. The starting assumption is */ +/* that we have a polygon with n sides. n - 1 of these sides are currently */ +/* represented as edges in the mesh. One side, called the "base", need not */ +/* be. */ +/* */ +/* Inside the polygon is a structure I call a "fan", consisting of n - 1 */ +/* triangles that share a common origin. For each of these triangles, the */ +/* edge opposite the origin is one of the sides of the polygon. The */ +/* primary edge of each triangle is the edge directed from the origin to */ +/* the destination; note that this is not the same edge that is a side of */ +/* the polygon. `firstedge' is the primary edge of the first triangle. */ +/* From there, the triangles follow in counterclockwise order about the */ +/* polygon, until `lastedge', the primary edge of the last triangle. */ +/* `firstedge' and `lastedge' are probably connected to other triangles */ +/* beyond the extremes of the fan, but their identity is not important, as */ +/* long as the fan remains connected to them. */ +/* */ +/* Imagine the polygon oriented so that its base is at the bottom. This */ +/* puts `firstedge' on the far right, and `lastedge' on the far left. */ +/* The right vertex of the base is the destination of `firstedge', and the */ +/* left vertex of the base is the apex of `lastedge'. */ +/* */ +/* The challenge now is to find the right sequence of edge flips to */ +/* transform the fan into a Delaunay triangulation of the polygon. Each */ +/* edge flip effectively removes one triangle from the fan, committing it */ +/* to the polygon. The resulting polygon has one fewer edge. If `doflip' */ +/* is set, the final flip will be performed, resulting in a fan of one */ +/* (useless?) triangle. If `doflip' is not set, the final flip is not */ +/* performed, resulting in a fan of two triangles, and an unfinished */ +/* triangular polygon that is not yet filled out with a single triangle. */ +/* On completion of the routine, `lastedge' is the last remaining triangle, */ +/* or the leftmost of the last two. */ +/* */ +/* Although the flips are performed in the order described above, the */ +/* decisions about what flips to perform are made in precisely the reverse */ +/* order. The recursive triangulatepolygon() procedure makes a decision, */ +/* uses up to two recursive calls to triangulate the "subproblems" */ +/* (polygons with fewer edges), and then performs an edge flip. */ +/* */ +/* The "decision" it makes is which vertex of the polygon should be */ +/* connected to the base. This decision is made by testing every possible */ +/* vertex. Once the best vertex is found, the two edges that connect this */ +/* vertex to the base become the bases for two smaller polygons. These */ +/* are triangulated recursively. Unfortunately, this approach can take */ +/* O(n^2) time not only in the worst case, but in many common cases. It's */ +/* rarely a big deal for point deletion, where n is rarely larger than ten, */ +/* but it could be a big deal for segment insertion, especially if there's */ +/* a lot of long segments that each cut many triangles. I ought to code */ +/* a faster algorithm some time. */ +/* */ +/* The `edgecount' parameter is the number of sides of the polygon, */ +/* including its base. `triflaws' is a flag that determines whether the */ +/* new triangles should be tested for quality, and enqueued if they are */ +/* bad. */ +/* */ +/*****************************************************************************/ + +void triangulatepolygon(firstedge, lastedge, edgecount, doflip, triflaws) +struct triedge *firstedge; +struct triedge *lastedge; +int edgecount; +int doflip; +int triflaws; +{ + struct triedge testtri; + struct triedge besttri; + struct triedge tempedge; + point leftbasepoint, rightbasepoint; + point testpoint; + point bestpoint; + int bestnumber; + int i; + triangle ptr; /* Temporary variable used by sym(), onext(), and oprev(). */ + + /* Identify the base vertices. */ + apex(*lastedge, leftbasepoint); + dest(*firstedge, rightbasepoint); + if (verbose > 2) { + printf(" Triangulating interior polygon at edge\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g)\n", leftbasepoint[0], + leftbasepoint[1], rightbasepoint[0], rightbasepoint[1]); + } + /* Find the best vertex to connect the base to. */ + onext(*firstedge, besttri); + dest(besttri, bestpoint); + triedgecopy(besttri, testtri); + bestnumber = 1; + for (i = 2; i <= edgecount - 2; i++) { + onextself(testtri); + dest(testtri, testpoint); + /* Is this a better vertex? */ + if (incircle(leftbasepoint, rightbasepoint, bestpoint, testpoint) > 0.0) { + triedgecopy(testtri, besttri); + bestpoint = testpoint; + bestnumber = i; + } + } + if (verbose > 2) { + printf(" Connecting edge to (%.12g, %.12g)\n", bestpoint[0], + bestpoint[1]); + } + if (bestnumber > 1) { + /* Recursively triangulate the smaller polygon on the right. */ + oprev(besttri, tempedge); + triangulatepolygon(firstedge, &tempedge, bestnumber + 1, 1, triflaws); + } + if (bestnumber < edgecount - 2) { + /* Recursively triangulate the smaller polygon on the left. */ + sym(besttri, tempedge); + triangulatepolygon(&besttri, lastedge, edgecount - bestnumber, 1, + triflaws); + /* Find `besttri' again; it may have been lost to edge flips. */ + sym(tempedge, besttri); + } + if (doflip) { + /* Do one final edge flip. */ + flip(&besttri); +#ifndef CDT_ONLY + if (triflaws) { + /* Check the quality of the newly committed triangle. */ + sym(besttri, testtri); + testtriangle(&testtri); + } +#endif /* not CDT_ONLY */ + } + /* Return the base triangle. */ + triedgecopy(besttri, *lastedge); +} + +/*****************************************************************************/ +/* */ +/* deletesite() Delete a vertex from a Delaunay triangulation, ensuring */ +/* that the triangulation remains Delaunay. */ +/* */ +/* The origin of `deltri' is deleted. The union of the triangles adjacent */ +/* to this point is a polygon, for which the Delaunay triangulation is */ +/* found. Two triangles are removed from the mesh. */ +/* */ +/* Only interior points that do not lie on segments (shell edges) or */ +/* boundaries may be deleted. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void deletesite(deltri) +struct triedge *deltri; +{ + struct triedge countingtri; + struct triedge firstedge, lastedge; + struct triedge deltriright; + struct triedge lefttri, righttri; + struct triedge leftcasing, rightcasing; + struct edge leftshelle, rightshelle; + point delpoint; + point neworg; + int edgecount; + triangle ptr; /* Temporary variable used by sym(), onext(), and oprev(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + org(*deltri, delpoint); + if (verbose > 1) { + printf(" Deleting (%.12g, %.12g).\n", delpoint[0], delpoint[1]); + } + pointdealloc(delpoint); + + /* Count the degree of the point being deleted. */ + onext(*deltri, countingtri); + edgecount = 1; + while (!triedgeequal(*deltri, countingtri)) { +#ifdef SELF_CHECK + if (countingtri.tri == dummytri) { + printf("Internal error in deletesite():\n"); + printf(" Attempt to delete boundary point.\n"); + internalerror(); + } +#endif /* SELF_CHECK */ + edgecount++; + onextself(countingtri); + } + +#ifdef SELF_CHECK + if (edgecount < 3) { + printf("Internal error in deletesite():\n Point has degree %d.\n", + edgecount); + internalerror(); + } +#endif /* SELF_CHECK */ + if (edgecount > 3) { + /* Triangulate the polygon defined by the union of all triangles */ + /* adjacent to the point being deleted. Check the quality of */ + /* the resulting triangles. */ + onext(*deltri, firstedge); + oprev(*deltri, lastedge); + triangulatepolygon(&firstedge, &lastedge, edgecount, 0, !nobisect); + } + /* Splice out two triangles. */ + lprev(*deltri, deltriright); + dnext(*deltri, lefttri); + sym(lefttri, leftcasing); + oprev(deltriright, righttri); + sym(righttri, rightcasing); + bond(*deltri, leftcasing); + bond(deltriright, rightcasing); + tspivot(lefttri, leftshelle); + if (leftshelle.sh != dummysh) { + tsbond(*deltri, leftshelle); + } + tspivot(righttri, rightshelle); + if (rightshelle.sh != dummysh) { + tsbond(deltriright, rightshelle); + } + + /* Set the new origin of `deltri' and check its quality. */ + org(lefttri, neworg); + setorg(*deltri, neworg); + if (!nobisect) { + testtriangle(deltri); + } + + /* Delete the two spliced-out triangles. */ + triangledealloc(lefttri.tri); + triangledealloc(righttri.tri); +} + +#endif /* not CDT_ONLY */ + +/** **/ +/** **/ +/********* Mesh transformation routines end here *********/ + +/********* Divide-and-conquer Delaunay triangulation begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* The divide-and-conquer bounding box */ +/* */ +/* I originally implemented the divide-and-conquer and incremental Delaunay */ +/* triangulations using the edge-based data structure presented by Guibas */ +/* and Stolfi. Switching to a triangle-based data structure doubled the */ +/* speed. However, I had to think of a few extra tricks to maintain the */ +/* elegance of the original algorithms. */ +/* */ +/* The "bounding box" used by my variant of the divide-and-conquer */ +/* algorithm uses one triangle for each edge of the convex hull of the */ +/* triangulation. These bounding triangles all share a common apical */ +/* vertex, which is represented by NULL and which represents nothing. */ +/* The bounding triangles are linked in a circular fan about this NULL */ +/* vertex, and the edges on the convex hull of the triangulation appear */ +/* opposite the NULL vertex. You might find it easiest to imagine that */ +/* the NULL vertex is a point in 3D space behind the center of the */ +/* triangulation, and that the bounding triangles form a sort of cone. */ +/* */ +/* This bounding box makes it easy to represent degenerate cases. For */ +/* instance, the triangulation of two vertices is a single edge. This edge */ +/* is represented by two bounding box triangles, one on each "side" of the */ +/* edge. These triangles are also linked together in a fan about the NULL */ +/* vertex. */ +/* */ +/* The bounding box also makes it easy to traverse the convex hull, as the */ +/* divide-and-conquer algorithm needs to do. */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* pointsort() Sort an array of points by x-coordinate, using the */ +/* y-coordinate as a secondary key. */ +/* */ +/* Uses quicksort. Randomized O(n log n) time. No, I did not make any of */ +/* the usual quicksort mistakes. */ +/* */ +/*****************************************************************************/ + +void pointsort(sortarray, arraysize) +point *sortarray; +int arraysize; +{ + int left, right; + int pivot; + REAL pivotx, pivoty; + point temp; + + if (arraysize == 2) { + /* Recursive base case. */ + if ((sortarray[0][0] > sortarray[1][0]) || + ((sortarray[0][0] == sortarray[1][0]) && + (sortarray[0][1] > sortarray[1][1]))) { + temp = sortarray[1]; + sortarray[1] = sortarray[0]; + sortarray[0] = temp; + } + return; + } + /* Choose a random pivot to split the array. */ + pivot = (int) randomnation(arraysize); + pivotx = sortarray[pivot][0]; + pivoty = sortarray[pivot][1]; + /* Split the array. */ + left = -1; + right = arraysize; + while (left < right) { + /* Search for a point whose x-coordinate is too large for the left. */ + do { + left++; + } while ((left <= right) && ((sortarray[left][0] < pivotx) || + ((sortarray[left][0] == pivotx) && + (sortarray[left][1] < pivoty)))); + /* Search for a point whose x-coordinate is too small for the right. */ + do { + right--; + } while ((left <= right) && ((sortarray[right][0] > pivotx) || + ((sortarray[right][0] == pivotx) && + (sortarray[right][1] > pivoty)))); + if (left < right) { + /* Swap the left and right points. */ + temp = sortarray[left]; + sortarray[left] = sortarray[right]; + sortarray[right] = temp; + } + } + if (left > 1) { + /* Recursively sort the left subset. */ + pointsort(sortarray, left); + } + if (right < arraysize - 2) { + /* Recursively sort the right subset. */ + pointsort(&sortarray[right + 1], arraysize - right - 1); + } +} + +/*****************************************************************************/ +/* */ +/* pointmedian() An order statistic algorithm, almost. Shuffles an array */ +/* of points so that the first `median' points occur */ +/* lexicographically before the remaining points. */ +/* */ +/* Uses the x-coordinate as the primary key if axis == 0; the y-coordinate */ +/* if axis == 1. Very similar to the pointsort() procedure, but runs in */ +/* randomized linear time. */ +/* */ +/*****************************************************************************/ + +void pointmedian(sortarray, arraysize, median, axis) +point *sortarray; +int arraysize; +int median; +int axis; +{ + int left, right; + int pivot; + REAL pivot1, pivot2; + point temp; + + if (arraysize == 2) { + /* Recursive base case. */ + if ((sortarray[0][axis] > sortarray[1][axis]) || + ((sortarray[0][axis] == sortarray[1][axis]) && + (sortarray[0][1 - axis] > sortarray[1][1 - axis]))) { + temp = sortarray[1]; + sortarray[1] = sortarray[0]; + sortarray[0] = temp; + } + return; + } + /* Choose a random pivot to split the array. */ + pivot = (int) randomnation(arraysize); + pivot1 = sortarray[pivot][axis]; + pivot2 = sortarray[pivot][1 - axis]; + /* Split the array. */ + left = -1; + right = arraysize; + while (left < right) { + /* Search for a point whose x-coordinate is too large for the left. */ + do { + left++; + } while ((left <= right) && ((sortarray[left][axis] < pivot1) || + ((sortarray[left][axis] == pivot1) && + (sortarray[left][1 - axis] < pivot2)))); + /* Search for a point whose x-coordinate is too small for the right. */ + do { + right--; + } while ((left <= right) && ((sortarray[right][axis] > pivot1) || + ((sortarray[right][axis] == pivot1) && + (sortarray[right][1 - axis] > pivot2)))); + if (left < right) { + /* Swap the left and right points. */ + temp = sortarray[left]; + sortarray[left] = sortarray[right]; + sortarray[right] = temp; + } + } + /* Unlike in pointsort(), at most one of the following */ + /* conditionals is true. */ + if (left > median) { + /* Recursively shuffle the left subset. */ + pointmedian(sortarray, left, median, axis); + } + if (right < median - 1) { + /* Recursively shuffle the right subset. */ + pointmedian(&sortarray[right + 1], arraysize - right - 1, + median - right - 1, axis); + } +} + +/*****************************************************************************/ +/* */ +/* alternateaxes() Sorts the points as appropriate for the divide-and- */ +/* conquer algorithm with alternating cuts. */ +/* */ +/* Partitions by x-coordinate if axis == 0; by y-coordinate if axis == 1. */ +/* For the base case, subsets containing only two or three points are */ +/* always sorted by x-coordinate. */ +/* */ +/*****************************************************************************/ + +void alternateaxes(sortarray, arraysize, axis) +point *sortarray; +int arraysize; +int axis; +{ + int divider; + + divider = arraysize >> 1; + if (arraysize <= 3) { + /* Recursive base case: subsets of two or three points will be */ + /* handled specially, and should always be sorted by x-coordinate. */ + axis = 0; + } + /* Partition with a horizontal or vertical cut. */ + pointmedian(sortarray, arraysize, divider, axis); + /* Recursively partition the subsets with a cross cut. */ + if (arraysize - divider >= 2) { + if (divider >= 2) { + alternateaxes(sortarray, divider, 1 - axis); + } + alternateaxes(&sortarray[divider], arraysize - divider, 1 - axis); + } +} + +/*****************************************************************************/ +/* */ +/* mergehulls() Merge two adjacent Delaunay triangulations into a */ +/* single Delaunay triangulation. */ +/* */ +/* This is similar to the algorithm given by Guibas and Stolfi, but uses */ +/* a triangle-based, rather than edge-based, data structure. */ +/* */ +/* The algorithm walks up the gap between the two triangulations, knitting */ +/* them together. As they are merged, some of their bounding triangles */ +/* are converted into real triangles of the triangulation. The procedure */ +/* pulls each hull's bounding triangles apart, then knits them together */ +/* like the teeth of two gears. The Delaunay property determines, at each */ +/* step, whether the next "tooth" is a bounding triangle of the left hull */ +/* or the right. When a bounding triangle becomes real, its apex is */ +/* changed from NULL to a real point. */ +/* */ +/* Only two new triangles need to be allocated. These become new bounding */ +/* triangles at the top and bottom of the seam. They are used to connect */ +/* the remaining bounding triangles (those that have not been converted */ +/* into real triangles) into a single fan. */ +/* */ +/* On entry, `farleft' and `innerleft' are bounding triangles of the left */ +/* triangulation. The origin of `farleft' is the leftmost vertex, and */ +/* the destination of `innerleft' is the rightmost vertex of the */ +/* triangulation. Similarly, `innerright' and `farright' are bounding */ +/* triangles of the right triangulation. The origin of `innerright' and */ +/* destination of `farright' are the leftmost and rightmost vertices. */ +/* */ +/* On completion, the origin of `farleft' is the leftmost vertex of the */ +/* merged triangulation, and the destination of `farright' is the rightmost */ +/* vertex. */ +/* */ +/*****************************************************************************/ + +void mergehulls(farleft, innerleft, innerright, farright, axis) +struct triedge *farleft; +struct triedge *innerleft; +struct triedge *innerright; +struct triedge *farright; +int axis; +{ + struct triedge leftcand, rightcand; + struct triedge baseedge; + struct triedge nextedge; + struct triedge sidecasing, topcasing, outercasing; + struct triedge checkedge; + point innerleftdest; + point innerrightorg; + point innerleftapex, innerrightapex; + point farleftpt, farrightpt; + point farleftapex, farrightapex; + point lowerleft, lowerright; + point upperleft, upperright; + point nextapex; + point checkvertex; + int changemade; + int badedge; + int leftfinished, rightfinished; + triangle ptr; /* Temporary variable used by sym(). */ + + dest(*innerleft, innerleftdest); + apex(*innerleft, innerleftapex); + org(*innerright, innerrightorg); + apex(*innerright, innerrightapex); + /* Special treatment for horizontal cuts. */ + if (dwyer && (axis == 1)) { + org(*farleft, farleftpt); + apex(*farleft, farleftapex); + dest(*farright, farrightpt); + apex(*farright, farrightapex); + /* The pointers to the extremal points are shifted to point to the */ + /* topmost and bottommost point of each hull, rather than the */ + /* leftmost and rightmost points. */ + while (farleftapex[1] < farleftpt[1]) { + lnextself(*farleft); + symself(*farleft); + farleftpt = farleftapex; + apex(*farleft, farleftapex); + } + sym(*innerleft, checkedge); + apex(checkedge, checkvertex); + while (checkvertex[1] > innerleftdest[1]) { + lnext(checkedge, *innerleft); + innerleftapex = innerleftdest; + innerleftdest = checkvertex; + sym(*innerleft, checkedge); + apex(checkedge, checkvertex); + } + while (innerrightapex[1] < innerrightorg[1]) { + lnextself(*innerright); + symself(*innerright); + innerrightorg = innerrightapex; + apex(*innerright, innerrightapex); + } + sym(*farright, checkedge); + apex(checkedge, checkvertex); + while (checkvertex[1] > farrightpt[1]) { + lnext(checkedge, *farright); + farrightapex = farrightpt; + farrightpt = checkvertex; + sym(*farright, checkedge); + apex(checkedge, checkvertex); + } + } + /* Find a line tangent to and below both hulls. */ + do { + changemade = 0; + /* Make innerleftdest the "bottommost" point of the left hull. */ + if (counterclockwise(innerleftdest, innerleftapex, innerrightorg) > 0.0) { + lprevself(*innerleft); + symself(*innerleft); + innerleftdest = innerleftapex; + apex(*innerleft, innerleftapex); + changemade = 1; + } + /* Make innerrightorg the "bottommost" point of the right hull. */ + if (counterclockwise(innerrightapex, innerrightorg, innerleftdest) > 0.0) { + lnextself(*innerright); + symself(*innerright); + innerrightorg = innerrightapex; + apex(*innerright, innerrightapex); + changemade = 1; + } + } while (changemade); + /* Find the two candidates to be the next "gear tooth". */ + sym(*innerleft, leftcand); + sym(*innerright, rightcand); + /* Create the bottom new bounding triangle. */ + maketriangle(&baseedge); + /* Connect it to the bounding boxes of the left and right triangulations. */ + bond(baseedge, *innerleft); + lnextself(baseedge); + bond(baseedge, *innerright); + lnextself(baseedge); + setorg(baseedge, innerrightorg); + setdest(baseedge, innerleftdest); + /* Apex is intentionally left NULL. */ + if (verbose > 2) { + printf(" Creating base bounding "); + printtriangle(&baseedge); + } + /* Fix the extreme triangles if necessary. */ + org(*farleft, farleftpt); + if (innerleftdest == farleftpt) { + lnext(baseedge, *farleft); + } + dest(*farright, farrightpt); + if (innerrightorg == farrightpt) { + lprev(baseedge, *farright); + } + /* The vertices of the current knitting edge. */ + lowerleft = innerleftdest; + lowerright = innerrightorg; + /* The candidate vertices for knitting. */ + apex(leftcand, upperleft); + apex(rightcand, upperright); + /* Walk up the gap between the two triangulations, knitting them together. */ + while (1) { + /* Have we reached the top? (This isn't quite the right question, */ + /* because even though the left triangulation might seem finished now, */ + /* moving up on the right triangulation might reveal a new point of */ + /* the left triangulation. And vice-versa.) */ + leftfinished = counterclockwise(upperleft, lowerleft, lowerright) <= 0.0; + rightfinished = counterclockwise(upperright, lowerleft, lowerright) <= 0.0; + if (leftfinished && rightfinished) { + /* Create the top new bounding triangle. */ + maketriangle(&nextedge); + setorg(nextedge, lowerleft); + setdest(nextedge, lowerright); + /* Apex is intentionally left NULL. */ + /* Connect it to the bounding boxes of the two triangulations. */ + bond(nextedge, baseedge); + lnextself(nextedge); + bond(nextedge, rightcand); + lnextself(nextedge); + bond(nextedge, leftcand); + if (verbose > 2) { + printf(" Creating top bounding "); + printtriangle(&baseedge); + } + /* Special treatment for horizontal cuts. */ + if (dwyer && (axis == 1)) { + org(*farleft, farleftpt); + apex(*farleft, farleftapex); + dest(*farright, farrightpt); + apex(*farright, farrightapex); + sym(*farleft, checkedge); + apex(checkedge, checkvertex); + /* The pointers to the extremal points are restored to the leftmost */ + /* and rightmost points (rather than topmost and bottommost). */ + while (checkvertex[0] < farleftpt[0]) { + lprev(checkedge, *farleft); + farleftapex = farleftpt; + farleftpt = checkvertex; + sym(*farleft, checkedge); + apex(checkedge, checkvertex); + } + while (farrightapex[0] > farrightpt[0]) { + lprevself(*farright); + symself(*farright); + farrightpt = farrightapex; + apex(*farright, farrightapex); + } + } + return; + } + /* Consider eliminating edges from the left triangulation. */ + if (!leftfinished) { + /* What vertex would be exposed if an edge were deleted? */ + lprev(leftcand, nextedge); + symself(nextedge); + apex(nextedge, nextapex); + /* If nextapex is NULL, then no vertex would be exposed; the */ + /* triangulation would have been eaten right through. */ + if (nextapex != (point) NULL) { + /* Check whether the edge is Delaunay. */ + badedge = incircle(lowerleft, lowerright, upperleft, nextapex) > 0.0; + while (badedge) { + /* Eliminate the edge with an edge flip. As a result, the */ + /* left triangulation will have one more boundary triangle. */ + lnextself(nextedge); + sym(nextedge, topcasing); + lnextself(nextedge); + sym(nextedge, sidecasing); + bond(nextedge, topcasing); + bond(leftcand, sidecasing); + lnextself(leftcand); + sym(leftcand, outercasing); + lprevself(nextedge); + bond(nextedge, outercasing); + /* Correct the vertices to reflect the edge flip. */ + setorg(leftcand, lowerleft); + setdest(leftcand, NULL); + setapex(leftcand, nextapex); + setorg(nextedge, NULL); + setdest(nextedge, upperleft); + setapex(nextedge, nextapex); + /* Consider the newly exposed vertex. */ + upperleft = nextapex; + /* What vertex would be exposed if another edge were deleted? */ + triedgecopy(sidecasing, nextedge); + apex(nextedge, nextapex); + if (nextapex != (point) NULL) { + /* Check whether the edge is Delaunay. */ + badedge = incircle(lowerleft, lowerright, upperleft, nextapex) + > 0.0; + } else { + /* Avoid eating right through the triangulation. */ + badedge = 0; + } + } + } + } + /* Consider eliminating edges from the right triangulation. */ + if (!rightfinished) { + /* What vertex would be exposed if an edge were deleted? */ + lnext(rightcand, nextedge); + symself(nextedge); + apex(nextedge, nextapex); + /* If nextapex is NULL, then no vertex would be exposed; the */ + /* triangulation would have been eaten right through. */ + if (nextapex != (point) NULL) { + /* Check whether the edge is Delaunay. */ + badedge = incircle(lowerleft, lowerright, upperright, nextapex) > 0.0; + while (badedge) { + /* Eliminate the edge with an edge flip. As a result, the */ + /* right triangulation will have one more boundary triangle. */ + lprevself(nextedge); + sym(nextedge, topcasing); + lprevself(nextedge); + sym(nextedge, sidecasing); + bond(nextedge, topcasing); + bond(rightcand, sidecasing); + lprevself(rightcand); + sym(rightcand, outercasing); + lnextself(nextedge); + bond(nextedge, outercasing); + /* Correct the vertices to reflect the edge flip. */ + setorg(rightcand, NULL); + setdest(rightcand, lowerright); + setapex(rightcand, nextapex); + setorg(nextedge, upperright); + setdest(nextedge, NULL); + setapex(nextedge, nextapex); + /* Consider the newly exposed vertex. */ + upperright = nextapex; + /* What vertex would be exposed if another edge were deleted? */ + triedgecopy(sidecasing, nextedge); + apex(nextedge, nextapex); + if (nextapex != (point) NULL) { + /* Check whether the edge is Delaunay. */ + badedge = incircle(lowerleft, lowerright, upperright, nextapex) + > 0.0; + } else { + /* Avoid eating right through the triangulation. */ + badedge = 0; + } + } + } + } + if (leftfinished || (!rightfinished && + (incircle(upperleft, lowerleft, lowerright, upperright) > 0.0))) { + /* Knit the triangulations, adding an edge from `lowerleft' */ + /* to `upperright'. */ + bond(baseedge, rightcand); + lprev(rightcand, baseedge); + setdest(baseedge, lowerleft); + lowerright = upperright; + sym(baseedge, rightcand); + apex(rightcand, upperright); + } else { + /* Knit the triangulations, adding an edge from `upperleft' */ + /* to `lowerright'. */ + bond(baseedge, leftcand); + lnext(leftcand, baseedge); + setorg(baseedge, lowerright); + lowerleft = upperleft; + sym(baseedge, leftcand); + apex(leftcand, upperleft); + } + if (verbose > 2) { + printf(" Connecting "); + printtriangle(&baseedge); + } + } +} + +/*****************************************************************************/ +/* */ +/* divconqrecurse() Recursively form a Delaunay triangulation by the */ +/* divide-and-conquer method. */ +/* */ +/* Recursively breaks down the problem into smaller pieces, which are */ +/* knitted together by mergehulls(). The base cases (problems of two or */ +/* three points) are handled specially here. */ +/* */ +/* On completion, `farleft' and `farright' are bounding triangles such that */ +/* the origin of `farleft' is the leftmost vertex (breaking ties by */ +/* choosing the highest leftmost vertex), and the destination of */ +/* `farright' is the rightmost vertex (breaking ties by choosing the */ +/* lowest rightmost vertex). */ +/* */ +/*****************************************************************************/ + +void divconqrecurse(sortarray, vertices, axis, farleft, farright) +point *sortarray; +int vertices; +int axis; +struct triedge *farleft; +struct triedge *farright; +{ + struct triedge midtri, tri1, tri2, tri3; + struct triedge innerleft, innerright; + REAL area; + int divider; + + if (verbose > 2) { + printf(" Triangulating %d points.\n", vertices); + } + if (vertices == 2) { + /* The triangulation of two vertices is an edge. An edge is */ + /* represented by two bounding triangles. */ + maketriangle(farleft); + setorg(*farleft, sortarray[0]); + setdest(*farleft, sortarray[1]); + /* The apex is intentionally left NULL. */ + maketriangle(farright); + setorg(*farright, sortarray[1]); + setdest(*farright, sortarray[0]); + /* The apex is intentionally left NULL. */ + bond(*farleft, *farright); + lprevself(*farleft); + lnextself(*farright); + bond(*farleft, *farright); + lprevself(*farleft); + lnextself(*farright); + bond(*farleft, *farright); + if (verbose > 2) { + printf(" Creating "); + printtriangle(farleft); + printf(" Creating "); + printtriangle(farright); + } + /* Ensure that the origin of `farleft' is sortarray[0]. */ + lprev(*farright, *farleft); + return; + } else if (vertices == 3) { + /* The triangulation of three vertices is either a triangle (with */ + /* three bounding triangles) or two edges (with four bounding */ + /* triangles). In either case, four triangles are created. */ + maketriangle(&midtri); + maketriangle(&tri1); + maketriangle(&tri2); + maketriangle(&tri3); + area = counterclockwise(sortarray[0], sortarray[1], sortarray[2]); + if (area == 0.0) { + /* Three collinear points; the triangulation is two edges. */ + setorg(midtri, sortarray[0]); + setdest(midtri, sortarray[1]); + setorg(tri1, sortarray[1]); + setdest(tri1, sortarray[0]); + setorg(tri2, sortarray[2]); + setdest(tri2, sortarray[1]); + setorg(tri3, sortarray[1]); + setdest(tri3, sortarray[2]); + /* All apices are intentionally left NULL. */ + bond(midtri, tri1); + bond(tri2, tri3); + lnextself(midtri); + lprevself(tri1); + lnextself(tri2); + lprevself(tri3); + bond(midtri, tri3); + bond(tri1, tri2); + lnextself(midtri); + lprevself(tri1); + lnextself(tri2); + lprevself(tri3); + bond(midtri, tri1); + bond(tri2, tri3); + /* Ensure that the origin of `farleft' is sortarray[0]. */ + triedgecopy(tri1, *farleft); + /* Ensure that the destination of `farright' is sortarray[2]. */ + triedgecopy(tri2, *farright); + } else { + /* The three points are not collinear; the triangulation is one */ + /* triangle, namely `midtri'. */ + setorg(midtri, sortarray[0]); + setdest(tri1, sortarray[0]); + setorg(tri3, sortarray[0]); + /* Apices of tri1, tri2, and tri3 are left NULL. */ + if (area > 0.0) { + /* The vertices are in counterclockwise order. */ + setdest(midtri, sortarray[1]); + setorg(tri1, sortarray[1]); + setdest(tri2, sortarray[1]); + setapex(midtri, sortarray[2]); + setorg(tri2, sortarray[2]); + setdest(tri3, sortarray[2]); + } else { + /* The vertices are in clockwise order. */ + setdest(midtri, sortarray[2]); + setorg(tri1, sortarray[2]); + setdest(tri2, sortarray[2]); + setapex(midtri, sortarray[1]); + setorg(tri2, sortarray[1]); + setdest(tri3, sortarray[1]); + } + /* The topology does not depend on how the vertices are ordered. */ + bond(midtri, tri1); + lnextself(midtri); + bond(midtri, tri2); + lnextself(midtri); + bond(midtri, tri3); + lprevself(tri1); + lnextself(tri2); + bond(tri1, tri2); + lprevself(tri1); + lprevself(tri3); + bond(tri1, tri3); + lnextself(tri2); + lprevself(tri3); + bond(tri2, tri3); + /* Ensure that the origin of `farleft' is sortarray[0]. */ + triedgecopy(tri1, *farleft); + /* Ensure that the destination of `farright' is sortarray[2]. */ + if (area > 0.0) { + triedgecopy(tri2, *farright); + } else { + lnext(*farleft, *farright); + } + } + if (verbose > 2) { + printf(" Creating "); + printtriangle(&midtri); + printf(" Creating "); + printtriangle(&tri1); + printf(" Creating "); + printtriangle(&tri2); + printf(" Creating "); + printtriangle(&tri3); + } + return; + } else { + /* Split the vertices in half. */ + divider = vertices >> 1; + /* Recursively triangulate each half. */ + divconqrecurse(sortarray, divider, 1 - axis, farleft, &innerleft); + divconqrecurse(&sortarray[divider], vertices - divider, 1 - axis, + &innerright, farright); + if (verbose > 1) { + printf(" Joining triangulations with %d and %d vertices.\n", divider, + vertices - divider); + } + /* Merge the two triangulations into one. */ + mergehulls(farleft, &innerleft, &innerright, farright, axis); + } +} + +long removeghosts(startghost) +struct triedge *startghost; +{ + struct triedge searchedge; + struct triedge dissolveedge; + struct triedge deadtri; + point markorg; + long hullsize; + triangle ptr; /* Temporary variable used by sym(). */ + + if (verbose) { + printf(" Removing ghost triangles.\n"); + } + /* Find an edge on the convex hull to start point location from. */ + lprev(*startghost, searchedge); + symself(searchedge); + dummytri[0] = encode(searchedge); + /* Remove the bounding box and count the convex hull edges. */ + triedgecopy(*startghost, dissolveedge); + hullsize = 0; + do { + hullsize++; + lnext(dissolveedge, deadtri); + lprevself(dissolveedge); + symself(dissolveedge); + /* If no PSLG is involved, set the boundary markers of all the points */ + /* on the convex hull. If a PSLG is used, this step is done later. */ + if (!poly) { + /* Watch out for the case where all the input points are collinear. */ + if (dissolveedge.tri != dummytri) { + org(dissolveedge, markorg); + if (pointmark(markorg) == 0) { + setpointmark(markorg, 1); + } + } + } + /* Remove a bounding triangle from a convex hull triangle. */ + dissolve(dissolveedge); + /* Find the next bounding triangle. */ + sym(deadtri, dissolveedge); + /* Delete the bounding triangle. */ + triangledealloc(deadtri.tri); + } while (!triedgeequal(dissolveedge, *startghost)); + return hullsize; +} + +/*****************************************************************************/ +/* */ +/* divconqdelaunay() Form a Delaunay triangulation by the divide-and- */ +/* conquer method. */ +/* */ +/* Sorts the points, calls a recursive procedure to triangulate them, and */ +/* removes the bounding box, setting boundary markers as appropriate. */ +/* */ +/*****************************************************************************/ + +long divconqdelaunay() +{ + point *sortarray; + struct triedge hullleft, hullright; + int divider; + int i, j; + + /* Allocate an array of pointers to points for sorting. */ + sortarray = (point *) malloc(inpoints * sizeof(point)); + if (sortarray == (point *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + traversalinit(&points); + for (i = 0; i < inpoints; i++) { + sortarray[i] = pointtraverse(); + } + if (verbose) { + printf(" Sorting points.\n"); + } + /* Sort the points. */ + pointsort(sortarray, inpoints); + /* Discard duplicate points, which can really mess up the algorithm. */ + i = 0; + for (j = 1; j < inpoints; j++) { + if ((sortarray[i][0] == sortarray[j][0]) + && (sortarray[i][1] == sortarray[j][1])) { + if (!quiet) { + printf( +"Warning: A duplicate point at (%.12g, %.12g) appeared and was ignored.\n", + sortarray[j][0], sortarray[j][1]); + } +/* Commented out - would eliminate point from output .node file, but causes + a failure if some segment has this point as an endpoint. + setpointmark(sortarray[j], DEADPOINT); +*/ + } else { + i++; + sortarray[i] = sortarray[j]; + } + } + i++; + if (dwyer) { + /* Re-sort the array of points to accommodate alternating cuts. */ + divider = i >> 1; + if (i - divider >= 2) { + if (divider >= 2) { + alternateaxes(sortarray, divider, 1); + } + alternateaxes(&sortarray[divider], i - divider, 1); + } + } + if (verbose) { + printf(" Forming triangulation.\n"); + } + /* Form the Delaunay triangulation. */ + divconqrecurse(sortarray, i, 0, &hullleft, &hullright); + free(sortarray); + + return removeghosts(&hullleft); +} + +/** **/ +/** **/ +/********* Divide-and-conquer Delaunay triangulation ends here *********/ + +/********* Incremental Delaunay triangulation begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* boundingbox() Form an "infinite" bounding triangle to insert points */ +/* into. */ +/* */ +/* The points at "infinity" are assigned finite coordinates, which are used */ +/* by the point location routines, but (mostly) ignored by the Delaunay */ +/* edge flip routines. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +void boundingbox() +{ + struct triedge inftri; /* Handle for the triangular bounding box. */ + REAL width; + + if (verbose) { + printf(" Creating triangular bounding box.\n"); + } + /* Find the width (or height, whichever is larger) of the triangulation. */ + width = xmax - xmin; + if (ymax - ymin > width) { + width = ymax - ymin; + } + if (width == 0.0) { + width = 1.0; + } + /* Create the vertices of the bounding box. */ + infpoint1 = (point) malloc(points.itembytes); + infpoint2 = (point) malloc(points.itembytes); + infpoint3 = (point) malloc(points.itembytes); + if ((infpoint1 == (point) NULL) || (infpoint2 == (point) NULL) + || (infpoint3 == (point) NULL)) { + printf("Error: Out of memory.\n"); + exit(1); + } + infpoint1[0] = xmin - 50.0 * width; + infpoint1[1] = ymin - 40.0 * width; + infpoint2[0] = xmax + 50.0 * width; + infpoint2[1] = ymin - 40.0 * width; + infpoint3[0] = 0.5 * (xmin + xmax); + infpoint3[1] = ymax + 60.0 * width; + + /* Create the bounding box. */ + maketriangle(&inftri); + setorg(inftri, infpoint1); + setdest(inftri, infpoint2); + setapex(inftri, infpoint3); + /* Link dummytri to the bounding box so we can always find an */ + /* edge to begin searching (point location) from. */ + dummytri[0] = (triangle) inftri.tri; + if (verbose > 2) { + printf(" Creating "); + printtriangle(&inftri); + } +} + +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* removebox() Remove the "infinite" bounding triangle, setting boundary */ +/* markers as appropriate. */ +/* */ +/* The triangular bounding box has three boundary triangles (one for each */ +/* side of the bounding box), and a bunch of triangles fanning out from */ +/* the three bounding box vertices (one triangle for each edge of the */ +/* convex hull of the inner mesh). This routine removes these triangles. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +long removebox() +{ + struct triedge deadtri; + struct triedge searchedge; + struct triedge checkedge; + struct triedge nextedge, finaledge, dissolveedge; + point markorg; + long hullsize; + triangle ptr; /* Temporary variable used by sym(). */ + + if (verbose) { + printf(" Removing triangular bounding box.\n"); + } + /* Find a boundary triangle. */ + nextedge.tri = dummytri; + nextedge.orient = 0; + symself(nextedge); + /* Mark a place to stop. */ + lprev(nextedge, finaledge); + lnextself(nextedge); + symself(nextedge); + /* Find a triangle (on the boundary of the point set) that isn't */ + /* a bounding box triangle. */ + lprev(nextedge, searchedge); + symself(searchedge); + /* Check whether nextedge is another boundary triangle */ + /* adjacent to the first one. */ + lnext(nextedge, checkedge); + symself(checkedge); + if (checkedge.tri == dummytri) { + /* Go on to the next triangle. There are only three boundary */ + /* triangles, and this next triangle cannot be the third one, */ + /* so it's safe to stop here. */ + lprevself(searchedge); + symself(searchedge); + } + /* Find a new boundary edge to search from, as the current search */ + /* edge lies on a bounding box triangle and will be deleted. */ + dummytri[0] = encode(searchedge); + hullsize = -2l; + while (!triedgeequal(nextedge, finaledge)) { + hullsize++; + lprev(nextedge, dissolveedge); + symself(dissolveedge); + /* If not using a PSLG, the vertices should be marked now. */ + /* (If using a PSLG, markhull() will do the job.) */ + if (!poly) { + /* Be careful! One must check for the case where all the input */ + /* points are collinear, and thus all the triangles are part of */ + /* the bounding box. Otherwise, the setpointmark() call below */ + /* will cause a bad pointer reference. */ + if (dissolveedge.tri != dummytri) { + org(dissolveedge, markorg); + if (pointmark(markorg) == 0) { + setpointmark(markorg, 1); + } + } + } + /* Disconnect the bounding box triangle from the mesh triangle. */ + dissolve(dissolveedge); + lnext(nextedge, deadtri); + sym(deadtri, nextedge); + /* Get rid of the bounding box triangle. */ + triangledealloc(deadtri.tri); + /* Do we need to turn the corner? */ + if (nextedge.tri == dummytri) { + /* Turn the corner. */ + triedgecopy(dissolveedge, nextedge); + } + } + triangledealloc(finaledge.tri); + + free(infpoint1); /* Deallocate the bounding box vertices. */ + free(infpoint2); + free(infpoint3); + + return hullsize; +} + +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* incrementaldelaunay() Form a Delaunay triangulation by incrementally */ +/* adding vertices. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED + +long incrementaldelaunay() +{ + struct triedge starttri; + point pointloop; + int i; + + /* Create a triangular bounding box. */ + boundingbox(); + if (verbose) { + printf(" Incrementally inserting points.\n"); + } + traversalinit(&points); + pointloop = pointtraverse(); + i = 1; + while (pointloop != (point) NULL) { + /* Find a boundary triangle to search from. */ + starttri.tri = (triangle *) NULL; + if (insertsite(pointloop, &starttri, (struct edge *) NULL, 0, 0) == + DUPLICATEPOINT) { + if (!quiet) { + printf( +"Warning: A duplicate point at (%.12g, %.12g) appeared and was ignored.\n", + pointloop[0], pointloop[1]); + } +/* Commented out - would eliminate point from output .node file. + setpointmark(pointloop, DEADPOINT); +*/ + } + pointloop = pointtraverse(); + i++; + } + /* Remove the bounding box. */ + return removebox(); +} + +#endif /* not REDUCED */ + +/** **/ +/** **/ +/********* Incremental Delaunay triangulation ends here *********/ + +/********* Sweepline Delaunay triangulation begins here *********/ +/** **/ +/** **/ + +#ifndef REDUCED + +void eventheapinsert(heap, heapsize, newevent) +struct event **heap; +int heapsize; +struct event *newevent; +{ + REAL eventx, eventy; + int eventnum; + int parent; + int notdone; + + eventx = newevent->xkey; + eventy = newevent->ykey; + eventnum = heapsize; + notdone = eventnum > 0; + while (notdone) { + parent = (eventnum - 1) >> 1; + if ((heap[parent]->ykey < eventy) || + ((heap[parent]->ykey == eventy) + && (heap[parent]->xkey <= eventx))) { + notdone = 0; + } else { + heap[eventnum] = heap[parent]; + heap[eventnum]->heapposition = eventnum; + + eventnum = parent; + notdone = eventnum > 0; + } + } + heap[eventnum] = newevent; + newevent->heapposition = eventnum; +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +void eventheapify(heap, heapsize, eventnum) +struct event **heap; +int heapsize; +int eventnum; +{ + struct event *thisevent; + REAL eventx, eventy; + int leftchild, rightchild; + int smallest; + int notdone; + + thisevent = heap[eventnum]; + eventx = thisevent->xkey; + eventy = thisevent->ykey; + leftchild = 2 * eventnum + 1; + notdone = leftchild < heapsize; + while (notdone) { + if ((heap[leftchild]->ykey < eventy) || + ((heap[leftchild]->ykey == eventy) + && (heap[leftchild]->xkey < eventx))) { + smallest = leftchild; + } else { + smallest = eventnum; + } + rightchild = leftchild + 1; + if (rightchild < heapsize) { + if ((heap[rightchild]->ykey < heap[smallest]->ykey) || + ((heap[rightchild]->ykey == heap[smallest]->ykey) + && (heap[rightchild]->xkey < heap[smallest]->xkey))) { + smallest = rightchild; + } + } + if (smallest == eventnum) { + notdone = 0; + } else { + heap[eventnum] = heap[smallest]; + heap[eventnum]->heapposition = eventnum; + heap[smallest] = thisevent; + thisevent->heapposition = smallest; + + eventnum = smallest; + leftchild = 2 * eventnum + 1; + notdone = leftchild < heapsize; + } + } +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +void eventheapdelete(heap, heapsize, eventnum) +struct event **heap; +int heapsize; +int eventnum; +{ + struct event *moveevent; + REAL eventx, eventy; + int parent; + int notdone; + + moveevent = heap[heapsize - 1]; + if (eventnum > 0) { + eventx = moveevent->xkey; + eventy = moveevent->ykey; + do { + parent = (eventnum - 1) >> 1; + if ((heap[parent]->ykey < eventy) || + ((heap[parent]->ykey == eventy) + && (heap[parent]->xkey <= eventx))) { + notdone = 0; + } else { + heap[eventnum] = heap[parent]; + heap[eventnum]->heapposition = eventnum; + + eventnum = parent; + notdone = eventnum > 0; + } + } while (notdone); + } + heap[eventnum] = moveevent; + moveevent->heapposition = eventnum; + eventheapify(heap, heapsize - 1, eventnum); +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +void createeventheap(eventheap, events, freeevents) +struct event ***eventheap; +struct event **events; +struct event **freeevents; +{ + point thispoint; + int maxevents; + int i; + + maxevents = (3 * inpoints) / 2; + *eventheap = (struct event **) malloc(maxevents * sizeof(struct event *)); + if (*eventheap == (struct event **) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + *events = (struct event *) malloc(maxevents * sizeof(struct event)); + if (*events == (struct event *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + traversalinit(&points); + for (i = 0; i < inpoints; i++) { + thispoint = pointtraverse(); + (*events)[i].eventptr = (VOID *) thispoint; + (*events)[i].xkey = thispoint[0]; + (*events)[i].ykey = thispoint[1]; + eventheapinsert(*eventheap, i, *events + i); + } + *freeevents = (struct event *) NULL; + for (i = maxevents - 1; i >= inpoints; i--) { + (*events)[i].eventptr = (VOID *) *freeevents; + *freeevents = *events + i; + } +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +int rightofhyperbola(fronttri, newsite) +struct triedge *fronttri; +point newsite; +{ + point leftpoint, rightpoint; + REAL dxa, dya, dxb, dyb; + + hyperbolacount++; + + dest(*fronttri, leftpoint); + apex(*fronttri, rightpoint); + if ((leftpoint[1] < rightpoint[1]) + || ((leftpoint[1] == rightpoint[1]) && (leftpoint[0] < rightpoint[0]))) { + if (newsite[0] >= rightpoint[0]) { + return 1; + } + } else { + if (newsite[0] <= leftpoint[0]) { + return 0; + } + } + dxa = leftpoint[0] - newsite[0]; + dya = leftpoint[1] - newsite[1]; + dxb = rightpoint[0] - newsite[0]; + dyb = rightpoint[1] - newsite[1]; + return dya * (dxb * dxb + dyb * dyb) > dyb * (dxa * dxa + dya * dya); +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +REAL circletop(pa, pb, pc, ccwabc) +point pa; +point pb; +point pc; +REAL ccwabc; +{ + REAL xac, yac, xbc, ybc, xab, yab; + REAL aclen2, bclen2, ablen2; + + circletopcount++; + + xac = pa[0] - pc[0]; + yac = pa[1] - pc[1]; + xbc = pb[0] - pc[0]; + ybc = pb[1] - pc[1]; + xab = pa[0] - pb[0]; + yab = pa[1] - pb[1]; + aclen2 = xac * xac + yac * yac; + bclen2 = xbc * xbc + ybc * ybc; + ablen2 = xab * xab + yab * yab; + return pc[1] + (xac * bclen2 - xbc * aclen2 + sqrt(aclen2 * bclen2 * ablen2)) + / (2.0 * ccwabc); +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +void check4deadevent(checktri, freeevents, eventheap, heapsize) +struct triedge *checktri; +struct event **freeevents; +struct event **eventheap; +int *heapsize; +{ + struct event *deadevent; + point eventpoint; + int eventnum; + + org(*checktri, eventpoint); + if (eventpoint != (point) NULL) { + deadevent = (struct event *) eventpoint; + eventnum = deadevent->heapposition; + deadevent->eventptr = (VOID *) *freeevents; + *freeevents = deadevent; + eventheapdelete(eventheap, *heapsize, eventnum); + (*heapsize)--; + setorg(*checktri, NULL); + } +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +struct splaynode *splay(splaytree, searchpoint, searchtri) +struct splaynode *splaytree; +point searchpoint; +struct triedge *searchtri; +{ + struct splaynode *child, *grandchild; + struct splaynode *lefttree, *righttree; + struct splaynode *leftright; + point checkpoint; + int rightofroot, rightofchild; + + if (splaytree == (struct splaynode *) NULL) { + return (struct splaynode *) NULL; + } + dest(splaytree->keyedge, checkpoint); + if (checkpoint == splaytree->keydest) { + rightofroot = rightofhyperbola(&splaytree->keyedge, searchpoint); + if (rightofroot) { + triedgecopy(splaytree->keyedge, *searchtri); + child = splaytree->rchild; + } else { + child = splaytree->lchild; + } + if (child == (struct splaynode *) NULL) { + return splaytree; + } + dest(child->keyedge, checkpoint); + if (checkpoint != child->keydest) { + child = splay(child, searchpoint, searchtri); + if (child == (struct splaynode *) NULL) { + if (rightofroot) { + splaytree->rchild = (struct splaynode *) NULL; + } else { + splaytree->lchild = (struct splaynode *) NULL; + } + return splaytree; + } + } + rightofchild = rightofhyperbola(&child->keyedge, searchpoint); + if (rightofchild) { + triedgecopy(child->keyedge, *searchtri); + grandchild = splay(child->rchild, searchpoint, searchtri); + child->rchild = grandchild; + } else { + grandchild = splay(child->lchild, searchpoint, searchtri); + child->lchild = grandchild; + } + if (grandchild == (struct splaynode *) NULL) { + if (rightofroot) { + splaytree->rchild = child->lchild; + child->lchild = splaytree; + } else { + splaytree->lchild = child->rchild; + child->rchild = splaytree; + } + return child; + } + if (rightofchild) { + if (rightofroot) { + splaytree->rchild = child->lchild; + child->lchild = splaytree; + } else { + splaytree->lchild = grandchild->rchild; + grandchild->rchild = splaytree; + } + child->rchild = grandchild->lchild; + grandchild->lchild = child; + } else { + if (rightofroot) { + splaytree->rchild = grandchild->lchild; + grandchild->lchild = splaytree; + } else { + splaytree->lchild = child->rchild; + child->rchild = splaytree; + } + child->lchild = grandchild->rchild; + grandchild->rchild = child; + } + return grandchild; + } else { + lefttree = splay(splaytree->lchild, searchpoint, searchtri); + righttree = splay(splaytree->rchild, searchpoint, searchtri); + + pooldealloc(&splaynodes, (VOID *) splaytree); + if (lefttree == (struct splaynode *) NULL) { + return righttree; + } else if (righttree == (struct splaynode *) NULL) { + return lefttree; + } else if (lefttree->rchild == (struct splaynode *) NULL) { + lefttree->rchild = righttree->lchild; + righttree->lchild = lefttree; + return righttree; + } else if (righttree->lchild == (struct splaynode *) NULL) { + righttree->lchild = lefttree->rchild; + lefttree->rchild = righttree; + return lefttree; + } else { +/* printf("Holy Toledo!!!\n"); */ + leftright = lefttree->rchild; + while (leftright->rchild != (struct splaynode *) NULL) { + leftright = leftright->rchild; + } + leftright->rchild = righttree; + return lefttree; + } + } +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +struct splaynode *splayinsert(splayroot, newkey, searchpoint) +struct splaynode *splayroot; +struct triedge *newkey; +point searchpoint; +{ + struct splaynode *newsplaynode; + + newsplaynode = (struct splaynode *) poolalloc(&splaynodes); + triedgecopy(*newkey, newsplaynode->keyedge); + dest(*newkey, newsplaynode->keydest); + if (splayroot == (struct splaynode *) NULL) { + newsplaynode->lchild = (struct splaynode *) NULL; + newsplaynode->rchild = (struct splaynode *) NULL; + } else if (rightofhyperbola(&splayroot->keyedge, searchpoint)) { + newsplaynode->lchild = splayroot; + newsplaynode->rchild = splayroot->rchild; + splayroot->rchild = (struct splaynode *) NULL; + } else { + newsplaynode->lchild = splayroot->lchild; + newsplaynode->rchild = splayroot; + splayroot->lchild = (struct splaynode *) NULL; + } + return newsplaynode; +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +struct splaynode *circletopinsert(splayroot, newkey, pa, pb, pc, topy) +struct splaynode *splayroot; +struct triedge *newkey; +point pa; +point pb; +point pc; +REAL topy; +{ + REAL ccwabc; + REAL xac, yac, xbc, ybc; + REAL aclen2, bclen2; + REAL searchpoint[2]; + struct triedge dummytri; + + ccwabc = counterclockwise(pa, pb, pc); + xac = pa[0] - pc[0]; + yac = pa[1] - pc[1]; + xbc = pb[0] - pc[0]; + ybc = pb[1] - pc[1]; + aclen2 = xac * xac + yac * yac; + bclen2 = xbc * xbc + ybc * ybc; + searchpoint[0] = pc[0] - (yac * bclen2 - ybc * aclen2) / (2.0 * ccwabc); + searchpoint[1] = topy; + return splayinsert(splay(splayroot, (point) searchpoint, &dummytri), newkey, + (point) searchpoint); +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +struct splaynode *frontlocate(splayroot, bottommost, searchpoint, searchtri, + farright) +struct splaynode *splayroot; +struct triedge *bottommost; +point searchpoint; +struct triedge *searchtri; +int *farright; +{ + int farrightflag; + triangle ptr; /* Temporary variable used by onext(). */ + + triedgecopy(*bottommost, *searchtri); + splayroot = splay(splayroot, searchpoint, searchtri); + + farrightflag = 0; + while (!farrightflag && rightofhyperbola(searchtri, searchpoint)) { + onextself(*searchtri); + farrightflag = triedgeequal(*searchtri, *bottommost); + } + *farright = farrightflag; + return splayroot; +} + +#endif /* not REDUCED */ + +#ifndef REDUCED + +long sweeplinedelaunay() +{ + struct event **eventheap; + struct event *events; + struct event *freeevents; + struct event *nextevent; + struct event *newevent; + struct splaynode *splayroot; + struct triedge bottommost; + struct triedge searchtri; + struct triedge fliptri; + struct triedge lefttri, righttri, farlefttri, farrighttri; + struct triedge inserttri; + point firstpoint, secondpoint; + point nextpoint, lastpoint; + point connectpoint; + point leftpoint, midpoint, rightpoint; + REAL lefttest, righttest; + int heapsize; + int check4events, farrightflag; + triangle ptr; /* Temporary variable used by sym(), onext(), and oprev(). */ + + poolinit(&splaynodes, sizeof(struct splaynode), SPLAYNODEPERBLOCK, POINTER, + 0); + splayroot = (struct splaynode *) NULL; + + if (verbose) { + printf(" Placing points in event heap.\n"); + } + createeventheap(&eventheap, &events, &freeevents); + heapsize = inpoints; + + if (verbose) { + printf(" Forming triangulation.\n"); + } + maketriangle(&lefttri); + maketriangle(&righttri); + bond(lefttri, righttri); + lnextself(lefttri); + lprevself(righttri); + bond(lefttri, righttri); + lnextself(lefttri); + lprevself(righttri); + bond(lefttri, righttri); + firstpoint = (point) eventheap[0]->eventptr; + eventheap[0]->eventptr = (VOID *) freeevents; + freeevents = eventheap[0]; + eventheapdelete(eventheap, heapsize, 0); + heapsize--; + do { + if (heapsize == 0) { + printf("Error: Input points are all identical.\n"); + exit(1); + } + secondpoint = (point) eventheap[0]->eventptr; + eventheap[0]->eventptr = (VOID *) freeevents; + freeevents = eventheap[0]; + eventheapdelete(eventheap, heapsize, 0); + heapsize--; + if ((firstpoint[0] == secondpoint[0]) + && (firstpoint[1] == secondpoint[1])) { + printf( +"Warning: A duplicate point at (%.12g, %.12g) appeared and was ignored.\n", + secondpoint[0], secondpoint[1]); +/* Commented out - would eliminate point from output .node file. + setpointmark(secondpoint, DEADPOINT); +*/ + } + } while ((firstpoint[0] == secondpoint[0]) + && (firstpoint[1] == secondpoint[1])); + setorg(lefttri, firstpoint); + setdest(lefttri, secondpoint); + setorg(righttri, secondpoint); + setdest(righttri, firstpoint); + lprev(lefttri, bottommost); + lastpoint = secondpoint; + while (heapsize > 0) { + nextevent = eventheap[0]; + eventheapdelete(eventheap, heapsize, 0); + heapsize--; + check4events = 1; + if (nextevent->xkey < xmin) { + decode(nextevent->eventptr, fliptri); + oprev(fliptri, farlefttri); + check4deadevent(&farlefttri, &freeevents, eventheap, &heapsize); + onext(fliptri, farrighttri); + check4deadevent(&farrighttri, &freeevents, eventheap, &heapsize); + + if (triedgeequal(farlefttri, bottommost)) { + lprev(fliptri, bottommost); + } + flip(&fliptri); + setapex(fliptri, NULL); + lprev(fliptri, lefttri); + lnext(fliptri, righttri); + sym(lefttri, farlefttri); + + if (randomnation(SAMPLERATE) == 0) { + symself(fliptri); + dest(fliptri, leftpoint); + apex(fliptri, midpoint); + org(fliptri, rightpoint); + splayroot = circletopinsert(splayroot, &lefttri, leftpoint, midpoint, + rightpoint, nextevent->ykey); + } + } else { + nextpoint = (point) nextevent->eventptr; + if ((nextpoint[0] == lastpoint[0]) && (nextpoint[1] == lastpoint[1])) { + printf( +"Warning: A duplicate point at (%.12g, %.12g) appeared and was ignored.\n", + nextpoint[0], nextpoint[1]); +/* Commented out - would eliminate point from output .node file. + setpointmark(nextpoint, DEADPOINT); +*/ + check4events = 0; + } else { + lastpoint = nextpoint; + + splayroot = frontlocate(splayroot, &bottommost, nextpoint, &searchtri, + &farrightflag); +/* + triedgecopy(bottommost, searchtri); + farrightflag = 0; + while (!farrightflag && rightofhyperbola(&searchtri, nextpoint)) { + onextself(searchtri); + farrightflag = triedgeequal(searchtri, bottommost); + } +*/ + + check4deadevent(&searchtri, &freeevents, eventheap, &heapsize); + + triedgecopy(searchtri, farrighttri); + sym(searchtri, farlefttri); + maketriangle(&lefttri); + maketriangle(&righttri); + dest(farrighttri, connectpoint); + setorg(lefttri, connectpoint); + setdest(lefttri, nextpoint); + setorg(righttri, nextpoint); + setdest(righttri, connectpoint); + bond(lefttri, righttri); + lnextself(lefttri); + lprevself(righttri); + bond(lefttri, righttri); + lnextself(lefttri); + lprevself(righttri); + bond(lefttri, farlefttri); + bond(righttri, farrighttri); + if (!farrightflag && triedgeequal(farrighttri, bottommost)) { + triedgecopy(lefttri, bottommost); + } + + if (randomnation(SAMPLERATE) == 0) { + splayroot = splayinsert(splayroot, &lefttri, nextpoint); + } else if (randomnation(SAMPLERATE) == 0) { + lnext(righttri, inserttri); + splayroot = splayinsert(splayroot, &inserttri, nextpoint); + } + } + } + nextevent->eventptr = (VOID *) freeevents; + freeevents = nextevent; + + if (check4events) { + apex(farlefttri, leftpoint); + dest(lefttri, midpoint); + apex(lefttri, rightpoint); + lefttest = counterclockwise(leftpoint, midpoint, rightpoint); + if (lefttest > 0.0) { + newevent = freeevents; + freeevents = (struct event *) freeevents->eventptr; + newevent->xkey = xminextreme; + newevent->ykey = circletop(leftpoint, midpoint, rightpoint, + lefttest); + newevent->eventptr = (VOID *) encode(lefttri); + eventheapinsert(eventheap, heapsize, newevent); + heapsize++; + setorg(lefttri, newevent); + } + apex(righttri, leftpoint); + org(righttri, midpoint); + apex(farrighttri, rightpoint); + righttest = counterclockwise(leftpoint, midpoint, rightpoint); + if (righttest > 0.0) { + newevent = freeevents; + freeevents = (struct event *) freeevents->eventptr; + newevent->xkey = xminextreme; + newevent->ykey = circletop(leftpoint, midpoint, rightpoint, + righttest); + newevent->eventptr = (VOID *) encode(farrighttri); + eventheapinsert(eventheap, heapsize, newevent); + heapsize++; + setorg(farrighttri, newevent); + } + } + } + + pooldeinit(&splaynodes); + lprevself(bottommost); + return removeghosts(&bottommost); +} + +#endif /* not REDUCED */ + +/** **/ +/** **/ +/********* Sweepline Delaunay triangulation ends here *********/ + +/********* General mesh construction routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* delaunay() Form a Delaunay triangulation. */ +/* */ +/*****************************************************************************/ + +long delaunay() +{ + eextras = 0; + initializetrisegpools(); + +#ifdef REDUCED + if (!quiet) { + printf( + "Constructing Delaunay triangulation by divide-and-conquer method.\n"); + } + return divconqdelaunay(); +#else /* not REDUCED */ + if (!quiet) { + printf("Constructing Delaunay triangulation "); + if (incremental) { + printf("by incremental method.\n"); + } else if (sweepline) { + printf("by sweepline method.\n"); + } else { + printf("by divide-and-conquer method.\n"); + } + } + if (incremental) { + return incrementaldelaunay(); + } else if (sweepline) { + return sweeplinedelaunay(); + } else { + return divconqdelaunay(); + } +#endif /* not REDUCED */ +} + +/*****************************************************************************/ +/* */ +/* reconstruct() Reconstruct a triangulation from its .ele (and possibly */ +/* .poly) file. Used when the -r switch is used. */ +/* */ +/* Reads an .ele file and reconstructs the original mesh. If the -p switch */ +/* is used, this procedure will also read a .poly file and reconstruct the */ +/* shell edges of the original mesh. If the -a switch is used, this */ +/* procedure will also read an .area file and set a maximum area constraint */ +/* on each triangle. */ +/* */ +/* Points that are not corners of triangles, such as nodes on edges of */ +/* subparametric elements, are discarded. */ +/* */ +/* This routine finds the adjacencies between triangles (and shell edges) */ +/* by forming one stack of triangles for each vertex. Each triangle is on */ +/* three different stacks simultaneously. Each triangle's shell edge */ +/* pointers are used to link the items in each stack. This memory-saving */ +/* feature makes the code harder to read. The most important thing to keep */ +/* in mind is that each triangle is removed from a stack precisely when */ +/* the corresponding pointer is adjusted to refer to a shell edge rather */ +/* than the next triangle of the stack. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +#ifdef TRILIBRARY + +int reconstruct(trianglelist, triangleattriblist, trianglearealist, elements, + corners, attribs, segmentlist, segmentmarkerlist, + numberofsegments) +int *trianglelist; +REAL *triangleattriblist; +REAL *trianglearealist; +int elements; +int corners; +int attribs; +int *segmentlist; +int *segmentmarkerlist; +int numberofsegments; + +#else /* not TRILIBRARY */ + +long reconstruct(elefilename, areafilename, polyfilename, polyfile) +char *elefilename; +char *areafilename; +char *polyfilename; +FILE *polyfile; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int pointindex; + int attribindex; +#else /* not TRILIBRARY */ + FILE *elefile; + FILE *areafile; + char inputline[INPUTLINESIZE]; + char *stringptr; + int areaelements; +#endif /* not TRILIBRARY */ + struct triedge triangleloop; + struct triedge triangleleft; + struct triedge checktri; + struct triedge checkleft; + struct triedge checkneighbor; + struct edge shelleloop; + triangle *vertexarray; + triangle *prevlink; + triangle nexttri; + point tdest, tapex; + point checkdest, checkapex; + point shorg; + point killpoint; + REAL area; + int corner[3]; + int end[2]; + int killpointindex; + int incorners; + int segmentmarkers; + int boundmarker; + int aroundpoint; + long hullsize; + int notfound; + int elementnumber, segmentnumber; + int i, j; + triangle ptr; /* Temporary variable used by sym(). */ + +#ifdef TRILIBRARY + inelements = elements; + incorners = corners; + if (incorners < 3) { + printf("Error: Triangles must have at least 3 points.\n"); + exit(1); + } + eextras = attribs; +#else /* not TRILIBRARY */ + /* Read the triangles from an .ele file. */ + if (!quiet) { + printf("Opening %s.\n", elefilename); + } + elefile = fopen(elefilename, "r"); + if (elefile == (FILE *) NULL) { + printf(" Error: Cannot access file %s.\n", elefilename); + exit(1); + } + /* Read number of triangles, number of points per triangle, and */ + /* number of triangle attributes from .ele file. */ + stringptr = readline(inputline, elefile, elefilename); + inelements = (int) strtol (stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + incorners = 3; + } else { + incorners = (int) strtol (stringptr, &stringptr, 0); + if (incorners < 3) { + printf("Error: Triangles in %s must have at least 3 points.\n", + elefilename); + exit(1); + } + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + eextras = 0; + } else { + eextras = (int) strtol (stringptr, &stringptr, 0); + } +#endif /* not TRILIBRARY */ + + initializetrisegpools(); + + /* Create the triangles. */ + for (elementnumber = 1; elementnumber <= inelements; elementnumber++) { + maketriangle(&triangleloop); + /* Mark the triangle as living. */ + triangleloop.tri[3] = (triangle) triangleloop.tri; + } + + if (poly) { +#ifdef TRILIBRARY + insegments = numberofsegments; + segmentmarkers = segmentmarkerlist != (int *) NULL; +#else /* not TRILIBRARY */ + /* Read number of segments and number of segment */ + /* boundary markers from .poly file. */ + stringptr = readline(inputline, polyfile, inpolyfilename); + insegments = (int) strtol (stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + segmentmarkers = 0; + } else { + segmentmarkers = (int) strtol (stringptr, &stringptr, 0); + } +#endif /* not TRILIBRARY */ + + /* Create the shell edges. */ + for (segmentnumber = 1; segmentnumber <= insegments; segmentnumber++) { + makeshelle(&shelleloop); + /* Mark the shell edge as living. */ + shelleloop.sh[2] = (shelle) shelleloop.sh; + } + } + +#ifdef TRILIBRARY + pointindex = 0; + attribindex = 0; +#else /* not TRILIBRARY */ + if (vararea) { + /* Open an .area file, check for consistency with the .ele file. */ + if (!quiet) { + printf("Opening %s.\n", areafilename); + } + areafile = fopen(areafilename, "r"); + if (areafile == (FILE *) NULL) { + printf(" Error: Cannot access file %s.\n", areafilename); + exit(1); + } + stringptr = readline(inputline, areafile, areafilename); + areaelements = (int) strtol (stringptr, &stringptr, 0); + if (areaelements != inelements) { + printf("Error: %s and %s disagree on number of triangles.\n", + elefilename, areafilename); + exit(1); + } + } +#endif /* not TRILIBRARY */ + + if (!quiet) { + printf("Reconstructing mesh.\n"); + } + /* Allocate a temporary array that maps each point to some adjacent */ + /* triangle. I took care to allocate all the permanent memory for */ + /* triangles and shell edges first. */ + vertexarray = (triangle *) malloc(points.items * sizeof(triangle)); + if (vertexarray == (triangle *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + /* Each point is initially unrepresented. */ + for (i = 0; i < points.items; i++) { + vertexarray[i] = (triangle) dummytri; + } + + if (verbose) { + printf(" Assembling triangles.\n"); + } + /* Read the triangles from the .ele file, and link */ + /* together those that share an edge. */ + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + elementnumber = firstnumber; + while (triangleloop.tri != (triangle *) NULL) { +#ifdef TRILIBRARY + /* Copy the triangle's three corners. */ + for (j = 0; j < 3; j++) { + corner[j] = trianglelist[pointindex++]; + if ((corner[j] < firstnumber) || (corner[j] >= firstnumber + inpoints)) { + printf("Error: Triangle %d has an invalid vertex index.\n", + elementnumber); + exit(1); + } + } +#else /* not TRILIBRARY */ + /* Read triangle number and the triangle's three corners. */ + stringptr = readline(inputline, elefile, elefilename); + for (j = 0; j < 3; j++) { + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Triangle %d is missing point %d in %s.\n", + elementnumber, j + 1, elefilename); + exit(1); + } else { + corner[j] = (int) strtol (stringptr, &stringptr, 0); + if ((corner[j] < firstnumber) || + (corner[j] >= firstnumber + inpoints)) { + printf("Error: Triangle %d has an invalid vertex index.\n", + elementnumber); + exit(1); + } + } + } +#endif /* not TRILIBRARY */ + + /* Find out about (and throw away) extra nodes. */ + for (j = 3; j < incorners; j++) { +#ifdef TRILIBRARY + killpointindex = trianglelist[pointindex++]; +#else /* not TRILIBRARY */ + stringptr = findfield(stringptr); + if (*stringptr != '\0') { + killpointindex = (int) strtol (stringptr, &stringptr, 0); +#endif /* not TRILIBRARY */ + if ((killpointindex >= firstnumber) && + (killpointindex < firstnumber + inpoints)) { + /* Delete the non-corner point if it's not already deleted. */ + killpoint = getpoint(killpointindex); + if (pointmark(killpoint) != DEADPOINT) { + pointdealloc(killpoint); + } + } +#ifndef TRILIBRARY + } +#endif /* not TRILIBRARY */ + } + + /* Read the triangle's attributes. */ + for (j = 0; j < eextras; j++) { +#ifdef TRILIBRARY + setelemattribute(triangleloop, j, triangleattriblist[attribindex++]); +#else /* not TRILIBRARY */ + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + setelemattribute(triangleloop, j, 0); + } else { + setelemattribute(triangleloop, j, + (REAL) strtod (stringptr, &stringptr)); + } +#endif /* not TRILIBRARY */ + } + + if (vararea) { +#ifdef TRILIBRARY + area = trianglearealist[elementnumber - firstnumber]; +#else /* not TRILIBRARY */ + /* Read an area constraint from the .area file. */ + stringptr = readline(inputline, areafile, areafilename); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + area = -1.0; /* No constraint on this triangle. */ + } else { + area = (REAL) strtod(stringptr, &stringptr); + } +#endif /* not TRILIBRARY */ + setareabound(triangleloop, area); + } + + /* Set the triangle's vertices. */ + triangleloop.orient = 0; + setorg(triangleloop, getpoint(corner[0])); + setdest(triangleloop, getpoint(corner[1])); + setapex(triangleloop, getpoint(corner[2])); + /* Try linking the triangle to others that share these vertices. */ + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + /* Take the number for the origin of triangleloop. */ + aroundpoint = corner[triangleloop.orient]; + /* Look for other triangles having this vertex. */ + nexttri = vertexarray[aroundpoint - firstnumber]; + /* Link the current triangle to the next one in the stack. */ + triangleloop.tri[6 + triangleloop.orient] = nexttri; + /* Push the current triangle onto the stack. */ + vertexarray[aroundpoint - firstnumber] = encode(triangleloop); + decode(nexttri, checktri); + if (checktri.tri != dummytri) { + dest(triangleloop, tdest); + apex(triangleloop, tapex); + /* Look for other triangles that share an edge. */ + do { + dest(checktri, checkdest); + apex(checktri, checkapex); + if (tapex == checkdest) { + /* The two triangles share an edge; bond them together. */ + lprev(triangleloop, triangleleft); + bond(triangleleft, checktri); + } + if (tdest == checkapex) { + /* The two triangles share an edge; bond them together. */ + lprev(checktri, checkleft); + bond(triangleloop, checkleft); + } + /* Find the next triangle in the stack. */ + nexttri = checktri.tri[6 + checktri.orient]; + decode(nexttri, checktri); + } while (checktri.tri != dummytri); + } + } + triangleloop.tri = triangletraverse(); + elementnumber++; + } + +#ifdef TRILIBRARY + pointindex = 0; +#else /* not TRILIBRARY */ + fclose(elefile); + if (vararea) { + fclose(areafile); + } +#endif /* not TRILIBRARY */ + + hullsize = 0; /* Prepare to count the boundary edges. */ + if (poly) { + if (verbose) { + printf(" Marking segments in triangulation.\n"); + } + /* Read the segments from the .poly file, and link them */ + /* to their neighboring triangles. */ + boundmarker = 0; + traversalinit(&shelles); + shelleloop.sh = shelletraverse(); + segmentnumber = firstnumber; + while (shelleloop.sh != (shelle *) NULL) { +#ifdef TRILIBRARY + end[0] = segmentlist[pointindex++]; + end[1] = segmentlist[pointindex++]; + if (segmentmarkers) { + boundmarker = segmentmarkerlist[segmentnumber - firstnumber]; + } +#else /* not TRILIBRARY */ + /* Read the endpoints of each segment, and possibly a boundary marker. */ + stringptr = readline(inputline, polyfile, inpolyfilename); + /* Skip the first (segment number) field. */ + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Segment %d has no endpoints in %s.\n", segmentnumber, + polyfilename); + exit(1); + } else { + end[0] = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Segment %d is missing its second endpoint in %s.\n", + segmentnumber, polyfilename); + exit(1); + } else { + end[1] = (int) strtol (stringptr, &stringptr, 0); + } + if (segmentmarkers) { + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + boundmarker = 0; + } else { + boundmarker = (int) strtol (stringptr, &stringptr, 0); + } + } +#endif /* not TRILIBRARY */ + for (j = 0; j < 2; j++) { + if ((end[j] < firstnumber) || (end[j] >= firstnumber + inpoints)) { + printf("Error: Segment %d has an invalid vertex index.\n", + segmentnumber); + exit(1); + } + } + + /* set the shell edge's vertices. */ + shelleloop.shorient = 0; + setsorg(shelleloop, getpoint(end[0])); + setsdest(shelleloop, getpoint(end[1])); + setmark(shelleloop, boundmarker); + /* Try linking the shell edge to triangles that share these vertices. */ + for (shelleloop.shorient = 0; shelleloop.shorient < 2; + shelleloop.shorient++) { + /* Take the number for the destination of shelleloop. */ + aroundpoint = end[1 - shelleloop.shorient]; + /* Look for triangles having this vertex. */ + prevlink = &vertexarray[aroundpoint - firstnumber]; + nexttri = vertexarray[aroundpoint - firstnumber]; + decode(nexttri, checktri); + sorg(shelleloop, shorg); + notfound = 1; + /* Look for triangles having this edge. Note that I'm only */ + /* comparing each triangle's destination with the shell edge; */ + /* each triangle's apex is handled through a different vertex. */ + /* Because each triangle appears on three vertices' lists, each */ + /* occurrence of a triangle on a list can (and does) represent */ + /* an edge. In this way, most edges are represented twice, and */ + /* every triangle-segment bond is represented once. */ + while (notfound && (checktri.tri != dummytri)) { + dest(checktri, checkdest); + if (shorg == checkdest) { + /* We have a match. Remove this triangle from the list. */ + *prevlink = checktri.tri[6 + checktri.orient]; + /* Bond the shell edge to the triangle. */ + tsbond(checktri, shelleloop); + /* Check if this is a boundary edge. */ + sym(checktri, checkneighbor); + if (checkneighbor.tri == dummytri) { + /* The next line doesn't insert a shell edge (because there's */ + /* already one there), but it sets the boundary markers of */ + /* the existing shell edge and its vertices. */ + insertshelle(&checktri, 1); + hullsize++; + } + notfound = 0; + } + /* Find the next triangle in the stack. */ + prevlink = &checktri.tri[6 + checktri.orient]; + nexttri = checktri.tri[6 + checktri.orient]; + decode(nexttri, checktri); + } + } + shelleloop.sh = shelletraverse(); + segmentnumber++; + } + } + + /* Mark the remaining edges as not being attached to any shell edge. */ + /* Also, count the (yet uncounted) boundary edges. */ + for (i = 0; i < points.items; i++) { + /* Search the stack of triangles adjacent to a point. */ + nexttri = vertexarray[i]; + decode(nexttri, checktri); + while (checktri.tri != dummytri) { + /* Find the next triangle in the stack before this */ + /* information gets overwritten. */ + nexttri = checktri.tri[6 + checktri.orient]; + /* No adjacent shell edge. (This overwrites the stack info.) */ + tsdissolve(checktri); + sym(checktri, checkneighbor); + if (checkneighbor.tri == dummytri) { + insertshelle(&checktri, 1); + hullsize++; + } + decode(nexttri, checktri); + } + } + + free(vertexarray); + return hullsize; +} + +#endif /* not CDT_ONLY */ + +/** **/ +/** **/ +/********* General mesh construction routines end here *********/ + +/********* Segment (shell edge) insertion begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* finddirection() Find the first triangle on the path from one point */ +/* to another. */ +/* */ +/* Finds the triangle that intersects a line segment drawn from the */ +/* origin of `searchtri' to the point `endpoint', and returns the result */ +/* in `searchtri'. The origin of `searchtri' does not change, even though */ +/* the triangle returned may differ from the one passed in. This routine */ +/* is used to find the direction to move in to get from one point to */ +/* another. */ +/* */ +/* The return value notes whether the destination or apex of the found */ +/* triangle is collinear with the two points in question. */ +/* */ +/*****************************************************************************/ + +enum finddirectionresult finddirection(searchtri, endpoint) +struct triedge *searchtri; +point endpoint; +{ + struct triedge checktri; + point startpoint; + point leftpoint, rightpoint; + REAL leftccw, rightccw; + int leftflag, rightflag; + triangle ptr; /* Temporary variable used by onext() and oprev(). */ + + org(*searchtri, startpoint); + dest(*searchtri, rightpoint); + apex(*searchtri, leftpoint); + /* Is `endpoint' to the left? */ + leftccw = counterclockwise(endpoint, startpoint, leftpoint); + leftflag = leftccw > 0.0; + /* Is `endpoint' to the right? */ + rightccw = counterclockwise(startpoint, endpoint, rightpoint); + rightflag = rightccw > 0.0; + if (leftflag && rightflag) { + /* `searchtri' faces directly away from `endpoint'. We could go */ + /* left or right. Ask whether it's a triangle or a boundary */ + /* on the left. */ + onext(*searchtri, checktri); + if (checktri.tri == dummytri) { + leftflag = 0; + } else { + rightflag = 0; + } + } + while (leftflag) { + /* Turn left until satisfied. */ + onextself(*searchtri); + if (searchtri->tri == dummytri) { + printf("Internal error in finddirection(): Unable to find a\n"); + printf(" triangle leading from (%.12g, %.12g) to", startpoint[0], + startpoint[1]); + printf(" (%.12g, %.12g).\n", endpoint[0], endpoint[1]); + internalerror(); + } + apex(*searchtri, leftpoint); + rightccw = leftccw; + leftccw = counterclockwise(endpoint, startpoint, leftpoint); + leftflag = leftccw > 0.0; + } + while (rightflag) { + /* Turn right until satisfied. */ + oprevself(*searchtri); + if (searchtri->tri == dummytri) { + printf("Internal error in finddirection(): Unable to find a\n"); + printf(" triangle leading from (%.12g, %.12g) to", startpoint[0], + startpoint[1]); + printf(" (%.12g, %.12g).\n", endpoint[0], endpoint[1]); + internalerror(); + } + dest(*searchtri, rightpoint); + leftccw = rightccw; + rightccw = counterclockwise(startpoint, endpoint, rightpoint); + rightflag = rightccw > 0.0; + } + if (leftccw == 0.0) { + return LEFTCOLLINEAR; + } else if (rightccw == 0.0) { + return RIGHTCOLLINEAR; + } else { + return WITHIN; + } +} + +/*****************************************************************************/ +/* */ +/* segmentintersection() Find the intersection of an existing segment */ +/* and a segment that is being inserted. Insert */ +/* a point at the intersection, splitting an */ +/* existing shell edge. */ +/* */ +/* The segment being inserted connects the apex of splittri to endpoint2. */ +/* splitshelle is the shell edge being split, and MUST be opposite */ +/* splittri. Hence, the edge being split connects the origin and */ +/* destination of splittri. */ +/* */ +/* On completion, splittri is a handle having the newly inserted */ +/* intersection point as its origin, and endpoint1 as its destination. */ +/* */ +/*****************************************************************************/ + +void segmentintersection(splittri, splitshelle, endpoint2) +struct triedge *splittri; +struct edge *splitshelle; +point endpoint2; +{ + point endpoint1; + point torg, tdest; + point leftpoint, rightpoint; + point newpoint; + enum insertsiteresult success; + enum finddirectionresult collinear; + REAL ex, ey; + REAL tx, ty; + REAL etx, ety; + REAL split, denom; + int i; + triangle ptr; /* Temporary variable used by onext(). */ + + /* Find the other three segment endpoints. */ + apex(*splittri, endpoint1); + org(*splittri, torg); + dest(*splittri, tdest); + /* Segment intersection formulae; see the Antonio reference. */ + tx = tdest[0] - torg[0]; + ty = tdest[1] - torg[1]; + ex = endpoint2[0] - endpoint1[0]; + ey = endpoint2[1] - endpoint1[1]; + etx = torg[0] - endpoint2[0]; + ety = torg[1] - endpoint2[1]; + denom = ty * ex - tx * ey; + if (denom == 0.0) { + printf("Internal error in segmentintersection():"); + printf(" Attempt to find intersection of parallel segments.\n"); + internalerror(); + } + split = (ey * etx - ex * ety) / denom; + /* Create the new point. */ + newpoint = (point) poolalloc(&points); + /* Interpolate its coordinate and attributes. */ + for (i = 0; i < 2 + nextras; i++) { + newpoint[i] = torg[i] + split * (tdest[i] - torg[i]); + } + setpointmark(newpoint, mark(*splitshelle)); + if (verbose > 1) { + printf( + " Splitting edge (%.12g, %.12g) (%.12g, %.12g) at (%.12g, %.12g).\n", + torg[0], torg[1], tdest[0], tdest[1], newpoint[0], newpoint[1]); + } + /* Insert the intersection point. This should always succeed. */ + success = insertsite(newpoint, splittri, splitshelle, 0, 0); + if (success != SUCCESSFULPOINT) { + printf("Internal error in segmentintersection():\n"); + printf(" Failure to split a segment.\n"); + internalerror(); + } + if (steinerleft > 0) { + steinerleft--; + } + /* Inserting the point may have caused edge flips. We wish to rediscover */ + /* the edge connecting endpoint1 to the new intersection point. */ + collinear = finddirection(splittri, endpoint1); + dest(*splittri, rightpoint); + apex(*splittri, leftpoint); + if ((leftpoint[0] == endpoint1[0]) && (leftpoint[1] == endpoint1[1])) { + onextself(*splittri); + } else if ((rightpoint[0] != endpoint1[0]) || + (rightpoint[1] != endpoint1[1])) { + printf("Internal error in segmentintersection():\n"); + printf(" Topological inconsistency after splitting a segment.\n"); + internalerror(); + } + /* `splittri' should have destination endpoint1. */ +} + +/*****************************************************************************/ +/* */ +/* scoutsegment() Scout the first triangle on the path from one endpoint */ +/* to another, and check for completion (reaching the */ +/* second endpoint), a collinear point, and the */ +/* intersection of two segments. */ +/* */ +/* Returns one if the entire segment is successfully inserted, and zero if */ +/* the job must be finished by conformingedge() or constrainededge(). */ +/* */ +/* If the first triangle on the path has the second endpoint as its */ +/* destination or apex, a shell edge is inserted and the job is done. */ +/* */ +/* If the first triangle on the path has a destination or apex that lies on */ +/* the segment, a shell edge is inserted connecting the first endpoint to */ +/* the collinear point, and the search is continued from the collinear */ +/* point. */ +/* */ +/* If the first triangle on the path has a shell edge opposite its origin, */ +/* then there is a segment that intersects the segment being inserted. */ +/* Their intersection point is inserted, splitting the shell edge. */ +/* */ +/* Otherwise, return zero. */ +/* */ +/*****************************************************************************/ + +int scoutsegment(searchtri, endpoint2, newmark) +struct triedge *searchtri; +point endpoint2; +int newmark; +{ + struct triedge crosstri; + struct edge crossedge; + point leftpoint, rightpoint; + point endpoint1; + enum finddirectionresult collinear; + shelle sptr; /* Temporary variable used by tspivot(). */ + + collinear = finddirection(searchtri, endpoint2); + dest(*searchtri, rightpoint); + apex(*searchtri, leftpoint); + if (((leftpoint[0] == endpoint2[0]) && (leftpoint[1] == endpoint2[1])) || + ((rightpoint[0] == endpoint2[0]) && (rightpoint[1] == endpoint2[1]))) { + /* The segment is already an edge in the mesh. */ + if ((leftpoint[0] == endpoint2[0]) && (leftpoint[1] == endpoint2[1])) { + lprevself(*searchtri); + } + /* Insert a shell edge, if there isn't already one there. */ + insertshelle(searchtri, newmark); + return 1; + } else if (collinear == LEFTCOLLINEAR) { + /* We've collided with a point between the segment's endpoints. */ + /* Make the collinear point be the triangle's origin. */ + lprevself(*searchtri); + insertshelle(searchtri, newmark); + /* Insert the remainder of the segment. */ + return scoutsegment(searchtri, endpoint2, newmark); + } else if (collinear == RIGHTCOLLINEAR) { + /* We've collided with a point between the segment's endpoints. */ + insertshelle(searchtri, newmark); + /* Make the collinear point be the triangle's origin. */ + lnextself(*searchtri); + /* Insert the remainder of the segment. */ + return scoutsegment(searchtri, endpoint2, newmark); + } else { + lnext(*searchtri, crosstri); + tspivot(crosstri, crossedge); + /* Check for a crossing segment. */ + if (crossedge.sh == dummysh) { + return 0; + } else { + org(*searchtri, endpoint1); + /* Insert a point at the intersection. */ + segmentintersection(&crosstri, &crossedge, endpoint2); + triedgecopy(crosstri, *searchtri); + insertshelle(searchtri, newmark); + /* Insert the remainder of the segment. */ + return scoutsegment(searchtri, endpoint2, newmark); + } + } +} + +/*****************************************************************************/ +/* */ +/* conformingedge() Force a segment into a conforming Delaunay */ +/* triangulation by inserting a point at its midpoint, */ +/* and recursively forcing in the two half-segments if */ +/* necessary. */ +/* */ +/* Generates a sequence of edges connecting `endpoint1' to `endpoint2'. */ +/* `newmark' is the boundary marker of the segment, assigned to each new */ +/* splitting point and shell edge. */ +/* */ +/* Note that conformingedge() does not always maintain the conforming */ +/* Delaunay property. Once inserted, segments are locked into place; */ +/* points inserted later (to force other segments in) may render these */ +/* fixed segments non-Delaunay. The conforming Delaunay property will be */ +/* restored by enforcequality() by splitting encroached segments. */ +/* */ +/*****************************************************************************/ + +#ifndef REDUCED +#ifndef CDT_ONLY + +void conformingedge(endpoint1, endpoint2, newmark) +point endpoint1; +point endpoint2; +int newmark; +{ + struct triedge searchtri1, searchtri2; + struct edge brokenshelle; + point newpoint; + point midpoint1, midpoint2; + enum insertsiteresult success; + int result1, result2; + int i; + shelle sptr; /* Temporary variable used by tspivot(). */ + + if (verbose > 2) { + printf("Forcing segment into triangulation by recursive splitting:\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g)\n", endpoint1[0], endpoint1[1], + endpoint2[0], endpoint2[1]); + } + /* Create a new point to insert in the middle of the segment. */ + newpoint = (point) poolalloc(&points); + /* Interpolate coordinates and attributes. */ + for (i = 0; i < 2 + nextras; i++) { + newpoint[i] = 0.5 * (endpoint1[i] + endpoint2[i]); + } + setpointmark(newpoint, newmark); + /* Find a boundary triangle to search from. */ + searchtri1.tri = (triangle *) NULL; + /* Attempt to insert the new point. */ + success = insertsite(newpoint, &searchtri1, (struct edge *) NULL, 0, 0); + if (success == DUPLICATEPOINT) { + if (verbose > 2) { + printf(" Segment intersects existing point (%.12g, %.12g).\n", + newpoint[0], newpoint[1]); + } + /* Use the point that's already there. */ + pointdealloc(newpoint); + org(searchtri1, newpoint); + } else { + if (success == VIOLATINGPOINT) { + if (verbose > 2) { + printf(" Two segments intersect at (%.12g, %.12g).\n", + newpoint[0], newpoint[1]); + } + /* By fluke, we've landed right on another segment. Split it. */ + tspivot(searchtri1, brokenshelle); + success = insertsite(newpoint, &searchtri1, &brokenshelle, 0, 0); + if (success != SUCCESSFULPOINT) { + printf("Internal error in conformingedge():\n"); + printf(" Failure to split a segment.\n"); + internalerror(); + } + } + /* The point has been inserted successfully. */ + if (steinerleft > 0) { + steinerleft--; + } + } + triedgecopy(searchtri1, searchtri2); + result1 = scoutsegment(&searchtri1, endpoint1, newmark); + result2 = scoutsegment(&searchtri2, endpoint2, newmark); + if (!result1) { + /* The origin of searchtri1 may have changed if a collision with an */ + /* intervening vertex on the segment occurred. */ + org(searchtri1, midpoint1); + conformingedge(midpoint1, endpoint1, newmark); + } + if (!result2) { + /* The origin of searchtri2 may have changed if a collision with an */ + /* intervening vertex on the segment occurred. */ + org(searchtri2, midpoint2); + conformingedge(midpoint2, endpoint2, newmark); + } +} + +#endif /* not CDT_ONLY */ +#endif /* not REDUCED */ + +/*****************************************************************************/ +/* */ +/* delaunayfixup() Enforce the Delaunay condition at an edge, fanning out */ +/* recursively from an existing point. Pay special */ +/* attention to stacking inverted triangles. */ +/* */ +/* This is a support routine for inserting segments into a constrained */ +/* Delaunay triangulation. */ +/* */ +/* The origin of fixuptri is treated as if it has just been inserted, and */ +/* the local Delaunay condition needs to be enforced. It is only enforced */ +/* in one sector, however, that being the angular range defined by */ +/* fixuptri. */ +/* */ +/* This routine also needs to make decisions regarding the "stacking" of */ +/* triangles. (Read the description of constrainededge() below before */ +/* reading on here, so you understand the algorithm.) If the position of */ +/* the new point (the origin of fixuptri) indicates that the vertex before */ +/* it on the polygon is a reflex vertex, then "stack" the triangle by */ +/* doing nothing. (fixuptri is an inverted triangle, which is how stacked */ +/* triangles are identified.) */ +/* */ +/* Otherwise, check whether the vertex before that was a reflex vertex. */ +/* If so, perform an edge flip, thereby eliminating an inverted triangle */ +/* (popping it off the stack). The edge flip may result in the creation */ +/* of a new inverted triangle, depending on whether or not the new vertex */ +/* is visible to the vertex three edges behind on the polygon. */ +/* */ +/* If neither of the two vertices behind the new vertex are reflex */ +/* vertices, fixuptri and fartri, the triangle opposite it, are not */ +/* inverted; hence, ensure that the edge between them is locally Delaunay. */ +/* */ +/* `leftside' indicates whether or not fixuptri is to the left of the */ +/* segment being inserted. (Imagine that the segment is pointing up from */ +/* endpoint1 to endpoint2.) */ +/* */ +/*****************************************************************************/ + +void delaunayfixup(fixuptri, leftside) +struct triedge *fixuptri; +int leftside; +{ + struct triedge neartri; + struct triedge fartri; + struct edge faredge; + point nearpoint, leftpoint, rightpoint, farpoint; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + lnext(*fixuptri, neartri); + sym(neartri, fartri); + /* Check if the edge opposite the origin of fixuptri can be flipped. */ + if (fartri.tri == dummytri) { + return; + } + tspivot(neartri, faredge); + if (faredge.sh != dummysh) { + return; + } + /* Find all the relevant vertices. */ + apex(neartri, nearpoint); + org(neartri, leftpoint); + dest(neartri, rightpoint); + apex(fartri, farpoint); + /* Check whether the previous polygon vertex is a reflex vertex. */ + if (leftside) { + if (counterclockwise(nearpoint, leftpoint, farpoint) <= 0.0) { + /* leftpoint is a reflex vertex too. Nothing can */ + /* be done until a convex section is found. */ + return; + } + } else { + if (counterclockwise(farpoint, rightpoint, nearpoint) <= 0.0) { + /* rightpoint is a reflex vertex too. Nothing can */ + /* be done until a convex section is found. */ + return; + } + } + if (counterclockwise(rightpoint, leftpoint, farpoint) > 0.0) { + /* fartri is not an inverted triangle, and farpoint is not a reflex */ + /* vertex. As there are no reflex vertices, fixuptri isn't an */ + /* inverted triangle, either. Hence, test the edge between the */ + /* triangles to ensure it is locally Delaunay. */ + if (incircle(leftpoint, farpoint, rightpoint, nearpoint) <= 0.0) { + return; + } + /* Not locally Delaunay; go on to an edge flip. */ + } /* else fartri is inverted; remove it from the stack by flipping. */ + flip(&neartri); + lprevself(*fixuptri); /* Restore the origin of fixuptri after the flip. */ + /* Recursively process the two triangles that result from the flip. */ + delaunayfixup(fixuptri, leftside); + delaunayfixup(&fartri, leftside); +} + +/*****************************************************************************/ +/* */ +/* constrainededge() Force a segment into a constrained Delaunay */ +/* triangulation by deleting the triangles it */ +/* intersects, and triangulating the polygons that */ +/* form on each side of it. */ +/* */ +/* Generates a single edge connecting `endpoint1' to `endpoint2'. The */ +/* triangle `starttri' has `endpoint1' as its origin. `newmark' is the */ +/* boundary marker of the segment. */ +/* */ +/* To insert a segment, every triangle whose interior intersects the */ +/* segment is deleted. The union of these deleted triangles is a polygon */ +/* (which is not necessarily monotone, but is close enough), which is */ +/* divided into two polygons by the new segment. This routine's task is */ +/* to generate the Delaunay triangulation of these two polygons. */ +/* */ +/* You might think of this routine's behavior as a two-step process. The */ +/* first step is to walk from endpoint1 to endpoint2, flipping each edge */ +/* encountered. This step creates a fan of edges connected to endpoint1, */ +/* including the desired edge to endpoint2. The second step enforces the */ +/* Delaunay condition on each side of the segment in an incremental manner: */ +/* proceeding along the polygon from endpoint1 to endpoint2 (this is done */ +/* independently on each side of the segment), each vertex is "enforced" */ +/* as if it had just been inserted, but affecting only the previous */ +/* vertices. The result is the same as if the vertices had been inserted */ +/* in the order they appear on the polygon, so the result is Delaunay. */ +/* */ +/* In truth, constrainededge() interleaves these two steps. The procedure */ +/* walks from endpoint1 to endpoint2, and each time an edge is encountered */ +/* and flipped, the newly exposed vertex (at the far end of the flipped */ +/* edge) is "enforced" upon the previously flipped edges, usually affecting */ +/* only one side of the polygon (depending upon which side of the segment */ +/* the vertex falls on). */ +/* */ +/* The algorithm is complicated by the need to handle polygons that are not */ +/* convex. Although the polygon is not necessarily monotone, it can be */ +/* triangulated in a manner similar to the stack-based algorithms for */ +/* monotone polygons. For each reflex vertex (local concavity) of the */ +/* polygon, there will be an inverted triangle formed by one of the edge */ +/* flips. (An inverted triangle is one with negative area - that is, its */ +/* vertices are arranged in clockwise order - and is best thought of as a */ +/* wrinkle in the fabric of the mesh.) Each inverted triangle can be */ +/* thought of as a reflex vertex pushed on the stack, waiting to be fixed */ +/* later. */ +/* */ +/* A reflex vertex is popped from the stack when a vertex is inserted that */ +/* is visible to the reflex vertex. (However, if the vertex behind the */ +/* reflex vertex is not visible to the reflex vertex, a new inverted */ +/* triangle will take its place on the stack.) These details are handled */ +/* by the delaunayfixup() routine above. */ +/* */ +/*****************************************************************************/ + +void constrainededge(starttri, endpoint2, newmark) +struct triedge *starttri; +point endpoint2; +int newmark; +{ + struct triedge fixuptri, fixuptri2; + struct edge fixupedge; + point endpoint1; + point farpoint; + REAL area; + int collision; + int done; + triangle ptr; /* Temporary variable used by sym() and oprev(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + org(*starttri, endpoint1); + lnext(*starttri, fixuptri); + flip(&fixuptri); + /* `collision' indicates whether we have found a point directly */ + /* between endpoint1 and endpoint2. */ + collision = 0; + done = 0; + do { + org(fixuptri, farpoint); + /* `farpoint' is the extreme point of the polygon we are "digging" */ + /* to get from endpoint1 to endpoint2. */ + if ((farpoint[0] == endpoint2[0]) && (farpoint[1] == endpoint2[1])) { + oprev(fixuptri, fixuptri2); + /* Enforce the Delaunay condition around endpoint2. */ + delaunayfixup(&fixuptri, 0); + delaunayfixup(&fixuptri2, 1); + done = 1; + } else { + /* Check whether farpoint is to the left or right of the segment */ + /* being inserted, to decide which edge of fixuptri to dig */ + /* through next. */ + area = counterclockwise(endpoint1, endpoint2, farpoint); + if (area == 0.0) { + /* We've collided with a point between endpoint1 and endpoint2. */ + collision = 1; + oprev(fixuptri, fixuptri2); + /* Enforce the Delaunay condition around farpoint. */ + delaunayfixup(&fixuptri, 0); + delaunayfixup(&fixuptri2, 1); + done = 1; + } else { + if (area > 0.0) { /* farpoint is to the left of the segment. */ + oprev(fixuptri, fixuptri2); + /* Enforce the Delaunay condition around farpoint, on the */ + /* left side of the segment only. */ + delaunayfixup(&fixuptri2, 1); + /* Flip the edge that crosses the segment. After the edge is */ + /* flipped, one of its endpoints is the fan vertex, and the */ + /* destination of fixuptri is the fan vertex. */ + lprevself(fixuptri); + } else { /* farpoint is to the right of the segment. */ + delaunayfixup(&fixuptri, 0); + /* Flip the edge that crosses the segment. After the edge is */ + /* flipped, one of its endpoints is the fan vertex, and the */ + /* destination of fixuptri is the fan vertex. */ + oprevself(fixuptri); + } + /* Check for two intersecting segments. */ + tspivot(fixuptri, fixupedge); + if (fixupedge.sh == dummysh) { + flip(&fixuptri); /* May create an inverted triangle on the left. */ + } else { + /* We've collided with a segment between endpoint1 and endpoint2. */ + collision = 1; + /* Insert a point at the intersection. */ + segmentintersection(&fixuptri, &fixupedge, endpoint2); + done = 1; + } + } + } + } while (!done); + /* Insert a shell edge to make the segment permanent. */ + insertshelle(&fixuptri, newmark); + /* If there was a collision with an interceding vertex, install another */ + /* segment connecting that vertex with endpoint2. */ + if (collision) { + /* Insert the remainder of the segment. */ + if (!scoutsegment(&fixuptri, endpoint2, newmark)) { + constrainededge(&fixuptri, endpoint2, newmark); + } + } +} + +/*****************************************************************************/ +/* */ +/* insertsegment() Insert a PSLG segment into a triangulation. */ +/* */ +/*****************************************************************************/ + +void insertsegment(endpoint1, endpoint2, newmark) +point endpoint1; +point endpoint2; +int newmark; +{ + struct triedge searchtri1, searchtri2; + triangle encodedtri; + point checkpoint; + triangle ptr; /* Temporary variable used by sym(). */ + + if (verbose > 1) { + printf(" Connecting (%.12g, %.12g) to (%.12g, %.12g).\n", + endpoint1[0], endpoint1[1], endpoint2[0], endpoint2[1]); + } + + /* Find a triangle whose origin is the segment's first endpoint. */ + checkpoint = (point) NULL; + encodedtri = point2tri(endpoint1); + if (encodedtri != (triangle) NULL) { + decode(encodedtri, searchtri1); + org(searchtri1, checkpoint); + } + if (checkpoint != endpoint1) { + /* Find a boundary triangle to search from. */ + searchtri1.tri = dummytri; + searchtri1.orient = 0; + symself(searchtri1); + /* Search for the segment's first endpoint by point location. */ + if (locate(endpoint1, &searchtri1) != ONVERTEX) { + printf( + "Internal error in insertsegment(): Unable to locate PSLG point\n"); + printf(" (%.12g, %.12g) in triangulation.\n", + endpoint1[0], endpoint1[1]); + internalerror(); + } + } + /* Remember this triangle to improve subsequent point location. */ + triedgecopy(searchtri1, recenttri); + /* Scout the beginnings of a path from the first endpoint */ + /* toward the second. */ + if (scoutsegment(&searchtri1, endpoint2, newmark)) { + /* The segment was easily inserted. */ + return; + } + /* The first endpoint may have changed if a collision with an intervening */ + /* vertex on the segment occurred. */ + org(searchtri1, endpoint1); + + /* Find a triangle whose origin is the segment's second endpoint. */ + checkpoint = (point) NULL; + encodedtri = point2tri(endpoint2); + if (encodedtri != (triangle) NULL) { + decode(encodedtri, searchtri2); + org(searchtri2, checkpoint); + } + if (checkpoint != endpoint2) { + /* Find a boundary triangle to search from. */ + searchtri2.tri = dummytri; + searchtri2.orient = 0; + symself(searchtri2); + /* Search for the segment's second endpoint by point location. */ + if (locate(endpoint2, &searchtri2) != ONVERTEX) { + printf( + "Internal error in insertsegment(): Unable to locate PSLG point\n"); + printf(" (%.12g, %.12g) in triangulation.\n", + endpoint2[0], endpoint2[1]); + internalerror(); + } + } + /* Remember this triangle to improve subsequent point location. */ + triedgecopy(searchtri2, recenttri); + /* Scout the beginnings of a path from the second endpoint */ + /* toward the first. */ + if (scoutsegment(&searchtri2, endpoint1, newmark)) { + /* The segment was easily inserted. */ + return; + } + /* The second endpoint may have changed if a collision with an intervening */ + /* vertex on the segment occurred. */ + org(searchtri2, endpoint2); + +#ifndef REDUCED +#ifndef CDT_ONLY + if (splitseg) { + /* Insert vertices to force the segment into the triangulation. */ + conformingedge(endpoint1, endpoint2, newmark); + } else { +#endif /* not CDT_ONLY */ +#endif /* not REDUCED */ + /* Insert the segment directly into the triangulation. */ + constrainededge(&searchtri1, endpoint2, newmark); +#ifndef REDUCED +#ifndef CDT_ONLY + } +#endif /* not CDT_ONLY */ +#endif /* not REDUCED */ +} + +/*****************************************************************************/ +/* */ +/* markhull() Cover the convex hull of a triangulation with shell edges. */ +/* */ +/*****************************************************************************/ + +void markhull() +{ + struct triedge hulltri; + struct triedge nexttri; + struct triedge starttri; + triangle ptr; /* Temporary variable used by sym() and oprev(). */ + + /* Find a triangle handle on the hull. */ + hulltri.tri = dummytri; + hulltri.orient = 0; + symself(hulltri); + /* Remember where we started so we know when to stop. */ + triedgecopy(hulltri, starttri); + /* Go once counterclockwise around the convex hull. */ + do { + /* Create a shell edge if there isn't already one here. */ + insertshelle(&hulltri, 1); + /* To find the next hull edge, go clockwise around the next vertex. */ + lnextself(hulltri); + oprev(hulltri, nexttri); + while (nexttri.tri != dummytri) { + triedgecopy(nexttri, hulltri); + oprev(hulltri, nexttri); + } + } while (!triedgeequal(hulltri, starttri)); +} + +/*****************************************************************************/ +/* */ +/* formskeleton() Create the shell edges of a triangulation, including */ +/* PSLG edges and edges on the convex hull. */ +/* */ +/* The PSLG edges are read from a .poly file. The return value is the */ +/* number of segments in the file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +int formskeleton(segmentlist, segmentmarkerlist, numberofsegments) +int *segmentlist; +int *segmentmarkerlist; +int numberofsegments; + +#else /* not TRILIBRARY */ + +int formskeleton(polyfile, polyfilename) +FILE *polyfile; +char *polyfilename; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + char polyfilename[6]; + int index; +#else /* not TRILIBRARY */ + char inputline[INPUTLINESIZE]; + char *stringptr; +#endif /* not TRILIBRARY */ + point endpoint1, endpoint2; + int segments; + int segmentmarkers; + int end1, end2; + int boundmarker; + int i; + + if (poly) { + if (!quiet) { + printf("Inserting segments into Delaunay triangulation.\n"); + } +#ifdef TRILIBRARY + strcpy(polyfilename, "input"); + segments = numberofsegments; + segmentmarkers = segmentmarkerlist != (int *) NULL; + index = 0; +#else /* not TRILIBRARY */ + /* Read the segments from a .poly file. */ + /* Read number of segments and number of boundary markers. */ + stringptr = readline(inputline, polyfile, polyfilename); + segments = (int) strtol (stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + segmentmarkers = 0; + } else { + segmentmarkers = (int) strtol (stringptr, &stringptr, 0); + } +#endif /* not TRILIBRARY */ + /* If segments are to be inserted, compute a mapping */ + /* from points to triangles. */ + if (segments > 0) { + if (verbose) { + printf(" Inserting PSLG segments.\n"); + } + makepointmap(); + } + + boundmarker = 0; + /* Read and insert the segments. */ + for (i = 1; i <= segments; i++) { +#ifdef TRILIBRARY + end1 = segmentlist[index++]; + end2 = segmentlist[index++]; + if (segmentmarkers) { + boundmarker = segmentmarkerlist[i - 1]; + } +#else /* not TRILIBRARY */ + stringptr = readline(inputline, polyfile, inpolyfilename); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Segment %d has no endpoints in %s.\n", i, + polyfilename); + exit(1); + } else { + end1 = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Segment %d is missing its second endpoint in %s.\n", i, + polyfilename); + exit(1); + } else { + end2 = (int) strtol (stringptr, &stringptr, 0); + } + if (segmentmarkers) { + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + boundmarker = 0; + } else { + boundmarker = (int) strtol (stringptr, &stringptr, 0); + } + } +#endif /* not TRILIBRARY */ + if ((end1 < firstnumber) || (end1 >= firstnumber + inpoints)) { + if (!quiet) { + printf("Warning: Invalid first endpoint of segment %d in %s.\n", i, + polyfilename); + } + } else if ((end2 < firstnumber) || (end2 >= firstnumber + inpoints)) { + if (!quiet) { + printf("Warning: Invalid second endpoint of segment %d in %s.\n", i, + polyfilename); + } + } else { + endpoint1 = getpoint(end1); + endpoint2 = getpoint(end2); + if ((endpoint1[0] == endpoint2[0]) && (endpoint1[1] == endpoint2[1])) { + if (!quiet) { + printf("Warning: Endpoints of segment %d are coincident in %s.\n", + i, polyfilename); + } + } else { + insertsegment(endpoint1, endpoint2, boundmarker); + } + } + } + } else { + segments = 0; + } + if (convex || !poly) { + /* Enclose the convex hull with shell edges. */ + if (verbose) { + printf(" Enclosing convex hull with segments.\n"); + } + markhull(); + } + return segments; +} + +/** **/ +/** **/ +/********* Segment (shell edge) insertion ends here *********/ + +/********* Carving out holes and concavities begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* infecthull() Virally infect all of the triangles of the convex hull */ +/* that are not protected by shell edges. Where there are */ +/* shell edges, set boundary markers as appropriate. */ +/* */ +/*****************************************************************************/ + +void infecthull() +{ + struct triedge hulltri; + struct triedge nexttri; + struct triedge starttri; + struct edge hulledge; + triangle **deadtri; + point horg, hdest; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + if (verbose) { + printf(" Marking concavities (external triangles) for elimination.\n"); + } + /* Find a triangle handle on the hull. */ + hulltri.tri = dummytri; + hulltri.orient = 0; + symself(hulltri); + /* Remember where we started so we know when to stop. */ + triedgecopy(hulltri, starttri); + /* Go once counterclockwise around the convex hull. */ + do { + /* Ignore triangles that are already infected. */ + if (!infected(hulltri)) { + /* Is the triangle protected by a shell edge? */ + tspivot(hulltri, hulledge); + if (hulledge.sh == dummysh) { + /* The triangle is not protected; infect it. */ + infect(hulltri); + deadtri = (triangle **) poolalloc(&viri); + *deadtri = hulltri.tri; + } else { + /* The triangle is protected; set boundary markers if appropriate. */ + if (mark(hulledge) == 0) { + setmark(hulledge, 1); + org(hulltri, horg); + dest(hulltri, hdest); + if (pointmark(horg) == 0) { + setpointmark(horg, 1); + } + if (pointmark(hdest) == 0) { + setpointmark(hdest, 1); + } + } + } + } + /* To find the next hull edge, go clockwise around the next vertex. */ + lnextself(hulltri); + oprev(hulltri, nexttri); + while (nexttri.tri != dummytri) { + triedgecopy(nexttri, hulltri); + oprev(hulltri, nexttri); + } + } while (!triedgeequal(hulltri, starttri)); +} + +/*****************************************************************************/ +/* */ +/* plague() Spread the virus from all infected triangles to any neighbors */ +/* not protected by shell edges. Delete all infected triangles. */ +/* */ +/* This is the procedure that actually creates holes and concavities. */ +/* */ +/* This procedure operates in two phases. The first phase identifies all */ +/* the triangles that will die, and marks them as infected. They are */ +/* marked to ensure that each triangle is added to the virus pool only */ +/* once, so the procedure will terminate. */ +/* */ +/* The second phase actually eliminates the infected triangles. It also */ +/* eliminates orphaned points. */ +/* */ +/*****************************************************************************/ + +void plague() +{ + struct triedge testtri; + struct triedge neighbor; + triangle **virusloop; + triangle **deadtri; + struct edge neighborshelle; + point testpoint; + point norg, ndest; + point deadorg, deaddest, deadapex; + int killorg; + triangle ptr; /* Temporary variable used by sym() and onext(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + if (verbose) { + printf(" Marking neighbors of marked triangles.\n"); + } + /* Loop through all the infected triangles, spreading the virus to */ + /* their neighbors, then to their neighbors' neighbors. */ + traversalinit(&viri); + virusloop = (triangle **) traverse(&viri); + while (virusloop != (triangle **) NULL) { + testtri.tri = *virusloop; + /* A triangle is marked as infected by messing with one of its shell */ + /* edges, setting it to an illegal value. Hence, we have to */ + /* temporarily uninfect this triangle so that we can examine its */ + /* adjacent shell edges. */ + uninfect(testtri); + if (verbose > 2) { + /* Assign the triangle an orientation for convenience in */ + /* checking its points. */ + testtri.orient = 0; + org(testtri, deadorg); + dest(testtri, deaddest); + apex(testtri, deadapex); + printf(" Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + deadorg[0], deadorg[1], deaddest[0], deaddest[1], + deadapex[0], deadapex[1]); + } + /* Check each of the triangle's three neighbors. */ + for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { + /* Find the neighbor. */ + sym(testtri, neighbor); + /* Check for a shell between the triangle and its neighbor. */ + tspivot(testtri, neighborshelle); + /* Check if the neighbor is nonexistent or already infected. */ + if ((neighbor.tri == dummytri) || infected(neighbor)) { + if (neighborshelle.sh != dummysh) { + /* There is a shell edge separating the triangle from its */ + /* neighbor, but both triangles are dying, so the shell */ + /* edge dies too. */ + shelledealloc(neighborshelle.sh); + if (neighbor.tri != dummytri) { + /* Make sure the shell edge doesn't get deallocated again */ + /* later when the infected neighbor is visited. */ + uninfect(neighbor); + tsdissolve(neighbor); + infect(neighbor); + } + } + } else { /* The neighbor exists and is not infected. */ + if (neighborshelle.sh == dummysh) { + /* There is no shell edge protecting the neighbor, so */ + /* the neighbor becomes infected. */ + if (verbose > 2) { + org(neighbor, deadorg); + dest(neighbor, deaddest); + apex(neighbor, deadapex); + printf( + " Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + deadorg[0], deadorg[1], deaddest[0], deaddest[1], + deadapex[0], deadapex[1]); + } + infect(neighbor); + /* Ensure that the neighbor's neighbors will be infected. */ + deadtri = (triangle **) poolalloc(&viri); + *deadtri = neighbor.tri; + } else { /* The neighbor is protected by a shell edge. */ + /* Remove this triangle from the shell edge. */ + stdissolve(neighborshelle); + /* The shell edge becomes a boundary. Set markers accordingly. */ + if (mark(neighborshelle) == 0) { + setmark(neighborshelle, 1); + } + org(neighbor, norg); + dest(neighbor, ndest); + if (pointmark(norg) == 0) { + setpointmark(norg, 1); + } + if (pointmark(ndest) == 0) { + setpointmark(ndest, 1); + } + } + } + } + /* Remark the triangle as infected, so it doesn't get added to the */ + /* virus pool again. */ + infect(testtri); + virusloop = (triangle **) traverse(&viri); + } + + if (verbose) { + printf(" Deleting marked triangles.\n"); + } + traversalinit(&viri); + virusloop = (triangle **) traverse(&viri); + while (virusloop != (triangle **) NULL) { + testtri.tri = *virusloop; + + /* Check each of the three corners of the triangle for elimination. */ + /* This is done by walking around each point, checking if it is */ + /* still connected to at least one live triangle. */ + for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { + org(testtri, testpoint); + /* Check if the point has already been tested. */ + if (testpoint != (point) NULL) { + killorg = 1; + /* Mark the corner of the triangle as having been tested. */ + setorg(testtri, NULL); + /* Walk counterclockwise about the point. */ + onext(testtri, neighbor); + /* Stop upon reaching a boundary or the starting triangle. */ + while ((neighbor.tri != dummytri) + && (!triedgeequal(neighbor, testtri))) { + if (infected(neighbor)) { + /* Mark the corner of this triangle as having been tested. */ + setorg(neighbor, NULL); + } else { + /* A live triangle. The point survives. */ + killorg = 0; + } + /* Walk counterclockwise about the point. */ + onextself(neighbor); + } + /* If we reached a boundary, we must walk clockwise as well. */ + if (neighbor.tri == dummytri) { + /* Walk clockwise about the point. */ + oprev(testtri, neighbor); + /* Stop upon reaching a boundary. */ + while (neighbor.tri != dummytri) { + if (infected(neighbor)) { + /* Mark the corner of this triangle as having been tested. */ + setorg(neighbor, NULL); + } else { + /* A live triangle. The point survives. */ + killorg = 0; + } + /* Walk clockwise about the point. */ + oprevself(neighbor); + } + } + if (killorg) { + if (verbose > 1) { + printf(" Deleting point (%.12g, %.12g)\n", + testpoint[0], testpoint[1]); + } + pointdealloc(testpoint); + } + } + } + + /* Record changes in the number of boundary edges, and disconnect */ + /* dead triangles from their neighbors. */ + for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { + sym(testtri, neighbor); + if (neighbor.tri == dummytri) { + /* There is no neighboring triangle on this edge, so this edge */ + /* is a boundary edge. This triangle is being deleted, so this */ + /* boundary edge is deleted. */ + hullsize--; + } else { + /* Disconnect the triangle from its neighbor. */ + dissolve(neighbor); + /* There is a neighboring triangle on this edge, so this edge */ + /* becomes a boundary edge when this triangle is deleted. */ + hullsize++; + } + } + /* Return the dead triangle to the pool of triangles. */ + triangledealloc(testtri.tri); + virusloop = (triangle **) traverse(&viri); + } + /* Empty the virus pool. */ + poolrestart(&viri); +} + +/*****************************************************************************/ +/* */ +/* regionplague() Spread regional attributes and/or area constraints */ +/* (from a .poly file) throughout the mesh. */ +/* */ +/* This procedure operates in two phases. The first phase spreads an */ +/* attribute and/or an area constraint through a (segment-bounded) region. */ +/* The triangles are marked to ensure that each triangle is added to the */ +/* virus pool only once, so the procedure will terminate. */ +/* */ +/* The second phase uninfects all infected triangles, returning them to */ +/* normal. */ +/* */ +/*****************************************************************************/ + +void regionplague(attribute, area) +REAL attribute; +REAL area; +{ + struct triedge testtri; + struct triedge neighbor; + triangle **virusloop; + triangle **regiontri; + struct edge neighborshelle; + point regionorg, regiondest, regionapex; + triangle ptr; /* Temporary variable used by sym() and onext(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + if (verbose > 1) { + printf(" Marking neighbors of marked triangles.\n"); + } + /* Loop through all the infected triangles, spreading the attribute */ + /* and/or area constraint to their neighbors, then to their neighbors' */ + /* neighbors. */ + traversalinit(&viri); + virusloop = (triangle **) traverse(&viri); + while (virusloop != (triangle **) NULL) { + testtri.tri = *virusloop; + /* A triangle is marked as infected by messing with one of its shell */ + /* edges, setting it to an illegal value. Hence, we have to */ + /* temporarily uninfect this triangle so that we can examine its */ + /* adjacent shell edges. */ + uninfect(testtri); + if (regionattrib) { + /* Set an attribute. */ + setelemattribute(testtri, eextras, attribute); + } + if (vararea) { + /* Set an area constraint. */ + setareabound(testtri, area); + } + if (verbose > 2) { + /* Assign the triangle an orientation for convenience in */ + /* checking its points. */ + testtri.orient = 0; + org(testtri, regionorg); + dest(testtri, regiondest); + apex(testtri, regionapex); + printf(" Checking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + regionorg[0], regionorg[1], regiondest[0], regiondest[1], + regionapex[0], regionapex[1]); + } + /* Check each of the triangle's three neighbors. */ + for (testtri.orient = 0; testtri.orient < 3; testtri.orient++) { + /* Find the neighbor. */ + sym(testtri, neighbor); + /* Check for a shell between the triangle and its neighbor. */ + tspivot(testtri, neighborshelle); + /* Make sure the neighbor exists, is not already infected, and */ + /* isn't protected by a shell edge. */ + if ((neighbor.tri != dummytri) && !infected(neighbor) + && (neighborshelle.sh == dummysh)) { + if (verbose > 2) { + org(neighbor, regionorg); + dest(neighbor, regiondest); + apex(neighbor, regionapex); + printf(" Marking (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + regionorg[0], regionorg[1], regiondest[0], regiondest[1], + regionapex[0], regionapex[1]); + } + /* Infect the neighbor. */ + infect(neighbor); + /* Ensure that the neighbor's neighbors will be infected. */ + regiontri = (triangle **) poolalloc(&viri); + *regiontri = neighbor.tri; + } + } + /* Remark the triangle as infected, so it doesn't get added to the */ + /* virus pool again. */ + infect(testtri); + virusloop = (triangle **) traverse(&viri); + } + + /* Uninfect all triangles. */ + if (verbose > 1) { + printf(" Unmarking marked triangles.\n"); + } + traversalinit(&viri); + virusloop = (triangle **) traverse(&viri); + while (virusloop != (triangle **) NULL) { + testtri.tri = *virusloop; + uninfect(testtri); + virusloop = (triangle **) traverse(&viri); + } + /* Empty the virus pool. */ + poolrestart(&viri); +} + +/*****************************************************************************/ +/* */ +/* carveholes() Find the holes and infect them. Find the area */ +/* constraints and infect them. Infect the convex hull. */ +/* Spread the infection and kill triangles. Spread the */ +/* area constraints. */ +/* */ +/* This routine mainly calls other routines to carry out all these */ +/* functions. */ +/* */ +/*****************************************************************************/ + +void carveholes(holelist, holes, regionlist, regions) +REAL *holelist; +int holes; +REAL *regionlist; +int regions; +{ + struct triedge searchtri; + struct triedge triangleloop; + struct triedge *regiontris; + triangle **holetri; + triangle **regiontri; + point searchorg, searchdest; + enum locateresult intersect; + int i; + triangle ptr; /* Temporary variable used by sym(). */ + + if (!(quiet || (noholes && convex))) { + printf("Removing unwanted triangles.\n"); + if (verbose && (holes > 0)) { + printf(" Marking holes for elimination.\n"); + } + } + + if (regions > 0) { + /* Allocate storage for the triangles in which region points fall. */ + regiontris = (struct triedge *) malloc(regions * sizeof(struct triedge)); + if (regiontris == (struct triedge *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + + if (((holes > 0) && !noholes) || !convex || (regions > 0)) { + /* Initialize a pool of viri to be used for holes, concavities, */ + /* regional attributes, and/or regional area constraints. */ + poolinit(&viri, sizeof(triangle *), VIRUSPERBLOCK, POINTER, 0); + } + + if (!convex) { + /* Mark as infected any unprotected triangles on the boundary. */ + /* This is one way by which concavities are created. */ + infecthull(); + } + + if ((holes > 0) && !noholes) { + /* Infect each triangle in which a hole lies. */ + for (i = 0; i < 2 * holes; i += 2) { + /* Ignore holes that aren't within the bounds of the mesh. */ + if ((holelist[i] >= xmin) && (holelist[i] <= xmax) + && (holelist[i + 1] >= ymin) && (holelist[i + 1] <= ymax)) { + /* Start searching from some triangle on the outer boundary. */ + searchtri.tri = dummytri; + searchtri.orient = 0; + symself(searchtri); + /* Ensure that the hole is to the left of this boundary edge; */ + /* otherwise, locate() will falsely report that the hole */ + /* falls within the starting triangle. */ + org(searchtri, searchorg); + dest(searchtri, searchdest); + if (counterclockwise(searchorg, searchdest, &holelist[i]) > 0.0) { + /* Find a triangle that contains the hole. */ + intersect = locate(&holelist[i], &searchtri); + if ((intersect != OUTSIDE) && (!infected(searchtri))) { + /* Infect the triangle. This is done by marking the triangle */ + /* as infect and including the triangle in the virus pool. */ + infect(searchtri); + holetri = (triangle **) poolalloc(&viri); + *holetri = searchtri.tri; + } + } + } + } + } + + /* Now, we have to find all the regions BEFORE we carve the holes, because */ + /* locate() won't work when the triangulation is no longer convex. */ + /* (Incidentally, this is the reason why regional attributes and area */ + /* constraints can't be used when refining a preexisting mesh, which */ + /* might not be convex; they can only be used with a freshly */ + /* triangulated PSLG.) */ + if (regions > 0) { + /* Find the starting triangle for each region. */ + for (i = 0; i < regions; i++) { + regiontris[i].tri = dummytri; + /* Ignore region points that aren't within the bounds of the mesh. */ + if ((regionlist[4 * i] >= xmin) && (regionlist[4 * i] <= xmax) && + (regionlist[4 * i + 1] >= ymin) && (regionlist[4 * i + 1] <= ymax)) { + /* Start searching from some triangle on the outer boundary. */ + searchtri.tri = dummytri; + searchtri.orient = 0; + symself(searchtri); + /* Ensure that the region point is to the left of this boundary */ + /* edge; otherwise, locate() will falsely report that the */ + /* region point falls within the starting triangle. */ + org(searchtri, searchorg); + dest(searchtri, searchdest); + if (counterclockwise(searchorg, searchdest, ®ionlist[4 * i]) > + 0.0) { + /* Find a triangle that contains the region point. */ + intersect = locate(®ionlist[4 * i], &searchtri); + if ((intersect != OUTSIDE) && (!infected(searchtri))) { + /* Record the triangle for processing after the */ + /* holes have been carved. */ + triedgecopy(searchtri, regiontris[i]); + } + } + } + } + } + + if (viri.items > 0) { + /* Carve the holes and concavities. */ + plague(); + } + /* The virus pool should be empty now. */ + + if (regions > 0) { + if (!quiet) { + if (regionattrib) { + if (vararea) { + printf("Spreading regional attributes and area constraints.\n"); + } else { + printf("Spreading regional attributes.\n"); + } + } else { + printf("Spreading regional area constraints.\n"); + } + } + if (regionattrib && !refine) { + /* Assign every triangle a regional attribute of zero. */ + traversalinit(&triangles); + triangleloop.orient = 0; + triangleloop.tri = triangletraverse(); + while (triangleloop.tri != (triangle *) NULL) { + setelemattribute(triangleloop, eextras, 0.0); + triangleloop.tri = triangletraverse(); + } + } + for (i = 0; i < regions; i++) { + if (regiontris[i].tri != dummytri) { + /* Make sure the triangle under consideration still exists. */ + /* It may have been eaten by the virus. */ + if (regiontris[i].tri[3] != (triangle) NULL) { + /* Put one triangle in the virus pool. */ + infect(regiontris[i]); + regiontri = (triangle **) poolalloc(&viri); + *regiontri = regiontris[i].tri; + /* Apply one region's attribute and/or area constraint. */ + regionplague(regionlist[4 * i + 2], regionlist[4 * i + 3]); + /* The virus pool should be empty now. */ + } + } + } + if (regionattrib && !refine) { + /* Note the fact that each triangle has an additional attribute. */ + eextras++; + } + } + + /* Free up memory. */ + if (((holes > 0) && !noholes) || !convex || (regions > 0)) { + pooldeinit(&viri); + } + if (regions > 0) { + free(regiontris); + } +} + +/** **/ +/** **/ +/********* Carving out holes and concavities ends here *********/ + +/********* Mesh quality maintenance begins here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* tallyencs() Traverse the entire list of shell edges, check each edge */ +/* to see if it is encroached. If so, add it to the list. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void tallyencs() +{ + struct edge edgeloop; + int dummy; + + traversalinit(&shelles); + edgeloop.shorient = 0; + edgeloop.sh = shelletraverse(); + while (edgeloop.sh != (shelle *) NULL) { + /* If the segment is encroached, add it to the list. */ + dummy = checkedge4encroach(&edgeloop); + edgeloop.sh = shelletraverse(); + } +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* precisionerror() Print an error message for precision problems. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void precisionerror() +{ + printf("Try increasing the area criterion and/or reducing the minimum\n"); + printf(" allowable angle so that tiny triangles are not created.\n"); +#ifdef SINGLE + printf("Alternatively, try recompiling me with double precision\n"); + printf(" arithmetic (by removing \"#define SINGLE\" from the\n"); + printf(" source file or \"-DSINGLE\" from the makefile).\n"); +#endif /* SINGLE */ +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* repairencs() Find and repair all the encroached segments. */ +/* */ +/* Encroached segments are repaired by splitting them by inserting a point */ +/* at or near their centers. */ +/* */ +/* `flaws' is a flag that specifies whether one should take note of new */ +/* encroached segments and bad triangles that result from inserting points */ +/* to repair existing encroached segments. */ +/* */ +/* When a segment is split, the two resulting subsegments are always */ +/* tested to see if they are encroached upon, regardless of the value */ +/* of `flaws'. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void repairencs(flaws) +int flaws; +{ + struct triedge enctri; + struct triedge testtri; + struct edge *encloop; + struct edge testsh; + point eorg, edest; + point newpoint; + enum insertsiteresult success; + REAL segmentlength, nearestpoweroftwo; + REAL split; + int acuteorg, acutedest; + int dummy; + int i; + triangle ptr; /* Temporary variable used by stpivot(). */ + shelle sptr; /* Temporary variable used by snext(). */ + + while ((badsegments.items > 0) && (steinerleft != 0)) { + traversalinit(&badsegments); + encloop = badsegmenttraverse(); + while ((encloop != (struct edge *) NULL) && (steinerleft != 0)) { + /* To decide where to split a segment, we need to know if the */ + /* segment shares an endpoint with an adjacent segment. */ + /* The concern is that, if we simply split every encroached */ + /* segment in its center, two adjacent segments with a small */ + /* angle between them might lead to an infinite loop; each */ + /* point added to split one segment will encroach upon the */ + /* other segment, which must then be split with a point that */ + /* will encroach upon the first segment, and so on forever. */ + /* To avoid this, imagine a set of concentric circles, whose */ + /* radii are powers of two, about each segment endpoint. */ + /* These concentric circles determine where the segment is */ + /* split. (If both endpoints are shared with adjacent */ + /* segments, split the segment in the middle, and apply the */ + /* concentric shells for later splittings.) */ + + /* Is the origin shared with another segment? */ + stpivot(*encloop, enctri); + lnext(enctri, testtri); + tspivot(testtri, testsh); + acuteorg = testsh.sh != dummysh; + /* Is the destination shared with another segment? */ + lnextself(testtri); + tspivot(testtri, testsh); + acutedest = testsh.sh != dummysh; + /* Now, check the other side of the segment, if there's a triangle */ + /* there. */ + sym(enctri, testtri); + if (testtri.tri != dummytri) { + /* Is the destination shared with another segment? */ + lnextself(testtri); + tspivot(testtri, testsh); + acutedest = acutedest || (testsh.sh != dummysh); + /* Is the origin shared with another segment? */ + lnextself(testtri); + tspivot(testtri, testsh); + acuteorg = acuteorg || (testsh.sh != dummysh); + } + + sorg(*encloop, eorg); + sdest(*encloop, edest); + /* Use the concentric circles if exactly one endpoint is shared */ + /* with another adjacent segment. */ + if (acuteorg ^ acutedest) { + segmentlength = sqrt((edest[0] - eorg[0]) * (edest[0] - eorg[0]) + + (edest[1] - eorg[1]) * (edest[1] - eorg[1])); + /* Find the power of two nearest the segment's length. */ + nearestpoweroftwo = 1.0; + while (segmentlength > SQUAREROOTTWO * nearestpoweroftwo) { + nearestpoweroftwo *= 2.0; + } + while (segmentlength < (0.5 * SQUAREROOTTWO) * nearestpoweroftwo) { + nearestpoweroftwo *= 0.5; + } + /* Where do we split the segment? */ + split = 0.5 * nearestpoweroftwo / segmentlength; + if (acutedest) { + split = 1.0 - split; + } + } else { + /* If we're not worried about adjacent segments, split */ + /* this segment in the middle. */ + split = 0.5; + } + + /* Create the new point. */ + newpoint = (point) poolalloc(&points); + /* Interpolate its coordinate and attributes. */ + for (i = 0; i < 2 + nextras; i++) { + newpoint[i] = (1.0 - split) * eorg[i] + split * edest[i]; + } + setpointmark(newpoint, mark(*encloop)); + if (verbose > 1) { + printf( + " Splitting edge (%.12g, %.12g) (%.12g, %.12g) at (%.12g, %.12g).\n", + eorg[0], eorg[1], edest[0], edest[1], newpoint[0], newpoint[1]); + } + /* Check whether the new point lies on an endpoint. */ + if (((newpoint[0] == eorg[0]) && (newpoint[1] == eorg[1])) + || ((newpoint[0] == edest[0]) && (newpoint[1] == edest[1]))) { + printf("Error: Ran out of precision at (%.12g, %.12g).\n", + newpoint[0], newpoint[1]); + printf("I attempted to split a segment to a smaller size than can\n"); + printf(" be accommodated by the finite precision of floating point\n" + ); + printf(" arithmetic.\n"); + precisionerror(); + exit(1); + } + /* Insert the splitting point. This should always succeed. */ + success = insertsite(newpoint, &enctri, encloop, flaws, flaws); + if ((success != SUCCESSFULPOINT) && (success != ENCROACHINGPOINT)) { + printf("Internal error in repairencs():\n"); + printf(" Failure to split a segment.\n"); + internalerror(); + } + if (steinerleft > 0) { + steinerleft--; + } + /* Check the two new subsegments to see if they're encroached. */ + dummy = checkedge4encroach(encloop); + snextself(*encloop); + dummy = checkedge4encroach(encloop); + + badsegmentdealloc(encloop); + encloop = badsegmenttraverse(); + } + } +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* tallyfaces() Test every triangle in the mesh for quality measures. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void tallyfaces() +{ + struct triedge triangleloop; + + if (verbose) { + printf(" Making a list of bad triangles.\n"); + } + traversalinit(&triangles); + triangleloop.orient = 0; + triangleloop.tri = triangletraverse(); + while (triangleloop.tri != (triangle *) NULL) { + /* If the triangle is bad, enqueue it. */ + testtriangle(&triangleloop); + triangleloop.tri = triangletraverse(); + } +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* findcircumcenter() Find the circumcenter of a triangle. */ +/* */ +/* The result is returned both in terms of x-y coordinates and xi-eta */ +/* coordinates. The xi-eta coordinate system is defined in terms of the */ +/* triangle: the origin of the triangle is the origin of the coordinate */ +/* system; the destination of the triangle is one unit along the xi axis; */ +/* and the apex of the triangle is one unit along the eta axis. */ +/* */ +/* The return value indicates which edge of the triangle is shortest. */ +/* */ +/*****************************************************************************/ + +enum circumcenterresult findcircumcenter(torg, tdest, tapex, circumcenter, + xi, eta) +point torg; +point tdest; +point tapex; +point circumcenter; +REAL *xi; +REAL *eta; +{ + REAL xdo, ydo, xao, yao, xad, yad; + REAL dodist, aodist, addist; + REAL denominator; + REAL dx, dy; + + circumcentercount++; + + /* Compute the circumcenter of the triangle. */ + xdo = tdest[0] - torg[0]; + ydo = tdest[1] - torg[1]; + xao = tapex[0] - torg[0]; + yao = tapex[1] - torg[1]; + dodist = xdo * xdo + ydo * ydo; + aodist = xao * xao + yao * yao; + if (noexact) { + denominator = (REAL)(0.5 / (xdo * yao - xao * ydo)); + } else { + /* Use the counterclockwise() routine to ensure a positive (and */ + /* reasonably accurate) result, avoiding any possibility of */ + /* division by zero. */ + denominator = (REAL)(0.5 / counterclockwise(tdest, tapex, torg)); + /* Don't count the above as an orientation test. */ + counterclockcount--; + } + circumcenter[0] = torg[0] - (ydo * aodist - yao * dodist) * denominator; + circumcenter[1] = torg[1] + (xdo * aodist - xao * dodist) * denominator; + + /* To interpolate point attributes for the new point inserted at */ + /* the circumcenter, define a coordinate system with a xi-axis, */ + /* directed from the triangle's origin to its destination, and */ + /* an eta-axis, directed from its origin to its apex. */ + /* Calculate the xi and eta coordinates of the circumcenter. */ + dx = circumcenter[0] - torg[0]; + dy = circumcenter[1] - torg[1]; + *xi = (REAL)((dx * yao - xao * dy) * (2.0 * denominator)); + *eta = (REAL)((xdo * dy - dx * ydo) * (2.0 * denominator)); + + xad = tapex[0] - tdest[0]; + yad = tapex[1] - tdest[1]; + addist = xad * xad + yad * yad; + if ((addist < dodist) && (addist < aodist)) { + return OPPOSITEORG; + } else if (dodist < aodist) { + return OPPOSITEAPEX; + } else { + return OPPOSITEDEST; + } +} + +/*****************************************************************************/ +/* */ +/* splittriangle() Inserts a point at the circumcenter of a triangle. */ +/* Deletes the newly inserted point if it encroaches upon */ +/* a segment. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void splittriangle(badtri) +struct badface *badtri; +{ + point borg, bdest, bapex; + point newpoint; + REAL xi, eta; + enum insertsiteresult success; + enum circumcenterresult shortedge; + int errorflag; + int i; + + org(badtri->badfacetri, borg); + dest(badtri->badfacetri, bdest); + apex(badtri->badfacetri, bapex); + /* Make sure that this triangle is still the same triangle it was */ + /* when it was tested and determined to be of bad quality. */ + /* Subsequent transformations may have made it a different triangle. */ + if ((borg == badtri->faceorg) && (bdest == badtri->facedest) && + (bapex == badtri->faceapex)) { + if (verbose > 1) { + printf(" Splitting this triangle at its circumcenter:\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", borg[0], + borg[1], bdest[0], bdest[1], bapex[0], bapex[1]); + } + errorflag = 0; + /* Create a new point at the triangle's circumcenter. */ + newpoint = (point) poolalloc(&points); + shortedge = findcircumcenter(borg, bdest, bapex, newpoint, &xi, &eta); + /* Check whether the new point lies on a triangle vertex. */ + if (((newpoint[0] == borg[0]) && (newpoint[1] == borg[1])) + || ((newpoint[0] == bdest[0]) && (newpoint[1] == bdest[1])) + || ((newpoint[0] == bapex[0]) && (newpoint[1] == bapex[1]))) { + if (!quiet) { + printf("Warning: New point (%.12g, %.12g) falls on existing vertex.\n" + , newpoint[0], newpoint[1]); + errorflag = 1; + } + pointdealloc(newpoint); + } else { + for (i = 2; i < 2 + nextras; i++) { + /* Interpolate the point attributes at the circumcenter. */ + newpoint[i] = borg[i] + xi * (bdest[i] - borg[i]) + + eta * (bapex[i] - borg[i]); + } + /* The new point must be in the interior, and have a marker of zero. */ + setpointmark(newpoint, 0); + /* Ensure that the handle `badtri->badfacetri' represents the shortest */ + /* edge of the triangle. This ensures that the circumcenter must */ + /* fall to the left of this edge, so point location will work. */ + if (shortedge == OPPOSITEORG) { + lnextself(badtri->badfacetri); + } else if (shortedge == OPPOSITEDEST) { + lprevself(badtri->badfacetri); + } + /* Insert the circumcenter, searching from the edge of the triangle, */ + /* and maintain the Delaunay property of the triangulation. */ + success = insertsite(newpoint, &(badtri->badfacetri), + (struct edge *) NULL, 1, 1); + if (success == SUCCESSFULPOINT) { + if (steinerleft > 0) { + steinerleft--; + } + } else if (success == ENCROACHINGPOINT) { + /* If the newly inserted point encroaches upon a segment, delete it. */ + deletesite(&(badtri->badfacetri)); + } else if (success == VIOLATINGPOINT) { + /* Failed to insert the new point, but some segment was */ + /* marked as being encroached. */ + pointdealloc(newpoint); + } else { /* success == DUPLICATEPOINT */ + /* Failed to insert the new point because a vertex is already there. */ + if (!quiet) { + printf( + "Warning: New point (%.12g, %.12g) falls on existing vertex.\n" + , newpoint[0], newpoint[1]); + errorflag = 1; + } + pointdealloc(newpoint); + } + } + if (errorflag) { + if (verbose) { + printf(" The new point is at the circumcenter of triangle\n"); + printf(" (%.12g, %.12g) (%.12g, %.12g) (%.12g, %.12g)\n", + borg[0], borg[1], bdest[0], bdest[1], bapex[0], bapex[1]); + } + printf("This probably means that I am trying to refine triangles\n"); + printf(" to a smaller size than can be accommodated by the finite\n"); + printf(" precision of floating point arithmetic. (You can be\n"); + printf(" sure of this if I fail to terminate.)\n"); + precisionerror(); + } + } + /* Return the bad triangle to the pool. */ + pooldealloc(&badtriangles, (VOID *) badtri); +} + +#endif /* not CDT_ONLY */ + +/*****************************************************************************/ +/* */ +/* enforcequality() Remove all the encroached edges and bad triangles */ +/* from the triangulation. */ +/* */ +/*****************************************************************************/ + +#ifndef CDT_ONLY + +void enforcequality() +{ + int i; + + if (!quiet) { + printf("Adding Steiner points to enforce quality.\n"); + } + /* Initialize the pool of encroached segments. */ + poolinit(&badsegments, sizeof(struct edge), BADSEGMENTPERBLOCK, POINTER, 0); + if (verbose) { + printf(" Looking for encroached segments.\n"); + } + /* Test all segments to see if they're encroached. */ + tallyencs(); + if (verbose && (badsegments.items > 0)) { + printf(" Splitting encroached segments.\n"); + } + /* Note that steinerleft == -1 if an unlimited number */ + /* of Steiner points is allowed. */ + while ((badsegments.items > 0) && (steinerleft != 0)) { + /* Fix the segments without noting newly encroached segments or */ + /* bad triangles. The reason we don't want to note newly */ + /* encroached segments is because some encroached segments are */ + /* likely to be noted multiple times, and would then be blindly */ + /* split multiple times. I should fix that some time. */ + repairencs(0); + /* Now, find all the segments that became encroached while adding */ + /* points to split encroached segments. */ + tallyencs(); + } + /* At this point, if we haven't run out of Steiner points, the */ + /* triangulation should be (conforming) Delaunay. */ + + /* Next, we worry about enforcing triangle quality. */ + if ((minangle > 0.0) || vararea || fixedarea) { + /* Initialize the pool of bad triangles. */ + poolinit(&badtriangles, sizeof(struct badface), BADTRIPERBLOCK, POINTER, + 0); + /* Initialize the queues of bad triangles. */ + for (i = 0; i < 64; i++) { + queuefront[i] = (struct badface *) NULL; + queuetail[i] = &queuefront[i]; + } + /* Test all triangles to see if they're bad. */ + tallyfaces(); + if (verbose) { + printf(" Splitting bad triangles.\n"); + } + while ((badtriangles.items > 0) && (steinerleft != 0)) { + /* Fix one bad triangle by inserting a point at its circumcenter. */ + splittriangle(dequeuebadtri()); + /* Fix any encroached segments that may have resulted. Record */ + /* any new bad triangles or encroached segments that result. */ + if (badsegments.items > 0) { + repairencs(1); + } + } + } + /* At this point, if we haven't run out of Steiner points, the */ + /* triangulation should be (conforming) Delaunay and have no */ + /* low-quality triangles. */ + + /* Might we have run out of Steiner points too soon? */ + if (!quiet && (badsegments.items > 0) && (steinerleft == 0)) { + printf("\nWarning: I ran out of Steiner points, but the mesh has\n"); + if (badsegments.items == 1) { + printf(" an encroached segment, and therefore might not be truly\n"); + } else { + printf(" %ld encroached segments, and therefore might not be truly\n", + badsegments.items); + } + printf(" Delaunay. If the Delaunay property is important to you,\n"); + printf(" try increasing the number of Steiner points (controlled by\n"); + printf(" the -S switch) slightly and try again.\n\n"); + } +} + +#endif /* not CDT_ONLY */ + +/** **/ +/** **/ +/********* Mesh quality maintenance ends here *********/ + +/*****************************************************************************/ +/* */ +/* highorder() Create extra nodes for quadratic subparametric elements. */ +/* */ +/*****************************************************************************/ + +void highorder() +{ + struct triedge triangleloop, trisym; + struct edge checkmark; + point newpoint; + point torg, tdest; + int i; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + + if (!quiet) { + printf("Adding vertices for second-order triangles.\n"); + } + /* The following line ensures that dead items in the pool of nodes */ + /* cannot be allocated for the extra nodes associated with high */ + /* order elements. This ensures that the primary nodes (at the */ + /* corners of elements) will occur earlier in the output files, and */ + /* have lower indices, than the extra nodes. */ + points.deaditemstack = (VOID *) NULL; + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + /* To loop over the set of edges, loop over all triangles, and look at */ + /* the three edges of each triangle. If there isn't another triangle */ + /* adjacent to the edge, operate on the edge. If there is another */ + /* adjacent triangle, operate on the edge only if the current triangle */ + /* has a smaller pointer than its neighbor. This way, each edge is */ + /* considered only once. */ + while (triangleloop.tri != (triangle *) NULL) { + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + sym(triangleloop, trisym); + if ((triangleloop.tri < trisym.tri) || (trisym.tri == dummytri)) { + org(triangleloop, torg); + dest(triangleloop, tdest); + /* Create a new node in the middle of the edge. Interpolate */ + /* its attributes. */ + newpoint = (point) poolalloc(&points); + for (i = 0; i < 2 + nextras; i++) { + newpoint[i] = (REAL)(0.5 * (torg[i] + tdest[i])); + } + /* Set the new node's marker to zero or one, depending on */ + /* whether it lies on a boundary. */ + setpointmark(newpoint, trisym.tri == dummytri); + if (useshelles) { + tspivot(triangleloop, checkmark); + /* If this edge is a segment, transfer the marker to the new node. */ + if (checkmark.sh != dummysh) { + setpointmark(newpoint, mark(checkmark)); + } + } + if (verbose > 1) { + printf(" Creating (%.12g, %.12g).\n", newpoint[0], newpoint[1]); + } + /* Record the new node in the (one or two) adjacent elements. */ + triangleloop.tri[highorderindex + triangleloop.orient] = + (triangle) newpoint; + if (trisym.tri != dummytri) { + trisym.tri[highorderindex + trisym.orient] = (triangle) newpoint; + } + } + } + triangleloop.tri = triangletraverse(); + } +} + +/********* File I/O routines begin here *********/ +/** **/ +/** **/ + +/*****************************************************************************/ +/* */ +/* readline() Read a nonempty line from a file. */ +/* */ +/* A line is considered "nonempty" if it contains something that looks like */ +/* a number. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +char *readline(string, infile, infilename) +char *string; +FILE *infile; +char *infilename; +{ + char *result; + + /* Search for something that looks like a number. */ + do { + result = fgets(string, INPUTLINESIZE, infile); + if (result == (char *) NULL) { + printf(" Error: Unexpected end of file in %s.\n", infilename); + exit(1); + } + /* Skip anything that doesn't look like a number, a comment, */ + /* or the end of a line. */ + while ((*result != '\0') && (*result != '#') + && (*result != '.') && (*result != '+') && (*result != '-') + && ((*result < '0') || (*result > '9'))) { + result++; + } + /* If it's a comment or end of line, read another line and try again. */ + } while ((*result == '#') || (*result == '\0')); + return result; +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* findfield() Find the next field of a string. */ +/* */ +/* Jumps past the current field by searching for whitespace, then jumps */ +/* past the whitespace to find the next field. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +char *findfield(string) +char *string; +{ + char *result; + + result = string; + /* Skip the current field. Stop upon reaching whitespace. */ + while ((*result != '\0') && (*result != '#') + && (*result != ' ') && (*result != '\t')) { + result++; + } + /* Now skip the whitespace and anything else that doesn't look like a */ + /* number, a comment, or the end of a line. */ + while ((*result != '\0') && (*result != '#') + && (*result != '.') && (*result != '+') && (*result != '-') + && ((*result < '0') || (*result > '9'))) { + result++; + } + /* Check for a comment (prefixed with `#'). */ + if (*result == '#') { + *result = '\0'; + } + return result; +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* readnodes() Read the points from a file, which may be a .node or .poly */ +/* file. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void readnodes(nodefilename, polyfilename, polyfile) +char *nodefilename; +char *polyfilename; +FILE **polyfile; +{ + FILE *infile; + point pointloop; + char inputline[INPUTLINESIZE]; + char *stringptr; + char *infilename; + REAL x, y; + int firstnode; + int nodemarkers; + int currentmarker; + int i, j; + + if (poly) { + /* Read the points from a .poly file. */ + if (!quiet) { + printf("Opening %s.\n", polyfilename); + } + *polyfile = fopen(polyfilename, "r"); + if (*polyfile == (FILE *) NULL) { + printf(" Error: Cannot access file %s.\n", polyfilename); + exit(1); + } + /* Read number of points, number of dimensions, number of point */ + /* attributes, and number of boundary markers. */ + stringptr = readline(inputline, *polyfile, polyfilename); + inpoints = (int) strtol (stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + mesh_dim = 2; + } else { + mesh_dim = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + nextras = 0; + } else { + nextras = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + nodemarkers = 0; + } else { + nodemarkers = (int) strtol (stringptr, &stringptr, 0); + } + if (inpoints > 0) { + infile = *polyfile; + infilename = polyfilename; + readnodefile = 0; + } else { + /* If the .poly file claims there are zero points, that means that */ + /* the points should be read from a separate .node file. */ + readnodefile = 1; + infilename = innodefilename; + } + } else { + readnodefile = 1; + infilename = innodefilename; + *polyfile = (FILE *) NULL; + } + + if (readnodefile) { + /* Read the points from a .node file. */ + if (!quiet) { + printf("Opening %s.\n", innodefilename); + } + infile = fopen(innodefilename, "r"); + if (infile == (FILE *) NULL) { + printf(" Error: Cannot access file %s.\n", innodefilename); + exit(1); + } + /* Read number of points, number of dimensions, number of point */ + /* attributes, and number of boundary markers. */ + stringptr = readline(inputline, infile, innodefilename); + inpoints = (int) strtol (stringptr, &stringptr, 0); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + mesh_dim = 2; + } else { + mesh_dim = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + nextras = 0; + } else { + nextras = (int) strtol (stringptr, &stringptr, 0); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + nodemarkers = 0; + } else { + nodemarkers = (int) strtol (stringptr, &stringptr, 0); + } + } + + if (inpoints < 3) { + printf("Error: Input must have at least three input points.\n"); + exit(1); + } + if (mesh_dim != 2) { + printf("Error: Triangle only works with two-dimensional meshes.\n"); + exit(1); + } + + initializepointpool(); + + /* Read the points. */ + for (i = 0; i < inpoints; i++) { + pointloop = (point) poolalloc(&points); + stringptr = readline(inputline, infile, infilename); + if (i == 0) { + firstnode = (int) strtol (stringptr, &stringptr, 0); + if ((firstnode == 0) || (firstnode == 1)) { + firstnumber = firstnode; + } + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Point %d has no x coordinate.\n", firstnumber + i); + exit(1); + } + x = (REAL) strtod(stringptr, &stringptr); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Point %d has no y coordinate.\n", firstnumber + i); + exit(1); + } + y = (REAL) strtod(stringptr, &stringptr); + pointloop[0] = x; + pointloop[1] = y; + /* Read the point attributes. */ + for (j = 2; j < 2 + nextras; j++) { + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + pointloop[j] = 0.0; + } else { + pointloop[j] = (REAL) strtod(stringptr, &stringptr); + } + } + if (nodemarkers) { + /* Read a point marker. */ + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + setpointmark(pointloop, 0); + } else { + currentmarker = (int) strtol (stringptr, &stringptr, 0); + setpointmark(pointloop, currentmarker); + } + } else { + /* If no markers are specified in the file, they default to zero. */ + setpointmark(pointloop, 0); + } + /* Determine the smallest and largest x and y coordinates. */ + if (i == 0) { + xmin = xmax = x; + ymin = ymax = y; + } else { + xmin = (x < xmin) ? x : xmin; + xmax = (x > xmax) ? x : xmax; + ymin = (y < ymin) ? y : ymin; + ymax = (y > ymax) ? y : ymax; + } + } + if (readnodefile) { + fclose(infile); + } + + /* Nonexistent x value used as a flag to mark circle events in sweepline */ + /* Delaunay algorithm. */ + xminextreme = 10 * xmin - 9 * xmax; +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* transfernodes() Read the points from memory. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void transfernodes(pointlist, pointattriblist, pointmarkerlist, numberofpoints, + numberofpointattribs) +REAL *pointlist; +REAL *pointattriblist; +int *pointmarkerlist; +int numberofpoints; +int numberofpointattribs; +{ + point pointloop; + REAL x, y; + int i, j; + int coordindex; + int attribindex; + + inpoints = numberofpoints; + mesh_dim = 2; + nextras = numberofpointattribs; + readnodefile = 0; + if (inpoints < 3) { + printf("Error: Input must have at least three input points.\n"); + exit(1); + } + + initializepointpool(); + + /* Read the points. */ + coordindex = 0; + attribindex = 0; + for (i = 0; i < inpoints; i++) { + pointloop = (point) poolalloc(&points); + /* Read the point coordinates. */ + x = pointloop[0] = pointlist[coordindex++]; + y = pointloop[1] = pointlist[coordindex++]; + /* Read the point attributes. */ + for (j = 0; j < numberofpointattribs; j++) { + pointloop[2 + j] = pointattriblist[attribindex++]; + } + if (pointmarkerlist != (int *) NULL) { + /* Read a point marker. */ + setpointmark(pointloop, pointmarkerlist[i]); + } else { + /* If no markers are specified, they default to zero. */ + setpointmark(pointloop, 0); + } + x = pointloop[0]; + y = pointloop[1]; + /* Determine the smallest and largest x and y coordinates. */ + if (i == 0) { + xmin = xmax = x; + ymin = ymax = y; + } else { + xmin = (x < xmin) ? x : xmin; + xmax = (x > xmax) ? x : xmax; + ymin = (y < ymin) ? y : ymin; + ymax = (y > ymax) ? y : ymax; + } + } + + /* Nonexistent x value used as a flag to mark circle events in sweepline */ + /* Delaunay algorithm. */ + xminextreme = 10 * xmin - 9 * xmax; +} + +#endif /* TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* readholes() Read the holes, and possibly regional attributes and area */ +/* constraints, from a .poly file. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void readholes(polyfile, polyfilename, hlist, holes, rlist, regions) +FILE *polyfile; +char *polyfilename; +REAL **hlist; +int *holes; +REAL **rlist; +int *regions; +{ + REAL *holelist; + REAL *regionlist; + char inputline[INPUTLINESIZE]; + char *stringptr; + int index; + int i; + + /* Read the holes. */ + stringptr = readline(inputline, polyfile, polyfilename); + *holes = (int) strtol (stringptr, &stringptr, 0); + if (*holes > 0) { + holelist = (REAL *) malloc(2 * *holes * sizeof(REAL)); + *hlist = holelist; + if (holelist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + for (i = 0; i < 2 * *holes; i += 2) { + stringptr = readline(inputline, polyfile, polyfilename); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Hole %d has no x coordinate.\n", + firstnumber + (i >> 1)); + exit(1); + } else { + holelist[i] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Hole %d has no y coordinate.\n", + firstnumber + (i >> 1)); + exit(1); + } else { + holelist[i + 1] = (REAL) strtod(stringptr, &stringptr); + } + } + } else { + *hlist = (REAL *) NULL; + } + +#ifndef CDT_ONLY + if ((regionattrib || vararea) && !refine) { + /* Read the area constraints. */ + stringptr = readline(inputline, polyfile, polyfilename); + *regions = (int) strtol (stringptr, &stringptr, 0); + if (*regions > 0) { + regionlist = (REAL *) malloc(4 * *regions * sizeof(REAL)); + *rlist = regionlist; + if (regionlist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + index = 0; + for (i = 0; i < *regions; i++) { + stringptr = readline(inputline, polyfile, polyfilename); + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Region %d has no x coordinate.\n", + firstnumber + i); + exit(1); + } else { + regionlist[index++] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf("Error: Region %d has no y coordinate.\n", + firstnumber + i); + exit(1); + } else { + regionlist[index++] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + printf( + "Error: Region %d has no region attribute or area constraint.\n", + firstnumber + i); + exit(1); + } else { + regionlist[index++] = (REAL) strtod(stringptr, &stringptr); + } + stringptr = findfield(stringptr); + if (*stringptr == '\0') { + regionlist[index] = regionlist[index - 1]; + } else { + regionlist[index] = (REAL) strtod(stringptr, &stringptr); + } + index++; + } + } + } else { + /* Set `*regions' to zero to avoid an accidental free() later. */ + *regions = 0; + *rlist = (REAL *) NULL; + } +#endif /* not CDT_ONLY */ + + fclose(polyfile); +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* finishfile() Write the command line to the output file so the user */ +/* can remember how the file was generated. Close the file. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void finishfile(outfile, argc, argv) +FILE *outfile; +int argc; +char **argv; +{ + int i; + + fprintf(outfile, "# Generated by"); + for (i = 0; i < argc; i++) { + fprintf(outfile, " "); + fputs(argv[i], outfile); + } + fprintf(outfile, "\n"); + fclose(outfile); +} + +#endif /* not TRILIBRARY */ + +/*****************************************************************************/ +/* */ +/* writenodes() Number the points and write them to a .node file. */ +/* */ +/* To save memory, the point numbers are written over the shell markers */ +/* after the points are written to a file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void writenodes(pointlist, pointattriblist, pointmarkerlist) +REAL **pointlist; +REAL **pointattriblist; +int **pointmarkerlist; + +#else /* not TRILIBRARY */ + +void writenodes(nodefilename, argc, argv) +char *nodefilename; +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + REAL *plist; + REAL *palist; + int *pmlist; + int coordindex; + int attribindex; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + point pointloop; + int pointnumber; + int i; + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing points.\n"); + } + /* Allocate memory for output points if necessary. */ + if (*pointlist == (REAL *) NULL) { + *pointlist = (REAL *) malloc(points.items * 2 * sizeof(REAL)); + if (*pointlist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + /* Allocate memory for output point attributes if necessary. */ + if ((nextras > 0) && (*pointattriblist == (REAL *) NULL)) { + *pointattriblist = (REAL *) malloc(points.items * nextras * sizeof(REAL)); + if (*pointattriblist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + /* Allocate memory for output point markers if necessary. */ + if (!nobound && (*pointmarkerlist == (int *) NULL)) { + *pointmarkerlist = (int *) malloc(points.items * sizeof(int)); + if (*pointmarkerlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + plist = *pointlist; + palist = *pointattriblist; + pmlist = *pointmarkerlist; + coordindex = 0; + attribindex = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", nodefilename); + } + outfile = fopen(nodefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", nodefilename); + exit(1); + } + /* Number of points, number of dimensions, number of point attributes, */ + /* and number of boundary markers (zero or one). */ + fprintf(outfile, "%ld %d %d %d\n", points.items, mesh_dim, nextras, + 1 - nobound); +#endif /* not TRILIBRARY */ + + traversalinit(&points); + pointloop = pointtraverse(); + pointnumber = firstnumber; + while (pointloop != (point) NULL) { +#ifdef TRILIBRARY + /* X and y coordinates. */ + plist[coordindex++] = pointloop[0]; + plist[coordindex++] = pointloop[1]; + /* Point attributes. */ + for (i = 0; i < nextras; i++) { + palist[attribindex++] = pointloop[2 + i]; + } + if (!nobound) { + /* Copy the boundary marker. */ + pmlist[pointnumber - firstnumber] = pointmark(pointloop); + } +#else /* not TRILIBRARY */ + /* Point number, x and y coordinates. */ + fprintf(outfile, "%4d %.17g %.17g", pointnumber, pointloop[0], + pointloop[1]); + for (i = 0; i < nextras; i++) { + /* Write an attribute. */ + fprintf(outfile, " %.17g", pointloop[i + 2]); + } + if (nobound) { + fprintf(outfile, "\n"); + } else { + /* Write the boundary marker. */ + fprintf(outfile, " %d\n", pointmark(pointloop)); + } +#endif /* not TRILIBRARY */ + + setpointmark(pointloop, pointnumber); + pointloop = pointtraverse(); + pointnumber++; + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* numbernodes() Number the points. */ +/* */ +/* Each point is assigned a marker equal to its number. */ +/* */ +/* Used when writenodes() is not called because no .node file is written. */ +/* */ +/*****************************************************************************/ + +void numbernodes() +{ + point pointloop; + int pointnumber; + + traversalinit(&points); + pointloop = pointtraverse(); + pointnumber = firstnumber; + while (pointloop != (point) NULL) { + setpointmark(pointloop, pointnumber); + pointloop = pointtraverse(); + pointnumber++; + } +} + +/*****************************************************************************/ +/* */ +/* writeelements() Write the triangles to an .ele file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void writeelements(trianglelist, triangleattriblist) +int **trianglelist; +REAL **triangleattriblist; + +#else /* not TRILIBRARY */ + +void writeelements(elefilename, argc, argv) +char *elefilename; +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int *tlist; + REAL *talist; + int pointindex; + int attribindex; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + struct triedge triangleloop; + point p1, p2, p3; + point mid1, mid2, mid3; + int elementnumber; + int i; + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing triangles.\n"); + } + /* Allocate memory for output triangles if necessary. */ + if (*trianglelist == (int *) NULL) { + *trianglelist = (int *) malloc(triangles.items * + ((order + 1) * (order + 2) / 2) * sizeof(int)); + if (*trianglelist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + /* Allocate memory for output triangle attributes if necessary. */ + if ((eextras > 0) && (*triangleattriblist == (REAL *) NULL)) { + *triangleattriblist = (REAL *) malloc(triangles.items * eextras * + sizeof(REAL)); + if (*triangleattriblist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + tlist = *trianglelist; + talist = *triangleattriblist; + pointindex = 0; + attribindex = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", elefilename); + } + outfile = fopen(elefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", elefilename); + exit(1); + } + /* Number of triangles, points per triangle, attributes per triangle. */ + fprintf(outfile, "%ld %d %d\n", triangles.items, + (order + 1) * (order + 2) / 2, eextras); +#endif /* not TRILIBRARY */ + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + triangleloop.orient = 0; + elementnumber = firstnumber; + while (triangleloop.tri != (triangle *) NULL) { + org(triangleloop, p1); + dest(triangleloop, p2); + apex(triangleloop, p3); + if (order == 1) { +#ifdef TRILIBRARY + tlist[pointindex++] = pointmark(p1); + tlist[pointindex++] = pointmark(p2); + tlist[pointindex++] = pointmark(p3); +#else /* not TRILIBRARY */ + /* Triangle number, indices for three points. */ + fprintf(outfile, "%4d %4d %4d %4d", elementnumber, + pointmark(p1), pointmark(p2), pointmark(p3)); +#endif /* not TRILIBRARY */ + } else { + mid1 = (point) triangleloop.tri[highorderindex + 1]; + mid2 = (point) triangleloop.tri[highorderindex + 2]; + mid3 = (point) triangleloop.tri[highorderindex]; +#ifdef TRILIBRARY + tlist[pointindex++] = pointmark(p1); + tlist[pointindex++] = pointmark(p2); + tlist[pointindex++] = pointmark(p3); + tlist[pointindex++] = pointmark(mid1); + tlist[pointindex++] = pointmark(mid2); + tlist[pointindex++] = pointmark(mid3); +#else /* not TRILIBRARY */ + /* Triangle number, indices for six points. */ + fprintf(outfile, "%4d %4d %4d %4d %4d %4d %4d", elementnumber, + pointmark(p1), pointmark(p2), pointmark(p3), pointmark(mid1), + pointmark(mid2), pointmark(mid3)); +#endif /* not TRILIBRARY */ + } + +#ifdef TRILIBRARY + for (i = 0; i < eextras; i++) { + talist[attribindex++] = elemattribute(triangleloop, i); + } +#else /* not TRILIBRARY */ + for (i = 0; i < eextras; i++) { + fprintf(outfile, " %.17g", elemattribute(triangleloop, i)); + } + fprintf(outfile, "\n"); +#endif /* not TRILIBRARY */ + + triangleloop.tri = triangletraverse(); + elementnumber++; + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* writepoly() Write the segments and holes to a .poly file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void writepoly(segmentlist, segmentmarkerlist) +int **segmentlist; +int **segmentmarkerlist; + +#else /* not TRILIBRARY */ + +void writepoly(polyfilename, holelist, holes, regionlist, regions, argc, argv) +char *polyfilename; +REAL *holelist; +int holes; +REAL *regionlist; +int regions; +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int *slist; + int *smlist; + int index; +#else /* not TRILIBRARY */ + FILE *outfile; + int i; +#endif /* not TRILIBRARY */ + struct edge shelleloop; + point endpoint1, endpoint2; + int shellenumber; + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing segments.\n"); + } + /* Allocate memory for output segments if necessary. */ + if (*segmentlist == (int *) NULL) { + *segmentlist = (int *) malloc(shelles.items * 2 * sizeof(int)); + if (*segmentlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + /* Allocate memory for output segment markers if necessary. */ + if (!nobound && (*segmentmarkerlist == (int *) NULL)) { + *segmentmarkerlist = (int *) malloc(shelles.items * sizeof(int)); + if (*segmentmarkerlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + slist = *segmentlist; + smlist = *segmentmarkerlist; + index = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", polyfilename); + } + outfile = fopen(polyfilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", polyfilename); + exit(1); + } + /* The zero indicates that the points are in a separate .node file. */ + /* Followed by number of dimensions, number of point attributes, */ + /* and number of boundary markers (zero or one). */ + fprintf(outfile, "%d %d %d %d\n", 0, mesh_dim, nextras, 1 - nobound); + /* Number of segments, number of boundary markers (zero or one). */ + fprintf(outfile, "%ld %d\n", shelles.items, 1 - nobound); +#endif /* not TRILIBRARY */ + + traversalinit(&shelles); + shelleloop.sh = shelletraverse(); + shelleloop.shorient = 0; + shellenumber = firstnumber; + while (shelleloop.sh != (shelle *) NULL) { + sorg(shelleloop, endpoint1); + sdest(shelleloop, endpoint2); +#ifdef TRILIBRARY + /* Copy indices of the segment's two endpoints. */ + slist[index++] = pointmark(endpoint1); + slist[index++] = pointmark(endpoint2); + if (!nobound) { + /* Copy the boundary marker. */ + smlist[shellenumber - firstnumber] = mark(shelleloop); + } +#else /* not TRILIBRARY */ + /* Segment number, indices of its two endpoints, and possibly a marker. */ + if (nobound) { + fprintf(outfile, "%4d %4d %4d\n", shellenumber, + pointmark(endpoint1), pointmark(endpoint2)); + } else { + fprintf(outfile, "%4d %4d %4d %4d\n", shellenumber, + pointmark(endpoint1), pointmark(endpoint2), mark(shelleloop)); + } +#endif /* not TRILIBRARY */ + + shelleloop.sh = shelletraverse(); + shellenumber++; + } + +#ifndef TRILIBRARY +#ifndef CDT_ONLY + fprintf(outfile, "%d\n", holes); + if (holes > 0) { + for (i = 0; i < holes; i++) { + /* Hole number, x and y coordinates. */ + fprintf(outfile, "%4d %.17g %.17g\n", firstnumber + i, + holelist[2 * i], holelist[2 * i + 1]); + } + } + if (regions > 0) { + fprintf(outfile, "%d\n", regions); + for (i = 0; i < regions; i++) { + /* Region number, x and y coordinates, attribute, maximum area. */ + fprintf(outfile, "%4d %.17g %.17g %.17g %.17g\n", firstnumber + i, + regionlist[4 * i], regionlist[4 * i + 1], + regionlist[4 * i + 2], regionlist[4 * i + 3]); + } + } +#endif /* not CDT_ONLY */ + + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* writeedges() Write the edges to a .edge file. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void writeedges(edgelist, edgemarkerlist) +int **edgelist; +int **edgemarkerlist; + +#else /* not TRILIBRARY */ + +void writeedges(edgefilename, argc, argv) +char *edgefilename; +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int *elist; + int *emlist; + int index; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + struct triedge triangleloop, trisym; + struct edge checkmark; + point p1, p2; + int edgenumber; + triangle ptr; /* Temporary variable used by sym(). */ + shelle sptr; /* Temporary variable used by tspivot(). */ + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing edges.\n"); + } + /* Allocate memory for edges if necessary. */ + if (*edgelist == (int *) NULL) { + *edgelist = (int *) malloc(edges * 2 * sizeof(int)); + if (*edgelist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + /* Allocate memory for edge markers if necessary. */ + if (!nobound && (*edgemarkerlist == (int *) NULL)) { + *edgemarkerlist = (int *) malloc(edges * sizeof(int)); + if (*edgemarkerlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + elist = *edgelist; + emlist = *edgemarkerlist; + index = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", edgefilename); + } + outfile = fopen(edgefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", edgefilename); + exit(1); + } + /* Number of edges, number of boundary markers (zero or one). */ + fprintf(outfile, "%ld %d\n", edges, 1 - nobound); +#endif /* not TRILIBRARY */ + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + edgenumber = firstnumber; + /* To loop over the set of edges, loop over all triangles, and look at */ + /* the three edges of each triangle. If there isn't another triangle */ + /* adjacent to the edge, operate on the edge. If there is another */ + /* adjacent triangle, operate on the edge only if the current triangle */ + /* has a smaller pointer than its neighbor. This way, each edge is */ + /* considered only once. */ + while (triangleloop.tri != (triangle *) NULL) { + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + sym(triangleloop, trisym); + if ((triangleloop.tri < trisym.tri) || (trisym.tri == dummytri)) { + org(triangleloop, p1); + dest(triangleloop, p2); +#ifdef TRILIBRARY + elist[index++] = pointmark(p1); + elist[index++] = pointmark(p2); +#endif /* TRILIBRARY */ + if (nobound) { +#ifndef TRILIBRARY + /* Edge number, indices of two endpoints. */ + fprintf(outfile, "%4d %d %d\n", edgenumber, + pointmark(p1), pointmark(p2)); +#endif /* not TRILIBRARY */ + } else { + /* Edge number, indices of two endpoints, and a boundary marker. */ + /* If there's no shell edge, the boundary marker is zero. */ + if (useshelles) { + tspivot(triangleloop, checkmark); + if (checkmark.sh == dummysh) { +#ifdef TRILIBRARY + emlist[edgenumber - firstnumber] = 0; +#else /* not TRILIBRARY */ + fprintf(outfile, "%4d %d %d %d\n", edgenumber, + pointmark(p1), pointmark(p2), 0); +#endif /* not TRILIBRARY */ + } else { +#ifdef TRILIBRARY + emlist[edgenumber - firstnumber] = mark(checkmark); +#else /* not TRILIBRARY */ + fprintf(outfile, "%4d %d %d %d\n", edgenumber, + pointmark(p1), pointmark(p2), mark(checkmark)); +#endif /* not TRILIBRARY */ + } + } else { +#ifdef TRILIBRARY + emlist[edgenumber - firstnumber] = trisym.tri == dummytri; +#else /* not TRILIBRARY */ + fprintf(outfile, "%4d %d %d %d\n", edgenumber, + pointmark(p1), pointmark(p2), trisym.tri == dummytri); +#endif /* not TRILIBRARY */ + } + } + edgenumber++; + } + } + triangleloop.tri = triangletraverse(); + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* writevoronoi() Write the Voronoi diagram to a .v.node and .v.edge */ +/* file. */ +/* */ +/* The Voronoi diagram is the geometric dual of the Delaunay triangulation. */ +/* Hence, the Voronoi vertices are listed by traversing the Delaunay */ +/* triangles, and the Voronoi edges are listed by traversing the Delaunay */ +/* edges. */ +/* */ +/* WARNING: In order to assign numbers to the Voronoi vertices, this */ +/* procedure messes up the shell edges or the extra nodes of every */ +/* element. Hence, you should call this procedure last. */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void writevoronoi(vpointlist, vpointattriblist, vpointmarkerlist, vedgelist, + vedgemarkerlist, vnormlist) +REAL **vpointlist; +REAL **vpointattriblist; +int **vpointmarkerlist; +int **vedgelist; +int **vedgemarkerlist; +REAL **vnormlist; + +#else /* not TRILIBRARY */ + +void writevoronoi(vnodefilename, vedgefilename, argc, argv) +char *vnodefilename; +char *vedgefilename; +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + REAL *plist; + REAL *palist; + int *elist; + REAL *normlist; + int coordindex; + int attribindex; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + struct triedge triangleloop, trisym; + point torg, tdest, tapex; + REAL circumcenter[2]; + REAL xi, eta; + int vnodenumber, vedgenumber; + int p1, p2; + int i; + triangle ptr; /* Temporary variable used by sym(). */ + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing Voronoi vertices.\n"); + } + /* Allocate memory for Voronoi vertices if necessary. */ + if (*vpointlist == (REAL *) NULL) { + *vpointlist = (REAL *) malloc(triangles.items * 2 * sizeof(REAL)); + if (*vpointlist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + /* Allocate memory for Voronoi vertex attributes if necessary. */ + if (*vpointattriblist == (REAL *) NULL) { + *vpointattriblist = (REAL *) malloc(triangles.items * nextras * + sizeof(REAL)); + if (*vpointattriblist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + *vpointmarkerlist = (int *) NULL; + plist = *vpointlist; + palist = *vpointattriblist; + coordindex = 0; + attribindex = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", vnodefilename); + } + outfile = fopen(vnodefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", vnodefilename); + exit(1); + } + /* Number of triangles, two dimensions, number of point attributes, */ + /* zero markers. */ + fprintf(outfile, "%ld %d %d %d\n", triangles.items, 2, nextras, 0); +#endif /* not TRILIBRARY */ + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + triangleloop.orient = 0; + vnodenumber = firstnumber; + while (triangleloop.tri != (triangle *) NULL) { + org(triangleloop, torg); + dest(triangleloop, tdest); + apex(triangleloop, tapex); + findcircumcenter(torg, tdest, tapex, circumcenter, &xi, &eta); +#ifdef TRILIBRARY + /* X and y coordinates. */ + plist[coordindex++] = circumcenter[0]; + plist[coordindex++] = circumcenter[1]; + for (i = 2; i < 2 + nextras; i++) { + /* Interpolate the point attributes at the circumcenter. */ + palist[attribindex++] = torg[i] + xi * (tdest[i] - torg[i]) + + eta * (tapex[i] - torg[i]); + } +#else /* not TRILIBRARY */ + /* Voronoi vertex number, x and y coordinates. */ + fprintf(outfile, "%4d %.17g %.17g", vnodenumber, circumcenter[0], + circumcenter[1]); + for (i = 2; i < 2 + nextras; i++) { + /* Interpolate the point attributes at the circumcenter. */ + fprintf(outfile, " %.17g", torg[i] + xi * (tdest[i] - torg[i]) + + eta * (tapex[i] - torg[i])); + } + fprintf(outfile, "\n"); +#endif /* not TRILIBRARY */ + + * (int *) (triangleloop.tri + 6) = vnodenumber; + triangleloop.tri = triangletraverse(); + vnodenumber++; + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing Voronoi edges.\n"); + } + /* Allocate memory for output Voronoi edges if necessary. */ + if (*vedgelist == (int *) NULL) { + *vedgelist = (int *) malloc(edges * 2 * sizeof(int)); + if (*vedgelist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + *vedgemarkerlist = (int *) NULL; + /* Allocate memory for output Voronoi norms if necessary. */ + if (*vnormlist == (REAL *) NULL) { + *vnormlist = (REAL *) malloc(edges * 2 * sizeof(REAL)); + if (*vnormlist == (REAL *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + elist = *vedgelist; + normlist = *vnormlist; + coordindex = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", vedgefilename); + } + outfile = fopen(vedgefilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", vedgefilename); + exit(1); + } + /* Number of edges, zero boundary markers. */ + fprintf(outfile, "%ld %d\n", edges, 0); +#endif /* not TRILIBRARY */ + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + vedgenumber = firstnumber; + /* To loop over the set of edges, loop over all triangles, and look at */ + /* the three edges of each triangle. If there isn't another triangle */ + /* adjacent to the edge, operate on the edge. If there is another */ + /* adjacent triangle, operate on the edge only if the current triangle */ + /* has a smaller pointer than its neighbor. This way, each edge is */ + /* considered only once. */ + while (triangleloop.tri != (triangle *) NULL) { + for (triangleloop.orient = 0; triangleloop.orient < 3; + triangleloop.orient++) { + sym(triangleloop, trisym); + if ((triangleloop.tri < trisym.tri) || (trisym.tri == dummytri)) { + /* Find the number of this triangle (and Voronoi vertex). */ + p1 = * (int *) (triangleloop.tri + 6); + if (trisym.tri == dummytri) { + org(triangleloop, torg); + dest(triangleloop, tdest); +#ifdef TRILIBRARY + /* Copy an infinite ray. Index of one endpoint, and -1. */ + elist[coordindex] = p1; + normlist[coordindex++] = tdest[1] - torg[1]; + elist[coordindex] = -1; + normlist[coordindex++] = torg[0] - tdest[0]; +#else /* not TRILIBRARY */ + /* Write an infinite ray. Edge number, index of one endpoint, -1, */ + /* and x and y coordinates of a vector representing the */ + /* direction of the ray. */ + fprintf(outfile, "%4d %d %d %.17g %.17g\n", vedgenumber, + p1, -1, tdest[1] - torg[1], torg[0] - tdest[0]); +#endif /* not TRILIBRARY */ + } else { + /* Find the number of the adjacent triangle (and Voronoi vertex). */ + p2 = * (int *) (trisym.tri + 6); + /* Finite edge. Write indices of two endpoints. */ +#ifdef TRILIBRARY + elist[coordindex] = p1; + normlist[coordindex++] = 0.0; + elist[coordindex] = p2; + normlist[coordindex++] = 0.0; +#else /* not TRILIBRARY */ + fprintf(outfile, "%4d %d %d\n", vedgenumber, p1, p2); +#endif /* not TRILIBRARY */ + } + vedgenumber++; + } + } + triangleloop.tri = triangletraverse(); + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* not TRILIBRARY */ +} + +#ifdef TRILIBRARY + +void writeneighbors(neighborlist) +int **neighborlist; + +#else /* not TRILIBRARY */ + +void writeneighbors(neighborfilename, argc, argv) +char *neighborfilename; +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ +#ifdef TRILIBRARY + int *nlist; + int index; +#else /* not TRILIBRARY */ + FILE *outfile; +#endif /* not TRILIBRARY */ + struct triedge triangleloop, trisym; + int elementnumber; + int neighbor1, neighbor2, neighbor3; + triangle ptr; /* Temporary variable used by sym(). */ + +#ifdef TRILIBRARY + if (!quiet) { + printf("Writing neighbors.\n"); + } + /* Allocate memory for neighbors if necessary. */ + if (*neighborlist == (int *) NULL) { + *neighborlist = (int *) malloc(triangles.items * 3 * sizeof(int)); + if (*neighborlist == (int *) NULL) { + printf("Error: Out of memory.\n"); + exit(1); + } + } + nlist = *neighborlist; + index = 0; +#else /* not TRILIBRARY */ + if (!quiet) { + printf("Writing %s.\n", neighborfilename); + } + outfile = fopen(neighborfilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", neighborfilename); + exit(1); + } + /* Number of triangles, three edges per triangle. */ + fprintf(outfile, "%ld %d\n", triangles.items, 3); +#endif /* not TRILIBRARY */ + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + triangleloop.orient = 0; + elementnumber = firstnumber; + while (triangleloop.tri != (triangle *) NULL) { + * (int *) (triangleloop.tri + 6) = elementnumber; + triangleloop.tri = triangletraverse(); + elementnumber++; + } + * (int *) (dummytri + 6) = -1; + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + elementnumber = firstnumber; + while (triangleloop.tri != (triangle *) NULL) { + triangleloop.orient = 1; + sym(triangleloop, trisym); + neighbor1 = * (int *) (trisym.tri + 6); + triangleloop.orient = 2; + sym(triangleloop, trisym); + neighbor2 = * (int *) (trisym.tri + 6); + triangleloop.orient = 0; + sym(triangleloop, trisym); + neighbor3 = * (int *) (trisym.tri + 6); +#ifdef TRILIBRARY + nlist[index++] = neighbor1; + nlist[index++] = neighbor2; + nlist[index++] = neighbor3; +#else /* not TRILIBRARY */ + /* Triangle number, neighboring triangle numbers. */ + fprintf(outfile, "%4d %d %d %d\n", elementnumber, + neighbor1, neighbor2, neighbor3); +#endif /* not TRILIBRARY */ + + triangleloop.tri = triangletraverse(); + elementnumber++; + } + +#ifndef TRILIBRARY + finishfile(outfile, argc, argv); +#endif /* TRILIBRARY */ +} + +/*****************************************************************************/ +/* */ +/* writeoff() Write the triangulation to an .off file. */ +/* */ +/* OFF stands for the Object File Format, a format used by the Geometry */ +/* Center's Geomview package. */ +/* */ +/*****************************************************************************/ + +#ifndef TRILIBRARY + +void writeoff(offfilename, argc, argv) +char *offfilename; +int argc; +char **argv; +{ + FILE *outfile; + struct triedge triangleloop; + point pointloop; + point p1, p2, p3; + + if (!quiet) { + printf("Writing %s.\n", offfilename); + } + outfile = fopen(offfilename, "w"); + if (outfile == (FILE *) NULL) { + printf(" Error: Cannot create file %s.\n", offfilename); + exit(1); + } + /* Number of points, triangles, and edges. */ + fprintf(outfile, "OFF\n%ld %ld %ld\n", points.items, triangles.items, + edges); + + /* Write the points. */ + traversalinit(&points); + pointloop = pointtraverse(); + while (pointloop != (point) NULL) { + /* The "0.0" is here because the OFF format uses 3D coordinates. */ + fprintf(outfile, " %.17g %.17g %.17g\n", pointloop[0], + pointloop[1], 0.0); + pointloop = pointtraverse(); + } + + /* Write the triangles. */ + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + triangleloop.orient = 0; + while (triangleloop.tri != (triangle *) NULL) { + org(triangleloop, p1); + dest(triangleloop, p2); + apex(triangleloop, p3); + /* The "3" means a three-vertex polygon. */ + fprintf(outfile, " 3 %4d %4d %4d\n", pointmark(p1) - 1, + pointmark(p2) - 1, pointmark(p3) - 1); + triangleloop.tri = triangletraverse(); + } + finishfile(outfile, argc, argv); +} + +#endif /* not TRILIBRARY */ + +/** **/ +/** **/ +/********* File I/O routines end here *********/ + +/*****************************************************************************/ +/* */ +/* quality_statistics() Print statistics about the quality of the mesh. */ +/* */ +/*****************************************************************************/ + +void quality_statistics() +{ + struct triedge triangleloop; + point p[3]; + REAL cossquaretable[8]; + REAL ratiotable[16]; + REAL dx[3], dy[3]; + REAL edgelength[3]; + REAL dotproduct; + REAL cossquare; + REAL triarea; + REAL shortest, longest; + REAL trilongest2; + REAL smallestarea, biggestarea; + REAL triminaltitude2; + REAL minaltitude; + REAL triaspect2; + REAL worstaspect; + REAL smallestangle, biggestangle; + REAL radconst, degconst; + int angletable[18]; + int aspecttable[16]; + int aspectindex; + int tendegree; + int acutebiggest; + int i, ii, j, k; + + printf("Mesh quality statistics:\n\n"); + radconst = (REAL)(PI / 18.0); + degconst = (REAL)(180.0 / PI); + for (i = 0; i < 8; i++) { + cossquaretable[i] = (REAL)(cos(radconst * (REAL) (i + 1))); + cossquaretable[i] = cossquaretable[i] * cossquaretable[i]; + } + for (i = 0; i < 18; i++) { + angletable[i] = 0; + } + + ratiotable[0] = 1.5; ratiotable[1] = 2.0; + ratiotable[2] = 2.5; ratiotable[3] = 3.0; + ratiotable[4] = 4.0; ratiotable[5] = 6.0; + ratiotable[6] = 10.0; ratiotable[7] = 15.0; + ratiotable[8] = 25.0; ratiotable[9] = 50.0; + ratiotable[10] = 100.0; ratiotable[11] = 300.0; + ratiotable[12] = 1000.0; ratiotable[13] = 10000.0; + ratiotable[14] = 100000.0; ratiotable[15] = 0.0; + for (i = 0; i < 16; i++) { + aspecttable[i] = 0; + } + + worstaspect = 0.0; + minaltitude = xmax - xmin + ymax - ymin; + minaltitude = minaltitude * minaltitude; + shortest = minaltitude; + longest = 0.0; + smallestarea = minaltitude; + biggestarea = 0.0; + worstaspect = 0.0; + smallestangle = 0.0; + biggestangle = 2.0; + acutebiggest = 1; + + traversalinit(&triangles); + triangleloop.tri = triangletraverse(); + triangleloop.orient = 0; + while (triangleloop.tri != (triangle *) NULL) { + org(triangleloop, p[0]); + dest(triangleloop, p[1]); + apex(triangleloop, p[2]); + trilongest2 = 0.0; + + for (i = 0; i < 3; i++) { + j = plus1mod3[i]; + k = minus1mod3[i]; + dx[i] = p[j][0] - p[k][0]; + dy[i] = p[j][1] - p[k][1]; + edgelength[i] = dx[i] * dx[i] + dy[i] * dy[i]; + if (edgelength[i] > trilongest2) { + trilongest2 = edgelength[i]; + } + if (edgelength[i] > longest) { + longest = edgelength[i]; + } + if (edgelength[i] < shortest) { + shortest = edgelength[i]; + } + } + + triarea = counterclockwise(p[0], p[1], p[2]); + if (triarea < smallestarea) { + smallestarea = triarea; + } + if (triarea > biggestarea) { + biggestarea = triarea; + } + triminaltitude2 = triarea * triarea / trilongest2; + if (triminaltitude2 < minaltitude) { + minaltitude = triminaltitude2; + } + triaspect2 = trilongest2 / triminaltitude2; + if (triaspect2 > worstaspect) { + worstaspect = triaspect2; + } + aspectindex = 0; + while ((triaspect2 > ratiotable[aspectindex] * ratiotable[aspectindex]) + && (aspectindex < 15)) { + aspectindex++; + } + aspecttable[aspectindex]++; + + for (i = 0; i < 3; i++) { + j = plus1mod3[i]; + k = minus1mod3[i]; + dotproduct = dx[j] * dx[k] + dy[j] * dy[k]; + cossquare = dotproduct * dotproduct / (edgelength[j] * edgelength[k]); + tendegree = 8; + for (ii = 7; ii >= 0; ii--) { + if (cossquare > cossquaretable[ii]) { + tendegree = ii; + } + } + if (dotproduct <= 0.0) { + angletable[tendegree]++; + if (cossquare > smallestangle) { + smallestangle = cossquare; + } + if (acutebiggest && (cossquare < biggestangle)) { + biggestangle = cossquare; + } + } else { + angletable[17 - tendegree]++; + if (acutebiggest || (cossquare > biggestangle)) { + biggestangle = cossquare; + acutebiggest = 0; + } + } + } + triangleloop.tri = triangletraverse(); + } + + shortest = (REAL)sqrt(shortest); + longest = (REAL)sqrt(longest); + minaltitude = (REAL)sqrt(minaltitude); + worstaspect = (REAL)sqrt(worstaspect); + smallestarea *= 2.0; + biggestarea *= 2.0; + if (smallestangle >= 1.0) { + smallestangle = 0.0; + } else { + smallestangle = (REAL)(degconst * acos(sqrt(smallestangle))); + } + if (biggestangle >= 1.0) { + biggestangle = 180.0; + } else { + if (acutebiggest) { + biggestangle = (REAL)(degconst * acos(sqrt(biggestangle))); + } else { + biggestangle = (REAL)(180.0 - degconst * acos(sqrt(biggestangle))); + } + } + + printf(" Smallest area: %16.5g | Largest area: %16.5g\n", + smallestarea, biggestarea); + printf(" Shortest edge: %16.5g | Longest edge: %16.5g\n", + shortest, longest); + printf(" Shortest altitude: %12.5g | Largest aspect ratio: %8.5g\n\n", + minaltitude, worstaspect); + printf(" Aspect ratio histogram:\n"); + printf(" 1.1547 - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", + ratiotable[0], aspecttable[0], ratiotable[7], ratiotable[8], + aspecttable[8]); + for (i = 1; i < 7; i++) { + printf(" %6.6g - %-6.6g : %8d | %6.6g - %-6.6g : %8d\n", + ratiotable[i - 1], ratiotable[i], aspecttable[i], + ratiotable[i + 7], ratiotable[i + 8], aspecttable[i + 8]); + } + printf(" %6.6g - %-6.6g : %8d | %6.6g - : %8d\n", + ratiotable[6], ratiotable[7], aspecttable[7], ratiotable[14], + aspecttable[15]); + printf( +" (Triangle aspect ratio is longest edge divided by shortest altitude)\n\n"); + printf(" Smallest angle: %15.5g | Largest angle: %15.5g\n\n", + smallestangle, biggestangle); + printf(" Angle histogram:\n"); + for (i = 0; i < 9; i++) { + printf(" %3d - %3d degrees: %8d | %3d - %3d degrees: %8d\n", + i * 10, i * 10 + 10, angletable[i], + i * 10 + 90, i * 10 + 100, angletable[i + 9]); + } + printf("\n"); +} + +/*****************************************************************************/ +/* */ +/* statistics() Print all sorts of cool facts. */ +/* */ +/*****************************************************************************/ + +void statistics() +{ + printf("\nStatistics:\n\n"); + printf(" Input points: %d\n", inpoints); + if (refine) { + printf(" Input triangles: %d\n", inelements); + } + if (poly) { + printf(" Input segments: %d\n", insegments); + if (!refine) { + printf(" Input holes: %d\n", holes); + } + } + + printf("\n Mesh points: %ld\n", points.items); + printf(" Mesh triangles: %ld\n", triangles.items); + printf(" Mesh edges: %ld\n", edges); + if (poly || refine) { + printf(" Mesh boundary edges: %ld\n", hullsize); + printf(" Mesh segments: %ld\n\n", shelles.items); + } else { + printf(" Mesh convex hull edges: %ld\n\n", hullsize); + } + if (verbose) { + quality_statistics(); + printf("Memory allocation statistics:\n\n"); + printf(" Maximum number of points: %ld\n", points.maxitems); + printf(" Maximum number of triangles: %ld\n", triangles.maxitems); + if (shelles.maxitems > 0) { + printf(" Maximum number of segments: %ld\n", shelles.maxitems); + } + if (viri.maxitems > 0) { + printf(" Maximum number of viri: %ld\n", viri.maxitems); + } + if (badsegments.maxitems > 0) { + printf(" Maximum number of encroached segments: %ld\n", + badsegments.maxitems); + } + if (badtriangles.maxitems > 0) { + printf(" Maximum number of bad triangles: %ld\n", + badtriangles.maxitems); + } + if (splaynodes.maxitems > 0) { + printf(" Maximum number of splay tree nodes: %ld\n", + splaynodes.maxitems); + } + printf(" Approximate heap memory use (bytes): %ld\n\n", + points.maxitems * points.itembytes + + triangles.maxitems * triangles.itembytes + + shelles.maxitems * shelles.itembytes + + viri.maxitems * viri.itembytes + + badsegments.maxitems * badsegments.itembytes + + badtriangles.maxitems * badtriangles.itembytes + + splaynodes.maxitems * splaynodes.itembytes); + + printf("Algorithmic statistics:\n\n"); + printf(" Number of incircle tests: %ld\n", incirclecount); + printf(" Number of orientation tests: %ld\n", counterclockcount); + if (hyperbolacount > 0) { + printf(" Number of right-of-hyperbola tests: %ld\n", + hyperbolacount); + } + if (circumcentercount > 0) { + printf(" Number of circumcenter computations: %ld\n", + circumcentercount); + } + if (circletopcount > 0) { + printf(" Number of circle top computations: %ld\n", + circletopcount); + } + printf("\n"); + } +} + +/*****************************************************************************/ +/* */ +/* main() or triangulate() Gosh, do everything. */ +/* */ +/* The sequence is roughly as follows. Many of these steps can be skipped, */ +/* depending on the command line switches. */ +/* */ +/* - Initialize constants and parse the command line. */ +/* - Read the points from a file and either */ +/* - triangulate them (no -r), or */ +/* - read an old mesh from files and reconstruct it (-r). */ +/* - Insert the PSLG segments (-p), and possibly segments on the convex */ +/* hull (-c). */ +/* - Read the holes (-p), regional attributes (-pA), and regional area */ +/* constraints (-pa). Carve the holes and concavities, and spread the */ +/* regional attributes and area constraints. */ +/* - Enforce the constraints on minimum angle (-q) and maximum area (-a). */ +/* Also enforce the conforming Delaunay property (-q and -a). */ +/* - Compute the number of edges in the resulting mesh. */ +/* - Promote the mesh's linear triangles to higher order elements (-o). */ +/* - Write the output files and print the statistics. */ +/* - Check the consistency and Delaunay property of the mesh (-C). */ +/* */ +/*****************************************************************************/ + +#ifdef TRILIBRARY + +void triangulate(triswitches, in, out, vorout) +char *triswitches; +struct triangulateio *in; +struct triangulateio *out; +struct triangulateio *vorout; + +#else /* not TRILIBRARY */ + +int main(argc, argv) +int argc; +char **argv; + +#endif /* not TRILIBRARY */ + +{ + REAL *holearray; /* Array of holes. */ + REAL *regionarray; /* Array of regional attributes and area constraints. */ +#ifndef TRILIBRARY + FILE *polyfile; +#endif /* not TRILIBRARY */ +#ifndef NO_TIMER + /* Variables for timing the performance of Triangle. The types are */ + /* defined in sys/time.h. */ + struct timeval tv0, tv1, tv2, tv3, tv4, tv5, tv6; + struct timezone tz; +#endif /* NO_TIMER */ + +#ifndef NO_TIMER + gettimeofday(&tv0, &tz); +#endif /* NO_TIMER */ + + triangleinit(); +#ifdef TRILIBRARY + parsecommandline(1, &triswitches); +#else /* not TRILIBRARY */ + parsecommandline(argc, argv); +#endif /* not TRILIBRARY */ + +#ifdef TRILIBRARY + transfernodes(in->pointlist, in->pointattributelist, in->pointmarkerlist, + in->numberofpoints, in->numberofpointattributes); +#else /* not TRILIBRARY */ + readnodes(innodefilename, inpolyfilename, &polyfile); +#endif /* not TRILIBRARY */ + +#ifndef NO_TIMER + if (!quiet) { + gettimeofday(&tv1, &tz); + } +#endif /* NO_TIMER */ + +#ifdef CDT_ONLY + hullsize = delaunay(); /* Triangulate the points. */ +#else /* not CDT_ONLY */ + if (refine) { + /* Read and reconstruct a mesh. */ +#ifdef TRILIBRARY + hullsize = reconstruct(in->trianglelist, in->triangleattributelist, + in->trianglearealist, in->numberoftriangles, + in->numberofcorners, in->numberoftriangleattributes, + in->segmentlist, in->segmentmarkerlist, + in->numberofsegments); +#else /* not TRILIBRARY */ + hullsize = reconstruct(inelefilename, areafilename, inpolyfilename, + polyfile); +#endif /* not TRILIBRARY */ + } else { + hullsize = delaunay(); /* Triangulate the points. */ + } +#endif /* not CDT_ONLY */ + +#ifndef NO_TIMER + if (!quiet) { + gettimeofday(&tv2, &tz); + if (refine) { + printf("Mesh reconstruction"); + } else { + printf("Delaunay"); + } + printf(" milliseconds: %ld\n", 1000l * (tv2.tv_sec - tv1.tv_sec) + + (tv2.tv_usec - tv1.tv_usec) / 1000l); + } +#endif /* NO_TIMER */ + + /* Ensure that no point can be mistaken for a triangular bounding */ + /* box point in insertsite(). */ + infpoint1 = (point) NULL; + infpoint2 = (point) NULL; + infpoint3 = (point) NULL; + + if (useshelles) { + checksegments = 1; /* Segments will be introduced next. */ + if (!refine) { + /* Insert PSLG segments and/or convex hull segments. */ +#ifdef TRILIBRARY + insegments = formskeleton(in->segmentlist, in->segmentmarkerlist, + in->numberofsegments); +#else /* not TRILIBRARY */ + insegments = formskeleton(polyfile, inpolyfilename); +#endif /* not TRILIBRARY */ + } + } + +#ifndef NO_TIMER + if (!quiet) { + gettimeofday(&tv3, &tz); + if (useshelles && !refine) { + printf("Segment milliseconds: %ld\n", + 1000l * (tv3.tv_sec - tv2.tv_sec) + + (tv3.tv_usec - tv2.tv_usec) / 1000l); + } + } +#endif /* NO_TIMER */ + + if (poly) { +#ifdef TRILIBRARY + holearray = in->holelist; + holes = in->numberofholes; + regionarray = in->regionlist; + regions = in->numberofregions; +#else /* not TRILIBRARY */ + readholes(polyfile, inpolyfilename, &holearray, &holes, + ®ionarray, ®ions); +#endif /* not TRILIBRARY */ + if (!refine) { + /* Carve out holes and concavities. */ + carveholes(holearray, holes, regionarray, regions); + } + } else { + /* Without a PSLG, there can be no holes or regional attributes */ + /* or area constraints. The following are set to zero to avoid */ + /* an accidental free() later. */ + holes = 0; + regions = 0; + } + +#ifndef NO_TIMER + if (!quiet) { + gettimeofday(&tv4, &tz); + if (poly && !refine) { + printf("Hole milliseconds: %ld\n", 1000l * (tv4.tv_sec - tv3.tv_sec) + + (tv4.tv_usec - tv3.tv_usec) / 1000l); + } + } +#endif /* NO_TIMER */ + +#ifndef CDT_ONLY + if (quality) { + enforcequality(); /* Enforce angle and area constraints. */ + } +#endif /* not CDT_ONLY */ + +#ifndef NO_TIMER + if (!quiet) { + gettimeofday(&tv5, &tz); +#ifndef CDT_ONLY + if (quality) { + printf("Quality milliseconds: %ld\n", + 1000l * (tv5.tv_sec - tv4.tv_sec) + + (tv5.tv_usec - tv4.tv_usec) / 1000l); + } +#endif /* not CDT_ONLY */ + } +#endif /* NO_TIMER */ + + /* Compute the number of edges. */ + edges = (3l * triangles.items + hullsize) / 2l; + + if (order > 1) { + highorder(); /* Promote elements to higher polynomial order. */ + } + if (!quiet) { + printf("\n"); + } + +#ifdef TRILIBRARY + out->numberofpoints = points.items; + out->numberofpointattributes = nextras; + out->numberoftriangles = triangles.items; + out->numberofcorners = (order + 1) * (order + 2) / 2; + out->numberoftriangleattributes = eextras; + out->numberofedges = edges; + if (useshelles) { + out->numberofsegments = shelles.items; + } else { + out->numberofsegments = hullsize; + } + if (vorout != (struct triangulateio *) NULL) { + vorout->numberofpoints = triangles.items; + vorout->numberofpointattributes = nextras; + vorout->numberofedges = edges; + } +#endif /* TRILIBRARY */ + /* If not using iteration numbers, don't write a .node file if one was */ + /* read, because the original one would be overwritten! */ + if (nonodewritten || (noiterationnum && readnodefile)) { + if (!quiet) { +#ifdef TRILIBRARY + printf("NOT writing points.\n"); +#else /* not TRILIBRARY */ + printf("NOT writing a .node file.\n"); +#endif /* not TRILIBRARY */ + } + numbernodes(); /* We must remember to number the points. */ + } else { +#ifdef TRILIBRARY + writenodes(&out->pointlist, &out->pointattributelist, + &out->pointmarkerlist); +#else /* not TRILIBRARY */ + writenodes(outnodefilename, argc, argv); /* Numbers the points too. */ +#endif /* TRILIBRARY */ + } + if (noelewritten) { + if (!quiet) { +#ifdef TRILIBRARY + printf("NOT writing triangles.\n"); +#else /* not TRILIBRARY */ + printf("NOT writing an .ele file.\n"); +#endif /* not TRILIBRARY */ + } + } else { +#ifdef TRILIBRARY + writeelements(&out->trianglelist, &out->triangleattributelist); +#else /* not TRILIBRARY */ + writeelements(outelefilename, argc, argv); +#endif /* not TRILIBRARY */ + } + /* The -c switch (convex switch) causes a PSLG to be written */ + /* even if none was read. */ + if (poly || convex) { + /* If not using iteration numbers, don't overwrite the .poly file. */ + if (nopolywritten || noiterationnum) { + if (!quiet) { +#ifdef TRILIBRARY + printf("NOT writing segments.\n"); +#else /* not TRILIBRARY */ + printf("NOT writing a .poly file.\n"); +#endif /* not TRILIBRARY */ + } + } else { +#ifdef TRILIBRARY + writepoly(&out->segmentlist, &out->segmentmarkerlist); + out->numberofholes = holes; + out->numberofregions = regions; + if (poly) { + out->holelist = in->holelist; + out->regionlist = in->regionlist; + } else { + out->holelist = (REAL *) NULL; + out->regionlist = (REAL *) NULL; + } +#else /* not TRILIBRARY */ + writepoly(outpolyfilename, holearray, holes, regionarray, regions, + argc, argv); +#endif /* not TRILIBRARY */ + } + } +#ifndef TRILIBRARY +#ifndef CDT_ONLY + if (regions > 0) { + free(regionarray); + } +#endif /* not CDT_ONLY */ + if (holes > 0) { + free(holearray); + } + if (geomview) { + writeoff(offfilename, argc, argv); + } +#endif /* not TRILIBRARY */ + if (edgesout) { +#ifdef TRILIBRARY + writeedges(&out->edgelist, &out->edgemarkerlist); +#else /* not TRILIBRARY */ + writeedges(edgefilename, argc, argv); +#endif /* not TRILIBRARY */ + } + if (voronoi) { +#ifdef TRILIBRARY + writevoronoi(&vorout->pointlist, &vorout->pointattributelist, + &vorout->pointmarkerlist, &vorout->edgelist, + &vorout->edgemarkerlist, &vorout->normlist); +#else /* not TRILIBRARY */ + writevoronoi(vnodefilename, vedgefilename, argc, argv); +#endif /* not TRILIBRARY */ + } + if (neighbors) { +#ifdef TRILIBRARY + writeneighbors(&out->neighborlist); +#else /* not TRILIBRARY */ + writeneighbors(neighborfilename, argc, argv); +#endif /* not TRILIBRARY */ + } + + if (!quiet) { +#ifndef NO_TIMER + gettimeofday(&tv6, &tz); + printf("\nOutput milliseconds: %ld\n", + 1000l * (tv6.tv_sec - tv5.tv_sec) + + (tv6.tv_usec - tv5.tv_usec) / 1000l); + printf("Total running milliseconds: %ld\n", + 1000l * (tv6.tv_sec - tv0.tv_sec) + + (tv6.tv_usec - tv0.tv_usec) / 1000l); +#endif /* NO_TIMER */ + + statistics(); + } + +#ifndef REDUCED + if (docheck) { + checkmesh(); + checkdelaunay(); + } +#endif /* not REDUCED */ + + triangledeinit(); +#ifndef TRILIBRARY + return 0; +#endif /* not TRILIBRARY */ +} diff --git a/contrib/gtkgensurf/triangle.h b/contrib/gtkgensurf/triangle.h new file mode 100644 index 00000000..70cd6596 --- /dev/null +++ b/contrib/gtkgensurf/triangle.h @@ -0,0 +1,288 @@ +/*****************************************************************************/ +/* */ +/* (triangle.h) */ +/* */ +/* Include file for programs that call Triangle. */ +/* */ +/* Accompanies Triangle Version 1.3 */ +/* July 19, 1996 */ +/* */ +/* Copyright 1996 */ +/* Jonathan Richard Shewchuk */ +/* School of Computer Science */ +/* Carnegie Mellon University */ +/* 5000 Forbes Avenue */ +/* Pittsburgh, Pennsylvania 15213-3891 */ +/* jrs@cs.cmu.edu */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* How to call Triangle from another program */ +/* */ +/* */ +/* If you haven't read Triangle's instructions (run "triangle -h" to read */ +/* them), you won't understand what follows. */ +/* */ +/* Triangle must be compiled into an object file (triangle.o) with the */ +/* TRILIBRARY symbol defined (preferably by using the -DTRILIBRARY compiler */ +/* switch). The makefile included with Triangle will do this for you if */ +/* you run "make trilibrary". The resulting object file can be called via */ +/* the procedure triangulate(). */ +/* */ +/* If the size of the object file is important to you, you may wish to */ +/* generate a reduced version of triangle.o. The REDUCED symbol gets rid */ +/* of all features that are primarily of research interest. Specifically, */ +/* the -DREDUCED switch eliminates Triangle's -i, -F, -s, and -C switches. */ +/* The CDT_ONLY symbol gets rid of all meshing algorithms above and beyond */ +/* constrained Delaunay triangulation. Specifically, the -DCDT_ONLY switch */ +/* eliminates Triangle's -r, -q, -a, -S, and -s switches. */ +/* */ +/* IMPORTANT: These definitions (TRILIBRARY, REDUCED, CDT_ONLY) must be */ +/* made in the makefile or in triangle.c itself. Putting these definitions */ +/* in this file will not create the desired effect. */ +/* */ +/* */ +/* The calling convention for triangulate() follows. */ +/* */ +/* void triangulate(triswitches, in, out, vorout) */ +/* char *triswitches; */ +/* struct triangulateio *in; */ +/* struct triangulateio *out; */ +/* struct triangulateio *vorout; */ +/* */ +/* `triswitches' is a string containing the command line switches you wish */ +/* to invoke. No initial dash is required. Some suggestions: */ +/* */ +/* - You'll probably find it convenient to use the `z' switch so that */ +/* points (and other items) are numbered from zero. This simplifies */ +/* indexing, because the first item of any type always starts at index */ +/* [0] of the corresponding array, whether that item's number is zero or */ +/* one. */ +/* - You'll probably want to use the `Q' (quiet) switch in your final code, */ +/* but you can take advantage of Triangle's printed output (including the */ +/* `V' switch) while debugging. */ +/* - If you are not using the `q' or `a' switches, then the output points */ +/* will be identical to the input points, except possibly for the */ +/* boundary markers. If you don't need the boundary markers, you should */ +/* use the `N' (no nodes output) switch to save memory. (If you do need */ +/* boundary markers, but need to save memory, a good nasty trick is to */ +/* set out->pointlist equal to in->pointlist before calling triangulate(),*/ +/* so that Triangle overwrites the input points with identical copies.) */ +/* - The `I' (no iteration numbers) and `g' (.off file output) switches */ +/* have no effect when Triangle is compiled with TRILIBRARY defined. */ +/* */ +/* `in', `out', and `vorout' are descriptions of the input, the output, */ +/* and the Voronoi output. If the `v' (Voronoi output) switch is not used, */ +/* `vorout' may be NULL. `in' and `out' may never be NULL. */ +/* */ +/* Certain fields of the input and output structures must be initialized, */ +/* as described below. */ +/* */ +/*****************************************************************************/ + +/*****************************************************************************/ +/* */ +/* The `triangulateio' structure. */ +/* */ +/* Used to pass data into and out of the triangulate() procedure. */ +/* */ +/* */ +/* Arrays are used to store points, triangles, markers, and so forth. In */ +/* all cases, the first item in any array is stored starting at index [0]. */ +/* However, that item is item number `1' unless the `z' switch is used, in */ +/* which case it is item number `0'. Hence, you may find it easier to */ +/* index points (and triangles in the neighbor list) if you use the `z' */ +/* switch. Unless, of course, you're calling Triangle from a Fortran */ +/* program. */ +/* */ +/* Description of fields (except the `numberof' fields, which are obvious): */ +/* */ +/* `pointlist': An array of point coordinates. The first point's x */ +/* coordinate is at index [0] and its y coordinate at index [1], followed */ +/* by the coordinates of the remaining points. Each point occupies two */ +/* REALs. */ +/* `pointattributelist': An array of point attributes. Each point's */ +/* attributes occupy `numberofpointattributes' REALs. */ +/* `pointmarkerlist': An array of point markers; one int per point. */ +/* */ +/* `trianglelist': An array of triangle corners. The first triangle's */ +/* first corner is at index [0], followed by its other two corners in */ +/* counterclockwise order, followed by any other nodes if the triangle */ +/* represents a nonlinear element. Each triangle occupies */ +/* `numberofcorners' ints. */ +/* `triangleattributelist': An array of triangle attributes. Each */ +/* triangle's attributes occupy `numberoftriangleattributes' REALs. */ +/* `trianglearealist': An array of triangle area constraints; one REAL per */ +/* triangle. Input only. */ +/* `neighborlist': An array of triangle neighbors; three ints per */ +/* triangle. Output only. */ +/* */ +/* `segmentlist': An array of segment endpoints. The first segment's */ +/* endpoints are at indices [0] and [1], followed by the remaining */ +/* segments. Two ints per segment. */ +/* `segmentmarkerlist': An array of segment markers; one int per segment. */ +/* */ +/* `holelist': An array of holes. The first hole's x and y coordinates */ +/* are at indices [0] and [1], followed by the remaining holes. Two */ +/* REALs per hole. Input only, although the pointer is copied to the */ +/* output structure for your convenience. */ +/* */ +/* `regionlist': An array of regional attributes and area constraints. */ +/* The first constraint's x and y coordinates are at indices [0] and [1], */ +/* followed by the regional attribute and index [2], followed by the */ +/* maximum area at index [3], followed by the remaining area constraints. */ +/* Four REALs per area constraint. Note that each regional attribute is */ +/* used only if you select the `A' switch, and each area constraint is */ +/* used only if you select the `a' switch (with no number following), but */ +/* omitting one of these switches does not change the memory layout. */ +/* Input only, although the pointer is copied to the output structure for */ +/* your convenience. */ +/* */ +/* `edgelist': An array of edge endpoints. The first edge's endpoints are */ +/* at indices [0] and [1], followed by the remaining edges. Two ints per */ +/* edge. Output only. */ +/* `edgemarkerlist': An array of edge markers; one int per edge. Output */ +/* only. */ +/* `normlist': An array of normal vectors, used for infinite rays in */ +/* Voronoi diagrams. The first normal vector's x and y magnitudes are */ +/* at indices [0] and [1], followed by the remaining vectors. For each */ +/* finite edge in a Voronoi diagram, the normal vector written is the */ +/* zero vector. Two REALs per edge. Output only. */ +/* */ +/* */ +/* Any input fields that Triangle will examine must be initialized. */ +/* Furthermore, for each output array that Triangle will write to, you */ +/* must either provide space by setting the appropriate pointer to point */ +/* to the space you want the data written to, or you must initialize the */ +/* pointer to NULL, which tells Triangle to allocate space for the results. */ +/* The latter option is preferable, because Triangle always knows exactly */ +/* how much space to allocate. The former option is provided mainly for */ +/* people who need to call Triangle from Fortran code, though it also makes */ +/* possible some nasty space-saving tricks, like writing the output to the */ +/* same arrays as the input. */ +/* */ +/* Triangle will not free() any input or output arrays, including those it */ +/* allocates itself; that's up to you. */ +/* */ +/* Here's a guide to help you decide which fields you must initialize */ +/* before you call triangulate(). */ +/* */ +/* `in': */ +/* */ +/* - `pointlist' must always point to a list of points; `numberofpoints' */ +/* and `numberofpointattributes' must be properly set. */ +/* `pointmarkerlist' must either be set to NULL (in which case all */ +/* markers default to zero), or must point to a list of markers. If */ +/* `numberofpointattributes' is not zero, `pointattributelist' must */ +/* point to a list of point attributes. */ +/* - If the `r' switch is used, `trianglelist' must point to a list of */ +/* triangles, and `numberoftriangles', `numberofcorners', and */ +/* `numberoftriangleattributes' must be properly set. If */ +/* `numberoftriangleattributes' is not zero, `triangleattributelist' */ +/* must point to a list of triangle attributes. If the `a' switch is */ +/* used (with no number following), `trianglearealist' must point to a */ +/* list of triangle area constraints. `neighborlist' may be ignored. */ +/* - If the `p' switch is used, `segmentlist' must point to a list of */ +/* segments, `numberofsegments' must be properly set, and */ +/* `segmentmarkerlist' must either be set to NULL (in which case all */ +/* markers default to zero), or must point to a list of markers. */ +/* - If the `p' switch is used without the `r' switch, then */ +/* `numberofholes' and `numberofregions' must be properly set. If */ +/* `numberofholes' is not zero, `holelist' must point to a list of */ +/* holes. If `numberofregions' is not zero, `regionlist' must point to */ +/* a list of region constraints. */ +/* - If the `p' switch is used, `holelist', `numberofholes', */ +/* `regionlist', and `numberofregions' is copied to `out'. (You can */ +/* nonetheless get away with not initializing them if the `r' switch is */ +/* used.) */ +/* - `edgelist', `edgemarkerlist', `normlist', and `numberofedges' may be */ +/* ignored. */ +/* */ +/* `out': */ +/* */ +/* - `pointlist' must be initialized (NULL or pointing to memory) unless */ +/* the `N' switch is used. `pointmarkerlist' must be initialized */ +/* unless the `N' or `B' switch is used. If `N' is not used and */ +/* `in->numberofpointattributes' is not zero, `pointattributelist' must */ +/* be initialized. */ +/* - `trianglelist' must be initialized unless the `E' switch is used. */ +/* `neighborlist' must be initialized if the `n' switch is used. If */ +/* the `E' switch is not used and (`in->numberofelementattributes' is */ +/* not zero or the `A' switch is used), `elementattributelist' must be */ +/* initialized. `trianglearealist' may be ignored. */ +/* - `segmentlist' must be initialized if the `p' or `c' switch is used, */ +/* and the `P' switch is not used. `segmentmarkerlist' must also be */ +/* initialized under these circumstances unless the `B' switch is used. */ +/* - `edgelist' must be initialized if the `e' switch is used. */ +/* `edgemarkerlist' must be initialized if the `e' switch is used and */ +/* the `B' switch is not. */ +/* - `holelist', `regionlist', `normlist', and all scalars may be ignored.*/ +/* */ +/* `vorout' (only needed if `v' switch is used): */ +/* */ +/* - `pointlist' must be initialized. If `in->numberofpointattributes' */ +/* is not zero, `pointattributelist' must be initialized. */ +/* `pointmarkerlist' may be ignored. */ +/* - `edgelist' and `normlist' must both be initialized. */ +/* `edgemarkerlist' may be ignored. */ +/* - Everything else may be ignored. */ +/* */ +/* After a call to triangulate(), the valid fields of `out' and `vorout' */ +/* will depend, in an obvious way, on the choice of switches used. Note */ +/* that when the `p' switch is used, the pointers `holelist' and */ +/* `regionlist' are copied from `in' to `out', but no new space is */ +/* allocated; be careful that you don't free() the same array twice. On */ +/* the other hand, Triangle will never copy the `pointlist' pointer (or any */ +/* others); new space is allocated for `out->pointlist', or if the `N' */ +/* switch is used, `out->pointlist' remains uninitialized. */ +/* */ +/* All of the meaningful `numberof' fields will be properly set; for */ +/* instance, `numberofedges' will represent the number of edges in the */ +/* triangulation whether or not the edges were written. If segments are */ +/* not used, `numberofsegments' will indicate the number of boundary edges. */ +/* */ +/*****************************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif + +struct triangulateio { + REAL *pointlist; /* In / out */ + REAL *pointattributelist; /* In / out */ + int *pointmarkerlist; /* In / out */ + int numberofpoints; /* In / out */ + int numberofpointattributes; /* In / out */ + + int *trianglelist; /* In / out */ + REAL *triangleattributelist; /* In / out */ + REAL *trianglearealist; /* In only */ + int *neighborlist; /* Out only */ + int numberoftriangles; /* In / out */ + int numberofcorners; /* In / out */ + int numberoftriangleattributes; /* In / out */ + + int *segmentlist; /* In / out */ + int *segmentmarkerlist; /* In / out */ + int numberofsegments; /* In / out */ + + REAL *holelist; /* In / pointer to array copied out */ + int numberofholes; /* In / copied out */ + + REAL *regionlist; /* In / pointer to array copied out */ + int numberofregions; /* In / copied out */ + + int *edgelist; /* Out only */ + int *edgemarkerlist; /* Not used with Voronoi diagram; out only */ + REAL *normlist; /* Used only with Voronoi diagram; out only */ + int numberofedges; /* Out only */ +}; + +void triangulate(char *, struct triangulateio *, struct triangulateio *, + struct triangulateio *); + +#ifdef __cplusplus +} +#endif diff --git a/contrib/gtkgensurf/view.cpp b/contrib/gtkgensurf/view.cpp new file mode 100644 index 00000000..ff4b1572 --- /dev/null +++ b/contrib/gtkgensurf/view.cpp @@ -0,0 +1,1287 @@ +/* +GenSurf plugin for GtkRadiant +Copyright (C) 2001 David Hyde, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include +#include +#include +#include "gensurf.h" + +#undef ISOMETRIC + +extern double backface; +extern double dh, dv; +extern double xmin,xmax,ymin,ymax,zmin,zmax; + +double SF, SFG; // Graphics scale factors +double XLo, XHi, YLo, YHi, ZLo, ZHi; +double yaw,roll; +double elevation,azimuth; +int cxChar = 10, cyChar = 16; +int X0, Y0; +int X0G, Y0G; + +static RECT rcCoord; // where X= Y= is drawn +static RECT rcGrid; // rectangle within rcLower that forms the border of the grid, plus + // a 3 pixel slop. +static RECT rcLower; // lower half of window, where plan view is drawn +static RECT rcUpper; // upper half or entire window, where isometric projection is drawn + +void vertex_selected (); +void texfont_init (); +void texfont_write (const char *text, float l, float t); + +#define PEN_GRID { \ + g_GLTable.m_pfn_qglLineWidth (1); \ + g_GLTable.m_pfn_qglColor3f (0, 1, 0); \ + g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); } + +#define PEN_RED { \ + g_GLTable.m_pfn_qglLineWidth (2); \ + g_GLTable.m_pfn_qglColor3f (1, 0, 0); \ + g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); } + +#define PEN_DASH { \ + g_GLTable.m_pfn_qglLineWidth (1); \ + g_GLTable.m_pfn_qglColor3f (0, 1, 0); \ + g_GLTable.m_pfn_qglLineStipple (1, 0xF0F0); \ + g_GLTable.m_pfn_qglEnable (GL_LINE_STIPPLE); } + +#define DRAW_QUAD(rc,r,g,b) { \ + g_GLTable.m_pfn_qglBegin (GL_QUADS); \ + g_GLTable.m_pfn_qglColor3f (0,1,0); \ + g_GLTable.m_pfn_qglVertex2f (rc.left-1, rc.bottom); \ + g_GLTable.m_pfn_qglVertex2f (rc.right, rc.bottom); \ + g_GLTable.m_pfn_qglVertex2f (rc.right, rc.top+1); \ + g_GLTable.m_pfn_qglVertex2f (rc.left-1, rc.top+1); \ + g_GLTable.m_pfn_qglColor3f (r,g,b); \ + g_GLTable.m_pfn_qglVertex2f (rc.left, rc.bottom+1); \ + g_GLTable.m_pfn_qglVertex2f (rc.right-1, rc.bottom+1); \ + g_GLTable.m_pfn_qglVertex2f (rc.right-1, rc.top); \ + g_GLTable.m_pfn_qglVertex2f (rc.left, rc.top); \ + g_GLTable.m_pfn_qglEnd (); } + + +#ifndef ISOMETRIC +double D=65536.; +double ct[3],st[3]; +double Hhi, Hlo, Vhi, Vlo; +#endif + +#define SUBDIVS 6 + + +void ShowPreview () +{ + if (Preview) + { + if (g_pWndPreview == NULL) + CreateViewWindow (); + gtk_widget_show (g_pWndPreview); + + UpdatePreview (true); + } + else + gtk_widget_hide (g_pWndPreview); +} + +static void draw_preview () +{ + int width = g_pPreviewWidget->allocation.width, height = g_pPreviewWidget->allocation.height; + + g_GLTable.m_pfn_qglClearColor (0, 0, 0, 1); + g_GLTable.m_pfn_qglViewport (0, 0, width, height); + g_GLTable.m_pfn_qglMatrixMode (GL_PROJECTION); + g_GLTable.m_pfn_qglLoadIdentity (); + g_GLTable.m_pfn_qglOrtho (0, width, 0, height, -1, 1); + g_GLTable.m_pfn_qglClear (GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); + + // ^Fishman - Antializing for the preview window. + if (Antialiasing) + { + g_GLTable.m_pfn_qglEnable(GL_BLEND); + g_GLTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_GLTable.m_pfn_qglEnable(GL_LINE_SMOOTH); + } + else + { + g_GLTable.m_pfn_qglDisable(GL_BLEND); + g_GLTable.m_pfn_qglDisable(GL_LINE_SMOOTH); + } + + texfont_init (); + + if (!ValidSurface ()) + return; + + rcUpper.left = 0; + rcUpper.right = width; + rcUpper.bottom = 0; + rcUpper.top = height; + rcLower.left = 0; + rcLower.right = width; + rcLower.bottom = 0; + rcLower.top = height; + + if (VertexMode) + { + rcUpper.bottom = rcUpper.top/2; + DrawPreview (rcUpper); + g_GLTable.m_pfn_qglBegin (GL_LINES); + g_GLTable.m_pfn_qglVertex2f (rcUpper.left, rcUpper.bottom); + g_GLTable.m_pfn_qglVertex2f (rcUpper.right, rcUpper.bottom); + g_GLTable.m_pfn_qglEnd (); + rcLower.top = rcUpper.bottom-1; + DrawGrid (rcLower); + rcCoord.left = rcLower.left; + rcCoord.right = rcLower.right; + rcCoord.bottom = rcLower.bottom; + rcCoord.top = rcLower.top; + rcCoord.top = rcCoord.bottom+cyChar; + rcCoord.right = rcCoord.left + 15*cxChar; + rcGrid.left = X0G - 3; + rcGrid.bottom = Y0G - 3; + rcGrid.right = X0G + (int)(SFG*(Hur-Hll)) + 3; + rcGrid.top = Y0G + (int)(SFG*(Vur-Vll)) + 3; + } + else + DrawPreview (rcUpper); +} + +static gint expose (GtkWidget *widget, GdkEventExpose *event, gpointer data) +{ + if (event->count > 0) + return TRUE; + + if (!g_UIGtkTable.m_pfn_glwidget_make_current (g_pPreviewWidget)) + { + g_FuncTable.m_pfnSysPrintf ("GtkGenSurf: glMakeCurrent failed\n"); + return TRUE; + } + + draw_preview (); + + g_UIGtkTable.m_pfn_glwidget_swap_buffers (g_pPreviewWidget); + g_GLTable.m_pfn_QE_CheckOpenGLForErrors (); + + return TRUE; +} + +static void button_press (GtkWidget *widget, GdkEventButton *event, gpointer data) +{ + POINT pt = { (long)event->x, widget->allocation.height - (long)event->y }; + bool Selected; + double x,y; + int i, j, k, ks; + int i0, i1, j0, j1; + + if ((!VertexMode) || (event->button != 1)) + return; + + if (!PtInRect (&rcGrid,pt)) + { + gdk_beep (); + return; + } + + x = Hll + (pt.x-X0G)/SFG; + y = Vur - (pt.y-Y0G)/SFG; + i = (int)(floor( (x-Hll)/dh - 0.5) + 1); + j = (int)(floor( (y-Vll)/dv - 0.5) + 1); + if (i < 0 || i > NH || j < 0 || j > NV) + { + gdk_beep (); + return; + } + + if(!CanEdit(i,j)) + { + gdk_beep (); + return; + } + + // Control key pressed - add this point, or remove it if already selected + if ((event->state & GDK_CONTROL_MASK) != 0) + { + Selected = FALSE; + if (NumVerticesSelected) + { + for (k=0; kstate & GDK_SHIFT_MASK) != 0) + { + if (NumVerticesSelected) + { + NumVerticesSelected = 1; + i0 = min(Vertex[0].i, i); + i1 = max(Vertex[0].i, i); + j0 = min(Vertex[0].j, j); + j1 = max(Vertex[0].j, j); + for(i=i0; i<=i1; i++) + { + for(j=j0; j<=j1; j++) + { + if(i==0 && j==0 ) continue; + if(i==NH && j==0 ) continue; + if(i==0 && j==NV) continue; + if(i==NH && j==NV) continue; + if(i != Vertex[0].i || j != Vertex[0].j) + { + Vertex[NumVerticesSelected].i = i; + Vertex[NumVerticesSelected].j = j; + NumVerticesSelected++; + } + } + } + } + else + { + Vertex[0].i = i; + Vertex[0].j = j; + NumVerticesSelected = 1; + } + } + else + { + Vertex[0].i = i; + Vertex[0].j = j; + NumVerticesSelected = 1; + } + + vertex_selected (); +} + +static void motion (GtkWidget *widget, GdkEventMotion *event, gpointer data) +{ + POINT pt = { (long)event->x, widget->allocation.height - (long)event->y }; + + if (!VertexMode) + return; + + if (!g_UIGtkTable.m_pfn_glwidget_make_current (g_pPreviewWidget)) + { + g_FuncTable.m_pfnSysPrintf ("GtkGenSurf: glMakeCurrent failed\n"); + return; + } + + g_GLTable.m_pfn_qglEnable (GL_SCISSOR_TEST); + g_GLTable.m_pfn_qglScissor (rcCoord.left, rcCoord.bottom, rcCoord.right-rcCoord.left, + rcCoord.top-rcCoord.bottom); + g_GLTable.m_pfn_qglClear (GL_COLOR_BUFFER_BIT); + + if (PtInRect(&rcGrid,pt)) + { + GdkCursor *cursor = gdk_cursor_new (GDK_CROSS); + gdk_window_set_cursor (g_pWndPreview->window, cursor); + gdk_cursor_unref (cursor); + + char Text[32]; + int x, y; + + x = (int)(Hll + (pt.x-X0G)/SFG); + y = (int)(Vur - (pt.y-Y0G)/SFG); + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + sprintf(Text," x=%d, z=%d ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) ); + break; + case PLANE_YZ0: + case PLANE_YZ1: + sprintf(Text," y=%d, z=%d ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) ); + break; + default: + sprintf(Text," x=%d, y=%d ",(int)(floor(x-0.5)+1.) ,(int)(floor(y-0.5)+1.) ); + } + + texfont_write (Text, rcCoord.left, rcCoord.top); + } + else + { + gdk_window_set_cursor (g_pWndPreview->window, NULL); + } + + g_UIGtkTable.m_pfn_glwidget_swap_buffers (g_pPreviewWidget); + g_GLTable.m_pfn_QE_CheckOpenGLForErrors (); + g_GLTable.m_pfn_qglDisable (GL_SCISSOR_TEST); +} + +static gint preview_close (GtkWidget *widget, gpointer data) +{ + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (g_object_get_data (G_OBJECT (g_pWnd), "main_preview")), FALSE); + return TRUE; +} + +static void preview_focusout (GtkSpinButton *spin, GdkEventFocus *event, double *data) +{ + *data = DegreesToRadians ((double)(gtk_spin_button_get_value_as_int (spin) % 360)); + UpdatePreview (false); +} + +static gint doublevariable_spinfocusout(GtkWidget* widget, GdkEventFocus* event, gpointer data) +{ + preview_focusout(GTK_SPIN_BUTTON(widget), event, reinterpret_cast(data)); + return FALSE; +} + +static void preview_spin (GtkAdjustment *adj, double *data) +{ + *data = DegreesToRadians (adj->value); + UpdatePreview (false); +} + +void CreateViewWindow () +{ + GtkWidget *dlg, *vbox, *hbox, *label, *spin, *frame; + GtkObject *adj; + +#ifndef ISOMETRIC + elevation = PI/6.; + azimuth = PI/6.; +#endif + + g_pWndPreview = dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "GtkGenSurf Preview"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", GTK_SIGNAL_FUNC (preview_close), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_window_set_transient_for (GTK_WINDOW (dlg), GTK_WINDOW (g_pWnd)); + gtk_window_set_default_size (GTK_WINDOW (dlg), 300, 400); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + +#ifndef ISOMETRIC + hbox = gtk_hbox_new (TRUE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, TRUE, 0); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 3); + + label = gtk_label_new ("Elevation"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, TRUE, 0); + + adj = gtk_adjustment_new (30, -90, 90, 1, 10, 10); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (preview_spin), &elevation); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_box_pack_start (GTK_BOX (hbox), spin, FALSE, TRUE, 0); + g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (doublevariable_spinfocusout), &elevation); + + adj = gtk_adjustment_new (30, 0, 359, 1, 10, 10); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (preview_spin), &azimuth); + spin = gtk_spin_button_new (GTK_ADJUSTMENT (adj), 1, 0); + gtk_widget_show (spin); + gtk_spin_button_set_wrap (GTK_SPIN_BUTTON (spin), TRUE); + gtk_box_pack_end (GTK_BOX (hbox), spin, FALSE, TRUE, 0); + + label = gtk_label_new ("Azimuth"); + gtk_widget_show (label); + gtk_misc_set_alignment (GTK_MISC (label), 1, 0.5); + gtk_box_pack_end (GTK_BOX (hbox), label, FALSE, TRUE, 0); + g_signal_connect (G_OBJECT (spin), "focus_out_event", G_CALLBACK (doublevariable_spinfocusout), &azimuth); +#endif + + frame = gtk_frame_new (NULL); + gtk_widget_show (frame); + gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN); + gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); + + g_pPreviewWidget = g_UIGtkTable.m_pfn_glwidget_new (FALSE, NULL); + + gtk_widget_set_events (g_pPreviewWidget, GDK_EXPOSURE_MASK|GDK_BUTTON_PRESS_MASK|GDK_POINTER_MOTION_MASK); + gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "expose_event", GTK_SIGNAL_FUNC (expose), NULL); + gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "motion_notify_event", GTK_SIGNAL_FUNC (motion), NULL); + gtk_signal_connect (GTK_OBJECT (g_pPreviewWidget), "button_press_event", + GTK_SIGNAL_FUNC (button_press), NULL); + + gtk_widget_show (g_pPreviewWidget); + gtk_container_add (GTK_CONTAINER (frame), g_pPreviewWidget); + + if (Preview) + gtk_widget_show (g_pWndPreview); + + UpdatePreview (true); +} + +//============================================================= +/* DrawPreview */ +void DrawPreview (RECT rc) +{ +#define COSXA 0.8660254037844 +#define SINXA 0.5 +#define COSYA 0.8660254037844 +#define SINYA 0.5 + + double L; + double x,y; + int i, j; + POINT pt[8]; + XYZ v[8]; + char axis[3][2] = {"X","Y","Z"}; + +#ifndef ISOMETRIC + evaluate(); +#endif + + XLo = xmin; + XHi = xmax; + YLo = ymin; + YHi = ymax; + ZLo = zmin; + ZHi = zmax; + switch (Plane) + { + case PLANE_XY1: + ZHi = backface; + break; + case PLANE_XZ0: + YLo = backface; + break; + case PLANE_XZ1: + YHi = backface; + break; + case PLANE_YZ0: + XLo = backface; + break; + case PLANE_YZ1: + XHi = backface; + break; + default: + ZLo = backface; + } + + + + GetScaleFactor(rc); + //PEN_GRID + g_GLTable.m_pfn_qglLineWidth (1); + g_GLTable.m_pfn_qglColor3f (0, 1, 0); + g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); + + if (Decimate > 0 && (Game != QUAKE3 || UsePatches==0) ) + { + XYZ *vv; + + vv = (XYZ *) malloc(gNumNodes * sizeof(XYZ)); + for(i=0; i 2) + x = Hll + dh * (int)(NH/2 + 1); + else + x = Hll + dh * (int)(NH/2); + if(NV > 2) + y = Vll + dv * (int)(NV/2 + 1); + else + y = Vll + dv * (int)(NV/2); + } + else + { + if(NH > 1) + x = Hll + dh * (int)(NH/2); + else + x = Hll + dh/2; + if(NV > 1) + y = Vll + dv * (int)(NV/2); + else + y = Vll + dv/2; + } +// x = (Hll+Hur)/2.; +// y = (Vll+Vur)/2.; + v[0].p[0] = x + PlayerBox[Game].x[0]; + v[0].p[1] = y + PlayerBox[Game].y[0]; + v[0].p[2] = PlayerStartZ(x,y) + PlayerBox[Game].z[0] + 8; // add 8 cuz I'm a pessimist + } + v[1].p[0] = v[0].p[0] + PlayerBox[Game].x[1] - PlayerBox[Game].x[0]; + v[1].p[1] = v[0].p[1]; + v[1].p[2] = v[0].p[2]; + v[2].p[0] = v[1].p[0]; + v[2].p[1] = v[1].p[1] + PlayerBox[Game].y[1] - PlayerBox[Game].y[0]; + v[2].p[2] = v[0].p[2]; + v[3].p[0] = v[0].p[0]; + v[3].p[1] = v[2].p[1]; + v[3].p[2] = v[0].p[2]; + VectorCopy(v[0].p,v[4].p); + VectorCopy(v[1].p,v[5].p); + VectorCopy(v[2].p,v[6].p); + VectorCopy(v[3].p,v[7].p); + v[4].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0]; + v[5].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0]; + v[6].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0]; + v[7].p[2] += PlayerBox[Game].z[1] - PlayerBox[Game].z[0]; + for(i=0; i<=7; i++) + { +#ifndef ISOMETRIC + project(&v[i]); +#endif + Scale(rc,v[i],&pt[i]); + } + g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP); + g_GLTable.m_pfn_qglVertex2f (pt[3].x, pt[3].y); + for(i=0; i<=3; i++) + g_GLTable.m_pfn_qglVertex2f (pt[i].x, pt[i].y); + g_GLTable.m_pfn_qglEnd (); + g_GLTable.m_pfn_qglBegin (GL_LINE_STRIP); + g_GLTable.m_pfn_qglVertex2f (pt[7].x, pt[7].y); + for(i=4; i<=7; i++) + g_GLTable.m_pfn_qglVertex2f (pt[i].x, pt[i].y); + g_GLTable.m_pfn_qglEnd (); + g_GLTable.m_pfn_qglBegin (GL_LINES); + for(i=0; i<=3; i++) + { + g_GLTable.m_pfn_qglVertex2f (pt[i].x,pt[i].y); + g_GLTable.m_pfn_qglVertex2f (pt[i+4].x,pt[i+4].y); + } + g_GLTable.m_pfn_qglEnd (); + + g_GLTable.m_pfn_qglLineWidth (1); + g_GLTable.m_pfn_qglColor3f (0, 1, 0); + g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); +} +//============================================================= +void DrawGrid(RECT rc) +{ + int i, j, k; + double h,w,x,y; + POINT pt[2]; + RECT rcBox; + + w = (double)(rc.right-rc.left+1) - cxChar; + h = (double)(rc.top-rc.bottom+1) - cxChar - cyChar; + + SFG = w/(Hur-Hll); + SFG = min(SFG, h/(Vur-Vll)); + + // Center drawing + X0G = (int)(rc.left + rc.right - (int)(SFG*(Hur-Hll)))/2; + Y0G = (int)(rc.top + rc.bottom + cyChar - (int)(SFG*(Vur-Vll)))/2; + + g_GLTable.m_pfn_qglLineWidth (2); + g_GLTable.m_pfn_qglColor3f (0, 1, 0); + g_GLTable.m_pfn_qglDisable (GL_LINE_STIPPLE); + + pt[0].y = Y0G; + pt[1].y = Y0G + (int)(SFG*(Vur-Vll)); + g_GLTable.m_pfn_qglBegin (GL_LINES); + for(i=0; i<=NH; i++) + { + x = Hll + i * dh; + pt[0].x = X0G + (int)(SFG*(x-Hll)); + g_GLTable.m_pfn_qglVertex2f(pt[0].x, pt[0].y); + g_GLTable.m_pfn_qglVertex2f(pt[0].x, pt[1].y); + } + g_GLTable.m_pfn_qglEnd (); + pt[0].x = X0G; + pt[1].x = X0G + (int)(SFG*(Hur-Hll)); + g_GLTable.m_pfn_qglBegin (GL_LINES); + for(i=0; i<=NV; i++) + { + y = Vll + i * dv; + pt[0].y = Y0G + (int)(SFG*(Vur-y)); + g_GLTable.m_pfn_qglVertex2f (pt[0].x,pt[0].y); + g_GLTable.m_pfn_qglVertex2f (pt[1].x,pt[0].y); + } + g_GLTable.m_pfn_qglEnd (); + + g_GLTable.m_pfn_qglLineWidth (1); + + // Draw axes + pt[0].x = rc.right - cyChar - cxChar - cyChar/2; + pt[0].y = rc.bottom + cyChar/2; + pt[1].x = pt[0].x + cyChar; + pt[1].y = pt[0].y; + g_GLTable.m_pfn_qglBegin (GL_LINES); + g_GLTable.m_pfn_qglVertex2f (pt[0].x,pt[0].y); + g_GLTable.m_pfn_qglVertex2f (pt[1].x,pt[1].y); + g_GLTable.m_pfn_qglEnd (); + switch(Plane) + { + case PLANE_YZ0: + case PLANE_YZ1: + texfont_write ("Y", pt[1].x, pt[1].y+cyChar/2); + break; + default: + texfont_write ("X", pt[1].x, pt[1].y+cyChar/2); + } + pt[1].x = pt[0].x; + pt[1].y = pt[0].y + cyChar; + g_GLTable.m_pfn_qglBegin (GL_LINES); + g_GLTable.m_pfn_qglVertex2f (pt[0].x,pt[0].y); + g_GLTable.m_pfn_qglVertex2f (pt[1].x,pt[1].y); + g_GLTable.m_pfn_qglEnd (); + switch(Plane) + { + case PLANE_XY0: + case PLANE_XY1: + texfont_write ("Y", pt[1].x-cyChar/2, pt[1].y+cyChar); + break; + default: + texfont_write ("Z", pt[1].x-cyChar/2, pt[1].y+cyChar); + } + + // Denote fixed points with a 5x5 red rectangle + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + if(xyz[i][j].fixed) + { + x = Hll + i*dh; + y = Vll + j*dv; + rcBox.left = X0G + (int)(SFG*(x-Hll)) - 2; + rcBox.top = Y0G + (int)(SFG*(Vur-y)) + 2; + rcBox.right = rcBox.left + 5; + rcBox.bottom = rcBox.top - 5; + + DRAW_QUAD (rcBox, 1,0,0); + } + } + } + + // Denote currently selected point with a 5x5 green rectangle + if (NumVerticesSelected) + { + for(k=0; kp[0]; + y = v->p[1]; + z = v->p[2]; + + // yaw + xa = ct[0]*x - st[0]*z; + za = st[0]*x + ct[0]*z; + + // roll + x = ct[1]*xa + st[1]*y; + ya = ct[1]*y - st[1]*xa; + + // azimuth + z = ct[2]*za - st[2]*ya; + y = ct[2]*ya + st[2]*za; + + // horizontal and vertical projections: +// v->pp[0] = D*x/z; +// v->pp[1] = D*y/z; + v->pp[0] = -y; + v->pp[1] = x; + v->pp[2] = z; + + // NOTE: if perspective transformation is desired, + // set "persp" to the range from the surface, + // then: + // v->projected_h = -v->projected_h * persp/(v->projected_z-persp); + // v->projected_v = -v->projected_v * persp/(v->projected_z-persp); +} +/*=======================================================================*/ +void evaluate() +{ + int i, j; + XYZ v[4]; + + if(elevation > PI) elevation -= 2.*PI; + roll = elevation * sin(azimuth); + yaw = 1.5*PI + elevation*cos(azimuth); + + // Find angles from midpoint to viewpoint: + st[0] = sin(yaw); + st[1] = sin(roll); + st[2] = sin(azimuth); + ct[0] = cos(yaw); + ct[1] = cos(roll); + ct[2] = cos(azimuth); + + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + project(&xyz[i][j]); + } + } + + Hhi = xyz[0][0].pp[0]; + Hlo = Hhi; + Vhi = xyz[0][0].pp[1]; + Vlo = Vhi; + for(i=0; i<=NH; i++) + { + for(j=0; j<=NV; j++) + { + Hlo = min(Hlo,xyz[i][j].pp[0]); + Hhi = max(Hhi,xyz[i][j].pp[0]); + Vlo = min(Vlo,xyz[i][j].pp[1]); + Vhi = max(Vhi,xyz[i][j].pp[1]); + } + } + + // Include backface in min-max + VectorCopy(xyz[ 0][ 0].p,v[0].p); + VectorCopy(xyz[NH][ 0].p,v[1].p); + VectorCopy(xyz[NH][NV].p,v[2].p); + VectorCopy(xyz[ 0][NV].p,v[3].p); + switch(Plane) + { + case PLANE_XZ0: + case PLANE_XZ1: + v[0].p[1] = backface; + v[1].p[1] = v[0].p[1]; + v[2].p[1] = v[0].p[1]; + v[3].p[1] = v[0].p[1]; + break; + case PLANE_YZ0: + case PLANE_YZ1: + v[0].p[0] = backface; + v[1].p[0] = v[0].p[0]; + v[2].p[0] = v[0].p[0]; + v[3].p[0] = v[0].p[0]; + break; + default: + v[0].p[2] = backface; + v[1].p[2] = v[0].p[2]; + v[2].p[2] = v[0].p[2]; + v[3].p[2] = v[0].p[2]; + } + for(i=0; i<=3; i++) + { + project(&v[i]); + Hlo = min(Hlo,v[i].pp[0]); + Hhi = max(Hhi,v[i].pp[0]); + Vlo = min(Vlo,v[i].pp[1]); + Vhi = max(Vhi,v[i].pp[1]); + } + +} +#endif diff --git a/contrib/hydratoolz/hydratoolz.def b/contrib/hydratoolz/hydratoolz.def new file mode 100644 index 00000000..c7ce9f33 --- /dev/null +++ b/contrib/hydratoolz/hydratoolz.def @@ -0,0 +1,8 @@ +; fgd.def : Declares the module parameters for the DLL. + +LIBRARY "HydraToolz" +DESCRIPTION 'HydraToolz Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + Synapse_EnumerateInterfaces @1 diff --git a/contrib/hydratoolz/hydratoolz.vcproj b/contrib/hydratoolz/hydratoolz.vcproj new file mode 100644 index 00000000..106ae05b --- /dev/null +++ b/contrib/hydratoolz/hydratoolz.vcproj @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/hydratoolz/plugin.cpp b/contrib/hydratoolz/plugin.cpp new file mode 100644 index 00000000..9e05e6d1 --- /dev/null +++ b/contrib/hydratoolz/plugin.cpp @@ -0,0 +1,412 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "plugin.h" +#include "version.h" + +/*! \file plugin.cpp + \brief HydraToolz! + + HydraToolz by Dominic Clifton - Hydra (Hydra@Hydras-World.com) + + Overview + ======== + + This plugin allows the user to rebuild the "wad" key pair in the worldspawn + so that it has a list of all the .wad files in use. + + Version History + =============== + + v0.1 - 28/May/2002 + - Initial version. + + v1.0 - 10/March/2003 + - Added more console output + - Removed some old test code + - Tweaked dialog box. + - Fixed up for Radiant 1.3.5 + + + ToDo + ==== + + Nothing... + +*/ + +// ============================================================================= +// Globals + +_QERFuncTable_1 g_FuncTable; +_QERFileSystemTable g_FileSystemTable; +_QEREntityTable g_EntityTable; + + +// ============================================================================= +// Ripped from cmdlib.cpp + +/* +==================== +Extract file parts +==================== +*/ +void ExtractFilePath (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' && *(src-1) != '\\') + src--; + + memcpy (dest, path, src-path); + dest[src-path] = 0; +} + +void ExtractFileName (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' + && *(src-1) != '\\' ) + src--; + + while (*src) + { + *dest++ = *src++; + } + *dest = 0; +} + +void ConvertDOSToUnixName( char *dst, const char *src ) +{ + while ( *src ) + { + if ( *src == '\\' ) + *dst = '/'; + else + *dst = *src; + dst++; src++; + } + *dst = 0; +} + +// End of rip from cmdlib.cpp + +// ============================================================================= +// Actual Plugin Code + +// get the wad name from the shader name (or an actual wadname) and add to a list of wad names making +// sure we don't add duplicates. + +GSList *AddToWadList(GSList *wadlist, const char *shadername, const char *wad) +{ + char tmpstr[QER_MAX_NAMELEN]; + char *wadname; + if (!shadername && !wad) return wadlist; + + if (shadername) + { + if (strcmp(shadername,"color") == 0) + return wadlist; + ExtractFilePath(shadername,tmpstr); + // Sys_Printf("checking: %s\n",shadername); + + int l = strlen(tmpstr) - 1; + + if (tmpstr[l] == '/' || tmpstr[l] == '\\') + tmpstr[l] = 0; + else + { + Sys_Printf("HydraToolz: WARNING: Unknown wad file for shader %s\n",shadername); + return wadlist; + } + + ExtractFileName(tmpstr,tmpstr); + + wadname = (char *)malloc(strlen(tmpstr) + 5); + sprintf(wadname,"%s.wad",tmpstr); + } + else + { + wadname=strdup(wad); + } + + for (GSList *l = wadlist; l != NULL ; l = l->next) + { + if (!stricmp((char *)l->data,wadname)) + { + free( wadname ); + return wadlist; + } + } + + Sys_Printf("HydraToolz: Adding Wad File to WAD list: %s (reason: ",wadname); + if (shadername) + Sys_Printf("see shader \"%s\")\n", shadername); + else + Sys_Printf("already in WAD key. )\n"); + return ( g_slist_append (wadlist, wadname ) ); +} + +void UpdateWadKeyPair( void ) +{ + int i,nb; + + char wads[2048]; // change to CString usage ? + *wads = 0; + char *p1,*p2; + entity_t *pEntity; + epair_t *pEpair; + GSList *wadlist = NULL; + face_t *f; + brush_t *b; + char cleanwadname[QER_MAX_NAMELEN]; + char *actualwad; + + + pEntity = (entity_t *)g_FuncTable.m_pfnGetEntityHandle(0); // get the worldspawn ent + + Sys_Printf("HydraToolz: Searching for in-use wad files...\n"); + for(pEpair = pEntity->epairs; pEpair != NULL; pEpair = pEpair->next) + { + if (stricmp(pEpair->key,"wad") == 0) + { + strcpy(wads,pEpair->value); + ConvertDOSToUnixName(wads,wads); + + Sys_Printf("HydraToolz: Current wad key is \"%s\"!\n",wads); + + // ok, we got the list of ; delimited wads, now split it into a GSList that contains + // just the wad names themselves. + + p1 = wads; + + do + { + p2 = strchr(p1,';'); + if (p2) + *p2 = 0; // swap the ; with a null terminator + + if (strchr(p1,'/') || strchr(p1,'\\')) + { + ExtractFileName(p1,cleanwadname); + wadlist = AddToWadList (wadlist, NULL, cleanwadname); + } + else + { + wadlist = AddToWadList (wadlist, NULL, p1); + } + if (p2) + p1 = p2+1; // point back to the remainder of the string + else + p1 = NULL; // make it so we exit the loop. + + } while (p1); + + // ok, now we have a list of wads in GSList. + // now we need to add any new wadfiles (with their paths) to this list + // so scan all brushes and see what wads are in use + // FIXME: scan brushes only in the region ? + + break; // we don't need to process any more key/pairs. + } + } + + if (!*wads) + Sys_Printf("HydraToolz: No \"wad\" keypair wound in worldspawn\n"); + + + nb = g_FuncTable.m_pfnAllocateActiveBrushHandles(); + for( i = 0; i < nb; i++ ) + { + b = (brush_t *)g_FuncTable.m_pfnGetActiveBrushHandle(i); + if (b->patchBrush) // patches in halflife ? + { + wadlist = AddToWadList(wadlist, b->pPatch->pShader->getName(),NULL); + } else + { + for (f=b->brush_faces ; f ; f=f->next) + { + wadlist = AddToWadList(wadlist, f->pShader->getName(),NULL); + } + } + } + g_FuncTable.m_pfnReleaseActiveBrushHandles(); + + nb = g_FuncTable.m_pfnAllocateSelectedBrushHandles(); + for( i = 0; i < nb; i++ ) + { + b = (brush_t *)g_FuncTable.m_pfnGetSelectedBrushHandle(i); + if (b->patchBrush) // patches in halflife ? + { + wadlist = AddToWadList(wadlist, b->pPatch->pShader->getName(),NULL); + } else + { + for (f=b->brush_faces ; f ; f=f->next) + { + wadlist = AddToWadList(wadlist, f->pShader->getName(),NULL); + } + } + } + g_FuncTable.m_pfnReleaseSelectedBrushHandles(); + + Sys_Printf("HydraToolz: Rebuilding worldspawn's \"wad\" key-pair...\n"); + // Now we have a complete list of wadnames (without paths) so we just have to turn this + // back to a ; delimited list. + + *wads = 0; + while (wadlist) + { + // skip wad files if they start with "common-" + if (strnicmp((char *)wadlist->data,"common-",7) == 0) + { + Sys_Printf("HydraToolz: Skipping radiant/user-supplied wad file %s\n",(char *)wadlist->data); + } + else + { + if (wads[0]) + strcat(wads,";"); + + actualwad = vfsGetFullPath((char *)wadlist->data); + + if (actualwad) + { + strcat(wads, actualwad); + } + else + { + Sys_Printf("HydraToolz: WARNING: could not locate wad file %s\n",(char *)wadlist->data); + strcat(wads, (char *)wadlist->data); + } + } + + free (wadlist->data); + wadlist = g_slist_remove (wadlist, wadlist->data); + } + + // store the wad list back in the worldspawn. + if (*wads) + { + //free(pEpair->value); + //pEpair->value = strdup(wads); + SetKeyValue(pEntity, "wad", wads); + Sys_Printf("HydraToolz: Setting worldspawn \"wad\" key value to \"%s\"\n",wads); + + } + + Sys_Printf("HydraToolz: Finished rebuilding wad keypair!\n"); + +} + +// ============================================================================= +// PLUGIN INTERFACE STUFF + +// plugin name +const char *PLUGIN_NAME = "HydraToolz"; + +// commands in the menu +const char *PLUGIN_COMMANDS = "About...;Create/Update WAD keypair"; + +const char *PLUGIN_ABOUT = "HydraToolz v1.0 for GTKRadiant\n\n" + "By Hydra!"; + +extern "C" void* WINAPI QERPlug_GetFuncTable () +{ + return &g_FuncTable; +} + +const char* QERPlug_Init (void* hApp, void *pWidget) +{ + return "HydraToolz for GTKRadiant"; // do we need this ? hmmm +} + +const char* QERPlug_GetName() +{ + return (char*)PLUGIN_NAME; +} + +const char* QERPlug_GetCommandList() +{ + return PLUGIN_COMMANDS; +} + +extern "C" void QERPlug_Dispatch(const char* p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) +{ + if(!strcmp(p, "Create/Update WAD keypair")) + UpdateWadKeyPair(); + else if(!strcmp(p, "About...")) + g_FuncTable.m_pfnMessageBox(NULL, PLUGIN_ABOUT, "About", MB_OK, NULL); +} + +// ============================================================================= +// SYNAPSE + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientHydraToolz g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + g_SynapseClient.AddAPI(PLUGIN_MAJOR, "HydraToolz", sizeof(_QERPluginTable)); + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(VFS_MAJOR, "wad", sizeof(g_FileSystemTable), SYN_REQUIRE, &g_FileSystemTable); + g_SynapseClient.AddAPI(ENTITY_MAJOR, NULL, sizeof(g_EntityTable), SYN_REQUIRE, &g_EntityTable); + return &g_SynapseClient; +} + +bool CSynapseClientHydraToolz::RequestAPI(APIDescriptor_t *pAPI) +{ + if (!strcmp(pAPI->major_name, PLUGIN_MAJOR)) + { + _QERPluginTable *pTable = static_cast<_QERPluginTable*>(pAPI->mpTable); + pTable->m_pfnQERPlug_Init = QERPlug_Init; + pTable->m_pfnQERPlug_GetName = QERPlug_GetName; + pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList; + pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch; + return true; + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +const char* CSynapseClientHydraToolz::GetInfo() +{ + return "HydraToolz plugin built " __DATE__ " " RADIANT_VERSION; +} diff --git a/contrib/hydratoolz/plugin.h b/contrib/hydratoolz/plugin.h new file mode 100644 index 00000000..493fa839 --- /dev/null +++ b/contrib/hydratoolz/plugin.h @@ -0,0 +1,51 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _PLUGIN_H_ +#define _PLUGIN_H_ + +//#include +//#include +#include +#include + +#include "synapse.h" +#include "iplugin.h" +#define USE_QERTABLE_DEFINE +#include "qerplugin.h" +#include "ishaders.h" +#define USE_VFSTABLE_DEFINE +#include "ifilesystem.h" +#define USE_ENTITYTABLE_DEFINE +#include "ientity.h" + +class CSynapseClientHydraToolz : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + CSynapseClientHydraToolz() { } + virtual ~CSynapseClientHydraToolz() { } +}; + +#endif // _PLUGIN_H_ diff --git a/contrib/prtview/.cvsignore b/contrib/prtview/.cvsignore new file mode 100644 index 00000000..66d25b10 --- /dev/null +++ b/contrib/prtview/.cvsignore @@ -0,0 +1,8 @@ +Debug +Release +*.d +*.plg +*.BAK +*.mak +*.ncb +*.opt diff --git a/contrib/prtview/AboutDialog.cpp b/contrib/prtview/AboutDialog.cpp new file mode 100644 index 00000000..b82a7a49 --- /dev/null +++ b/contrib/prtview/AboutDialog.cpp @@ -0,0 +1,139 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// AboutDialog.cpp : implementation file +// + +#include "stdafx.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +//static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CAboutDialog dialog + +#ifdef GTK_PLUGIN + +static void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +void DoAboutDlg () +{ + GtkWidget *dlg, *hbox, *vbox, *button, *label; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "About Portal Viewer"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 10); + + label = gtk_label_new ("Version 1.000\n\n" + "Gtk port by Leonardo Zide\nleo@lokigames.com\n\n" + "Written by Geoffrey DeWan\ngdewan@prairienet.org\n\n" + "Built against GtkRadiant " RADIANT_VERSION "\n" + __DATE__ + ); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +#else // GTK_PLUGIN + +CAboutDialog::CAboutDialog(CWnd* pParent /*=NULL*/) + : CDialog(CAboutDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CAboutDialog) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + + +void CAboutDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CAboutDialog) + // NOTE: the ClassWizard will add DDX and DDV calls here + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CAboutDialog, CDialog) + //{{AFX_MSG_MAP(CAboutDialog) + // NOTE: the ClassWizard will add message map macros here + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +#endif // GTK_PLUGIN + +///////////////////////////////////////////////////////////////////////////// +// CAboutDialog message handlers diff --git a/contrib/prtview/AboutDialog.h b/contrib/prtview/AboutDialog.h new file mode 100644 index 00000000..73dbad78 --- /dev/null +++ b/contrib/prtview/AboutDialog.h @@ -0,0 +1,72 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_ABOUTDIALOG_H__FA3BE6A2_1F1F_11D4_BFF1_204C4F4F5020__INCLUDED_) +#define AFX_ABOUTDIALOG_H__FA3BE6A2_1F1F_11D4_BFF1_204C4F4F5020__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// AboutDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CAboutDialog dialog + +#ifdef GTK_PLUGIN +void DoAboutDlg (); + +#else // GTK_PLUGIN + +class CAboutDialog : public CDialog +{ +// Construction +public: + CAboutDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CAboutDialog) + enum { IDD = IDD_ABOUT }; + // NOTE: the ClassWizard will add data members here + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CAboutDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CAboutDialog) + // NOTE: the ClassWizard will add member functions here + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +#endif // GTK_PLUGIN + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_ABOUTDIALOG_H__FA3BE6A2_1F1F_11D4_BFF1_204C4F4F5020__INCLUDED_) diff --git a/contrib/prtview/ConfigDialog.cpp b/contrib/prtview/ConfigDialog.cpp new file mode 100644 index 00000000..ced949bb --- /dev/null +++ b/contrib/prtview/ConfigDialog.cpp @@ -0,0 +1,925 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// ConfigDialog.cpp : implementation file +// + +#include "stdafx.h" +#include + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +//static char THIS_FILE[] = __FILE__; +#endif + +///////////////////////////////////////////////////////////////////////////// +// CConfigDialog dialog + +#ifdef GTK_PLUGIN + +static void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +// ============================================================================= +// Color selection dialog + +static int DoColor (COLORREF *c) +{ + GtkWidget* dlg; + double clr[3]; + int loop = 1, ret = IDCANCEL; + + clr[0] = ((double)GetRValue (*c)) / 255.0; + clr[1] = ((double)GetGValue (*c)) / 255.0; + clr[2] = ((double)GetBValue (*c)) / 255.0; + + dlg = gtk_color_selection_dialog_new ("Choose Color"); + gtk_color_selection_set_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->ok_button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->cancel_button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + gtk_widget_show(dlg); + gtk_grab_add(dlg); + + while (loop) + gtk_main_iteration (); + + gtk_color_selection_get_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + if (ret == IDOK) + { + *c = RGB (clr[0]*255, clr[1]*255, clr[2]*255); + } + + return ret; +} + +static void Set2DText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Line Width = %6.3f", portals.width_2d * 0.5f); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void Set3DText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Line Width = %6.3f", portals.width_3d * 0.5f); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void Set3DTransText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Polygon transparency = %d%%", (int)portals.trans_3d); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void SetClipText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Cubic clip range = %d", (int)portals.clip_range * 64); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void OnScroll2d (GtkAdjustment *adj, gpointer data) +{ + portals.width_2d = adj->value; + Set2DText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +static void OnScroll3d (GtkAdjustment *adj, gpointer data) +{ + portals.width_3d = adj->value; + Set3DText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnScrollTrans (GtkAdjustment *adj, gpointer data) +{ + portals.trans_3d = adj->value; + Set3DTransText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnScrollClip (GtkAdjustment *adj, gpointer data) +{ + portals.clip_range = adj->value; + SetClipText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnAntiAlias2d (GtkWidget *widget, gpointer data) +{ + portals.aa_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +static void OnConfig2d (GtkWidget *widget, gpointer data) +{ + portals.show_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +static void OnColor2d (GtkWidget *widget, gpointer data) +{ + if (DoColor (&portals.color_2d) == IDOK) + { + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); + } +} + +static void OnConfig3d (GtkWidget *widget, gpointer data) +{ + portals.show_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + + +static void OnAntiAlias3d (GtkWidget *widget, gpointer data) +{ + portals.aa_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnColor3d (GtkWidget *widget, gpointer data) +{ + if (DoColor (&portals.color_3d) == IDOK) + { + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +static void OnColorFog (GtkWidget *widget, gpointer data) +{ + if (DoColor (&portals.color_fog) == IDOK) + { + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +static void OnFog (GtkWidget *widget, gpointer data) +{ + portals.fog = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnSelchangeZbuffer (GtkWidget *widget, gpointer data) +{ + portals.zbuffer = GPOINTER_TO_INT (data); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnPoly (GtkWidget *widget, gpointer data) +{ + portals.polygons = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnLines (GtkWidget *widget, gpointer data) +{ + portals.lines = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnClip (GtkWidget *widget, gpointer data) +{ + portals.clip = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)) ? true : false; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void DoConfigDialog () +{ + GtkWidget *dlg, *hbox, *vbox, *vbox2, *button, *table, *frame; + GtkWidget *lw3slider, *lw3label, *lw2slider, *lw2label, *zlist, *menu, *item; + GtkWidget *aa2check, *aa3check, *depthcheck, *linescheck, *polyscheck; + GtkWidget *transslider, *translabel, *clipslider, *cliplabel; + GtkWidget *show2check, *show3check, *portalcheck; + int loop = 1, ret = IDCANCEL; + GtkObject *adj; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Portal Viewer Configuration"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + frame = gtk_frame_new ("3D View"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, TRUE, 0); + + adj = gtk_adjustment_new (portals.width_3d, 2, 40, 1, 1, 1); + lw3slider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (lw3slider); + gtk_box_pack_start (GTK_BOX (hbox), lw3slider, TRUE, TRUE, 0); + gtk_scale_set_draw_value (GTK_SCALE (lw3slider), FALSE); + + lw3label = gtk_label_new (""); + gtk_widget_show (lw3label); + gtk_box_pack_start (GTK_BOX (hbox), lw3label, FALSE, TRUE, 0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScroll3d), lw3label); + + table = gtk_table_new (2, 4, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + button = gtk_button_new_with_label ("Color"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColor3d), NULL); + + button = gtk_button_new_with_label ("Depth Color"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColorFog), NULL); + + aa3check = gtk_check_button_new_with_label ("Anti-Alias (May not work on some video cards)"); + gtk_widget_show (aa3check); + gtk_table_attach (GTK_TABLE (table), aa3check, 1, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (aa3check), "toggled", GTK_SIGNAL_FUNC (OnAntiAlias3d), NULL); + + depthcheck = gtk_check_button_new_with_label ("Depth Cue"); + gtk_widget_show (depthcheck); + gtk_table_attach (GTK_TABLE (table), depthcheck, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (depthcheck), "toggled", GTK_SIGNAL_FUNC (OnFog), NULL); + + linescheck = gtk_check_button_new_with_label ("Lines"); + gtk_widget_show (linescheck); + gtk_table_attach (GTK_TABLE (table), linescheck, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (linescheck), "toggled", GTK_SIGNAL_FUNC (OnLines), NULL); + + polyscheck = gtk_check_button_new_with_label ("Polygons"); + gtk_widget_show (polyscheck); + gtk_table_attach (GTK_TABLE (table), polyscheck, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (polyscheck), "toggled", GTK_SIGNAL_FUNC (OnPoly), NULL); + + zlist = gtk_option_menu_new (); + gtk_widget_show (zlist); + gtk_box_pack_start (GTK_BOX (vbox2), zlist, TRUE, FALSE, 0); + + menu = gtk_menu_new (); + gtk_widget_show (menu); + gtk_option_menu_set_menu (GTK_OPTION_MENU (zlist), menu); + + item = gtk_menu_item_new_with_label ("Z-Buffer Test and Write (recommended for solid or no polygons)"); + gtk_widget_show (item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (0)); + gtk_menu_append (GTK_MENU (menu), item); + + item = gtk_menu_item_new_with_label ("Z-Buffer Test Only (recommended for transparent polygons)"); + gtk_widget_show (item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (1)); + gtk_menu_append (GTK_MENU (menu), item); + + item = gtk_menu_item_new_with_label ("Z-Buffer Off"); + gtk_widget_show (item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (2)); + gtk_menu_append (GTK_MENU (menu), item); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + adj = gtk_adjustment_new (portals.trans_3d, 0, 100, 1, 1, 1); + transslider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (transslider); + gtk_table_attach (GTK_TABLE (table), transslider, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_scale_set_draw_value (GTK_SCALE (transslider), FALSE); + + translabel = gtk_label_new (""); + gtk_widget_show (translabel); + gtk_table_attach (GTK_TABLE (table), translabel, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (translabel), 0.0, 0.0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScrollTrans), translabel); + + adj = gtk_adjustment_new (portals.clip_range, 1, 128, 1, 1, 1); + clipslider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (clipslider); + gtk_table_attach (GTK_TABLE (table), clipslider, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_scale_set_draw_value (GTK_SCALE (clipslider), FALSE); + + cliplabel = gtk_label_new (""); + gtk_widget_show (cliplabel); + gtk_table_attach (GTK_TABLE (table), cliplabel, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (cliplabel), 0.0, 0.0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScrollClip), cliplabel); + + hbox = gtk_hbox_new (TRUE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + show3check = gtk_check_button_new_with_label ("Show"); + gtk_widget_show (show3check); + gtk_box_pack_start (GTK_BOX (hbox), show3check, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (show3check), "toggled", GTK_SIGNAL_FUNC (OnConfig3d), NULL); + + portalcheck = gtk_check_button_new_with_label ("Portal cubic clipper"); + gtk_widget_show (portalcheck); + gtk_box_pack_start (GTK_BOX (hbox), portalcheck, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (portalcheck), "toggled", GTK_SIGNAL_FUNC (OnClip), NULL); + + frame = gtk_frame_new ("2D View"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + adj = gtk_adjustment_new (portals.width_2d, 2, 40, 1, 1, 1); + lw2slider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (lw2slider); + gtk_box_pack_start (GTK_BOX (hbox), lw2slider, TRUE, TRUE, 0); + gtk_scale_set_draw_value (GTK_SCALE (lw2slider), FALSE); + + lw2label = gtk_label_new (""); + gtk_widget_show (lw2label); + gtk_box_pack_start (GTK_BOX (hbox), lw2label, FALSE, TRUE, 0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScroll2d), lw2label); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + button = gtk_button_new_with_label ("Color"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColor2d), NULL); + gtk_widget_set_usize (button, 60, -2); + + aa2check = gtk_check_button_new_with_label ("Anti-Alias (May not work on some video cards)"); + gtk_widget_show (aa2check); + gtk_box_pack_start (GTK_BOX (hbox), aa2check, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (aa2check), "toggled", GTK_SIGNAL_FUNC (OnAntiAlias2d), NULL); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + show2check = gtk_check_button_new_with_label ("Show"); + gtk_widget_show (show2check); + gtk_box_pack_start (GTK_BOX (hbox), show2check, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (show2check), "toggled", GTK_SIGNAL_FUNC (OnConfig2d), NULL); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + // initialize dialog + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show2check), portals.show_2d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aa2check), portals.aa_2d); + Set2DText (lw2label); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show3check), portals.show_3d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (depthcheck), portals.fog); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (polyscheck), portals.polygons); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (linescheck), portals.lines); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aa3check), portals.aa_3d); + gtk_option_menu_set_history (GTK_OPTION_MENU (zlist), portals.zbuffer); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (portalcheck), portals.clip); + + Set3DText (lw3label); + Set3DTransText (translabel); + SetClipText (cliplabel); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +#else // GTK_PLUGIN + +CConfigDialog::CConfigDialog(CWnd* pParent /*=NULL*/) + : CDialog(CConfigDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CConfigDialog) + //}}AFX_DATA_INIT +} + + +void CConfigDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CConfigDialog) + DDX_Control(pDX, IDC_CLIP, m_clip_ctrl); + DDX_Control(pDX, IDC_CUBIC, m_cubic_ctrl); + DDX_Control(pDX, IDC_SCROLL_CUBIC, m_scroll_cubic_ctrl); + DDX_Control(pDX, IDC_LINES, m_line_ctrl); + DDX_Control(pDX, IDC_SCROLL_3D_TRANS, m_scroll_3d_trans_ctrl); + DDX_Control(pDX, IDC_3D_TRANS, m_3d_trans_ctrl); + DDX_Control(pDX, IDC_POLY, m_poly_ctrl); + DDX_Control(pDX, IDC_FOG, m_fog_ctrl); + DDX_Control(pDX, IDC_ZBUFFER, m_z_ctrl); + DDX_Control(pDX, IDC_SCROLL_3D_WIDTH, m_scroll_3d_width_ctrl); + DDX_Control(pDX, IDC_ANTI_ALIAS_3D, m_aa_3d_ctrl); + DDX_Control(pDX, IDC_3D_WIDTH, m_3d_width_ctrl); + DDX_Control(pDX, IDC_ANTI_ALIAS_2D, m_aa_2d_ctrl); + DDX_Control(pDX, IDC_SCROLL_2D_WIDTH, m_scroll_2d_width_ctrl); + DDX_Control(pDX, IDC_2D_WIDTH, m_2d_width_ctrl); + DDX_Control(pDX, IDC_CONFIG_3D, m_3d_ctrl); + DDX_Control(pDX, IDC_CONFIG_2D, m_2d_ctrl); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CConfigDialog, CDialog) + //{{AFX_MSG_MAP(CConfigDialog) + ON_WM_HSCROLL() + ON_BN_CLICKED(IDC_ANTI_ALIAS_2D, OnAntiAlias2d) + ON_BN_CLICKED(IDC_CONFIG_2D, OnConfig2d) + ON_BN_CLICKED(IDC_CONFIG_3D, OnConfig3d) + ON_BN_CLICKED(IDC_COLOR_2D, OnColor2d) + ON_BN_CLICKED(IDC_ANTI_ALIAS_3D, OnAntiAlias3d) + ON_BN_CLICKED(IDC_COLOR_3D, OnColor3d) + ON_BN_CLICKED(IDC_COLOR_FOG, OnColorFog) + ON_BN_CLICKED(IDC_FOG, OnFog) + ON_CBN_SELCHANGE(IDC_ZBUFFER, OnSelchangeZbuffer) + ON_BN_CLICKED(IDC_POLY, OnPoly) + ON_BN_CLICKED(IDC_LINES, OnLines) + ON_BN_CLICKED(IDC_CLIP, OnClip) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + +///////////////////////////////////////////////////////////////////////////// +// CConfigDialog message handlers + +void CConfigDialog::Set2DText() +{ + char s[40]; + + sprintf(s, "Line Width = %6.3f", portals.width_2d * 0.5f); + + m_2d_width_ctrl.SetWindowText(s); +} + +void CConfigDialog::Set3DText() +{ + char s[40]; + + sprintf(s, "Line Width = %6.3f", portals.width_3d * 0.5f); + + m_3d_width_ctrl.SetWindowText(s); +} + +void CConfigDialog::Set3DTransText() +{ + char s[40]; + + sprintf(s, "Polygon transparency = %d%%", (int)portals.trans_3d); + + m_3d_trans_ctrl.SetWindowText(s); +} + +void CConfigDialog::SetClipText() +{ + char s[40]; + + sprintf(s, "Cubic clip range = %d", (int)portals.clip_range * 64); + + m_cubic_ctrl.SetWindowText(s); +} + +qboolean CConfigDialog::OnInitDialog() +{ + CDialog::OnInitDialog(); + + m_2d_ctrl.SetCheck(portals.show_2d); + m_aa_2d_ctrl.SetCheck(portals.aa_2d); + Set2DText(); + + m_scroll_2d_width_ctrl.SetScrollRange(2, 40, FALSE); + m_scroll_2d_width_ctrl.SetScrollPos((int)portals.width_2d, TRUE); + + m_3d_ctrl.SetCheck(portals.show_3d); + m_fog_ctrl.SetCheck(portals.fog); + m_poly_ctrl.SetCheck(portals.polygons); + m_line_ctrl.SetCheck(portals.lines); + m_aa_3d_ctrl.SetCheck(portals.aa_3d); + m_z_ctrl.SetCurSel(portals.zbuffer); + m_clip_ctrl.SetCheck(portals.clip); + + Set3DText(); + Set3DTransText(); + SetClipText(); + + m_scroll_3d_width_ctrl.SetScrollRange(2, 40, FALSE); + m_scroll_3d_width_ctrl.SetScrollPos((int)portals.width_3d, TRUE); + m_scroll_3d_trans_ctrl.SetScrollRange(0, 100, FALSE); + m_scroll_3d_trans_ctrl.SetScrollPos((int)portals.trans_3d, TRUE); + m_scroll_cubic_ctrl.SetScrollRange(1, 128, FALSE); + m_scroll_cubic_ctrl.SetScrollPos((int)portals.clip_range, TRUE); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CConfigDialog::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) +{ + float *adj; + float scr_min, scr_max, scr_big; + + if(nSBCode == SB_THUMBPOSITION) + { + CDialog::OnHScroll(nSBCode, nPos, pScrollBar); + return; + } + + if(pScrollBar == &m_scroll_2d_width_ctrl) + { + scr_min = 2.0f; + scr_max = 40.0f; + scr_big = 4.0f; + + adj = &portals.width_2d; + } + else if(pScrollBar == &m_scroll_3d_width_ctrl) + { + scr_min = 2.0f; + scr_max = 40.0f; + scr_big = 4.0f; + + adj = &portals.width_3d; + } + else if(pScrollBar == &m_scroll_3d_trans_ctrl) + { + scr_min = 0.0f; + scr_max = 100.0f; + scr_big = 10.0f; + + adj = &portals.trans_3d; + } + else if(pScrollBar == &m_scroll_cubic_ctrl) + { + scr_min = 1.0f; + scr_max = 128.0f; + scr_big = 8.0f; + + adj = &portals.clip_range; + } + else + { + CDialog::OnHScroll(nSBCode, nPos, pScrollBar); + return; + } + + switch(nSBCode) + { + case SB_LEFT: + *adj = scr_min; + pScrollBar->SetScrollPos((int)scr_min, TRUE); + break; + case SB_RIGHT: + *adj = scr_max; + pScrollBar->SetScrollPos((int)scr_max, TRUE); + break; + case SB_LINELEFT: + *adj -= 1.0f; + + if(*adj < scr_min) + *adj = scr_min; + + pScrollBar->SetScrollPos((int)(*adj), TRUE); + + break; + case SB_LINERIGHT: + *adj += 1.0f; + + if(*adj > scr_max) + *adj = scr_max; + + pScrollBar->SetScrollPos((int)(*adj), TRUE); + + break; + case SB_PAGELEFT: + *adj -= scr_big; + + if(*adj < scr_min) + *adj = scr_min; + + pScrollBar->SetScrollPos((int)(*adj), TRUE); + + break; + case SB_PAGERIGHT: + *adj += scr_big; + + if(*adj > scr_max) + *adj = scr_max; + + pScrollBar->SetScrollPos((int)(*adj), TRUE); + + break; + case SB_THUMBTRACK: + *adj = (float)nPos; + + break; + case SB_ENDSCROLL: + pScrollBar->SetScrollPos((int)(*adj), TRUE); + + break; + default: + CDialog::OnHScroll(nSBCode, nPos, pScrollBar); + } + + if(pScrollBar == &m_scroll_2d_width_ctrl) + { + Set2DText(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); + } + else if(pScrollBar == &m_scroll_3d_width_ctrl) + { + Set3DText(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } + else if(pScrollBar == &m_scroll_3d_trans_ctrl) + { + Set3DTransText(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } + else if(pScrollBar == &m_scroll_cubic_ctrl) + { + SetClipText(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +void CConfigDialog::OnAntiAlias2d() +{ + portals.aa_2d = m_aa_2d_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +void CConfigDialog::OnConfig2d() +{ + portals.show_2d = m_2d_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +void CConfigDialog::OnColor2d() +{ + CColorDialog dlg(portals.color_2d, CC_ANYCOLOR, this); + + if(dlg.DoModal() == IDOK) + { + portals.color_2d = dlg.GetColor(); + + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); + } +} + +void CConfigDialog::OnConfig3d() +{ + portals.show_3d = m_3d_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + + +void CConfigDialog::OnAntiAlias3d() +{ + portals.aa_3d = m_aa_3d_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void CConfigDialog::OnColor3d() +{ + CColorDialog dlg(portals.color_3d, CC_ANYCOLOR, this); + + if(dlg.DoModal() == IDOK) + { + portals.color_3d = dlg.GetColor(); + + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +void CConfigDialog::OnColorFog() +{ + CColorDialog dlg(portals.color_fog, CC_ANYCOLOR, this); + + if(dlg.DoModal() == IDOK) + { + portals.color_fog = dlg.GetColor(); + + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +void CConfigDialog::OnFog() +{ + portals.fog = m_fog_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void CConfigDialog::OnSelchangeZbuffer() +{ + portals.zbuffer = m_z_ctrl.GetCurSel(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void CConfigDialog::OnPoly() +{ + portals.polygons = m_poly_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void CConfigDialog::OnLines() +{ + portals.lines = m_line_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void CConfigDialog::OnClip() +{ + portals.clip = m_clip_ctrl.GetCheck(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +#endif // GTK_PLUGIN diff --git a/contrib/prtview/ConfigDialog.h b/contrib/prtview/ConfigDialog.h new file mode 100644 index 00000000..7ca84920 --- /dev/null +++ b/contrib/prtview/ConfigDialog.h @@ -0,0 +1,107 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_CONFIGDIALOG_H__E484E672_2088_11D4_BFFA_204C4F4F5020__INCLUDED_) +#define AFX_CONFIGDIALOG_H__E484E672_2088_11D4_BFFA_204C4F4F5020__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// ConfigDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CConfigDialog dialog + +#ifdef GTK_PLUGIN + +void DoConfigDialog (); + +#else + +class CConfigDialog : public CDialog +{ +// Construction +public: + CConfigDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CConfigDialog) + enum { IDD = IDD_CONFIG }; + CButton m_clip_ctrl; + CStatic m_cubic_ctrl; + CScrollBar m_scroll_cubic_ctrl; + CButton m_line_ctrl; + CScrollBar m_scroll_3d_trans_ctrl; + CStatic m_3d_trans_ctrl; + CButton m_poly_ctrl; + CButton m_fog_ctrl; + CComboBox m_z_ctrl; + CScrollBar m_scroll_3d_width_ctrl; + CButton m_aa_3d_ctrl; + CStatic m_3d_width_ctrl; + CButton m_aa_2d_ctrl; + CScrollBar m_scroll_2d_width_ctrl; + CStatic m_2d_width_ctrl; + CButton m_3d_ctrl; + CButton m_2d_ctrl; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CConfigDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + void Set2DText(); + void Set3DText(); + void Set3DTransText(); + void SetClipText(); + + // Generated message map functions + //{{AFX_MSG(CConfigDialog) + virtual qboolean OnInitDialog(); + afx_msg void OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar); + afx_msg void OnAntiAlias2d(); + afx_msg void OnConfig2d(); + afx_msg void OnConfig3d(); + afx_msg void OnColor2d(); + afx_msg void OnAntiAlias3d(); + afx_msg void OnColor3d(); + afx_msg void OnColorFog(); + afx_msg void OnFog(); + afx_msg void OnSelchangeZbuffer(); + afx_msg void OnPoly(); + afx_msg void OnLines(); + afx_msg void OnClip(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +#endif // GTK_PLUGIN + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_CONFIGDIALOG_H__E484E672_2088_11D4_BFFA_204C4F4F5020__INCLUDED_) diff --git a/contrib/prtview/LoadPortalFileDialog.cpp b/contrib/prtview/LoadPortalFileDialog.cpp new file mode 100644 index 00000000..ed7d9de1 --- /dev/null +++ b/contrib/prtview/LoadPortalFileDialog.cpp @@ -0,0 +1,288 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// LoadPortalFileDialog.cpp : implementation file +// + +#include "stdafx.h" + +#ifdef _DEBUG +#define new DEBUG_NEW +#undef THIS_FILE +//static char THIS_FILE[] = __FILE__; +#endif + +#ifdef GTK_PLUGIN + +static void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +static void file_sel_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop; + char **filename; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + filename = (char**)g_object_get_data (G_OBJECT (parent), "filename"); + + *loop = 0; + if ((int)data == IDOK) + *filename = g_strdup (gtk_file_selection_get_filename (GTK_FILE_SELECTION (parent))); +} + +static void change_clicked (GtkWidget *widget, gpointer data) +{ + GtkWidget* file_sel; + char* filename = NULL; + int loop = 1; + + file_sel = gtk_file_selection_new ("Locate portal (.prt) file"); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK)); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel)); + + g_object_set_data (G_OBJECT (file_sel), "loop", &loop); + g_object_set_data (G_OBJECT (file_sel), "filename", &filename); + gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), portals.fn); + + gtk_grab_add (file_sel); + gtk_widget_show (file_sel); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (file_sel); + gtk_widget_destroy (file_sel); + + if (filename != NULL) + { + strcpy (portals.fn, filename); + gtk_entry_set_text (GTK_ENTRY (data), filename); + g_free (filename); + } +} + +int DoLoadPortalFileDialog () +{ + GtkWidget *dlg, *vbox, *hbox, *button, *entry, *check2d, *check3d; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Load .prt"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_entry_set_editable (GTK_ENTRY (entry), FALSE); + gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + check3d = gtk_check_button_new_with_label ("Show 3D"); + gtk_widget_show (check3d); + gtk_box_pack_start (GTK_BOX (hbox), check3d, FALSE, FALSE, 0); + + check2d = gtk_check_button_new_with_label ("Show 2D"); + gtk_widget_show (check2d); + gtk_box_pack_start (GTK_BOX (hbox), check2d, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Change"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (change_clicked), entry); + gtk_widget_set_usize (button, 60, -2); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + char *fn = g_FuncTable.m_pfnGetMapName(); + strcpy (portals.fn, fn); + fn = strrchr (portals.fn, '.'); + if (fn != NULL) + { + *fn = '\0'; + strcat (portals.fn, ".prt"); + } + + gtk_entry_set_text (GTK_ENTRY (entry), portals.fn); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check2d), portals.show_2d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check3d), portals.show_3d); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + portals.Purge(); + + portals.show_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check3d)) ? true : false; + portals.show_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check2d)) ? true : false; + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + return ret; +} + +#else // GTK_PLUGIN + +///////////////////////////////////////////////////////////////////////////// +// CLoadPortalFileDialog dialog + +CLoadPortalFileDialog::CLoadPortalFileDialog(CWnd* pParent /*=NULL*/) + : CDialog(CLoadPortalFileDialog::IDD, pParent) +{ + //{{AFX_DATA_INIT(CLoadPortalFileDialog) + // NOTE: the ClassWizard will add member initialization here + //}}AFX_DATA_INIT +} + + +void CLoadPortalFileDialog::DoDataExchange(CDataExchange* pDX) +{ + CDialog::DoDataExchange(pDX); + //{{AFX_DATA_MAP(CLoadPortalFileDialog) + DDX_Control(pDX, IDC_LOAD_3D, m_3d_ctrl); + DDX_Control(pDX, IDC_LOAD_2D, m_2d_ctrl); + DDX_Control(pDX, IDC_LOAD_FILE_NAME, m_fn_ctrl); + //}}AFX_DATA_MAP +} + + +BEGIN_MESSAGE_MAP(CLoadPortalFileDialog, CDialog) + //{{AFX_MSG_MAP(CLoadPortalFileDialog) + ON_BN_CLICKED(IDC_LOAD_OTHER, OnLoadOther) + //}}AFX_MSG_MAP +END_MESSAGE_MAP() + + +///////////////////////////////////////////////////////////////////////////// +// CLoadPortalFileDialog message handlers + +qboolean CLoadPortalFileDialog::OnInitDialog() +{ + CDialog::OnInitDialog(); + + char fn_drive[_MAX_DRIVE]; + char fn_dir[_MAX_DIR]; + char fn_name[_MAX_FNAME]; + char fn_ext[_MAX_EXT]; + + char *fn = g_IBSPTable.m_pfnGetMapName(); + + _fullpath(portals.fn, fn, _MAX_PATH); + _splitpath(fn, fn_drive, fn_dir, fn_name, fn_ext); + + strcpy(portals.fn, fn_drive); + strcat(portals.fn, fn_dir); + strcat(portals.fn, fn_name); + strcat(portals.fn, ".prt"); + + m_fn_ctrl.SetWindowText(portals.fn); + + m_2d_ctrl.SetCheck(portals.show_2d); + m_3d_ctrl.SetCheck(portals.show_3d); + + return TRUE; // return TRUE unless you set the focus to a control + // EXCEPTION: OCX Property Pages should return FALSE +} + +void CLoadPortalFileDialog::OnOK() +{ + portals.Purge(); + + portals.show_3d = m_3d_ctrl.GetCheck(); + portals.show_2d = m_2d_ctrl.GetCheck(); + + CDialog::OnOK(); +} + +void CLoadPortalFileDialog::OnLoadOther() +{ + CFileDialog dlg(TRUE, "prt", portals.fn, OFN_NOCHANGEDIR | OFN_HIDEREADONLY | OFN_LONGNAMES | OFN_FILEMUSTEXIST, + "Portal files (*.prt)|*.prt|All Files (*.*)|*.*||", NULL); + + dlg.m_ofn.lpstrTitle = "Locate portal file"; + + if(IDOK == dlg.DoModal()) + { + _fullpath(portals.fn, dlg.GetPathName().GetBuffer(1), _MAX_PATH); + m_fn_ctrl.SetWindowText(portals.fn); + } +} + +#endif // GTK_PLUGIN diff --git a/contrib/prtview/LoadPortalFileDialog.h b/contrib/prtview/LoadPortalFileDialog.h new file mode 100644 index 00000000..c11c01ea --- /dev/null +++ b/contrib/prtview/LoadPortalFileDialog.h @@ -0,0 +1,77 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#if !defined(AFX_LOADPORTALFILEDIALOG_H__6BEDE392_1FDC_11D4_BFF7_204C4F4F5020__INCLUDED_) +#define AFX_LOADPORTALFILEDIALOG_H__6BEDE392_1FDC_11D4_BFF7_204C4F4F5020__INCLUDED_ + +#if _MSC_VER >= 1000 +#pragma once +#endif // _MSC_VER >= 1000 +// LoadPortalFileDialog.h : header file +// + +///////////////////////////////////////////////////////////////////////////// +// CLoadPortalFileDialog dialog + +#ifdef GTK_PLUGIN + +int DoLoadPortalFileDialog (); + +#else + +class CLoadPortalFileDialog : public CDialog +{ +// Construction +public: + CLoadPortalFileDialog(CWnd* pParent = NULL); // standard constructor + +// Dialog Data + //{{AFX_DATA(CLoadPortalFileDialog) + enum { IDD = IDD_LOAD }; + CButton m_3d_ctrl; + CButton m_2d_ctrl; + CStatic m_fn_ctrl; + //}}AFX_DATA + + +// Overrides + // ClassWizard generated virtual function overrides + //{{AFX_VIRTUAL(CLoadPortalFileDialog) + protected: + virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support + //}}AFX_VIRTUAL + +// Implementation +protected: + + // Generated message map functions + //{{AFX_MSG(CLoadPortalFileDialog) + virtual qboolean OnInitDialog(); + virtual void OnOK(); + afx_msg void OnLoadOther(); + //}}AFX_MSG + DECLARE_MESSAGE_MAP() +}; + +#endif // GTK_PLUGIN + +//{{AFX_INSERT_LOCATION}} +// Microsoft Developer Studio will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_LOADPORTALFILEDIALOG_H__6BEDE392_1FDC_11D4_BFF7_204C4F4F5020__INCLUDED_) diff --git a/contrib/prtview/PrtView.aps b/contrib/prtview/PrtView.aps new file mode 100644 index 00000000..d86f0607 Binary files /dev/null and b/contrib/prtview/PrtView.aps differ diff --git a/contrib/prtview/PrtView.def b/contrib/prtview/PrtView.def new file mode 100644 index 00000000..4b693944 --- /dev/null +++ b/contrib/prtview/PrtView.def @@ -0,0 +1,8 @@ +; PrtView.def : Declares the module parameters for the DLL. + +LIBRARY "PrtView" +; DESCRIPTION 'PrtView Windows Dynamic Link Library' + +EXPORTS + ; Explicit exports can go here + Synapse_EnumerateInterfaces @1 diff --git a/contrib/prtview/PrtView.rc b/contrib/prtview/PrtView.rc new file mode 100644 index 00000000..d876753a --- /dev/null +++ b/contrib/prtview/PrtView.rc @@ -0,0 +1,264 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "#define _AFX_NO_SPLITTER_RESOURCES\r\n" + "#define _AFX_NO_OLE_RESOURCES\r\n" + "#define _AFX_NO_TRACKER_RESOURCES\r\n" + "#define _AFX_NO_PROPERTY_RESOURCES\r\n" + "\r\n" + "#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU)\r\n" + "#ifdef _WIN32\r\n" + "LANGUAGE 9, 1\r\n" + "#pragma code_page(1252)\r\n" + "#endif\r\n" + "#include ""res\\PrtView.rc2"" // non-Microsoft Visual C++ edited resources\r\n" + "#include ""afxres.rc"" // Standard components\r\n" + "#endif\0" +END + +#endif // APSTUDIO_INVOKED + + +#ifndef _MAC +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 1,0,0,0 + PRODUCTVERSION 0,0,0,0 + FILEFLAGSMASK 0x3fL +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "\0" + VALUE "CompanyName", "\0" + VALUE "FileDescription", "Q3Radiant Portal Viewer\0" + VALUE "FileVersion", "1.000\0" + VALUE "InternalName", "PrtView\0" + VALUE "LegalCopyright", "GNU Copyleft (C) 2000\0" + VALUE "LegalTrademarks", "\0" + VALUE "OriginalFilename", "PrtView.DLL\0" + VALUE "PrivateBuild", "\0" + VALUE "ProductName", "Q3Radiant Portal Viewer\0" + VALUE "ProductVersion", "1.000\0" + VALUE "SpecialBuild", "\0" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // !_MAC + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ABOUT DIALOG DISCARDABLE 0, 0, 186, 52 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "About Portal Viewer" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,129,16,50,14 + LTEXT "Version 1.000\r\rWritten by Geoffrey DeWan\rgdewan@prairienet.org", + IDC_STATIC,7,7,116,38 +END + +IDD_LOAD DIALOGEX 0, 0, 224, 69 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Load .prt" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,167,48,50,14 + PUSHBUTTON "Change",IDC_LOAD_OTHER,167,22,50,14 + CONTROL "Show 3D",IDC_LOAD_3D,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,7,23,52,13 + CONTROL "Show 2D",IDC_LOAD_2D,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,67,23,61,13 + PUSHBUTTON "Cancel",IDCANCEL,113,48,50,14 + LTEXT "",IDC_LOAD_FILE_NAME,7,7,209,12,SS_CENTERIMAGE, + WS_EX_CLIENTEDGE +END + +IDD_CONFIG DIALOG DISCARDABLE 0, 0, 262, 260 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Portal Viewer Configuration" +FONT 8, "MS Sans Serif" +BEGIN + DEFPUSHBUTTON "OK",IDOK,205,239,50,14 + GROUPBOX "3D View",IDC_STATIC,7,7,248,149 + SCROLLBAR IDC_SCROLL_3D_WIDTH,15,20,144,10 + LTEXT "-",IDC_3D_WIDTH,167,20,82,10,SS_CENTERIMAGE + PUSHBUTTON "Color",IDC_COLOR_3D,15,41,50,14 + CONTROL "Anti-Alias (May not work on some video cards)", + IDC_ANTI_ALIAS_3D,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 81,38,174,17 + PUSHBUTTON "Depth Color",IDC_COLOR_FOG,15,60,50,14 + CONTROL "Depth Cue",IDC_FOG,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,81,61,57,13 + CONTROL "Lines",IDC_LINES,"Button",BS_AUTO3STATE | WS_TABSTOP, + 140,61,49,13 + CONTROL "Polygons",IDC_POLY,"Button",BS_AUTO3STATE | WS_TABSTOP, + 206,61,49,13 + COMBOBOX IDC_ZBUFFER,15,85,231,109,CBS_DROPDOWNLIST | WS_TABSTOP + SCROLLBAR IDC_SCROLL_3D_TRANS,15,105,128,10 + LTEXT "-",IDC_3D_TRANS,152,105,95,10,SS_CENTERIMAGE + CONTROL "Show",IDC_CONFIG_3D,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,15,137,52,13 + GROUPBOX "2D View",IDC_STATIC,7,158,248,72 + SCROLLBAR IDC_SCROLL_2D_WIDTH,15,172,144,10 + LTEXT "-",IDC_2D_WIDTH,166,172,82,10,SS_CENTERIMAGE + PUSHBUTTON "Color",IDC_COLOR_2D,15,190,50,14 + CONTROL "Anti-Alias (May not work on some video cards)", + IDC_ANTI_ALIAS_2D,"Button",BS_AUTOCHECKBOX | WS_TABSTOP, + 81,193,174,13 + CONTROL "Show",IDC_CONFIG_2D,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,15,212,61,13 + SCROLLBAR IDC_SCROLL_CUBIC,15,122,128,10 + LTEXT "-",IDC_CUBIC,152,122,95,10,SS_CENTERIMAGE + CONTROL "Portal cubic clipper",IDC_CLIP,"Button",BS_AUTOCHECKBOX | + WS_TABSTOP,147,137,52,13 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_ABOUT, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 179 + TOPMARGIN, 7 + BOTTOMMARGIN, 45 + END + + IDD_LOAD, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 217 + TOPMARGIN, 7 + BOTTOMMARGIN, 62 + END + + IDD_CONFIG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 255 + VERTGUIDE, 15 + TOPMARGIN, 7 + BOTTOMMARGIN, 253 + HORZGUIDE, 21 + HORZGUIDE, 31 + END +END +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog Info +// + +IDD_CONFIG DLGINIT +BEGIN + IDC_ZBUFFER, 0x403, 62, 0 +0x2d5a, 0x7542, 0x6666, 0x7265, 0x5420, 0x7365, 0x2074, 0x6e61, 0x2064, +0x7257, 0x7469, 0x2065, 0x7228, 0x6365, 0x6d6f, 0x656d, 0x646e, 0x6620, +0x726f, 0x7320, 0x6c6f, 0x6469, 0x2020, 0x726f, 0x6e20, 0x206f, 0x6f70, +0x796c, 0x6f67, 0x736e, 0x0029, + IDC_ZBUFFER, 0x403, 56, 0 +0x2d5a, 0x7542, 0x6666, 0x7265, 0x5420, 0x7365, 0x2074, 0x6e4f, 0x796c, +0x2820, 0x6572, 0x6f63, 0x6d6d, 0x6e65, 0x2064, 0x6f66, 0x2072, 0x7274, +0x6e61, 0x7073, 0x7261, 0x6e65, 0x2074, 0x6f70, 0x796c, 0x6f67, 0x736e, +0x0029, + IDC_ZBUFFER, 0x403, 13, 0 +0x2d5a, 0x7542, 0x6666, 0x7265, 0x4f20, 0x6666, "\000" + 0 +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// +#define _AFX_NO_SPLITTER_RESOURCES +#define _AFX_NO_OLE_RESOURCES +#define _AFX_NO_TRACKER_RESOURCES +#define _AFX_NO_PROPERTY_RESOURCES + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE 9, 1 +#pragma code_page(1252) +#endif +#include "res\PrtView.rc2" // non-Microsoft Visual C++ edited resources +#include "afxres.rc" // Standard components +#endif +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/contrib/prtview/PrtView.txt b/contrib/prtview/PrtView.txt new file mode 100644 index 00000000..fba9508d --- /dev/null +++ b/contrib/prtview/PrtView.txt @@ -0,0 +1,12 @@ +Put PrtView.dll in the Q3Radiant plugins directory. + +This program is pretty self explanitary, but point needs to +be mentioned. In the configuration menu for 3D view options, +the lines and polygons flags are tri-state. In the third state, +the lines or polygons will only be drawn if the have the +hint flag set. Older version of q3map will not set this flag +and the hint shader may have to be modified to set it. As of +this writing, I do not know all the details. + +Geoffrey DeWan +gdewan@prairienet.org \ No newline at end of file diff --git a/contrib/prtview/PrtView.vcproj b/contrib/prtview/PrtView.vcproj new file mode 100644 index 00000000..bfb7567d --- /dev/null +++ b/contrib/prtview/PrtView.vcproj @@ -0,0 +1,103 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/contrib/prtview/gtkdlgs.cpp b/contrib/prtview/gtkdlgs.cpp new file mode 100644 index 00000000..d19dd39b --- /dev/null +++ b/contrib/prtview/gtkdlgs.cpp @@ -0,0 +1,732 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// +// PrtView dialogs done with GTK+ +// + +#include +#include "stdafx.h" + +// ============================================================================= +// Static functions + +static void dialog_button_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop, *ret; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + ret = (int*)g_object_get_data (G_OBJECT (parent), "ret"); + + *loop = 0; + *ret = (int)data; +} + +static gint dialog_delete_callback (GtkWidget *widget, GdkEvent* event, gpointer data) +{ + int *loop; + + gtk_widget_hide (widget); + loop = (int*)g_object_get_data (G_OBJECT (widget), "loop"); + *loop = 0; + + return TRUE; +} + +static void file_sel_callback (GtkWidget *widget, gpointer data) +{ + GtkWidget *parent; + int *loop; + char **filename; + + parent = gtk_widget_get_toplevel (widget); + loop = (int*)g_object_get_data (G_OBJECT (parent), "loop"); + filename = (char**)g_object_get_data (G_OBJECT (parent), "filename"); + + *loop = 0; + if ((int)data == IDOK) + *filename = g_strdup (gtk_file_selection_get_filename (GTK_FILE_SELECTION (parent))); +} + +static void change_clicked (GtkWidget *widget, gpointer data) +{ + GtkWidget* file_sel; + char* filename = NULL; + int loop = 1; + + file_sel = gtk_file_selection_new ("Locate portal (.prt) file"); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->ok_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDOK)); + gtk_signal_connect (GTK_OBJECT (GTK_FILE_SELECTION (file_sel)->cancel_button), "clicked", + GTK_SIGNAL_FUNC (file_sel_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_signal_connect (GTK_OBJECT (file_sel), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_file_selection_hide_fileop_buttons (GTK_FILE_SELECTION (file_sel)); + + g_object_set_data (G_OBJECT (file_sel), "loop", &loop); + g_object_set_data (G_OBJECT (file_sel), "filename", &filename); + gtk_file_selection_set_filename (GTK_FILE_SELECTION (file_sel), portals.fn); + + gtk_grab_add (file_sel); + gtk_widget_show (file_sel); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (file_sel); + gtk_widget_destroy (file_sel); + + if (filename != NULL) + { + strcpy (portals.fn, filename); + gtk_entry_set_text (GTK_ENTRY (data), filename); + g_free (filename); + } +} + +// ============================================================================= +// LoadPortalFile dialog + +int DoLoadPortalFileDialog () +{ + GtkWidget *dlg, *vbox, *hbox, *button, *entry, *check2d, *check3d; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Load .prt"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + entry = gtk_entry_new (); + gtk_widget_show (entry); + gtk_entry_set_editable (GTK_ENTRY (entry), FALSE); + gtk_box_pack_start (GTK_BOX (vbox), entry, FALSE, FALSE, 0); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + check3d = gtk_check_button_new_with_label ("Show 3D"); + gtk_widget_show (check3d); + gtk_box_pack_start (GTK_BOX (hbox), check3d, FALSE, FALSE, 0); + + check2d = gtk_check_button_new_with_label ("Show 2D"); + gtk_widget_show (check2d); + gtk_box_pack_start (GTK_BOX (hbox), check2d, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Change"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (change_clicked), entry); + gtk_widget_set_usize (button, 60, -2); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("Cancel"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + gtk_widget_set_usize (button, 60, -2); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + char *fn = g_IBSPTable.m_pfnGetMapName(); + strcpy (portals.fn, fn); + fn = strrchr (portals.fn, '.'); + if (fn != NULL) + { + *fn = '\0'; + strcat (portals.fn, ".prt"); + } + + gtk_entry_set_text (GTK_ENTRY (entry), portals.fn); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check2d), portals.show_2d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check3d), portals.show_3d); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + if (ret == IDOK) + { + portals.Purge(); + + portals.show_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check3d)); + portals.show_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (check2d)); + } + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + return ret; +} + +// ============================================================================= +// About dialog + +void DoAboutDlg () +{ + GtkWidget *dlg, *hbox, *vbox, *button, *label; + int loop = 1, ret = IDCANCEL; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "About Portal Viewer"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + hbox = gtk_hbox_new (FALSE, 10); + gtk_widget_show (hbox); + gtk_container_add (GTK_CONTAINER (dlg), hbox); + gtk_container_set_border_width (GTK_CONTAINER (hbox), 10); + + label = gtk_label_new ("Version 1.000\n\n" + "Gtk port by Leonardo Zide\nleo@lokigames.com\n\n" + "Written by Geoffrey DeWan\ngdewan@prairienet.org"); + gtk_widget_show (label); + gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0); + gtk_label_set_justify (GTK_LABEL (label), GTK_JUSTIFY_LEFT); + + vbox = gtk_vbox_new (FALSE, 0); + gtk_widget_show (vbox); + gtk_box_pack_start (GTK_BOX (hbox), vbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} + +// ============================================================================= +// Config dialog + +static int DoColor (COLORREF *c) +{ + GtkWidget* dlg; + double clr[3]; + int loop = 1, ret = IDCANCEL; + + clr[0] = ((double)GetRValue (*c)) / 255.0; + clr[1] = ((double)GetGValue (*c)) / 255.0; + clr[2] = ((double)GetBValue (*c)) / 255.0; + + dlg = gtk_color_selection_dialog_new ("Choose Color"); + gtk_color_selection_set_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->ok_button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_signal_connect (GTK_OBJECT (GTK_COLOR_SELECTION_DIALOG (dlg)->cancel_button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDCANCEL)); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + gtk_widget_show(dlg); + gtk_grab_add(dlg); + + while (loop) + gtk_main_iteration (); + + gtk_color_selection_get_color (GTK_COLOR_SELECTION (GTK_COLOR_SELECTION_DIALOG (dlg)->colorsel), clr); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); + + if (ret == IDOK) + { + *c = RGB (clr[0]*255, clr[1]*255, clr[2]*255); + } + + return ret; +} + +static void Set2DText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Line Width = %6.3f", portals.width_2d * 0.5f); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void Set3DText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Line Width = %6.3f", portals.width_3d * 0.5f); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void Set3DTransText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Polygon transparency = %d%%", (int)portals.trans_3d); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void SetClipText (GtkWidget* label) +{ + char s[40]; + + sprintf(s, "Cubic clip range = %d", (int)portals.clip_range * 64); + + gtk_label_set_text (GTK_LABEL (label), s); +} + +static void OnScroll2d (GtkAdjustment *adj, gpointer data) +{ + portals.width_2d = adj->value; + Set2DText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +static void OnScroll3d (GtkAdjustment *adj, gpointer data) +{ + portals.width_3d = adj->value; + Set3DText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnScrollTrans (GtkAdjustment *adj, gpointer data) +{ + portals.trans_3d = adj->value; + Set3DTransText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnScrollClip (GtkAdjustment *adj, gpointer data) +{ + portals.clip_range = adj->value; + SetClipText (GTK_WIDGET (data)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnAntiAlias2d (GtkWidget *widget, gpointer data) +{ + portals.aa_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +static void OnConfig2d (GtkWidget *widget, gpointer data) +{ + portals.show_2d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); +} + +static void OnColor2d (GtkWidget *widget, gpointer data) +{ + if (DoColor (&portals.color_2d) == IDOK) + { + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_2D); + } +} + +static void OnConfig3d (GtkWidget *widget, gpointer data) +{ + portals.show_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + + +static void OnAntiAlias3d (GtkWidget *widget, gpointer data) +{ + portals.aa_3d = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnColor3d (GtkWidget *widget, gpointer data) +{ + if (DoColor (&portals.color_3d) == IDOK) + { + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +static void OnColorFog (GtkWidget *widget, gpointer data) +{ + if (DoColor (&portals.color_fog) == IDOK) + { + portals.FixColors(); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); + } +} + +static void OnFog (GtkWidget *widget, gpointer data) +{ + portals.fog = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnSelchangeZbuffer (GtkWidget *widget, gpointer data) +{ + portals.zbuffer = GPOINTER_TO_INT (data); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnPoly (GtkWidget *widget, gpointer data) +{ + portals.polygons = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnLines (GtkWidget *widget, gpointer data) +{ + portals.lines = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +static void OnClip (GtkWidget *widget, gpointer data) +{ + portals.clip = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget)); + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_3D); +} + +void DoConfigDialog () +{ + GtkWidget *dlg, *hbox, *vbox, *vbox2, *button, *table, *frame; + GtkWidget *lw3slider, *lw3label, *lw2slider, *lw2label, *zlist, *menu, *item; + GtkWidget *aa2check, *aa3check, *depthcheck, *linescheck, *polyscheck; + GtkWidget *transslider, *translabel, *clipslider, *cliplabel; + GtkWidget *show2check, *show3check, *portalcheck; + int loop = 1, ret = IDCANCEL; + GtkObject *adj; + + dlg = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (dlg), "Portal Viewer Configuration"); + gtk_signal_connect (GTK_OBJECT (dlg), "delete_event", + GTK_SIGNAL_FUNC (dialog_delete_callback), NULL); + gtk_signal_connect (GTK_OBJECT (dlg), "destroy", + GTK_SIGNAL_FUNC (gtk_widget_destroy), NULL); + g_object_set_data (G_OBJECT (dlg), "loop", &loop); + g_object_set_data (G_OBJECT (dlg), "ret", &ret); + + vbox = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox); + gtk_container_add (GTK_CONTAINER (dlg), vbox); + gtk_container_set_border_width (GTK_CONTAINER (vbox), 5); + + frame = gtk_frame_new ("3D View"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, TRUE, 0); + + adj = gtk_adjustment_new (portals.width_3d, 2, 40, 1, 1, 1); + lw3slider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (lw3slider); + gtk_box_pack_start (GTK_BOX (hbox), lw3slider, TRUE, TRUE, 0); + gtk_scale_set_draw_value (GTK_SCALE (lw3slider), FALSE); + + lw3label = gtk_label_new (""); + gtk_widget_show (lw3label); + gtk_box_pack_start (GTK_BOX (hbox), lw3label, FALSE, TRUE, 0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScroll3d), lw3label); + + table = gtk_table_new (2, 4, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + button = gtk_button_new_with_label ("Color"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColor3d), NULL); + + button = gtk_button_new_with_label ("Depth Color"); + gtk_widget_show (button); + gtk_table_attach (GTK_TABLE (table), button, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColorFog), NULL); + + aa3check = gtk_check_button_new_with_label ("Anti-Alias (May not work on some video cards)"); + gtk_widget_show (aa3check); + gtk_table_attach (GTK_TABLE (table), aa3check, 1, 4, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (aa3check), "toggled", GTK_SIGNAL_FUNC (OnAntiAlias3d), NULL); + + depthcheck = gtk_check_button_new_with_label ("Depth Cue"); + gtk_widget_show (depthcheck); + gtk_table_attach (GTK_TABLE (table), depthcheck, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (depthcheck), "toggled", GTK_SIGNAL_FUNC (OnFog), NULL); + + linescheck = gtk_check_button_new_with_label ("Lines"); + gtk_widget_show (linescheck); + gtk_table_attach (GTK_TABLE (table), linescheck, 2, 3, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (linescheck), "toggled", GTK_SIGNAL_FUNC (OnLines), NULL); + + polyscheck = gtk_check_button_new_with_label ("Polygons"); + gtk_widget_show (polyscheck); + gtk_table_attach (GTK_TABLE (table), polyscheck, 3, 4, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_signal_connect (GTK_OBJECT (polyscheck), "toggled", GTK_SIGNAL_FUNC (OnPoly), NULL); + + zlist = gtk_option_menu_new (); + gtk_widget_show (zlist); + gtk_box_pack_start (GTK_BOX (vbox2), zlist, TRUE, FALSE, 0); + + menu = gtk_menu_new (); + gtk_widget_show (menu); + gtk_option_menu_set_menu (GTK_OPTION_MENU (zlist), menu); + + item = gtk_menu_item_new_with_label ("Z-Buffer Test and Write (recommended for solid or no polygons)"); + gtk_widget_show (item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (0)); + gtk_menu_append (GTK_MENU (menu), item); + + item = gtk_menu_item_new_with_label ("Z-Buffer Test Only (recommended for transparent polygons)"); + gtk_widget_show (item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (1)); + gtk_menu_append (GTK_MENU (menu), item); + + item = gtk_menu_item_new_with_label ("Z-Buffer Off"); + gtk_widget_show (item); + gtk_signal_connect (GTK_OBJECT (item), "activate", + GTK_SIGNAL_FUNC (OnSelchangeZbuffer), GINT_TO_POINTER (2)); + gtk_menu_append (GTK_MENU (menu), item); + + table = gtk_table_new (2, 2, FALSE); + gtk_widget_show (table); + gtk_box_pack_start (GTK_BOX (vbox2), table, TRUE, TRUE, 0); + gtk_table_set_row_spacings (GTK_TABLE (table), 5); + gtk_table_set_col_spacings (GTK_TABLE (table), 5); + + adj = gtk_adjustment_new (portals.trans_3d, 0, 100, 1, 1, 1); + transslider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (transslider); + gtk_table_attach (GTK_TABLE (table), transslider, 0, 1, 0, 1, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_scale_set_draw_value (GTK_SCALE (transslider), FALSE); + + translabel = gtk_label_new (""); + gtk_widget_show (translabel); + gtk_table_attach (GTK_TABLE (table), translabel, 1, 2, 0, 1, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (translabel), 0.0, 0.0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScrollTrans), translabel); + + adj = gtk_adjustment_new (portals.clip_range, 1, 128, 1, 1, 1); + clipslider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (clipslider); + gtk_table_attach (GTK_TABLE (table), clipslider, 0, 1, 1, 2, + (GtkAttachOptions) (GTK_EXPAND|GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_scale_set_draw_value (GTK_SCALE (clipslider), FALSE); + + cliplabel = gtk_label_new (""); + gtk_widget_show (cliplabel); + gtk_table_attach (GTK_TABLE (table), cliplabel, 1, 2, 1, 2, + (GtkAttachOptions) (GTK_FILL), + (GtkAttachOptions) (0), 0, 0); + gtk_misc_set_alignment (GTK_MISC (cliplabel), 0.0, 0.0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScrollClip), cliplabel); + + hbox = gtk_hbox_new (TRUE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + show3check = gtk_check_button_new_with_label ("Show"); + gtk_widget_show (show3check); + gtk_box_pack_start (GTK_BOX (hbox), show3check, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (show3check), "toggled", GTK_SIGNAL_FUNC (OnConfig3d), NULL); + + portalcheck = gtk_check_button_new_with_label ("Portal cubic clipper"); + gtk_widget_show (portalcheck); + gtk_box_pack_start (GTK_BOX (hbox), portalcheck, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (portalcheck), "toggled", GTK_SIGNAL_FUNC (OnClip), NULL); + + frame = gtk_frame_new ("2D View"); + gtk_widget_show (frame); + gtk_box_pack_start (GTK_BOX (vbox), frame, TRUE, TRUE, 0); + + vbox2 = gtk_vbox_new (FALSE, 5); + gtk_widget_show (vbox2); + gtk_container_add (GTK_CONTAINER (frame), vbox2); + gtk_container_set_border_width (GTK_CONTAINER (vbox2), 5); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + adj = gtk_adjustment_new (portals.width_2d, 2, 40, 1, 1, 1); + lw2slider = gtk_hscale_new (GTK_ADJUSTMENT (adj)); + gtk_widget_show (lw2slider); + gtk_box_pack_start (GTK_BOX (hbox), lw2slider, TRUE, TRUE, 0); + gtk_scale_set_draw_value (GTK_SCALE (lw2slider), FALSE); + + lw2label = gtk_label_new (""); + gtk_widget_show (lw2label); + gtk_box_pack_start (GTK_BOX (hbox), lw2label, FALSE, TRUE, 0); + gtk_signal_connect (adj, "value_changed", GTK_SIGNAL_FUNC (OnScroll2d), lw2label); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + button = gtk_button_new_with_label ("Color"); + gtk_widget_show (button); + gtk_box_pack_start (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", GTK_SIGNAL_FUNC (OnColor2d), NULL); + gtk_widget_set_usize (button, 60, -2); + + aa2check = gtk_check_button_new_with_label ("Anti-Alias (May not work on some video cards)"); + gtk_widget_show (aa2check); + gtk_box_pack_start (GTK_BOX (hbox), aa2check, TRUE, TRUE, 0); + gtk_signal_connect (GTK_OBJECT (aa2check), "toggled", GTK_SIGNAL_FUNC (OnAntiAlias2d), NULL); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox2), hbox, TRUE, FALSE, 0); + + show2check = gtk_check_button_new_with_label ("Show"); + gtk_widget_show (show2check); + gtk_box_pack_start (GTK_BOX (hbox), show2check, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (show2check), "toggled", GTK_SIGNAL_FUNC (OnConfig2d), NULL); + + hbox = gtk_hbox_new (FALSE, 5); + gtk_widget_show (hbox); + gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0); + + button = gtk_button_new_with_label ("OK"); + gtk_widget_show (button); + gtk_box_pack_end (GTK_BOX (hbox), button, FALSE, FALSE, 0); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (dialog_button_callback), GINT_TO_POINTER (IDOK)); + gtk_widget_set_usize (button, 60, -2); + + // initialize dialog + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show2check), portals.show_2d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aa2check), portals.aa_2d); + Set2DText (lw2label); + + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (show3check), portals.show_3d); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (depthcheck), portals.fog); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (polyscheck), portals.polygons); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (linescheck), portals.lines); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (aa3check), portals.aa_3d); + gtk_option_menu_set_history (GTK_OPTION_MENU (zlist), portals.zbuffer); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (portalcheck), portals.clip); + + Set3DText (lw3label); + Set3DTransText (translabel); + SetClipText (cliplabel); + + gtk_grab_add (dlg); + gtk_widget_show (dlg); + + while (loop) + gtk_main_iteration (); + + gtk_grab_remove (dlg); + gtk_widget_destroy (dlg); +} diff --git a/contrib/prtview/gtkdlgs.h b/contrib/prtview/gtkdlgs.h new file mode 100644 index 00000000..afa3ea74 --- /dev/null +++ b/contrib/prtview/gtkdlgs.h @@ -0,0 +1,27 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _GTKDLGS_H_ +#define _GTKDLGS_H_ + +int DoLoadPortalFileDialog (); +void DoAboutDlg (); +void DoConfigDialog (); + +#endif // _GTKDLGS_H_ diff --git a/contrib/prtview/portals.cpp b/contrib/prtview/portals.cpp new file mode 100644 index 00000000..378bb85d --- /dev/null +++ b/contrib/prtview/portals.cpp @@ -0,0 +1,802 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#include "stdafx.h" +#include +#include +#ifndef __APPLE__ +#include +#endif +#include + +#define LINE_BUF 1000 + +CPortals portals; +CPortalsRender render; + +int compare( const void *arg1, const void *arg2 ) +{ + + if(portals.portal[*((int *)arg1)].dist > portals.portal[*((int *)arg2)].dist) + return -1; + else if(portals.portal[*((int *)arg1)].dist < portals.portal[*((int *)arg2)].dist) + return 1; + + return 0; +} + + +CBspPortal::CBspPortal() +{ + memset(this, 0, sizeof(CBspPortal)); +} + +CBspPortal::~CBspPortal() +{ + delete[] point; + delete[] inner_point; +} + +qboolean CBspPortal::Build(char *def) +{ + char *c = def; + unsigned int n; + int dummy1, dummy2; + int res_cnt, i; + + if(portals.hint_flags) + { + res_cnt = sscanf(def, "%u %d %d %d", &point_count, &dummy1, &dummy2, (int *)&hint); + } + else + { + sscanf(def, "%u", &point_count); + hint = FALSE; + } + + if(point_count < 3 || (portals.hint_flags && res_cnt < 4)) + return FALSE; + + point = new CBspPoint[point_count]; + inner_point = new CBspPoint[point_count]; + + for(n = 0; n < point_count; n++) + { + for(; *c != 0 && *c != '('; c++); + + if(*c == 0) + return FALSE; + + c++; + + sscanf(c, "%f %f %f", point[n].p, point[n].p+1, point[n].p+2); + + center.p[0] += point[n].p[0]; + center.p[1] += point[n].p[1]; + center.p[2] += point[n].p[2]; + + if(n == 0) + { + for(i = 0; i < 3; i++) + { + min[i] = point[n].p[i]; + max[i] = point[n].p[i]; + } + } + else + { + for(i = 0; i < 3; i++) + { + if(min[i] > point[n].p[i]) + min[i] = point[n].p[i]; + if(max[i] < point[n].p[i]) + max[i] = point[n].p[i]; + } + } + } + + center.p[0] /= (float)point_count; + center.p[1] /= (float)point_count; + center.p[2] /= (float)point_count; + + for(n = 0; n < point_count; n++) + { + inner_point[n].p[0] = (0.01f * center.p[0]) + (0.99f * point[n].p[0]); + inner_point[n].p[1] = (0.01f * center.p[1]) + (0.99f * point[n].p[1]); + inner_point[n].p[2] = (0.01f * center.p[2]) + (0.99f * point[n].p[2]); + } + + fp_color_random[0] = (float)(rand() & 0xff) / 255.0f; + fp_color_random[1] = (float)(rand() & 0xff) / 255.0f; + fp_color_random[2] = (float)(rand() & 0xff) / 255.0f; + fp_color_random[3] = 1.0f; + + return TRUE; +} + +CPortals::CPortals() +{ + memset(this, 0, sizeof(CPortals)); +} + +CPortals::~CPortals() +{ + Purge(); +} + +void CPortals::Purge() +{ + delete[] portal; + delete[] portal_sort; + portal = NULL; + portal_sort = NULL; + portal_count = 0; + + /* + delete[] node; + node = NULL; + node_count = 0; + */ +} + +void CPortals::Load() +{ + char buf[LINE_BUF+1]; + + memset(buf, 0, LINE_BUF + 1); + + Purge(); + + Sys_Printf(MSG_PREFIX "Loading portal file %s.\n", fn); + + FILE *in; + + in = fopen(fn, "rt"); + + if(in == NULL) + { + Sys_Printf(" ERROR - could not open file.\n"); + + return; + } + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + if(strncmp("PRT1", buf, 4) != 0) + { + fclose(in); + + Sys_Printf(" ERROR - File header indicates wrong file type (should be \"PRT1\").\n"); + + return; + } + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + sscanf(buf, "%u", &node_count); +/* + if(node_count > 0xFFFF) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - Extreme number of nodes, aborting.\n"); + + return; + } + */ + + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + node_count = 0; + + Sys_Printf(" ERROR - File ended prematurely.\n"); + + return; + } + + sscanf(buf, "%u", &portal_count); + + if(portal_count > 0xFFFF) + { + fclose(in); + + portal_count = 0; + node_count = 0; + + Sys_Printf(" ERROR - Extreme number of portals, aborting.\n"); + + return; + } + + if(portal_count < 0) + { + fclose(in); + + portal_count = 0; + node_count = 0; + + Sys_Printf(" ERROR - number of portals equals 0, aborting.\n"); + + return; + } + +// node = new CBspNode[node_count]; + portal = new CBspPortal[portal_count]; + portal_sort = new int[portal_count]; + + unsigned int n; + qboolean first = TRUE; + unsigned test_vals_1, test_vals_2; + + hint_flags = FALSE; + + for(n = 0; n < portal_count; ) + { + if(!fgets(buf, LINE_BUF, in)) + { + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Could not find information for portal number %d of %d.\n", n + 1, portal_count); + + return; + } + + if(!portal[n].Build(buf)) + { + if(first && sscanf(buf, "%d %d", &test_vals_1, &test_vals_2) == 1) // skip additional counts of later data, not needed + { + // We can count on hint flags being in the file + hint_flags = TRUE; + continue; + } + + first = FALSE; + + fclose(in); + + Purge(); + + Sys_Printf(" ERROR - Information for portal number %d of %d is not formatted correctly.\n", n + 1, portal_count); + + return; + } + + n++; + } + + fclose(in); + + Sys_Printf(" %u portals read in.\n", node_count, portal_count); +} + +void CPortals::FixColors() +{ + fp_color_2d[0] = (float)GetRValue(color_2d) / 255.0f; + fp_color_2d[1] = (float)GetGValue(color_2d) / 255.0f; + fp_color_2d[2] = (float)GetBValue(color_2d) / 255.0f; + fp_color_2d[3] = 1.0f; + + fp_color_3d[0] = (float)GetRValue(color_3d) / 255.0f; + fp_color_3d[1] = (float)GetGValue(color_3d) / 255.0f; + fp_color_3d[2] = (float)GetBValue(color_3d) / 255.0f; + fp_color_3d[3] = 1.0f; + + fp_color_fog[0] = 0.0f;//(float)GetRValue(color_fog) / 255.0f; + fp_color_fog[1] = 0.0f;//(float)GetGValue(color_fog) / 255.0f; + fp_color_fog[2] = 0.0f;//(float)GetBValue(color_fog) / 255.0f; + fp_color_fog[3] = 1.0f; +} + +CPortalsRender::CPortalsRender() +{ + refCount = 1; +} + +CPortalsRender::~CPortalsRender() +{ +} + +void CPortalsRender::Register() +{ + g_QglTable.m_pfnHookGL2DWindow( this ); + g_QglTable.m_pfnHookGL3DWindow( this ); +} + +void CPortalsRender::Draw2D( VIEWTYPE vt ) +{ + if(!portals.show_2d || portals.portal_count < 1) + return; + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + if(portals.aa_2d) + { + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH); + } + else + { + g_QglTable.m_pfn_qglDisable(GL_BLEND); + g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH); + } + + switch(vt) + { + case XY: + break; + case XZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + break; + case YZ: + g_QglTable.m_pfn_qglRotatef(270.0f, 1.0f, 0.0f, 0.0f); + g_QglTable.m_pfn_qglRotatef(270.0f, 0.0f, 0.0f, 1.0f); + break; + } + + g_QglTable.m_pfn_qglLineWidth(portals.width_2d * 0.5f); + + g_QglTable.m_pfn_qglColor4fv(portals.fp_color_2d); + + unsigned int n, p; + + for(n = 0; n < portals.portal_count; n++) + { + g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); + + for(p = 0; p < portals.portal[n].point_count; p++) + g_QglTable.m_pfn_qglVertex3fv(portals.portal[n].point[p].p); + + g_QglTable.m_pfn_qglEnd(); + } + + g_QglTable.m_pfn_qglPopAttrib(); +} + +/* + * Transform a point (column vector) by a 4x4 matrix. I.e. out = m * in + * Input: m - the 4x4 matrix + * in - the 4x1 vector + * Output: out - the resulting 4x1 vector. + */ +static void transform_point( GLdouble out[4], const GLdouble m[16], + const GLdouble in[4] ) +{ +#define M(row,col) m[col*4+row] + out[0] = M(0,0) * in[0] + M(0,1) * in[1] + M(0,2) * in[2] + M(0,3) * in[3]; + out[1] = M(1,0) * in[0] + M(1,1) * in[1] + M(1,2) * in[2] + M(1,3) * in[3]; + out[2] = M(2,0) * in[0] + M(2,1) * in[1] + M(2,2) * in[2] + M(2,3) * in[3]; + out[3] = M(3,0) * in[0] + M(3,1) * in[1] + M(3,2) * in[2] + M(3,3) * in[3]; +#undef M +} + +#include + + +/* + * Perform a 4x4 matrix multiplication (product = a x b). + * Input: a, b - matrices to multiply + * Output: product - product of a and b + */ +static void matmul( GLdouble *product, const GLdouble *a, const GLdouble *b ) +{ + /* This matmul was contributed by Thomas Malik */ + GLdouble temp[16]; + GLint i; + +#define A(row,col) a[(col<<2)+row] +#define B(row,col) b[(col<<2)+row] +#define T(row,col) temp[(col<<2)+row] + + /* i-te Zeile */ + for (i = 0; i < 4; i++) + { + T(i, 0) = A(i, 0) * B(0, 0) + A(i, 1) * B(1, 0) + A(i, 2) * B(2, 0) + A(i, 3) * B(3, 0); + T(i, 1) = A(i, 0) * B(0, 1) + A(i, 1) * B(1, 1) + A(i, 2) * B(2, 1) + A(i, 3) * B(3, 1); + T(i, 2) = A(i, 0) * B(0, 2) + A(i, 1) * B(1, 2) + A(i, 2) * B(2, 2) + A(i, 3) * B(3, 2); + T(i, 3) = A(i, 0) * B(0, 3) + A(i, 1) * B(1, 3) + A(i, 2) * B(2, 3) + A(i, 3) * B(3, 3); + } + +#undef A +#undef B +#undef T + memcpy ( product, temp, 16*sizeof(GLdouble) ); +} + + + +/* + * Compute inverse of 4x4 transformation matrix. + * Code contributed by Jacques Leroy jle@star.be + * Return GL_TRUE for success, GL_FALSE for failure (singular matrix) + */ +static GLboolean invert_matrix( const GLdouble *m, GLdouble *out ) +{ +/* NB. OpenGL Matrices are COLUMN major. */ +#define SWAP_ROWS(a, b) { GLdouble *_tmp = a; (a)=(b); (b)=_tmp; } +#define MAT(m,r,c) (m)[(c)*4+(r)] + + GLdouble wtmp[4][8]; + GLdouble m0, m1, m2, m3, s; + GLdouble *r0, *r1, *r2, *r3; + + r0 = wtmp[0], r1 = wtmp[1], r2 = wtmp[2], r3 = wtmp[3]; + + r0[0] = MAT(m,0,0), r0[1] = MAT(m,0,1), + r0[2] = MAT(m,0,2), r0[3] = MAT(m,0,3), + r0[4] = 1.0, r0[5] = r0[6] = r0[7] = 0.0, + + r1[0] = MAT(m,1,0), r1[1] = MAT(m,1,1), + r1[2] = MAT(m,1,2), r1[3] = MAT(m,1,3), + r1[5] = 1.0, r1[4] = r1[6] = r1[7] = 0.0, + + r2[0] = MAT(m,2,0), r2[1] = MAT(m,2,1), + r2[2] = MAT(m,2,2), r2[3] = MAT(m,2,3), + r2[6] = 1.0, r2[4] = r2[5] = r2[7] = 0.0, + + r3[0] = MAT(m,3,0), r3[1] = MAT(m,3,1), + r3[2] = MAT(m,3,2), r3[3] = MAT(m,3,3), + r3[7] = 1.0, r3[4] = r3[5] = r3[6] = 0.0; + + /* choose pivot - or die */ + if (fabs(r3[0])>fabs(r2[0])) SWAP_ROWS(r3, r2); + if (fabs(r2[0])>fabs(r1[0])) SWAP_ROWS(r2, r1); + if (fabs(r1[0])>fabs(r0[0])) SWAP_ROWS(r1, r0); + if (0.0 == r0[0]) return GL_FALSE; + + /* eliminate first variable */ + m1 = r1[0]/r0[0]; m2 = r2[0]/r0[0]; m3 = r3[0]/r0[0]; + s = r0[1]; r1[1] -= m1 * s; r2[1] -= m2 * s; r3[1] -= m3 * s; + s = r0[2]; r1[2] -= m1 * s; r2[2] -= m2 * s; r3[2] -= m3 * s; + s = r0[3]; r1[3] -= m1 * s; r2[3] -= m2 * s; r3[3] -= m3 * s; + s = r0[4]; + if (s != 0.0) { r1[4] -= m1 * s; r2[4] -= m2 * s; r3[4] -= m3 * s; } + s = r0[5]; + if (s != 0.0) { r1[5] -= m1 * s; r2[5] -= m2 * s; r3[5] -= m3 * s; } + s = r0[6]; + if (s != 0.0) { r1[6] -= m1 * s; r2[6] -= m2 * s; r3[6] -= m3 * s; } + s = r0[7]; + if (s != 0.0) { r1[7] -= m1 * s; r2[7] -= m2 * s; r3[7] -= m3 * s; } + + /* choose pivot - or die */ + if (fabs(r3[1])>fabs(r2[1])) SWAP_ROWS(r3, r2); + if (fabs(r2[1])>fabs(r1[1])) SWAP_ROWS(r2, r1); + if (0.0 == r1[1]) return GL_FALSE; + + /* eliminate second variable */ + m2 = r2[1]/r1[1]; m3 = r3[1]/r1[1]; + r2[2] -= m2 * r1[2]; r3[2] -= m3 * r1[2]; + r2[3] -= m2 * r1[3]; r3[3] -= m3 * r1[3]; + s = r1[4]; if (0.0 != s) { r2[4] -= m2 * s; r3[4] -= m3 * s; } + s = r1[5]; if (0.0 != s) { r2[5] -= m2 * s; r3[5] -= m3 * s; } + s = r1[6]; if (0.0 != s) { r2[6] -= m2 * s; r3[6] -= m3 * s; } + s = r1[7]; if (0.0 != s) { r2[7] -= m2 * s; r3[7] -= m3 * s; } + + /* choose pivot - or die */ + if (fabs(r3[2])>fabs(r2[2])) SWAP_ROWS(r3, r2); + if (0.0 == r2[2]) return GL_FALSE; + + /* eliminate third variable */ + m3 = r3[2]/r2[2]; + r3[3] -= m3 * r2[3], r3[4] -= m3 * r2[4], + r3[5] -= m3 * r2[5], r3[6] -= m3 * r2[6], + r3[7] -= m3 * r2[7]; + + /* last check */ + if (0.0 == r3[3]) return GL_FALSE; + + s = 1.0/r3[3]; /* now back substitute row 3 */ + r3[4] *= s; r3[5] *= s; r3[6] *= s; r3[7] *= s; + + m2 = r2[3]; /* now back substitute row 2 */ + s = 1.0/r2[2]; + r2[4] = s * (r2[4] - r3[4] * m2), r2[5] = s * (r2[5] - r3[5] * m2), + r2[6] = s * (r2[6] - r3[6] * m2), r2[7] = s * (r2[7] - r3[7] * m2); + m1 = r1[3]; + r1[4] -= r3[4] * m1, r1[5] -= r3[5] * m1, + r1[6] -= r3[6] * m1, r1[7] -= r3[7] * m1; + m0 = r0[3]; + r0[4] -= r3[4] * m0, r0[5] -= r3[5] * m0, + r0[6] -= r3[6] * m0, r0[7] -= r3[7] * m0; + + m1 = r1[2]; /* now back substitute row 1 */ + s = 1.0/r1[1]; + r1[4] = s * (r1[4] - r2[4] * m1), r1[5] = s * (r1[5] - r2[5] * m1), + r1[6] = s * (r1[6] - r2[6] * m1), r1[7] = s * (r1[7] - r2[7] * m1); + m0 = r0[2]; + r0[4] -= r2[4] * m0, r0[5] -= r2[5] * m0, + r0[6] -= r2[6] * m0, r0[7] -= r2[7] * m0; + + m0 = r0[1]; /* now back substitute row 0 */ + s = 1.0/r0[0]; + r0[4] = s * (r0[4] - r1[4] * m0), r0[5] = s * (r0[5] - r1[5] * m0), + r0[6] = s * (r0[6] - r1[6] * m0), r0[7] = s * (r0[7] - r1[7] * m0); + + MAT(out,0,0) = r0[4]; MAT(out,0,1) = r0[5], + MAT(out,0,2) = r0[6]; MAT(out,0,3) = r0[7], + MAT(out,1,0) = r1[4]; MAT(out,1,1) = r1[5], + MAT(out,1,2) = r1[6]; MAT(out,1,3) = r1[7], + MAT(out,2,0) = r2[4]; MAT(out,2,1) = r2[5], + MAT(out,2,2) = r2[6]; MAT(out,2,3) = r2[7], + MAT(out,3,0) = r3[4]; MAT(out,3,1) = r3[5], + MAT(out,3,2) = r3[6]; MAT(out,3,3) = r3[7]; + + return GL_TRUE; + +#undef MAT +#undef SWAP_ROWS +} + +GLint UnProject(GLdouble winx,GLdouble winy,GLdouble winz, + const GLdouble model[16],const GLdouble proj[16], + const GLint viewport[4], + GLdouble *objx,GLdouble *objy,GLdouble *objz) +{ + /* matrice de transformation */ + GLdouble m[16], A[16]; + GLdouble in[4],out[4]; + + /* transformation coordonnees normalisees entre -1 et 1 */ + in[0]=(winx-viewport[0])*2/viewport[2] - 1.0; + in[1]=(winy-viewport[1])*2/viewport[3] - 1.0; + in[2]=2*winz - 1.0; + in[3]=1.0; + + /* calcul transformation inverse */ + matmul(A,proj,model); + invert_matrix(A,m); + + /* d'ou les coordonnees objets */ + transform_point(out,m,in); + if (out[3]==0.0) + return GL_FALSE; + *objx=out[0]/out[3]; + *objy=out[1]/out[3]; + *objz=out[2]/out[3]; + return GL_TRUE; +} + +void CPortalsRender::Draw3D() +{ + if(!portals.show_3d || portals.portal_count < 1) + return; + + g_QglTable.m_pfn_qglPushAttrib(GL_ALL_ATTRIB_BITS); + + double cam[3]; + double proj_m[16]; + double model_m[16]; + float min_check[3]; + float max_check[3]; + float trans = (100.0f - portals.trans_3d) / 100.0f; + int view[4]; + + g_QglTable.m_pfn_qglGetDoublev(GL_PROJECTION_MATRIX, proj_m); + g_QglTable.m_pfn_qglGetDoublev(GL_MODELVIEW_MATRIX, model_m); + g_QglTable.m_pfn_qglGetIntegerv(GL_VIEWPORT, view); + + UnProject(0.5 * (double)view[2], 0.5 * (double)view[3], 0.0, model_m, proj_m, view, cam, cam+1, cam+2); + + min_check[0] = (float)cam[0] + (portals.clip_range * 64.0f); + min_check[1] = (float)cam[1] + (portals.clip_range * 64.0f); + min_check[2] = (float)cam[2] + (portals.clip_range * 64.0f); + max_check[0] = (float)cam[0] - (portals.clip_range * 64.0f); + max_check[1] = (float)cam[1] - (portals.clip_range * 64.0f); + max_check[2] = (float)cam[2] - (portals.clip_range * 64.0f); + + g_QglTable.m_pfn_qglHint(GL_FOG_HINT, GL_NICEST); + + g_QglTable.m_pfn_qglDisable(GL_CULL_FACE); + + g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); + g_QglTable.m_pfn_qglDisable(GL_POLYGON_SMOOTH); + + g_QglTable.m_pfn_qglPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + g_QglTable.m_pfn_qglShadeModel(GL_SMOOTH); + + g_QglTable.m_pfn_qglEnable(GL_BLEND); + g_QglTable.m_pfn_qglBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + g_QglTable.m_pfn_qglEnable(GL_POLYGON_SMOOTH); + + if(portals.aa_3d) + g_QglTable.m_pfn_qglEnable(GL_LINE_SMOOTH); + else + g_QglTable.m_pfn_qglDisable(GL_LINE_SMOOTH); + + if(portals.fog) + { + g_QglTable.m_pfn_qglEnable(GL_FOG); + + g_QglTable.m_pfn_qglFogi(GL_FOG_MODE, GL_EXP); + g_QglTable.m_pfn_qglFogf(GL_FOG_DENSITY, 0.001f); + g_QglTable.m_pfn_qglFogf(GL_FOG_START, 10.0f); + g_QglTable.m_pfn_qglFogf(GL_FOG_END, 10000.0f); + g_QglTable.m_pfn_qglFogi(GL_FOG_INDEX, 0); + g_QglTable.m_pfn_qglFogfv(GL_FOG_COLOR, portals.fp_color_fog); + } + else + { + g_QglTable.m_pfn_qglDisable(GL_FOG); + } + + switch(portals.zbuffer) + { + case 1: + g_QglTable.m_pfn_qglEnable(GL_DEPTH_TEST); + g_QglTable.m_pfn_qglDepthMask(GL_FALSE); + break; + case 2: + g_QglTable.m_pfn_qglDisable(GL_DEPTH_TEST); + break; + default: + g_QglTable.m_pfn_qglEnable(GL_DEPTH_TEST); + g_QglTable.m_pfn_qglDepthMask(GL_TRUE); + } + + g_QglTable.m_pfn_qglLineWidth(portals.width_3d * 0.5f); + + unsigned int n, p; + + if(portals.polygons) + { + if(portals.zbuffer != 0) + { + float d; + + for(n = 0; n < portals.portal_count; n++) + { + d = (float)cam[0] - portals.portal[n].center.p[0]; + portals.portal[n].dist = d * d; + + d = (float)cam[1] - portals.portal[n].center.p[1]; + portals.portal[n].dist += d * d; + + d = (float)cam[2] - portals.portal[n].center.p[2]; + portals.portal[n].dist += d * d; + + portals.portal_sort[n] = n; + } + + qsort(portals.portal_sort, portals.portal_count, 4, compare); + + for(n = 0; n < portals.portal_count; n++) + { + if(portals.polygons == 2 && !portals.portal[portals.portal_sort[n]].hint) + continue; + + if(portals.clip) + { + if(min_check[0] < portals.portal[portals.portal_sort[n]].min[0]) + continue; + else if(min_check[1] < portals.portal[portals.portal_sort[n]].min[1]) + continue; + else if(min_check[2] < portals.portal[portals.portal_sort[n]].min[2]) + continue; + else if(max_check[0] > portals.portal[portals.portal_sort[n]].max[0]) + continue; + else if(max_check[1] > portals.portal[portals.portal_sort[n]].max[1]) + continue; + else if(max_check[2] > portals.portal[portals.portal_sort[n]].max[2]) + continue; + } + + g_QglTable.m_pfn_qglColor4f(portals.portal[portals.portal_sort[n]].fp_color_random[0], portals.portal[portals.portal_sort[n]].fp_color_random[1], + portals.portal[portals.portal_sort[n]].fp_color_random[2], trans); + + g_QglTable.m_pfn_qglBegin(GL_POLYGON); + + for(p = 0; p < portals.portal[portals.portal_sort[n]].point_count; p++) + g_QglTable.m_pfn_qglVertex3fv(portals.portal[portals.portal_sort[n]].point[p].p); + + g_QglTable.m_pfn_qglEnd(); + } + } + else + { + for(n = 0; n < portals.portal_count; n++) + { + if(portals.polygons == 2 && !portals.portal[n].hint) + continue; + + if(portals.clip) + { + if(min_check[0] < portals.portal[n].min[0]) + continue; + else if(min_check[1] < portals.portal[n].min[1]) + continue; + else if(min_check[2] < portals.portal[n].min[2]) + continue; + else if(max_check[0] > portals.portal[n].max[0]) + continue; + else if(max_check[1] > portals.portal[n].max[1]) + continue; + else if(max_check[2] > portals.portal[n].max[2]) + continue; + } + + g_QglTable.m_pfn_qglColor4f(portals.portal[n].fp_color_random[0], portals.portal[n].fp_color_random[1], + portals.portal[n].fp_color_random[2], trans); + + g_QglTable.m_pfn_qglBegin(GL_POLYGON); + + for(p = 0; p < portals.portal[n].point_count; p++) + g_QglTable.m_pfn_qglVertex3fv(portals.portal[n].point[p].p); + + g_QglTable.m_pfn_qglEnd(); + } + } + } + + if(portals.lines) + { + g_QglTable.m_pfn_qglColor4fv(portals.fp_color_3d); + + for(n = 0; n < portals.portal_count; n++) + { + if(portals.lines == 2 && !portals.portal[n].hint) + continue; + + if(portals.clip) + { + if(min_check[0] < portals.portal[n].min[0]) + continue; + else if(min_check[1] < portals.portal[n].min[1]) + continue; + else if(min_check[2] < portals.portal[n].min[2]) + continue; + else if(max_check[0] > portals.portal[n].max[0]) + continue; + else if(max_check[1] > portals.portal[n].max[1]) + continue; + else if(max_check[2] > portals.portal[n].max[2]) + continue; + } + + g_QglTable.m_pfn_qglBegin(GL_LINE_LOOP); + + for(p = 0; p < portals.portal[n].point_count; p++) + g_QglTable.m_pfn_qglVertex3fv(portals.portal[n].inner_point[p].p); + + g_QglTable.m_pfn_qglEnd(); + } + } + + g_QglTable.m_pfn_qglPopAttrib(); +} + diff --git a/contrib/prtview/portals.h b/contrib/prtview/portals.h new file mode 100644 index 00000000..33bac1ec --- /dev/null +++ b/contrib/prtview/portals.h @@ -0,0 +1,125 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef _PORTALS_H_ +#define _PORTALS_H_ + +class CBspPoint { +public: + float p[3]; +}; + +class CBspPortal { +public: + CBspPortal(); + ~CBspPortal(); + +protected: + +public: + CBspPoint center; + unsigned point_count; + CBspPoint *point; + CBspPoint *inner_point; + float fp_color_random[4]; + float min[3]; + float max[3]; + float dist; + qboolean hint; + + qboolean Build(char *def); +}; + +class CPortals { +public: + + CPortals(); + ~CPortals(); + +protected: + + +public: + + void Load(); // use filename in fn + void Purge(); + + void FixColors(); + + char fn[_MAX_PATH]; + + int zbuffer; + int polygons; + int lines; + qboolean show_3d; + qboolean aa_3d; + qboolean fog; + COLORREF color_3d; + float width_3d; // in 8'ths + float fp_color_3d[4]; + COLORREF color_fog; + float fp_color_fog[4]; + float trans_3d; + float clip_range; + qboolean clip; + + qboolean show_2d; + qboolean aa_2d; + COLORREF color_2d; + float width_2d; // in 8'ths + float fp_color_2d[4]; + + CBspPortal *portal; + int *portal_sort; + qboolean hint_flags; +// CBspNode *node; + + unsigned int node_count; + unsigned int portal_count; +}; + +class CPortalsRender : public IGL2DWindow, public IGL3DWindow { +public: + + CPortalsRender(); + virtual ~CPortalsRender(); + +protected: + + int refCount; +#ifdef _WIN32 + CRITICAL_SECTION protect; +#endif + +public: + + // IGL2DWindow IGL3DWindow interface + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } + void Draw2D( VIEWTYPE vt ); + void Draw3D(); + void Register(); +}; + +// void Sys_Printf (char *text, ...); + +extern CPortals portals; +extern CPortalsRender render; + +#endif // _PORTALS_H_ diff --git a/contrib/prtview/prtview.cpp b/contrib/prtview/prtview.cpp new file mode 100644 index 00000000..3e1ba2db --- /dev/null +++ b/contrib/prtview/prtview.cpp @@ -0,0 +1,543 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// PrtView.cpp : Defines the initialization routines for the DLL. +// + +#include "stdafx.h" +#include +#include + +#define Q3R_CMD_SPLITTER "-" +#define Q3R_CMD_ABOUT "About Portal Viewer" +#define Q3R_CMD_LOAD "Load .prt file" +#define Q3R_CMD_RELEASE "Unload .prt file" +#define Q3R_CMD_SHOW_3D "Toggle portals (3D)" +#define Q3R_CMD_SHOW_2D "Toggle portals (2D)" +#define Q3R_CMD_OPTIONS "Configure Portal Viewer" + +static char INIfn[NAME_MAX]; + +///////////////////////////////////////////////////////////////////////////// +// CPrtViewApp construction + +#define RENDER_2D "Render2D" +#define WIDTH_2D "Width2D" +#define AA_2D "AntiAlias2D" +#define COLOR_2D "Color2D" + +#define RENDER_3D "Render3D" +#define WIDTH_3D "Width3D" +#define AA_3D "AntiAlias3D" +#define COLOR_3D "Color3D" +#define COLOR_FOG "ColorFog" +#define FOG "Fog" +#define ZBUFFER "ZBuffer" +#define POLYGON "Polygons" +#define LINE "Lines" +#define TRANS_3D "Transparency" +#define CLIP_RANGE "ClipRange" +#define CLIP "Clip" + +void InitInstance () +{ +#ifdef _WIN32 + char fn[_MAX_PATH]; + char fn_drive[_MAX_DRIVE]; + char fn_dir[_MAX_DIR]; + char fn_name[_MAX_FNAME]; + char fn_ext[_MAX_EXT]; + + GetModuleFileName(GetModuleHandle("PrtView.dll"), fn, _MAX_PATH); + + _splitpath(fn, fn_drive, fn_dir, fn_name, fn_ext); + + strcpy(INIfn, fn_drive); + strcat(INIfn, fn_dir); + strcat(INIfn, fn_name); + strcat(INIfn, ".ini"); +#else // if def __linux__ + strcpy (INIfn, g_get_home_dir ()); + strcat (INIfn, "/.radiant/"); + strcat (INIfn, RADIANT_VERSION); + strcat (INIfn, "/prtview.ini"); +#endif + + portals.show_2d = INIGetInt(RENDER_2D, FALSE) ? true : false; + portals.aa_2d = INIGetInt(AA_2D, FALSE) ? true : false; + portals.width_2d = (float)INIGetInt(WIDTH_2D, 10); + portals.color_2d = (COLORREF)INIGetInt(COLOR_2D, RGB(0, 0, 255)) & 0xFFFFFF; + + if (portals.width_2d > 40.0f) + portals.width_2d = 40.0f; + else if (portals.width_2d < 2.0f) + portals.width_2d = 2.0f; + + portals.show_3d = INIGetInt(RENDER_3D, TRUE) ? true : false; + + portals.zbuffer = INIGetInt(ZBUFFER, 1); + portals.fog = INIGetInt(FOG, FALSE) ? true : false; + portals.polygons = INIGetInt(POLYGON, TRUE); + portals.lines = INIGetInt(LINE, TRUE); + portals.aa_3d = INIGetInt(AA_3D, FALSE) ? true : false; + portals.width_3d = (float)INIGetInt(WIDTH_3D, 4); + portals.color_3d = (COLORREF)INIGetInt(COLOR_3D, RGB(255, 255, 0)) & 0xFFFFFF; + portals.color_fog = (COLORREF)INIGetInt(COLOR_FOG, RGB(127, 127, 127)) & 0xFFFFFF; + portals.trans_3d = (float)INIGetInt(TRANS_3D, 50); + portals.clip = INIGetInt(CLIP, FALSE) ? true : false; + portals.clip_range = (float)INIGetInt(CLIP_RANGE, 16); + + if (portals.clip_range < 1) + portals.clip_range = 1; + else if (portals.clip_range > 128) + portals.clip_range = 128; + + if (portals.zbuffer < 0) + portals.zbuffer = 0; + else if (portals.zbuffer > 2) + portals.zbuffer = 0; + + if (portals.width_3d > 40.0f) + portals.width_3d = 40.0f; + else if (portals.width_3d < 2.0f) + portals.width_3d = 2.0f; + + if (portals.trans_3d > 100.0f) + portals.trans_3d = 100.0f; + else if (portals.trans_3d < 0.0f) + portals.trans_3d = 0.0f; + + SaveConfig(); + + portals.FixColors(); +} + +void SaveConfig () +{ + INISetInt(RENDER_2D, portals.show_2d, "Draw in 2D windows"); + INISetInt(WIDTH_2D, (int)portals.width_2d, "Width of lines in 2D windows (in units of 1/2)"); + INISetInt(COLOR_2D, (int)portals.color_2d, "Color of lines in 2D windows"); + INISetInt(AA_2D, portals.aa_2d, "Draw lines in 2D window anti-aliased"); + + INISetInt(ZBUFFER, portals.zbuffer, "ZBuffer level in 3D window"); + INISetInt(FOG, portals.fog, "Use depth cueing in 3D window"); + INISetInt(POLYGON, portals.polygons, "Render using polygons polygons in 3D window"); + INISetInt(LINE, portals.polygons, "Render using lines in 3D window"); + INISetInt(RENDER_3D, portals.show_3d, "Draw in 3D windows"); + INISetInt(WIDTH_3D, (int)portals.width_3d, "Width of lines in 3D window (in units of 1/2)"); + INISetInt(COLOR_3D, (int)portals.color_3d, "Color of lines/polygons in 3D window"); + INISetInt(COLOR_FOG, (int)portals.color_fog, "Color of distant lines/polygons in 3D window"); + INISetInt(AA_3D, portals.aa_3d, "Draw lines in 3D window anti-aliased"); + INISetInt(TRANS_3D, (int)portals.trans_3d, "Transparency in 3d view (0 = solid, 100 = invisible)"); + INISetInt(CLIP, portals.clip, "Cubic clipper active for portal viewer"); + INISetInt(CLIP_RANGE, (int)portals.clip_range, "Portal viewer cubic clip distance (in units of 64)"); +} + +// Radiant function table +// use to access what Radiant provides +_QERFuncTable_1 g_FuncTable; +_QERQglTable g_QglTable; + +#define CONFIG_SECTION "Configuration" + +#if defined(__linux__) || defined(__APPLE__) + +static bool read_var (const char *filename, const char *section, const char *key, char *value) +{ + char line[1024], *ptr; + FILE *rc; + + rc = fopen (filename, "rt"); + + if (rc == NULL) + return false; + + while (fgets (line, 1024, rc) != 0) + { + // First we find the section + if (line[0] != '[') + continue; + + ptr = strchr (line, ']'); + *ptr = '\0'; + + if (strcmp (&line[1], section) == 0) + { + while (fgets (line, 1024, rc) != 0) + { + ptr = strchr (line, '='); + + if (ptr == NULL) + { + // reached the end of the section + fclose (rc); + return false; + } + *ptr = '\0'; + + if (strcmp (line, key) == 0) + { + strcpy (value, ptr+1); + fclose (rc); + + while (value[strlen (value)-1] == 10 || + value[strlen (value)-1] == 13 || + value[strlen (value)-1] == 32) + value[strlen (value)-1] = 0; + return true; + } + } + } + } + + fclose (rc); + return false; +} + +static bool save_var (const char *filename, const char *section, const char *key, const char *value) +{ + char line[1024], *ptr; + FILE *old_rc = NULL, *rc; + bool found; + + rc = fopen (filename, "rb"); + + if (rc != NULL) + { + guint32 len; + void *buf; + + char *tmpname = g_strdup_printf ("%s.tmp", filename); + old_rc = fopen (tmpname, "w+b"); + g_free (tmpname); + + fseek (rc, 0, SEEK_END); + len = ftell (rc); + rewind (rc); + buf = g_malloc (len); + fread (buf, len, 1, rc); + fwrite (buf, len, 1, old_rc); + g_free (buf); + fclose (rc); + rewind (old_rc); + } + + rc = fopen (filename, "wb"); + + if (rc == NULL) + return false; + + // First we need to find the section + found = false; + if (old_rc != NULL) + while (fgets (line, 1024, old_rc) != NULL) + { + fputs (line, rc); + + if (line[0] == '[') + { + ptr = strchr (line, ']'); + *ptr = '\0'; + + if (strcmp (&line[1], section) == 0) + { + found = true; + break; + } + } + } + + if (!found) + { + fputs ("\n", rc); + fprintf (rc, "[%s]\n", section); + } + + fprintf (rc, "%s=%s\n", key, value); + + if (old_rc != NULL) + { + while (fgets (line, 1024, old_rc) != NULL) + { + ptr = strchr (line, '='); + + if (ptr != NULL) + { + *ptr = '\0'; + + if (strcmp (line, key) == 0) + break; + + *ptr = '='; + fputs (line, rc); + } + else + { + fputs (line, rc); + break; + } + } + + while (fgets (line, 1024, old_rc) != NULL) + fputs (line, rc); + + fclose (old_rc); + + char *tmpname = g_strdup_printf ("%s.tmp", filename); + remove (tmpname); + g_free (tmpname); + } + + fclose (rc); + + return true; +} + +#endif + +int INIGetInt(char *key, int def) +{ +#if defined(__linux__) || defined(__APPLE__) + char value[1024]; + + if (read_var (INIfn, CONFIG_SECTION, key, value)) + return atoi (value); + else + return def; +#else + return GetPrivateProfileInt(CONFIG_SECTION, key, def, INIfn); +#endif +} + +void INISetInt(char *key, int val, char *comment /* = NULL */) +{ + char s[1000]; + + if(comment) + sprintf(s, "%d ; %s", val, comment); + else + sprintf(s, "%d", val); +#if defined(__linux__) || defined(__APPLE__) + save_var (INIfn, CONFIG_SECTION, key, s); +#else + WritePrivateProfileString(CONFIG_SECTION, key, s, INIfn); +#endif +} + + +// plugin name +static const char *PLUGIN_NAME = "Portal Viewer"; +// commands in the menu +static const char *PLUGIN_COMMANDS = + Q3R_CMD_ABOUT ";" + Q3R_CMD_SPLITTER ";" + Q3R_CMD_OPTIONS ";" + Q3R_CMD_SPLITTER ";" + Q3R_CMD_SHOW_2D ";" + Q3R_CMD_SHOW_3D ";" + Q3R_CMD_SPLITTER ";" + Q3R_CMD_RELEASE ";" + Q3R_CMD_LOAD; + +extern "C" LPVOID WINAPI QERPlug_GetFuncTable() +{ + return &g_FuncTable; +} + + +//extern "C" LPCSTR WINAPI QERPlug_Init (HMODULE hApp, GtkWidget* hwndMain) +extern "C" const char* QERPlug_Init (void *hApp, void* pMainWidget) +{ + // Setup defaults & load config + InitInstance(); + + return "Portal Viewer for Q3Radiant"; +} + +extern "C" const char* QERPlug_GetName() +{ + return (char*)PLUGIN_NAME; +} + +extern "C" const char* QERPlug_GetCommandList() +{ + return (char*)PLUGIN_COMMANDS; +} + +/* +void Sys_Printf (char *text, ...) +{ + va_list argptr; + char buf[32768]; + + va_start (argptr,text); + vsprintf (buf, text, argptr); + va_end (argptr); + + g_FuncTable.m_pfnSysMsg (buf); +} +*/ + +bool interfaces_started = false; + +static void CheckInterfaces() +{ + if (interfaces_started) + return; + + render.Register(); + + interfaces_started = true; +} + +extern "C" void QERPlug_Dispatch(const char* p, vec3_t vMin, vec3_t vMax, bool bSingleBrush) +{ + Sys_Printf (MSG_PREFIX "Command \"%s\"\n",p); + + if (!strcmp(p,Q3R_CMD_ABOUT)) + { + DoAboutDlg (); + } + else if (!strcmp(p,Q3R_CMD_LOAD)) + { + CheckInterfaces(); + + if (interfaces_started) + { + if (DoLoadPortalFileDialog () == IDOK) + { + portals.Load(); + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); + } + else + { + Sys_Printf(MSG_PREFIX "Portal file load aborted.\n", portals.fn); + } + } + } + else if (!strcmp(p,Q3R_CMD_RELEASE)) + { + portals.Purge(); + + if (interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); + + Sys_Printf(MSG_PREFIX "Portals unloaded.\n"); + } + else if (!strcmp(p,Q3R_CMD_SHOW_2D)) + { + portals.show_2d = !portals.show_2d; + + if(interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); + SaveConfig(); + + if(portals.show_2d) + Sys_Printf(MSG_PREFIX "Portals will be rendered in 2D view.\n"); + else + Sys_Printf(MSG_PREFIX "Portals will NOT be rendered in 2D view.\n"); + } + else if (!strcmp(p,Q3R_CMD_SHOW_3D)) + { + portals.show_3d = !portals.show_3d; + SaveConfig(); + + if (interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); + + if (portals.show_3d) + Sys_Printf(MSG_PREFIX "Portals will be rendered in 3D view.\n"); + else + Sys_Printf(MSG_PREFIX "Portals will NOT be rendered in 3D view.\n"); + } + else if (!strcmp(p,Q3R_CMD_OPTIONS)) + { + DoConfigDialog (); + SaveConfig(); + + if (interfaces_started) + g_FuncTable.m_pfnSysUpdateWindows(UPDATE_ALL); + } +} + + + +// ============================================================================= +// SYNAPSE + +class CSynapseClientPrtView : public CSynapseClient +{ +public: + // CSynapseClient API + bool RequestAPI(APIDescriptor_t *pAPI); + const char* GetInfo(); + + CSynapseClientPrtView() { } + virtual ~CSynapseClientPrtView() { } +}; + + +CSynapseServer* g_pSynapseServer = NULL; +CSynapseClientPrtView g_SynapseClient; + +extern "C" CSynapseClient* SYNAPSE_DLL_EXPORT Synapse_EnumerateInterfaces (const char *version, CSynapseServer *pServer) +{ + if (strcmp(version, SYNAPSE_VERSION)) + { + Syn_Printf("ERROR: synapse API version mismatch: should be '" SYNAPSE_VERSION "', got '%s'\n", version); + return NULL; + } + g_pSynapseServer = pServer; + g_pSynapseServer->IncRef(); + Set_Syn_Printf(g_pSynapseServer->Get_Syn_Printf()); + + g_SynapseClient.AddAPI(PLUGIN_MAJOR, PRTVIEW_MINOR, sizeof(_QERPluginTable)); + + g_SynapseClient.AddAPI(RADIANT_MAJOR, NULL, sizeof(g_FuncTable), SYN_REQUIRE, &g_FuncTable); + g_SynapseClient.AddAPI(QGL_MAJOR, NULL, sizeof(g_QglTable), SYN_REQUIRE, &g_QglTable); + + return &g_SynapseClient; +} + +bool CSynapseClientPrtView::RequestAPI(APIDescriptor_t *pAPI) +{ + if( !strcmp(pAPI->major_name, PLUGIN_MAJOR) ) + { + if( !strcmp(pAPI->minor_name, PRTVIEW_MINOR) ) + { + _QERPluginTable* pTable= static_cast<_QERPluginTable*>(pAPI->mpTable); + + pTable->m_pfnQERPlug_Init = QERPlug_Init; + pTable->m_pfnQERPlug_GetName = QERPlug_GetName; + pTable->m_pfnQERPlug_GetCommandList = QERPlug_GetCommandList; + pTable->m_pfnQERPlug_Dispatch = QERPlug_Dispatch; + return true; + } + } + + Syn_Printf("ERROR: RequestAPI( '%s' ) not found in '%s'\n", pAPI->major_name, GetInfo()); + return false; +} + +#include "version.h" + +const char* CSynapseClientPrtView::GetInfo() +{ + return "PrtView module built " __DATE__ " " RADIANT_VERSION; +} diff --git a/contrib/prtview/prtview.h b/contrib/prtview/prtview.h new file mode 100644 index 00000000..e478f7d9 --- /dev/null +++ b/contrib/prtview/prtview.h @@ -0,0 +1,29 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// PrtView.h : main header file for the PRTVIEW DLL +// + +#if !defined(AFX_PRTVIEW_H__234356A6_1D66_11D4_BFEB_204C4F4F5020__INCLUDED_) +#define AFX_PRTVIEW_H__234356A6_1D66_11D4_BFEB_204C4F4F5020__INCLUDED_ + +void InitInstance (); +void SaveConfig (); + +#endif // !defined(AFX_PRTVIEW_H__234356A6_1D66_11D4_BFEB_204C4F4F5020__INCLUDED_) diff --git a/contrib/prtview/res/PrtView.rc2 b/contrib/prtview/res/PrtView.rc2 new file mode 100644 index 00000000..0422bb19 --- /dev/null +++ b/contrib/prtview/res/PrtView.rc2 @@ -0,0 +1,13 @@ +// +// PRTVIEW.RC2 - resources Microsoft Visual C++ does not edit directly +// + +#ifdef APSTUDIO_INVOKED + #error this file is not editable by Microsoft Visual C++ +#endif //APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// Add manually edited resources here... + +///////////////////////////////////////////////////////////////////////////// diff --git a/contrib/prtview/resource.h b/contrib/prtview/resource.h new file mode 100644 index 00000000..afa9db6e --- /dev/null +++ b/contrib/prtview/resource.h @@ -0,0 +1,42 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by PrtView.rc +// +#define IDD_ABOUT 129 +#define IDD_LOAD 130 +#define IDD_CONFIG 131 +#define IDC_LOAD_2D 1000 +#define IDC_LOAD_3D 1001 +#define IDC_LOAD_FILE_NAME 1002 +#define IDC_LOAD_OTHER 1003 +#define IDC_CONFIG_3D 1004 +#define IDC_CONFIG_2D 1005 +#define IDC_SCROLL_2D_WIDTH 1006 +#define IDC_2D_WIDTH 1007 +#define IDC_ANTI_ALIAS_2D 1008 +#define IDC_COLOR_2D 1009 +#define IDC_ZBUFFER 1010 +#define IDC_SCROLL_3D_WIDTH 1011 +#define IDC_3D_WIDTH 1012 +#define IDC_ANTI_ALIAS_3D 1013 +#define IDC_COLOR_3D 1014 +#define IDC_COLOR_FOG 1015 +#define IDC_FOG 1016 +#define IDC_SCROLL_3D_TRANS 1017 +#define IDC_POLY 1018 +#define IDC_3D_TRANS 1019 +#define IDC_LINES 1020 +#define IDC_SCROLL_CUBIC 1021 +#define IDC_CUBIC 1022 +#define IDC_CLIP 1023 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 133 +#define _APS_NEXT_COMMAND_VALUE 32771 +#define _APS_NEXT_CONTROL_VALUE 1011 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/contrib/prtview/stdafx.cpp b/contrib/prtview/stdafx.cpp new file mode 100644 index 00000000..6bee6d29 --- /dev/null +++ b/contrib/prtview/stdafx.cpp @@ -0,0 +1,25 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +// stdafx.cpp : source file that includes just the standard includes +// PrtView.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + diff --git a/contrib/prtview/stdafx.h b/contrib/prtview/stdafx.h new file mode 100644 index 00000000..b4afbc8e --- /dev/null +++ b/contrib/prtview/stdafx.h @@ -0,0 +1,79 @@ +/* +PrtView plugin for GtkRadiant +Copyright (C) 2001 Geoffrey Dewan, Loki software and qeradiant.com + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +*/ + +#ifndef __PRTVIEW_AFX_H__ +#define __PRTVIEW_AFX_H__ + +#include + +#if defined(__linux__) || defined(__APPLE__) +#include + +// Necessary for proper boolean type declaration +#include "qertypes.h" + +typedef guint32 COLORREF; +typedef void* LPVOID; +typedef char* LPCSTR; +typedef void* HMODULE; +typedef int BOOL; + +#define RGB(r, g, b) ((guint32)(((guint8) (r) | ((guint16) (g) << 8))|(((guint32) (guint8) (b)) << 16))) +#define GetRValue(rgb) ((guint8)(rgb)) +#define GetGValue(rgb) ((guint8)(((guint16)(rgb)) >> 8)) +#define GetBValue(rgb) ((guint8)((rgb)>>16)) + +#define _MAX_PATH PATH_MAX + +#define IDOK 1 +#define IDCANCEL 2 + +#endif // __linux__ + +#include "synapse.h" + +// plugin +#include "iplugin.h" +#define USE_QERTABLE_DEFINE +#include "qerplugin.h" +#include "ibspfrontend.h" +#include "igl.h" +#include "version.h" + +// PrtView +#include "gtkdlgs.h" +#include "prtview.h" +#include "portals.h" + +#define MSG_PREFIX "Portal Viewer plugin: " +#define PRTVIEW_MINOR "prtview" + +#define UPDATE_2D (W_XY | W_XZ | W_YZ) +#define UPDATE_3D (W_CAMERA) +#define UPDATE_ALL (UPDATE_2D | UPDATE_3D) + +int INIGetInt(char *key, int def); +void INISetInt(char *key, int val, char *comment = NULL); + +extern bool interfaces_started; + +extern _QERFuncTable_1 g_FuncTable; +extern _QERQglTable g_QglTable; + +#endif diff --git a/docs/developer/.cvsignore b/docs/developer/.cvsignore new file mode 100644 index 00000000..cc43c10e --- /dev/null +++ b/docs/developer/.cvsignore @@ -0,0 +1 @@ +*.BAK diff --git a/docs/developer/CHANGES b/docs/developer/CHANGES new file mode 100644 index 00000000..20d07a9b --- /dev/null +++ b/docs/developer/CHANGES @@ -0,0 +1,5616 @@ +This is the changelog for developers, != changelog for the end user +that we distribute with the binaries. (see changelog) + +05/19/2004 +TTimo +- testing CIA setup + +04/09/2004 +TTimo +- update the OSX setup / .info generation code + +04/08/2004 +TTimo +- fix for scons 0.95 +- re-enable Python >= 2.1 version check +- OSX 10.3: remove obsolete dlsym_auto_underscore (bug #920) +- OSX: disable q2 tools build (broken thread code) + +-- 1.4.0 + +SCDS_reyalP +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=963 + fix to multiple monitor support (ABI compatibility with NT4) + +-- 1.4.0-rc2 + +14/12/2003 +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=955 + fix setup to install VC7 runtime + +-- 1.4.0-rc1 + +10/12/2003 +TTimo +- created stable branch, branches/1.4 on all SVN modules +- removed outdated .dsp/.dsw (.net 2002 required now) + +-- branches/1.4 + +06/12/2003 +SCDS_ReyalP +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=930 + shortcuts to change texture window scale + +02/12/2003 +SCDS_ReyalP +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=913 + fix for single monitor window positioning save +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=924 + fixes to CenterXYView shortcut, correctly bound to Shift+Control+Tab now +TTimo +- add a 'q3map2' command line to win32_install.py, factorize and remove win32_install_q3map2.py + +-- linux 1.3.14 test build 1 + +29/11/2003 +TTimo +- heretic2 has no q2map. linux setup tries to install and breaks + removed faulty setup line +- cleaned more Linux setup fuckage caused by q2/her2 + a tip: rm -rf build install before building and testing a new setup + +28/11/2003 +ydnar +- full SCC purge of the vs.net project files (for real this time) +- added seperate Q3Map2 build targets +- added seperate Q3Map2 post-build Python script +- _skybox entity support +- _skybox and _decal in entities.def (Q3) + +-- win32 1.3.14 test build 1 + +28/11/2003 +djbob +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=899 + bobtoolz update (icon functionality is in menu too) +djbob & TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=842 + migration of the win32 build system to vs.net/VC7 + new libxml and libpng packages are required: + http://zerowing.idsoftware.com/libxml/ + http://zerowing.idsoftware.com/libpng/ + updated win32_install.py for new names and paths +TTimo +- assraped the vcproj with sed to remove Scc entries +SCDS_ReyalP +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=88 + 2D background image plugin +TTimo +- putting together win32 setup updates for 1.3.14 + msvcr70.dll goes in core directory + bkgrnd2d plugin content + changed file paths (libxml/libpng) + .xlink for new JA content + +27/11/2003 +TTimo +- using a central scons.signatures file for checksums +- version bump to 1.3.14 +- a libxml-related build bug in qe3.cpp on Debian sid +- it looks like Sid no longer has inflate_mask exported from /usr/lib/libz.so + switched the mask to be defined in our source + this may be a problem on other distros, and on holy box (Woody) +SCDS_ReyalP +- bug 921 and 922, Z floating window fixes +- bug 926, hullcaulk, hintskip, subtlehint +EvilTypeGuy +- bug 505 - select all faces with a given texture + +19/11/2003 +ydnar +- clipper tool plane points default to 1st selected patch mesh + +17/11/2003 +TTimo +- upgraded server to subversion 0.33 + +-- released 1.3.13 + +10/11/2003 +SCDS_reyalP +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=917 + floating windows startup crash + +09/11/2003 +TTimo +- fix M4_GAME_ET ( OSX setup ) +AstroCreep +- cleaned up JA shader scripts + +01/11/2003 +ydnar +- Merged ASE submaterial/subobject code from BirdDawg +- Made Q2/Heretic2 tools not use precompiled headers to eliminate Win32 compilation errors +- Added glColor4ubv() support to the GL function table +- Changed PicoModel rendering to use glColor4ubv() instead of 4 divides and pass-by-value glColor4f() +- Fixed bug 900 by setting alpha to 255 explicitly in image module, rather than 3 input components, + which was borking Q3Map2 jpeg loading, and thus compiles + +24/10/2003 +TTimo +- bump to 1.3.13 +Anders +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=826 +new osx patch, fixes strip bug in setup. merging setup patches to a single file +SCDS_reyalP +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=900 +Some jpegs get garbaged alpha channel + +22/10/2003 +-- merge https://zerowing.idsoftware.com:666/radiant/GtkRadiant/branches/Release-1.3.12/ + 19/10/2003 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=826 + scons BUILD=info to generate a tarball and it's .info + + 18/10/2003 + Spog + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=888 + patch for 16 bit RGBA support in glwidget + + -- released 1.3.12 Linux + + 14/10/2003 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=879 + fixed hellish dlclose issue only occuring with holy builds + + -- released 1.3.12 win32 +-- end merge +Arnout +- added epsilon testing to hashtable compares to eliminate almost-identical vertices +- pico surfaces now use the normals from LWO vertices + +21/10/2003 +Arnout +- added hashtable for faster vertex matching during LWO surface generation +- model rendering now uses DrawElements and will use vertex colours in wireframe/flats shade mode + +20/10/2003 +Arnout +- added LWO support to picomodel. + shader names are derived from surface name + only geometry from layer 0 is used +- added support for 'vertical flipped' TGAs + +19/10/2003 +Arnout +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=893 + fixed starton primary monitor + fixed mouse pointer setting on win32 to properly translate gdk's offset coordinate system in windows' one + +-- released 1.3.12 win32 + +11/10/2003 +Spog +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=865 + fix texture subsets +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=889 + misc update, missing JA system textures +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=824 + fixed .pref file trashing +Nurail +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=881 + BSP monitoring disabled by default in Q2 + +09/10/2003 +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=883 + more JA pack: shaders and mapextras.pk3 textures +- fix Q2 win32_install.py to put the tools at the right spot +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=878 + correctly support PNG images with an alpha channel +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=885 + fix console to refresh during a texture directory load +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=739 + fix weird Shift + Control + Z causing a Redo in non-floating window mode + +07/10/2003 +Nurail & TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=872 + Q2 tools, added -fs_basepath. Need corresponding setup and .proj updates +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=875 + fixed broken surface properties in Q2 surface plugin +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=872 + more fixes, build paths in scons, take out INSTALL config on command line (not functional + not need) + added Q2 tools back to Linux setup +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=197 + using "*" as the shaders minor in surface plugin +- updated makeself copy to the latest from icculus.org cvs +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=574 + sprite plugins, tweak to make it functional for all games +- updated Q2 tools .dsp +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=876 + more Jedi Academy setup work and content + moving imagepng.dll module to the core, as now both Sof2 and JA need it + sample maps reorg, new siege_hoth_sample.map +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=874 + a lot more models - using a dynamic File Group in IS to cope with that +- Q2 IS setup fix, was not properly putting stuff in baseq2/ + IS setup: tweak to Q2 tools stuff + +06/10/2003 +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=872 + Q2 setup needs to be cleaned up and unified between win32 and Linux + using INSTALL_Q2 and TOOLS_Q2 in SCons script to install the Q2 tools + fixed the setup build dependencies to reference the Q2 tools targets + moved the Q2 specific modules imagewad and vfspak to q2/modules + +05/10/2003 +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=871 + updating the gtk2 version to 2.2.4 + adding an SVN module with the Gtk2 developer package: checkout gtk2-win32 + updating IS to the new files + sed'ing the .dsp to replace src-gtk2 by gtk2-win32 +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=609 + Q2 tools: comment out dupe strupr on win32 + update IS setup to missing Q2 stuff ( vfspak and tools ) +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=866 + Fixed Camera inspector window not refreshing. Was a missing top level gtk_widget_show call + +03/10/2003 +Nurail +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=609 + quake2 tools build scripts + Linux setup updates - Q2 game pack in Linux setup +TTimo +- scan through all URL links in game.xlink to update them +- added JA links (Raven and MapCenter forums) + +30/09/2003 +TTimo +- update all synapse.config, win32 .dsw and install_win32.py for new surface module +- Jedi Academy and Quake II game packs in IS setups +- hardcoded hacks in editor core for JA, copied over from JKII +- bug #867, disable sleep by default +- q3map2 bug fix + +Nurail +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=862 + Q2's 'no patch' stuff + +29/09/2003 +TTimo +- OSX: fixup setup.xml.in + +-- merge bug856 back into trunk +16/09/2003 +Nurail +- new patch + win32 stuff for surface module +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=804 + refactored the XML synapse.config handling: + better detection of invalid XML file + less code, factorized to CSynapseClient::ConfigXML +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=828 + fixing bobtoolz 'shaders' major loading issues + added '*' minor. to be used with lots of caution. only if the given major will have a single API such as 'shaders' + also, map module was missing a VFS entry in non-HL configs. that's bad karma, using a minor "*" instead + NOTE: on a lot of modules we could be using a '*' entry instead of having lines in synapse.config +- took out obsolete md3model + +15/09/2003 +Nurail +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=856 + quake2 surface module + +07/09/2003 +Nurail & TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=856 + a surface inspector module to customize per-game API + removing DO_SURFACEPLUGIN define (enabled implicitely) + removing bSurfacePropertiesPlugin (true implicitely) + remove SI_SetActiveInRadiant, it's always on by default + why was USE_UNDOTABLE_DEFINE taken out? - put back in + removed DBG_PLUGIN define and related code, that stuff is from way back and no longer relevant + cleanup QERApp_FreeShaders in shader module from DO_SURFACEPLUGIN stuff + the WINAPI stuff in interfaces is not needed, that's an old remnant. Cleaned up +-- end merge bug856 back into trunk + +19/09/2003 +Justin Blur +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=785 + fix ~/.radiant permission bug +Nurail & TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=849 + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=851 + win32 updates for the new modules and install_win32.py + +16/09/2003 +Nurail & Hydra +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=848 + q2 map format minor + +08/09/2003 +Tr3B +- imagepng.so / PNG format support in Linux + NOTE: atm no official supported Linux game by GtkR uses this + +07/09/2003 +Nurail +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=851 + imagewal.so module / wal image format +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=840 + md2 support in picomodel + +06/09/2003 +Nurail & TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=848 + renaming mapq3.so to map.so + added hooks for Q2 map format load/save to single map module (minor mapq2) +Nurail +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=849 + vfspak port to synapse and updates + +04/09/2003 +SPoG +- Fixed crash in RunBsp caused by passing an invalid pointer to printf. +- Changed console to wrap long lines instead of using horizontal scrollbar. + +30/08/2003 +Anders & TTimo +- OSX setup, new patch to make scons SETUP=1 produce a .run +- don't put bspc Linux binary in the setup + +26/08/2003 +Anders +- more scons OSX, start on setup stuff + +25/08/2003 +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=855 + make 'move into worldspawn' work again +Anders Gudmundson & TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=826 + OSX scons build system + +24/08/2003 +ydnar +- Removed "test.cpp" from radiant.dsp (merge artifact?) +- Added ddslib to radiant.dsw +- Correctly set lib deps for q3map2.dsp for ddslib +- [bug 852] Increased buffers from 260 bytes on Win32 to 4096 bytes + +TTimo +- bump to ver 1.3.12 +- EnsurePythonVersion broke in 0.91 (commented out) + +David Hogue +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=844 + q3data Linux. q3data can read .ase and turn them into .md3 + +23/08/2003 +ydnar +- Added ddslib to repository, based on nvidia sample code, cleaned up a bit + straight C, loads DXT1, DXT3 and DXT5 format DDS textures. + +22/08/2003 +TTimo +- https://zerowing.idsoftware.com:666/viewsvn/ +- Arnout's commit email script - try #2 + the commit script doesn't handle viewsvn root remaps (radiant instead of radiant.svn) + adding a prefix to the report + +04/08/2003 +TTimo +- conversion from CVS to Subversion: +repository convert completed (with revml) +module repositories glued together in a single one +hooking email commit scripts and backup scripts +- Python >= 2.1 required instead of 2.2 + +-- tagged as head-cvs2svn + +01/08/2003 +SPoG +- Changed gl widget to request maximum available depth buffer precision. +- Changed all uses of deprecated GtkCList and GtkCTree to use GtkTreeView/Model. +- Fixed directory handle leakage in synapse module search. +- Fixed dir_dialog always returning NULL for Textures -> Load Directory. + +23/07/2003 +SPoG +- Ported focus_out_event handlers in gensurf to gtk2 signals system. +- Fixed failure to load models for entities other than misc_model. +- Fixed crash in model module shutdown caused by mismatched resource capture/release. + +22/07/2003 +TTimo +- fix q3map2 .dsp for correct glib-2.0 includes (common/vfs.c) +- camera plugin installs to core now (RTCW and ET) +- fixups to the merged setup stuff +- patched cvsreport to provide explicit diff for some files #2 +- fix to work with scons 0.90 / added LIBPREFIX ('lib') where needed + https://sourceforge.net/tracker/?func=detail&atid=398971&aid=766975&group_id=30337 +SPoG +- Fixed crash in cmdlib ExtractFileBase when source filename is an empty string. + +20/07/2003 +TTimo +- SCons scripts for the ported plugins: bobtoolz, camera, prtview, gensurf +- ET Linux setup script + new plugins +- q3map2.x86 is installed and wrapped through a q3map2 script (libstdc++ LD_LIBRARY_PATH) +- update ChangeLog and credits +- put back the GTKRAD_DIR in .fgl + +19/07/2003 +SPoG +- Tagged trunk before merge as bug537-merge-3. +- Tagged branch port_gtk2_20030307 as gtk2-merge-final. +- Merged changes since tag bug537-merge-2 into trunk. +- Removed gtk dependency from plugin toolbar interface. +- Ported prtview, bobtoolz and gensurf to gtk2. + +18/07/2003 +Anders Gud +- OSX build fix + +16/07/2003 +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=814 + merging ET support code into to trunk +- cvsreport 0.3.0 - http://www.nongnu.org/cvsreport/ + rolling out this ver since old cvsreport setup broke +- fixup to build on Linux (including fixing plugin builds) + +-- release-1_3_8-ET + +02/07/2003 +TTimo +- new setup build, with patches and updates from SD +- local fixing of bobtoolz dependency against libcmd, and itoolbar.h gtk header bustage + +19/06/2003 +TTimo +- missing plugins. add them to .dsw for default build, add them to IS setup: + camera, gensurf, bobtoolz, prtview +- fixup bobtoolz code for VC6. for(int i=0 causing duplicate definition errors +- removed pk3man from IS (we no longer distribute/maintain it) + TODO: cvs remove the IS files for it +- re-enabled plugins in build by default, disabled curry and textool + TODO: following error when bring up About box of bobtoolz: + BobToolz::ERROR->Failed To Load Exclusion List: C:\Program Files\GtkRadiant-ET-1.3\plugins\bobtoolz.dllbt\bt-el2.txt + +18/06/2003 +TTimo +- add ET game pack. from Arnout's full dump of editor source + game pack data + trunk tagged at ET-tag for this +- Dlg_SdAskCorePath: + szDir = "C:\\Program Files\\GtkRadiant-ET-1.<>"; + +09/06/2003 +ydnar +- Added Q3Map2 keys/entities to Quake 3 entities.def +- Removed obsolete vlight keys from Quake 3 entities.def +- Added MD5 functionality to mathlib, from: + http://sourceforge.net/projects/libmd5-rfc/ + +------- merged changes since tag bug537-merge-2 from branch port_gtk2_20030307 to trunk + +TTimo +- try checkin on branch see if cvsreport 0.3.0 will verbose it + +08/07/2003 +SPoG +- Fixed recent-files list for file names containing underscores. + +07/07/2003 +SPoG +- Fixed crash and file-type bugs in gtk file-dialog. +TTimo +- converted the setup code from perl to python +- added copy over of libgcc_s and libstdc++, and LD_LIBRARY_PATH in the wrapper script + +06/07/2003 +SPoG +- Changed console popup menu to include cut/copy/paste as well as clear. + +05/07/2003 +SPoG +- Fixed the way surface-inspector dialog responds to escape key. + +04/07/2003 +TTimo +- linux building / SCons + 0.90 is broken, use 0.14 for now. added version check + adding scons SETUP=1 option to spawn setup build + enable back vfswad in scons + TODO: grab Conscript-setup, convert it to python in build_setup function + +02/07/2003 +TTimo +- building a win32 setup, using -gtk2 suffix (game packs in Radiant-1.3-gtk2 and core in GtkRadiant-1.3-gtk2) +SPoG +- Ported vfswad to gtk2. +- Fixed memory leak in vfspk3 directory search. +- Added vfswad to win32_install.py. + +09/06/2003 +TTimo +- tagging setup/ as gtk2_setup_rollback + rolling back trunk setup code to the branch to build an experimental release +- merge trunk to branch: +-- tagged HEAD with bug537-merge-2 +-- merge HEAD between bug537 and bug537-merge-2 into the branch -- + 31/05/2003 + TTimo + - grab back vfswad code that I forgot in bug 800 rollback + - add prtview back to the project, fix it to build (#817) + + 27/05/2003 + djbob + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=817 + prtview fixes, upgrade to synapse + + -- release-1_3_8 +-- end merge HEAD between bug537 and bug537-merge-2 into the branch -- +- freshly merged in vfswad is broken +- freshly merged in prtview is broken +- q3radiant.dsp -> GtkRadiant.dsp, outputs GtkRadiant.exe +- removed vc5 dsps +SPoG +- Updated win32 setup stuff to use gtk2 dlls. +- Modified setup.pl to run correctly (tested on cygwin perl 5.6). + +08/06/2003 +TTimo +- Linux: + check gcc 3.x, better ldd check + add gcc version to about message + kill old cons stuff +- added q3map2.x86 scons build +- header conflict libs/cmdlib.h tools/quake3/common/cmdlib.h + grepped through q3map2 source to change #include "cmdlib.h" to common/cmdlib.h +- killed more cons files remnants +SPoG +- Improved error reporting for win32 setup system. +- Fixed errors reported when running setup scripts. +- Fixed scale of xor selection rectangle in XY window. + +07/06/2003 +SPoG +- Fixed X Window System error when entering freelook on *nix. + +06/06/2003 +SPoG +- Fixed copy/paste on *nix. +- Changed copy/paste on *nix to use GtkClipboard api. +- Changed copy/paste on win32 to be non-window-specific. +- Further cleaned up MainFrame::Create. +- Changed freelook to use gdk_window_get_origin instead of gdk_window_get_root_origin to place the cursor. + +05/06/2003 +SPoG +- Fixed grey statusbar in 4-way-split mode. +- Redirected gtk messages before creating main window. +- Removed unused XYFriend hack from camwindow. + +04/06/2003 +TTimo +- win32_install.py settings loaded/saved from site.conf + +02/06/2003 +TTimo +- fixed python running with no output. Make sure VC6 finds native Python before any cygwin Python + look at the Directories settings in Tools > Options to either kill the c:\cygwin\bin path, or have Python path first +- renamed dupe files to avoid header collision and general confusion between entity and model +- added win32_install.py to perform post-build install (need to load the configuration paths from a non-cvs stored site.conf file) + +01/06/2003 +TTimo +- bind gen.dsp to makeversion.py +- added a run_python.bat to check for python presence and execute + +27/05/2003 +TTimo +- write makeversion.py module - hook it up to SCons build - cleaner, easier to use +- comment out vfswad build lines. source is still not in tree (bug 800 aftermath I think) + +18/05/2003 +SPoG +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=537 + Changed Sys_FPrintf_VA to immediately process console events during map load. + Changed startup to create main window after QE_Init(). + Fixed loading last map on startup. + Fixed crash on exit. + Fixed colour dialog. +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=537 + have to delay merging back to trunk. + have a behaviour problem between debug and release builds. + while debug is fine, release is screwed (see bug item) + +-- tagged HEAD with bug537 +-- merge HEAD between merge-gtk2-20030413 and bug537 into the branch ----- + 11/05/2003 + Dan Olofson & TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=812 + workaround for ATI drivers bug (polygon backfaces) + use Preferences > 2D Display/rendering > ATI cards with broken drivers + Riant + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=806 + updated synapse.config for SoF2 png + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=805 + dir_dialog is broken - is only used in prefab path prompt + + -- release-1_3_7 + + 14/04/2003 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=801 + moved "ignoring sprite for entity.." to be a _DEBUG only thing + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=802 + fixed models not drawing on win32. was a setup bug + - OSX setup build updates - added dependency against libpng3-shlibs + - added openurl.sh to open urls on *nix (with setup updates) + Riant + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=803 + RTCW - default_project.proj in setup + + 13/04/2003 + Michael Schlueter & EvilTypeGuy + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=684 + imagepng building under Linux + Riant & TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=797 + fixed texture compression support + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=799 + regen project file from template on version upgrade + updated all default_project.proj to have "version" "1" + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=798 + missing modules/bitmaps/model_reload_entity.bmp from Linux setup +-- end merge HEAD between merge-gtk2-20030413 and bug537 into the branch ----- + +17/05/2003 +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=537 + http://www.qeradiant.com/wikifaq/index.php?Gtk2%20build%20notes + went through the new dll dependencies, listed required files preparing for a single zip package + updated all the project files to rely on src-gtk2/ + +13/04/2003 +SPoG +- Tagged HEAD with 'merge-gtk2-20030413' and merged HEAD --> port_gtk2_20030307. + +12/04/2003 +SPoG +- Added gtk-2.x libraries to win32 setup. +- Changed win32 setup to use 'dynamic' file-groups, making it possible to add files without + modifying installshield scripts. +- Modified win32/setup.pl to copy setup data to dynamic file-group directories. + +30/03/2003 +TTimo +- added scons scripts. the scons engine is included in the tree. you just need to have python + have ldd -r safe check on .so + TODO: + - make sure it's gcc3 + - check OSX + - add q3map2 build + +29/03/2003 +TTimo +- tracked and fixed the startup bomb on Debian sid: + `pkg-config gtk+-2.0 --libs` + -Wl,--export-dynamic -lgtk-x11-2.0 -lgdk-x11-2.0 -latk-1.0 -lgdk_pixbuf-2.0 -lm -lpangoxft-1.0 -lpangox-1.0 -lpango-1.0 -lgobject-2.0 -lgmodule-2.0 -ldl -lglib-2.0 + http://www.gnu.org/manual/ld-2.9.1/html_chapter/ld_2.html#SEC3 + --export-dynamic + When creating a dynamically linked executable, add all symbols to the dynamic symbol table. + The dynamic symbol table is the set of symbols which are visible from dynamic objects at run time. + If you do not use this option, the dynamic symbol table will normally contain only those symbols + which are referenced by some dynamic object mentioned in the link. If you use dlopen to load + a dynamic object which needs to refer back to the symbols defined by the program, rather than + some other dynamic object, then you will probably need to use this option when linking the program + itself. + this causes symbol confusion, shaders.so's g_ShaderTable suddenly resolves to the core's g_ShaderTable + one is a 'shaders' API, the other an 'appshaders' .. everything gets badly mixed up + added a check in the cons script, using `pkg-config gtk+-2.0 --libs-only-L` `pkg-config gtk+-2.0 --libs-only-l` + (same for gtkglext) + +28/03/2003 +TTimo +- propagate jpeg compile fix from bug750 branch +- use PKG_CONFIG_PATH when building radiant/ (alternate gtkglext-1.0) +- on OSX, you need gtk+2-dev package, and pkgconfig, atk1 + build gtkglext from source http://gtkglext.sourceforge.net + +17/03/2003 +TTimo +- updated the build system to glib2/gtk2/gtkglext + atm it compiles and starts on my dev box (Debian Sid) + but doesn't reach end of initialization, hangs on + q = (qtexture_t*)g_hash_table_lookup (g_ShadersTable.m_pfnQTexmap (), stdName); + in shaders.cpp QERApp_Try_Texture_ForName + need to have the gtk2 dev packages, and libgtkglext1-dev + +12/03/2003 +SPoG +- Replaced alpha-blended area-selection rect with XOR rect. +- Fixed YX/XZ/YZ toggle in floating windows layout. +- Cleaned up xor rectangle code. + +11/03/2003 +SPoG +- Fixed console scroll-to-last-text-inserted. +- Fixed console error/warning colours. +- Refactored or removed WIN32-specific gtk-related stuff. +- Removed win32 SetCapture/ReleaseCapture on GLWindow. +- Removed win32 gtk_main_iteration calls in glwindow mousemoved. +- Cleaned up start-on-primary-monitor stuff. +- Changed main window to use standard save/load window position/size. +- Replaced deprecated gtk_widget_set_uposition with gtk_window_move. +- Removed win32/X gl functions from igl. +- TODO: replace/remove deprecated gtk_widget_usize. + +10/03/2003 +SPoG +- Changed fonts in win32 rc file to 8pt tahoma. +- Fixed flat-grey gui in Regular layout mode. +- Changed main-window save/restore maximized to use gtk API. +- Fixed button_press_event handling on console/entity/entitylist windows. + +09/03/2003 +SPoG +- Fixed crash on shutdown after changing floating-z-window preference. +- Removed win32_realize_floating hack. +- Refactored MainFrame::Create to make it more readable. +- Fixed key_press_event handlers for entity/surface/patch dialogs. +- Fixed delete_event handlers for dialogs derived from Dialog class. + +08/03/2003 +SPoG +- Fixed viewport for entity window comment text. +- Fixed x-shrinking for entity window comment text. +- Fixed menu underscore shortcut hack in MRU list. +- Changed groupdialog to connect switch_page signal after creating all pages. +- Changed gl widget to use gtkglext/pango to create fonts. +- Cleaned up gtkglext glwidget implementation. +- Reduced border size on toolbar widgets. +- Replaced font with font_name in win32 rc file. +- Added viewports for all scrolled text boxes. +- Fixed entities/textures/console window title update when page is changed. +- Fixed floating windows not being transient to main window (don't want them on taskbar). + +07/03/2003 +SPoG +- Created a new branch for the port to gtk 2.x. +- Fixed menu underscore shortcuts to use gtk_label_new_with_mnemonic. +- Fixed global keyboard shortcuts by using mainframe_keypress. +- Fixed use of deprecated gtk_color_selection_get_color. +- Removed use of deprecated gtk_paned_set_gutter_size. +- Replaced deprecated gtk_widget_draw with gtk_widget_queue_draw. +- Replaced deprecated gtk_object_get/set_data with g_object_get/set_data. +- Replaced deprecated gdk functions with 2.x equivalents. + + +----- branch port_gtk2_20030307 ------ + + +13/04/2003 +Michael Schlueter & EvilTypeGuy +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=684 + imagepng building under Linux +Riant & TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=797 + broken texture compression support + +12/04/2003 +TTimo +- push version to 1.3.7-dev +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=794 + add a synapse.config chunk for image module + also added check for correct dynamic APIs initializations (bug 796) + misc stability fixes to synapse +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=796 + "map" "maphl" not checking for "VFS" "wad" presence + added a safe check. don't have an HL setup to test on though +LordHavoc +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=790 + misc crash fixes related to vfsLoadFullPathFile returning -1 on not found +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=89 + work on Q1 support + added a new module 'Q1Pack' wit the synapse.config for Q1 + applied the patch (#415) - with some modifications. Removed unused TGA stuff from imagehl. +Riant +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=781 + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=795 + 1.3 SoF2/JK2 setup missing synapse.config + several fixes to the SoF2/JK2 support + BSP menu, q3map2 + monitored compiling + fixed TEMPLATEapppath expansion + Q3 default_project.proj + +10/04/2003 +** who ? ** (ETG?) +- Compilation warning fixes including: + lack of newline at end of files + non-virtual destructor for virtual function class + addition of header #includes to solve "implicit declaration" cases + corrected bogus #endif declarations + added declaration of WinPrint for l_net_berkley.c +- Added _GNU_SOURCE define for q3map2 threads.c for non-WIN32 platforms + (usage of mutex_setattr_settype is a posix *extension*) + +29/03/2003 +TTimo +- merging bug750 branch back into trunk. Have Linux and OSX setup live together +- added setup.sh.in config.sh.in / stuff flagged as OSX-only - setup.sh only tries to run setup.gtk +- the .deb building on Linux was experimental, we don't plan to use it. took it out (.deb is for OSX/fink setup build) +- setup.xml.in with a bunch of OSX updates +- propagated back the GtkR setup patch to lokisetup ML +-- bug750 branch ------------------------------- + 18/03/2003 + X-Man & TTimo + - corrected setup.gtk bugs (don't strip, detect arch correctly) + - fixed arch detection in postinstall.sh + - updated setup.sh to do the right thing and point to help + - rebuilding a rev 3 + + 17/03/2003 + TTimo + - setup.sh sources fink's init.sh stuff + - abort if not root + - fake xsu to have correct abort (run it as root directly) + - rebuilt .deb + + 10/03/2003 + TTimo + - building a fink .deb to wrap the setup: when run as root, ./cons -- setup + now produces a .deb which wraps the graphical installer + - updated setup.gtk and related source patch to new loki_setup source + - handy script to use when putting together a list of dependencies: + otool -L radiant.ppc > otool.txt + cat otool.txt | sed -e 's/^\([^ ]*\) .*/\1/' | while read i ; do dpkg -S $i ; done 2>/dev/null + + 05/03/2003 + TTimo + - making ./cons -- setup builds a .deb + the idea is to use a .deb for dependencies against fink, and trigger our custom setup once the .deb is installed + no dependencies atm, need to rebuild on OSX and write in the whole set of deps + - happy place, happy place .. the code to build a .deb for debian and a .deb + for fink won't be compatible. fink lacks -fakeroot support, some stuff needs + to run as root. Disabled for now + - hacked to fix libjpeg build, need to -Ilibs/jpeg6 before system paths + (would need a CPP_BASEPATH in the build system) +-- end bug750 branch ----------------------------- + +13/03/2003 +Hydra +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=197 + cleanup in hydratoolz plugin +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=776 + more post build step cleanup +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=648 + enginepath in setup +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=574 + sprites loader verbosity + +TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=775 + - updating 1.3 setup against 1.2 tree + - zlib and libpng12 in Program DLL Files + - changelog.q3map2.txt to Program Misc Files + - merged RTCW GOTY edition prompt from 1.2 setup + - merge SoF2 setup prompt code from 1.2 setup + - made sure merged SoF2 .game has enginepath + - remove the media update items (we start from scratch on 1.3) + - bitmaps in Program Executable Files + file0=<>\GtkRadiant\plugins\model\bitmaps\picomodel.bmp + file1=<>\GtkRadiant\plugins\model\bitmaps\model_reload_entity.bmp + - added dependencies of q3data.exe installed in STVEF Executable Files (libxml2 etc.) + - removed libxml2 / iconv / glib where not needed + +11/03/2003 +Hydra TTimo +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=776 + sanitize post build step +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=574 + updates for spritemodel stuff. cleaned up the patch a bit + +Hydra +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=777 + improve visibility of selected models +- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=197 + hydratoolz update + +28/02/2003 +TTimo +- building an experimental 1.3 full setup on win32 + includes all games (Q3 RTCW JKII EF SOF2 HL) + several updates to .dsp's to get everything building in release + setup updates: + took out all plugins (they have not been ported) + took out q3map references (we only distribute q3map2 in 1.3) + add q3map2 to Program Executable Files + using GtkRadiant-1.<> for core path + usign Radiant-1.<> for game packs + adding synapse.config: HL / Q3 / RTCW (HL untested) - others don't have one yet + +17/02/2003 +TTimo +- tweaking ./cons -- setup on OSX, look for gcc 3.x by default + -- creating branch bug750 for OSX setup work + - long term, we want a single setup file working for both Linux and OSX + but initial OSX setup work is easier if we just do a standalone OSX setup + though since it breaks Linux setup for a bit, putting this on a branch + - compiled a ppc setup.gtk from loki_setup + - updated Conscript-setup and related stuff to be OSX / ppc compliant + +16/02/2003 +TTimo +- fixed symlink bug in Linux setup stuff + +15/02/2003 +TTimo +- added CreateDirectoryPath to cmdlib, shuffled some utility code around. + QE_SaveProject correctly creates the paths + +10/02/2003 +TTimo +- Finalize Linux x86 setup. + Updated loki_setup patch with SETUP_COMPONENT_PATH env var for postinstall.sh, rebuilt a glibc 2.1 x86 image for setup.gtk + Finished ./cons -- setup code up to final setup generation + +31/01/2003 +SPoG +- bug #752 - Construct fix for ppc, patch applied. + +26/01/2003 +TTimo +- bug #750 - revamp of the setup stuff on Linux + (under way, see bug for progress - feel free to help!) +- reworked the cons scripts, setup is hooked in to cons now + also, added gcc version select on command line, using Cons_gcc.pm utility + +22/01/2003 +TTimo +- merged merge-1_2_10-post back to trunk + +=============================================================== +-- merging release-1_2_9 -> merge-post-1_2_10 into trunk + trunk before merge is tagged pre-merge-1_2_10 +=============================================================== + +22/01/2003 +TTimo +- finished up the TODO items, turned into bug items or dropped them. branch is ready to move back in to trunk + +18/01/2003 +TTimo +- fixed ID_SELECTION_MERGE + +17/01/2003 +TTimo +- fixups + FlushReloadSelectedToolbarButton -> CFlushReloadSelected + incorrect naming: RadiantToolbarModuleManager -> CRadiantToolbarModuleManager + ToolbarButton -> IToolbarButton, and C* implementations + http://www.qeradiant.com/wikifaq/admin.php?Code%20Conventions + +14/01/2003 +ydnar +- Minor Cons fix for OS X (bug 729) + +13/01/2003 +ydnar +- GtkRadiant now builds on OS X, Linux, and Win32 out of the same tree +- OSX build uses gtkfileselect-linux now, as the Darwin version was broken/old + fixme: change this to use OS X open dialog box or something? +- Minor fixes to a few files to fix gcc warnings +- Model module now builds on OS X and Linux, using Synapse properly +- PicoModel change to invert T coordinate on ASE models +- Q3Map2 change to export ASE models with T coordinate flipped +- Misc Q3Map2 changes + +09/01/2003 +ydnar +- Updated Construct with Darwin/OS X ld flags for 4MB stack size +- Misc Q3Map2 updates (2.3.35-dev) + +05/01/2003 +ydnar +- "angles" key now properly ordered, to work with current mathlib + (also changed in Q3Map2) + +31/12/2002 +ydnar +- PicoModel: Minor fix to MDC loader (naming/define) +- Q3Map2: 2.3.34-pre-1 updates +- MapXML dsp unix->dos newlines + +29/12/2002 +SPoG +- Merged q3map2-texturing prefs key. +- Merged vfs check for gamemode project key. + +27/12/2002 +TTimo +- fix GetTickCount stuff +- added q3map2 cons script +- fixed Linux build + +23/12/2002 +SPoG +- Added model cache API, moved model cache implementation from entity module to core. +- Added file-type registry API, replaced core file-type manager with registry. +- Changed model module to register supported file types with core registry. +- Removed or #ifdef'd non-functional code from model module. +- Added support for misc_gamemodel and model_static to entity module. +- Cleaned up entity module's on-epair-changed API. +- Moved light-entity-specific code to a seperate file in entity module. +- Cleaned up file dialog interface - specify file-type-lists with a string. + +22/12/2002 +SPoG +- Ported camera plugin to synapse, adding support for camera and ui APIs. + +20/12/2002 +SPoG +- Fixed default prefs setting for selected-brushes-camera, gridmajor-alt and gridminor-alt. +- Merged CEntityEclassModel::Draw in entity module. +- Ported imagepng module to synapse. +- Fixed warning for CamDragMultiSelect preference bool used as int. + +19/12/2002 +SPoG +- Fixed white-textures bug caused by texture compression preferences. +- Ported light-radius rendering to 1.3 entity module. + +18/12/2002 +SPoG +- Merged win32 project files, with the exception of camera plugin. +- Ported model module to synapse API. +- Redesigned toolbar API to remove gtk-dependency from toolbar plugins. +- Refactored window-position preference save/load. + +17/12/2002 +TTimo +- kick doxygen generation for branch merge-1_2_10-post + +15/12/2002 +TTimo +- having the linux version compile and start again. took out numerous elements while merging, built a list of TODO stuff + the main thing to do being to bring the win32 build back up too, then to go through TODO list and fix stuff + until the win32 version runs too, I check this in to a seperate branch merge-1_2_10-post +- There is quite a massive update in mainframe.cpp switch case for all events. + Looks like it's just a reordering of stuff, but it looks bad in the diffs. +- added m_MapReg pattern + +- At some point, I'm thinking that forcing correct TAB/SPACE conversion on the server end would be a good thing to have. + Nazisticly forcing the formatting sounds like the only viable solution. + + 11/12/2002 + RR2DO2 + - #418, mdc load and display (RTCW) + - #597, CenterCamera shortcut + Use Ctrl+Shift+TAB to center the views onto the current camera location + - #714, bitmap loading fixes and speedups + - #715, fixed Alt+Shift cycle/drill select to work with brush-based entities + EvilTypeGuy + - #718, fix compilation warnings + Riant + - #707, fixed HM mode in STV:EF + + 10/12/2002 + EvilTypeGuy + - Fix gcc3 compilation warning + EvilTypeGuy and X-Man + - Fix OpenURL so browser launching works on XDarwin (Mac) systems. + + 8/12/2002 + RR2DO2 + - #710, AssignSound pattern + - #711, SoF2 model_static drawing + - #713, sync 2d and 3d rendering of models + - #238, apply 0..1 T range when Fitting a patch (instead of 0..-1 previously) + - #633, Add ability to change default color in 3D window Misc > Colors > Camera background + ydnar + - Q3Map 2.3.33 (see changes.q3map2.txt) + - Quake 3 + TA common.shader updates (q3map_terrain, hint) + + 3/12/2002 + TTimo + - merging Stable-1_2-Apple into Stable-1_2 + - why INSTALL.TXT? re-used INSTALL, updated to point to wiki + - why the -machinedump test against i386-redhat-linux? removed + - using $is_darwin flag instead of $gcc_machine tests in the build scripts: + gotta leave some room for a Linux ppc build, and darwin x86 + exporting it for use in sub scripts + - the addition of ccache support broke some Apple SConstruct patches to $ENV{PATH}, fixing + merged version is compiling fine on Debian Sid + checking in on a branch, need to validate win32 build and OSX build before applying in Stable-1_2 + + -- release-1_2_11 + + 30/11/2002 + TTimo + - added seaw0lf to credits + - ydnar's changelog.q3map2, added to global.xlink and Linux setup + - 1.2.11 version tag + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=699 + updated IS setup for q3map_terrain keyword + also fixed details in STVEF media + Arnout + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=569 + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=698 + fixed drill select, Ctrl bug in vertex mode, and updated changelog.txt + + 29/11/2002 + TTimo + - 1.2.11-rc1 + - update changelog credits links for release + - update linux setup, putting EULA and new README instructions + + 28/11/2002 + ydnar + - Removed redundant 'p' from "developers" + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=637 - fixed + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=694 - fixed + - Updated to Q3Map 2.3.32 + - Added epsilon to texture plane choose code to eliminate numerical + inconsistencies on brush faces slanted at 45 degree angles (bug 637) + - Fixed bug in lightmap export after lighting when map contains 0 BSP lightmaps + - Adjusted some light tracing constants to fix certain brush/patch seam shadows + - Tinkered with skylight code again + - Fixed bug where lightgrid would be black if level was compiled with -nogrid + - Fixed -approx code to work in floating-point space, using _minlight + - Fixed bug where vertex light code was using invalid pvs data to create + light list for surface, leading to incorrect vertex lighting + - Fixed related bug in anti-light-leak code that was causing brush faces to go + black (bug 694) + - New: _minlight sets _minvertexlight and (new) _mingridlight automatically + - New: _mingridlight key to set minimum grid lighting + + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=637 + added preference setting in Preferences > BSP monitoring + added an item on the wiki + + 27/11/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=662 + picomodel-based model.dll module (new model.dll, removed md3module.dll) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=664 + media/setup updates for q3map2 support + added modified quakev3.qe4, bumped internal version to 4 for all games + SOF2 and JKII were forcing BSP monitoring off because of sof2map, now only printing a warning + added -rename to SOF2 BSP phase + Q3 & RTCW new templates are working + haven't tested the STVEF & SOF2 versions + updated IS setup scripts to make sure quakev3.qe4 is updated in nightly release + (not needed on Linux, we will be doing a full release) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=662 + updated win32 setup to provide right model.dll stuff + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=621 + typo was causing memory error + + RR2DO2 & TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=662 + more model fixes, fixed the Linux build to build model.so + added search path to modules/ for bitmaps + model reload, patch and bitmap + + 26/11/2002 + RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=569 + area select - Alt+Shift for area select (complete tall) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=621 + broken undo creating ghost undo entities (and trashes memory) + partly fixes the issue, it's a memory error still + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=659 + updates to RTCW camera plugin - works in 4 view mode + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=663 + more fixes to plugin API + + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=638 + libpng in the core DLLs instead of SoF2 (for q3map2 dependencies) + putting q3map2 binary with the Core Binaries + + 25/11/2002 + TTimo + - added ccache support to cons build system - http://ccache.samba.org/ + + 21/11/2002 + ydnar + - minor bugfix to PicoModel ASE material loader + - Q3Map2 updated to 2.3.31 (Splash Damage) + - Stitching the edges of lightmaps on patches that wrap around (cyls and cones) + so the seam is no longer visible + - The -patchmeta switch works better now, the patches are still stored in the + BSP for collision, but are pre-tesselated into nonplanar meta surfaces for + more efficient rendering + - Better, more uniform lightmap sample position finding on patch meshes + - Moved q3map_tcMod and q3map_alphaMod processing to the final phase + - New: q3map_skylight AMOUNT ITERATIONS to replace surfacelight on sky surfaces + for much faster and more uniform sky illumination + - Fixed bug in PicoModel ASE material parsing code + - Fixed a few seam/lightmap precision/projection errors + - Increased MAX_SHADER FILES to 1024 and fixed overrun error when more than that + number of shaders was listed in shaderlist.txt + - Increased a few compiler maximums for larger maps + - New: -np N switch on BSP phase, works like -shadeangle, in that it forces all + planar shaders to be nonplanar with the shading angle specified + - New: -nohint switch on BSP phase, omits hint brushes from compile for testing + - New: -debugaxis switch on light mode. Colors lightmaps based on their lightmap + axis (which direction the lightmap was projected on) + - New: -debugorigin switch on light mode. Colors lightmaps based on the luxel + origin relative to the raw lightmap's bounding box + - New: -debugcluster switch on light mode. Colors lightmaps based on the pvs + cluster the luxel falls into + - New: -convert switch to convert BSP to ASE file (experimental) + - New: q3map_lightmapmergable directive to allow terrain to be mapped onto a + single lightmap page for seamless terrain shadows + + 18/11/2002 + TTimo + - fixed pk3man build system to work with new cons layout + - fixing linux setup system to work with new cons layout + Linux 1.2.11 will be a full setup, much easier that way + - update makeself to the latest (and best) version + - add q3map2 to Linux setup. goes in core (g_strAppPath) + NOTE: has a dynamic dependency to libpng + - pk3man still has issues with the zlib code that's been thrown in it + unresolved which I don't have time to look at + since we plan to drop pk3man in 1.3, dropping it now is just as good + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=644 + detect GOTY install from registry and use it as default path + + 13/11/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=639 + reworked to have the UI in game settings dialog + (this is strictly win32 thing, if that broke Linux build, then fix the typos) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=630 + mouse AngleSpeed setting was getting clobbered. fixed and upped the max values + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=623 + applied a fix, rolls back the values when the compression formats are not supported + fix ain't very clean, if we have to deal with extensions some more, we need to deal with the settings persistance better + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=624 + updated the setup code for town_*.shader (both in full setup and update) + updated files in WolfPack + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=672 + using a QE4_VERSION define, added a message if there's a project template with wrong version + + 12/11/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=671 + guard junk.txt path between " " + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=663 + fix to CommitBrushHandleToEntity stuff + + RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=660 + previously you could select patch control points when patch selected + vertex edit (V) in 2D view. Works in camera view now + + 12/11/2002 + TTimo + - nudging zerowing to trigger Stable-1_2-Apple doxygen generation + http://zerowing.idsoftware.com/doxygen/ + + 11/11/2002 + TTimo + - http://ttimo.net/web/anjuta + modified the .prj to work with the cons patches (linked dirs) + still way experimental + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=651 + fixing linking for radiant.x86 + + 10/11/2002 + RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=669 + patch inspector bug - fixed + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=663 + fucked up change in the plugin API caused breakage of several plugins + still have to fix bobtoolz http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=665 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=661 + Undolevels not set properly + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=660 + drag selection to the camwindow for patches in controlpoint edit mode + (not sure about the actual shortcuts, Ctrl+Alt on my current Linux setup) + + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=657 + mark map modified on editing entity keys + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=651 + added the correct link and ldflags statements to have static linking everywhere + didn't check gcc 3 build, check correct static on Debian Sid and holy box + has a $staticstdcxx in Construct to toggle On/Off if needed + + 09/11/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=651 + reworking the cons building. support for gcc2 and gcc3 + cons -- gcc= + read gcc version and configure accordingly + changed _NO_STLPORT to Q_NO_STLPORT + independant BASE_CFLAGS and BASE_CXXFLAGS + correcting usage of CC/CXX for c/cpp source and linking + fixed missing -lz in vfspk3.so + changed the way we build curry.so, works from the GtkRadiant tree now + (NOTE: gcc 3.2 build of curry.so spews quite a few warnings) + tweaked the way we do -fno-rtti -fno-exception + + 04/11/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=638 + .qe4 version 4, udpated q3's .qe4 template, update setup to put q3map2 in the right place + bumped version to 1.2.11-test for test setups + + 03/11/2002 + ydnar + - fixed bug in jpeg loading code (4 components instead of 3 for RGB images, mh) + - updated PicoModel to 0.8.8 and Q3Map2 sundry fixes (2.3.29): + - Merged with latest CVS, fixed minor issues with matrix order + - Fixed minor Sys_FPrintf/Sys_Printf substitution typo in Q3Map2 + - Expanded debug colors to 12 for debugging surface meshes + - PicoModel: fixed ASE loader to support > 1 texture coordinate per-vertex, + so more models supported correctly, also loading vertex normals + - PicoModel: md3 shader names are now cleaned. Suffixes (such as .tga or .jpg) + are stripped, and \ path separators are changed to / + - New: Add :q3map to the end of any shader name, and it will be interpreted as + the named shader minus :q3map. Example: + textures/shaderlab/concrete:q3map -> textures/shaderlab/concrete + One potential use is the -approx feature to collapse lightmapped surfaces + into vertexlit surfaces, saving lightmap space/memory + - New: q3map_clipModel -- does what you think it does, sort of. This code ix + really experimental, and should *only* be used on large models such as terrain + (not small decorative models). This code will be evolving. Note: the shader's + surfaceparms are inherited by the magic clip brush, so if you have nonsolid + in your model's shader that uses q3map_clipModel, then the brush will also + be nonsolid + + 03/11/2002 + TTimo + - cleaning up some cons stuff, checking that the setup building process is still good on Linux + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=622 + updated Linux setup to put the bitmap + + 02/11/2002 + ydnar + - PicoModel: replaced stricmp with _pico_stricmp + + 02/11/2002 + ydnar + - PicoModel: added obj.c and ms3d.c, removed wfobj.c + + 02/11/2002 + ydnar - seaw0lf + - Updated Q3Map2 to 2.3.29 sources + 2.3.29 + - Merged with latest CVS, fixed minor issues with matrix order + 2.3.28 + - Bug 654 (http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=654): + Fixed problem where brush faces, drawsurfaces, and surfaceparms weren't living + together in perfect harmony (terrain surfaceparms now inherited by brushes) + - Nodraw fog works now, albeit when you're underneath, surfaces above don't get + fogged properly. Could be good for foggy water where you want the above-water + portions to only be occluded by the water surface + - Bug 656 (http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=656): + Number of lightgrid points displayed (byte size is currently out of proportion + due to internal storage format) when Q3Map is called with the -info switch + - Fixed wack surface merging bug where code would attempt to merge triangles not + adjacent to the current set, causing bad lightmap projections on nonplanar + surfaces + - Fixed tiny 1-character bug in 2d lightmap texture allocator where adjacent + luxels were being checked for occlusion rather than the actual source luxel + 2.3.27 + - Fixed minor bug in scriplib bugfix where the last character in a file wasn't + being read. + - Fixed bug where 0-area or bogus triangles were causing crash in MapRawLightmap + if they used a shader with a normalmap (thanks ShadowSpawn) + - Fixed bug where lightmaps were getting hosed levelwide on a prerelease version + of 2.3.27 + - Fixed bug where lightmaps were getting knackered on models and certain patches + - Merged latest PicoModel version from seaw0lf, adding support for ASE and WF OBJ + models (preliminary) + - Increased MAX_MAP_PLANES to 0x40000 (~256k) + 2.3.26 + - Now using GtkRadiant's libpng and zlib config (linked as DLLs) + - Fixed bug in script parser where repeat calls to GetToken() were causing + memory corruption + - Fixed SOF2 -rename bug + - When using -game sof2 or -game jk2, the -flares argument is implied + - Added -noflares argument to disable the above behavior + - Added support for flares on entities. Use one of the following keys: + "_flare" "1" -- use default flare (different for each game) + "_flareshader" "path/to/flareshader" -- use a specific flare shader + Note: This only matters in SOF2/JK2 now. Make a light targetted (a spotlight) + to get it to aim the correct direction, otherwise it defaults to pointing + downward. You cannot have omnidirectional flares + - Lightgrid size is automatically increased to accomodate large maps. The + MAX_MAP_LIGHTGRID error will never happen again + - Update PicoModel to 0.8.7 sources + - ASE support + - Alias|Wavefront OBJ support + - .remap shader remapping suport + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=655 + handle grayscale jpegs gracefully + - mathlib: fixed VectorClear(), got rid of braces + - scriplib: fixed double-free memory corruption bug + - radiant: added new color scheme to emulate Lightwave/Maya/3DS Max + + 02/11/2002 + TTimo + - too many issues with build system reading system's libjpeg.h instead of libs/libjpeg.h + renamed libs/libjpeg.h to libs/radiant_libjpeg.h, updated sources + + 29/10/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=639 + running from a network share - saving prefs per-user + + 27/10/2002 + TTimo + - merged in some more m4x4 code for q3map2 + - fixed unresolved code in picomodel (strlwr / strnicmp) + - reworked the tools building to build both q3map and q3map2 without trouble + + 25/10/2002 + ydnar + - q3map2 and picomodel source, initial checkin to Stable-1_2 branch (does not compile yet, tweaking to be done) + + 23/10/2002 + TTimo + - camera.dll goes into $(RTCWRADIANTDIR)/plugins instead of $(RTCWRADIANTDIR)/modules + fixed up camera compile (exports) + added camera bitmap (plugin toolbar) + + 21/10/2002 + TTimo + - quickfix to the build (typo) + - changed dynamic linking on Linux to look for libGL.so.1 by default + fixes "all textures are blank" Linux bug with NVidia cards + (you still have to have a working NVidia GL installation though, xlibmesa-dev on Debian screws things up) + - checked in modified q3 .qe4 with q3map2 menu (see bug #638) + + 09/10/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=622 + reworked the plugin toolbar to rely on interface instead of straight exports + cleaned up the botclip monsterclip Brush_Draw filtering, added proper selection filtering (Brush_Ray) + merged bug-622 back into Stable-1_2, bug-622 branch is dead now + + 06/09/2002 + James Monroe - RR2DO2 - TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=619 + light globes, applying patch by RR2DO2 built from the initial light globe code + - note to self: indent -kr -nut -st -ts2 -i2 + + RR2DO2 - TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=622 + massive patch update from SD's GtkRadiant + - camera plugin: new bitmap + fixed Linux install path for camera plugin to wolf/plugins + - fixed various warnings in camera build gcc / Linux + - fixed pref crash if plugin toolbar disabled + - fixed Gtk-WARNING on bad cast in AddPlugInToolbarItem + - renamed the new select to 'Use paint-select in camera view:' in prefs + (camera paint-select, should be our default name for this) + + NEW: you can 'paint select' in the camera view: 'camera paint-select' + press shift and move the mouse over the camera view to paint over brushes you want to select + configurable in prefs to enable / use Shift key, or use 'classic mode' ctrl+alt + + NEW: light radius drawing + Added in-editor light envelope drawing. Outer circle is max envelope, + inner fullbright radius. Optional classic mode emulates the similar drawing + from Rituals and Ravens tools (not q3map correct, easier for the level designer + to understand/legacy). + + NOTE: 'angles' is q3map2 only + NOTE: could manipulate angles directly from the views (2d and 3d with some handles) + + NOTE TO SELF: + hey guys .. just a quick question if you don't mind .. I'm trying to track a Gtk-WARNING .. is there a way to make those apps cause a break to track them easily ? + just run your app with --g-fatal-warnings + + TODO: add new bitmap to win32 & linux setups + TODO: don't use exports for the plugin toolbar, use entry functions + do something like CPlugIn::InitBSPFrontendPlugin + TODO: botclip is broken with the new Brush_Ray code + + initial ChangeLog for the patch: + + 28-09-2002 + Arnout + + Added 'angles' support for models (misc_model/misc_gamemodel). + + Prevented pivot drawing of model from scaling and rotating. + + Cleaned up the dropdown boxes in the preferences a bit (all use + tables now, so not multiline). + + Added 'Classic Key Setup' option to camera paint select configuration, this + drag-selects with ctrl+alt instead of shift. + + Changed XYWnd::PositionView to position on the center of the + selection, not on the mins. + + 27-09-2002 + Arnout + + Added in-editor light envelope drawing. Outer circle is max envelope, + inner fullbright radius. Optional classic mode emulates the similar drawing + from Rituals and Ravens tools (not q3map correct, easier for the level designer + to understand/legacy). + + 26-09-2002 + Arnout + + Upped MAX_TEXTUREDIRS to 256 (from 128). + + 25-09-2002 + Arnout + + Fixed patches not being drawn in XY window with colour of parent + entity. + + Made paste to camera snap destination spot snap to grid. + + 18-09-2002 + Arnout + + Changed Select_Reselect to be much faster. + + 12-09-2002 + Arnout + + Fixed curve point drag-selection area not showing properly in XY + views. + + Fixed size info breaking over 9999.9 units. + + Fixed AllocateSelectedPatchHandles not setting patchesmode to + ESelectedPatches. + + Changed the horizontal and vertical tc shift spin control to have a + limit of 8192. + + Moved SPoG's implementation of redisperse cols to a seperate function + and reinstated the old code. + + Added 'Paste to Camera', shortcut Alt+V, which pastes the contents of + the clipboard to the current camera origin. + + Added centerview functionality to 4 window mode. Ctrl+tab will focus + on the selection, or if non existant, on the camera. + + 11-09-2002 + Arnout + + Made sure settings set in savedinfo.bin get initialized to their + proper defaults. + + Added botclip filter (filters *botclip* and *monsterclip*). + + 10-09-2002 + Arnout + + Removed .reg from normal map saving, can only save as region + using 'Save region'. + + Added outline style cycling (j) cycle between z buffered outlines and + selected colour rendering. + + Added colour dialog to pick the colour of selected surfaces in the + camwindow. + + Third coordinate for clip points now gets set to the center of the + selection. + + Changed arbitrary rotation dialog to accept negative angles as well. + + Changed texture alignment dialog to accept values up to 2 decimal + points. + + Fixed entity inspector to say 'Textures:' in the window title. + NOTE: still broke in floating window mode + + Changed entity inspector so that tab doesn't clear the epair value + field anymore, so it retains the value while jumping to it. + + Disabling camera paint-select now returns selection behaviour for groups to + the old behaviour as well (shift+click selects whole group). + + Changed load_plugin_bitmap to load bitmaps from g_strAppPath if + g_strGameToolsPath fails. + + Added plugin toolbar and api. + + Fixed m_pfnCommitBrushHandleToEntity, wasn't creating brushes + properly (well, not at all really). + + Older changes: + Arnout + + Added misc_gamemodel drawing. + + Ported camera paint-select over from 1.3. + + Fixed statusbar display of text (removed a bunch of \n's). + + Added area selection in 3d view for patches. + + 30/09/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=556 + quickfix crash bug + + 27/09/2002 + TTimo + - more CORERADIANTDIR cleanup (q3data) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=602 + added cascading to the entity submenu (doesn't cascade the main menu, only the sub ones, NPC_* for instance) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=556 + with clip and caulk filtered out, won't be selected anymore in camera view (i.e. selecting invisible faces) + added SF_CAMERA to the flags in the selection process + cleanup up various ugly syntaxes in the selection code: + don't ever do if (flags == SF_SINGLEFACE) on a bitmask and assert that the other flags will always be NULL + don't do arithmetic on bitmasks: + if ( (flags & SF_ENTITIES_FIRST) && t.brush == NULL) + return Test_Ray (origin, dir, flags - SF_ENTITIES_FIRST); + is WRONG + using flags & ~SF_ENTITIES_FIRST is the appropriate way + + 23/09/2002 + Riant + - new IS scripts to go with recent media updates + Riant & TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=615 + reworked the fix to use "caulk_shader" in .game + updated IS .rul script to generate special values for Sof2 and JKII + + 21/09/2002 + Riant + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=595 + more texture compression, dialog and settings + Michael Schlueter + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=592 + fixes to the Linux build system, exclusive q3 or wolf working now + + 22/08/2002 + EvilTypeGuy + - Fix @*$&)@)$$ memory leak of my own doing, yes it's really been in there this long. + This should help memory usage drastically, especially when flushing & reloading + the same sets of textures, GtkRadiant's memory usage no longer becomes heinous. + + 14/08/2002 + EvilTypeGuy + - Fix build on some linux boxen by including qertypes.h for proper boolean type declaration + + -- release-1_2_10 + + 16/08/2002 + TTimo + - STVEF media update finalized (some .def) + - 1_2 Core Update for shader manual update + - in JKII, typo with nar_shader? replaced by nar_shaddar, with proper support in update too + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=530 + Q3/TA media update with cleaned up shaders + - validated the update content by a diff between 1.2.9 + 1.2.10-update and 1.2.10 full + - added a DO_NIGHTLY_BOOL to setup.rul AND a warning during setup about update content for games that are not installed + - built 1.2.10-sof2, SoF2 full install + + 15/08/2002 + Michael Schlueter + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=590 + added the option to build a Linux setup with the debug binaries + + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=530 + cleaned up shaders, done nightly setup update on Linux + updated Linux nightly for 1.2 to use /usr/local/games/GtkRadiant-1.2 as default base + - using version 1.2.10-update. Full Sof2 setup will be 1.2.10-sof2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=426 + don't straffe when using Ctrl+Shift(+Alt) + - camera.so RTCW plugin in Linux setup + - quickfix to non-initialized var in camera code + - awfull piece of work that had been completely left out, nightly elements for JK2 and STVEF + added JKII media update and STVEF media update (for the DIR_GAME elements) + JKII nightly is finalized + + 14/08/2002 + TTimo + - fixed a missing file + - Linux build quickfix + - fixed silly rendering bug + - added pref to force texture compression off (hey why would you do that??) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=466 + fixed MAX_POINTS_ON_WINDING overflow in q3map (and relevant code to handle in radiant) + + 13/08/2002 + TTimo + - cleared up notexture (dead code) + - cleaned up QERApp_LoadTextureRGBA gamma table init + - having a shot at 1.3 texture compression + sees the extension, binds the texture with the currect setting + but rendering is fucked .. someone explain? + + 08/7/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=586 + search and destroy Q3Radiant -> Radiant + + 07/7/2002 + SCDS_reyalP + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=526 + wolf_entities.def update + + riant + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=548 + STV:EF updates + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=541 + SOF2 updates + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=584 + JKII updates + + 06/7/2002 + Riant + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=541 + Sof2 patches and IS setup + TTimo + - game pack prompt asking about STVEF, fixed + - mp_examples was leaked and non lighted, fixed + - imagepng.dll goes into Sof2 install / modules, and not in DIR_CORE + - libpng12.dll needs installed only with Sof2 pack (added 'SOF2 Pogram DLL') + default texture scale is 0.125 + + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=582 + nomipmap -> nomipmaps in shader manual + - removed libs/pak, this was still being linked in to Radiant, but not used at all + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=580 + .PK3 are recognized along .pk3 files (strcmp ->strcasecmp) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=386 + added the RTCW camera plugin to IS setup + + Michael Schlueter + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=581 + GL warning fix + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=567 + GL font display fixes (mostly Linux) + applied the changes with some tweaking + + 31/6/2002 + TTimo + - compiling the camera plugin on Linux: + move the GUID and other misc compatibility definitions to include/misc_def.h + GetTickCount being used in camera.so, this is from radiant/missing.cpp (unresolved) + -> use QGetTickCount instead (in main function table) + + 30/6/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=530 + cleaned the .shader from 'light 1' statements + updated the IS script for the updated .shader + + 17/6/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=541 + Sof2 support, PNG format + wrote imagepng module, dynamic dependencies to zlib and libpng + changes in the core: + some hardcoded to "sof2.game" for png interface loading and extensions + in GetTextureExtension, killed outdated support for texture plugins + if ! "sof2.game", png is not loaded, support disabled + http://zerowing.idsoftware.com/libpng/ + correctly configured for VC build (post build steps and dependencies) + is required on win32 to build imagepng + - added m_pfnGetGameFileName to the main function table (was needed for png stuff) + - cleaned up the QERApp_LoadTextureRGBA path + using (unsigned char* pPixels, int nWidth, int nHeight) + cleaning up internal access path + RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=386 + camera plugin for RTCW + TTimo: wrote the .dsp, post build steps etc. + IMPORTANT: you need to have RTCWRADIANTDIR env variable pointing to the RTCW Radiant files + (default C:\Program Files\Return To Castle Wolfenstein\Radiant) + + + 12/6/2002 + RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=299 + MP/SP pk3 filtering in VFS + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=386 + .camera support: splines library, camera plugin + TTimo: portability fixups, cons build, guarding pragma, __cdecl BOOL + virtual functions but non-virtual destructor + declaration with no type + int idCameraFOV::start - control reaches end of non-void, making it void + enumeration not handled in switch + no _MAX_PATH, the portable one is PATH_MAX + implicit declaration of int _fullpath + for(int i = 0; .. + struct _IO_FILE has no member named '_bufsiz' + stricmp -> Q_stricmp + attempt at implementation in .h file (InitIglToQgl) + camera stuff still vastly broken (particularly on Linux), need to check in because of new fixes incoming + djbob + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=17 + quick fix to spawnflags getting corrupted when multiple entities selected + (doesn't completely solve the problems we have with spawnflags yet though) + +=============================================================== +END -- merging release-1_2_9 -> merge-post-1_2_10 into trunk - END +=============================================================== + +12/12/2002 + Hydra + - #197, HL support update + +11/12/2002 + TTimo + - added cmdlib dependency to mapq3.so (fixes unresolved) + +25/10/2002 + Hydra + - vfsGetFullPath() can now (optionally) search PK3/WAD files + - Half-life map loading is now un-borked (my original patch worked + but some conditional code in the patch was incorrectly applied. + That, coupled with the missing vfsFileExists and vfsFindFile replacements) + - A patch to imagehl/lbmlib.cpp/LoadIDSP() was missed out, causing all sprite + models to be reverse-rendered (due to an inverted alphamask) + - Renamed HydraToolz to HydraToolz-HL as it's half-life specific + changed project files and renamed all appropriate files and directories + (for the merge, just delete contrib/hydratoolz and apply the diff) + + - Comments on previous notes: + + - TODO: need to rationalize where the modules are placed and identify HL specific modules + (this affects the build system / post build step too) + imagehl and spritemodel are halflife specific and can be placed in + either $coreradiantdir/modules or $hlradiantdir/modules + I've updated the .dsp files so that they are copied to $coreradiantdir/modules + spritemodel can actually be used for other engines, not just HL so it makes sense + to keep it in $coreradiantdir/modules + hydratoolz is a half-life specific plugin and must go in $hlradiantdir/modules as it + is NOT to be used for any other engines. I've also updated the "about text" to + reflect this. + +14/08/2002 + EvilTypeGuy + - fix build process for textool plugin on some Linux boxen by including qertypes.h + +11/06/2002 + TTimo + - spritemodels in build system + - applying HL setup patch (att 270, bug 197) + - the templating went one filename seperator too far, causing all *.fgl to be modified .. + fixed so that we only have the relevant changes + - modules added to main Executable Files, TODO for later will need to identify what is HL specific + - .game generation: don't want enginename yet, gamename is ok + - updated HL .game generation for eclass_singleload and no_patch + - update hydratoolz location in setup + - update maphl in synapse.config + +07/06/2002 + TTimo + - realized that \func doesn't work in doxygen, should be \fn (updated everywhere) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=197 + applying the HL patch (see original list of changes below) + - ugly eclass API changes + eclassfgd/plugin.cpp.rej, eclass API changes involved, a bunch of .rej + SupportsMultiple tries to send configuration information from the eclass format file module to the eclass manager + dropping it, using a proper configuration node instead (eclass_singleload) + - added "no_patch" prop to disable patch support + the patch toolbar prompts are only present in prefs if there is patch support + otherwise everything is force-disabled + - PFN_VFSFINDFILE PFN_VFSFILEEXISTS: + one of the problems we have is that the 'manager' code and file format code are in the same module + (i.e. vfspk3 / vfswad: two formats, but the manager part is pretty much the same) + vfsFindFile(relative filename): + this worked by searching through the list of loaded pk3/wad files for the file + then trying to search through the search directories + - wasn't properly documented about what it does / how is the search performed + - not consistent with existing code, duplicate of vfsGetFullPath for the most part + can't be added to the VFS API as-is, it would confuse the interface + - usage of vfsFindFile in the code doesn't justify the way it proceeds for search + foxing it, replacing by calls to vfsGetFullPath + vfsFileExists(relative filename): + returns wether a file exist, can be flagged to search in pk3/wad or straight filesystem + - this is a duplicate / particular case of vfsGetFileCount + foxing it too, we need to extend and update vfsGetFileCount instead + - mapq3: the changes completely fucked q3 map parsing + need reorganization. same module provides parsing for all .map based formats + we use wrappers around the actual calls and globals in the module to select formats + MAPVERSION_Q2 and MAPVERSION_Q1 don't need to be there yet, they are not supported + MAPVERSION_HL means WC >= 2.2 + (when introduced, MAPVERSION_Q2 would be Q2 or qer+hl plugin (same)) + MAPVERSION_HL uses "maphl" minor name (instead of mapq2) + cleaned up the Q3 read/write code that got broken + cleaned up various commenting/hack that deal with Q2!=HL format .. we'll see about Q2 when we actually do it + bad cut and paste from cmdlib code, using actual dependency to cmdlib instead (see below for some cmdlib updates) + - took out all SafeRead SafeWrite code from cmdlib, removed annoying cmdlib dependency to Error function + all file access go through VFS module, the cmdlib 07/06/2002 15:47file code was way old + - radiant/points.cpp pointfile code changes (that's used only for non-monitored compiling now) + - applied patch 267 (hydratoolz fixes) + - commented out some bworldcraft flagged stuff in mapq3/parse.cpp + - updated the .dsw .dsp to compile and copy HL stuff + - TODO: need to rationalize where the modules are placed and identify HL specific modules + - TODO: seems to be a synapse crash when unloading plugins (hydratools) + (looks like I didn't look at the plugin unload code yet actually) + - TODO: make sure HL setup puts eclass_singleload="1" and no_patch="1" + - TODO: WATCHBSP_KEY and TEXTURE_KEY hardcoded for HL need cleanup + - TODO: imagehl duplicates some image functionality + imagehl is supposed to be only for HL-specific image formats + it 'adds' the required formats to the stuff that image makes available for everyone already + - TODO: HL doesn't have a BSP menu! + - TODO: rename mapq3/ into map/, the map module handles all .map formats + - TODO: it's likely that we only need a vfs/ module instead of vfspk3/ and vfspak/ + think about it, see if we really act on this (or do we need to abstract the manager and some file format modules) + - TODO: HL synapse.config needs to use maphl + - TODO: wtf is enginename="quake2" in hl.game + - TODO: I don't have a sample HL map to play with, so I didn't test the changes against + +05/06/2002 + TTimo + - fixups to make 1.3 start (Q3 mode) + - turned off C++ exception support in the modules/plugins, as we don't use it + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=543 + exit properly if missing chunks in synapse.config, don't crash + + Hydra + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=558 + fix for version check in release build + + ====================================================================================== + -- http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=197 + HL support patch + ====================================================================================== + 04/6/2002 + Hydra + - Patched in some CVS changes and fixed a little issue with the + new entity file loader code. + + 28/5/2002 + Hydra + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=544 + Selected Entity Bounding Box obscured by brushes fix. + - Moved the "wad" keypair creation code from the Map module into + a new plugin called HydraToolz, this means that wad keypair is + done manually by the user, as in fact it should be. (as the + order of the wads is actually important). + - Fixed a problem with the wads in the wad list being re-ordered. + + 27/5/2002 + Hydra + - Created an inital implementation of a sprite model plugin. + According to the powers that be, it seems creating a model + plugin is hackish. + It works ok, but there is no way to attach models (sprites if you will) + to non-fixedsize entities (like func_bombtarget) + Also, I can't get the alpha map stuff right so I had to invert the alpha + mask in the spr loader so that 0xff = not drawn pixel. + + 17/5/2002 + Hydra + - "Wad" keypairs are now used when loading a map and speeds up map loading + significantly. This sorts out quite a few issues that could otherwise occur. + - Map loader now uses textures from wads listed in the the "wad" keypair first. + - Added a texture name mapping cache system to the .map loader + this significantly improves load times of maps that don't store texture + names along with paths (e.g. "mytexture" not "mytextures/mytexture".) + - Added vfsFileExists() to the vfs table (for above) and added it to + vfspk3 and vfswad + - Map loading and saving times are printed to the console. + - Wad file names from the "wad" key pair are logged to the console when + a map is loaded + - The user is informed if the textures loaded were not found in the + wad files in the "wad" keypair. + - The user is informed if the textures was not found in any wad file at all + (Q2/HL only, the shader module still gives you similar information for other + games when a shader activation fails) + + + 8/5/2002 + Hydra + - Added basic support in mapq3 for reading maps saved by Worldcraft 2.2+ + in .map format (It uses [ ]'s round some of the texture co-ordinates) + TODO: do we need to be able to save a map in this format too ? + - Added support for loading ZHLT style point files (*.lin) + - Added wad filename information when loading textures. + (This helps take the ambiguity out of which wad files textures come from, + so that we can correctly setup the worldspawn "wads" e-pair manually.) + Note: This will be removed when the "wads" worldspawn key is built by radiant. + - added vfsFindFile() to vfs table. + - VFSWAD: vfsLoadFile() no longer ignores paths when loading textures + (this was by design, but the design has changed for the better) + - When loading a Quake2 map file, vfsFindFile() is used to find the actual path of + the shader/texture being loaded. + This fixes all the weird issues that crop up when we were able to use non + wad-relative texture names () and wad-relative(/). + (such as having an image loaded twice in memory.) + We also now get the correct shader name in the suface inspector too. + Note: not sure if this code should stay in the map parser, or wether it should + be moved to where shaders are first initialised. + Note: maybe this needs to be when a halflife map is loaded, not specifically a + quake2 map file. + - added EClass_SupportsMultiple to the EClass loader API. + Note: this is poop. FGD files can be additive but radiant makes it so they can't be. + This function would not be needed if the eclass loader itself took care of the init, + rather then the manager taking care of the init. Also note that if the loader were + to take care of the init then FGD files *CAN* be additive, as it's not down to the + format of the FGD files. However, it'll do for the moment because all the supplied + FGD files that come with halflife and it's mods are meant to be used one at a time. + - removed support for having an additional (not external) eclass loader. + Just ifdef'd for now, grep for USEADDITIONALECLASSLOADER. + We never mix entity definition formats and synapse.config allows us to just have the + right one and also there is no mechanism for setting g_bHaveEClassExt anymore. + - Texture subset on by default for halflife. + - default texture scale is now set to 1 instead of 0.5 for halflife. + (needs to be 1 for q1/q2 too) + - patch toolbar disabled by default for halflife and it's also disabled + in the preferences so it can't be turned back on) + (needs to be 1 for q1/q2 too) + - bsp monitoring disabled by default for halflife + - When you drop a light entity the epair "_light" is used instead of "light" (halflife specific) + - removed -fs_game additions to the map compiler commands; ZHLT doesn't support it. + - saving of contents/flags/values in q2 format maps disabled (ZHLT doesn't like em !#?!) + TODO: re-enable for Q2 (but not halflife) format maps when we can + can figure out what game/engine combo we're using from within a module + - configured mapq3 to have dynamic VFS API too + - Added halflife shaderlist.txt parsing back in, it's actually useful + afterall (for editor shaders). + ====================================================================================== + -- end HL support patch + ====================================================================================== + +01/06/2002 + TTimo + - merging 1.2.7 -> 1.2.9 changes into 1.3, merge notes: + - the win32 .dsp are a bit different, using the $(CORERADIANTDIR) post build commands now + - merged in the JKII/STVEF hardcoded chunks, should probably check that everything is still fine on that end + was setting the "dir" epair in project files intead of "gamename" like all other games? + (which should really be "fs_game" anyway, I wonder who decided to call it "gamename") + - rebuilt a setup. we have a problem with RADIANT_MAJOR RADIANT_MINOR it seems + TODO: setup needs to use GtkRadiant-1. as basename in start menu, and base for installation + C:\Program Files\GtkRadiant-1.3 and C:\quake3\Radiant-1.3 etc. for the game packs + TODO: add HL setup chunks! + +=============================================================== +-- merging release-1_2_7 -> release-1_2_9 into 1.3 +=============================================================== +28/5/2002 + TTimo + - final fixes for Linux 1.2.9 setup + +27/5/2002 + TTimo + - bug 521, q3 entities.def trigger_hurt fix + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=542 + default texture scale is configured in .game + defaults to 0.5 (q3/wolf) if nothing specified, under the prop "default_scale" + removed the item from the prefs dialog too + updated the nightly setup to put the proper param in JKII .game + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=509 + changing texture window scale changes selected brushes texture + re-selecting the previous texture can be done, but is a bit tedious to write + made sure we deselect before re-init of the tex window view + - fixed linux setup code bug. won't be any update, only a full release on linux + +26/5/2002 + TTimo + - parallel cons working at last! was a problem with the targets list ('Default' command) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=515 + using the eclass extents for the box if model can't be found + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=435 + changed the submenu cascading params to avoid the overlap (we fit less stuff now obviously) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=540 + that sigchld handler is only used on Linux to report the run times + since we are rewriting the whole BSP code stuff, we can drop this for now + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=538 + removed that prompt and display + - we build radiant.x86 in cons scripts, updated the setup code + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=526 + updated the setup script to install new wolf_entities.def + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=302 + added q3map2 URL to global.xlink, updated Linux setup + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=465 + printing q3map version info through the net stream + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=539 + fixed various media, some related code, and Linux setup + - fixed watchbsp.cpp "jk2.game", was breaking game spawn for wolf (needed else if) + + SCDS_reyalP + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=504 + fixed bobtoolz vis viewer to work with RTCW (BSP version) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=526 + update of the Wolf entities file + +25/5/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=164 + corruption on exit, tried to look some more. Cleaned up some source, need looking at Gtk code closer + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=536 + cleaned up SHADER_NOT_FOUND SHADER_NOTEX internals some more + added a clean error exit in case this happens, fixed a crash that would happen anyway (Patch_LODMatchAll) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=394 + cleanup/sanitize of the pattern filtering code, it was ugly. did some doxygen documentation + fixed part of the print XY code, more broken stuff showed up, dropping it + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=503 + region compiling was indeed fucked, spog b0rkage + fixed so that it works again + denying compile with camera out of the region + reworked SelectBrush to deal with regioning and select the right brushes + +24/5/2002 + TTimo + - Linux build fix + +23/5/2002 + Riant & TTimo + - STVEF patch and setup scripts + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=516 + moved error handling code to it's own file radiant/error.cpp + compiled with UNICODE define (that's why I had to isolate), and process the error string + so that Gtk can print it (that's only relevant to win32) + +22/5/2002 + TTimo + - quickfix, cleanup of the console verbosity + +11/5/2002 + TTimo + - final IS script updates for JKII game pack, version 1.2.8-jk2 + - fixed a bad karma #ifdef _DEBUG chunk in Texture_NextPos (causing crash of release build) + - added web url support in .xlink files (strstr on http://) + +10/5/2002 + TTimo + - cleaned the build step copy from $(QUAKE3RADIANTDIR) to $(CORERADIANTDIR) + - system shaders auto-load: display 'system' in the prefs + - force BSP monitoring off in jk2 mode + - cleaned up web update check, added HL (3) and Jedi Knight II (number 4) (on the web database too) + - updated IS setup script for mapextras.pk3 + Riant + - system shaders auto-load in prefs + Raven + - mapextras.pk3 as replacement for system.pk3 (system editor textures) + +8/5/2002 + Riant + - game pack and patches for JKII support + TTimo + - .game additions to specify .shader path (shaderlist and shader scripts) + NOTE: if we ever use q3map for JKII compiles, that would need to be propagated + - reworked the shaderlist to list all the included shaders + - built a system.pk3 pack for textures/system/ and textures/radiant/ (misses a few pieces still) + - MP / SP mapping mode toggle, SP ignores mp_*.def MP ignores sp_*.def + - fs_basepath does not get added during BSP command expansion for JKII mode + - more verbose on script location and junk.txt location when monitored compile is disabled + (the BSP compilation WANTS to be rewritten, it's getting VERY URGENT) + - JKII game back IS setup lands + +7/5/2002 + TTimo + - using radiant.x86 as Linux target (instead of radiant, didn't fit with the setup procedure) + - bumped version tag + - TODO: bug #453 code needs backported from 1.3 + +6/5/2002 + TTimo + - fixed typo in plugins/mapq3/write.cpp Map_Write + g_count_entities = 0; instead of g_count_brushes + - more fixes which showed up while merging this with 1.3 + +-- release-1_2_7 ----------- tagged and Stable-1_2 merging into trunk + +02/5/2002 + Gef + - added filtering on unselect for newly created brushes/entities (bugzilla: #374) + SPoG + - added undo for pasted/cloned brushes + +============================================================ +-- end release-1_2_7 -> release-1_2_9 merge +============================================================ + +15/05/2002 + TTimo + - rewrote the ref count code cleanly, added some elements to design and todo + - wrote the core shutdown code of synapse, 1.3 exits cleanly without crashing (well, in most cases it seems) + +10/05/2002 + TTimo + - began writing proper unloading and shutdown of synapse (see libs/synapse/docs/unload.txt) + design doc started, non active modules are unloaded after startup + need win32 implementation of ReleaseSO + - quickfix on win32 (ReleaseSO) + +07/05/2002 + SPoG + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=512 + - cleaned up strHomeMaps and strFSBasePath stuff + prompts for maps, models, sounds etc are fs_game-dependant + + =========================================================================== + -- merging Stable-1_2 between Stable-1_2-tag and release_1_2_7 into trunk + merge ChangeLog + ============================================================================= + 07/05/2002 + - using RADIANT_MAJOR_VERSION and RADIANT_MINOR_VERSION for the version info, this was conflicting with synapse + + - m_strHomeMaps + http://zerowing.idsoftware.com/viewcvs/viewcvs.cgi/GtkRadiant/include/qertypes.h.diff?r1=1.27&r2=1.28&only_with_tag=MAIN + http://zerowing.idsoftware.com/archives/gtkradiant/2002-February/002170.html + posted on the ML, bringing it back in from 1.2 + + setup scripts: + easily merged, as the 1.3 scripts have not been touched mostly + + qe3.cpp conflict: + 1.2 tweaks stuff in the QE_*Project* functions + 1.3 has them mostly commented out + applying manually where relevant + the project settings stuff is very different, and the changes can't be applied as is + given the fixes I had to do in 1.2, I'd expect the current 1.3 version to be fairly broken + a complete kill and rewrite of the prefs/project stuff might be our option anyway + http://zerowing.idsoftware.com/archives/gtkradiant/2002-May/003038.html + qe3.cpp QE_InitVFS conflict: + 1.3 has some changes when creating the files in a new userprefix (ex. ~/.q3a/baseq3/scripts /maps /maps/prefabs etc.) + merged by hand, probably needs to be checked + qe3.cpp OpenDialog SaveAsDialog conflict: + commented out in 1.3, getting rid of it completely + + preferences.cpp conflict: + 1.2 adds CUSTOMSHADEREDITOR_KEY pref + 1.3 uses a completely different syntax for prefs + preferences.cpp conflict: + prefab path pref changes conflict with 1.3 pref syntax + applying changes manually to 1.3 codebase + + pmesh.cpp conflict: + 1.2 adds pref to group / not group patch thickening + 1.3 changes the way we manipulate entities around that code + merged manually, would be worth checking that the thicken pref works + + pluginmanager.cpp conflicts: synapse completely changes that part + on relevant 1.2 thing is the removal of pfnRadiant_Free + + map.cpp Map_ImportEntities conflict + 1.3 has bug 453 map conversion promt that was not backported to 1.2 (caused merge to conflict a bit) + usin 1.3 code and checking 1.2 changes manually + + using radiant.x86 as Linux target (instead of radiant, didn't fit with the setup procedure) + + 06/05/2002 + not merging in .dsw .dsp + an eclass.cpp fixed moved to eclass_def.cpp + mainframe.cpp is always a bitch to merge, sent several mail comments to list about conflicts that arose + MainFrame::OnFileSaveas needed some updates that were not in the diff (correct default prompt) + (same for MainFrame::OnFileSaveregion) + MainFrame::OnFileNewproject conflicts a bit, changes have been made in 1.2 and 1.3 + changes in 1.2 seem more crucial, using the 1.2 version, and patched the 1.3 manually over it + (might need to be checked, bug #506) + + TODO: need to check for parasite g_free that I added back from the file dialog + + propagated ChangeLog from Stable-1_2 + ============================================================================= + 02/5/2002 + Gef + - added filtering on unselect for newly created brushes/entities (bugzilla: #374) + SPoG + - added undo for pasted/cloned brushes + TTimo + - shift+left click to open shader editor no longer selects the texture on the way + (this was unstable, pCurrentShader could become NULL somehow) + - editpad bindings were completely broken + attempts to make it work again failed + taking it out + changed the prefs, on win32 you select between internal shader editor or win32 .shader binding + we have lost the ability to jump to a given line, if someone has a good solution for line jumping, let me know + - one more fix to the MAJOR / MINOR safe checks stuff + - bug #500: oooogly, I removed a line which I should not have :) + + 01/5/2002 + TTimo + - "Save selected.." load/save in fs_game sensitive directory too + - removed a bunch of unused/broken project settings items + removed most of them actually .. project settings are .. ahem + - added an optional 'go to url' button in gtk_MessageBox + + 30/4/2002 + Gef + - fixed lod drawing of selected patches when patches are filtered + + 29/4/2002 + TTimo + - bugzilla #467 + make patch inspector deny space textures + make mapq3 write code drop space textures + - bugzilla #132 + removed remotebasepath and texturepath + rewrote the Textures > Load Directory (which was kinda relying on texturepath) + - bugzilla #355 + uploading editpad zip to qeradiant.com misc/ in files section, replacing the win32 message about editpad + added editpad quote in qer.com totd + - fixing the map load/save dialogs to work correctly with mod settings on win32 (was done on Linux and still broken on win32) + + + 26/4/2002 + Gef + - fixed patches losing their shader if outside region when calling flush/reload + (bugzilla: #492) + - blocked textures with spaces from loading in Texture_ShowDirectory with a warning + (bugzilla: #467) + - fixed a dud shader (liquids.shader -> textures/liquids/ripplewater2_back) didn't have + the textures/liquids prefix + + 25/4/2002 + Gef + - fixed a broken image link in the shader manual (bugzilla: #486) + - changed prtview to use ~/.radiant//prtview.ini instead of + ~/.q3a/radiant/prtview.ini on linux + - fixed prtview loading/saving config (bugzilla: #424) + TTimo + - removed QERApp_RadiantFree from the function table + we can malloc and free across modules configured correctly for the CRT (Common Runtime DLLs) + cleaned up related broken malloc / free strategy in the plugins (vfsLoadFile uglyness) + - added main build date and version to curry / pk3man / prtview + + 23/4/2002 + SmallPileOfGibs + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=229 + flush and reload was affecting texturing of selected brushes + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=489 + File > Check for update menu item, jumps to the website and checks for update + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=431 + win32 part, RADIANT_MAJOR RADIANT_MINOR written out by setup + - more stuff on File > New Project and common mod setup issues (not finished yet) + + 22/4/2002 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=431 + reworking a bit the installer stuff + wrote the version checking + needs testing on win32 (RADIANT_MAJOR and RADIANT_MINOR are required in the install now) + + 21/4/2002 + TTimo + - trying more seriously to get a new nightly out + updating the ChangeLog for current 1.2.7 from this file + cleanups, browsing through the bugs to close/update/fix + - http://zerowing.idsoftware.com/bugzilla/showattachment.cgi?attach_id=197 + I kinda fixed that myself already, going through the diff and applying the missing stuff + creating the prefabs/ dir in QE_InitVFS + - added a line about the games dialog / auto-select at startup in the dialog frame + + 15/4/2002 + TTimo + - cleaning some old commented out map load code + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=477 + on Linux: + - strHomeMaps was init without taking care of m_strFSGame + - SaveAsDialog was not using strHomeMaps + NOTE: should strHomeMaps be spcific to Linux, or we will do better if we unify + need similar checks on win32 + + 13/4/2002 + TTimo + - kicking the source to generate new doxygen on zerowing + + 09/4/2002 + Gef + - setting the sel_mode accordingly when (i)nverting selection, verts were being drawn when + they shouldn't have been + + 05/4/2002 + Gef + - fix File/New Project for mods so it doesn't fail if the dir exists (bugzilla: #459) + - add Linux-isms for New Projects & read/write permissions... + note: for a total conversion, basepath needs to be manually set + - prevent opening multiple internal shader editor dialogs + - added preference for using a custom shader editor + - set horizontal scrollbar to be automatic instead of never for entity keyval list (bugzilla: #4) + - added a call to Select_Reselect() in XYWnd->OnViewEntity() to make sure its modifying the + current selection (bugzilla: #436) + - fixed entity dialog passing events through to main window (bugzilla: #454) return values + were backwards + - patching in the .pfb extension adding stuff (bugzilla: #259) + - fixed thickened patches not being grouped (bugzilla: #226). this was supposed to be happening + anyway, the entity create code was called before the patches were selected + + 02/4/2002 + EvilTypeGuy + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=457 + add entity #X and brush #X comments back to saved .map files + + 24/3/2002 + Hydra & TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=444 + only show empty alpha channel warning if the tga texture is actually 32 bit + (24 bit would always have empty alpha, the warning was useless in this case) + + 19/3/2002 + Gef + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=217 + - Set show value to true for angle and movement velocity sliders in preferences + - Increased the maximum value of angle velocity from 6 to 100 + + 18/3/2002 + SPoG + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=419 + fixed File->Save with region active acts the same as File->SaveRegion for ents + + + end merge + ============================================================================= + +16/4/2002 + SPoG + - fixed MDC_XYZ_SCALE value + +12/4/2002 + SPoG + - fixed win32 compile error - vc6 being nitpicky + - fixed refcount init on CSynapseAPIManager + - cleaned up md3model win32 project file + +9/4/2002 + Gef + - added nudging for selected brush and patch vertices (bugzilla: #240) + - added selected brush vertex highlighting + - sorted all the ID_'s in HandleCommand alphabetically to make it easier to track things down + - setting the sel_mode accordingly when (i)nverting selection, verts were being drawn when + they shouldn't have been + +5/4/2002 + EvilTypeGuy & djbob + - patched in djbob's grid minor/major color settings for gridsize < 1 + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=24 + +1/4/2002 + TTimo + - configured md3model to have dynamic VFS API too + - cleaned up texwindow.cpp texture extension loop + - updated current HL media with hl's synapse.config + http://zerowing.idsoftware.com/stuff/HL-media-0401.zip + - checking in new synapse.config for Q3/RTCW + - fixed win32 project files, removed hltoggle.h + - bumped version to 1.3.3 + +31/3/2002 + TTimo + - XML runtime configuration of synapse + uses a synapse.config in the gametools path, we can add a line in the .game to specify the file later on + - various cleanups and removal of dead code + - Linux build system: sanitized CFLAGS, libxml, STLPort and glib include path all in the toplevel Construct file + - removed the 'cons -- halflife' option, the binaries are unified again + - cleaned up image loading + + +29/3/2002 + TTimo + - patching in Hydra's code for Half-Life, builds and runs on Linux, need to quickfix on win32 now + - build system on Linux: some things are still hardcoded into the core, you need a different core + for Q3/RTCW or HL for now. do ./cons -- halflife to build HL mode (build trees are seperate) + - there is no media / install procedure yet, but a zip with what you may need for install is available: + http://zerowing.idsoftware.com/stuff/HL-media-0329.zip + - cvs added all the new files + - patched various things from the patches, don't have a precise list + cleaned up the interface requests, isolated HL specific between TMP_HALFLIFE defines + removed 'tga' from imagehl, two modules providing the same API has unexpected results + + TODO: the image loading is the main problem right now. We should not have any place that scans the + extensions, this is done internally to the image load manager? texwindow.cpp does enumeration of the + minors too .. but that may be legal in this case. + + TODO: synapse config at runtime through XML (rather big piece) + + - fixing build on win32 + bad coding practices: 'for (GSList *choicelst = ..' + added a quick hack include/hltoggle.h for easy switch q3/rtcw or hl compile + (remaining hardcoded stuff is temporary) + + +28/3/2002 + Gef + - added linux pthreads support to tools + - removed old terrain.c and lightv.c from q3map2 Conscript + +27/3/2002 + Gef + - updated cons for q3map 2 + - minor q3map2 fixes for linux compile errors/warnings + - minor warning fix in map.cpp + SPoG + - changed entity_addtolist to add entities to end of list instead of beginning + - added eclass_forname to eclassmanager interface + - fixed setting eclass before model-update for entities loaded from map + - fixed setting bounding box for models after model-update + ydnar - q3map2 + - fixed crash on -connect and other gremlins related to argument processing + - removed flag that prevented Castle's maps from compiling + + +27/3/2002 + + Hydra + + Important Changes: + + - Added VFSWAD modules for extracting textures from WAD files. + - Added ImageHL for loading textures contained in WAD files + - Updated shaders source code so that you can produce ShadersHL.dll + (single minor using #ifdefs) + - MapQ3 source updated so that it can load and save q2 format maps + provides a multiple minors. + - Added EClassFGD for loading FGD definition files + (I documented this code quite well, if you're interested...) + - Added support for iconsprite() settings in the FGD loader, we set + eclass_t->skinpath with the name of the sprite + TODO: write a sprite model plugin. + + Fixes: + + - Fixed incorrect line numbers being reported when script files had // comments in them + - Removed EClass_Create from the EClass manager _EClassManagerTable + - Replaced all occurences of "textures/radiant/notex" in shaders.cpp with a define. + - Fixed a crash in shaders.cpp when there was no default texture. + - Fixed a possible issue with g_bCancel_Map_LoadFile + - Added a crash fix for uninitialised patchMesh_t->pSymbiot + + Core Changes Required for HalfLife Support: + + - Set MAX_FLAGS to 16 to support Halflife's extra spawnflags, adjusted + entity inspector to display the new spawnflags, updated FGD loader + to load them correctly (previously it only loaded the ones with values <8) + (Done without breaking the old Q2 code that was commented out) + - Added GetTokenExtra to the _ScripLibTable + - Kludged texwindow.cpp to allow loading extension other than "tga" and "jpg" + TODO: ttimo, we need something in synapse to help with this. + - Plugin manager requests different API's depending on .game file used. + TODO: this needs to be done on a PER GAME basis, not PER .GAME FILE. + - Shaderlist.txt is not parsed on startup if hl.game is used. + TODO: this needs to be done on a PER ENGINE basis, not PER GAME. + + Cosmetic Changes: + + - Changed MAPQ3's minor_name from "map" to "mapq3" (also adds "mapq2" as a minor) + - Changed XMAP's minor_name from "xmap" to "mapxml" + - Changed VFS's minor_name from "quake3" to "pk3", more inline with VFSWAD now. + - Changed file/Load to file/Import on the menus + - When a shader (Q3/HL) is not found a message is displayed in the console + (only once for each shader that is not found). This is so the user can + quickly get a list of missing textures/shaders. + +26/3/2002 + ydnar + - initial q3map 2.0 source import + new tools/quake3/q3map2 directory + common/qfiles.h and common/surfaceflags.h modified + affects q3map 1.x too, bumped MAX_MAP_BRUSHSIDES to 0x40000 + will need to write the build scripts and compile on Linux too + SPoG + - Re-added dialog prompting user to convert/change-mode/abort when map BP mode + conflicts with project settings + - large entity/models update + +++ include/ientity.h 25 Mar 2002 11:37:54 -0000 + entity module + - interface cleanup + - common #defines for easy transition + +++ include/igl.h 25 Mar 2002 11:37:55 -0000 + opengl module + - Vertex Arrays support + +++ include/imodel.h 25 Mar 2002 11:37:57 -0000 + model module + - interface cleanup + +++ libs/mathlib.h 25 Mar 2002 11:37:59 -0000 + vector macros - cleanup + m4x4 + - documentation of matrix layout + - interface for utility functions for axis-angle and quaternion rotations + - interface for new utilities for specifically transforming points/normals + aabb + - interface for faster aabb-ray test without finding intersection point + - interface for utility to calculate an aabb to contain a transformed aabb + +++ libs/mathlib/bbox.c 25 Mar 2002 11:38:01 -0000 + - cleanup of use of qboolean + - implementation of fast aabb-ray-test + - implementation of aabb-for-transformed-aabb + +++ libs/mathlib/m4x4.c 25 Mar 2002 11:38:02 -0000 + - implementation of utility for rotation matrix from axis-angle/quaternion + - cleanup of implementation of matrix multiplication functions (optimise for in-order array traversal) + - implementation of new utilities for specifically transforming points/normals + +++ libs/mathlib/ray.c 25 Mar 2002 11:38:02 -0000 + - replace use of m4x4_transform_vec3 with new point/normal specific utils + +++ plugins/mapq3/plugin.cpp 25 Mar 2002 11:38:06 -0000 + - rename g_EntityTable using #define in ientity.h + +++ plugins/mapq3/plugin.h 25 Mar 2002 11:38:06 -0000 + - rename g_EntityTable using #define in ientity.h + +++ plugins/mapxml/xmlparse.cpp 25 Mar 2002 11:38:06 -0000 + - buffer-safe dtd path construction (without using string class, in case of unknown bugs) + +++ plugins/md3model/Conscript 25 Mar 2002 11:38:06 -0000 + - remove entity-module files from md3model conscript + +++ plugins/md3model/md3model.cpp 25 Mar 2002 11:38:07 -0000 + - implementation of generic quake-style-model class CModel + - implementation of CModel-derived md3/mdc classes + +++ plugins/md3model/md3model.dsp 25 Mar 2002 11:38:08 -0000 + - remove entity-module files from md3model dsp + +++ plugins/md3model/md3model.h 25 Mar 2002 11:38:08 -0000 + - interface for generic quake-style-model class CModel + - interface for CModel-derived md3/mdc classes + +++ plugins/md3model/md3surface.cpp 25 Mar 2002 11:38:09 -0000 + - implementation of generic quake-style-model class CSurface + - implementation of CSurface-derived md3/md2/mdl/mdc classes + +++ plugins/md3model/md3surface.h 25 Mar 2002 11:38:09 -0000 + - interface for generic quake-style-model class CSurface + - interface for CSurface-derived md3/md2/mdl/mdc classes + +++ plugins/md3model/plugin.cpp 25 Mar 2002 11:38:10 -0000 + - provide support to synapse for loading md3/mdc/mdl/md2 models, and mdl images + +++ plugins/md3model/plugin.h 25 Mar 2002 11:38:10 -0000 + - interface for loading md3/mdc/mdl/md2 models, and mdl images + +++ radiant/brush.cpp 25 Mar 2002 11:38:18 -0000 + - #ifdef remove Group/Brush-Patch-Epair related stuff + - const correctness for ValueForKey interface const change + - add bounding-box update for models in Brush_Build + - remove old brush parsing/writing stuff + - remove old eclass-model loading/displaying stuff + - enable vertex arrays on light drawing + - moved brush is-selected? utility to brush.cpp + +++ radiant/brush.h 25 Mar 2002 11:38:18 -0000 + - comment out interface for old brush parse/write stuff + - comment out interface for brush epair stuff + +++ radiant/brush_primit.cpp 25 Mar 2002 11:38:20 -0000 + - remove old brush-primitives parsing/writing stuff + +++ radiant/camwindow.cpp 25 Mar 2002 11:38:23 -0000 + - moved brush-bbox update for models to brush.cpp:Brush_Build + - bugfix for material colour setting when drawing models + +++ radiant/eclass.cpp 25 Mar 2002 11:38:24 -0000 + - removed old eclass-model checking/loading stuff + - added const checking for Eclass_ForName interface + +++ radiant/entity.cpp 25 Mar 2002 11:38:26 -0000 + - REMOVE THIS FILE + +++ radiant/entity.h 25 Mar 2002 11:38:26 -0000 + - REMOVE THIS FILE + +++ radiant/groupdialog.cpp 25 Mar 2002 11:38:29 -0000 + - change entity creation to not use Entity_Create (function was removed) + - commented groups stuff + +++ radiant/gtkdlgs.cpp 25 Mar 2002 11:38:36 -0000 + - const correctness for ValueForKey + +++ radiant/gtkmisc.cpp 25 Mar 2002 11:38:39 -0000 + - added filetype patterns for mdc/mdl/md2 + +++ radiant/main.cpp 25 Mar 2002 11:38:41 -0000 + - const correctness fixes + +++ radiant/mainframe.cpp 25 Mar 2002 11:38:59 -0000 + - change selection -> merge entity and selection -> separate from entity to go through mainframe class + - implementation of mainframe functions for selection -> merge entity and selection -> separate from entity + - made entity grouping and detail/structural settings undoable + - commented out old groups stuff + +++ radiant/mainframe.h 25 Mar 2002 11:39:01 -0000 + - interface for mainframe functions for selection -> merge entity and selection -> separate from entity + +++ radiant/map.cpp 25 Mar 2002 11:39:04 -0000 + - const correctness fixes + +++ radiant/pluginmanager.cpp 25 Mar 2002 11:39:08 -0000 + - removed model table + - stopped requesting model table from synapse + - request undo table from synapse + - commented out support for IEpairs stuff - NOTE: to be integrated with entity module + - fill interface table for opengl vertex array support + - fill interface table for undo + +++ radiant/pmesh.cpp 25 Mar 2002 11:39:18 -0000 + - cleanup patch cap and patch thicken to create entities using entity module interface (without Entity_Create) + - removed old patch parse/write stuff + - #ifdef'd out patch epair/groups stuff + +++ radiant/qe3.cpp 25 Mar 2002 11:39:21 -0000 + - const fixes + - buffer-safe dtd path construction (without using string class, in case of unknown bugs) + +++ radiant/qe3.h 25 Mar 2002 11:39:24 -0000 + - don't include entity.h, include ientity.h and forward-declare entity-table instead + - include imodel.h but don't forward declare model-table + - include iundo.h and forward-declare undo table + - comment out interface to old patch parse/write stuff + - comment out interface to old brush parse/write stuff + - comment out iepairs header include.. NOTE: to be integrated with entity module/interface + - include eclass interface (we don't have an eclass.h) + - declare interface for CreateEntityFromName (generic useful func) + - declare target/targetname utils interface (we don't have a targetname.h) + +++ radiant/select.cpp 25 Mar 2002 11:39:27 -0000 + - cleanup implementation of entity selection-grouping/ungrouping utlities + +++ radiant/select.h 25 Mar 2002 11:39:27 -0000 + - cleanup interface for entity selection-grouping/ungrouping utlities + +++ radiant/undo.cpp 25 Mar 2002 11:39:29 -0000 + - removed workaround for wierd entity_clone behaviour (changed in entity module) + - avoid using Entity_FreeEpairs (not exposed by entity module) + +++ radiant/xywindow.cpp 25 Mar 2002 11:39:35 -0000 + - const fixes + - cleanup implementation of CreateEntityFromName to be a usful generic utiliy function + - enable vertex arrays in XY_Draw + - enable undo for right-click dropping entities in XY window + TTimo + - various fixes to make the above compile on Linux, checkin to cvs + - fixing some win32 build stuff + + Hydra + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=434 + fixed setSpecialLoad in .def code + +19/3/2002 + Gef + - Modified the fix for LoadImage to be more consistent with other code + - Applied Hydra's fix for empty alpha channel warnings & cleaned up indentations (tabs) in lbmlib.cpp + also added output of the tga type when a tga file fails to load + - Reverted my over complex fix (read; mess) for strtok_r to use strtok instead of manual tokenising + +17/3/2002 + Gef + - Fixed LoadImage API list not being incremented while trying to find image minors, result was + infinite loop when loading images that weren't of the first type (tga) + - Fixed cloning giving dtd errors. mapxml/xmlparse.cpp:ParseXMLStream() was using + g_FuncTable.m_pfnGetQERPath() as the dtds path... disabled validation until spog can check + that my fix is the right solution + - Added simple formatting to xmap file output so that each node has a new line for readability + +13/3/2002 + TTimo + - introduced API List managers + we deal with two types of APIManager now, the ones that matching all minors for a given major + and the ones that require a fixed list of minors + - converted the image loaders to go through a API list manager + - fixed various things in synapse (introduced more bugs?) + - fixed plugins, realized it was still broken + +12/3/2002 + Hydra & TTimo + - EClass_Create in the EClass manager _EClassManagerTable + - removed InitFromText from _EClassTable + +8/3/2002 + TTimo + - some commented out code cleanups + - added eclassfgd/ fgd.so module skeleton + loaded up in radiant core as an optional entity format + added eclass manager code to deal with the new format if present + this still loads .def, the actual .fgd code needs to be written now + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=433 + added a g_strDTDPath global + disabled DTD validation, broken on win32 + - Str copy constructor (const Str &) working correctly with a __strDup + +7/3/2002 + TTimo + - added verbosity in file accesses for CXMLPropertyBag + - more fixes to project lookup + - dropping dtds/ prefix, this is installation dependent + - removed ipluginentities.h, the plugin entities stuff was disabled long time ago already + - cleaned up some old commented out stuff + - proof of concept synapse builtin module: new class CSynapseClientBuiltin allows to have + modules builtin to the application (i.e. statically linked) + adding + include/ieclass.h (eclass loader API) + radiant/eclass_def.cpp (.def class loader, builtin) + radiant/eclass_def.h (.def loade, API public to the core) + + NOTE: radiant/eclass_def.cpp needs to be added to the win32 projects + - quickfix to project file loading ("/scripts/") + - introduced an EClass manager, hooked up the .def builtin module through it + (not yet possible to push new entity format modules, but .def reading is already fully synapsed) + +6/3/2002 + Gef + - Fixed a segfault when getting mUserPathPrefix in CGameDescription::CGameDescription() + - added preferences check for fixing target/name collisions + - fixed a logical error on my part, where setting g_qeglobals.m_strHomeGame in + CGameDescription constructor results in a value from the last file parsed. Moved it + to a more appropriate location, where it gets a value from the selected .game file. + SPoG + - changed g_strGameToolsPath to g_strAppPath in GetQERPath API + - fixed mapq3.dtd + - enabled DTD validation of xmap files + - added mapq3.dtd to setup scripts (not tested) + TTimo + - added OnActivated() to synapse clients, override to put some init code + - fixing default project path lookup and user project increment (again) + - fix to linux setup, no trailing slash in basegame items + (wolf.game and q3.game) + - removed old plugin/modules code, leaving only the synapse implementation + recoded image loading and Map_Import/Map_Export + still some temporary solutions and cleanup work to be done + removed plugin.cpp from the tree / build system + +5/3/2002 + SPoG + - TODO: add default project for wolf to WolfPack CVS module + - changed xml project file load to search for DTD "dtds/project.dtd" under radiant path + - fixed crash in mapq3 on trying to read uninitialised token ptr + - changed .map to be default map format for now + - changed runbsp to not hardcode -fs_basepath + - added -fs_basepath to quake3 default project + - added project.dtd to setup scripts and swapped quakev2.qe4 for default_project.proj (not tested) + +4/3/2002 + TTimo + - merged synapse2 branch back into trunk, checked Linux and win32 builds ok + - updated the .dsp to work with new libxml2 2.4.16 + - fixed broken enginepath guessing, and broken project path rotation / saving + +28/2/2002 + Gef + - Added extra checks for target/targetname collisions + - Find Brush dialog title correction (bugzilla #393) + +26/2/2002 + Gef + - Added Entity_Connect() to entity.cpp to avoid duplicating code + - Fixed target/targetname collisions - entities being cross-linked when copied + Bugzilla #385 : http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=385 + +16/2/2002 + Gef + - cleaned up the kyro gl_point workaround stuff + - taught ClipPoint's (clips & path points) how to draw themselves + +8/2/2002 + Gef + - Added mapxml.so to linux setup + - strip debug symbols option in setup + - removed g_qeglobals.m_strHomeMaps, writing it to project instead + fixes a bunch of re-broken path issues. Also uses fs_game now. + - Minor grid colour in QER Black & Green theme + - Save window's pos/size for all view types in MainFrame::OnDestroy + +--------------------------- on branch synapse2 +4/3/2002 + - modules don't show up in plugins menu, added a dump in console before entering interactive mode + - added compile time def for synapse verbosity + +3/3/2002 + - finished converting all the modules to synapse, disabled old ResolveInterface call + +24/2/2002 + - hooked TexTool into Radiant plugin menu through synapse + - added iplugin.h which I had forgotten earlier + - ported synapse code to compile and run on win32 + +19/2/2002 + - SYN_REQUIRE_ANY / multiple API manager code + can load multiple interfaces based on a matching pattern + converted TexTool to load that way + +18/2/2002 + - added iplugin.h with basic interface for plugins + +13/2/2002 + - synapse on modules currently disabled, + the basics of the code are working fine, need to look at multiple interfaces matches before going further + - started converting shaders, requires conversion of a lot more others + - image converted to synapse + - no longer using GUID in synapse, all done through *_MAJOR strings + HOWTO: convert a module to synapse: + configure it to link against synapse static lib + (+include path to STLPort required) + add #include "synapse.h" to the plugin header + declare the : public CSynapseClient in plugin header + implement it (listing provides and requires, implement the request code) + +12/2/2002 + - vfspk3 converted to synapse + +11/2/2002 + TODO: get rid of all WINAPI crap + - debugged the API dependencies solver to actually work + - added newer cons at the head of the tree + +10/2/2002 + TTimo + - added the basic code for solving API dependencies and requesting the various tables + - more diagnostic printing code fixes + - version checkings + - some more design work (libs/synapse/doc) + +9/2/2002 + TTimo + - some changes to the files layout, cleanup of the diagnostics printing + (stuff's mostly broken right now) + - reworked the complete Sys_Printf stuff to rely on va_list implementation + - include/isynapse.h declared useless and foxed without mercy + - added include/irefcount.h + +8/2/2002 + TTimo + - adding an experimental Anjuta project file to play around with + +7/2/2002 + TTimo + - various fixes to build on linux, listed a bunch of current issues + - fixing terrademo.map to remove broken mapobj~1 -> mapobjects + -- synapse2 branch -- + - propagate the code from old synapse branch to a new branch out of 1.3 tree + (builds and runs on linux, that's about it for now) + +--------------------------- end branch synapse2 + +7/2/2002 + djbob + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=354 + moved all the preferences code to XML + +6/2/2002 + SPoG + - checked all paths conform to: unix dir separators + trailing separator + - changed file dialogs for load/save of maps to default to "mapspath" + - removed OpenDialog and SaveAsDialog, use file_dialog instead + - removed FileSystem paths stored in QEGlobals_t.. replaced by CGameDescription + - removed dependence on EnginePath from preferences, replaced by CGameDescription + - removed hardcoded g_get_home_dir calls for file dialogs + - added validation of project settings entry paths before they are set + +5/2/2002 + EvilTypeGuy + - moved filters.cpp related function declarations to filters.h + and added #include "filters.h" to brush.cpp, csg.cpp, main.cpp, + mainframe.cpp, map.cpp, select.cpp as not all files include + qe3.h and qe3.h is a rather monolithic header this seems to be + a cleaner solution per SPoG's suggestion...Fixes compilation. + + Gef + - contrib/plugins BOOL cleanup (uses qboolean now) fixes X header conflict + - cons update for mapxml + - SaveAsDialog() changed to match path's used in OpenDialog() + - removed radiant/xy.h - moved contents to qe3.h (FilterBrush declaration) + +4/2/2002 + SPoG + - changed QE_LoadProject and QE_SaveProject to load/save xml project file format + - changed request dialog for project files to loop until a valid file is found + - fixed memleaks in CGameDescription constructor for xmlGetProp + - added converting gametoolspath unix format when parsed from game file + + - fixed m4x4 lib to use column-major order (more compatible with opengl) + - added divergence parameter to ray-point intersection test + (now easier to select distant points in perspective views) + - cleaned up modelview/projection matrix manipulations in 2d/3d view + - cleaned up map modules / interface source files a bit + + - added ability to specify map module version when importing/exporting map + - cleaned up file dialog code, returned filename is static and in unix format + - save-as dialogs force a file extension depending on filetype selected + - added filetype manager to support registering custom file types + - fixed loading and cleaning engine path from radiant.ini correctly + +3/2/2002 + EvilTypeGuy + - fixed win32 compilation (userpathprefix is Linux specific) + + ETG & Powzer + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=308 + added preference to allow 'paint drag-select' brushes/faces in 3d camera view + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=389 + added preference to strafe camera foward/back in 3d view while freelook is active + + ETG & RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=388 + patch adds ability to strafe up/down/left right while freelook is active + +1/2/2002 + TTimo + - bumped to 1.3.1-nightly + +-- 1.2 stable branch branched here + + Gef & TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=372 + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=376 + appplied the patch, corrected the mapspath expansion stuff + TTimo + - linux nightly setup code + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=384 + hacked a corrective action in the nightly setup + + SPoG + - fixed creating region brushes that fill the entire grid for Save Region + +31/1/2002 + + Micheal Schlueter + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=375 + syntax fix to q3map path_init.c + + Gef + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=279 + patch 185 == 186 + tweaking to config stuff in linux setup + patch 187 + Ensures the games directory exists before trying to create a file there + patch 177 + Adds *.cf files & uses them. I think I have all the files in the right places now... maybe + (some additional fixes on top by me) + + ETG + quick fix to shader prefs load + +29/1/2002 + + EvilTypeGuy + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=345 + more detachable menus fixes + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=334 + fixes 'load shaders at startup' preference + + SPoG + - fixed misc_model "modelscale" and "modelscale_vec" support + + TTimo + - upgraded setup scripts to support nightly build + - last minute fix to the modelscale and modelscale_vec code (md3 module) + + ydnar + q3map 1.2.4-y2 + + New features: + - -nopatchfix argument. This disables lightmap patch fixes and makes a map suitable for lighting with -vlight. + - Degenerate patches are treated like broken brushes. They are ignored, warned about, and selected in Radiant if you ran with the -connect option (or from the BSP menu). This was what was causing the "0 valued axis" error some people were experiencing. + + New entity keys: + - "_lightmapscale" key for brush entities (worldspawn, func_*). This lets a mapper scale the lightmap samplesize per-entity. For large constructions, 2.0 or 3.0 is a fine value, and keeps BSP size down and compile times low. For those areas you want to have high-detail shadows, make a func_group and use a value of 0.25 or so. It will scale the samplesize value for the surface's shader (default 16) or the -samplesize argument. + - "modelscale" and "modelscale_vec" keys for misc_models (1.0 = default). This was for proper RTCW support and is available for Quake 3 maps as well. Lets you scale up map models in the world, getting around the MD3 size limitation. The next build of GtkRadiant has SPoG's code to support this in-editor so you can see what effect a scale has. + - Flare surfaces are now supressed from the BSP. They serve no purpose other than add to the vert & surfacecount in a BSP. These surfaces were created silently when a shader has "light 1" or "q3map_flareshader X." Use the new -flares switch when BSPing your map to have them emitted. + + Changes: + - GtkRadiant 1.2.4-nightly version increment. + - Full WolfSDK style lighting enabled with -game wolf, including lightJuniors. This includes linear lights by default (no angle attenuation) and support for the additional RTCW "fade" and "angle" keys, and spawnflag changes, including q3map_nondynamic on light entities. This may require maps being constructed for RTCW with the current toolset to change their light entities. Sorry. :) Note, Wolf-style lighting only works with -light, and not -vlight. + - Vertex light stitching now uses a near-ambient light check for dark vertexes as opposed to lower-than-average fixups. This preserves some shadow detail better while getting the buried verts lit properly. Comments encouraged. + - Surfaces' samplesize are now stored in the BSP. This change makes BSPs generated from this version incompatible with all other q3maps. The upside is that -samplesize N is no longer necessary on the -light or -vlight stage. This feature is necessary to support the "_lightmapscale" key. + - Additional PVS optimizations in lighting. + + Fixes: + - Will compile for RTCW properly (1.2.1-y12 didn't). + - No more sparklies where fog meets brush faces. They're split properly now. + - Crash bug in vlight fixed. + - Vertex light fixups/stitching is considerably faster. + - Vertex light fixups ONLY stitch faces with lightmaps. For pointlight surfaces you're on your own. + - Better snapping logic when merging nearly-coincident vertexes on complex brush windings. + - Bug where the .prt file had some bogus or nearly-borked portals. They're cleaned up like everything else now. + - A few stupid bugs in path initialization. Should work better. Also includes TTimo's fixes to my code so it would work properly on Linux. + - RR2DO2's PCX loading patch for alphamaps. This bug was manifesting itself in the form of offset or incorrect samples being used on terrain entities. + - A ton of other minor little fixes here and there. + +28/1/2002 + + TTimo + - win32 fixes + - 1.2.4-nightly + + djbob + - EClass_ForName fix if malformed name + +---- 1.2.3 linux released + + TTimo + - fixed BSP version depending on game mode in q3map + (home dir guessing is still fucked, have to fix before release) + - fixed q3map init_path.c home path bug on init + + Gef + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=369 + more fixes to texture paths in gensurf + +27/1/2002 + TTimo + - switching to v3 project file, forcing reload of template if non-v3 + need to distribute quakev3.qe4 in setups now (done for linux setup, will have to in win32) + - renamed Main to main in q3map init paths + - fixes the ~/. inits and init order in q3map + - added m_pfnPathForPluginName to the main function table, returns the directory a plugin is running from + used in bobtoolz / curry / pk3man to find various files + see also todo: http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=368 + - some fixes to textures loading paths in curry + - linux setup copying correct content for curry (pk3 in wolf media) and bobtoolz (bt/ in plugins/) + - building 1.2.2 setups + + Gef + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=362 + gensurf fix + + djbob + - bobtoolz update + + Hydra + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=361 + fixes a bug with the texture menu loading, now we see the non-shaderlist directories too + +26/1/2002 + Gef - Michael Schlueter - TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=279 + applied several patches (to setup code and to the setup scripts) + modified makesdk.pl to update with more content + added an "enginepath" attribute to the game file, reworked the handling in editor + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=347 + took out the refresh command from the plugin menu + - more linux fixes: + bringing all the plugins to compile again on linux + polishing the setup code (all the right files in the right places) + - for linux release, bumping ver to 1.2.2 + win32 will have a 1.2.3-nightly after that + - added correct init of ~/.q3a or ~/.wolf + *nix systems have a 'prefix' attribute in the .game file to specify + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=359 + identified the mod compiling problems + applying back the old fs_basepath fs_game code to the BSP generation + + ydnar- TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=351 + cleaner path init code + it doesn't init for ~/.q3a and ~/.wolf paths yet + +25/1/2002 + SPoG + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=352 + using the wrong matrix stack for XY_Draw caused stack overflow error + - texture_mode was set to an invalid enum in wireframe/flatshade mode + - changed plugin API to expect gamedir-relative texturenames + - fixed gensurf to create faces/patches with gamedir-relative textures + +24/1/2002 + SPoG + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=322 + added modelscale key check to misc_model entity in md3/entity module + added angle key check to eclassmodel class in md3/entity module + fixed bugs in BP writing and reading in map module + TTimo (commited as SPoG) + - fixing permissions on cvsreport and doxygen stuff, upgraded dot + +23/1/2002 + SPoG + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=336 + plugin API bugfix - fixes textures on stuff created by plugins + +---- 1.2.1 was released here + +22/1/2002 + Gef + - linux build fixes + SCDS_reyalP + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=325 + wrong file packaged in setup + RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=327 + fix to PCX loading + SPoG + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=298 + cut & paste bugfix + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=332 + update origin key on entities + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=333 + made fixedsize entities not scalable + +21/1/2002 + TTimo + - scanning in g_strAppPath/modules/ and plugins/ prior to g_strGameToolsPath + using the main path to put general plugins and modules + - fixed bobtoolz bug, init of epairs table was relying on wrong params + - fixed curry to compile again on 1.2 + - fixed pk3man to compile again on 1.2 + - updated IS setup: + installing the plugins with the core + installing the common modules in the core + - Compiling manual, more IS stuff, .xlink etc. + + RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=315 + patches for improved multimonitor support (with some associated pref items) + + ydnar + - more q3map: http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=324 + - radiosity fixes (proper handling of ambient light) + - polygonoffset fixes + - lightmaps on patches work better (normal calcs adjusted, planar patches are + box projected like brush sides) + - double vfs init in bsp stage removed (this needs to be tested on Linux) + - lighting is faster again + - a couple crash bugs resolved + - other tasty nibbles + +20/1/2002 + EvilTypeGuy + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=313 + detachable menus set as preference (in layout) + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=255 + path prompt + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=307 + patch dialog names + ETG & RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=306 + fix 'Natural' texturing crash + ETG & TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=291 + found out the problem, Wolf SP spawn works now + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=144 + fixed more problems with model loading vfsExtractRelativePath + prolly broke the linux build, just a matter of putting a bunch of #idfdef + - fixed an additionnal .pid lock situation, cleaning the global prefs on game .pid lock + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=301 + fixed md3 tris test selection bug + djbob + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=219 + fixed bobtoolz for 1.2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=318 + filter structural + RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=305 + filter in viewmenu for lightgrid brushes (ydnar's q3map) + fixes image lib loading bugs + Hydra + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=298 + copy/clone deselects the copied stuff + added a pref to deselect or not, and to nudge pasted stuff or not + +19/1/2002 + djbob + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=311 + IEpair wrapper to access project entity from plugins + RR2DO2 + - missing IncRef in CShaderArray::AddSingle + TTimo + - game.xlink files in gametools path, is scanned to build items in the Help menu + (and the associated code) + +18/1/2002 + Gef / Michael Schlueter / TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=279 + patches 133 and 138 applied, new setup code + +14/1/2002 + TTimo + - adding djbob write access for bobtoolz + +13/1/2002 + ydnar + - q3map code updates 1.2.1-y8 + new lightgrid surface flag feature + lightgrid shader and editor image for Wolf and Q3/TA: in the common .pk3 and in all common.shader + cvs remove setup/data/baseq3/common-q3r.pk3 (unused, we use common-spog.pk3) + TTimo + - updating setup to use mapq3 module instead of map (both Wolf and Q3 game packs) + (also checked the lightgrid option) + - fixed setup.pl bug for template gen from WorkDir/ + - correct spawning between SP and MP mapping mode + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=297 + .pid check, console logging and prefs cleanup + Wolfen + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=294 + checked in updates to the manual links page and setup instructions + (i.e. new prefs dialog) + +12/1/2002 + Gef & Michael Schlueter + - bugs #295 and #279, new patches applied + EvilTypeGuy & djbob + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=220 + patch selection crash + EvilTypeGuy + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=260 + Dense and Very Dense Cylinders have wrong number of rows + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=292 + latching patch toolbar settings + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=144 + win32 long/short pathname bugs reappearing, switching back to short paths for project settings + - removed obsolete radiant/vfs.cpp radiant/vfs.h + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=291 + using new .qe4 for Wolf, fixed stuff editor side (long path names and engine spawn) + SCDS_reyalP + - http://zerowing.idsoftware.com/bugzilla/showattachment.cgi?attach_id=118 + realloc bug in terrain + +11/1/2002 + SPoG + - unpatched bug #239, unintended duplication of brushes, patch #96 + Note: bug #239 now unresolved + EvilTypeGuy + - bug #295 fixes for compile under Linux + +10/1/2002 + SPoG + - fixed CEntityEclassModel referencing eclass after eclass has been deleted + SPoG - map-module branch + - new map module, provides current functionality, using new map interface + - cleaned up merging/creating of entity array used by map module + - implemented MemStream::printf(const char,...) - can't print strings larger than 1024 currently + - changed copy/paste to use the map module, via abstraction of FileStream/MemStream as DataStream + - fixed Save Region and Save Selected + - new xml map module "mapxml" + - cleaned up map.cpp + +6/1/2002 + TTimo + - removed m_bPak from pref dialogs (it was dead code) + +5/1/2002 + RR2DO2 + - q3map terrain blending fix for >5 layers + EvilTypeGuy + - fs_homepath patch on linux + Gef + - bug #279, linux setup, patch #102 + - bug #239, unintended duplication of brushes, patch #96 + TTimo + - added Wolf specific project settings dialog: + correct fs_game selection and combo names + added multiplayer / single player mapping mode selection + +4/1/2002 + TTimo + - adding -game wolf switch to q3map (-game quake3 works too, but it's the default anyway) + using different bsp version and different fs_basegame on wolf + - updated the setup/win32/setup.pl script to generate from a config file instead of hardcoded + (added corresponding q3.cf wolf.cf and all.cf config files) + - added a default Start Menu shortcut name (RR2DO2 special) + - diffing against Id's internal SOS source and merging in new stuff: + - bumped MAX_SURFACE_INFO to 4096 in shaders.c + - new terrain code (Jim Dose) + ParseTerrain() addition in terrain.c + Creates a mapDrawSurface_t from the terrain text + - VL_SurfaceRadiosity and VL_SurfaceRadiosity + MrElusive's vlight radiosity code + - speedups to vis.c and visflow.c (MrElusive) + +3/1/2002 + TTimo + - merge gameselect branch back into trunk + the IS setup scripts have been updated for the new paths layout + developement environment needs to be updated to copy binaries to the right places for debug + it is recommended to run a 1.2.1 setup on win32 prior to compile and install debug bins + - updated the setup to be more templated for inclusion/non inclusion of game packs on demand + + - propagating recent fixes to Alpha into the trunk + based on diffing between Merge-1_1_1 and Merge-1_1_2: + ===================================================================== + 13/11/2001 + djbob + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=244 + reverted again the shader manual and tcMod docs + + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=214 + patched aselib.c, was calling strstr badly (relative path extraction) + + 12/11/2001 + djbob + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=241 + applied patch, will release in next nightly + + Spog + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=254 + patch for safe_malloc + + TTimo + - fixing STLPort config checks and XML config (CHAR -> xmlChar) + - added safe_malloc_info and safe_malloc in the common/ dir + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=179 + added XML stream version checking between Radiant and q3map + ======================================================================== + also, manual merge of docs/manual and setup media + this merge work is related to bug #280 too: + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=280 + + ydnar + - new q3map, radiosity and bug fixes, code merged in with the trunk version + (TODO: add more detailed changes log) + + EvilTypeGuy + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=274 + broken auto caulking fix + + EvilTypeGyu & LordHavoc + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=207 + (two new files, project settings updated) + +2/1/2002 + TTimo - branch gameselect + - copying over the linux setup binaries (setup, uninstall, setup.gtk) + from Alpha branch. Those have the ability to prompt destination path + per component. + Gef - branch gameselect + - patch 101 for bug 279 + .game files generation by the setup, makesdk.sh and postinstall.sh fixups + +1/1/2002 + Gef - branch gameselect + - linux source fix http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=279 + (we use PATH_MAX as the cross platform define instead of MAX_PATH which only works on win32) + + TTimo - branch gameselect + - cleanup and homogeneisation of the paths for prefs storage + m_global_rc_path: + win32: g_strAppPath + linux: ~/.radiant// + m_rc_path: + win32: g_strGameToolsPath + linux: ~/.radiant// + so that global.pref goes in ~/.radiant//global.pref + and radiant.ini ~/.radiant///radiant.ini + +27/12/2001 + TTimo - branch gameselect + - global prefs file (global.pref), XML based in core directory + stores game selection setting + stores autoload setting + - dropping 'gameid' from .game file, gonna use a 'gamefile' in global prefs instead + (and the .game file name .. thks Gef) + - TODO: radiant.log stuff in global prefs? + +21/12/2001 + TTimo - branch gameselect + - more Wolf setup tweaking for an experimental build release: + quakev2.qe4 project template file + using a 'gameid' attribute in the game file to select hardcoded features in the editor binary + 'basegame' node for lookup of the default project file + 'engine' node for engine path + - added experimental Wolf game pack to IS + - added setup/win32/HOWTO with extensive information about the procedure to + add new game packs + - reading the 'name' attribute in the game node for game selection dialog + - TODO: pid files to make safe startup? + The .pid stuff should be happening after game selection, since it covers game-specific + preference settings. + - TODO: console logging pref should be a global pref, goes with game autoload? + +17/12/2001 + TTimo - branch gameselect + - updating the setup script for experimental 1.2.0 setup: + + merged some of the docs back into trunk (Radiant manual, some TA docs) + will need to perform a complete diffing between Alpha and trunk about docs/manual at some point + merged bitmaps from Alpha too + + added the Q3 modules (image, map, md3model, shaders, vfspk3) to Q3 game pack in setup + + generating per-game config file q3.game in OnMoved (IS setup) + will need equivalent with linux setup of course + + various other generic fixes to the setup code + + - multiple games support, list of changes, and TODO: + NOTE: this is on a 'gameselect' branch for now + Doxygen documentation should be at http://zerowing.idsoftware.com/doxygen + for this branch too. + + The installation procedure has changed. The win32 installer is partly ready, linux installer + will need to be modified too. The editor binary and the Gtk DLLs are installed in a common + location, i.e. 'C:\Program Files\GtkRadiant' typically. The game specific binaries and modules + go in the same location as usual, for instance 'C:\Program Files\Quake III Arena\GtkRadiant\' + (and also 'C:\Program Files\Quake III Arena\GtkRadiant\modules' 'C:\<..>\plugins') + + The environment variables used by the build system (VC6 project files) have been adapted: + $(QUAKE3RADIANTDIR) is still used + $(CORERADIANTDIR) is used for the main editor location + + When editor starts, it looks for games/*.game under g_strAppPath and prompts the user for a game + Once game is selected, parameters are used for regular startup. + You need to write your own q3.game for now, it will be generated by the setup procedure + my C:\Program Files\GtkRadiant\games\q3.game looks like that: + + + + + + given that, the editor does a complete startup, and the basics are here for multiple games + + - precise changes: + + g_strToolsPath renamed to g_strGameToolsPath + most of former g_strAppPath uses g_strGameToolsPath + the name change was also meant for homogeneity with DIR_GAMETOOLS_* variables we use in the setups + g_strAppPath still used, points to the main installation path + + added the game selection code in CPrefsDlg::Init + using several classes and a dialog box, parsing XML files + + - TODO: + + the console 'Radiant.log' doesn't catch the game selection stuff as it is now + initialize it to the main install, without the game setting + (console logging is a debugging tool anyway, no reason it should go to the proper game folder + each time) + + the 'preferences reset/cleanup' code is probably broken, specially when used with the .pid checking + since we check for .pid even before we know where the GameTools path is + + on linux, we need to sanitize the ~/.q3a dir usage. Switch to ~/.radiant, use the version tag + to maintain things independant, and use the game name to isolate per-game settings? + ~/.radiant/1.2.0-nightly/quake3/radiant.ini (.pid, .log) + ~/.radiant/1.2.0-nightly/wolf/.. + + also, when looking for those files (.ini mostly), win32 stores them in a main installation, and + linux has them in ~/.radiant/.. (which is the read/write area). This should be homogenized? + Maybe by adding a 'Main' to the readonly path and a new variable with 'RW', pointing to 'Main' on + win32 and to ~/.radiant on linux + +11/12/2001 + TTimo + - replaced setup/win32/setup.sh by setup/win32/setup.pl + same functionality level + abiliy to generate back a template from a work version + - major rework on the IS scripts, basics of multiple games support installer + clean seperation between editor core and game pack + design doc and analysis of custom setup generation, setup script UI requierements + see setup/win32/TODO for more details + +10/12/2001 + TTimo + - new generation of InstallShield setup + using a template/ directory instead of a .zip file + requires rewrite of the processing script + allows easier maintenance of the IS script + +23/11/2001 + TTimo + - yet another update to cvsreport script, + catch the branch and forward the info to user commands too + able to build doxygen for several branches selectively now: + http://zerowing.idsoftware.com/doxygen + +22/11/2001 + TTimo + - new cvsreport script, should send explicit diff of the CHANGES file now + +03/12/2001 + TTimo - md3-module branch + - validated the fixes and the build on linux, ready to merge in trunk + SPoG - md3-module branch + - changed function naming conventions in mathlib for m4x4, ray, bbox, to be consistent + - fixed bug in m4x4_invert + +29/11/2001 + TTimo - md3-module branch + - flagged all new mathlib functions that need a name change or an argument order change + also added various \todo to point out inconsistencies + +28/11/2001 + TTimo - md3-module branch + - updated linux build + - fixed CEntityMiscModel and CEntityEclassModel destructors + (any destructor should be virtual) + +27/11/2001 + Spog - md3-module branch + - stopped texturewindow showing shaders without the "textures/" path + - made md3 module functionally identical to current radiant md3 code + +22/11/2001 + TTimo - md3-module branch + - fixes to the core for linux build + - model.so module builds on linux + - added plugins/md3model/doc/md3-design.txt + - several doxy-friendly \todo chunks about the module model + + Spog - md3-module branch + - fixed aabb_add_aabb() algorithm wasn't very reliable + - added VectorMid, VectorNegative and CrossProduct macros to mathlib + - added bbox_intersect_plane() + +21/11/2001 + Spog & TTimo - md3-module branch + - initial code from Spog following a preparatory design work + merging in as new 'md3-module' branch + geomlib code merged into mathlib + some reorganisation of the source layout and cleanup (more stuff in imodel.h, less in qertypes.h) + + Spog + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=261 + fix applied + +20/23/11/2001 + TTimo + - yet another update to cvsreport script, + catch the branch and forward the info to user commands too + able to build doxygen for several branches selectively now: + http://zerowing.idsoftware.com/doxygen + +22/11/2001 + TTimo + - new cvsreport script, should send explicit diff of the CHANGES file now + +11/2001 + Spog + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=253 + additional fixes + TTimo + - renamed tools/quake3/common/threads.h to qthreads.h + avoids a collision with system headers + +19/11/2001 + Spog + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=251 + Fixed "Move into worldspawn" deleting entities with only one brush + Fixed Brush_Move using texture lock on fixedsize entity brushes + Fixed Textures > Texture Lock > Rotations toggle checkbox + +16/11/2001 + Gef + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=247 + applied patch 77, using a notebook layout for preferences dialog + also patched in some preferences saving that had been forgotten + (such as invert mouse in freelook) + + Spog + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=253 + patch 84 + additional modifs, bug still open + +15/11/2001 + Spog + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=252 + rewritten rendering pipeline for cam window - fixes some hacks, improves speed, + makes rendering modes more consistent with each other + +07/11/2001 + TTimo + - more IMAP interface, adding a blind data void *pData to entity_t + more info about it and why it's done is in map.cpp, should be a small base for next additions to the editor + +31/10/2001 + TTimo + - using IDataStream in map module, moved back some of the module code into the trunk + +30/10/2001 + Gef + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=245 + applied patch 76 + + TTimo + - renaming istream.h to idatastream.h, this had nasty conflicts with OS includes + already had to IStream -> IDataStream some time ago anyway + +27/10/2001 + TTimo + - updated cvsreport, testing new ver + - added a static version of texdef (no memory alloc on the texture name) + unused for now, was just experimental + Gef + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=245 + applied patch 75 + +26/01/2001 + TTimo + - various updates: + new GtkSDK precompiled binaries + updated libxml2 package (to 2.4.3) + updated STLPort (to 4.5) + now compiling with STLPort and threading (since we are using threading throughout the app) + - exposing the data stream API to the modules, renamed some stuff on the way + need to update the map module to use it now + - cleanup on qtexture_t definition + guarding and disabling chunks of the surface plugin code behind DO_SURFACEPLUGIN + (see earlier patch on plugin entities) + +25/01/2001 + Hydra + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=202 + applied patch commenting out plugin entities code + might come back in 1.2 under another implementation + the code is still there, only commented out for now + +17/01/2001 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=93 + checking in doxygen content, setting up generation on zerowing + auto generation on zerowing upon a commit: + http://zerowing.idsoftware.com/doxygen + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=231 + checked in the patch + - switching to a new cvs commit script + +14/10/2001 + TTimo + - libs/mathlib library + unifies mathlib code squattered all over the tree + mainly a merge of tools math code and radiant/mathlib.cpp + C implementation, using an extern "C" construct for use from C++ + need to check on linux, win32 builds ok + extracted qboolean code into libs/bytebool.h on the way + +11/10/2001 + TTimo + merged TmpMerge-1_1_1 branch back in the trunk, the update process from Alpha 1.1.1 is done + + TTimo - branch TmpMerge-1_1_1 + looking through all remaining .rej files and applying the failed patches accordingly + bobtoolz is broken, but it's not due to the merge + the plugin API is different and some things need updated + (disabled bobtoolz build in contrib/Construct for now) + same for gensurf + same for prtview + same for textool + setup: replaced the existing stuff with 1.1.1 code + fixed various things for win32 build, checked correct CRT lib config + +10/10/2001 + TTimo - branch TmpMerge-1_1_1 + building modules, going through all the .rej + merging radiant/missing.h and modules/shaders/missing.h into a single one, moving to libs/ + exposing BuildShaderList PreloadShaders in _QERAppShadersTable + have to review all the remaining .rej to finalize the merge now + +04/10/2001 + TTimo - branch TmpMerge-1_1_1 + using this branch as temporary location for merge process + copied over new binary files. mostly .dsp (prolly broken) + and setup/linux/setup.data stuff + +25/08/2001 + TTimo + map module successfully loaded and saved q3dm1, the saved file was then loaded back into 1.1-TA without problems + rebuilt and checked on win32 + merged IMap back in trunk, fixed some memory conflicts on win32 + Took me a lot more time than I would have liked to, but there's a script tied to the CVS server now, which will post on this list a diff of the docs/developer/CHANGES file whenever it gets updated. This will probably be very handy for me since I'll only have to put update information in the CHANGES file instead of having to post on the list too. + The script is likely to be a bit laggy, or miss some features (for instance I'd like to extract the branch name .. anyone know how I can get the branch name (Alpha/IMap/HEAD) from the version number? + PS: I can email this script to anyone who would like to have a look + +22/08/2001 + TTimo + did more work on map module, one big chunk of work left: the core should broadcast interface requests to plugins + when it doesn't know how to do it by itself.. + Gef + new doxygen patch, generates output from core (libs/ include/ and radiant/) + +21/08/2001 + TTimo + removed Makefile, use cons damnit! + +18/08/2001 + Gef + automated documentation via doxygen, new scripts and content + +18/08/2001 + EvilTypeGuy + patch for CHAR to xmlChar conversion (xml2 consistency) + +09/08/2001 + TTimo + the map module starts to look like something, cleaned up the interface stuff + started moving the actual code out in the module and removing it from the core + lots of issues raised on the way, some structures to export, and the macro scheme to access API functions more easily + it compiles right now, but won't run because it's missing a lot of things .. the process simply happens to be "under way" + +04/08/2001 + TTimo + patched more path code, to look for stuff in "bitmaps/" and "modules/" instead of "tools/bitmaps" and "tools/modules" + modified the Construct files accordingly + merged in radiant/ishaders.cpp diff into plugins/shaders/shaders.cpp (PreloadShaders) + merged in radiant/lbmlib.cpp diff into plugins/images/lbmlib.cpp (Sys_FPrintf) + checked the .rej and patched a few remaining things + NOTE + the diffs are space/tab sensisitive, and we used the "beautify source" a bunch of times, so it's a bit fucked now + next time, generate the diffs not space sensitive.. + TODO + map loading is fucked, "textures/" prefix issue? + +27/07/2001 + TTimo + merging recent changes from Alpha branch into the Trunk + this could not be done with a regular cvs merge because we already did a cvs merge of Alpha into trunk some time ago + manually built a diff between the current Alpha (now tagged Merge-1_1-TA_1-nightly) + and the Alpha we had right after the former cvs merge: -r Alpha -D 2000-05-28 + binary files ignored in the diff, only going for source stuff + built with diff -Nru Reference/ Current/ + then patch -p1 < patchfile + next, started rebuilding: + big manual updates were in vfs.cpp and texwindow.cpp + cleaned up some VFS stuff .. it had an absurd QERAppFileSystem / QERPlugFileSystem scheme + TODO: + the ISSetup has not been copied over from Alpha + OK check the Construct files + OK radiant/ishaders.cpp no longer exists .. apply the patch on the shader module + OK radiant/lbmlib.cpp no longer exists .. in the image code? + OK look at the *.rej files + +03/10/2001 + TTimo + - adding a pref to select patches by BBox, fixes + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=212 + +02/10/2001 + TTimo + - reverting Spog patch 67 to bug #209, starting from scratch + applied again, with HasModel returning NULL safe checks + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=211 + fixed overlays drawing (XY and Cam) + +01/10/2001 + TTimo + - building and distributing q3data (.ase -> .md3 conversion utility) + updated q3data to show main GtkRadiant version information and build date + - generating a new GUID per-setup + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=206 + Gef + - updated credits.html and links.htm, look much better + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=200 + - update Z-checker view on camera up and down + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=199 + Spog + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=209 + Fixed QERApp_ReloadShaders.. PreloadShaders needs a BuildShaderList call + Fixed Flush & Reload Shaders for md3 models + +25/09/2001 + Gef / djbob + - several patches to the key handling code, for linux specific issues and sticky keys + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=191 + TTimo + - fixing q3map bug, not processing the argv correctly + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=192 + - fixed ToggleCubicClip shortcut Ctrl+\ (win32 Gtk source patch) + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=15 + +18/09/2001 + RR2DO2 + - discreet movement for camera (prefs setting) + fixes texture window bug + latching view layout changes until restart + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23 + djbob + - added back "view > show > show angles" in view filters + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=188 + +15/09/2001 + G_Dewan + - fixed problems with q3map when not using -connect + SPoG + - fixed q3map texture projection for brushes belonging to entities with local origin + - added SafeOpenRead() check, terminating map->bsp stage if .map file cannot be read + +13/09/2001 + RR2DO2 + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=181 + fixing key handling bug (key pressed with repetition was not properly catched) + TTimo + - added new Radiant manual elements (GtkRad section) to the win32 full setup + - reverting version to nightly, going back to nightly / RC delayed + - patched linux setup, now prompting for component path only if at least + one of the options is checked. Still need to handle Cancel in dialog though. + +12/09/2001 + TTimo + - more fixes to linux script, copy plugins right now + +10/09/2001 + TTimo + - patched contrib plugins, using seperate build scheme + - fixed textool issues, compiles again + +09/09/2001 + TTimo + - sub-menu cascading + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=178 + - udpated the Q3Radiant manual with some new GtkRadiant stuff + - updated the FAQ with 1.1.1 known issues + Gef + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=174 + applied all the patches + +07/09/2001 + SPoG + - fixed qer_editorimages outside "textures/" being ignored + - stopped q3map_lightimage being used to set shader image dimensions + - changed bsp menu to remove "bsp_", changed menu text in default .qe4 + - fixed patch LOD update - now always occurs on both cam/xy draw + + djbob + - dynamic DEpair class strings in bobtoolz + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=171 + - decrease VESF verbosity + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=169 + + TTimo + - fixed Gtk keyboard bug Ctrl + [ and ] + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=15 + +06/09/2001 + TTimo + - merged FullSetup branch into the trunk, we have basic functionality + for a full linux setup (components prompting for path) + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=158 + + Gef + - CapDialog source cleanup patch (got rid of the namespace) + + RR2DO2 + - more camera fixes, wheel mouse and texture drag drop + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23 + - additionnal patch to optimize camera refreshes + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23 + + djbob + - remember last key/pair in entity dialog for easy "apply again" + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=18 + - re-enabled texture name edit on PI + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=18 + +04/09/2001 + djbob + - left pane on status bar + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=166 + + RR2DO2 + - cam window cursor fix + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23 + + TTimo (FullSetup branch) + patched setupdb and setup to allow for path prompt in install + modified the setup script scheme to go towards a solution similar to what + we do under win32 (build a full and nightly build) + the binaries in setup.data/ (setup and setup.gtk) still need to be updated + with proper binaries built from setup and setupdb cvs source + +03/09/2001 + TTimo + - wheel mouse in texture window on win32 (with a pref setting for increment) + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=160 + - not saving prefs while exit on sleep + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=157 + - fixed select all of type (changed behaviour to something that makes more sense?) + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=79 + + Gef + - final tweaks to wheel mouse scrolling (locks texwin scrolling and scrollbar update) + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=160 + - prevent multiple color selection dialog for light entity + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=165 + + djbob & TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=137 + window positions + applied patch to store SI and PI positions + storing entity info and map info positions + reworked the overall position load/save scheme + added an enum for the view style, makes things more readable + +02/09/2001 + TTimo + - added/cleanup ToggleFreeMode to camwindow.cpp .. stopped working on cam stuff since RR2DO2 has another patch in preparation + Gef + - patched Conscript to accept 'cons -- release' on the command line to performa a release build + djbob + - added patch splitting to bobtoolz + - fix to patch control points bug in camera + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=159 + - handling of NWUV errors in q3map + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=147 + RR2DO2 + - new patch for camera control + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23 + +01/09/2001 + SPoG + - Fixed .wal texture support, searches for .wal extension if .tga and .jpg fail + NOTE: requires a "pics/colormap.pcx" file to obtain a palette from + - Added variable default texture scale in preferences (ini key: TextureDefaultScale) + +01/09/2001 + djbob + - fixed surface inspector "fit" bug + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=161 + - single face deselection on a selected brush + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=153 + +31/08/2001 + TTimo + - Moved *.def files to scripts/ in win32 setup + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=116 + - Applied patch for background position on widgets (win32) + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=108 + - Checked C runtime lib configs + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=135 + - updating docs (add to CVS, update setups etc.) + added TA teams manual to the full setup + uploaded on web site + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=97 + - changed versioning to 1.1.1-nightly, next release will be 1.1.1 + (the -TA part was removed, since we now support ALL mods) + - removed AFX_MANAGE_STATE calls, this is old MFC related code for win32 + - moved texdef_t::name to private, added const char * GetName() + (doesn't fix explosion on exit for win32 debug builds though) + - fixed DoTextEdit / EditPad b0rkage (due to recent Q_Exec changes) + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=134 + - added targetShaderName documentation to shader manual + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=102 + - added "notta" and "notq3a" documentation to the TA Mapping manual + - fixed entities.def on shootable doors and buttons + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=101 + + djbob + - added MAX_POINT_ON_WINDING error handling + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=129 + - bobtoolz update + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=123 + + RR2DO2 + - noclip-type camera movement + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=23 + +30/08/2001 + TTimo + - Fixed CHANGES commit script bug + - Fixed -onlyents bug in q3map / origin brushes + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=92 + - added mouse wheel to the texture window + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=81 + SPoG + - Fixed texture rotation not updating correctly on patches + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=136 + - Fixed long delay on toggling cubic clip by removing call to Map_BuildBrushData() + - Added note in entities.def for default worldspawn _color value + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=105 + - Added IncRef and DecRef to Patch_FindReplaceTexture() + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=95 + - Fixed misc_model updating on changing model key or with invalid model + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=138 + +30/08/2001 + SPoG + - Added negative vertical scale on SET and FIT in patch/surface inspector + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=65 + +27/08/2001 + Gef + - running makeversion.sh from Conscript + - a bunch of patches to cleanup compile warnings on linux + - added VectorSnap on float grid + - IWindowListener modified to pass float values for X Y in click messages + TTimo + - fixed crash when adding a misc_model if Gtk dialog is on + djbob + - md3 filtering for misc_model dialog + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=76 + +26/08/2001 + Gef + fixed http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=152 + Kyro II GL drivers bug + fixed http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=150 + using a scrolling textbox for GL extensions in the about list + fixed http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=150 + func_group toggle in cap dialog + + TTimo + fixed running BSP commands on linux + fixed http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=133 + VFS init on linux + +around 15/08/2001 + TTimo + quakecon fixes: switched to long filenames in project and misc_model dialogs, + removed all occurences of win32 conversion to old 8.3 filenames + NOTE: this might raise some bugs and issues, but it's the way to go for the future, + already fixes more issues than it creates + +03/08/2001 + djbob + fixed Radiant hijacks win32 copy/paste + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=36 + +--- merged Alpha into Trunk, see Merge-1_1-TA-nightly tag + +25/07/2001 + TTimo + fixed project dialog to behave right + proper .def scanning + fixed shader loading with VFS and mod stuff + added a local to texwindow.cpp GSList *l_shaderfiles + holds the names of the active .shader files + modified q3map to read "fs_basepath" and "fs_game" + TODO: + .def files in the media need to move to /scripts/ + rename entities-TA.def to entities-ta.def + +24/07/2001 + TTimo + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=116 + updated cmdlib's Q_Exec to be more widely used through Radiant (during watchbsp.cpp cleanup) + patching in MarsMattel's code for mod support, and started fixing: + added m_strFSBasePath m_strFSMain m_strFSGame to g_qeglobals to match Q3's filesystem + reworked the project file dialog + changed the way we load and initialize eclass and shaders to work with mod code + updated VFS initialisation code, cleaner and better console output + the "game" key in the project file is no longer relevant, only "dir" is + (if "dir" is not present, then no mod support, vanilla Q3) + changed the loading of the .def files to scan in scripts/, you might need to move your entites.def to use + TODO: + cleanup .. (search where "basepath" is used for instance) + using fs_game when calling q3map + fixing project dialog to behave right + shader loading using VFS functions (seems to work again but I'm not sure) + win32 ver. might be slightly broken + .def scanning, don't scan ALL .def + +23/07/2001 + TTimo + added version and build info to the log file + current timestamp + +22/07/2001 + SPoG + fixed selection of misc_model when viewed as a bounding box + +20/07/2001 + TTimo + cons script for q3map building + added general GtkRadiant versioning (version.h) to q3map + nightly setup on linux: + using the right install path (with GtkRadiant's version name) + cleaned up options to only the stuff relevant to nightly + fixed Radiant and core binaries path in setup + added some template processing of setup.xml (similar to what is being done on win32) + +19/07/2001 + TTimo + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=112 + applied ^Fishman's path + inclusion of version.h and aboutmsg.h moved to qe3.h + changed base path location process (in most cases it will prompt) + fixed the path construction to initialize according to the new layout + +16/07/2001 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=115 + fixed wake up crash on linux + +12/07/2001 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=117 + fixed + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=120 + fixed installer bug on win98, was a problem with cygwin config + +11/07/2001 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=64 + cleanup and fixed + +06/07/2001 + TTimo + - http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=100 + can't locate the "textures: in use" problem, has been fixed already? + now selecting the right entity in the list, had to go around an inifinite recursion problem + (i.e. selection message in the entity class list causes UpdateSel recursion) + +04/07/2001 + TTimo + - added botclip to missionpack/common.shader + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=114 + +01/07/2001 + TTimo + - backported cons scripts to Alpha branch. Type 'cons' at the head to build + regular makefiles should soon be outdated.. + +30/06/2001 + TTimo + - updated the IS script (Gtk changes and and BACK problem) + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=68 + - bunch of fixed to make it build on win32 against new STLPort + http://zerowing.idsoftware.com/STLPort/ + using an STLPort configured locally in GtkRadiant (with stl_config.h, new file) + +29/06/2001 + TTimo + - fixed GDI leak affecting text widgets, specially the console and the entity inspector + +18/06/2001 + TTimo + - more win32 project file cleanup, removing libs/libxml2 from the tree + - importing back "gtkr_list.h" from 1.2, made Alpha branch STLport compliant too + http://www.qeradiant.com/faq/fom-serve/cache/174.html + +30/05/2001 + TTimo + - added libxml2 as an external dependency. libxml2 should be installed as a seperate + directory on win32. dynamic linking now instead of static previously. + - cleaned up q3map win32 project file, removed opengl dependency + (the drawflag command line is inoperant now .. I don't think it was used anyway?) + +26/07/2001 + TTimo + - checking in Gef's doxygen files + +14/06/2001 + TTimo + - added .dsp for map module on win32 + - fixed several issues with module loading, stability of the debug and release builds + http://www.qeradiant.com/faq/index.cgi?file=197 + +12/06/2001 + TTimo + - got rid of of SysMsg thing, using SysPrintf and SysFPrintf now + - got rid of InfoMsg functions (can't remember what it was) + - changed the m_pfnError in the plugin API to match Radiant's (void)(char *, ...) + - changed Warning to Sys_Warning, as #define to Sys_FPrintf(SYS_WRN, + +11/06/2001 + TTimo + - new map module, in plugins/map, required for execution (linux Makefiles written, win32 needs to be) + this is using the imap.h interface + - added Sys_ functions to the main table (Sys_BeginWait Sys_EndWait) + - got rid of AFX_MANAGE_STATE macros .. those are crappy MFC remnants + - reverted Spog's changes to the console logging switches to their original behaviour + - removed m_fVersion from the func table .. we use the size of the table to do the checks + XMLmap merge from 31/11/2000: + - started moving the map loading code into a module + +08/06/2001 + TTimo + - updates to the plugin loading code, verbose a bit more, and more interesting information + +05/06/2001 + TTimo + - some fixes to vfspk3 string code, using the proper str implementation + http://www.qeradiant.com/faq/index.cgi?file=175 + - added and tweaked various cons build files, Radiant 1.2 core and required Q3 modules are building now + - fixes to image module + +04/06/2001 + TTimo + - started using cons for the linux (*NIX) build system + see http://www.dsmit.com/cons/ + + SPoG + - Fixed drawing too much coordinate text in XY window + - Changed grid line drawing in XY window to be more consistent + - Fixed clipper-tool-uses-caulk to only apply common/caulk to solid opaque brushes + (shaders.dll now parses some new surfaceparms) + - Changed shader parsing to pass over layer information in shaders, + rather than parsing and ignoring it all + - Changed misc_model selection to ignore back-facing triangles + - Added axes to show the grid origin in XY window + - Changed misc_model rendering and selection to minimise the number of extra + transformation calculations + - Fixed texture directory listing to allocate and free memory correctly using vfs + - Added qglDeleteTextures() to plugin GL API - fixes crash + - Fixed image.dll to correctly allocate and free memory for jpgs + - Moved modules to /modules from /plugins, updated win32 project files. + (linux/mac makefiles will need to be updated) + - Changed console logging toggle in main() to automatically disable logging after any successful startup + - Changed console logging to only activate when a Release build finds a .pid file + - Changed "found .pid" and "logging console output" messageboxes to give a clearer message + - Added vfsFreeFile - which is kinda redundant if we use g_free and g_malloc for everything + +31/05/2001 + TTimo + - cleanup of the win32 project file and C++ options.\ + Turned off exception handling, changed some code generation options and fixed + some threaded/non-threaded linking problems + - STL in GtkRadiant or a plugin must now use STLPort + a custom configured version of STLPort is available at http://zerowing.idsoftware.com/STLPort + still need to write some guidelines about it + bascially, we are using STL: iostreams disabled, no namespace, no threading, no exceptions + +30/05/2001 + TTimo + - removed libxml2 from tree, use a seperate libxml2/ directory next to GtkRadiant/ for win32 + libxml2 will be distributed seperately as an archive based on official release (same as win32 Gtk SDK) + (check on zerowing for the latest archive) + libxml2 is now used as dynamic shared object on win32, makes sense since many module will rely on it + - cleaned q3map, removed GL dependencies + - updated Debug and Release builds on win32, it compiles and runs now + +28/05/2001 + Spog + - moved vfsExtractRelativePath and vfsGetFullPath to vfs.cpp in vfspk3, + added vfsExtractRelativePath and vfsGetFullPath to IFileSystem. Copied BuildShortPathName() from qe3.cpp to vfs.cpp as a Temp fix. + - Changed Error() calls in bmp.cpp as a Temp fix, they relied on definition of Error in qe3.cpp. Should probably use Error() from cmdlib instead. + - Fixed unresolved external in jpgload.obj - merged bufsize argument into jpeg_stdio_src from Alpha branch... assuming Alpha is the newer version. + - Changed GtkWidget* to void* in image.cpp.. this could be cleaned up more.. i only did enough to make it compile. + - Added jpeg.cpp to msvc project for image.dll.. changed declaraction of LoadJPG() in image.cpp to an extern... is this correct? + - TODO: update vfs.cpp, vfspak.cpp and vfs.h in plugins/vfspak + - fixed unresolved external load_pixmap() - merged load_pixmap declaration from Alpha branch into gtkmisc.cpp + - moved vfsBasePromptPath() to qe3.cpp as a Temp fix - not currently required in vfs module, but it will be in future. + - two calls to free() in texwindow.cpp freeing memory allocated by vfs module, causing debug assert errors - changed them to g_free() + - TODO: Delete vfs.cpp and vfs.h from /radiant + TTimo + - additional fixes after Spog's merge (linux version), removed messaging.cpp messaging.h (name changed to ui.h ui.cpp) + updated linux makefile accordingly + - merge of Alpha version into trunk (massive amount of changes and merges, not detailed) + +25/05/2001 + TTimo (Alpha branch) + - merged the recent MacOS branch back into Alpha + this makes a potential source codebase for a MacOS release + +24/05/2001 + TTimo (Alpha branch) + - patching Spog's recent changes to fix linux build + using DBL_MAX and FLT_MAX from for float and double max + +23/05/2001 + TTimo (Alpha branch) + - testing Spog's write access + + SPoG (Alpha branch) + - Added variable LOD for PatchMeshes based on curvature + - Added LOD-matching to eliminate gaps between patches with mismatched LOD + - Fixed texture shift/scale on LOD'd PatchMeshes + - Added opengl lighting (three infinite light sources) + - Added dynamically calculating vertex normals for PatchMeshes, for gl lighting + - Added decoding/transforming md3 vertex normals for gl lighting + - Changed camera drawing routine to minimise gl state changes + - Removed Patch_InsertDelete() - not functional + - Added CV lattice to selected patches + - Added Per-polygon patch selection + - Added Per-polygon misc_model selection + - Changed default "patch subdivisions" to 4 + - Rewrote camwindow drawing to only change opengl state within the camwnd's member functions + fixes all rendering modes to be more consistent, speeds up rendering + +--------- GtkRadiant 1.1-TA win32 and linux release ---------- + +13/05/2001 + + Spog (patched in TTimo) (Alpha branch) + - Fixed "Fix entity-target/targetname collisions" to use next available tN if tN, else use next available name_N + - Changed patch point selection to pick already-selected points in preference over non-selected + - Changed RemoveCols and RemoveRows to not extrapolate unless a col/row is selected + +11/05/2001 + TTimo (Alpha branch) + - final fix pass to the generated version and about message tags + - improved texture adjustment code (shift+arrows shortcuts) + + texture adjustment commands now affect the texture relatively to their current orientation + they will move along their texture axis, and not along world axis + the texture adjustment commands are now interpreted to be more intuitive: + Radiant will match the up/down/right/left translation messages to the face that is affected + depending on the way the camera is looking at the face, the right move commands will be used + + changes start in Select_ShiftTexture, using new ShiftTextureRelative_Camera + + ShiftTextureRelative_Camera uses several new functions: + + // get the two relative texture axes for the current texturing + BrushPrimit_GetRelativeAxes(f, vecS, vecT); + + MatchViewAxes does the matching between up/down/left/right commands and world directions: + // vec defines a direction in geometric space and P an origin point + // the user is interacting from the camera view + // (for example with texture adjustment shortcuts) + // and intuitively if he hits left / right / up / down + // what happens in geometric space should match the left/right/up/down move in camera space + // axis = 0: vec is along left/right + // axis = 1: vec is along up/down + // sgn = +1: same directions + // sgn = -1: opposite directions + // Implementation: + // typical use case is giving a face center and a normalized vector + // 1) compute start and endpoint, project them in camera view, get the direction + // depending on the situation, we might bump into precision issues with that + // 2) possible to compute the projected direction independently? + // this solution would be better but right now I don't see how to do it.. + void CamWnd::MatchViewAxes(const vec3_t P, const vec3_t vec, int &axis, float &sgn) + + // shift a texture (texture adjustments) along it's current texture axes + // x and y are geometric values, which we must compute as ST increments + // this depends on the texture size and the pixel/texel ratio + void ShiftTextureRelative_BrushPrimit( face_t *f, float x, float y) + + those functions are using various new utility functions: + + // GL matrix product + void GLMatMul(vec_t M[4][4], vec_t A[4], vec_t B[4]); + + // project a 3D point onto the camera space + // we use the GL viewing matrixes + // this is the implementation of a glu function (I realized that afterwards): gluProject + void CamWnd::ProjectCamera(const vec3_t A, vec_t B[2]) + + - UI abstraction layer (interfaces for Gtk MFC and Q3 UI) + +09/05/2001 + Maj (Alpha branch) + - new splash screen + + Spog (patched in by TTimo) (Alpha branch) + + patcing in changes: + - moving void VectorSnap(vec3_t point, int snap); to mathlib + - NOTE: STL dependency removed .. leaving this comment + this will rely on M$ implementation of STL on win32 and the libstdc++ for linux + it should work fine for basic stuff + but M$ implementation doesn't follow the standards when it comes to advanced stuff + it is probably better to leave the STL header in local files and not go towards including it directly from qe3.h + + Spog's Changelog: + + rushing this a bit.. make sure you check it doesn't remove anything you + changed. This only contains changes within /radiant .. i'm pretty sure I didn't + change anything else, but i'll check again. Patch below. + + Fixed ctrl+G SnapToGrid, now never creates degenerate face-planes + Fixed setting an origin for multiple brushes to use origin point of fixedsize + entities + Fixed mirroring and rotation of fixedsize entities including misc_model + Fixed undo/redo on multiple entities to link brushes to entities correctly + Fixed "view > entities as.." menu to display correct default setting + Fixed "view > entities as.." toolbar button to show menu + Changed selection-area of edge/vertex control handles to stay constant when + zoomed + Fixed undo on ctrl+G SnapToGrid + Fixed Selection Invert to set bSelected correctly on patches + Fixed XY-window Z selection origin to be g_MaxWorldCoord + Changed RotateIcon to draw same size at all zoom levels + + Fixed origin drift on saving misc_model with null md3Class + Fixed creation of cap for 'Bevel' type patches + Fixed inverted cap being created for 'Endcap' type patches + Fixed inverting patches on mirror operations + Added snap-selected-to-grid affects only the patch points selected + Cleaned up Select_ApplyMatrix and Select_SnapToGrid + Added drawing of brush planepts in debug build + Fixed texture quality slider adjustment + Removed redundant menu items curve > cap > inverted bevel/inverted endcap + Fixed texture scrolling not working when scrollbar is disabled + Fixed textures with odd dimensions being skewed with texture quality less than + max + Changed Patch Inspector Horizontal/Vertical increment to use pixel values + (default 8) + Changed Patch Inspector Horizontal increment to subtract from S values but not + T values + Changed Patch Inspector Stretch spinner to do something useful + Changed Patch Inspector Stretch default amount to 0.5 + Changed Arbitrary Rotation dialog to reset rotation spinner values to 0 on Apply + !! stops output in console window !! - Added sending q3map output + to /temp/junk.txt to bsp commands, in win32 only + Fixed Patch_Naturalize to calculate T values backwards, correcting texture + vertical flip + Changed patch row/column Insert/Remove to interpolate/extrapolate from existing + curves + Fixed point selection on patches when new points are added + Fixed redundant edge/vertex handles being created for patch brushes and + fixedsize brushes + Fixed refusal to activate brush vertex-drag mode if any patches are selected + Partly fixed Undo picking up patch point drags when no points are selected + Fixed behaviour of vertex selection on patches + Fixed patch point colours in textured mode in cam window + Changed patch point selection to update selection pool on each selection click + +06/05/2001 + TTimo (Alpha branch) + - more setup script changes, will rely on version information + various other fixes in the script file + +02/05/2001 + TTimo (Alpha branch) + - added makeversion.sh to the root, will generate version and date files before compilation + version.h and date.h + - cleanup and fixes to the linux setup scripts + + Spog (CVS add and config by TTimo) (Alpha branch) + - win32 setup script, run setup/setup.sh from cygwin to create a working directory for the setup + +01/05/2001 + TTimo (Alpha branch) + - fixes to linux version from previous set of patches + +19/04/2001 + Hydra (patched in TTimo) (Alpha branch) + http://fenris.lokigames.com/show_bug.cgi?id=3458 : + - *.pfb filter + + SpoG (patched in TTimo) (Alpha branch) + - updated setup data: entities.def common.shader(Q3) and common-spog.pk3 + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=25 : + - Patches: Curve > matrix > redisperse > rows/columns + I changed this function to treat a patch as multiple 3by3 sections when doing + redispersal of control points. The effect is that green patch points are never + moved. I also removed the call to Patch_Naturalize, so the texture coordinates + are not changed (user can hit ctrl+n to naturalize afterwards if desired). + - rewrote the patch_captexture function to be more reliable + - Fixed YZ view drawing and selection being mirrored on plane X=0 + - Fixed X and Z rotation direction to be clockwise as shown on the toolbar button + icons + http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=8 : + - Fixed: Removed orientation-switching hack to fix 2pt-clip orientation problems, + originally stemming from ass-backwards representation of grid axes. Fixed + clipper to generate 3rd clip point correctly for each axis instead. + - Fixed: Stopped clipper-caulker from NOT applying caulk if the first face of a + brush was "common/caulk". + + TTimo (Alpha branch) + - removed some unused code in the Gtk file dialog, hopefully stabilizing it + +02/04/2001 + TTimo (Alpha branch) + - changed the regular/BP conversion prompt + +01/04/2001 + Spog (patched in by TTimo) (Alpha branch) + - Fixed view > show coordinates now affects Z window + - Fixed minimum/maximum world coordinates now -65536/65536 + - Fixed view > show blocks now only draws vertical lines if not XY view + - Added variable blocksize (gtkr only displays 1024 < blocksize < 65536) + - Changed XY/Z window grid drawing to use floats internally + - Fixed broken XY window grid drawing for higher zoom levels + - Changed camera and Z-checker icons to stay the same size when zoom level changes + +24/03/2001 + Spog (patched in by TTimo) (Alpha branch) + - added filters.cpp to the VC6 Makefile. Linux build needs updating + - Changed Filter system to use brush-flags updated only on actions that affect filtering + - Changed Filter system to allow further extension and future customisation + - Changed show/hide to use brush filter flags + - Changed Find/Replace textures to only rebuild brushes that changed. + - Changed View > Filter menu shortcuts and behaviour + - Fixed various minor spelling errors + + TTimo (Alpha branch) + - Fixed the 'Clean' command in preferences, used to remove only Radiant.ini and not SavedInfo.bin + +06/03/2001 + TTimo (Alpha branch) + - better parse error information: added the line number of the error in (hopefully) all cases + +30/02/2001 + TTimo (Alpha branch) + - texture locking in BP mode for axis flipping and axis rotation (toolbar buttons) (Id bugfix request) + - fixed undo in BP mode + - MatchToken error message in q3map improved with the script name + +27/02/2001 + TTimo (Alpha branch) + - switched linux makefiles to xml2-config instead of xml-config + latest version of libxml2 is using xml2-config instead of xml-config now + +26/02/2001 + TTimo (Alpha branch) + - fixed a loki_initpath misbehaviour, was overriding the path to the binary with RADIANT_DATA if defined + +21/02/2001 + - Added setup data and a script to build linux setups to the cvs + TTimo (Alpha branch) + - various printf -> Sys_Printf + - added vslick/ directory for Visual Slickedit 6.0 on win32 <- THIS IDE RULES + +20/02/2001 + - Removed "Show Paths" option, already in the filter menu + +19/02/2001 + - Fixed the Enter key handling on the surface inspector (suggested by Spog) + - Fixed skewed textures with lower texture quality + - Changed the order the include directories are searched under Linux + +15/02/2001 + - Moved the Show Cluster Portals option to the Filter menu + - Fixed the rotate and scale toolbar buttons being incorrectly checked + - Fixed arbitrary rotation bug (#3073) + +14/02/2001 + - Fixed CreateFont memory leak on glwidget + +12/02/2001 + TTimo (Alpha branch) + - fixed save as prefab stuff (right dialog name and overwrite prompt) + +10/02/2001 + TTimo (Alpha branch) + - was crashing on win32 boxes where HOME env var was not defined (loading bookmarks) + +09/02/2001 + TTimo (Alpha branch) + - change some code in the file dialog to use g_malloc g_free instead of new + for win32 file dialog and malloc for Gtk file dialog. (all of this trying to get rid of + some of the crashes) + +07/02/2001 + - Fixed Load command initial path + - Fixed some toolbar buttons not being correctly initialized + +-----------? + +06/02/2001 + (Alpha branch) + - Fixed pk3man file dialog errors + - New RC uploaded + - Changed conflicting shortcuts: FilterModels = Shift+M, FilterTriggers = Ctrl+Shift+T + TTimo (Alpha branch) + - fix to hide/show, still selecting hidden brushes + +05/02/2001 + (Alpha branch) + - Fixed compile errors (use stat, not _stat) + - Removed --nofonts option + +04/02/2001 + TTimo (Alpha branch) + - fenris #2866, added a pref to turn on/off name conflicts resolution, rewrote the whole algorithm + - fenris #2823, fixed patch and brush dragging in 0.25 0.5 grids (it's an ugly hack btw) + - fixed the black squares at end of line in Gtk text boxes + RR2DO2 (Alpha branch) + - fix to the "entitypath" fixup in QE_CheckProject. might not compile on linux yet (use of _stat?) + +03/02/2001 + TTimo (Alpha branch) + - fenris #2867, limiting the amount of "spawnflags" "0" appearing in entities. This bug has work left to do, + there are some oddities in the entity inspector behavior described. + +02/02/2001 + (Alpha branch) + - Fixed sleep mode not restoring windows correctly + - Fixed some minimize/restore issues on floating views mode + TTimo (Alpha branch) + - fixed more gtkfilesel stuff. pattern filtering works for both Gtk dialogs + and win32 native. Also checked on linux that it compiles. Renamed gtkfilesel.h + to gtkfilesel-linux.h for consistency. + +31/01/2001 + (Alpha branch) + - New file selection widget with filtering, masks and all other shit we need + TTimo (Alpha branch) + - changed some gtkfilesel API and fixed some bugs on pattern filtering, need to reboot on linux and fix some more + +30/01/2001 + (Alpha branch) + - Added an option to keep the Z and XY views on the same window in floating views mode + - Did some cleanup + TTimo (Alpha branch) + - removed the 3 layers in terrain entities limitation, increase version tag to patchlevel 3 + sent for testing to AstroCreep, bug is still there + - fixed one more thing with RC file (get it in the right dir) + - worked on file dialog and pattern filtering, still issues left + +29/01/2001 + Jonas (patched in by TTimo) (Alpha branch) + - Using RC file to tweak the font size on win32, looks much nicer now! + - Fixed fenris #2773: esc key behaviour when group window has focus / dependant on view modes + +28/01/2001 + TTimo (Alpha branch) + - Finished fenris #2810 (Snap T to grid), it was a bitch + - Fixed fenris #2769: raise the brush max size (it was already big, now it's just not sane) + - Fixed fenris #2965: eclass (entities) loading code broken, needs to be checked on linux build before closing + +27/01/2001 + TTimo (Alpha branch) + - Fixed vertex edit prefs broken + - more fixes in Gtk libs + - Fixed clipping + brush primitives bug (#2644) + - Fixed clip caulk related issues (#2912) + - Added Snap T to grid back (#2810) <- still need to test and validate it, I'm too tired tonight + +25/01/2001 + TTimo (Alpha branch) + - New Gtk file selection dialog seems stabilized, built a Gtk SDK for the new Gtk libs. + +24/01/2001 + (Alpha branch) + - Fixed elapsed time displayed by q3map + - Fixed Radiant loading some TGA files upside down + TTimo (Alpha branch) + - more work done on the file selector. Added a win32 pref to select between regular win32 file dialog and Gtk one. + The advanced file selector is still not stabilized on win32. I am thinking about letting go and sticking to the regular one. + +23/01/2001 + (Alpha branch) + - Fixed q3map not finding md3 files under missionpack/ + - Prompt to save changes when choosing a recent file + - Fixed window title when choosing File/Load Map + - Don't show hidden brushes in the Z window + +22/01/2001 + (Alpha branch) + - More File Dialog fixes + +21/01/2001 + TTimo (Alpha branch) + - version first version of the advanced file selector on win32 + seems to work nicely, but crashes when you actually load something .. needs debugging! + + leo (Alpha branch) + - Set correct initial directory for the File/Load command + +17/01/2001 + (Alpha branch) + - Fixed q3map is crash if a .shader file is referenced in shaderlist and not found + + TTimo (Alpha branch) + - fixed some license headers on gtkfilesel.c, started looking into porting gtkfilesel.c to win32 + +16/01/2001 + raistlin + - the tree is opened whoooo! + + TTimo (Alpha branch) + - replaced the old Id header by the newer version (BIG update, to trunk and Alpha) + - switched str.h to BSP + - added LGPL license to the sample dll + +15/01/2001 + (Alpha branch) + - Added camera window toggle option to all views mode + + TTimo + for trunk and Alpha: + - renamed TOOL_SOURCE_EULA to LICENSE_ID + - renamed CONTRIBUTOR to CONTRIBUTOR_AGREEMENT + - added CONTRIBUTORS and LICENSE + +14/01/2001 + (Alpha branch) + - plugin SDK is back in setup/ moved the sample dll to be in plugins/, need to rewrite the SDK scripts + - built a lightweight plugin SDK with cygwin makefile for the sample plugin + +12/01/2001 + (Alpha branch) + - Set map modified flag when deleting a brush + - Minimize all windows when the main window is minimized in floating views mode + +11/01/2001 + (Alpha branch) + - Cleaned up the View/Show submenu + - Fixed texture menu splitting + - Fixed major grid lines on 128 and 256 grids + - Load only a single .def file if specified in the project settings + - Fixed q3map Makefile + + TTimo + (Alpha branch) + - Removed plugins/shaders from Alpha branch + - got rid of common2/ and code, moved qfiles.h and surfaceflags.h into common/ + - put the licensing headers in all source files (forgot some? byte me) + +10/01/2001 + leo (Alpha branch) + - Added new filter system based on FAKK2 Radiant + + TTimo + - fixed whatever could be fixed to make it compile with the new directory layout + (Alpha branch) + - project files update + +09/01/2001 + (Alpha branch) + - Added undo for patch redisperse rows and patch redisperse cols commands + - Fixed Show Z Outline menu item + +30/11/2000 + TTimo + - removed content flags and value from qtexture_t, these have moved to the IShader + (NOTE: qtexture_t != texdef_t, texdef_t still using flags value and content) + + - Rewrote the linux plugins Makefiles + +29/11/2000 + - Improved the way modules are loaded + - Added new parameter to QERPlug_RequestInterface + - finished VC6 project files conversion for new directory structure + - fixed shader blending on terrain maps bug + +08/01/2001 + - Updated Makefiles for the new directory structure + - Fixed View/Show/Entities menu not being checked correctly + - Fixed "Invert Selection" command selecting hidden brushes + - Fixed "Select All of Type" command not working correctly after the Enitity Window is closed + - Fixed grid being drawn even when it's the same color of the background + - Fixed "Toggle Size Paint" not turning off + +05/01/2001 + - Fixed autosave interval being calculated wrong + - Fixed autosave path under Linux + - Fixed q3map crash when trying to load missing pcx files + - Fixed q3map not finding .bmp files for the terrain alpha map + +04/01/2001 + - Fixed GL stack underflow when loading a misc_model + +03/01/2001 + - Fixed patches remaining half-selected after "Region set selected" (#2748) + - Fixed Surface Inspector spin buttons rate (#2776) + - Fixed some shortcuts not appearing on menu items (#2786) + + +================================================================================ + 1.1-TA beta +================================================================================ + +02/01/2001 + - Fixed memory problem if a file without extension is entered in the file save dialog. + - Fixed double slashes "//" on filenames when saving a map + - Fixed pk3man plugin not finding the toolbar bitmaps + - Fixed double clicks being considered 2 mouse clicks + + RR2DO2 (applied by TTimo) + - Clusterportal filtering ('View > Show > Show clusterportal' toggle) + +01/01/2001 + TTimo + - updated Web/ with new stuff, web site ready for release + - fixed a crash with multiple edge dragging on win32 (was caused by compiler optimizations, + this one was a major pain) + +31/12/2000 + - fixed the file open/save dialogs initial directory + + RR2DO2 (applied by TTimo) + - bug fix in the terrain loading speedup + + TTimo + - tried to lookup the Z window minimum width problem, added #define DBG_WINDOWPOS code to investigate + +30/12/2000 + RR2DO2 (applied by TTimo) + - fix to CSG Merge in the menu drop down (menu was there, command not hooked) + - some message formatting fixes + + TTimo + - rudimentary pattern matching in file selection, affects the plugin API too + - fixed silly bug in the "clipper uses caulk" code + - major speedup to the loading code on terrain entities + (in mpterra2, from 113s to 4s for the main terrain entity) + - patched back the file open/save dialogs initial directory to override in TA mode + - fixed Patch output crash in the plugin API + - fixed BP conversion in the brush output of the plugin API + + minkey (applied by TTimo) + - fix to the m_pfnLoadFile code to use VFS + +29/12/2000 + - Remember main window position in floating views mode + - Fixed wake up when running the engine in floating views mode under win32 + + TTimo + - various fixes and debug hooks for PJ bug reports + +28/12/2000 + - Fixed VFS initialization order + - Removed texture menu splitting option from preferences (now it's automatic) + + TTimo + - built an initial setup, updated the changelog file for 1.1-TA-beta + +27/12/2000 + - Fixed Q3Map output window being too wide on some errors + - Added VFS to q3map + + TTimo + - replace a printf in q3map by Sys_Printf (!), which is what should actually be used + - added a set of functions to vfs to help with file dialogs, building relative files etc. + - reworked the file dialogs so they default in the right location (open/save as/md3 loading/sound loading) + - fixed shader editor to work with the right path + +26/12/2000 + TTimo + - put the converted HTML manuals (Radiant, shaders and model) in the tree (and the win32 setup) + - added the new Terrain and Team Arena mapping manuals (added to the setups too) + + leo + - Copy and paste across different instances of Radiant + - Fixed wait cursor when copying + - Print engine command line to the console + - Fix glib warnings when running the engine + - Fixed shader files being loaded twice + - Texture menu now automatically breaks when it reaches the maximum screen height + +24/12/2000 + - Fixed q3map to compile with the new LoadJPGBuf parameter + + TTimo + - added TA paths to the BSP commands and running engine + - fixed a bug if running with monitoring disabled (generating the .bat was borked) + - changed the -moddir implementation to a global switch in q3map (same as -connect) + - moddirparam as a global variable in cmdlib, added a TA_HACK in there + - changed the SetQDirFromPath to stick to "baseq3/" when using -moddir + TODO: check standalone files + +23/12/2000 + TTimo + - fixed some sleep/wake code (crashes and wakeup problems on models) + - vfsInitDirectory for TA directory (needs to be checked on linux) + - changed my mind on entities.def, if TA is enabled, load entities-TA.def on top of regular entities.def + + mickey (applied by TTimo) + - some memory overrun fixes + +22/12/2000 + - Fixed plugin Makefiles to not use private/ + + RR2DO2 (applied by leo) + - Fixed SetTallBrush undo + - Added bug report link to help menu + +21/12/2000 + - Daily Linux compilation fixes + - Fixed q3map to read .pk3 files from the directory set by -moddir + - Fixed vfs not listing all files correctly + - Fixed libjpeg crashing on some jpeg files + - Load .def files depending on the current game + +20/12/2000 + - Applied Mickey's patch to fix win32 window position save/load. + - removed missing _msize call + + TTimo + - cleaned up more g_malloc g_free problems, cleaned a INPUT_BUF_SIZE problem in jpeglib + +19/12/2000 + - More manual updates + - Fixed bugs comparing file extensions + - Added VFS to the Alpha branch + + TTimo + - moved game selection to the project settings + - got leo's vfs fixes, started changing the memory allocation scheme to glib + - moved 'free' calls to g_free with a #define in cmdlib, Radiant seems to run nicely again + - removed calls to _msize .. those were causing heap debug assertion failures + - upped more stuff + +18/12/2000 + - Added popup menus with the list of active textures to the find texture dialog + - Fixed some menu checkbuttons + - Changed max number of shader files parsed by q3map to 128 + - Updated manual images + +17/12/2000 + - Fixed bug with the texture window scrollbar range + + Mickey (patched in by TTimo) + - fix to the floating windows mode, don't send windows to the desktop when raising something else (#2659) + + TTimo + - finalized the merge and move into worldspawn commands by adding the undo stuff + - fixed the clamping problems when flipping or mirroring patches + - added 0.5 and 0.25 grids + - added undo to Select_CompleteTall Select_PartialTall and Select_Inside + - added on-the-fly conversion between regular brush coordinates and brush primitives texturing in the plugin API + +15/12/2000 + - Fixed crash on Shift-A (Select all of type) + - Save the state of the toolbar buttons + - Remember the state of the Show Patch Bounding Box button + - Double clicking on an entity on the Entity View tree selects the entity + - Sort the list columns of the map info dialog + - Fixed a bug that would allow multiple Entity View dialogs + + Mickey (patched in by TTimo) + - saving position and size of the entity window between runs and during usage + + TTimo + - two new commands in the drop down menu: + "move into worldspawn" will move selected brushes to worldspawn and eventually delete entities which end up with no brushes + "merge brushes" will merge brushes into an entity (from worldspawn or from another entity) + - added cleaned HTML version of the editor manual in the tree + +14/12/2000 + - When pressing a letter key in the entity window list, scroll to the entity starting with the key pressed + - Fixed backspace not working on the texture subset entry + - Added version check when loading savedinfo.bin + + TTimo + - started implementing Select_Merge and Select_Seperate for workflow improvement on terrain maps + +13/12/2000 + - Finished GtkGenSurf + + RR2DO2 (merged in by TTimo) + - patch to q3map, added option -custinfoparams for custom surface flags (still need documentation) + + TTimo + - zoom out and grid drawing taylored to the world size + +12/12/2000 + TTimo + - quick win32 update to gensurf + - fixed #2610 (MAX_NETMESSAGE) .. needed a consistent rewrite of the way we parse the stream + +11/12/2000 + - Fixed linux compiler errors from recent changes + Not fixed today but I forgot to add those to the Alpha changelog + - Fixed multiple Map Info dialogs bug + - Fixed texture window not scrolling to the top when a new directory is loaded + - Fixed GL Windows grab pointer bug + - Fixed crash after map compilation if the map leaked + - Fixed q3map crash if MAX_SHADER_FILES is reached + +28/11/2000 + - Fixed sleep mode restoring hidden windows (win32) + - Fixed find/replace textures dialog layout and keep it always on top of the main window + - Replaced malloc/free calls with g_malloc/g_free to avoid the win32 limitation + +27/11/2000 + - Removed glu.h dependencies + - Added new file selection dialog + - Removed g_PrefsDlg.m_bDisableAlphaChannel (always FALSE) + - Added shortcuts for sleep and simple patch mesh + - Fixed crash after sleep mode (no GL context current) + +24/11/2000 + - Rewrote the jpeg functions of the image plugin + - Replaced some MFC classes with glib + - More shader plugin fixes + - Fixed bug with select all entities command + + TTimo + - fixed q3map to handle the new LoadJPGBuff length parameter + +22/11/2000 + - Fixed crash in Error() if there's no current GL context + - Fixes to the shaders plugin + + TTimo + - created VC6 project file for image module + - modified the m_pfnError in qerplugin.h to use (char *, ...) construct + +21/11/2000 + - Ensured that the plugins are loaded in the correct order + - Added Sys_FPrintf and Sys_Printf to the plugin interfaces + - Some VC++ fixes + + TTimo + - more fixes to the world size + - modified moduleentry_t so it compiles on win32. need to update the code in all modules probably + - other minor fixes and updates to get everything building on win32 + +20/11/2000 + - Moved image loading code to a plugin + - Fixed some bugs in the shader plugin + - Now using glGenTextures to set texture ids + +19/11/2000 + TTimo + - shader code removed from Radiant core, relies on shader module + - added ctrl-alt-LBUTTON = multiple brush select without selecting whole entities (from TA update) + - added an XML testing proggy in DevDocs/ + +18/11/2000 + TTimo + - shader module is compiling + - reworked the way we deal with required interfaces, + automated the interface request process and added code to check the required modules have been found + +17/11/2000 + - Q1 VFS plugin + - Changes to the VFS API to detect the format supported by a plugin + - Added checks to PluginManager to load the correct VFS plugin + + TTimo + - made a mess with XML MAX_NETMESSAGE error, still not fixed + - merged q3map 1.0r (TA update from Id) into the tree - important files modified: surfaceflags.h qfiles.h + +08/12/2000 + TTimo (shit I'm 24 now) + - added gtk gensurf, VC6 project files are up to date, linux Makefile not checked + - fix some WINAPI stuff on above code + - add idata.h for raw access to editor data + - new _QERAppShaderTable for shader module -> editor functions + - added new entries in various tables (GL, parser etc.) + - shader module is well under way + +16/11/2000 + - Added a color selection dialog function to the plugin API + - Added profile read/write functions to the plugin API + + TTimo + - MAX_NETMESSAGE bug: patched q3map so it sends in several messages if the problem occurs + still need to update Radiant to recognize XML nodes split into several messages (using an input buffer) + - added a test map for MAX_NETMESSAGE: sput.map + - project file for vfspk3and win32 patching + +15/11/2000 + - More plugin cleanup + - Added IsEqualGUID() to qerplugin.h + + TTimo + - merged Alpha back in (didn't try to merge this CHANGES file) + - backported some stuff from the trunk to here, the Sys_Printf, gtk_MessageBox and profile stuff + - created VC project file for gtk-based gensurf plugin + +14/11/2000 + - Fixed DumpUnreferencedShaders() + + TTimo + - added QE_CheckProjectEntity to check paths are following the right conventions + +13/11/2000 + - Fixed bugs in the vfs plugin + - Added support to vfs plugins in Radiant + + TTimo + - updated project file to libxml2-2.2.8, use libxml2 as the directory name for whatever version.. + NOTE: libxml2-2.2.8 needs some patching to compile right.. + +12/11/2000 + TTimo + - all Radiant functions that might be exported in interfaces need to use the WINAPI calling convention + modified the GTK functions code accordingly + - started writing the shaders module + +10/11/2000 + - Added new GTK functions to the plugin API + - Added 'parent' parameter to MessageBox, file_dialog and dir_dialog + - Fixed Help commands (Linux) + +09/11/2000 + - Fixed bug in the Z wnd code + - Fixed copy text from the console (win32) + + TTimo + - moved the libxml library out of the tree, updated the VC6 project files accordingly + +08/11/2000 + - ZWnd always on top (view #2, win32) + + TTimo + - added Escape key to hide the entity inspector + - S and Shift+S now act as toggles on the inspectors + +07/11/2000 + - Added ungroup command to right click menu + - Fixed message box accelerator bug + - Fixed GL error on win32 startup + + TTimo + - additions to the BSP interface + - fixed DestroyCursor error + - clipper caulks faces (and prefs checkbox) + +06/11/2000 + - Cleaned PrtView and TexTool plugins + - Fixed bug in texture menu names (#2506) + - Added splitters to Entity dialog + + TTimo + - started clipper caulk implementation + - fix to the pointfile not drawing in 2D views + - MAX_BUILD_SIDES in q3map debug stream + +05/11/2000 + - Merged Alpha branch with the trunk + + TTimo + - more plugin interface for Q3Build, and plugin SDK additions + - merged q3map Realloc back into Alpha branch + +04/11/2000 + - Fixed crash during startup if Zwnd was hidden in views #2 and #3 + - Fixed ToggleConsole command + - Fixed ToggleEntity and ToggleTexture commands in view #2 + - Fixed plugin Makefiles + - Removed -rdynamic from Radiant link options (crashes pk3man plugin) + +03/11/2000 + TTimo + - directory reorganisation for the plugin SDK, added an interface/ directory + +02/11/2000 + - Save ZWnd state in views #2 and #3 + - Entity dlg always on top (linux) + - Fixed shortcuts.ini parsing bug + - Fixed editpad crash if editpad not present (win32) + - Fixed bugs in the internal shader editor + - Fixed widget_show if window moved after gtk_widget_set_uposition + +================================================================================ + 1.1 beta +================================================================================ + +31/10/2000 + - Continue loading if glXGetProcAddressARB is not present (Utah-GLX fix) + - Fix BSP commands not working if a map is not in "mapspath" (linux) + +30/10/2000 + - fixed the Region commands, "Region > Set brush" is working + Region uses the camera as spawn point. + - Fixed view/show menu initialization + - Fixed warning when starting view #2 + - Fixed z wnd in view #3 + - Fixed win32 sleep mode crashes on views #2 and #3 + - Added "Restart" message when changing texture quality in the preferences + - Cleanup: removed radbsp.cpp (unused) and unzip.cpp (already in pak.a) + +29/10/2000 + - Fixed SIGCHLD handler + - Built 1.1b setups + +28/10/2000 + - Fixed q3map bug visbytes > MAX_MAP_VISIBILITY + - Fixed clipper display bug + + TTimo + - updated quakev2.qe4 with -vlight options + - added checks in q3map to prevent crashing on allocating a winding too big + will stop with an error now. + - added the corresponding editor support for debug messages if MAX_POINTS_ON_WINDING is exceeded + + G_Dewan + - improved q3map, reducing minimal memory footprint by about 45Mb + +27/10/2000 + - Fixed crash in BSP debug window + - Reorganized the preferences dialog + - Fixed q3map Makefile + - Fixed +/- bug in win32 (Gtk patch) + - Fixed Alt shortcuts bug in win32 (Gtk patch) + - Fixed q3map crash when visbytes > MAX_MAP_VISIBILITY + + TTimo + - improved snapshots behaviour, doesn't snapshot non-modified maps + +26/10/2000 + - Fixed patch inspector not showing after it has been closed + - Added 'Reset' button to entity dialog + +25/10/2000 + - Fixed more grid issues + - Fixed load window position bug (saved pos greater than screen resolution) + - Fixed selection nudge bug + - Improved entity windows layout + - Fixed GL font not being recreated when exiting sleep mode + + TTimo + - cleaned m_nTextureTweak and m_bSnapTToGrid + - improved the CycleCapTexturePatch command, now cycles across the 3 planes only + and works on multiple patches at once + +24/10/2000 + - Added an overwrite prompt when saving files + - Fixed 128 and 256 grid display + - Commented-out grouping code (not functional yet) + +23/10/2000 + - Fixed q3map to load jpgs under Linux + - Fixed wake-up crash when floating windows were closed (#2423) + +21/10/2000 + - More q3map and radiant Makefile fixes + - Remember size/position of the entities dialog + +20/10/2000 + - Redirect Gdk warnings + - Draw border around active XY wnd + - Moved some scripts to the Makefile + - Added shift+rclick to zoom in/out + - Removed minimize/maximize buttons for z wnd in floating mode under win32 + + TTimo + - Two new entries in View > Show: Show Outline and Show Axes + Show Outline turns on/off colored outline of the current view + Show Axes turns on/off display of a small axis base in the 2D view + - fix q3map Makefile to use external libxml2 source + + G_DEWAN + - Fix to bogus noshader error message in q3map + +19/10/2000 + - Added new console functions that support colors + - Revised linux makefile for debug/release builds + - Redirect Gtk warnings to the console + + TTimo + - reorganized the entity inspector window, layout depends on the number of flags to get + more space in the comment window. + +18/10/2000 + - Fixed add/remove bsp items in project settings dialog + - Did some cleanup (removed #define WIN32_CONSOLE) + - Fixed console not working in view #3 + - Fixed warning when exiting in views #2 #3 + + TTimo + - fix to entity inspector comment window for the eclass_t on win32 (removed the white squares) + +17/10/2000 + - Fixed texwindow not scrolling when last texture is large + - Added LOD for patches + - Fixed prefab path & user ini in preferences dialog + +13/10/2000 + TTimo (XML branch) + - basic architecture for XML feedback is functional + see radiant/feedback.cpp radiant/watchbsp.cpp q3tools/common2/inout.c + merging back in alpha + +04/10/2000 + TTimo (XML branch) + - sax interface is in Radiant, need to add a state machine and proper processing + +04/10/2000 + TTimo (XML branch) + - experimental use of SAX interface to parse the stream on the server side, see q3tools/q3map/NetTest + +03/10/2000 + TTimo (XML branch) + - adding libxml2 in the repository, based on libxml2-2.2.4 with project files and stuff to build on win32 + +31/09/2000 + TTimo (XML branch) + - new common2/ dir, output system rewritten through Sys_Printf + - experimental use of libxml + +28/09/2000 + TTimo (Inspector branch) + - shift+arrows matches the increments from the surface inspector + - button 'Match Grid' in the SI to set the increment according to current grid + +25/09/2000 + TTimo (Inspector branch) + - fixed crappy bug in SavedInfo.bin upgrade (when the struct sizes don't match) + - surface inspector has inc step dialog boxes (+saved in prefs) + - face selection is always on (was something weird from the prefs) + - undo works better with the surface inspector + +25/09/2000 + - Added ARB_Multitexture support + +21/09/2000 + - Fixed preferences dialog warning + - Added new grid sizes + +20/09/2000 + - Fixed small bugs reported from Fenris + +17/09/2000 + TTimo + - fixed a bug with template project loading / path to the engine safecheck (a weird hidden one) + G_Dewan & TTimo + - fixes to the process spawning (Q_Exec in cmdlib) + appropriate warning and error messages + Fishman + - antialiased drawing in 2D views + +14/09/2000 + TTimo + - radiant.log commandlist.txt and radiant.pid are create in g_strAppPath on win32 and g_strTempPath on linux + - moved the splash screen after the .pid code + - I suspect a bug in the .pid removal, added a check and message box + - help works again on win32, spawning Word with the Q3Rad_Manual.doc (temporary solution of course) + - surface inspector: removed all Q2 related stuff, fixed horizontal shift, reorganized the widgets layout + hooked the widgets to apply the changes on the fly (the inspectors need a good chunk of work) + - fixed a radiant.pid bug + - added icon to MSVC6 project (with some help) + + G_Dewan + - fix to BSP menu order getting mixed up + - fix to the file dialog + +11/09/2000 + - Added splash screen + +25/08/2000 TTimo + - launch sleep mode before running game + - fixed Map_Snapshot bug + - going to sleep works on view n2, raising is still screwed (contexts) + +24/08/2000 TTimo + - fixed some sleep mode stuff + - fixed map snapshot bug + +21/08/2000 + - fixed stuff to build on linux + - Merged in q3map 1.0p + +18/08/2000 + - Removed "High Color Textures" option (always on) + - Removed "Status Point Size" option + +17/08/2000 + - Fixed win32 console issues + +16/08/2000 + - added g_strTempPath + - restore maximized window state + - fixed logo.bmp + +15/08/2000 TTimo + - fixed keyboard shortcuts + - fixed engine path in prefs (must use the file dialog to change) + - fixed a bug related to engine path and project templates + +15/08/2000 + - Removed QE4 update model option (always on) + - Removed Buggy ICD option (always off) + - Reorganized the preferences dialog to take a bit less space + +14/08/2000 TTimo + - using profile.cpp code to read shortcut keys files + - moved DevDocs/changelog.txt to data/changelog.txt + (data/ should be used for user-side stuff and DevDocs/ for developpers) + - added data/quickstart.txt with a beginning of info about the main differences + between Q3Radiant 202 and GtkRadiant. to be used as a doc later. + +13/08/2000 TTimo + - added DevDocs/WIN32SETUP and DevDocs/changelog.txt + changelog.txt is end user changes + WIN32SETUP the TODO list for install specific stuff + - wrapped a first version of the win32 installers (full and patch) + +11/08/2000 TTimo + - quickfix to put undo/redo back in + - added DevDocs/WIN32SETUP, describes what I'm up to with the setup of win32 version + +10/08/2000 TTimo + - added back the window position saving code that was in earlier tree + NOTE: would have rather have it done in prefs than hooked in mainframe_delete and MainFrame::Create + (would have been cleaner IMO) + NOTE: IT'S STILL BROKEN .. I ADDED THE CODE BUT I MUST BE MISSING SOMETHING + NOTE: it doesn't remember the maximized state. It should. + +08/08/2000 TTimo + - fixed win32 build for GLWidget code, added WINAPI calling convention on all exported stuff + - fixed TexTool to compile under win32 + +07/08/2000 TTimo + - fixed some crash with the new jpeg lib + - fixed console logging behaviour (was always turned on at startup) + - added console logging checkbutton in prefs + +07/08/2000 + - Merged the GLWidget branch + - Merged 202 patches + - Fixed "clean" button in the preferences dialog + - Added pid startup detection + - Updated plugin interface with GLWidget functions + - Updated TexTool plugin + +04/08/2000 + - Added "errno" string to the Error() message box + - More 202 patches + +03/08/2000 + - Merged changes from MFC Radiant 202 + - Fixed the win32 GLWidget stuff + +02/08/2000 + - new OpenGL widget to keep all platform specific code in only one file + +01/08/2000 + - Added code to restore the windows when coming out of sleep mode + - Rewrote the TexTool plugin + +31/07/2000 TTimo + - added vc6 projects for PrtView + - tested PrtView and Radiant against latest binary release of Gtk (works great) + + Leo: + - Updated VC5 projects + - Fixed plugin loading under win32 + - Updated PrtView to compile under win32 + - Radiant is now iconified when going in sleep mode + +30/07/2000 TTimo + - prefs dialog for BSP monitoring + - Added data/ directory with entities.def and quakev2.qe4 + - stabilized syntax of v2 project file, same project file for both platforms + - added DevDocs/WIN32BETA with a list of stuff to do before going on public beta on win32 + - added DevDocs/d2u .. handy script to remove linefeeds from DOS files + - added radiant/radiant.proj, project file for source navigator (SN rules) + + Leo: + - Fixed the logfile crash when ~/.q3a/radiant doesn't exist (fenris #1953) + +28/07/2000 TTimo + - Fix to the win32 console to use window's default font + - Added File > Sleep for experimentation + NOTE: we need to keep Radiant minimized when going into sleep mode + +28/07/2000 + - Finished the win32 console replacement + - Fixed bug 1952 (map loading segfault) + - Added a Makefile to the libs dir + +26/07/2000 + - Added PrtView plugin + - Added qvm target to source/Makefile + - Another release candidate sent to QA + +18/07/2000 + - Fixed the slow updates issue in the win32 version + - Added 3 new variables to fix the paths issue + +17/07/2000 + - Fixed the plugin search directory (broken with the changes to g_strAppPath) + +14/07/2000 + - Increased the timer speed in MainFrame::RoutineProcessing + - Added code to release and recreate the contexts to the win32 version + - Fixed the mouse capture under win32 + +13/07/2000 + - Fixed the new path and bsp problems + - Sent new version to QA for testing/release + +12/07/2000 + - Added "tools/" back to g_strAppPath under linux + +11/07/2000 + - Added code to release and the recreate the GL contexts (linux) + +10/07/2000 + - Changed directory structure + +09/07/2000 + - Added CS_OWNDC for win32 with a GDK hack + +07/07/2000 + - Fixed "white textures" bug (gluBuild2DMipmaps bug) + +03/07/2000 +TTimo: - main.cpp l386, removed tools/ appending to g_strAppPath, g_strAppPath is expected to point to the app.. (hope it doesn't break anything) + +02/07/2000 + - Added precompiled headers for faster win32 builds + +01/07/2000 + - Finally got q3asm/lcc working + +26/06/2000 + - 201 patches + - Added screenshot option + - Added an error message if X is running in 8 bits + +23/06/2000 + - Updated with build 200 source + +13/06/2000 + - Remove --noshare option + - Added --nofonts option to workaround a bug using glXUseXFonts in XFree 4.0 + +04/06/2000 + - Fixed bug with the Ctrl-X accelerator for the File/Exit menu + +02/06/2000 + - Converting the TexTool plugin + +30/05/2000 + - Changes to the plugin loading code + +28/05/2000 + - Files with an underscore character are now correctly parsed in the MRU menu + +25/05/2000 + - Fixed _exit bugs + - Fixed bug in CMapStringToString::SetAt + - Fixed copy/paste/clone bug + +24/05/2000 + - Finished applying the 199 patches + - Fixed a bug in CShaderArray::SortShaders() that was calling the wrong version of InsertAt() + - Added numbers to the MRU menu items + +23/05/2000 + - Fixed the floating point bug in gluBuild2DMipmaps + - Fixed the time display after a bsp command is executed + - Applied several patches from the 199 version + - The console is now visible by default + +21/05/2000 + - Added a replacement for gluBuild2DMipmaps + +20/05/2000 + - Fixed the repeating textures bug when playing a map, "brush_primit" must be set to "1". + - Fixed the bug about no current GL context when exiting in computers with 3dfx cards. + - Textures in the directory pointed by "texturepath" are now loaded correctly in Radiant. + - Fixed bug in q3map where it would require a shaderlist.txt file in ~/.q3a/baseq3/scripts. + +19/05/2000 + - Fixed a bug in the multiple directories hack in libs/pakstuff.cc + - Finished the filter in the texture window + - The wait cursor is now correctly set in the XY window + - Added replacements for gluPerspective and gluLookAt + - Textures can now be stored in 2 places: + * The path pointed by "texturepath" (defaults to ~/.q3a/baseq3/textures, + but can be changed in the project settings) + * The base texture path (/baseq3/textures) + - Radiant and the q3map tool now looks for shaders in ~/.q3a/baseq3/shaderlist.txt + and /baseq3/scripts/shaderlist.txt + +18/05/2000 + - Plugin menu fixes + - Created a simple text editor to edit the shaders (instead of calling an external program) + - Copy and paste now work + - Fixed some bugs with the MRU menu + - Some menu items are now enabled/disabled correctly in MainFrame::RoutineProcessing () + - Added a new command line option (--cdpath) to set the CD-ROM path + - Fixed some bugs in the entity window, now it's possible to add/edit/remove properties + - New directory paths: + * maps now default to ~/.q3a/baseq3/maps + * autosave files are saved in ~/.q3a/baseq3/maps + * .pk3 files can be in ~/.q3a/baseq3, /baseq3 and in the CD-ROM + +17/05/2000 + - Fixed bug deselecting a brush after the surface dialog is open + - hide cursor when right-dragging XYWnd + - files saved to /tmp are now saved in ~/.q3a/radiant + - Disabled undo + - Fixed a bug in FillTextureMenu + - User can now correctly change the accelerators at run-time + - Accelerators are read from ~/.q3a/radiant/radiant.ini + +16/05/2000 + - Finished the patch inspector + - Finished the texture toolbar + - more small bug fixes + +11/05/2000 + - Finished the GroupDlg stuff + - Added support to read pak files from the Quake3 CD-ROM + - moved /tmp/paklog.txt to ~/.q3a/radiant/paklog + - added functions to replace GetKeyState and SetCursorPos + - fixed the command key handlers for the mainwindow diff --git a/docs/developer/DRAFT b/docs/developer/DRAFT new file mode 100644 index 00000000..2ba0f75d --- /dev/null +++ b/docs/developer/DRAFT @@ -0,0 +1,130 @@ +usefull global variables in Radiant: +g_strAppPath has the path to the binary + +----------------------------------------------------------------------- +using prefs / ini settings: +are stored in Radiant.ini and *.bin files +win32: +looks in the current directory for a Radiant.ini file +if found, will use it and set the ini directory to the proper location +if not found: +the registry has a path to the default directory? +under key HKEY_CURRENT_USER/Software/GtkRadiant/PrimaryEditorPath +(DefaultEditorPath cause that gets used for +if the key doesn't exist create in current directory and set the key +NOTE: need some registry version info, when we find in another dir than ours, + check version and prompt to use existing settings or our own? + +storing version information: +each build publicly released should have a version string +- use it in the about box +- store it in the Radiant.ini file +- use it in the registry GtkRadiant/ +do we need major and minor? minor could be used for versions that don't break .ini compatibility + (well I'm lazy .. won't do) + +linux: +look in the current directory (check write permission!) +if found, use it +if not found: +look in ~/.q3a/radiant + +----------------------------------------------------------------------- +icons: +look for bitmaps/ under g_strAppPath +win32: +if not found, use DefaultEditorPath registry key and try to locate there +linux: +we also need a DefaultEditorPath kind of thing? +somewhere in ~/.q3a/radiant? + +----------------------------------------------------------------------- +project file: +Radiant.ini must have full path to the project file +if no project file path: +win32: +we have to locate BASEPATH one way or the other. we have code that will look for the +main directory and go down into baseq3/scripts. If that fails we prompt the user. +it would be good to store BASEPATH in the .ini as well! +linux: +store path to Radiant installation somewhere in ~/.q3a/radiant +if not found try some defaults and prompt the user + +NOTE: on linux radiant is in /usr/local/games/quake3/ instead of some +quake3/tools directory. This makes looking for the basepath easier. + +g_PrefsDlg.m_strLastProject points to the project to be loaded +if radiant cannot find it at startup it will try to guess and/or ask the user +once the project file is loaded you can deduce a lot of things.. +but project file parsing has some prerequisites: __QERPATH / __QERHOMEPATH ?? +need to unify between win32 and linux! +PrefsDlg has a bunch of defaults, but it must not try to guess + __QERPATH and __QERHOMEPATH until there has been an ini load (or a lack of) +the involved members are: +m_strQuake2 <- points to the engine path, renamed to m_strBasePath m_strEngine +m_strPAKFile <- built from m_strBasePath, removed (not used?) +and: need to add more, like map compilers directory m_strToolsPath + +project file syntax: +linux version is using __QERPATH / __QERHOMEPATH +win32 has __Q2PATH __QERPATH +and the overall syntax is different! + +big problem is user customization, it performs expansion and saves with static +paths. but we'd like to keep the original one with generic naming. (cause if the +config fucks up and user reinstalls he'll still get broken project settings) +so: we try to load quake.qe4 project, expand it, and save as user.qe4 +(on linux, user.qe4 goes in ~/.q3a/baseq3/scripts) + +TODO: how is "New project" supposed to work? would copy the current project.. +TODO: get rid of m_bLoadLast .. we require having a project loaded for use? +TODO: store path to the tools in prefs? (see usage for project file expansion?) + -> so you can use q3map in a given dir etc? + +unifying project file syntaxes: + +get rid of BuildShortPathName things! + +----------------------------------------------------------------- +some common operations and portable code: +document XP use of stat, checking for directory / file existence + +how to have code that reads well across XP: +don't use TABS, have them emulated to 2 spaces + +----------------------------------------------------------------- +project files: +unless we rewrite a whole bunch of it from scratch there's no much +hope for evolution of the project files. Nevertheless, introduced +a new "version" key that describes the version of the project file. +version 2 adds a # keyword for q3map global options +NOTE: and it's a compatibility nightmare, we can't call this one +quake.qe4 or default.qe4 cause it will break backward compatibility + +----------------------------------------------------------------- +monitoring BSP process: +we monitor through network connections +we need to stop the process if an error occurs during one of the three steps +and launch quake3 when all is done +we don't want to CreateProcess and watch cause for rsh mode it will return immediately +a BSP process is decomposed in several steps and we expect a connection at each step +- later we can add custom steps that don't net connect and then we just spawn and +watch them +- we could add a name to the step to identify them, for now we'll just assume +the first connection that we get is the one of the process we spawned +when we loose the connection we wait one sec and spawn the next one... +- we don't use batch file, just produce the command lines for each steps, the batch file +will be produced only if we don't monitor the process (we can add an option to output +the BAT file anyway) + +what stuff goes in prefs? "Monitor BSP process" + +detecting when the socket closes? +using select() one can detect if a socket has closed or if there's some input +NOTE: when launching a new BSP process we may still be connected. Need to ask the user +about overridding and closing current connection. + +in prefs, boolean flag for process monitoring .. g_PrefsDlg.m_bWatchBSP + +when running in monitored mode, the BSP watcher is in charge of spawning and watching +the processes (and more later when it will be parsing the output). diff --git a/docs/developer/HEAP b/docs/developer/HEAP new file mode 100644 index 00000000..11c9e0fa --- /dev/null +++ b/docs/developer/HEAP @@ -0,0 +1,33 @@ +find and xargs: + I need to remember that grep trick + 'find -type f | xargs grep -n whatever' is handy.. + find -type f -name '*.[ch]' is even better at times. + +stdout / stderr redirections: +make -f makefile.cygwin 2> err.log +make -f makefile.cygwin >& full.log + +escape shell expansion: +find gtk-20001023 -name "*.zip" -exec unzip {} \; +find and -exec: +find //c/Donwload/Gtk-20001226 -name '*src*zip' -exec unzip {} \; +find //c/Donwload/Gtk-20001226 -name '*dev*zip' -exec unzip {} \; + +simple encryption for /etc/passwd entries: +perl -e 'print crypt("password","hk");' + +debian and /etc/init.d +update-rc.d + +silly hint on sed and regexp: +cat bspfile.c | sed -e 's/\([^_]\)malloc/\1safe_malloc/' | grep malloc + +*poke 10* +bleh +bleh +bleh +bleh +bleh +bleh +bleh +bleh diff --git a/docs/developer/Inspector/Inspectors.argo b/docs/developer/Inspector/Inspectors.argo new file mode 100644 index 00000000..0512d60e --- /dev/null +++ b/docs/developer/Inspector/Inspectors.argo @@ -0,0 +1,76 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/docs/developer/Inspector/Inspectors.xmi b/docs/developer/Inspector/Inspectors.xmi new file mode 100644 index 00000000..0d6c906a --- /dev/null +++ b/docs/developer/Inspector/Inspectors.xmi @@ -0,0 +1,247 @@ + + + + + + + + + Surface inspectors + + + + + + + SurfaceDlg + + + + + + + + + + + + + + Toggle + + + + + + + + + + + + + + + + + + + + + + + activeInspectors + + + + + Java + 0 + + + + + + + + + + + + + Dialog + + + + + + + + + + + + + + + + + + + + + + + + + + void + + + + + + + + + + + ISurfaceDlg + + + + + + + + + + + + + + + + CQ3BrushDlg + + + + + + + + + + + + + + + + + + + + + + + + + + CQ3PatchDlg + + + + + + + + + + + + + + + + + + + + + + + + + + COtherGameDlg + + + + + + + + + + + + + + + + + + + + + + + + + + Undo / Redo code + + + + + + + + + + Messaging API + + + + + + + + + + int + + + + + + + + + + + list + + + + + + + + + + + + + diff --git a/docs/developer/Inspector/Inspectors_classdiagram1.pgml b/docs/developer/Inspector/Inspectors_classdiagram1.pgml new file mode 100644 index 00000000..6ef4a8d0 --- /dev/null +++ b/docs/developer/Inspector/Inspectors_classdiagram1.pgml @@ -0,0 +1,571 @@ + + + + + + + + + SurfaceDlg + public int newAttr = 0 + void Toggle() + + + + + + + Dialog + + + + Toggle hide/shows SurfaceDlg +replace DoSurface and ByeByeSurfaceDialog + + + + + + ISurfaceDlg + + + + Available in the plugin API +defined in ISurfacePlugin.h + + + + + + CQ3BrushDlg + + + + + + + + + CQ3PatchDlg + + + + These two hardcoded in Radiant + + + + + + COtherGameDlg + + + + Implemented in a plugin + + + + + + Undo / Redo code + + + + + + + + Messaging API + + + Selection / Deselection messages + Store a snapshot of something for later use + List of the SurfaceDlg objects we currently need +Updated on the way when we get messages + + + sourcePortFig="Fig0" + destPortFig="Fig1" + sourceFigNode="Fig0" + destFigNode="Fig1" + + + + + + + + + sourcePortFig="Fig6" + destPortFig="Fig4" + sourceFigNode="Fig6" + destFigNode="Fig4" + + + + + + + + + sourcePortFig="Fig8" + destPortFig="Fig4" + sourceFigNode="Fig8" + destFigNode="Fig4" + + + + + + + + + sourcePortFig="Fig11.0" + destPortFig="Fig4.0" + sourceFigNode="Fig11" + destFigNode="Fig4" + + + + + + + diff --git a/docs/developer/Inspector/Inspectors_collaborationdiagram1.pgml b/docs/developer/Inspector/Inspectors_collaborationdiagram1.pgml new file mode 100644 index 00000000..95c7614e --- /dev/null +++ b/docs/developer/Inspector/Inspectors_collaborationdiagram1.pgml @@ -0,0 +1,6 @@ + + + + diff --git a/docs/developer/Inspector/Inspectors_usecasediagram1.pgml b/docs/developer/Inspector/Inspectors_usecasediagram1.pgml new file mode 100644 index 00000000..a6182ca9 --- /dev/null +++ b/docs/developer/Inspector/Inspectors_usecasediagram1.pgml @@ -0,0 +1,6 @@ + + + + diff --git a/docs/developer/Inspector/classdiagram1.gif b/docs/developer/Inspector/classdiagram1.gif new file mode 100644 index 00000000..bf468e2f Binary files /dev/null and b/docs/developer/Inspector/classdiagram1.gif differ diff --git a/docs/developer/Inspector/collaborationdiagram1.pgml b/docs/developer/Inspector/collaborationdiagram1.pgml new file mode 100644 index 00000000..95c7614e --- /dev/null +++ b/docs/developer/Inspector/collaborationdiagram1.pgml @@ -0,0 +1,6 @@ + + + + diff --git a/docs/developer/Inspector/inspector.txt b/docs/developer/Inspector/inspector.txt new file mode 100644 index 00000000..acf80040 --- /dev/null +++ b/docs/developer/Inspector/inspector.txt @@ -0,0 +1,266 @@ +OK. Again I would have liked to get a design document before it being done. Main functionalities we +need in the inspector: + +- Unifiy the inspector under a single dialog box, called with 'S' + +- Depending on what is currently selected, display several frames in the inspector: +only brushes -> surface inspector +only patches -> patch inspector +brushes & patches -> both +and later when brush primitives are mixed with regular brushes + plugin entities, raise whatever +additional inspector stuff we need + +- The camera view must update realtime when we change some parameters. + +- Get rid of the Apply button, use the Undo code to store settings when surface inspector is +raised. If user hits Cancel, call the undo stuff. + +- Use the message broadcasting stuff to keep the inspectors up to date when the user changes the +current selection. Be careful to keep the undo stuff in sync with the select / deselect operations. + +- Use a 3-state scheme to display the params in the widgets. If two faces are selected that don't +have the same shift increment, just grey out the shift box. + +Messaging: +- a good chunk of the work is moving the selection/creation stuff to the messaging API + we no longer use UpdateSurfaceDialog, we post messages instead .. + the surface inspector has hooked one of it's listeners into the corresponding message + we may need to reorganize the messages, maybe introduce a hierarchy? + or pass a void * param with messages? + +- we don't post messages like "update surface inspector", we post messages that say "this and that +have changed", then the surface inspector reacts if it needs to. +Do we need marshalling in the messages? Very likely .. maybe using Gtk signal stuff would be interesting? + +-> the messaging stuff is a big chunk of work and our surface inspector changes are not totally +dependent on it. Better leave that for l8r + +the inspector works by states and transitions? Or we post messages to it? +Use case: +the user raises the inspector .. if we are up we'll ignore, if we are hidden we'll +go through the whole process (initialise, look at what is selected, display) +then we enter an active state (listening for select / deselects and applying stuff) + +all in all it seems to be too big a change for next release. will see later probably. +Trying a few more days with it, see what happens. after all the interface is fairly restricted +so there's a good chance our changes are fairly stable in the end. But rebuilding the whole interface +part might be too much ... +We need something state based? AND a set of messages .. +but first, need to write the initialisation loop +build the dialog, get the current surface information and display + +Undoing the changes on the selected stuff: +at any point in time, one can get a snapshot of selected stuff and use it to store the surface +properties settings for later on. But what happens if the user modifies the selected brush, pushing +it in the undo stack? Then we would cancel the changes? (and just backup to the state right after +the modif) +We could has the 'Apply' button used for that .. grey it out when the current state is the one in +the backup. This happens whenever we hit 'Apply' or change something in the selection. +The selection has several items: entities, brushes and selected faces (possibly later generic plugin entities) +Current undo stuff is aimed at entities and brushes. +NOTE: you can't have selected faces and brushes/entities at the same time, that's a good point to +keep that seperated to deal with undo and storage +On what side should the implemetation be ? undo.cpp select.cpp or surfacedialog.cpp ? +We are going to do it with the messaging API anyway.. +And hook in the undo stuff, to reset the snapshot each time something gets pushed in the undo? + +We have advanced stuff on the Inspector branch, doing basics on Alpha branch. +Start writing the watch code in surfacedialog.cpp, see if we need some merging with Undo stuff l8r +We need to track for the patch inspector as well.. + +basic code for CSurfaceUndo written. need to add hooks for the snapshot stuff and undo stuff. and a +debug flag to monitor the life cycle of the object. + +some use cases: +- select a brush +- bring up surface inspector +- check we had the debug messages from CSurfaceUndo (initialise, activate, snapshot) +- edit the surface settings +- check the views are updating correctly +- hit Ok +- check we had a deactivate message +OK + +- select a brush +- bring up surface inspector +- check we had the debug messages from CSurfaceUndo (initialise, activate, snapshot) +- edit the surface settings +- check the views are updating correctly +- hit cancel / escape +- check we have a undo and deactivate from CSurfaceUndo +OK + +- select a brush +- bring up the surface inspector +- edit the surface settings +- hit apply +- edit them again +- hit cancel / escape +- check you get back to the apply state +OK + +- make two brushes +- select a brush +- bring up surface inspector +- change settings +- select an additional brush +- check the surface inspector, new snapshot +- hit cancel +- check brushes remained in the same state +- use standard Undo +- check the first brush got back to it's initial settings +OK + +- select a brush +- bring up surface inspector +- change settings +- select an additional brush +- check the surface inspector, new snapshot +- change more settings +- hit cancel +- check the first brush returned to intermediate state, and second to initial state (i.e. last snapshot) +OK + +g_surfaceUndo acts as a layer on top of the core Undo code when the surface inspector is activated. +We need it because the surface inspector can edit faces which are not handled by the undo? +(or does the current code push the whole brush when editing a face?) + +not sure of the utility of the g_surfaceDialog hooks here .. +default undo usage in the sruface inspector sends way too many undo messages. +with the new scheme we store in undo only when select/deselect or user hits apply +that way the 'Cancel' and later Ctrl+Z calls make sense +but is it worth implementing a new class to achieve that?? .. yes because we intend a later cleanup +of this part. (ahem is this reason good enough..) +this part is actually much closer from the undo code than I had expected.. +'Cancel' call being an Undo call.. + +going to Inspector3: +don't create a new class, simply use the Undo more intelligently? +i.e. don't create undo stuff when editing the brush +-> we add a flag to turn off the default undo behaviour and force Undo storage when we want +we could also store the undo Id we are interested in and call undo several times to get it back + +NOTE: what happens if the user hits undo when the surface inspector is up? +-> we'll have to take his request into account? +err .. performing which undo? The texture positioning or something else? +seems the snapshot approach would still make sense then? + +more use cases, see with Undo calls and select/deselect events +NOTE: this whole thing is probably a single call to select_settexture that needs to be turned on/off +instead of working at the undo level. but we would like to move to messaging so maybe it still makes sense +the undo call is in Select_SetTexture (which does not have that many callers, I was expecting more) + +the question about having the undo code keep working when surface inspector is around is still raised. +but it makes it a lot harder, gotta have a real inspector mode in the undo? +dunno, think about it again later + +two operations are mixed in a single one and should not be: +reading the map to get the current data we'll manipulate +feed it in the dialog box widgets +WARNING: when putting stuff in the widgets, it raises a shitload of update messages and therefor completely +fucks up our OnOK OnApply OnCancel scheme (specially OnApply!) + +NOTE: we want to switch between Surface inspector for brushes only and Patch inspector for patches only +there's some crappy code in the surface inspector that we need to get rid of +but need to check about that before with Spog or others + +Forcing the way into using the surface inspector is SCREWED? +Doesn't seem to work the way we want to. Always get parasite Undo messages and stuff. +We could use a seperate stack for Undo with the surface inspector? +Just store the surface properties in a seperate stack? +When user hits cancel you go back and apply whatever you had? +Doesn't seem like a clean way either. + +Now dealing with both regular surface inspector and patch inspector: +we have some stuff that needs to be on/off with the two inspectors +what about catching the messages and issuing new snapshots? +the main surface inspector is doing it? +no! +so what, we have several states? +FUCKED UP + +INSPECTOR 5 ---------------------------------------------------------------- +restarted from scratch, made much more simple changes. +trying another trick for undo (!) +just let the undo work as usual, but call undo ourselves in SetTexMods if we have create the last do +requires proper initialization/deinitialisation.. in SetTexMods and GetTexMods.. + +getting rid of patch manipulation code in the regular surface inspector. The buttons will +still work, but manip will require the patch inspector. (seems the patch inspector doesn't have that +much success anyway) + +TODO: +OK get rid of patch stuff +OK get rid of the texture toolbar? (it's broken right now) + (and doesn't have anything usefull..) +OK (Partial) OnCancel? we need to cancel the texdef as well + store an undo texdef each time we grab new texdef stuff + this works in reverse than the Undo code? When we do the initial + problem is, in some cases the settings that show up are not in sync with what's in the inspector?? + (we can't avoid that because if a brush is selected there's no single setting) + prolly get it out as is and let Spog or others send feedback about what it's supposed to do.. + for now: store stuff in the cancel texdef when we initialize an undo loop + revert to that if OnCancel is used +OK message when spinning over a patch? +DUPLICATE (.. see below ..) check the increments we store in the SI are used when shift + arrows etc. + no it doesn't work .. the shifting on keyboard shortcuts is done with m_nTextureTweak + seems m_nTextureTweak is nowhere available in the prefs (and it's not in MFC builds either) + some cleanup to be done around that it seems +OK (.. merged with below, maybe some special cases left ..) texture widget (catch the Enter key to force-call an OnApply) +OK (.. see above ..) catch Enter key at dialog level to call OnDone +NO (.. it's clean, but thats too many lines of code ..) move the code that blokes updates to use gtk_signal_handler_block_by_func and gtk_signal_handler_block_by_func +OK shift + arrow must match the SI settings, +OK (FIXME .. not using the right scale (using the scale step instead! + add a button in SI to 'Match grid') +POSTPONED (.. m_nTextureTweak is used in the nudge commands .. + .. and nudge shortcuts are broken right now ..) get rid of m_nTextureTweak ++ SI and PI always on top! + ++ known issues: "Match Grid" is broken in BP mode + +now on the patch inspector (nightmare!): +OK (.. put it as readonly .. don't bother ..) texture name widget is screwed? +OK the spinners scheme doesn't work, the stuff in the dialog is the inc step and we just need arrows +OK get rid of the 'Type' dialog box +POSTPONED (.. can't do undo on PI without proper Undo module ..) add proper Done Apply Cancel with Undo +NO (.. too much work for something that sucks ..) make the changes reflect in the views when manipulating the entries +OK (.. using %g ..) cut down on the number of digits! +OK increment steps to be stored in the registry + +putting the Cancel stuff in the surface inspector: only based on the Undo code, no cancel settings to store +because we don't have actual storage of a current texdef (we only send alterations) BTW we should do that for +brushes as well +the patch inspector works by increments, Patch_SetTextureInfo to incrementally modify the patch. +we can still do some undo by having a texdef storing the changes and working together with the undo +if the undo is recognized, it means our current texdef increment is valid +no, we can't represent the combination of several increments scale and rotate in a single texdef.. +get rid of the undo code for now .. only Apply and Done left + +it seems it's still vastly broken when you select something. or is it on linux only? +need a LOT of testing and figuring it out!! +selecting a brush breaks totally.. (the texture screws up it seems) +does it attempt to change the texture of the selected object?? +also: it seems you can multiple select a same brush?? + +the UNDO code of the SURFACE INSPECTOR IS STILL BROKEN ???? +(ok I'm really screwed, time to sleep) +-> can't reproduce now?? maybe it's linux specific problem, I can't tell + +FOUND A WAY TO REPRODUCE THE CRASH: ++ select brush ++ hit "Fit" ++ hit the shift spinners two times +OR: ++ select single face on brush ++ manually edit scale values +-> maybe we have a problem with current texture? (NO) +it's some kind of infinite loop? we call UpdateSurfaceInspector from Select_Brush and bang! +no, it's a texdef from a face that got deleted +prolly that hooking the undo code in there screws up the selected faces stuff +if you undo a selected face operation, you end up with the whole brush selected. +but that does not necessarily explain why you remove the face at Undo_Start +ho well .. removed the undo buffering when selected faces and everything's better +would need to re-establish the right face selection after undo, might solve the problem +(actually you'd still need to have the settings point to the right object) + +From PJ about the 'Match Grid' stuff: textures are moved in pixels, not units. +We must rely on the current texture scale AND gridsize to compute the shift increment diff --git a/docs/developer/RegExp/Go b/docs/developer/RegExp/Go new file mode 100644 index 00000000..9c6a3ce7 --- /dev/null +++ b/docs/developer/RegExp/Go @@ -0,0 +1,92 @@ +./replace.pl bsp.c 255 +./replace.pl facebsp.c 240 +./replace.pl facebsp.c 251 +./replace.pl facebsp.c 260 +./replace.pl fog.c 83 +./replace.pl fog.c 439 +./replace.pl fog.c 529 +./replace.pl fog.c 530 +./replace.pl fog.c 531 +./replace.pl fog.c 532 +./replace.pl leakfile.c 34 +./replace.pl leakfile.c 75 +light.c:212: qprintf ("--- CountLightmaps ---\n"); +light.c:228: qprintf( "%5i drawSurfaces\n", numDrawSurfaces ); +light.c:229: qprintf( "%5i lightmaps\n", count ); +light.c:252: qprintf ("--- CreateSurfaceLights ---\n"); +light.c:1730: qprintf( "%5i gridPoints\n", numGridPoints ); +light.c:1786: qprintf ("--- CreateLights ---\n"); +light.c:1788: qprintf ("%i point lights\n", numPointLights); +light.c:1789: qprintf ("%i area lights\n", numAreaLights); +light.c:1792: qprintf ("--- TraceGrid ---\n"); +light.c:1794: qprintf( "%i x %i x %i = %i grid\n", gridBounds[0], gridBounds[1], +light.c:1798: qprintf ("--- TraceLtm ---\n"); +light.c:1800: qprintf( "%5i visible samples\n", c_visible ); +light.c:1801: qprintf( "%5i occluded samples\n", c_occluded ); +lightmaps.c:312: qprintf ("--- AllocateLightmaps ---\n"); +lightmaps.c:347: qprintf( "%5i unique shaders\n", numSortShaders ); +lightmaps.c:369: qprintf( "%7i exact lightmap texels\n", c_exactLightmap ); +lightmaps.c:370: qprintf( "%7i block lightmap texels\n", numLightmaps * LIGHTMAP_WIDTH*LIGHTMAP_HEIGHT ); +lightv.c:4769: qprintf("light in solid at %1.1f %1.1f %1.1f\n", light->origin[0], light->origin[1], light->origin[2]); +lightv.c:4771: qprintf("spot light in solid at %1.1f %1.1f %1.1f\n", light->origin[0], light->origin[1], light->origin[2]); +map.c:294: qprintf ("Entity %i, Brush %i: mixed face contents\n" +map.c:1138: qprintf ("--- LoadMapFile ---\n"); +map.c:1163: qprintf ("%5i total world brushes\n", CountBrushList( entities[0].brushes ) ); +map.c:1164: qprintf ("%5i detail brushes\n", c_detail ); +map.c:1165: qprintf ("%5i patches\n", numMapPatches); +map.c:1166: qprintf ("%5i boxbevels\n", c_boxbevels); +map.c:1167: qprintf ("%5i edgebevels\n", c_edgebevels); +map.c:1168: qprintf ("%5i entities\n", num_entities); +map.c:1169: qprintf ("%5i planes\n", nummapplanes); +map.c:1170: qprintf ("%5i areaportals\n", c_areaportals); +map.c:1171: qprintf ("size: %5.0f,%5.0f,%5.0f to %5.0f,%5.0f,%5.0f\n", map_mins[0],map_mins[1],map_mins[2], +misc_model.c:411: qprintf("----- AddTriangleModels -----\n"); +misc_model.c:446: qprintf( "%5i triangle models\n", c_triangleModels ); +misc_model.c:447: qprintf( "%5i triangle surfaces\n", c_triangleSurfaces ); +misc_model.c:448: qprintf( "%5i triangle vertexes\n", c_triangleVertexes ); +misc_model.c:449: qprintf( "%5i triangle indexes\n", c_triangleIndexes ); +patch.c:176: qprintf( "----- PatchMapDrawSurfs -----\n" ); +patch.c:262: qprintf( "%5i patches\n", patchCount ); +patch.c:263: qprintf( "%5i patch LOD groups\n", groupCount ); +portals.c:500: qprintf( "----- MakeTreePortals -----\n"); +portals.c:503: qprintf("%6d tiny portals\n", c_tinyportals); +portals.c:589: qprintf ("--- FloodEntities ---\n"); +portals.c:608: qprintf("%5i flooded leafs\n", c_floodedleafs ); +portals.c:612: qprintf ("no entities in open -- no filling\n"); +portals.c:616: qprintf ("entity reached from outside -- no filling\n"); +portals.c:762: qprintf ("--- FloodAreas ---\n"); +portals.c:768: qprintf ("%5i areas\n", c_areas); +portals.c:813: qprintf ("--- FillOutside ---\n"); +portals.c:815: qprintf ("%5i solid leafs\n", c_solid); +portals.c:816: qprintf ("%5i leafs filled\n", c_outside); +portals.c:817: qprintf ("%5i inside leafs\n", c_inside); +prtfile.c:213: qprintf ("--- NumberClusters ---\n"); +prtfile.c:218: qprintf ("%5i visclusters\n", num_visclusters); +prtfile.c:219: qprintf ("%5i visportals\n", num_visportals); +prtfile.c:220: qprintf ("%5i solidfaces\n", num_solidfaces); +prtfile.c:232: qprintf ("--- WritePortalFile ---\n"); +shaders.c:301:// qprintf( "shaderFile: %s\n", filename ); +shaders.c:600: qprintf( "%5i shaderInfo\n", numShaderInfo); +surface.c:176: qprintf( "----- MergeSides -----\n"); +surface.c:182: qprintf( "%5i siderefs\n", numSideRefs ); +surface.c:266: qprintf( "----- SubdivideDrawSurfs -----\n"); +surface.c:365: qprintf( "----- ClipSidesIntoTree -----\n"); +surface.c:1013: qprintf( "----- FilterDrawsurfsIntoTree -----\n"); +surface.c:1045: qprintf( "%5i emited drawsurfs\n", c_surfs ); +surface.c:1046: qprintf( "%5i references\n", c_refs ); +surface.c:1047: qprintf( "%5i stripfaces\n", c_stripSurfaces ); +surface.c:1048: qprintf( "%5i fanfaces\n", c_fanSurfaces ); +tjunction.c:476: qprintf("----- FixTJunctions -----\n"); +tjunction.c:508: qprintf( "%6i axial edge lines\n", axialEdgeLines ); +tjunction.c:509: qprintf( "%6i non-axial edge lines\n", numEdgeLines - axialEdgeLines ); +tjunction.c:510: qprintf( "%6i degenerate edges\n", c_degenerateEdges ); +tjunction.c:525: qprintf( "%6i verts added for tjunctions\n", c_addedVerts ); +tjunction.c:526: qprintf( "%6i total verts\n", c_totalVerts ); +tjunction.c:527: qprintf( "%6i naturally ordered\n", c_natural ); +tjunction.c:528: qprintf( "%6i rotated orders\n", c_rotate ); +tjunction.c:529: qprintf( "%6i can't order\n", c_cant ); +vis.c:223: qprintf ("cluster %4i : %4i visible\n", leafnum, numvis); +visflow.c:642: qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n", +visflow.c:774: qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n", +visflow.c:1037: qprintf ("portal:%4i mightsee:%4i cansee:%4i (%i chains)\n", +writebsp.c:388: qprintf ("--- EndModel ---\n"); diff --git a/docs/developer/RegExp/Go.cleaned b/docs/developer/RegExp/Go.cleaned new file mode 100644 index 00000000..be03c468 --- /dev/null +++ b/docs/developer/RegExp/Go.cleaned @@ -0,0 +1,92 @@ +./replace.pl bsp.c 255 +./replace.pl facebsp.c 240 +./replace.pl facebsp.c 251 +./replace.pl facebsp.c 260 +./replace.pl fog.c 83 +./replace.pl fog.c 439 +./replace.pl fog.c 529 +./replace.pl fog.c 530 +./replace.pl fog.c 531 +./replace.pl fog.c 532 +./replace.pl leakfile.c 34 +./replace.pl leakfile.c 75 +./replace.pl light.c 212 +./replace.pl light.c 228 +./replace.pl light.c 229 +./replace.pl light.c 252 +./replace.pl light.c 1730 +./replace.pl light.c 1786 +./replace.pl light.c 1788 +./replace.pl light.c 1789 +./replace.pl light.c 1792 +./replace.pl light.c 1794 +./replace.pl light.c 1798 +./replace.pl light.c 1800 +./replace.pl light.c 1801 +./replace.pl lightmaps.c 312 +./replace.pl lightmaps.c 347 +./replace.pl lightmaps.c 369 +./replace.pl lightmaps.c 370 +./replace.pl lightv.c 4769 +./replace.pl lightv.c 4771 +./replace.pl map.c 294 +./replace.pl map.c 1138 +./replace.pl map.c 1163 +./replace.pl map.c 1164 +./replace.pl map.c 1165 +./replace.pl map.c 1166 +./replace.pl map.c 1167 +./replace.pl map.c 1168 +./replace.pl map.c 1169 +./replace.pl map.c 1170 +./replace.pl map.c 1171 +./replace.pl misc_model.c 411 +./replace.pl misc_model.c 446 +./replace.pl misc_model.c 447 +./replace.pl misc_model.c 448 +./replace.pl misc_model.c 449 +./replace.pl patch.c 176 +./replace.pl patch.c 262 +./replace.pl patch.c 263 +./replace.pl portals.c 500 +./replace.pl portals.c 503 +./replace.pl portals.c 589 +./replace.pl portals.c 608 +./replace.pl portals.c 612 +./replace.pl portals.c 616 +./replace.pl portals.c 762 +./replace.pl portals.c 768 +./replace.pl portals.c 813 +./replace.pl portals.c 815 +./replace.pl portals.c 816 +./replace.pl portals.c 817 +./replace.pl prtfile.c 213 +./replace.pl prtfile.c 218 +./replace.pl prtfile.c 219 +./replace.pl prtfile.c 220 +./replace.pl prtfile.c 232 +./replace.pl shaders.c 301 +./replace.pl shaders.c 600 +./replace.pl surface.c 176 +./replace.pl surface.c 182 +./replace.pl surface.c 266 +./replace.pl surface.c 365 +./replace.pl surface.c 1013 +./replace.pl surface.c 1045 +./replace.pl surface.c 1046 +./replace.pl surface.c 1047 +./replace.pl surface.c 1048 +./replace.pl tjunction.c 476 +./replace.pl tjunction.c 508 +./replace.pl tjunction.c 509 +./replace.pl tjunction.c 510 +./replace.pl tjunction.c 525 +./replace.pl tjunction.c 526 +./replace.pl tjunction.c 527 +./replace.pl tjunction.c 528 +./replace.pl tjunction.c 529 +./replace.pl vis.c 223 +./replace.pl visflow.c 642 +./replace.pl visflow.c 774 +./replace.pl visflow.c 1037 +./replace.pl writebsp.c 388 diff --git a/docs/developer/RegExp/pattern b/docs/developer/RegExp/pattern new file mode 100644 index 00000000..843bb113 --- /dev/null +++ b/docs/developer/RegExp/pattern @@ -0,0 +1,4 @@ +#s/.*:/.\/replace.pl &/ +#s/\(.*\):\([0-9]*\):\(.*\):/.\/replace.pl \1 \2/ +#s/\(.*\):\([0-9]*\):/.\/replace.pl \1 \2 / +s/\(.*\):\([0-9]*\):\(.*\)/.\/replace.pl \1 \2 / \ No newline at end of file diff --git a/docs/developer/RegExp/replace.pl b/docs/developer/RegExp/replace.pl new file mode 100644 index 00000000..86bbb389 --- /dev/null +++ b/docs/developer/RegExp/replace.pl @@ -0,0 +1,17 @@ +#!perl +rename("$ARGV[0]", "$ARGV[0].old"); +open(FILE, "$ARGV[0].old"); +open(OFILE, ">$ARGV[0]"); +while() +{ +if($. != $ARGV[1]) +{ +print OFILE; +next; +} +s/Sys_Printf \(/Sys_FPrintf \(SYS_VRB,/; +s/Sys_Printf\(/Sys_FPrintf \(SYS_VRB,/; +print OFILE; +} +close(OFILE); +close(FILE); \ No newline at end of file diff --git a/docs/developer/RegExp/tstscrpt.pl b/docs/developer/RegExp/tstscrpt.pl new file mode 100644 index 00000000..84e646d3 --- /dev/null +++ b/docs/developer/RegExp/tstscrpt.pl @@ -0,0 +1,17 @@ +#!perl +rename("brush.c", "brush.c.old"); +open(FILE, "brush.c.old"); +open(OFILE, ">brush.c"); +while() +{ +if($. != 150) +{ +print OFILE; +next; +} +s/Sys_Printf \(/Sys_FPrintf \(SYS_VRB,/; +s/Sys_Printf\(/Sys_FPrintf \(SYS_VRB,/; +print OFILE; +} +close(OFILE); +close(FILE); \ No newline at end of file diff --git a/docs/developer/TESTERS b/docs/developer/TESTERS new file mode 100644 index 00000000..6b3e5c1c --- /dev/null +++ b/docs/developer/TESTERS @@ -0,0 +1,19 @@ +a few basic contacts for people willing to test GtkRadiant: + ++ everyone on the RadiantBinaries mailing list + ++ ----------------------- + |UL|FeNiX: (5:20 PM) when will you be letting loose a new beta for this "completely" new radiant? + |UL|FeNiX: (5:20 PM) I would love the honor to help you alpha and or beta test anything....... + |UL|FeNiX: (5:20 PM) you could consider me your win2K tester...... +Tim: (5:21 PM) well .. within a few days I hope .. it will need lots of testing +but I want something that is basically usable before we can go forward +yeah, w2k testing is much needed +what's your email? + + |UL|FeNiX: (5:21 PM) kingfenix1@home.com +Tim: (5:21 PM) k + ++ GL slowdowns tests -------------------------------------------- +mac (from Q3W forum) +gangstapoodle@hotmail.com diff --git a/docs/developer/TODO b/docs/developer/TODO new file mode 100644 index 00000000..fbfbb5f1 --- /dev/null +++ b/docs/developer/TODO @@ -0,0 +1,123 @@ +Things that need to be done in Q3Radiant Linux: + +- copy and paste to other instances + +Bugs: + +- The surface inspector is not updated if you close it, + select another brush and open it again. (Win32 too) + +Win32 version BUGS/TODO list: + +- write an XP version of _stat / FileExists in cmdlib +- put the sleep thing in a proper place, bind it in the keyboard shortcuts +- console output bugs: properly format the output, fix "console not scrolling but keeps + overwriting lines" + we no longer need to convert to CR/LF to output in the console. removed that. + interesting piece about the text widget here: + http://www.gtk.org/tutorial/gtk_tut-14.html + added freeze and thaw calls in Sys_BeginWait Sys_EndWait + need to call Sys_BeginWait Sys_EndWait in all appropriate places (Map_LoadFile) + need to limit size of the console, and scroll down on output + wrote a test program that reproduces the bug with scrolling +- write a coding directions document (what and where to put stuff) + qe3.h, globals, map data storage structures + see DevDocs/draft, need to do something along those lines +- remember maximized state (not only the size) + and various window position settings +- get rid of the SGIOpenGL flag, (make it default?) + actually, remove all the prefs crap that's not relevant +- widgets too big? + at least the menus, or the dialog boxes as well? +- get rid of Texture_LoadTGATexture (or rename it) + (do l8r) +- sleep mode +- proper about box +- have basic default position and size for the windows in the four views +- plugin API +- have plugin links accessed from plugins menu +- make sure the registry cleaning works +- version information! +- custom shortcut keys file! + shortcut.ini ? +- problem with strPrefab + +- fix user.qe4 thing, don't overwrite. And tell the user about it. Actually allow him to + select another location / name for the project file. + +- command map: changing the file to command.ini? put it in the same dir as radiant.ini + (get rid of user path + +- logging console: add the checkbox +- add the radiant.pid detection!! (this is from 200 -> 201) +- remember window position on the desktop and maximized state +- fix browsing for a directory, the win32 dialog to browse for a dir is fucked +- check creating a new project on linux, I rewrote it and tested on win +- cleanup the q3map code, remove the dirty __TTIMOBUILD stuff + +- changes to the jpeg library for the MFC version, must make their way to Gtk + (proper error handling) + +- saving window pos in MainFrame::OnDestroy crashes in 4-view mode (Sagnor) +- 4-view: [00:31] oh and the "o" for the console doens't work + +FIXED: -------- +- Printing: Saving screenshot instead +- icon in KDE has "name=quake3": Fixed in the latest setup (thanks Stephane) +- add precompiled headers to speedup building + done. basically added stdafx.h, the VC5 project needs to be updated + stdafx.cpp: generate precompiled header with stdafx.h + all other files: automatic use of precompiled headers... + (maybe later add more headers to stdafx) +- context switch problems + seem to have disappeared since I fixed a bug in Str + no it's definitely back! + fix by Leo, hacked into gdk.dll for CS_OWNDC window class style +- use proper texture when not found instead of white + Leo fixed, bug in the custom gluBuild2DMipmaps +- use registry + for window positions <- Leo did + have proper default positions! +- bitmap loading broken (can't get anything to load up) + ok Leo fixed +- renaming some files .. linux_dlgs.cpp to dlgs.cpp etc. let's be neutral! + done that .. removed linux_*, renamed qgl_linux.c to qgl.c + (Makefile and VC5 project need updating) +- prefs stuff? big open/close loop on radiant.ini? + fixed radiant.ini growing huge on win32 (doesn't seem to affect the linux version) + will have to check with a profiler if that's so bad +- fixed m_strQuake2 (change name and have proper defaults) + it's the path to the engine we've all been waiting for! +- fixed the new project step +- fixed paklog crashes if /tmp/paklog.txt and the dir tmp doesn't exist on win32 + (ask windows for the temp directory? .. I would put in radiant current dir .. on win32) + also check on a machine that doesn't define a HOME env var! +- can't reproduce: crash in gluBuild2DMipmaps? seems very random. was not able to reproduce + it for sure. First time happened on base_trim/pewter. + happens on image[k++] = *ubptr++; (l1038) +- merge 201 in, use the console logging stuff to debug project settings things + +DISCUSSION LOG ABOUT GL SPEED: +[19:17] Then why not use your own main, calling g_main_iteration at even intervals? :) +[19:17] shuoldn't be too hard. I hve plenty of code like that +[19:18] *** Joins: Centove (gregm@coco.comstar.net) +[19:18] while(1) { while(g_main_iteration(0)) /* do nothing, process until done */; [do own stuff]; pause(); } or so +[19:18] I see .. well actually my main problem is that the GL view is dead slow +[19:19] at first we though it was because of all the stuff between windows and the handlers +[19:19] but the problem seems somwhere else +[19:20] can you profile the code? +[19:21] we'll try .. but actually I don't know for sure where the perfomance hit happens +[19:21] might be because it doesn't process the mouse messages quickly enough, or because the refresh messages are sent once every g_main_interaction +[19:22] but compared to the MFC version, it feels sluggish +[19:22] yoda: fwiw, it looks like Lance mispaired two sets of speakers when he packed up the Utah offices. If you have no complaints, I'll put my mismatched pair back and take a known pair, which should leave you even. 'k? +[19:22] I believe that g_main can block +[19:23] block? what do you mean? +[19:23] g_main_iteration(1) blocks if there are no events to process +[19:23] might not be at all what's wrong here though. :) +[19:23] you mean it sleeps until more events happen? +[19:23] yeahj +[19:24] well that would not be a problem .. the problem is I'd like to emit paint messages faster when the user interacts with the GL window +[19:24] I don't know g_main works, but I would assume it uses g_main_iteration(1) +[19:24] ok, well thanks for the insight .. we'll keep looking anyway +[19:24] hmm. Your own main look might do the trick, possibly. Dunno. :) + diff --git a/docs/developer/TstMaps/Desktop_pb_leaf.map b/docs/developer/TstMaps/Desktop_pb_leaf.map new file mode 100644 index 00000000..da1a4a4b --- /dev/null +++ b/docs/developer/TstMaps/Desktop_pb_leaf.map @@ -0,0 +1,9221 @@ +{ +"classname" "worldspawn" +"music" "sounds/world/desktop/intro.wav sounds/world/desktop/loop.wav" +// brush 0 +{ +( 1391 438 1580 ) ( 1263 438 1580 ) ( 1263 426 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 469 1595 ) ( 1259 481 1595 ) ( 1387 481 1595 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 364 1593 ) ( 1387 364 1593 ) ( 1387 364 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1423 380 1593 ) ( 1423 392 1593 ) ( 1423 392 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1355 527 1595 ) ( 1227 527 1595 ) ( 1227 527 1582 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 376 1593 ) ( 1259 364 1593 ) ( 1259 364 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 1 +{ +( 1391 977 1579 ) ( 1263 977 1579 ) ( 1263 965 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 1008 1594 ) ( 1259 1020 1594 ) ( 1387 1020 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 903 1592 ) ( 1387 903 1592 ) ( 1387 903 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1423 919 1592 ) ( 1423 931 1592 ) ( 1423 931 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1355 1066 1594 ) ( 1227 1066 1594 ) ( 1227 1066 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 915 1592 ) ( 1259 903 1592 ) ( 1259 903 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 2 +{ +( 1919 793 1579 ) ( 1791 793 1579 ) ( 1791 781 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1787 824 1594 ) ( 1787 836 1594 ) ( 1915 836 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1787 719 1592 ) ( 1915 719 1592 ) ( 1915 719 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1951 735 1592 ) ( 1951 747 1592 ) ( 1951 747 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1883 882 1594 ) ( 1755 882 1594 ) ( 1755 882 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1787 731 1592 ) ( 1787 719 1592 ) ( 1787 719 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 3 +{ +( 1919 -807 1579 ) ( 1791 -807 1579 ) ( 1791 -819 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1787 -776 1594 ) ( 1787 -764 1594 ) ( 1915 -764 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1787 -881 1592 ) ( 1915 -881 1592 ) ( 1915 -881 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1951 -865 1592 ) ( 1951 -853 1592 ) ( 1951 -853 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1883 -718 1594 ) ( 1755 -718 1594 ) ( 1755 -718 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1787 -869 1592 ) ( 1787 -881 1592 ) ( 1787 -881 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 4 +{ +( 855 -983 1579 ) ( 727 -983 1579 ) ( 727 -995 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 723 -952 1594 ) ( 723 -940 1594 ) ( 851 -940 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 723 -1057 1592 ) ( 851 -1057 1592 ) ( 851 -1057 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 887 -1041 1592 ) ( 887 -1029 1592 ) ( 887 -1029 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 819 -894 1594 ) ( 691 -894 1594 ) ( 691 -894 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 723 -1045 1592 ) ( 723 -1057 1592 ) ( 723 -1057 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 5 +{ +( 1391 -623 1579 ) ( 1263 -623 1579 ) ( 1263 -635 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 -592 1594 ) ( 1259 -580 1594 ) ( 1387 -580 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 -697 1592 ) ( 1387 -697 1592 ) ( 1387 -697 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1423 -681 1592 ) ( 1423 -669 1592 ) ( 1423 -669 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1355 -534 1594 ) ( 1227 -534 1594 ) ( 1227 -534 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 -685 1592 ) ( 1259 -697 1592 ) ( 1259 -697 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 6 +{ +( 1391 -1162 1580 ) ( 1263 -1162 1580 ) ( 1263 -1174 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 -1131 1595 ) ( 1259 -1119 1595 ) ( 1387 -1119 1595 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 -1236 1593 ) ( 1387 -1236 1593 ) ( 1387 -1236 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1423 -1220 1593 ) ( 1423 -1208 1593 ) ( 1423 -1208 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1355 -1073 1595 ) ( 1227 -1073 1595 ) ( 1227 -1073 1582 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1259 -1224 1593 ) ( 1259 -1236 1593 ) ( 1259 -1236 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 7 +{ +( 311 -642 1580 ) ( 183 -642 1580 ) ( 183 -654 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 -611 1595 ) ( 179 -599 1595 ) ( 307 -599 1595 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 -716 1593 ) ( 307 -716 1593 ) ( 307 -716 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 343 -700 1593 ) ( 343 -688 1593 ) ( 343 -688 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 275 -553 1595 ) ( 147 -553 1595 ) ( 147 -553 1582 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 -704 1593 ) ( 179 -716 1593 ) ( 179 -716 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 8 +{ +( 311 -103 1579 ) ( 183 -103 1579 ) ( 183 -115 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 -72 1594 ) ( 179 -60 1594 ) ( 307 -60 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 -177 1592 ) ( 307 -177 1592 ) ( 307 -177 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 343 -161 1592 ) ( 343 -149 1592 ) ( 343 -149 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 275 -14 1594 ) ( 147 -14 1594 ) ( 147 -14 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 -165 1592 ) ( 179 -177 1592 ) ( 179 -177 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 9 +{ +( -225 -463 1579 ) ( -353 -463 1579 ) ( -353 -475 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -357 -432 1594 ) ( -357 -420 1594 ) ( -229 -420 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -357 -537 1592 ) ( -229 -537 1592 ) ( -229 -537 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -193 -521 1592 ) ( -193 -509 1592 ) ( -193 -509 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -261 -374 1594 ) ( -389 -374 1594 ) ( -389 -374 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -357 -525 1592 ) ( -357 -537 1592 ) ( -357 -537 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 10 +{ +( 839 -287 1579 ) ( 711 -287 1579 ) ( 711 -299 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 707 -256 1594 ) ( 707 -244 1594 ) ( 835 -244 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 707 -361 1592 ) ( 835 -361 1592 ) ( 835 -361 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 871 -345 1592 ) ( 871 -333 1592 ) ( 871 -333 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 803 -198 1594 ) ( 675 -198 1594 ) ( 675 -198 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 707 -349 1592 ) ( 707 -361 1592 ) ( 707 -361 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 11 +{ +( -585 -103 1579 ) ( -713 -103 1579 ) ( -713 -115 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -717 -72 1594 ) ( -717 -60 1594 ) ( -589 -60 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -717 -177 1592 ) ( -589 -177 1592 ) ( -589 -177 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -553 -161 1592 ) ( -553 -149 1592 ) ( -553 -149 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -621 -14 1594 ) ( -749 -14 1594 ) ( -749 -14 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -717 -165 1592 ) ( -717 -177 1592 ) ( -717 -177 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 12 +{ +( -1649 -279 1579 ) ( -1777 -279 1579 ) ( -1777 -291 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1781 -248 1594 ) ( -1781 -236 1594 ) ( -1653 -236 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1781 -353 1592 ) ( -1653 -353 1592 ) ( -1653 -353 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1617 -337 1592 ) ( -1617 -325 1592 ) ( -1617 -325 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1685 -190 1594 ) ( -1813 -190 1594 ) ( -1813 -190 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1781 -341 1592 ) ( -1781 -353 1592 ) ( -1781 -353 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 13 +{ +( -1113 81 1579 ) ( -1241 81 1579 ) ( -1241 69 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 112 1594 ) ( -1245 124 1594 ) ( -1117 124 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 7 1592 ) ( -1117 7 1592 ) ( -1117 7 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1081 23 1592 ) ( -1081 35 1592 ) ( -1081 35 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1149 170 1594 ) ( -1277 170 1594 ) ( -1277 170 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 19 1592 ) ( -1245 7 1592 ) ( -1245 7 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 14 +{ +( -1113 -458 1580 ) ( -1241 -458 1580 ) ( -1241 -470 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 -427 1595 ) ( -1245 -415 1595 ) ( -1117 -415 1595 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 -532 1593 ) ( -1117 -532 1593 ) ( -1117 -532 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1081 -516 1593 ) ( -1081 -504 1593 ) ( -1081 -504 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1149 -369 1595 ) ( -1277 -369 1595 ) ( -1277 -369 1582 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 -520 1593 ) ( -1245 -532 1593 ) ( -1245 -532 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 15 +{ +( -1113 630 1580 ) ( -1241 630 1580 ) ( -1241 618 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 661 1595 ) ( -1245 673 1595 ) ( -1117 673 1595 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 556 1593 ) ( -1117 556 1593 ) ( -1117 556 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1081 572 1593 ) ( -1081 584 1593 ) ( -1081 584 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1149 719 1595 ) ( -1277 719 1595 ) ( -1277 719 1582 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 568 1593 ) ( -1245 556 1593 ) ( -1245 556 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 16 +{ +( -1113 1169 1579 ) ( -1241 1169 1579 ) ( -1241 1157 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 1200 1594 ) ( -1245 1212 1594 ) ( -1117 1212 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 1095 1592 ) ( -1117 1095 1592 ) ( -1117 1095 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1081 1111 1592 ) ( -1081 1123 1592 ) ( -1081 1123 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1149 1258 1594 ) ( -1277 1258 1594 ) ( -1277 1258 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 1107 1592 ) ( -1245 1095 1592 ) ( -1245 1095 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 17 +{ +( -1649 809 1579 ) ( -1777 809 1579 ) ( -1777 797 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1781 840 1594 ) ( -1781 852 1594 ) ( -1653 852 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1781 735 1592 ) ( -1653 735 1592 ) ( -1653 735 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1617 751 1592 ) ( -1617 763 1592 ) ( -1617 763 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1685 898 1594 ) ( -1813 898 1594 ) ( -1813 898 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1781 747 1592 ) ( -1781 735 1592 ) ( -1781 735 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 18 +{ +( -585 985 1579 ) ( -713 985 1579 ) ( -713 973 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -717 1016 1594 ) ( -717 1028 1594 ) ( -589 1028 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -717 911 1592 ) ( -589 911 1592 ) ( -589 911 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -553 927 1592 ) ( -553 939 1592 ) ( -553 939 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -621 1074 1594 ) ( -749 1074 1594 ) ( -749 1074 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -717 923 1592 ) ( -717 911 1592 ) ( -717 911 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 19 +{ +( 839 801 1579 ) ( 711 801 1579 ) ( 711 789 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 707 832 1594 ) ( 707 844 1594 ) ( 835 844 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 707 727 1592 ) ( 835 727 1592 ) ( 835 727 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 871 743 1592 ) ( 871 755 1592 ) ( 871 755 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 803 890 1594 ) ( 675 890 1594 ) ( 675 890 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 707 739 1592 ) ( 707 727 1592 ) ( 707 727 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 20 +{ +( -225 625 1579 ) ( -353 625 1579 ) ( -353 613 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -357 656 1594 ) ( -357 668 1594 ) ( -229 668 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -357 551 1592 ) ( -229 551 1592 ) ( -229 551 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -193 567 1592 ) ( -193 579 1592 ) ( -193 579 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -261 714 1594 ) ( -389 714 1594 ) ( -389 714 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -357 563 1592 ) ( -357 551 1592 ) ( -357 551 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 21 +{ +( 311 985 1579 ) ( 183 985 1579 ) ( 183 973 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 1016 1594 ) ( 179 1028 1594 ) ( 307 1028 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 911 1592 ) ( 307 911 1592 ) ( 307 911 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 343 927 1592 ) ( 343 939 1592 ) ( 343 939 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 275 1074 1594 ) ( 147 1074 1594 ) ( 147 1074 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 923 1592 ) ( 179 911 1592 ) ( 179 911 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 22 +{ +( 311 446 1580 ) ( 183 446 1580 ) ( 183 434 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 477 1595 ) ( 179 489 1595 ) ( 307 489 1595 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 372 1593 ) ( 307 372 1593 ) ( 307 372 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 343 388 1593 ) ( 343 400 1593 ) ( 343 400 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 275 535 1595 ) ( 147 535 1595 ) ( 147 535 1582 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 384 1593 ) ( 179 372 1593 ) ( 179 372 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 23 +{ +( 847 1326 1580 ) ( 719 1326 1580 ) ( 719 1314 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 715 1357 1595 ) ( 715 1369 1595 ) ( 843 1369 1595 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 715 1252 1593 ) ( 843 1252 1593 ) ( 843 1252 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 879 1268 1593 ) ( 879 1280 1593 ) ( 879 1280 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 811 1415 1595 ) ( 683 1415 1595 ) ( 683 1415 1582 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 715 1264 1593 ) ( 715 1252 1593 ) ( 715 1252 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 24 +{ +( 847 1865 1579 ) ( 719 1865 1579 ) ( 719 1853 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 715 1896 1594 ) ( 715 1908 1594 ) ( 843 1908 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 715 1791 1592 ) ( 843 1791 1592 ) ( 843 1791 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 879 1807 1592 ) ( 879 1819 1592 ) ( 879 1819 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 811 1954 1594 ) ( 683 1954 1594 ) ( 683 1954 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 715 1803 1592 ) ( 715 1791 1592 ) ( 715 1791 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 25 +{ +( 311 1505 1579 ) ( 183 1505 1579 ) ( 183 1493 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 1536 1594 ) ( 179 1548 1594 ) ( 307 1548 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 1431 1592 ) ( 307 1431 1592 ) ( 307 1431 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 343 1447 1592 ) ( 343 1459 1592 ) ( 343 1459 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 275 1594 1594 ) ( 147 1594 1594 ) ( 147 1594 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 179 1443 1592 ) ( 179 1431 1592 ) ( 179 1431 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 26 +{ +( 1375 1681 1579 ) ( 1247 1681 1579 ) ( 1247 1669 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1243 1712 1594 ) ( 1243 1724 1594 ) ( 1371 1724 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1243 1607 1592 ) ( 1371 1607 1592 ) ( 1371 1607 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1407 1623 1592 ) ( 1407 1635 1592 ) ( 1407 1635 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1339 1770 1594 ) ( 1211 1770 1594 ) ( 1211 1770 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( 1243 1619 1592 ) ( 1243 1607 1592 ) ( 1243 1607 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 27 +{ +( -49 1865 1579 ) ( -177 1865 1579 ) ( -177 1853 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -181 1896 1594 ) ( -181 1908 1594 ) ( -53 1908 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -181 1791 1592 ) ( -53 1791 1592 ) ( -53 1791 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -17 1807 1592 ) ( -17 1819 1592 ) ( -17 1819 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -85 1954 1594 ) ( -213 1954 1594 ) ( -213 1954 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -181 1803 1592 ) ( -181 1791 1592 ) ( -181 1791 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 28 +{ +( -1113 1689 1579 ) ( -1241 1689 1579 ) ( -1241 1677 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 1720 1594 ) ( -1245 1732 1594 ) ( -1117 1732 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 1615 1592 ) ( -1117 1615 1592 ) ( -1117 1615 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1081 1631 1592 ) ( -1081 1643 1592 ) ( -1081 1643 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1149 1778 1594 ) ( -1277 1778 1594 ) ( -1277 1778 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -1245 1627 1592 ) ( -1245 1615 1592 ) ( -1245 1615 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 29 +{ +( -577 2049 1579 ) ( -705 2049 1579 ) ( -705 2037 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -709 2080 1594 ) ( -709 2092 1594 ) ( -581 2092 1594 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -709 1975 1592 ) ( -581 1975 1592 ) ( -581 1975 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -545 1991 1592 ) ( -545 2003 1592 ) ( -545 2003 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -613 2138 1594 ) ( -741 2138 1594 ) ( -741 2138 1581 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -709 1987 1592 ) ( -709 1975 1592 ) ( -709 1975 1579 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 30 +{ +( -577 1510 1580 ) ( -705 1510 1580 ) ( -705 1498 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -709 1541 1595 ) ( -709 1553 1595 ) ( -581 1553 1595 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -709 1436 1593 ) ( -581 1436 1593 ) ( -581 1436 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -545 1452 1593 ) ( -545 1464 1593 ) ( -545 1464 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -613 1599 1595 ) ( -741 1599 1595 ) ( -741 1599 1582 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +( -709 1448 1593 ) ( -709 1436 1593 ) ( -709 1436 1580 ) desktop/ceiling2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 31 +{ +( -392 667 -457 ) ( -412 643 -453 ) ( -382 623 -416 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -422 689 -474 ) ( -441 665 -470 ) ( -402 632 -468 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -449 714 -460 ) ( -470 690 -456 ) ( -443 662 -492 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -459 728 -424 ) ( -478 704 -420 ) ( -481 698 -472 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -445 723 -387 ) ( -465 699 -383 ) ( -496 718 -421 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -416 701 -371 ) ( -436 677 -367 ) ( -476 710 -369 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -388 676 -384 ) ( -409 651 -381 ) ( -435 680 -345 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -378 661 -420 ) ( -399 637 -416 ) ( -396 643 -365 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -458 719 -475 ) ( -384 658 -472 ) ( -379 670 -369 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -450 585 -356 ) ( -456 573 -459 ) ( -530 635 -462 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 32 + { + patchDef2 + { + desktop/deskwood + ( 3 3 0 0 0 ) +( +( ( -360 160 -136 -2.812500 -1.250000 ) ( 368 160 -136 2.875000 -1.250000 ) ( 368 928 -136 2.875000 -7.250000 ) ) +( ( 368 160 -136 2.875000 -1.250000 ) ( 368 160 -136 2.875000 -1.250000 ) ( 368 160 -136 2.875000 -1.250000 ) ) +( ( 368 160 -136 2.875000 -1.250000 ) ( 368 160 -136 2.875000 -1.250000 ) ( 368 160 -136 2.875000 -1.250000 ) ) +) + } + } +// brush 33 + { + patchDef2 + { + desktop/deskwood + ( 3 3 0 0 0 ) +( +( ( 368 928 -168 2.875000 -7.250000 ) ( 368 160 -168 2.875000 -1.250000 ) ( -360 160 -168 -2.812500 -1.250000 ) ) +( ( 368 160 -168 2.875000 -1.250000 ) ( 368 160 -168 2.875000 -1.250000 ) ( 368 160 -168 2.875000 -1.250000 ) ) +( ( 368 160 -168 2.875000 -1.250000 ) ( 368 160 -168 2.875000 -1.250000 ) ( 368 160 -168 2.875000 -1.250000 ) ) +) + } + } +// brush 34 +{ +( 8192 8192 -136 ) ( 8192 -8192 -136 ) ( -8192 -8192 -136 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -168 ) ( 8192 8192 -168 ) ( -8192 -8192 -168 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 160 8192 ) ( -8192 160 8192 ) ( -8192 160 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1360 8192 ) ( 8192 -1360 8192 ) ( -8192 -1360 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 368 -8192 8192 ) ( 368 8192 8192 ) ( 368 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -1912 8192 8192 ) ( -1912 -8192 8192 ) ( -1912 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 35 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -448 676 -828 -7 -10.562500 ) ( -472 676 -828 -7.375000 -10.562500 ) ( -472 652 -828 -7.375000 -10.187500 ) ) +( ( -424 676 -828 -6.625000 -10.562500 ) ( -448 652 -828 -7 -10.187500 ) ( -472 628 -828 -7.375000 -9.812500 ) ) +( ( -424 652 -828 -6.625000 -10.187500 ) ( -424 628 -828 -6.625000 -9.812500 ) ( -448 628 -828 -7 -9.812500 ) ) +) + } + } +// brush 36 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -472 652 -660 -7.375000 -10.187500 ) ( -472 676 -660 -7.375000 -10.562500 ) ( -448 676 -660 -7 -10.562500 ) ) +( ( -472 628 -660 -7.375000 -9.812500 ) ( -448 652 -660 -7 -10.187500 ) ( -424 676 -660 -6.625000 -10.562500 ) ) +( ( -448 628 -660 -7 -9.812500 ) ( -424 628 -660 -6.625000 -9.812500 ) ( -424 652 -660 -6.625000 -10.187500 ) ) +) + } + } +// brush 37 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -448 688 -1120 -7 -10.750000 ) ( -484 688 -1120 -7.562500 -10.750000 ) ( -484 652 -1120 -7.562500 -10.187500 ) ) +( ( -412 688 -1120 -6.437500 -10.750000 ) ( -448 652 -1120 -7 -10.187500 ) ( -484 616 -1120 -7.562500 -9.625000 ) ) +( ( -412 652 -1120 -6.437500 -10.187500 ) ( -412 616 -1120 -6.437500 -9.625000 ) ( -448 616 -1120 -7 -9.625000 ) ) +) + } + } +// brush 38 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -484 652 -828 -7.562500 -10.187500 ) ( -484 688 -828 -7.562500 -10.750000 ) ( -448 688 -828 -7 -10.750000 ) ) +( ( -484 616 -828 -7.562500 -9.625000 ) ( -448 652 -828 -7 -10.187500 ) ( -412 688 -828 -6.437500 -10.750000 ) ) +( ( -448 616 -828 -7 -9.625000 ) ( -412 616 -828 -6.437500 -9.625000 ) ( -412 652 -828 -6.437500 -10.187500 ) ) +) + } + } +// brush 39 +{ +( -197 857 -1176 ) ( -197 857 -1120 ) ( -186 868 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -208 852 -1176 ) ( -208 852 -1120 ) ( -192 852 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -219 857 -1176 ) ( -219 857 -1120 ) ( -208 846 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -224 868 -1176 ) ( -224 868 -1120 ) ( -224 852 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -219 879 -1176 ) ( -219 879 -1120 ) ( -230 868 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -208 884 -1176 ) ( -208 884 -1120 ) ( -224 884 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -197 879 -1176 ) ( -197 879 -1120 ) ( -208 890 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -192 868 -1176 ) ( -192 868 -1120 ) ( -192 884 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -224 852 -1188 ) ( -192 852 -1188 ) ( -192 884 -1188 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -192 884 -1132 ) ( -192 852 -1132 ) ( -224 852 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 40 +{ +( -437 963 -1176 ) ( -437 963 -1120 ) ( -426 974 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -448 958 -1176 ) ( -448 958 -1120 ) ( -432 958 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -459 963 -1176 ) ( -459 963 -1120 ) ( -448 952 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 974 -1176 ) ( -464 974 -1120 ) ( -464 958 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -459 985 -1176 ) ( -459 985 -1120 ) ( -470 974 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -448 990 -1176 ) ( -448 990 -1120 ) ( -464 990 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -437 985 -1176 ) ( -437 985 -1120 ) ( -448 996 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 974 -1176 ) ( -432 974 -1120 ) ( -432 990 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 958 -1188 ) ( -432 958 -1188 ) ( -432 990 -1188 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 990 -1132 ) ( -432 958 -1132 ) ( -464 958 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 41 +{ +( -719 803 -1176 ) ( -719 803 -1120 ) ( -708 814 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -730 798 -1176 ) ( -730 798 -1120 ) ( -714 798 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -741 803 -1176 ) ( -741 803 -1120 ) ( -730 792 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -746 814 -1176 ) ( -746 814 -1120 ) ( -746 798 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -741 825 -1176 ) ( -741 825 -1120 ) ( -752 814 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -730 830 -1176 ) ( -730 830 -1120 ) ( -746 830 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -719 825 -1176 ) ( -719 825 -1120 ) ( -730 836 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -714 814 -1176 ) ( -714 814 -1120 ) ( -714 830 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -746 798 -1188 ) ( -714 798 -1188 ) ( -714 830 -1188 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -714 830 -1132 ) ( -714 798 -1132 ) ( -746 798 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 42 +{ +( -677 425 -1176 ) ( -677 425 -1120 ) ( -666 436 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -688 420 -1176 ) ( -688 420 -1120 ) ( -672 420 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -699 425 -1176 ) ( -699 425 -1120 ) ( -688 414 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -704 436 -1176 ) ( -704 436 -1120 ) ( -704 420 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -699 447 -1176 ) ( -699 447 -1120 ) ( -710 436 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -688 452 -1176 ) ( -688 452 -1120 ) ( -704 452 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -677 447 -1176 ) ( -677 447 -1120 ) ( -688 458 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -672 436 -1176 ) ( -672 436 -1120 ) ( -672 452 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -704 420 -1188 ) ( -672 420 -1188 ) ( -672 452 -1188 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -672 452 -1132 ) ( -672 420 -1132 ) ( -704 420 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 43 +{ +( -437 317 -1176 ) ( -437 317 -1120 ) ( -426 328 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -448 312 -1176 ) ( -448 312 -1120 ) ( -432 312 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -459 317 -1176 ) ( -459 317 -1120 ) ( -448 306 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 328 -1176 ) ( -464 328 -1120 ) ( -464 312 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -459 339 -1176 ) ( -459 339 -1120 ) ( -470 328 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -448 344 -1176 ) ( -448 344 -1120 ) ( -464 344 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -437 339 -1176 ) ( -437 339 -1120 ) ( -448 350 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 328 -1176 ) ( -432 328 -1120 ) ( -432 344 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 312 -1188 ) ( -432 312 -1188 ) ( -432 344 -1188 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 344 -1132 ) ( -432 312 -1132 ) ( -464 312 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 44 +{ +( -153 469 -1176 ) ( -153 469 -1120 ) ( -142 480 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -164 464 -1176 ) ( -164 464 -1120 ) ( -148 464 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -175 469 -1176 ) ( -175 469 -1120 ) ( -164 458 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -180 480 -1176 ) ( -180 480 -1120 ) ( -180 464 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -175 491 -1176 ) ( -175 491 -1120 ) ( -186 480 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -164 496 -1176 ) ( -164 496 -1120 ) ( -180 496 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -153 491 -1176 ) ( -153 491 -1120 ) ( -164 502 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -148 480 -1176 ) ( -148 480 -1120 ) ( -148 496 -1120 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -180 464 -1188 ) ( -148 464 -1188 ) ( -148 496 -1188 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -148 496 -1132 ) ( -148 464 -1132 ) ( -180 464 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 45 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 944 8 120 ) ( 592 8 120 ) ( 592 -688 120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 -688 400 ) ( 592 8 400 ) ( 944 8 400 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 544 -688 480 ) ( 544 8 480 ) ( 544 -688 168 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 46 +{ +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 944 8 120 ) ( 592 8 120 ) ( 592 -688 120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 -688 400 ) ( 592 8 400 ) ( 944 8 400 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 944 8 480 ) ( 944 -688 480 ) ( 944 8 168 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 47 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 688 ) ( 8192 -8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 400 ) ( 592 -688 400 ) ( 944 8 400 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 48 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 120 ) ( 944 8 120 ) ( 592 -688 120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 49 +{ +( 744 8192 8192 ) ( 744 -8192 8192 ) ( 744 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -641 8192 ) ( -8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8159 -997 8192 ) ( 8212 -355 8192 ) ( 8212 -355 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8212 -354 8192 ) ( -8159 -996 8192 ) ( -8159 -996 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8209 -296 8192 ) ( 8161 -938 8192 ) ( 8161 -938 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 400 ) ( 592 -688 400 ) ( 944 8 400 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 50 +{ +( 744 8192 8192 ) ( 744 -8192 8192 ) ( 744 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -641 8192 ) ( -8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8159 -997 8192 ) ( 8212 -355 8192 ) ( 8212 -355 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8212 -354 8192 ) ( -8159 -996 8192 ) ( -8159 -996 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8209 -296 8192 ) ( 8161 -938 8192 ) ( 8161 -938 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 120 ) ( 944 8 120 ) ( 592 -688 120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 51 +{ +( 8192 -620 8192 ) ( -8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7955 -2103 8192 ) ( 8210 559 8192 ) ( 8210 559 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8202 560 8192 ) ( -7964 -2102 8192 ) ( -7964 -2102 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7033 -4318 8192 ) ( 7865 2498 8192 ) ( 7865 2498 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 944 8 120 ) ( 592 8 120 ) ( 592 -688 120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 -688 400 ) ( 592 8 400 ) ( 944 8 400 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 944 8 480 ) ( 944 -688 480 ) ( 944 8 168 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 52 +{ +( 914 8192 8192 ) ( 914 -8192 8192 ) ( 914 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -641 8192 ) ( 8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -620 8192 ) ( -8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7955 -2103 8192 ) ( 8210 559 8192 ) ( 8210 559 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8202 560 8192 ) ( -7964 -2102 8192 ) ( -7964 -2102 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8159 -997 8192 ) ( 8212 -355 8192 ) ( 8212 -355 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7033 -4318 8192 ) ( 7865 2498 8192 ) ( 7865 2498 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 400 ) ( 592 -688 400 ) ( 944 8 400 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 53 +{ +( 914 8192 8192 ) ( 914 -8192 8192 ) ( 914 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -641 8192 ) ( 8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -620 8192 ) ( -8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7955 -2103 8192 ) ( 8210 559 8192 ) ( 8210 559 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8202 560 8192 ) ( -7964 -2102 8192 ) ( -7964 -2102 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8159 -997 8192 ) ( 8212 -355 8192 ) ( 8212 -355 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7033 -4318 8192 ) ( 7865 2498 8192 ) ( 7865 2498 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 120 ) ( 944 8 120 ) ( 592 -688 120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 54 +{ +( 744 -8192 8192 ) ( 744 8192 8192 ) ( 744 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -641 8192 ) ( -8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8209 -296 8192 ) ( 8161 -938 8192 ) ( 8161 -938 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8161 -937 8192 ) ( -8209 -295 8192 ) ( -8209 -295 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 400 ) ( 592 -688 400 ) ( 944 8 400 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 55 +{ +( 744 -8192 8192 ) ( 744 8192 8192 ) ( 744 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -641 8192 ) ( -8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8209 -296 8192 ) ( 8161 -938 8192 ) ( 8161 -938 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8161 -937 8192 ) ( -8209 -295 8192 ) ( -8209 -295 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 120 ) ( 944 8 120 ) ( 592 -688 120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 56 +{ +( 8192 -620 8192 ) ( -8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8170 797 8192 ) ( 7995 -1864 8192 ) ( 7995 -1864 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8019 -1863 8192 ) ( -8146 798 8192 ) ( -8146 798 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 944 8 120 ) ( 592 8 120 ) ( 592 -688 120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 -688 400 ) ( 592 8 400 ) ( 944 8 400 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 544 -688 480 ) ( 544 8 480 ) ( 544 -688 168 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 57 +{ +( -8192 -641 8192 ) ( 8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -620 8192 ) ( -8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8170 797 8192 ) ( 7995 -1864 8192 ) ( 7995 -1864 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8019 -1863 8192 ) ( -8146 798 8192 ) ( -8146 798 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8209 -296 8192 ) ( 8161 -938 8192 ) ( 8161 -938 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 400 ) ( 592 -688 400 ) ( 944 8 400 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 58 +{ +( -8192 -641 8192 ) ( 8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -620 8192 ) ( -8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8170 797 8192 ) ( 7995 -1864 8192 ) ( 7995 -1864 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8019 -1863 8192 ) ( -8146 798 8192 ) ( -8146 798 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8209 -296 8192 ) ( 8161 -938 8192 ) ( 8161 -938 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 592 8 120 ) ( 944 8 120 ) ( 592 -688 120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 59 + { + patchDef2 + { + desktop/greenfoot + ( 9 3 0 0 0 ) +( +( ( 536 1304 -1208 0 0 ) ( 536 1304 -1144 0 2.625000 ) ( 536 1304 -1080 0 5.250000 ) ) +( ( 536 1264 -1208 1.250000 0 ) ( 536 1264 -1144 1.250000 2.625000 ) ( 536 1264 -1080 1.250000 5.250000 ) ) +( ( 576 1264 -1208 2.500000 0 ) ( 576 1264 -1144 2.500000 2.625000 ) ( 576 1264 -1080 2.500000 5.250000 ) ) +( ( 616 1264 -1208 3.750000 0 ) ( 616 1264 -1144 3.750000 2.625000 ) ( 616 1264 -1080 3.750000 5.250000 ) ) +( ( 616 1304 -1208 5 0 ) ( 616 1304 -1144 5 2.625000 ) ( 616 1304 -1080 5 5.250000 ) ) +( ( 616 1344 -1208 6.250000 0 ) ( 616 1344 -1144 6.250000 2.625000 ) ( 616 1344 -1080 6.250000 5.250000 ) ) +( ( 576 1344 -1208 7.500000 0 ) ( 576 1344 -1144 7.500000 2.625000 ) ( 576 1344 -1080 7.500000 5.250000 ) ) +( ( 536 1344 -1208 8.750000 0 ) ( 536 1344 -1144 8.750000 2.625000 ) ( 536 1344 -1080 8.750000 5.250000 ) ) +( ( 536 1304 -1208 10 0 ) ( 536 1304 -1144 10 2.625000 ) ( 536 1304 -1080 10 5.250000 ) ) +) + } + } +// brush 60 + { + patchDef2 + { + desktop/greenfoot + ( 9 3 0 0 0 ) +( +( ( 536 904 -1208 0 0 ) ( 536 904 -1144 0 2.625000 ) ( 536 904 -1080 0 5.250000 ) ) +( ( 536 864 -1208 1.250000 0 ) ( 536 864 -1144 1.250000 2.625000 ) ( 536 864 -1080 1.250000 5.250000 ) ) +( ( 576 864 -1208 2.500000 0 ) ( 576 864 -1144 2.500000 2.625000 ) ( 576 864 -1080 2.500000 5.250000 ) ) +( ( 616 864 -1208 3.750000 0 ) ( 616 864 -1144 3.750000 2.625000 ) ( 616 864 -1080 3.750000 5.250000 ) ) +( ( 616 904 -1208 5 0 ) ( 616 904 -1144 5 2.625000 ) ( 616 904 -1080 5 5.250000 ) ) +( ( 616 944 -1208 6.250000 0 ) ( 616 944 -1144 6.250000 2.625000 ) ( 616 944 -1080 6.250000 5.250000 ) ) +( ( 576 944 -1208 7.500000 0 ) ( 576 944 -1144 7.500000 2.625000 ) ( 576 944 -1080 7.500000 5.250000 ) ) +( ( 536 944 -1208 8.750000 0 ) ( 536 944 -1144 8.750000 2.625000 ) ( 536 944 -1080 8.750000 5.250000 ) ) +( ( 536 904 -1208 10 0 ) ( 536 904 -1144 10 2.625000 ) ( 536 904 -1080 10 5.250000 ) ) +) + } + } +// brush 61 + { + patchDef2 + { + desktop/greenfoot + ( 9 3 0 0 0 ) +( +( ( 1824 904 -1208 0 0 ) ( 1824 904 -1144 0 2.625000 ) ( 1824 904 -1080 0 5.250000 ) ) +( ( 1824 864 -1208 1.250000 0 ) ( 1824 864 -1144 1.250000 2.625000 ) ( 1824 864 -1080 1.250000 5.250000 ) ) +( ( 1864 864 -1208 2.500000 0 ) ( 1864 864 -1144 2.500000 2.625000 ) ( 1864 864 -1080 2.500000 5.250000 ) ) +( ( 1904 864 -1208 3.750000 0 ) ( 1904 864 -1144 3.750000 2.625000 ) ( 1904 864 -1080 3.750000 5.250000 ) ) +( ( 1904 904 -1208 5 0 ) ( 1904 904 -1144 5 2.625000 ) ( 1904 904 -1080 5 5.250000 ) ) +( ( 1904 944 -1208 6.250000 0 ) ( 1904 944 -1144 6.250000 2.625000 ) ( 1904 944 -1080 6.250000 5.250000 ) ) +( ( 1864 944 -1208 7.500000 0 ) ( 1864 944 -1144 7.500000 2.625000 ) ( 1864 944 -1080 7.500000 5.250000 ) ) +( ( 1824 944 -1208 8.750000 0 ) ( 1824 944 -1144 8.750000 2.625000 ) ( 1824 944 -1080 8.750000 5.250000 ) ) +( ( 1824 904 -1208 10 0 ) ( 1824 904 -1144 10 2.625000 ) ( 1824 904 -1080 10 5.250000 ) ) +) + } + } +// brush 62 + { + patchDef2 + { + desktop/greenfoot + ( 9 3 0 0 0 ) +( +( ( 1824 1304 -1208 0 0 ) ( 1824 1304 -1144 0 2.625000 ) ( 1824 1304 -1080 0 5.250000 ) ) +( ( 1824 1264 -1208 1.250000 0 ) ( 1824 1264 -1144 1.250000 2.625000 ) ( 1824 1264 -1080 1.250000 5.250000 ) ) +( ( 1864 1264 -1208 2.500000 0 ) ( 1864 1264 -1144 2.500000 2.625000 ) ( 1864 1264 -1080 2.500000 5.250000 ) ) +( ( 1904 1264 -1208 3.750000 0 ) ( 1904 1264 -1144 3.750000 2.625000 ) ( 1904 1264 -1080 3.750000 5.250000 ) ) +( ( 1904 1304 -1208 5 0 ) ( 1904 1304 -1144 5 2.625000 ) ( 1904 1304 -1080 5 5.250000 ) ) +( ( 1904 1344 -1208 6.250000 0 ) ( 1904 1344 -1144 6.250000 2.625000 ) ( 1904 1344 -1080 6.250000 5.250000 ) ) +( ( 1864 1344 -1208 7.500000 0 ) ( 1864 1344 -1144 7.500000 2.625000 ) ( 1864 1344 -1080 7.500000 5.250000 ) ) +( ( 1824 1344 -1208 8.750000 0 ) ( 1824 1344 -1144 8.750000 2.625000 ) ( 1824 1344 -1080 8.750000 5.250000 ) ) +( ( 1824 1304 -1208 10 0 ) ( 1824 1304 -1144 10 2.625000 ) ( 1824 1304 -1080 10 5.250000 ) ) +) + } + } +// brush 63 + { + patchDef2 + { + desktop/greenfoot + ( 9 3 0 0 0 ) +( +( ( 1824 1304 -336 0 0 ) ( 1824 1304 -252 0 2.625000 ) ( 1824 1304 -168 0 5.250000 ) ) +( ( 1824 1264 -336 1.250000 0 ) ( 1824 1264 -252 1.250000 2.625000 ) ( 1824 1264 -168 1.250000 5.250000 ) ) +( ( 1864 1264 -336 2.500000 0 ) ( 1864 1264 -252 2.500000 2.625000 ) ( 1864 1264 -168 2.500000 5.250000 ) ) +( ( 1904 1264 -336 3.750000 0 ) ( 1904 1264 -252 3.750000 2.625000 ) ( 1904 1264 -168 3.750000 5.250000 ) ) +( ( 1904 1304 -336 5 0 ) ( 1904 1304 -252 5 2.625000 ) ( 1904 1304 -168 5 5.250000 ) ) +( ( 1904 1344 -336 6.250000 0 ) ( 1904 1344 -252 6.250000 2.625000 ) ( 1904 1344 -168 6.250000 5.250000 ) ) +( ( 1864 1344 -336 7.500000 0 ) ( 1864 1344 -252 7.500000 2.625000 ) ( 1864 1344 -168 7.500000 5.250000 ) ) +( ( 1824 1344 -336 8.750000 0 ) ( 1824 1344 -252 8.750000 2.625000 ) ( 1824 1344 -168 8.750000 5.250000 ) ) +( ( 1824 1304 -336 10 0 ) ( 1824 1304 -252 10 2.625000 ) ( 1824 1304 -168 10 5.250000 ) ) +) + } + } +// brush 64 + { + patchDef2 + { + desktop/greenfoot + ( 9 3 0 0 0 ) +( +( ( 1824 904 -336 0 0 ) ( 1824 904 -252 0 2.625000 ) ( 1824 904 -168 0 5.250000 ) ) +( ( 1824 864 -336 1.250000 0 ) ( 1824 864 -252 1.250000 2.625000 ) ( 1824 864 -168 1.250000 5.250000 ) ) +( ( 1864 864 -336 2.500000 0 ) ( 1864 864 -252 2.500000 2.625000 ) ( 1864 864 -168 2.500000 5.250000 ) ) +( ( 1904 864 -336 3.750000 0 ) ( 1904 864 -252 3.750000 2.625000 ) ( 1904 864 -168 3.750000 5.250000 ) ) +( ( 1904 904 -336 5 0 ) ( 1904 904 -252 5 2.625000 ) ( 1904 904 -168 5 5.250000 ) ) +( ( 1904 944 -336 6.250000 0 ) ( 1904 944 -252 6.250000 2.625000 ) ( 1904 944 -168 6.250000 5.250000 ) ) +( ( 1864 944 -336 7.500000 0 ) ( 1864 944 -252 7.500000 2.625000 ) ( 1864 944 -168 7.500000 5.250000 ) ) +( ( 1824 944 -336 8.750000 0 ) ( 1824 944 -252 8.750000 2.625000 ) ( 1824 944 -168 8.750000 5.250000 ) ) +( ( 1824 904 -336 10 0 ) ( 1824 904 -252 10 2.625000 ) ( 1824 904 -168 10 5.250000 ) ) +) + } + } +// brush 65 + { + patchDef2 + { + desktop/greenfoot + ( 9 3 0 0 0 ) +( +( ( 536 904 -336 0 0 ) ( 536 904 -252 0 2.625000 ) ( 536 904 -168 0 5.250000 ) ) +( ( 536 864 -336 1.250000 0 ) ( 536 864 -252 1.250000 2.625000 ) ( 536 864 -168 1.250000 5.250000 ) ) +( ( 576 864 -336 2.500000 0 ) ( 576 864 -252 2.500000 2.625000 ) ( 576 864 -168 2.500000 5.250000 ) ) +( ( 616 864 -336 3.750000 0 ) ( 616 864 -252 3.750000 2.625000 ) ( 616 864 -168 3.750000 5.250000 ) ) +( ( 616 904 -336 5 0 ) ( 616 904 -252 5 2.625000 ) ( 616 904 -168 5 5.250000 ) ) +( ( 616 944 -336 6.250000 0 ) ( 616 944 -252 6.250000 2.625000 ) ( 616 944 -168 6.250000 5.250000 ) ) +( ( 576 944 -336 7.500000 0 ) ( 576 944 -252 7.500000 2.625000 ) ( 576 944 -168 7.500000 5.250000 ) ) +( ( 536 944 -336 8.750000 0 ) ( 536 944 -252 8.750000 2.625000 ) ( 536 944 -168 8.750000 5.250000 ) ) +( ( 536 904 -336 10 0 ) ( 536 904 -252 10 2.625000 ) ( 536 904 -168 10 5.250000 ) ) +) + } + } +// brush 66 + { + patchDef2 + { + desktop/greenfoot + ( 9 3 0 0 0 ) +( +( ( 536 1304 -336 0 0 ) ( 536 1304 -252 0 2.625000 ) ( 536 1304 -168 0 5.250000 ) ) +( ( 536 1264 -336 1.250000 0 ) ( 536 1264 -252 1.250000 2.625000 ) ( 536 1264 -168 1.250000 5.250000 ) ) +( ( 576 1264 -336 2.500000 0 ) ( 576 1264 -252 2.500000 2.625000 ) ( 576 1264 -168 2.500000 5.250000 ) ) +( ( 616 1264 -336 3.750000 0 ) ( 616 1264 -252 3.750000 2.625000 ) ( 616 1264 -168 3.750000 5.250000 ) ) +( ( 616 1304 -336 5 0 ) ( 616 1304 -252 5 2.625000 ) ( 616 1304 -168 5 5.250000 ) ) +( ( 616 1344 -336 6.250000 0 ) ( 616 1344 -252 6.250000 2.625000 ) ( 616 1344 -168 6.250000 5.250000 ) ) +( ( 576 1344 -336 7.500000 0 ) ( 576 1344 -252 7.500000 2.625000 ) ( 576 1344 -168 7.500000 5.250000 ) ) +( ( 536 1344 -336 8.750000 0 ) ( 536 1344 -252 8.750000 2.625000 ) ( 536 1344 -168 8.750000 5.250000 ) ) +( ( 536 1304 -336 10 0 ) ( 536 1304 -252 10 2.625000 ) ( 536 1304 -168 10 5.250000 ) ) +) + } + } +// brush 67 + { + patchDef2 + { + desktop/greenfoot + ( 3 3 0 0 0 ) +( +( ( 1784 -512 -168 0 32.500000 ) ( 1784 -512 -656 0 16.250000 ) ( 1784 -512 -1144 0 0 ) ) +( ( 1832 -512 -168 1.500000 32.500000 ) ( 1832 -512 -656 1.500000 16.250000 ) ( 1832 -512 -1144 1.500000 0 ) ) +( ( 1832 -744 -168 8.750000 32.500000 ) ( 1832 -744 -656 8.750000 16.250000 ) ( 1832 -744 -1144 8.750000 0 ) ) +) + } + } +// brush 68 + { + patchDef2 + { + desktop/greenfoot + ( 3 3 0 0 0 ) +( +( ( 1784 -976 -168 0 32.500000 ) ( 1784 -976 -656 0 16.250000 ) ( 1784 -976 -1144 0 0 ) ) +( ( 1736 -976 -168 1.500000 32.500000 ) ( 1736 -976 -656 1.500000 16.250000 ) ( 1736 -976 -1144 1.500000 0 ) ) +( ( 1736 -744 -168 8.750000 32.500000 ) ( 1736 -744 -656 8.750000 16.250000 ) ( 1736 -744 -1144 8.750000 0 ) ) +) + } + } +// brush 69 + { + patchDef2 + { + desktop/greenfoot + ( 3 3 0 0 0 ) +( +( ( 1784 -976 -1144 0 0 ) ( 1784 -976 -656 0 16.250000 ) ( 1784 -976 -168 0 32.500000 ) ) +( ( 1832 -976 -1144 1.500000 0 ) ( 1832 -976 -656 1.500000 16.250000 ) ( 1832 -976 -168 1.500000 32.500000 ) ) +( ( 1832 -744 -1144 8.750000 0 ) ( 1832 -744 -656 8.750000 16.250000 ) ( 1832 -744 -168 8.750000 32.500000 ) ) +) + } + } +// brush 70 + { + patchDef2 + { + desktop/greenfoot + ( 3 3 0 0 0 ) +( +( ( 1784 -512 -1144 0 0 ) ( 1784 -512 -656 0 16.250000 ) ( 1784 -512 -167.999969 0 32.500000 ) ) +( ( 1736 -512 -1144 1.500000 0 ) ( 1736 -512 -656 1.500000 16.250000 ) ( 1736 -512 -167.999969 1.500000 32.500000 ) ) +( ( 1736 -744 -1144 8.750000 0 ) ( 1736 -744 -656 8.750000 16.250000 ) ( 1736 -744 -167.999969 8.750000 32.500000 ) ) +) + } + } +// brush 71 + { + patchDef2 + { + desktop/greenfoot + ( 3 3 0 0 0 ) +( +( ( -1640 -1008 -1144 0 0 ) ( -1640 -1008 -656 0 16.250000 ) ( -1640 -1008 -168 0 32.500000 ) ) +( ( -1592 -1008 -1144 1.500000 0 ) ( -1592 -1008 -656 1.500000 16.250000 ) ( -1592 -1008 -168 1.500000 32.500000 ) ) +( ( -1592 -776 -1144 8.750000 0 ) ( -1592 -776 -656 8.750000 16.250000 ) ( -1592 -776 -168 8.750000 32.500000 ) ) +) + } + } +// brush 72 + { + patchDef2 + { + desktop/greenfoot + ( 3 3 0 0 0 ) +( +( ( -1640 -1008 -168 0 32.500000 ) ( -1640 -1008 -656 0 16.250000 ) ( -1640 -1008 -1144 0 0 ) ) +( ( -1688 -1008 -168 1.500000 32.500000 ) ( -1688 -1008 -656 1.500000 16.250000 ) ( -1688 -1008 -1144 1.500000 0 ) ) +( ( -1688 -776 -168 8.750000 32.500000 ) ( -1688 -776 -656 8.750000 16.250000 ) ( -1688 -776 -1144 8.750000 0 ) ) +) + } + } +// brush 73 + { + patchDef2 + { + desktop/greenfoot + ( 3 3 0 0 0 ) +( +( ( -1640 -544 -1144 0 0 ) ( -1640 -544 -656 0 16.250000 ) ( -1640 -544 -168 0 32.500000 ) ) +( ( -1688 -544 -1144 1.500000 0 ) ( -1688 -544 -656 1.500000 16.250000 ) ( -1688 -544 -168 1.500000 32.500000 ) ) +( ( -1688 -776 -1144 8.750000 0 ) ( -1688 -776 -656 8.750000 16.250000 ) ( -1688 -776 -168 8.750000 32.500000 ) ) +) + } + } +// brush 74 + { + patchDef2 + { + desktop/greenfoot + ( 3 3 0 0 0 ) +( +( ( -1640 -544 -168 0 32.500000 ) ( -1640 -544 -656 0 16.250000 ) ( -1640 -544 -1144 0 0 ) ) +( ( -1592 -544 -168 1.500000 32.500000 ) ( -1592 -544 -656 1.500000 16.250000 ) ( -1592 -544 -1144 1.500000 0 ) ) +( ( -1592 -776 -168 8.750000 32.500000 ) ( -1592 -776 -656 8.750000 16.250000 ) ( -1592 -776 -1144 8.750000 0 ) ) +) + } + } +// brush 75 +{ +( -34 -176 -136 ) ( -34 -176 0 ) ( 4 -138 0 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -70 -190 -136 ) ( -70 -190 0 ) ( -16 -190 0 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -104 -174 -136 ) ( -104 -174 0 ) ( -66 -212 0 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -118 -138 -136 ) ( -118 -138 0 ) ( -118 -192 0 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -102 -104 -136 ) ( -102 -104 0 ) ( -140 -142 0 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -66 -92 -136 ) ( -66 -92 0 ) ( -120 -92 0 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -40 -104 -136 ) ( -40 -104 0 ) ( -78 -66 0 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -22 -140 -136 ) ( -22 -140 0 ) ( -22 -86 0 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -120 -192 -136 ) ( -16 -192 -136 ) ( -16 -84 -136 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -18 -84 -8 ) ( -18 -192 -8 ) ( -122 -192 -8 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 76 + { + patchDef2 + { + common/clip + ( 9 3 0 0 0 ) +( +( ( -122 -140 0 0 8.500000 ) ( -122 -140 -68 0 4.250000 ) ( -122 -140 -136 0 0 ) ) +( ( -122 -194 0 3.750000 8.500000 ) ( -122 -194 -68 3.750000 4.250000 ) ( -122 -194 -136 3.750000 0 ) ) +( ( -70 -194 0 7.500000 8.500000 ) ( -70 -194 -68 7.500000 4.250000 ) ( -70 -194 -136 7.500000 0 ) ) +( ( -17.999998 -194 0 11.250000 8.500000 ) ( -17.999998 -194 -68 11.250000 4.250000 ) ( -17.999998 -194 -136 11.250000 0 ) ) +( ( -17.999998 -140 0 15 8.500000 ) ( -17.999998 -140 -68 15 4.250000 ) ( -17.999998 -140 -136 15 0 ) ) +( ( -17.999998 -86 0 18.750000 8.500000 ) ( -17.999998 -86 -68 18.750000 4.250000 ) ( -17.999998 -86 -136 18.750000 0 ) ) +( ( -70 -86 0 22.500000 8.500000 ) ( -70 -86 -68 22.500000 4.250000 ) ( -70 -86 -136 22.500000 0 ) ) +( ( -122 -86 0 26.250000 8.500000 ) ( -122 -86 -68 26.250000 4.250000 ) ( -122 -86 -136 26.250000 0 ) ) +( ( -122 -140 0 30 8.500000 ) ( -122 -140 -68 30 4.250000 ) ( -122 -140 -136 30 0 ) ) +) + } + } +// brush 77 + { + patchDef2 + { + common/clip + ( 9 3 0 0 0 ) +( +( ( -130 -141 -136 0 0 ) ( -130 -141 -68 0 4.250000 ) ( -130 -141 0 0 8.500000 ) ) +( ( -130 -200 -136 3.750000 0 ) ( -130 -200 -68 3.750000 4.250000 ) ( -130 -200 0 3.750000 8.500000 ) ) +( ( -70 -200 -136 7.500000 0 ) ( -70 -200 -68 7.500000 4.250000 ) ( -70 -200 0 7.500000 8.500000 ) ) +( ( -10 -200 -136 11.250000 0 ) ( -10 -200 -68 11.250000 4.250000 ) ( -10 -200 0 11.250000 8.500000 ) ) +( ( -10 -141 -136 15 0 ) ( -10 -141 -68 15 4.250000 ) ( -10 -141 0 15 8.500000 ) ) +( ( -10 -82 -136 18.750000 0 ) ( -10 -82 -68 18.750000 4.250000 ) ( -10 -82 0 18.750000 8.500000 ) ) +( ( -70 -82 -136 22.500000 0 ) ( -70 -82 -68 22.500000 4.250000 ) ( -70 -82 0 22.500000 8.500000 ) ) +( ( -130 -82 -136 26.250000 0 ) ( -130 -82 -68 26.250000 4.250000 ) ( -130 -82 0 26.250000 8.500000 ) ) +( ( -130 -141 -136 30 0 ) ( -130 -141 -68 30 4.250000 ) ( -130 -141 0 30 8.500000 ) ) +) + } + } +// brush 78 +{ +( -8192 -256 7850 ) ( 8192 -256 7850 ) ( -8192 -256 -8534 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 7850 ) ( -8192 -216 7850 ) ( -8192 -216 -8534 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -134 ) ( 8192 -8192 -134 ) ( -8192 -8192 -134 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 749 -8161 7850 ) ( -272 8190 7850 ) ( -272 8190 -8534 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 583 8171 7850 ) ( -438 -8180 7850 ) ( -438 -8180 -8534 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 79 +{ +( 232 -198 -10 ) ( 40 -198 -10 ) ( 40 -230 -10 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 40 -232 206 ) ( 40 -200 206 ) ( 232 -200 206 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 40 -216 142 ) ( 232 -216 142 ) ( 232 -216 -146 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 232 -202 120 ) ( 40 -202 120 ) ( 40 -202 -168 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 254 -240 150 ) ( 254 -240 -138 ) ( 256 -272 150 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 252 -236 -154 ) ( 252 -236 134 ) ( 254 -268 134 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 80 +{ +( 232 -200 -10 ) ( 40 -200 -10 ) ( 40 -232 -10 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 40 -230 206 ) ( 40 -198 206 ) ( 232 -198 206 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 40 -216 144 ) ( 232 -216 144 ) ( 232 -216 -144 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 232 -202 120 ) ( 40 -202 120 ) ( 40 -202 -168 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 60 -198 310 ) ( 58 -230 310 ) ( 60 -198 22 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 60 -232 328 ) ( 62 -200 328 ) ( 62 -200 40 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 81 +{ +( 230 -200 -10 ) ( 38 -200 -10 ) ( 38 -232 -10 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 40 -232 206 ) ( 40 -200 206 ) ( 232 -200 206 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 234 -200 122 ) ( 42 -200 122 ) ( 42 -200 -166 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 60 -198 328 ) ( 58 -230 328 ) ( 60 -198 40 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 254 -238 152 ) ( 254 -238 -136 ) ( 256 -270 152 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 40 -202 120 ) ( 232 -202 120 ) ( 40 -202 -168 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 82 +{ +( 40 -232 208 ) ( 40 -200 208 ) ( 232 -200 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -216 144 ) ( 232 -216 144 ) ( 232 -216 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 240 -200 152 ) ( 48 -200 152 ) ( 48 -200 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 60 -198 328 ) ( 58 -230 328 ) ( 60 -198 40 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 254 -238 152 ) ( 254 -238 -136 ) ( 256 -270 152 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -200 206 ) ( 40 -232 206 ) ( 232 -200 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 83 +{ +( 240 -200 -12 ) ( 48 -200 -12 ) ( 48 -232 -12 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -216 92 ) ( 232 -216 92 ) ( 232 -216 -196 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 240 -200 100 ) ( 48 -200 100 ) ( 48 -200 -188 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 60 -198 276 ) ( 58 -230 276 ) ( 60 -198 -12 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 254 -238 100 ) ( 254 -238 -188 ) ( 256 -270 100 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 48 -200 -10 ) ( 240 -200 -10 ) ( 48 -232 -10 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 84 +{ +( 264 -256 -136 ) ( 72 -256 -136 ) ( 72 -288 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 64 -288 206 ) ( 64 -256 206 ) ( 256 -256 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 72 -480 144 ) ( 264 -480 144 ) ( 264 -480 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 264 -256 152 ) ( 72 -256 152 ) ( 72 -256 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 257 -233 -80 ) ( 255 -265 -80 ) ( 257 -233 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 253 -265 -80 ) ( 255 -233 -80 ) ( 255 -233 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 85 +{ +( 264 -256 -136 ) ( 72 -256 -136 ) ( 72 -288 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 64 -288 206 ) ( 64 -256 206 ) ( 256 -256 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 72 -480 144 ) ( 264 -480 144 ) ( 264 -480 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 264 -256 152 ) ( 72 -256 152 ) ( 72 -256 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 55 -241 152 ) ( 57 -273 152 ) ( 55 -241 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 59 -273 152 ) ( 57 -241 152 ) ( 57 -241 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 86 +{ +( 64 -288 208 ) ( 64 -256 208 ) ( 256 -256 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 72 -480 144 ) ( 264 -480 144 ) ( 264 -480 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 264 -256 152 ) ( 72 -256 152 ) ( 72 -256 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 55 -241 152 ) ( 57 -273 152 ) ( 55 -241 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 257 -233 -80 ) ( 255 -265 -80 ) ( 257 -233 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 64 -256 206 ) ( 64 -288 206 ) ( 256 -256 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 87 +{ +( 264 -256 -136 ) ( 72 -256 -136 ) ( 72 -288 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 72 -480 144 ) ( 264 -480 144 ) ( 264 -480 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 264 -256 152 ) ( 72 -256 152 ) ( 72 -256 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 55 -241 152 ) ( 57 -273 152 ) ( 55 -241 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 257 -233 -80 ) ( 255 -265 -80 ) ( 257 -233 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 72 -256 -134 ) ( 264 -256 -134 ) ( 72 -288 -134 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 88 +{ +( 240 -200 -136 ) ( 48 -200 -136 ) ( 48 -232 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -232 206 ) ( 40 -200 206 ) ( 232 -200 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -256 144 ) ( 232 -256 144 ) ( 232 -256 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 240 -216 152 ) ( 48 -216 152 ) ( 48 -216 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 254 -238 152 ) ( 254 -238 -136 ) ( 256 -270 152 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 252 -238 -136 ) ( 252 -238 152 ) ( 254 -270 152 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 89 +{ +( 240 -200 -136 ) ( 48 -200 -136 ) ( 48 -232 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -232 206 ) ( 40 -200 206 ) ( 232 -200 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -256 144 ) ( 232 -256 144 ) ( 232 -256 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 240 -216 150 ) ( 48 -216 150 ) ( 48 -216 -138 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 60 -198 152 ) ( 58 -230 152 ) ( 60 -198 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 60 -230 150 ) ( 62 -198 150 ) ( 62 -198 -138 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 90 +{ +( 240 -200 -136 ) ( 48 -200 -136 ) ( 48 -232 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -232 18 ) ( 40 -200 18 ) ( 232 -200 18 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 242 -216 110 ) ( 50 -216 110 ) ( 50 -216 -178 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 60 -198 128 ) ( 58 -230 128 ) ( 60 -198 -160 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 254 -238 128 ) ( 254 -238 -160 ) ( 256 -270 128 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 48 -218 128 ) ( 240 -218 128 ) ( 48 -218 -160 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 91 +{ +( 40 -232 208 ) ( 40 -200 208 ) ( 232 -200 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -256 144 ) ( 232 -256 144 ) ( 232 -256 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 240 -216 152 ) ( 48 -216 152 ) ( 48 -216 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 60 -198 152 ) ( 58 -230 152 ) ( 60 -198 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 254 -238 152 ) ( 254 -238 -136 ) ( 256 -270 152 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 40 -200 206 ) ( 40 -232 206 ) ( 232 -200 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 92 +{ +( 192 -520 -130 ) ( 192 -176 -130 ) ( 168 -176 -130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 168 -184 -57 ) ( 192 -184 -57 ) ( 192 -528 -57 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 176 -168 -22 ) ( 176 -512 -22 ) ( 176 -512 -126 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 168 -479 -29 ) ( 192 -479 -29 ) ( 192 -479 -133 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 178 -520 -26 ) ( 178 -176 -26 ) ( 178 -176 -130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 184 -437 -28 ) ( 160 -437 -28 ) ( 160 -437 -132 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 93 +{ +( 264 -256 -136 ) ( 72 -256 -136 ) ( 72 -288 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 72 -480 144 ) ( 264 -480 144 ) ( 264 -480 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 55 -241 152 ) ( 57 -273 152 ) ( 55 -241 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 257 -233 -80 ) ( 255 -265 -80 ) ( 257 -233 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 264 -478 144 ) ( 72 -478 144 ) ( 264 -478 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -126 -464 -130 ) ( 218 -464 -130 ) ( -126 -488 -130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 94 +{ +( 66 -288 208 ) ( 66 -256 208 ) ( 258 -256 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 74 -480 144 ) ( 266 -480 144 ) ( 266 -480 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 57 -241 152 ) ( 59 -273 152 ) ( 57 -241 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 256 -233 -80 ) ( 254 -265 -80 ) ( 256 -233 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 263 -478 144 ) ( 71 -478 144 ) ( 263 -478 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -116 -464 -57 ) ( -116 -488 -57 ) ( 228 -464 -57 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 95 +{ +( 72 -480 144 ) ( 264 -480 144 ) ( 264 -480 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 257 -233 -80 ) ( 255 -265 -80 ) ( 257 -233 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 264 -478 144 ) ( 72 -478 144 ) ( 264 -478 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 218 -464 -130 ) ( -126 -464 -130 ) ( -126 -488 -130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -118 -488 -57 ) ( -118 -464 -57 ) ( 226 -464 -57 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 177 -464 -25 ) ( 177 -488 -25 ) ( 177 -464 -129 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 96 +{ +( 72 -480 144 ) ( 264 -480 144 ) ( 264 -480 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 55 -241 152 ) ( 57 -273 152 ) ( 55 -241 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 264 -478 144 ) ( 72 -478 144 ) ( 264 -478 -144 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 218 -464 -130 ) ( -126 -464 -130 ) ( -126 -488 -130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -118 -488 -57 ) ( -118 -464 -57 ) ( 226 -464 -57 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 135 -496 -28 ) ( 135 -472 -28 ) ( 135 -496 -132 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 97 +{ +( -432 648 -1148 ) ( -464 648 -1148 ) ( -464 368 -1148 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 796 -1101 ) ( -464 796 -1101 ) ( -464 519 -1140 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 312 -1124 ) ( -432 312 -1124 ) ( -432 312 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 652 -1077 ) ( -432 652 -1077 ) ( -464 375 -1116 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 648 -1124 ) ( -464 368 -1124 ) ( -464 368 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 648 -1124 ) ( -464 648 -1124 ) ( -464 648 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 368 -1124 ) ( -432 648 -1124 ) ( -432 648 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 368 -1092 ) ( -464 648 -1092 ) ( -432 648 -1092 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 98 +{ +( -464 656 -1148 ) ( -432 656 -1148 ) ( -432 936 -1148 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 508 -1101 ) ( -432 508 -1101 ) ( -432 785 -1140 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 992 -1124 ) ( -464 992 -1124 ) ( -464 992 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 652 -1077 ) ( -464 652 -1077 ) ( -432 929 -1116 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 656 -1124 ) ( -432 936 -1124 ) ( -432 936 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 656 -1124 ) ( -432 656 -1124 ) ( -432 656 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -464 936 -1124 ) ( -464 656 -1124 ) ( -464 656 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -432 936 -1092 ) ( -432 656 -1092 ) ( -464 656 -1092 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 99 +{ +( -456 666 -1148 ) ( -434 643 -1148 ) ( -226 830 -1148 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -566 568 -1101 ) ( -544 543 -1101 ) ( -338 729 -1140 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -184 867 -1124 ) ( -206 892 -1124 ) ( -206 892 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -438 640 -1077 ) ( -458 664 -1077 ) ( -232 826 -1116 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -434 643 -1124 ) ( -226 830 -1124 ) ( -226 830 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -456 666 -1124 ) ( -434 643 -1124 ) ( -434 643 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -248 854 -1124 ) ( -456 666 -1124 ) ( -456 666 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -226 830 -1092 ) ( -434 643 -1092 ) ( -456 666 -1092 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 100 +{ +( -440 638 -1148 ) ( -462 661 -1148 ) ( -670 474 -1148 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -330 736 -1101 ) ( -352 761 -1101 ) ( -558 575 -1140 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -712 437 -1124 ) ( -690 412 -1124 ) ( -690 412 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -458 664 -1077 ) ( -438 640 -1077 ) ( -664 478 -1116 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -462 661 -1124 ) ( -670 474 -1124 ) ( -670 474 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -440 638 -1124 ) ( -462 661 -1124 ) ( -462 661 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -648 450 -1124 ) ( -440 638 -1124 ) ( -440 638 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -670 474 -1092 ) ( -462 661 -1092 ) ( -440 638 -1092 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 101 +{ +( -459 640 -1148 ) ( -444 668 -1148 ) ( -686 808 -1148 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -331 566 -1101 ) ( -315 594 -1101 ) ( -556 733 -1140 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -734 836 -1124 ) ( -751 808 -1124 ) ( -751 808 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -440 666 -1077 ) ( -456 638 -1077 ) ( -680 804 -1116 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -444 668 -1124 ) ( -686 808 -1124 ) ( -686 808 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -459 640 -1124 ) ( -444 668 -1124 ) ( -444 668 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -702 780 -1124 ) ( -459 640 -1124 ) ( -459 640 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -686 808 -1092 ) ( -444 668 -1092 ) ( -459 640 -1092 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 102 +{ +( -437 664 -1148 ) ( -452 636 -1148 ) ( -210 496 -1148 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -565 738 -1101 ) ( -581 710 -1101 ) ( -340 571 -1140 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -162 468 -1124 ) ( -145 496 -1124 ) ( -145 496 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -456 638 -1077 ) ( -440 666 -1077 ) ( -216 500 -1116 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -452 636 -1124 ) ( -210 496 -1124 ) ( -210 496 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -437 664 -1124 ) ( -452 636 -1124 ) ( -452 636 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -194 524 -1124 ) ( -437 664 -1124 ) ( -437 664 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -210 496 -1092 ) ( -452 636 -1092 ) ( -437 664 -1092 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 103 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -168 464 -1208 0 0 ) ( -176 464 -1208 0 0.062500 ) ( -184 464 -1208 0 0.125000 ) ) +( ( -168 436 -1208 0.218750 0 ) ( -176 436 -1208 0.218750 0.062500 ) ( -184 436 -1208 0.218750 0.125000 ) ) +( ( -168 436 -1180 0.437500 0 ) ( -176 436 -1180 0.437500 0.062500 ) ( -184 436 -1180 0.437500 0.125000 ) ) +( ( -168 436 -1152 0.656250 0 ) ( -176 436 -1152 0.656250 0.062500 ) ( -184 436 -1152 0.656250 0.125000 ) ) +( ( -168 464 -1152 0.875000 0 ) ( -176 464 -1152 0.875000 0.062500 ) ( -184 464 -1152 0.875000 0.125000 ) ) +( ( -168 492 -1152 1.093750 0 ) ( -176 492 -1152 1.093750 0.062500 ) ( -184 492 -1152 1.093750 0.125000 ) ) +( ( -168 492 -1180 1.312500 0 ) ( -176 492 -1180 1.312500 0.062500 ) ( -184 492 -1180 1.312500 0.125000 ) ) +( ( -168 492 -1208 1.531250 0 ) ( -176 492 -1208 1.531250 0.062500 ) ( -184 492 -1208 1.531250 0.125000 ) ) +( ( -168 464 -1208 1.750000 0 ) ( -176 464 -1208 1.750000 0.062500 ) ( -184 464 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 104 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -168 492 -1180 -8.031250 -18 ) ( -168 492 -1208 -8.250000 -18 ) ( -168 464 -1208 -8.250000 -17.781250 ) ) +( ( -168 492 -1152 -7.812500 -18 ) ( -168 464 -1180 -8.031250 -17.781250 ) ( -168 436 -1208 -8.250000 -17.562500 ) ) +( ( -168 464 -1152 -7.812500 -17.781250 ) ( -168 436 -1152 -7.812500 -17.562500 ) ( -168 436 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 105 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -184 464 -1208 -8.250000 -17.781250 ) ( -184 492 -1208 -8.250000 -18 ) ( -184 492 -1180 -8.031250 -18 ) ) +( ( -184 436 -1208 -8.250000 -17.562500 ) ( -184 464 -1180 -8.031250 -17.781250 ) ( -184 492 -1152 -7.812500 -18 ) ) +( ( -184 436 -1180 -8.031250 -17.562500 ) ( -184 436 -1152 -7.812500 -17.562500 ) ( -184 464 -1152 -7.812500 -17.781250 ) ) +) + } + } +// brush 106 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -144 464 -1208 0 0 ) ( -152 464 -1208 0 0.062500 ) ( -160 464 -1208 0 0.125000 ) ) +( ( -144 436 -1208 0.218750 0 ) ( -152 436 -1208 0.218750 0.062500 ) ( -160 436 -1208 0.218750 0.125000 ) ) +( ( -144 436 -1180 0.437500 0 ) ( -152 436 -1180 0.437500 0.062500 ) ( -160 436 -1180 0.437500 0.125000 ) ) +( ( -144 436 -1152 0.656250 0 ) ( -152 436 -1152 0.656250 0.062500 ) ( -160 436 -1152 0.656250 0.125000 ) ) +( ( -144 464 -1152 0.875000 0 ) ( -152 464 -1152 0.875000 0.062500 ) ( -160 464 -1152 0.875000 0.125000 ) ) +( ( -144 492 -1152 1.093750 0 ) ( -152 492 -1152 1.093750 0.062500 ) ( -160 492 -1152 1.093750 0.125000 ) ) +( ( -144 492 -1180 1.312500 0 ) ( -152 492 -1180 1.312500 0.062500 ) ( -160 492 -1180 1.312500 0.125000 ) ) +( ( -144 492 -1208 1.531250 0 ) ( -152 492 -1208 1.531250 0.062500 ) ( -160 492 -1208 1.531250 0.125000 ) ) +( ( -144 464 -1208 1.750000 0 ) ( -152 464 -1208 1.750000 0.062500 ) ( -160 464 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 107 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -144 492 -1180 -8.031250 -18 ) ( -144 492 -1208 -8.250000 -18 ) ( -144 464 -1208 -8.250000 -17.781250 ) ) +( ( -144 492 -1152 -7.812500 -18 ) ( -144 464 -1180 -8.031250 -17.781250 ) ( -144 436 -1208 -8.250000 -17.562500 ) ) +( ( -144 464 -1152 -7.812500 -17.781250 ) ( -144 436 -1152 -7.812500 -17.562500 ) ( -144 436 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 108 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -160 464 -1208 -8.250000 -17.781250 ) ( -160 492 -1208 -8.250000 -18 ) ( -160 492 -1180 -8.031250 -18 ) ) +( ( -160 436 -1208 -8.250000 -17.562500 ) ( -160 464 -1180 -8.031250 -17.781250 ) ( -160 492 -1152 -7.812500 -18 ) ) +( ( -160 436 -1180 -8.031250 -17.562500 ) ( -160 436 -1152 -7.812500 -17.562500 ) ( -160 464 -1152 -7.812500 -17.781250 ) ) +) + } + } +// brush 109 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -196 852 -1208 -8.250000 -17.781250 ) ( -196 880 -1208 -8.250000 -18 ) ( -196 880 -1180 -8.031250 -18 ) ) +( ( -196 824 -1208 -8.250000 -17.562500 ) ( -196 852 -1180 -8.031250 -17.781250 ) ( -196 880 -1152 -7.812500 -18 ) ) +( ( -196 824 -1180 -8.031250 -17.562500 ) ( -196 824 -1152 -7.812500 -17.562500 ) ( -196 852 -1152 -7.812500 -17.781250 ) ) +) + } + } +// brush 110 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -180 880 -1180 -8.031250 -18 ) ( -180 880 -1208 -8.250000 -18 ) ( -180 852 -1208 -8.250000 -17.781250 ) ) +( ( -180 880 -1152 -7.812500 -18 ) ( -180 852 -1180 -8.031250 -17.781250 ) ( -180 824 -1208 -8.250000 -17.562500 ) ) +( ( -180 852 -1152 -7.812500 -17.781250 ) ( -180 824 -1152 -7.812500 -17.562500 ) ( -180 824 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 111 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -180 852 -1208 0 0 ) ( -188 852 -1208 0 0.062500 ) ( -196 852 -1208 0 0.125000 ) ) +( ( -180 824 -1208 0.218750 0 ) ( -188 824 -1208 0.218750 0.062500 ) ( -196 824 -1208 0.218750 0.125000 ) ) +( ( -180 824 -1180 0.437500 0 ) ( -188 824 -1180 0.437500 0.062500 ) ( -196 824 -1180 0.437500 0.125000 ) ) +( ( -180 824 -1152 0.656250 0 ) ( -188 824 -1152 0.656250 0.062500 ) ( -196 824 -1152 0.656250 0.125000 ) ) +( ( -180 852 -1152 0.875000 0 ) ( -188 852 -1152 0.875000 0.062500 ) ( -196 852 -1152 0.875000 0.125000 ) ) +( ( -180 880 -1152 1.093750 0 ) ( -188 880 -1152 1.093750 0.062500 ) ( -196 880 -1152 1.093750 0.125000 ) ) +( ( -180 880 -1180 1.312500 0 ) ( -188 880 -1180 1.312500 0.062500 ) ( -196 880 -1180 1.312500 0.125000 ) ) +( ( -180 880 -1208 1.531250 0 ) ( -188 880 -1208 1.531250 0.062500 ) ( -196 880 -1208 1.531250 0.125000 ) ) +( ( -180 852 -1208 1.750000 0 ) ( -188 852 -1208 1.750000 0.062500 ) ( -196 852 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 112 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -220 852 -1208 -8.250000 -17.781250 ) ( -220 880 -1208 -8.250000 -18 ) ( -220 880 -1180 -8.031250 -18 ) ) +( ( -220 824 -1208 -8.250000 -17.562500 ) ( -220 852 -1180 -8.031250 -17.781250 ) ( -220 880 -1152 -7.812500 -18 ) ) +( ( -220 824 -1180 -8.031250 -17.562500 ) ( -220 824 -1152 -7.812500 -17.562500 ) ( -220 852 -1152 -7.812500 -17.781250 ) ) +) + } + } +// brush 113 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -204 880 -1180 -8.031250 -18 ) ( -204 880 -1208 -8.250000 -18 ) ( -204 852 -1208 -8.250000 -17.781250 ) ) +( ( -204 880 -1152 -7.812500 -18 ) ( -204 852 -1180 -8.031250 -17.781250 ) ( -204 824 -1208 -8.250000 -17.562500 ) ) +( ( -204 852 -1152 -7.812500 -17.781250 ) ( -204 824 -1152 -7.812500 -17.562500 ) ( -204 824 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 114 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -204 852 -1208 0 0 ) ( -212 852 -1208 0 0.062500 ) ( -220 852 -1208 0 0.125000 ) ) +( ( -204 824 -1208 0.218750 0 ) ( -212 824 -1208 0.218750 0.062500 ) ( -220 824 -1208 0.218750 0.125000 ) ) +( ( -204 824 -1180 0.437500 0 ) ( -212 824 -1180 0.437500 0.062500 ) ( -220 824 -1180 0.437500 0.125000 ) ) +( ( -204 824 -1152 0.656250 0 ) ( -212 824 -1152 0.656250 0.062500 ) ( -220 824 -1152 0.656250 0.125000 ) ) +( ( -204 852 -1152 0.875000 0 ) ( -212 852 -1152 0.875000 0.062500 ) ( -220 852 -1152 0.875000 0.125000 ) ) +( ( -204 880 -1152 1.093750 0 ) ( -212 880 -1152 1.093750 0.062500 ) ( -220 880 -1152 1.093750 0.125000 ) ) +( ( -204 880 -1180 1.312500 0 ) ( -212 880 -1180 1.312500 0.062500 ) ( -220 880 -1180 1.312500 0.125000 ) ) +( ( -204 880 -1208 1.531250 0 ) ( -212 880 -1208 1.531250 0.062500 ) ( -220 880 -1208 1.531250 0.125000 ) ) +( ( -204 852 -1208 1.750000 0 ) ( -212 852 -1208 1.750000 0.062500 ) ( -220 852 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 115 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -736 796 -1208 0 0 ) ( -744 796 -1208 0 0.062500 ) ( -752 796 -1208 0 0.125000 ) ) +( ( -736 768 -1208 0.218750 0 ) ( -744 768 -1208 0.218750 0.062500 ) ( -752 768 -1208 0.218750 0.125000 ) ) +( ( -736 768 -1180 0.437500 0 ) ( -744 768 -1180 0.437500 0.062500 ) ( -752 768 -1180 0.437500 0.125000 ) ) +( ( -736 768 -1152 0.656250 0 ) ( -744 768 -1152 0.656250 0.062500 ) ( -752 768 -1152 0.656250 0.125000 ) ) +( ( -736 796 -1152 0.875000 0 ) ( -744 796 -1152 0.875000 0.062500 ) ( -752 796 -1152 0.875000 0.125000 ) ) +( ( -736 824 -1152 1.093750 0 ) ( -744 824 -1152 1.093750 0.062500 ) ( -752 824 -1152 1.093750 0.125000 ) ) +( ( -736 824 -1180 1.312500 0 ) ( -744 824 -1180 1.312500 0.062500 ) ( -752 824 -1180 1.312500 0.125000 ) ) +( ( -736 824 -1208 1.531250 0 ) ( -744 824 -1208 1.531250 0.062500 ) ( -752 824 -1208 1.531250 0.125000 ) ) +( ( -736 796 -1208 1.750000 0 ) ( -744 796 -1208 1.750000 0.062500 ) ( -752 796 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 116 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -736 824 -1180 -8.031250 -18 ) ( -736 824 -1208 -8.250000 -18 ) ( -736 796 -1208 -8.250000 -17.781250 ) ) +( ( -736 824 -1152 -7.812500 -18 ) ( -736 796 -1180 -8.031250 -17.781250 ) ( -736 768 -1208 -8.250000 -17.562500 ) ) +( ( -736 796 -1152 -7.812500 -17.781250 ) ( -736 768 -1152 -7.812500 -17.562500 ) ( -736 768 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 117 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -752 796 -1208 -8.250000 -17.781250 ) ( -752 824 -1208 -8.250000 -18 ) ( -752 824 -1180 -8.031250 -18 ) ) +( ( -752 768 -1208 -8.250000 -17.562500 ) ( -752 796 -1180 -8.031250 -17.781250 ) ( -752 824 -1152 -7.812500 -18 ) ) +( ( -752 768 -1180 -8.031250 -17.562500 ) ( -752 768 -1152 -7.812500 -17.562500 ) ( -752 796 -1152 -7.812500 -17.781250 ) ) +) + } + } +// brush 118 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -712 796 -1208 0 0 ) ( -720 796 -1208 0 0.062500 ) ( -728 796 -1208 0 0.125000 ) ) +( ( -712 768 -1208 0.218750 0 ) ( -720 768 -1208 0.218750 0.062500 ) ( -728 768 -1208 0.218750 0.125000 ) ) +( ( -712 768 -1180 0.437500 0 ) ( -720 768 -1180 0.437500 0.062500 ) ( -728 768 -1180 0.437500 0.125000 ) ) +( ( -712 768 -1152 0.656250 0 ) ( -720 768 -1152 0.656250 0.062500 ) ( -728 768 -1152 0.656250 0.125000 ) ) +( ( -712 796 -1152 0.875000 0 ) ( -720 796 -1152 0.875000 0.062500 ) ( -728 796 -1152 0.875000 0.125000 ) ) +( ( -712 824 -1152 1.093750 0 ) ( -720 824 -1152 1.093750 0.062500 ) ( -728 824 -1152 1.093750 0.125000 ) ) +( ( -712 824 -1180 1.312500 0 ) ( -720 824 -1180 1.312500 0.062500 ) ( -728 824 -1180 1.312500 0.125000 ) ) +( ( -712 824 -1208 1.531250 0 ) ( -720 824 -1208 1.531250 0.062500 ) ( -728 824 -1208 1.531250 0.125000 ) ) +( ( -712 796 -1208 1.750000 0 ) ( -720 796 -1208 1.750000 0.062500 ) ( -728 796 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 119 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -712 824 -1180 -8.031250 -18 ) ( -712 824 -1208 -8.250000 -18 ) ( -712 796 -1208 -8.250000 -17.781250 ) ) +( ( -712 824 -1152 -7.812500 -18 ) ( -712 796 -1180 -8.031250 -17.781250 ) ( -712 768 -1208 -8.250000 -17.562500 ) ) +( ( -712 796 -1152 -7.812500 -17.781250 ) ( -712 768 -1152 -7.812500 -17.562500 ) ( -712 768 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 120 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -728 796 -1208 -8.250000 -17.781250 ) ( -728 824 -1208 -8.250000 -18 ) ( -728 824 -1180 -8.031250 -18 ) ) +( ( -728 768 -1208 -8.250000 -17.562500 ) ( -728 796 -1180 -8.031250 -17.781250 ) ( -728 824 -1152 -7.812500 -18 ) ) +( ( -728 768 -1180 -8.031250 -17.562500 ) ( -728 768 -1152 -7.812500 -17.562500 ) ( -728 796 -1152 -7.812500 -17.781250 ) ) +) + } + } +// brush 121 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -692 408 -1208 -8.250000 -17.781250 ) ( -692 436 -1208 -8.250000 -18 ) ( -692 436 -1180 -8.031250 -18 ) ) +( ( -692 380 -1208 -8.250000 -17.562500 ) ( -692 408 -1180 -8.031250 -17.781250 ) ( -692 436 -1152 -7.812500 -18 ) ) +( ( -692 380 -1180 -8.031250 -17.562500 ) ( -692 380 -1152 -7.812500 -17.562500 ) ( -692 408 -1152 -7.812500 -17.781250 ) ) +) + } + } +// brush 122 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -676 436 -1180 -8.031250 -18 ) ( -676 436 -1208 -8.250000 -18 ) ( -676 408 -1208 -8.250000 -17.781250 ) ) +( ( -676 436 -1152 -7.812500 -18 ) ( -676 408 -1180 -8.031250 -17.781250 ) ( -676 380 -1208 -8.250000 -17.562500 ) ) +( ( -676 408 -1152 -7.812500 -17.781250 ) ( -676 380 -1152 -7.812500 -17.562500 ) ( -676 380 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 123 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -676 408 -1208 0 0 ) ( -684 408 -1208 0 0.062500 ) ( -692 408 -1208 0 0.125000 ) ) +( ( -676 380 -1208 0.218750 0 ) ( -684 380 -1208 0.218750 0.062500 ) ( -692 380 -1208 0.218750 0.125000 ) ) +( ( -676 380 -1180 0.437500 0 ) ( -684 380 -1180 0.437500 0.062500 ) ( -692 380 -1180 0.437500 0.125000 ) ) +( ( -676 380 -1152 0.656250 0 ) ( -684 380 -1152 0.656250 0.062500 ) ( -692 380 -1152 0.656250 0.125000 ) ) +( ( -676 408 -1152 0.875000 0 ) ( -684 408 -1152 0.875000 0.062500 ) ( -692 408 -1152 0.875000 0.125000 ) ) +( ( -676 436 -1152 1.093750 0 ) ( -684 436 -1152 1.093750 0.062500 ) ( -692 436 -1152 1.093750 0.125000 ) ) +( ( -676 436 -1180 1.312500 0 ) ( -684 436 -1180 1.312500 0.062500 ) ( -692 436 -1180 1.312500 0.125000 ) ) +( ( -676 436 -1208 1.531250 0 ) ( -684 436 -1208 1.531250 0.062500 ) ( -692 436 -1208 1.531250 0.125000 ) ) +( ( -676 408 -1208 1.750000 0 ) ( -684 408 -1208 1.750000 0.062500 ) ( -692 408 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 124 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -716 408 -1208 -8.250000 -17.781250 ) ( -716 436 -1208 -8.250000 -18 ) ( -716 436 -1180 -8.031250 -18 ) ) +( ( -716 380 -1208 -8.250000 -17.562500 ) ( -716 408 -1180 -8.031250 -17.781250 ) ( -716 436 -1152 -7.812500 -18 ) ) +( ( -716 380 -1180 -8.031250 -17.562500 ) ( -716 380 -1152 -7.812500 -17.562500 ) ( -716 408 -1152 -7.812500 -17.781250 ) ) +) + } + } +// brush 125 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -700 436 -1180 -8.031250 -18 ) ( -700 436 -1208 -8.250000 -18 ) ( -700 408 -1208 -8.250000 -17.781250 ) ) +( ( -700 436 -1152 -7.812500 -18 ) ( -700 408 -1180 -8.031250 -17.781250 ) ( -700 380 -1208 -8.250000 -17.562500 ) ) +( ( -700 408 -1152 -7.812500 -17.781250 ) ( -700 380 -1152 -7.812500 -17.562500 ) ( -700 380 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 126 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -700 408 -1208 0 0 ) ( -708 408 -1208 0 0.062500 ) ( -716 408 -1208 0 0.125000 ) ) +( ( -700 380 -1208 0.218750 0 ) ( -708 380 -1208 0.218750 0.062500 ) ( -716 380 -1208 0.218750 0.125000 ) ) +( ( -700 380 -1180 0.437500 0 ) ( -708 380 -1180 0.437500 0.062500 ) ( -716 380 -1180 0.437500 0.125000 ) ) +( ( -700 380 -1152 0.656250 0 ) ( -708 380 -1152 0.656250 0.062500 ) ( -716 380 -1152 0.656250 0.125000 ) ) +( ( -700 408 -1152 0.875000 0 ) ( -708 408 -1152 0.875000 0.062500 ) ( -716 408 -1152 0.875000 0.125000 ) ) +( ( -700 436 -1152 1.093750 0 ) ( -708 436 -1152 1.093750 0.062500 ) ( -716 436 -1152 1.093750 0.125000 ) ) +( ( -700 436 -1180 1.312500 0 ) ( -708 436 -1180 1.312500 0.062500 ) ( -716 436 -1180 1.312500 0.125000 ) ) +( ( -700 436 -1208 1.531250 0 ) ( -708 436 -1208 1.531250 0.062500 ) ( -716 436 -1208 1.531250 0.125000 ) ) +( ( -700 408 -1208 1.750000 0 ) ( -708 408 -1208 1.750000 0.062500 ) ( -716 408 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 127 +{ +( -112 896 -556 ) ( -800 896 -556 ) ( -800 336 -556 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -792 336 -492 ) ( -792 896 -492 ) ( -104 896 -492 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -808 456 -548 ) ( -120 456 -548 ) ( -120 456 -588 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -128 336 -548 ) ( -128 896 -548 ) ( -128 896 -588 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -112 848 -548 ) ( -800 848 -548 ) ( -800 848 -588 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -784 896 -548 ) ( -784 336 -548 ) ( -784 336 -588 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 128 +{ +( -48 960 -556 ) ( -736 960 -556 ) ( -736 400 -556 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -728 400 -492 ) ( -728 960 -492 ) ( -40 960 -492 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -736 848 -548 ) ( -48 848 -548 ) ( -48 848 -588 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -192 400 -548 ) ( -192 960 -548 ) ( -192 960 -588 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -48 912 -548 ) ( -736 912 -548 ) ( -736 912 -588 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -720 960 -548 ) ( -720 400 -548 ) ( -720 400 -588 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 129 +{ +( -864 344 -556 ) ( -176 344 -556 ) ( -176 904 -556 ) desktop/blackdrawer 0 0 -180 0.500000 0.500000 0 0 0 +( -184 904 -492 ) ( -184 344 -492 ) ( -872 344 -492 ) desktop/blackdrawer 0 0 -180 0.500000 0.500000 0 0 0 +( -176 456 -548 ) ( -864 456 -548 ) ( -864 456 -588 ) desktop/blackdrawer 0 0 -180 0.500000 -0.500000 0 0 0 +( -712 904 -548 ) ( -712 344 -548 ) ( -712 344 -588 ) desktop/blackdrawer 0 0 -180 0.500000 -0.500000 0 0 0 +( -856 392 -548 ) ( -168 392 -548 ) ( -168 392 -588 ) desktop/blackdrawer 0 0 -180 0.500000 -0.500000 0 0 0 +( -184 344 -548 ) ( -184 904 -548 ) ( -184 904 -588 ) desktop/blackdrawer 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 130 +{ +( -864 344 -492 ) ( -176 344 -492 ) ( -176 904 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -184 904 -460 ) ( -184 344 -460 ) ( -872 344 -460 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -176 456 -452 ) ( -864 456 -452 ) ( -864 456 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -712 904 -452 ) ( -712 344 -452 ) ( -712 344 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -856 392 -452 ) ( -168 392 -452 ) ( -168 392 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -184 344 -452 ) ( -184 904 -452 ) ( -184 904 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 131 +{ +( -48 960 -492 ) ( -736 960 -492 ) ( -736 400 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -728 400 -460 ) ( -728 960 -460 ) ( -40 960 -460 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -736 848 -452 ) ( -48 848 -452 ) ( -48 848 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -192 400 -452 ) ( -192 960 -452 ) ( -192 960 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -48 912 -452 ) ( -736 912 -452 ) ( -736 912 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -720 960 -452 ) ( -720 400 -452 ) ( -720 400 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 132 +{ +( -112 896 -492 ) ( -800 896 -492 ) ( -800 336 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -792 336 -460 ) ( -792 896 -460 ) ( -104 896 -460 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -808 456 -452 ) ( -120 456 -452 ) ( -120 456 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -128 336 -452 ) ( -128 896 -452 ) ( -128 896 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -112 848 -452 ) ( -800 848 -452 ) ( -800 848 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +( -784 896 -452 ) ( -784 336 -452 ) ( -784 336 -492 ) desktop/chair 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 133 +{ +( -800 976 -428 ) ( -112 976 -428 ) ( -112 976 132 ) desktop/blackdrawer 0 -80 -180 0.500000 -0.500000 0 0 0 +( -120 912 132 ) ( -120 912 -428 ) ( -808 912 -428 ) desktop/blackdrawer 0 -80 -180 0.500000 -0.500000 0 0 0 +( -96 968 -252 ) ( -784 968 -252 ) ( -784 1008 -252 ) desktop/blackdrawer 0 16 -180 0.500000 -0.500000 0 0 0 +( -784 968 132 ) ( -784 968 -428 ) ( -784 1008 -428 ) desktop/blackdrawer 80 16 90 0.500000 -0.500000 0 0 0 +( -800 968 -380 ) ( -112 968 -380 ) ( -112 1008 -380 ) desktop/blackdrawer 0 16 -180 0.500000 -0.500000 0 0 0 +( -128 968 -428 ) ( -128 968 132 ) ( -128 1008 132 ) desktop/blackdrawer 80 16 90 0.500000 -0.500000 0 0 0 +} +// brush 134 +{ +( -864 976 -492 ) ( -176 976 -492 ) ( -176 976 68 ) desktop/blackdrawer 0 -80 -180 0.500000 -0.500000 0 0 0 +( -184 912 68 ) ( -184 912 -492 ) ( -872 912 -492 ) desktop/blackdrawer 0 -80 -180 0.500000 -0.500000 0 0 0 +( -176 968 -380 ) ( -864 968 -380 ) ( -864 1008 -380 ) desktop/blackdrawer 0 16 -180 0.500000 -0.500000 0 0 0 +( -720 968 68 ) ( -720 968 -492 ) ( -720 1008 -492 ) desktop/blackdrawer 80 16 90 0.500000 -0.500000 0 0 0 +( -864 968 -444 ) ( -176 968 -444 ) ( -176 1008 -444 ) desktop/blackdrawer 0 16 -180 0.500000 -0.500000 0 0 0 +( -192 968 -492 ) ( -192 968 68 ) ( -192 1008 68 ) desktop/blackdrawer 80 16 90 0.500000 -0.500000 0 0 0 +} +// brush 135 +{ +( -800 912 -428 ) ( -112 912 -428 ) ( -112 912 132 ) desktop/chair 0 -80 -180 0.500000 -0.500000 0 0 0 +( -120 880 132 ) ( -120 880 -428 ) ( -808 880 -428 ) desktop/chair 0 -80 -180 0.500000 -0.500000 0 0 0 +( -88 872 -252 ) ( -776 872 -252 ) ( -776 912 -252 ) desktop/chair 0 16 -180 0.500000 -0.500000 0 0 0 +( -784 872 132 ) ( -784 872 -428 ) ( -784 912 -428 ) desktop/chair 80 16 90 0.500000 -0.500000 0 0 0 +( -800 872 -380 ) ( -112 872 -380 ) ( -112 912 -380 ) desktop/chair 0 16 -180 0.500000 -0.500000 0 0 0 +( -128 872 -428 ) ( -128 872 132 ) ( -128 912 132 ) desktop/chair 80 16 90 0.500000 -0.500000 0 0 0 +} +// brush 136 +{ +( -88 912 124 ) ( -776 912 124 ) ( -776 912 -436 ) desktop/chair 0 -80 -180 0.500000 -0.500000 0 0 0 +( -768 880 -436 ) ( -768 880 124 ) ( -80 880 124 ) desktop/chair 0 -80 -180 0.500000 -0.500000 0 0 0 +( -768 872 -252 ) ( -80 872 -252 ) ( -80 912 -252 ) desktop/chair 0 16 -180 0.500000 -0.500000 0 0 0 +( -296 872 -436 ) ( -296 872 124 ) ( -296 912 124 ) desktop/chair 80 16 90 0.500000 -0.500000 0 0 0 +( -100 872 222 ) ( -788 872 222 ) ( -788 912 222 ) desktop/chair 0 16 -180 0.500000 -0.500000 0 0 0 +( -616 872 116 ) ( -616 872 -444 ) ( -616 912 -444 ) desktop/chair 80 16 90 0.500000 -0.500000 0 0 0 +} +// brush 137 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -192 880 -380 -11.875000 -34.250000 ) ( -160 880 -380 -11.875000 -34.750000 ) ( -160 880 -380 -11.875000 -34.750000 ) ) +( ( -192 880 -444 -10.875000 -34.250000 ) ( -160 880 -412 -11.375000 -34.750000 ) ( -128 880 -380 -11.875000 -35.250000 ) ) +( ( -192 880 -444 -10.875000 -34.250000 ) ( -128 880 -444 -10.875000 -35.250000 ) ( -128 880 -380 -11.875000 -35.250000 ) ) +) + } + } +// brush 138 +{ +( -864 912 -492 ) ( -176 912 -492 ) ( -176 912 68 ) desktop/chair 0 -80 -180 0.500000 -0.500000 0 0 0 +( -184 880 68 ) ( -184 880 -492 ) ( -872 880 -492 ) desktop/chair 0 -80 -180 0.500000 -0.500000 0 0 0 +( -176 872 -380 ) ( -864 872 -380 ) ( -864 912 -380 ) desktop/chair 0 16 -180 0.500000 -0.500000 0 0 0 +( -720 872 68 ) ( -720 872 -492 ) ( -720 912 -492 ) desktop/chair 80 16 90 0.500000 -0.500000 0 0 0 +( -864 872 -444 ) ( -176 872 -444 ) ( -176 912 -444 ) desktop/chair 0 16 -180 0.500000 -0.500000 0 0 0 +( -192 872 -492 ) ( -192 872 68 ) ( -192 912 68 ) desktop/chair 80 16 90 0.500000 -0.500000 0 0 0 +} +// brush 139 + { + patchDef2 + { + desktop/chair + ( 9 3 0 0 0 ) +( +( ( -160 944 -380 0 0 ) ( -160 960 -380 0 0.750000 ) ( -160 976 -380 0 1.500000 ) ) +( ( -128 944 -380 0.500000 0 ) ( -128 960 -380 0.500000 0.750000 ) ( -128 976 -380 0.500000 1.500000 ) ) +( ( -128 944 -380 0.500000 0 ) ( -128 960 -380 0.500000 0.750000 ) ( -128 976 -380 0.500000 1.500000 ) ) +( ( -128 944 -444 1.500000 0 ) ( -128 960 -444 1.500000 0.750000 ) ( -128 976 -444 1.500000 1.500000 ) ) +( ( -192 944 -444 2.500000 0 ) ( -192 960 -444 2.500000 0.750000 ) ( -192 976 -444 2.500000 1.500000 ) ) +( ( -192 944 -444 2.500000 0 ) ( -192 960 -444 2.500000 0.750000 ) ( -192 976 -444 2.500000 1.500000 ) ) +( ( -192 944 -380 3.500000 0 ) ( -192 960 -380 3.500000 0.750000 ) ( -192 976 -380 3.500000 1.500000 ) ) +( ( -160 944 -380 4 0 ) ( -160 960 -380 4 0.750000 ) ( -160 976 -380 4 1.500000 ) ) +( ( -160 944 -380 4 0 ) ( -160 960 -380 4 0.750000 ) ( -160 976 -380 4 1.500000 ) ) +) + } + } +// brush 140 + { + patchDef2 + { + desktop/chair + ( 9 3 0 0 0 ) +( +( ( -720 944 -412 0 0 ) ( -720 960 -412 0 0.750000 ) ( -720 976 -412 0 1.500000 ) ) +( ( -720 944 -444 0.500000 0 ) ( -720 960 -444 0.500000 0.750000 ) ( -720 976 -444 0.500000 1.500000 ) ) +( ( -720 944 -444 0.500000 0 ) ( -720 960 -444 0.500000 0.750000 ) ( -720 976 -444 0.500000 1.500000 ) ) +( ( -784 944 -444 1.500000 0 ) ( -784 960 -444 1.500000 0.750000 ) ( -784 976 -444 1.500000 1.500000 ) ) +( ( -784 944 -380 2.500000 0 ) ( -784 960 -380 2.500000 0.750000 ) ( -784 976 -380 2.500000 1.500000 ) ) +( ( -784 944 -380 2.500000 0 ) ( -784 960 -380 2.500000 0.750000 ) ( -784 976 -380 2.500000 1.500000 ) ) +( ( -720 944 -380 3.500000 0 ) ( -720 960 -380 3.500000 0.750000 ) ( -720 976 -380 3.500000 1.500000 ) ) +( ( -720 944 -412 4 0 ) ( -720 960 -412 4 0.750000 ) ( -720 976 -412 4 1.500000 ) ) +( ( -720 944 -412 4 0 ) ( -720 960 -412 4 0.750000 ) ( -720 976 -412 4 1.500000 ) ) +) + } + } +// brush 141 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -720 880 -380 -11.875000 -34.250000 ) ( -720 880 -412 -11.875000 -34.750000 ) ( -720 880 -412 -11.875000 -34.750000 ) ) +( ( -784 880 -380 -10.875000 -34.250000 ) ( -752 880 -412 -11.375000 -34.750000 ) ( -720 880 -444 -11.875000 -35.250000 ) ) +( ( -784 880 -380 -10.875000 -34.250000 ) ( -784 880 -444 -10.875000 -35.250000 ) ( -720 880 -444 -11.875000 -35.250000 ) ) +) + } + } +// brush 142 +{ +( -88 976 124 ) ( -776 976 124 ) ( -776 976 -436 ) desktop/blackdrawer 0 80 0 0.500000 -0.500000 0 0 0 +( -768 912 -436 ) ( -768 912 124 ) ( -80 912 124 ) desktop/blackdrawer 0 80 0 0.500000 -0.500000 0 0 0 +( -776 968 -252 ) ( -88 968 -252 ) ( -88 1008 -252 ) desktop/blackdrawer 0 16 0 0.500000 0.500000 0 0 0 +( -296 968 -436 ) ( -296 968 124 ) ( -296 1008 124 ) desktop/blackdrawer -80 16 -90 0.500000 0.500000 0 0 0 +( -90 968 222 ) ( -778 968 222 ) ( -778 1008 222 ) desktop/blackdrawer 0 16 0 0.500000 0.500000 0 0 0 +( -616 968 124 ) ( -616 968 -436 ) ( -616 1008 -436 ) desktop/blackdrawer -80 16 -90 0.500000 0.500000 0 0 0 +} +// brush 143 +{ +( -416 976 -510 ) ( -480 976 -510 ) ( -480 928 -510 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -480 928 -444 ) ( -480 976 -444 ) ( -416 976 -444 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -480 924 -444 ) ( -416 924 -444 ) ( -416 924 -532 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -416 928 -444 ) ( -416 976 -444 ) ( -416 976 -532 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -416 959 -444 ) ( -480 959 -444 ) ( -480 959 -532 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -480 976 -444 ) ( -480 928 -444 ) ( -480 928 -532 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 144 +{ +( -416 907 -557 ) ( -480 907 -557 ) ( -480 875 -521 ) desktop/blackdrawer 0 40 0 0.500000 -0.372040 0 0 0 +( -480 905 -527 ) ( -416 905 -527 ) ( -416 839 -586 ) desktop/blackdrawer 0 79 0 0.500000 0.371704 0 0 0 +( -416 917 -483 ) ( -416 949 -519 ) ( -416 883 -578 ) desktop/blackdrawer -61 -27 -47 0.500113 0.499524 0 0 0 +( -416 949 -519 ) ( -480 949 -519 ) ( -480 883 -578 ) desktop/blackdrawer 0 50 0 0.500000 0.371338 0 0 0 +( -480 949 -519 ) ( -480 917 -483 ) ( -480 851 -542 ) desktop/blackdrawer -61 -27 -47 0.500113 0.499524 0 0 0 +( -480 976 -510 ) ( -416 976 -510 ) ( -480 928 -510 ) desktop/blackdrawer -61 -27 -47 0.500113 0.499524 0 0 0 +} +// brush 145 +{ +( 384 8192 8192 ) ( 384 -8192 8192 ) ( 384 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 400 -8192 8192 ) ( 400 8192 8192 ) ( 400 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 736 8192 ) ( 8192 736 8192 ) ( -8192 736 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1456 8192 ) ( -8192 1456 8192 ) ( -8192 1456 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1032 ) ( 8192 8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -864 ) ( 8192 -8192 -864 ) ( -8192 -8192 -864 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 146 +{ +( 384 8192 8192 ) ( 384 -8192 8192 ) ( 384 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 2000 -8192 8192 ) ( 2000 8192 8192 ) ( 2000 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1456 8192 ) ( 8192 1456 8192 ) ( -8192 1456 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1472 8192 ) ( -8192 1472 8192 ) ( -8192 1472 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1032 ) ( 8192 8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -864 ) ( 8192 -8192 -864 ) ( -8192 -8192 -864 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 147 +{ +( 384 8192 8192 ) ( 384 -8192 8192 ) ( 384 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 2000 -8192 8192 ) ( 2000 8192 8192 ) ( 2000 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 720 8192 ) ( 8192 720 8192 ) ( -8192 720 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1472 8192 ) ( -8192 1472 8192 ) ( -8192 1472 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1048 ) ( 8192 8192 -1048 ) ( -8192 -8192 -1048 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1032 ) ( 8192 -8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 148 +{ +( 1984 8192 8192 ) ( 1984 -8192 8192 ) ( 1984 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 2000 -8192 8192 ) ( 2000 8192 8192 ) ( 2000 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 736 8192 ) ( 8192 736 8192 ) ( -8192 736 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1456 8192 ) ( -8192 1456 8192 ) ( -8192 1456 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1032 ) ( 8192 8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -864 ) ( 8192 -8192 -864 ) ( -8192 -8192 -864 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 149 +{ +( 384 8192 8192 ) ( 384 -8192 8192 ) ( 384 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 2000 -8192 8192 ) ( 2000 8192 8192 ) ( 2000 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 720 8192 ) ( 8192 720 8192 ) ( -8192 720 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 736 8192 ) ( -8192 736 8192 ) ( -8192 736 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1032 ) ( 8192 8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -864 ) ( 8192 -8192 -864 ) ( -8192 -8192 -864 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 150 +{ +( -2168 8192 8192 ) ( -2168 -8192 8192 ) ( -2168 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( -2160 -8192 8192 ) ( -2160 8192 8192 ) ( -2160 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1424 8192 ) ( 8192 -1424 8192 ) ( -8192 -1424 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 2656 8192 ) ( -8192 2656 8192 ) ( -8192 2656 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1216 ) ( 8192 8192 -1216 ) ( -8192 -8192 -1216 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 1608 ) ( 8192 -8192 1608 ) ( -8192 -8192 1608 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 151 +{ +( -2160 8192 8192 ) ( -2160 -8192 8192 ) ( -2160 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 2120 -8192 8192 ) ( 2120 8192 8192 ) ( 2120 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( -8192 2648 8192 ) ( 8192 2648 8192 ) ( -8192 2648 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 2656 8192 ) ( -8192 2656 8192 ) ( -8192 2656 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1216 ) ( 8192 8192 -1216 ) ( -8192 -8192 -1216 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 1608 ) ( 8192 -8192 1608 ) ( -8192 -8192 1608 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 152 +{ +( 2120 8192 8192 ) ( 2120 -8192 8192 ) ( 2120 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 2128 -8192 8192 ) ( 2128 8192 8192 ) ( 2128 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1424 8192 ) ( 8192 -1424 8192 ) ( -8192 -1424 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 2656 8192 ) ( -8192 2656 8192 ) ( -8192 2656 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1216 ) ( 8192 8192 -1216 ) ( -8192 -8192 -1216 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 1608 ) ( 8192 -8192 1608 ) ( -8192 -8192 1608 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 153 +{ +( -2168 8192 8192 ) ( -2168 -8192 8192 ) ( -2168 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 2128 -8192 8192 ) ( 2128 8192 8192 ) ( 2128 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1432 8192 ) ( 8192 -1432 8192 ) ( -8192 -1432 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1424 8192 ) ( -8192 -1424 8192 ) ( -8192 -1424 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1216 ) ( 8192 8192 -1216 ) ( -8192 -8192 -1216 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 1608 ) ( 8192 -8192 1608 ) ( -8192 -8192 1608 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 154 +{ +( -2168 8192 8192 ) ( -2168 -8192 8192 ) ( -2168 8192 -8192 ) desktop/carpet 0 0 0 0.500000 0.500000 0 0 0 +( 2128 -8192 8192 ) ( 2128 8192 8192 ) ( 2128 8192 -8192 ) desktop/carpet 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1424 8192 ) ( 8192 -1424 8192 ) ( -8192 -1424 -8192 ) desktop/carpet 0 0 0 0.500000 0.500000 0 0 0 +( 8192 2656 8192 ) ( -8192 2656 8192 ) ( -8192 2656 -8192 ) desktop/carpet 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1216 ) ( 8192 8192 -1216 ) ( -8192 -8192 -1216 ) desktop/carpet 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1208 ) ( 8192 -8192 -1208 ) ( -8192 -8192 -1208 ) desktop/carpet 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 155 +{ +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 206 ) ( 8192 8192 206 ) ( -8192 -8192 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 749 -8161 8192 ) ( -272 8190 8192 ) ( -272 8190 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 583 8171 8192 ) ( -438 -8180 8192 ) ( -438 -8180 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 156 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 8 ) ( 8192 -8192 8 ) ( -8192 -8192 8 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 157 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 336 -8192 8192 ) ( 336 8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 688 ) ( 8192 -8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 158 +{ +( -8192 -136 8192 ) ( 8192 -136 8192 ) ( -8192 -136 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 -7808 2544 ) ( 8191 8090 -1409 ) ( -8192 8087 -1423 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1911 7973 8192 ) ( 2572 -7785 8192 ) ( 2572 -7785 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1196 -8176 8192 ) ( 3288 7581 8192 ) ( 3288 7581 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7809 2539 ) ( 8192 8088 -1418 ) ( -8192 8088 -1418 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 159 +{ +( -8192 -136 8192 ) ( 8192 -136 8192 ) ( -8192 -136 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1196 -8176 8192 ) ( 3288 7581 8192 ) ( 3288 7581 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1911 7973 8192 ) ( 2572 -7785 8192 ) ( 2572 -7785 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 7925 2075 ) ( 8191 -7985 -1832 ) ( -8192 -7980 -1851 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1912 7973 8192 ) ( 2573 -7784 8192 ) ( 2573 -7784 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 160 +{ +( 384 8192 8192 ) ( 384 -8192 8192 ) ( 384 8192 -8192 ) desktop/myscreen 0 32 0 -0.031250 2.250000 0 0 0 +( 1104 -8192 8192 ) ( 1104 8192 8192 ) ( 1104 8192 -8192 ) desktop/myscreen 0 32 0 -0.031250 2.250000 0 0 0 +( -8192 -144 8192 ) ( 8192 -144 8192 ) ( -8192 -144 -8192 ) desktop/myscreen 136 32 0 -2.812500 2.250000 0 0 0 +( 8192 -136 8192 ) ( -8192 -136 8192 ) ( -8192 -136 -8192 ) desktop/myscreen 136 32 0 -2.812500 2.250000 0 0 0 +( 8192 -8192 72 ) ( 8192 8192 72 ) ( -8192 -8192 72 ) desktop/myscreen 136 0 0 -2.812500 0.031250 0 0 0 +( 8192 8192 648 ) ( 8192 -8192 648 ) ( -8192 -8192 648 ) desktop/myscreen 136 0 0 -2.812500 0.031250 0 0 0 +} +// brush 161 +{ +( 352 8192 8192 ) ( 352 -8192 8192 ) ( 352 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1136 -8192 8192 ) ( 1136 8192 8192 ) ( 1136 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -166 8192 ) ( -8192 -166 8192 ) ( -8192 -166 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -56 ) ( 8192 8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 0 ) ( 8192 -8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 162 +{ +( 464 8192 8192 ) ( 464 -8192 8192 ) ( 464 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 984 -8192 8192 ) ( 984 8192 8192 ) ( 984 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -144 8192 ) ( -8192 -144 8192 ) ( -8192 -144 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -120 ) ( 8192 -8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 163 +{ +( 416 8192 8192 ) ( 416 -8192 8192 ) ( 416 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1224 -8192 8192 ) ( 1224 8192 8192 ) ( 1224 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 24 8192 ) ( 8192 24 8192 ) ( -8192 24 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 360 8192 ) ( -8192 360 8192 ) ( -8192 360 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -112 ) ( 8192 -8192 -112 ) ( -8192 -8192 -112 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 164 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/Keybesc 113 -17 180 0.095893 0.101763 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 492 -8191 8261 ) ( 492 8191 8261 ) ( 1853 8191 -8065 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1505 8191 8136 ) ( 1505 -8191 8136 ) ( 823 -8191 -8233 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 165 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F1 84 -5 180 0.190898 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 421 -8191 8255 ) ( 421 8191 8255 ) ( 1781 8191 -8071 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1433 8191 8139 ) ( 1433 -8191 8139 ) ( 751 -8191 -8230 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 166 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F2 2 -5 180 0.188531 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 389 -8191 8252 ) ( 389 8191 8252 ) ( 1750 8191 -8074 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1401 8191 8140 ) ( 1401 -8191 8140 ) ( 719 -8191 -8229 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 167 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F3 41 -5 180 0.189517 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 357 -8191 8250 ) ( 357 8191 8250 ) ( 1718 8191 -8077 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1369 8191 8142 ) ( 1369 -8191 8142 ) ( 687 -8191 -8227 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 168 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F4 -34 -5 180 0.190813 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 325 -8191 8247 ) ( 325 8191 8247 ) ( 1686 8191 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1337 8191 8143 ) ( 1337 -8191 8143 ) ( 655 -8191 -8226 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 169 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/F5 60 58 0 -0.234493 0.226945 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F5 24 3 180 0.188937 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 278 -8191 8243 ) ( 278 8191 8243 ) ( 1638 8191 -8083 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1289 8191 8145 ) ( 1289 -8191 8145 ) ( 607 -8191 -8224 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 170 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F6 40 -5 180 0.186584 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 246 -8191 8240 ) ( 246 8191 8240 ) ( 1607 8191 -8086 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1257 8191 8146 ) ( 1257 -8191 8146 ) ( 575 -8191 -8223 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 171 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F7 -27 -5 180 0.187561 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 214 -8191 8238 ) ( 214 8191 8238 ) ( 1575 8191 -8089 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1225 8191 8148 ) ( 1225 -8191 8148 ) ( 543 -8191 -8221 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 172 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F8 31 -13 180 0.188858 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 182 -8191 8235 ) ( 182 8191 8235 ) ( 1543 8191 -8091 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1193 8191 8149 ) ( 1193 -8191 8149 ) ( 511 -8191 -8220 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 173 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F9 74 -5 180 0.186992 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 135 -8191 8231 ) ( 135 8191 8231 ) ( 1495 8191 -8095 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1145 8191 8151 ) ( 1145 -8191 8151 ) ( 463 -8191 -8218 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 174 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F10 90 -5 180 0.184310 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 103 -8191 8229 ) ( 103 8191 8229 ) ( 1464 8191 -8098 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1113 8191 8152 ) ( 1113 -8191 8152 ) ( 431 -8191 -8217 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 175 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/F11 56 -5 180 0.189489 0.203526 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 71 -8191 8226 ) ( 71 8191 8226 ) ( 1432 8191 -8101 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1082 8191 8154 ) ( 1082 -8191 8154 ) ( 399 -8191 -8215 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 176 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 39 -8191 8223 ) ( 39 8191 8223 ) ( 1400 8191 -8103 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1050 8191 8155 ) ( 1050 -8191 8155 ) ( 368 -8191 -8214 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 177 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -71 -8191 8214 ) ( -71 8191 8214 ) ( 1289 8191 -8112 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 938 8191 8160 ) ( 938 -8191 8160 ) ( 256 -8191 -8209 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 178 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -39 -8191 8217 ) ( -39 8191 8217 ) ( 1321 8191 -8110 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 970 8191 8158 ) ( 970 -8191 8158 ) ( 288 -8191 -8211 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 179 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7 -8191 8219 ) ( -7 8191 8219 ) ( 1352 8191 -8107 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1002 8191 8157 ) ( 1002 -8191 8157 ) ( 320 -8191 -8212 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 180 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/Kplus 74 59 180 0.187958 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 111 -8191 8229 ) ( 111 8191 8229 ) ( 1471 8191 -8097 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1121 8191 8152 ) ( 1121 -8191 8152 ) ( 439 -8191 -8217 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 181 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/Kminus 138 59 180 0.186671 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 143 -8191 8232 ) ( 143 8191 8232 ) ( 1503 8191 -8095 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1153 8191 8151 ) ( 1153 -8191 8151 ) ( 471 -8191 -8218 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 182 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K0 -11 59 180 0.189511 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 174 -8191 8234 ) ( 174 8191 8234 ) ( 1535 8191 -8092 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1185 8191 8149 ) ( 1185 -8191 8149 ) ( 503 -8191 -8220 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 183 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K9 62 59 180 0.187882 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 206 -8191 8237 ) ( 206 8191 8237 ) ( 1567 8191 -8089 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1217 8191 8148 ) ( 1217 -8191 8148 ) ( 535 -8191 -8221 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 184 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K8 19 59 180 0.186586 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 238 -8191 8240 ) ( 238 8191 8240 ) ( 1599 8191 -8087 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1249 8191 8147 ) ( 1249 -8191 8147 ) ( 567 -8191 -8222 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 185 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K7 112 59 180 0.189598 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 270 -8191 8242 ) ( 270 8191 8242 ) ( 1630 8191 -8084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1281 8191 8145 ) ( 1281 -8191 8145 ) ( 599 -8191 -8224 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 186 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K6 77 59 180 0.187970 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 302 -8191 8245 ) ( 302 8191 8245 ) ( 1662 8191 -8081 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1313 8191 8144 ) ( 1313 -8191 8144 ) ( 631 -8191 -8225 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 187 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K5 45 59 180 0.190493 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 333 -8191 8248 ) ( 333 8191 8248 ) ( 1694 8191 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1345 8191 8143 ) ( 1345 -8191 8143 ) ( 663 -8191 -8226 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 188 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K4 -9 59 180 0.189508 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 365 -8191 8250 ) ( 365 8191 8250 ) ( 1726 8191 -8076 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1377 8191 8141 ) ( 1377 -8191 8141 ) ( 695 -8191 -8228 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 189 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K3 73 59 180 0.191880 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 397 -8191 8253 ) ( 397 8191 8253 ) ( 1757 8191 -8073 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1409 8191 8140 ) ( 1409 -8191 8140 ) ( 727 -8191 -8229 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 190 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K2 146 59 180 0.190578 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 429 -8191 8256 ) ( 429 8191 8256 ) ( 1789 8191 -8071 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1441 8191 8139 ) ( 1441 -8191 8139 ) ( 759 -8191 -8230 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 191 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/K1 93 59 180 0.193414 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 460 -8191 8258 ) ( 460 8191 8258 ) ( 1821 8191 -8068 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1473 8191 8137 ) ( 1473 -8191 8137 ) ( 791 -8191 -8232 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 192 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/Topleftkey 52 59 180 0.191785 0.211339 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 492 -8191 8261 ) ( 492 8191 8261 ) ( 1853 8191 -8065 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1505 8191 8136 ) ( 1505 -8191 8136 ) ( 823 -8191 -8233 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 193 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 79 -8191 8227 ) ( 79 8191 8227 ) ( 1440 8191 -8100 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1058 8191 8155 ) ( 1058 -8191 8155 ) ( 376 -8191 -8214 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 194 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/Q 110 123 180 0.293417 0.311340 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 452 -8191 8258 ) ( 452 8191 8258 ) ( 1813 8191 -8069 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1465 8191 8138 ) ( 1465 -8191 8138 ) ( 783 -8191 -8231 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 195 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/W 164 115 180 0.290898 0.311340 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 421 -8191 8255 ) ( 421 8191 8255 ) ( 1781 8191 -8071 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1433 8191 8139 ) ( 1433 -8191 8139 ) ( 751 -8191 -8230 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 196 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/E 82 115 180 0.288531 0.311340 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 389 -8191 8252 ) ( 389 8191 8252 ) ( 1750 8191 -8074 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1401 8191 8140 ) ( 1401 -8191 8140 ) ( 719 -8191 -8229 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 197 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/R 81 115 180 0.289517 0.311340 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 357 -8191 8250 ) ( 357 8191 8250 ) ( 1718 8191 -8077 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1369 8191 8142 ) ( 1369 -8191 8142 ) ( 687 -8191 -8227 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 198 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/T 78 115 180 0.290813 0.311340 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 325 -8191 8247 ) ( 325 8191 8247 ) ( 1686 8191 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1337 8191 8143 ) ( 1337 -8191 8143 ) ( 655 -8191 -8226 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 199 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/Y 125 115 180 0.288615 0.311340 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 294 -8191 8244 ) ( 294 8191 8244 ) ( 1654 8191 -8082 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1305 8191 8144 ) ( 1305 -8191 8144 ) ( 623 -8191 -8225 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 200 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/U 130 115 180 0.289599 0.311340 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 262 -8191 8242 ) ( 262 8191 8242 ) ( 1622 8191 -8085 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1273 8191 8146 ) ( 1273 -8191 8146 ) ( 591 -8191 -8223 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 201 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 230 -8191 8239 ) ( 230 8191 8239 ) ( 1591 8191 -8087 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1241 8191 8147 ) ( 1241 -8191 8147 ) ( 559 -8191 -8222 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 202 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 198 -8191 8236 ) ( 198 8191 8236 ) ( 1559 8191 -8090 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1209 8191 8148 ) ( 1209 -8191 8148 ) ( 527 -8191 -8221 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 203 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 166 -8191 8234 ) ( 166 8191 8234 ) ( 1527 8191 -8093 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1177 8191 8150 ) ( 1177 -8191 8150 ) ( 495 -8191 -8219 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 204 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 135 -8191 8231 ) ( 135 8191 8231 ) ( 1495 8191 -8095 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1145 8191 8151 ) ( 1145 -8191 8151 ) ( 463 -8191 -8218 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 205 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 103 -8191 8229 ) ( 103 8191 8229 ) ( 1464 8191 -8098 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1113 8191 8152 ) ( 1113 -8191 8152 ) ( 431 -8191 -8217 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 206 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 95 -8191 8228 ) ( 95 8191 8228 ) ( 1456 8191 -8099 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1106 8191 8153 ) ( 1106 -8191 8153 ) ( 423 -8191 -8216 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 207 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 127 -8191 8230 ) ( 127 8191 8230 ) ( 1487 8191 -8096 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1137 8191 8151 ) ( 1137 -8191 8151 ) ( 455 -8191 -8218 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 208 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 159 -8191 8233 ) ( 159 8191 8233 ) ( 1519 8191 -8093 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1169 8191 8150 ) ( 1169 -8191 8150 ) ( 487 -8191 -8219 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 209 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 190 -8191 8236 ) ( 190 8191 8236 ) ( 1551 8191 -8091 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1201 8191 8149 ) ( 1201 -8191 8149 ) ( 519 -8191 -8220 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 210 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 222 -8191 8238 ) ( 222 8191 8238 ) ( 1583 8191 -8088 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1233 8191 8147 ) ( 1233 -8191 8147 ) ( 551 -8191 -8222 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 211 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 254 -8191 8241 ) ( 254 8191 8241 ) ( 1614 8191 -8085 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1265 8191 8146 ) ( 1265 -8191 8146 ) ( 583 -8191 -8223 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 212 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 286 -8191 8244 ) ( 286 8191 8244 ) ( 1646 8191 -8083 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1297 8191 8145 ) ( 1297 -8191 8145 ) ( 615 -8191 -8224 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 213 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 317 -8191 8246 ) ( 317 8191 8246 ) ( 1678 8191 -8080 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1329 8191 8143 ) ( 1329 -8191 8143 ) ( 647 -8191 -8226 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 214 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 349 -8191 8249 ) ( 349 8191 8249 ) ( 1710 8191 -8077 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1361 8191 8142 ) ( 1361 -8191 8142 ) ( 679 -8191 -8227 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 215 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 381 -8191 8252 ) ( 381 8191 8252 ) ( 1742 8191 -8075 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1393 8191 8141 ) ( 1393 -8191 8141 ) ( 711 -8191 -8228 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 216 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 413 -8191 8254 ) ( 413 8191 8254 ) ( 1773 8191 -8072 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1425 8191 8139 ) ( 1425 -8191 8139 ) ( 743 -8191 -8230 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 217 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 445 -8191 8257 ) ( 445 8191 8257 ) ( 1805 8191 -8069 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1457 8191 8138 ) ( 1457 -8191 8138 ) ( 775 -8191 -8231 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 218 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 492 -8191 8261 ) ( 492 8191 8261 ) ( 1853 8191 -8065 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1497 8191 8136 ) ( 1497 -8191 8136 ) ( 815 -8191 -8233 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 219 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 758 8160 ) ( 8192 758 8160 ) ( 8192 -263 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 492 -8191 8261 ) ( 492 8191 8261 ) ( 1853 8191 -8065 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1497 8191 8136 ) ( 1497 -8191 8136 ) ( 815 -8191 -8233 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 220 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 460 -8191 8258 ) ( 460 8191 8258 ) ( 1821 8191 -8068 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1473 8191 8137 ) ( 1473 -8191 8137 ) ( 791 -8191 -8232 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 221 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 429 -8191 8256 ) ( 429 8191 8256 ) ( 1789 8191 -8071 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1441 8191 8139 ) ( 1441 -8191 8139 ) ( 759 -8191 -8230 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 222 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 397 -8191 8253 ) ( 397 8191 8253 ) ( 1757 8191 -8073 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1409 8191 8140 ) ( 1409 -8191 8140 ) ( 727 -8191 -8229 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 223 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 365 -8191 8250 ) ( 365 8191 8250 ) ( 1726 8191 -8076 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1377 8191 8141 ) ( 1377 -8191 8141 ) ( 695 -8191 -8228 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 224 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 333 -8191 8248 ) ( 333 8191 8248 ) ( 1694 8191 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1345 8191 8143 ) ( 1345 -8191 8143 ) ( 663 -8191 -8226 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 225 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 302 -8191 8245 ) ( 302 8191 8245 ) ( 1662 8191 -8081 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1313 8191 8144 ) ( 1313 -8191 8144 ) ( 631 -8191 -8225 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 226 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 270 -8191 8242 ) ( 270 8191 8242 ) ( 1630 8191 -8084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1281 8191 8145 ) ( 1281 -8191 8145 ) ( 599 -8191 -8224 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 227 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 238 -8191 8240 ) ( 238 8191 8240 ) ( 1599 8191 -8087 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1249 8191 8147 ) ( 1249 -8191 8147 ) ( 567 -8191 -8222 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 228 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 206 -8191 8237 ) ( 206 8191 8237 ) ( 1567 8191 -8089 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1217 8191 8148 ) ( 1217 -8191 8148 ) ( 535 -8191 -8221 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 229 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 174 -8191 8234 ) ( 174 8191 8234 ) ( 1535 8191 -8092 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1185 8191 8149 ) ( 1185 -8191 8149 ) ( 503 -8191 -8220 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 230 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 143 -8191 8232 ) ( 143 8191 8232 ) ( 1503 8191 -8095 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1153 8191 8151 ) ( 1153 -8191 8151 ) ( 471 -8191 -8218 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 231 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 111 -8191 8229 ) ( 111 8191 8229 ) ( 1471 8191 -8097 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1121 8191 8152 ) ( 1121 -8191 8152 ) ( 439 -8191 -8217 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 232 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 492 -8191 8261 ) ( 492 8191 8261 ) ( 1853 8191 -8065 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1505 8191 8136 ) ( 1505 -8191 8136 ) ( 823 -8191 -8233 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 233 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 71 -8191 8226 ) ( 71 8191 8226 ) ( 1432 8191 -8101 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1058 8191 8155 ) ( 1058 -8191 8155 ) ( 376 -8191 -8214 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 234 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -248 8192 ) ( -8192 -248 8192 ) ( -8192 773 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 750 8161 ) ( 8192 750 8161 ) ( 8192 -271 -8191 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 63 -8191 8225 ) ( 63 8191 8225 ) ( 1424 8191 -8101 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1058 8191 8155 ) ( 1058 -8191 8155 ) ( 376 -8191 -8214 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 235 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8194 ) ( -8192 -216 8194 ) ( -8192 805 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 790 8158 ) ( 8192 790 8158 ) ( 8192 -231 -8193 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 79 -8191 8227 ) ( 79 8191 8227 ) ( 1440 8191 -8100 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1058 8191 8155 ) ( 1058 -8191 8155 ) ( 376 -8191 -8214 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 236 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7 -8191 8219 ) ( -7 8191 8219 ) ( 1352 8191 -8107 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1002 8191 8157 ) ( 1002 -8191 8157 ) ( 320 -8191 -8212 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 237 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -39 -8191 8217 ) ( -39 8191 8217 ) ( 1321 8191 -8110 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 970 8191 8158 ) ( 970 -8191 8158 ) ( 288 -8191 -8211 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 238 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -280 8190 ) ( -8192 -280 8190 ) ( -8192 741 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 726 8162 ) ( 8192 726 8162 ) ( 8192 -295 -8189 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -71 -8191 8214 ) ( -71 8191 8214 ) ( 1289 8191 -8112 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 938 8191 8160 ) ( 938 -8191 8160 ) ( 256 -8191 -8209 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 239 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7 -8191 8219 ) ( -7 8191 8219 ) ( 1352 8191 -8107 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1002 8191 8157 ) ( 1002 -8191 8157 ) ( 320 -8191 -8212 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 240 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -39 -8191 8217 ) ( -39 8191 8217 ) ( 1321 8191 -8110 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 970 8191 8158 ) ( 970 -8191 8158 ) ( 288 -8191 -8211 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 241 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -360 8185 ) ( -8192 -360 8185 ) ( -8192 661 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 647 8167 ) ( 8192 647 8167 ) ( 8192 -374 -8184 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -71 -8191 8214 ) ( -71 8191 8214 ) ( 1289 8191 -8112 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 938 8191 8160 ) ( 938 -8191 8160 ) ( 256 -8191 -8209 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 242 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -177 8196 ) ( -8192 -177 8196 ) ( -8192 844 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 830 8156 ) ( 8192 830 8156 ) ( 8192 -191 -8196 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -71 -8191 8214 ) ( -71 8191 8214 ) ( 1289 8191 -8112 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 938 8191 8160 ) ( 938 -8191 8160 ) ( 256 -8191 -8209 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 243 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -177 8196 ) ( -8192 -177 8196 ) ( -8192 844 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 830 8156 ) ( 8192 830 8156 ) ( 8192 -191 -8196 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -39 -8191 8217 ) ( -39 8191 8217 ) ( 1321 8191 -8110 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 970 8191 8158 ) ( 970 -8191 8158 ) ( 288 -8191 -8211 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 244 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -177 8196 ) ( -8192 -177 8196 ) ( -8192 844 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 830 8156 ) ( 8192 830 8156 ) ( 8192 -191 -8196 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7 -8191 8219 ) ( -7 8191 8219 ) ( 1352 8191 -8107 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1002 8191 8157 ) ( 1002 -8191 8157 ) ( 320 -8191 -8212 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 245 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -208 8194 ) ( -8192 -208 8194 ) ( -8192 813 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 798 8158 ) ( 8192 798 8158 ) ( 8192 -223 -8194 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -39 -8191 8217 ) ( -39 8191 8217 ) ( 1321 8191 -8110 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 970 8191 8158 ) ( 970 -8191 8158 ) ( 288 -8191 -8211 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 246 +{ +( 368 8192 8192 ) ( 368 -8192 8192 ) ( 368 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2072 -8192 8192 ) ( 2072 8192 8192 ) ( 2072 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1360 8192 ) ( 8192 -1360 8192 ) ( -8192 -1360 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1512 8192 ) ( -8192 1512 8192 ) ( -8192 1512 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -168 ) ( 8192 8192 -168 ) ( -8192 -8192 -168 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -136 ) ( 8192 -8192 -136 ) ( -8192 -8192 -136 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 247 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -185 8196 ) ( -8192 -185 8196 ) ( -8192 836 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 822 8156 ) ( 8192 822 8156 ) ( 8192 -199 -8195 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 492 -8191 8261 ) ( 492 8191 8261 ) ( 1853 8191 -8065 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1489 8191 8137 ) ( 1489 -8191 8137 ) ( 807 -8191 -8232 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 248 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -185 8196 ) ( -8192 -185 8196 ) ( -8192 836 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 822 8156 ) ( 8192 822 8156 ) ( 8192 -199 -8195 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 445 -8191 8257 ) ( 445 8191 8257 ) ( 1805 8191 -8069 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1449 8191 8138 ) ( 1449 -8191 8138 ) ( 767 -8191 -8231 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 249 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -185 8196 ) ( -8192 -185 8196 ) ( -8192 836 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 822 8156 ) ( 8192 822 8156 ) ( 8192 -199 -8195 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 405 -8191 8254 ) ( 405 8191 8254 ) ( 1765 8191 -8073 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1409 8191 8140 ) ( 1409 -8191 8140 ) ( 727 -8191 -8229 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 250 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -185 8196 ) ( -8192 -185 8196 ) ( -8192 836 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 822 8156 ) ( 8192 822 8156 ) ( 8192 -199 -8195 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 55 -8191 8225 ) ( 55 8191 8225 ) ( 1416 8191 -8102 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1050 8191 8155 ) ( 1050 -8191 8155 ) ( 368 -8191 -8214 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 251 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -185 8196 ) ( -8192 -185 8196 ) ( -8192 836 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 822 8156 ) ( 8192 822 8156 ) ( 8192 -199 -8195 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 95 -8191 8228 ) ( 95 8191 8228 ) ( 1456 8191 -8099 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1098 8191 8153 ) ( 1098 -8191 8153 ) ( 415 -8191 -8216 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 252 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -185 8196 ) ( -8192 -185 8196 ) ( -8192 836 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 822 8156 ) ( 8192 822 8156 ) ( 8192 -199 -8195 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 135 -8191 8231 ) ( 135 8191 8231 ) ( 1495 8191 -8095 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1137 8191 8151 ) ( 1137 -8191 8151 ) ( 455 -8191 -8218 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 253 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -185 8196 ) ( -8192 -185 8196 ) ( -8192 836 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 822 8156 ) ( 8192 822 8156 ) ( 8192 -199 -8195 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 174 -8191 8234 ) ( 174 8191 8234 ) ( 1535 8191 -8092 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1177 8191 8150 ) ( 1177 -8191 8150 ) ( 495 -8191 -8219 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 254 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -185 8196 ) ( -8192 -185 8196 ) ( -8192 836 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 822 8156 ) ( 8192 822 8156 ) ( 8192 -199 -8195 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 365 -8191 8250 ) ( 365 8191 8250 ) ( 1726 8191 -8076 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1217 8191 8148 ) ( 1217 -8191 8148 ) ( 535 -8191 -8221 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 255 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -272 8190 ) ( -8192 -272 8190 ) ( -8192 749 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 734 8162 ) ( 8192 734 8162 ) ( 8192 -287 -8190 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -182 -8191 8205 ) ( -182 8191 8205 ) ( 1178 8191 -8122 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 826 8191 8164 ) ( 826 -8191 8164 ) ( 144 -8191 -8205 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 256 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -272 8190 ) ( -8192 -272 8190 ) ( -8192 749 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 734 8162 ) ( 8192 734 8162 ) ( 8192 -287 -8190 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -150 -8191 8207 ) ( -150 8191 8207 ) ( 1209 8191 -8119 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 858 8191 8163 ) ( 858 -8191 8163 ) ( 176 -8191 -8206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 257 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -272 8190 ) ( -8192 -272 8190 ) ( -8192 749 -8161 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 734 8162 ) ( 8192 734 8162 ) ( 8192 -287 -8190 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -119 -8191 8210 ) ( -119 8191 8210 ) ( 1241 8191 -8116 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 890 8191 8162 ) ( 890 -8191 8162 ) ( 208 -8191 -8207 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 258 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -119 -8191 8210 ) ( -119 8191 8210 ) ( 1241 8191 -8116 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 890 8191 8162 ) ( 890 -8191 8162 ) ( 208 -8191 -8207 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 259 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -150 -8191 8207 ) ( -150 8191 8207 ) ( 1209 8191 -8119 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 858 8191 8163 ) ( 858 -8191 8163 ) ( 176 -8191 -8206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 260 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -182 -8191 8205 ) ( -182 8191 8205 ) ( 1178 8191 -8122 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 826 8191 8164 ) ( 826 -8191 8164 ) ( 144 -8191 -8205 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 261 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -208 8194 ) ( -8192 -208 8194 ) ( -8192 813 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 798 8158 ) ( 8192 798 8158 ) ( 8192 -223 -8194 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -182 -8191 8205 ) ( -182 8191 8205 ) ( 1178 8191 -8122 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 826 8191 8164 ) ( 826 -8191 8164 ) ( 144 -8191 -8205 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 262 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -208 8194 ) ( -8192 -208 8194 ) ( -8192 813 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 798 8158 ) ( 8192 798 8158 ) ( 8192 -223 -8194 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -150 -8191 8207 ) ( -150 8191 8207 ) ( 1209 8191 -8119 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 858 8191 8163 ) ( 858 -8191 8163 ) ( 176 -8191 -8206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 263 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -208 8194 ) ( -8192 -208 8194 ) ( -8192 813 -8157 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 798 8158 ) ( 8192 798 8158 ) ( 8192 -223 -8194 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -119 -8191 8210 ) ( -119 8191 8210 ) ( 1241 8191 -8116 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 890 8191 8162 ) ( 890 -8191 8162 ) ( 208 -8191 -8207 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 264 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -177 8196 ) ( -8192 -177 8196 ) ( -8192 844 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 830 8156 ) ( 8192 830 8156 ) ( 8192 -191 -8196 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -119 -8191 8210 ) ( -119 8191 8210 ) ( 1241 8191 -8116 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 858 8191 8163 ) ( 858 -8191 8163 ) ( 176 -8191 -8206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 265 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -177 8196 ) ( -8192 -177 8196 ) ( -8192 844 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 830 8156 ) ( 8192 830 8156 ) ( 8192 -191 -8196 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -182 -8191 8205 ) ( -182 8191 8205 ) ( 1178 8191 -8122 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 826 8191 8164 ) ( 826 -8191 8164 ) ( 144 -8191 -8205 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 266 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -240 8192 ) ( -8192 -240 8192 ) ( -8192 781 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 766 8160 ) ( 8192 766 8160 ) ( 8192 -255 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -119 -8191 8210 ) ( -119 8191 8210 ) ( 1241 8191 -8116 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 890 8191 8162 ) ( 890 -8191 8162 ) ( 208 -8191 -8207 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 267 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -240 8192 ) ( -8192 -240 8192 ) ( -8192 781 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 766 8160 ) ( 8192 766 8160 ) ( 8192 -255 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -150 -8191 8207 ) ( -150 8191 8207 ) ( 1209 8191 -8119 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 858 8191 8163 ) ( 858 -8191 8163 ) ( 176 -8191 -8206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 268 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -240 8192 ) ( -8192 -240 8192 ) ( -8192 781 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 766 8160 ) ( 8192 766 8160 ) ( 8192 -255 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -182 -8191 8205 ) ( -182 8191 8205 ) ( 1178 8191 -8122 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 826 8191 8164 ) ( 826 -8191 8164 ) ( 144 -8191 -8205 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 269 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8188 ) ( -8192 -312 8188 ) ( -8192 709 -8163 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 694 8164 ) ( 8192 694 8164 ) ( 8192 -327 -8187 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -214 -8191 8202 ) ( -214 8191 8202 ) ( 1146 8191 -8124 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 794 8191 8166 ) ( 794 -8191 8166 ) ( 112 -8191 -8203 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 270 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -240 8192 ) ( -8192 -240 8192 ) ( -8192 781 -8159 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 734 8162 ) ( 8192 734 8162 ) ( 8192 -287 -8190 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -214 -8191 8202 ) ( -214 8191 8202 ) ( 1146 8191 -8124 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 794 8191 8166 ) ( 794 -8191 8166 ) ( 112 -8191 -8203 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 271 +{ +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -96 ) ( 8192 -8192 -96 ) ( -8192 -8192 -96 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -177 8196 ) ( -8192 -177 8196 ) ( -8192 844 -8155 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 798 8158 ) ( 8192 798 8158 ) ( 8192 -223 -8194 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -214 -8191 8202 ) ( -214 8191 8202 ) ( 1146 8191 -8124 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 794 8191 8166 ) ( 794 -8191 8166 ) ( 112 -8191 -8203 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 272 +{ +( 540 8192 8192 ) ( 540 -8192 8192 ) ( 540 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1136 -8192 8192 ) ( 1136 8192 8192 ) ( 1136 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -166 8192 ) ( 8192 -166 8192 ) ( -8192 -166 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -56 ) ( 8192 8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 0 ) ( 8192 -8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1275 8093 ) ( -8192 -1275 8093 ) ( -8192 988 -8133 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 273 +{ +( 828 8192 8192 ) ( 828 -8192 8192 ) ( 828 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 854 -8192 8192 ) ( 854 8192 8192 ) ( 854 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 274 +{ +( 884 8192 8192 ) ( 884 -8192 8192 ) ( 884 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 910 -8192 8192 ) ( 910 8192 8192 ) ( 910 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 275 +{ +( 856 8192 8192 ) ( 856 -8192 8192 ) ( 856 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 882 -8192 8192 ) ( 882 8192 8192 ) ( 882 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 276 +{ +( 912 8192 8192 ) ( 912 -8192 8192 ) ( 912 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 938 -8192 8192 ) ( 938 8192 8192 ) ( 938 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 277 +{ +( 940 8192 8192 ) ( 940 -8192 8192 ) ( 940 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 966 -8192 8192 ) ( 966 8192 8192 ) ( 966 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 278 +{ +( 968 8192 8192 ) ( 968 -8192 8192 ) ( 968 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 992 -8192 8192 ) ( 992 8192 8192 ) ( 992 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 279 +{ +( 740 8192 8192 ) ( 740 -8192 8192 ) ( 740 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 764 -8192 8192 ) ( 764 8192 8192 ) ( 764 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 280 +{ +( 712 8192 8192 ) ( 712 -8192 8192 ) ( 712 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 738 -8192 8192 ) ( 738 8192 8192 ) ( 738 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 281 +{ +( 634 8192 8192 ) ( 634 -8192 8192 ) ( 634 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 660 -8192 8192 ) ( 660 8192 8192 ) ( 660 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 282 +{ +( 606 8192 8192 ) ( 606 -8192 8192 ) ( 606 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 632 -8192 8192 ) ( 632 8192 8192 ) ( 632 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -146 8192 ) ( 8192 -146 8192 ) ( -8192 -146 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -138 8192 ) ( -8192 -138 8192 ) ( -8192 -138 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 283 +{ +( 352 8192 8192 ) ( 352 -8192 8192 ) ( 352 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 464 -8192 8192 ) ( 464 8192 8192 ) ( 464 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -166 8192 ) ( 8192 -166 8192 ) ( -8192 -166 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -56 ) ( 8192 8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 0 ) ( 8192 -8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1275 8093 ) ( -8192 -1275 8093 ) ( -8192 988 -8133 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 284 +{ +( 465 8192 8192 ) ( 465 -8192 8192 ) ( 465 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 539 -8192 8192 ) ( 539 8192 8192 ) ( 539 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -166 8192 ) ( 8192 -166 8192 ) ( -8192 -166 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -56 ) ( 8192 8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 0 ) ( 8192 -8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1275 8093 ) ( -8192 -1275 8093 ) ( -8192 988 -8133 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 285 +{ +( 368 8192 8192 ) ( 368 -8192 8192 ) ( 368 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2072 -8192 8192 ) ( 2072 8192 8192 ) ( 2072 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 680 8192 ) ( 8192 680 8192 ) ( -8192 680 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1512 8192 ) ( -8192 1512 8192 ) ( -8192 1512 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -360 ) ( 8192 8192 -360 ) ( -8192 -8192 -360 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -336 ) ( 8192 -8192 -336 ) ( -8192 -8192 -336 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 286 +{ +( 368 8192 8192 ) ( 368 -8192 8192 ) ( 368 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2072 -8192 8192 ) ( 2072 8192 8192 ) ( 2072 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 688 8192 ) ( 8192 688 8192 ) ( -8192 688 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1504 8192 ) ( -8192 1504 8192 ) ( -8192 1504 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1080 ) ( 8192 8192 -1080 ) ( -8192 -8192 -1080 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1048 ) ( 8192 -8192 -1048 ) ( -8192 -8192 -1048 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 287 +{ +( 368 8192 8192 ) ( 368 -8192 8192 ) ( 368 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2072 -8192 8192 ) ( 2072 8192 8192 ) ( 2072 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1472 8192 ) ( 8192 1472 8192 ) ( -8192 1472 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1504 8192 ) ( -8192 1504 8192 ) ( -8192 1504 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1048 ) ( 8192 8192 -1048 ) ( -8192 -8192 -1048 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -360 ) ( 8192 -8192 -360 ) ( -8192 -8192 -360 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 288 +{ +( 368 8192 8192 ) ( 368 -8192 8192 ) ( 368 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2072 -8192 8192 ) ( 2072 8192 8192 ) ( 2072 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 688 8192 ) ( 8192 688 8192 ) ( -8192 688 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 720 8192 ) ( -8192 720 8192 ) ( -8192 720 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1048 ) ( 8192 8192 -1048 ) ( -8192 -8192 -1048 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -360 ) ( 8192 -8192 -360 ) ( -8192 -8192 -360 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 289 +{ +( 2056 8192 8192 ) ( 2056 -8192 8192 ) ( 2056 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2072 -8192 8192 ) ( 2072 8192 8192 ) ( 2072 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 720 8192 ) ( 8192 720 8192 ) ( -8192 720 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1472 8192 ) ( -8192 1472 8192 ) ( -8192 1472 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1048 ) ( 8192 8192 -1048 ) ( -8192 -8192 -1048 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -360 ) ( 8192 -8192 -360 ) ( -8192 -8192 -360 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 290 +{ +( 368 8192 8192 ) ( 368 -8192 8192 ) ( 368 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 384 -8192 8192 ) ( 384 8192 8192 ) ( 384 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 720 8192 ) ( 8192 720 8192 ) ( -8192 720 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1472 8192 ) ( -8192 1472 8192 ) ( -8192 1472 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1048 ) ( 8192 8192 -1048 ) ( -8192 -8192 -1048 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -634 ) ( 8192 -8192 -634 ) ( -8192 -8192 -634 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 291 +{ +( -8192 -920 8192 ) ( 8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -918 8192 ) ( -8192 -918 8192 ) ( -8192 -918 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 7 ) ( 8192 8192 7 ) ( -8192 -8192 7 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 600 ) ( 8192 -8192 600 ) ( -8192 -8192 600 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 607 -8245 8192 ) ( 1629 8106 8192 ) ( 1629 8106 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -145 8198 8192 ) ( 876 -8153 8192 ) ( 876 -8153 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 292 +{ +( -8192 -920 8192 ) ( 8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -600 8192 ) ( -8192 -600 8192 ) ( -8192 -600 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 598 ) ( 8192 8192 598 ) ( -8192 -8192 598 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 600 ) ( 8192 -8192 600 ) ( -8192 -8192 600 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 609 -8246 8192 ) ( 1631 8106 8192 ) ( 1631 8106 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -142 8199 8192 ) ( 879 -8152 8192 ) ( 879 -8152 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 293 +{ +( -8192 -920 8192 ) ( 8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -600 8192 ) ( -8192 -600 8192 ) ( -8192 -600 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 8 ) ( 8192 8192 8 ) ( -8192 -8192 8 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 600 ) ( 8192 -8192 600 ) ( -8192 -8192 600 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -147 8198 8192 ) ( 874 -8153 8192 ) ( 874 -8153 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 881 -8152 8192 ) ( -140 8199 8192 ) ( -140 8199 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 294 +{ +( -8192 -920 8192 ) ( 8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -600 8192 ) ( -8192 -600 8192 ) ( -8192 -600 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 8 ) ( 8192 8192 8 ) ( -8192 -8192 8 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 600 ) ( 8192 -8192 600 ) ( -8192 -8192 600 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 613 -8246 8192 ) ( 1635 8105 8192 ) ( 1635 8105 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1629 8106 8192 ) ( 607 -8245 8192 ) ( 1629 8106 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 295 +{ +( -8192 -920 8192 ) ( 8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -600 8192 ) ( -8192 -600 8192 ) ( -8192 -600 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 6 ) ( 8192 8192 6 ) ( -8192 -8192 6 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 8 ) ( 8192 -8192 8 ) ( -8192 -8192 8 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 609 -8246 8192 ) ( 1631 8106 8192 ) ( 1631 8106 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -140 8199 8192 ) ( 881 -8152 8192 ) ( -140 8199 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 296 +{ +( -1696 8192 8192 ) ( -1696 -8192 8192 ) ( -1696 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1584 -8192 8192 ) ( -1584 8192 8192 ) ( -1584 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1280 8192 ) ( 8192 -1280 8192 ) ( -8192 -1280 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -256 8192 ) ( -8192 -256 8192 ) ( -8192 -256 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1152 ) ( 8192 -8192 -1152 ) ( -8192 -8192 -1152 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 297 +{ +( 1728 8192 8192 ) ( 1728 -8192 8192 ) ( 1728 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 1840 -8192 8192 ) ( 1840 8192 8192 ) ( 1840 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1248 8192 ) ( 8192 -1248 8192 ) ( -8192 -1248 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -224 8192 ) ( -8192 -224 8192 ) ( -8192 -224 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1152 ) ( 8192 -8192 -1152 ) ( -8192 -8192 -1152 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 298 +{ +( -576 8192 8192 ) ( -576 -8192 8192 ) ( -576 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -544 -8192 8192 ) ( -544 8192 8192 ) ( -544 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 276 8193 ) ( 8192 276 8193 ) ( 8192 -890 -8149 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7995 -1789 ) ( 8192 -8044 1551 ) ( -8192 -8044 1551 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 815 8155 ) ( -8192 815 8155 ) ( -8192 -1350 -8084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8172 577 ) ( 8192 8155 -783 ) ( -8192 8155 -783 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 299 +{ +( -528 8192 8192 ) ( -528 -8192 8192 ) ( -528 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -496 -8192 8192 ) ( -496 8192 8192 ) ( -496 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 276 8193 ) ( 8192 276 8193 ) ( 8192 -890 -8149 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7995 -1789 ) ( 8192 -8044 1551 ) ( -8192 -8044 1551 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 815 8155 ) ( -8192 815 8155 ) ( -8192 -1350 -8084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8172 577 ) ( 8192 8155 -783 ) ( -8192 8155 -783 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 300 +{ +( -480 8192 8192 ) ( -480 -8192 8192 ) ( -480 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -448 -8192 8192 ) ( -448 8192 8192 ) ( -448 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8170 642 8194 ) ( 8194 -136 8194 ) ( 8139 -1301 -8147 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7995 -1789 ) ( 8192 -8044 1551 ) ( -8192 -8044 1551 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 815 8155 ) ( -8192 815 8155 ) ( -8192 -1350 -8084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8172 577 ) ( 8192 8155 -783 ) ( -8192 8155 -783 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 301 +{ +( -480 8192 8192 ) ( -480 -8192 8192 ) ( -480 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -448 -8192 8192 ) ( -448 8192 8192 ) ( -448 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8213 345 8169 ) ( 8156 1027 8169 ) ( 8240 -1001 -8087 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1109 ) ( 8192 -8140 922 ) ( -8192 -8140 922 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 767 8162 ) ( -8192 767 8162 ) ( -8192 -1397 -8078 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8171 584 ) ( 8192 8155 -776 ) ( -8192 8155 -776 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 667 8172 ) ( 8191 667 8172 ) ( 8191 -1364 -8085 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -52 ) ( 8192 -8192 -52 ) ( -8192 -8192 -52 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 302 +{ +( -528 8192 8192 ) ( -528 -8192 8192 ) ( -528 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -496 -8192 8192 ) ( -496 8192 8192 ) ( -496 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 667 8172 ) ( 8191 667 8172 ) ( 8191 -1364 -8085 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1109 ) ( 8192 -8140 922 ) ( -8192 -8140 922 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 767 8162 ) ( -8192 767 8162 ) ( -8192 -1397 -8078 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8171 584 ) ( 8192 8155 -776 ) ( -8192 8155 -776 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 303 +{ +( -576 8192 8192 ) ( -576 -8192 8192 ) ( -576 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -544 -8192 8192 ) ( -544 8192 8192 ) ( -544 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 667 8172 ) ( 8191 667 8172 ) ( 8191 -1364 -8085 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1109 ) ( 8192 -8140 922 ) ( -8192 -8140 922 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 767 8162 ) ( -8192 767 8162 ) ( -8192 -1397 -8078 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8171 584 ) ( 8192 8155 -776 ) ( -8192 8155 -776 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 304 +{ +( -576 8192 8192 ) ( -576 -8192 8192 ) ( -576 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -544 -8192 8192 ) ( -544 8192 8192 ) ( -544 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 620 8178 ) ( 8191 620 8178 ) ( 8191 -1412 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1104 ) ( 8192 -8139 927 ) ( -8192 -8139 927 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 719 8168 ) ( -8192 719 8168 ) ( -8192 -1445 -8071 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8171 591 ) ( 8192 8156 -769 ) ( -8192 8156 -769 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 305 +{ +( -528 8192 8192 ) ( -528 -8192 8192 ) ( -528 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -496 -8192 8192 ) ( -496 8192 8192 ) ( -496 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 620 8178 ) ( 8191 620 8178 ) ( 8191 -1412 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1104 ) ( 8192 -8139 927 ) ( -8192 -8139 927 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 719 8168 ) ( -8192 719 8168 ) ( -8192 -1445 -8071 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8171 591 ) ( 8192 8156 -769 ) ( -8192 8156 -769 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 306 +{ +( -480 8192 8192 ) ( -480 -8192 8192 ) ( -480 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -448 -8192 8192 ) ( -448 8192 8192 ) ( -448 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 620 8178 ) ( 8191 620 8178 ) ( 8191 -1412 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1104 ) ( 8192 -8139 927 ) ( -8192 -8139 927 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 719 8168 ) ( -8192 719 8168 ) ( -8192 -1445 -8071 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8171 591 ) ( 8192 8156 -769 ) ( -8192 8156 -769 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 307 +{ +( -480 8192 8192 ) ( -480 -8192 8192 ) ( -480 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -448 -8192 8192 ) ( -448 8192 8192 ) ( -448 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 572 8184 ) ( 8191 572 8184 ) ( 8191 -1459 -8073 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8118 -1099 ) ( 8192 -8139 932 ) ( -8192 -8139 932 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 672 8174 ) ( -8192 672 8174 ) ( -8192 -1493 -8065 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7799 2512 ) ( 8192 7675 -2870 ) ( -8192 7675 -2870 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 308 +{ +( -528 8192 8192 ) ( -528 -8192 8192 ) ( -528 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -496 -8192 8192 ) ( -496 8192 8192 ) ( -496 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 572 8184 ) ( 8191 572 8184 ) ( 8191 -1459 -8073 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8118 -1099 ) ( 8192 -8139 932 ) ( -8192 -8139 932 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 672 8174 ) ( -8192 672 8174 ) ( -8192 -1493 -8065 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7799 2512 ) ( 8192 7675 -2870 ) ( -8192 7675 -2870 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 309 +{ +( -576 8192 8192 ) ( -576 -8192 8192 ) ( -576 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -544 -8192 8192 ) ( -544 8192 8192 ) ( -544 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 572 8184 ) ( 8191 572 8184 ) ( 8191 -1459 -8073 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8118 -1099 ) ( 8192 -8139 932 ) ( -8192 -8139 932 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 672 8174 ) ( -8192 672 8174 ) ( -8192 -1493 -8065 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7799 2512 ) ( 8192 7675 -2870 ) ( -8192 7675 -2870 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 310 +{ +( -392 8192 8192 ) ( -392 -8192 8192 ) ( -392 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( -320 -8192 8192 ) ( -320 8192 8192 ) ( -320 8192 -8192 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( -8191 445 8200 ) ( 8191 445 8200 ) ( 8191 -1586 -8057 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7972 -1889 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8191 1800 7993 ) ( -8191 1800 7993 ) ( -8191 -2172 -7900 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 1617 ) ( 8192 7967 -1909 ) ( -8192 7967 -1909 ) base_wall/metalfloor_wall_12 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 311 +{ +( -285 8192 8192 ) ( -285 -8192 8192 ) ( -285 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -199 -8192 8192 ) ( -199 8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 909 8145 ) ( 8191 909 8145 ) ( 8191 -1407 -8074 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7939 -2020 ) ( 8192 -7998 1774 ) ( -8192 -7998 1774 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1230 8101 ) ( -8192 1230 8101 ) ( -8192 -1593 -8037 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8047 1537 ) ( 8192 7987 -1824 ) ( -8192 7987 -1824 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 312 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -199 -8192 8192 ) ( -199 8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -405 8203 ) ( 8192 -405 8203 ) ( 8192 -795 -8175 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8182 402 ) ( 8192 -8184 -353 ) ( -8192 -8184 -353 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 396 8199 ) ( -8192 396 8199 ) ( -8192 -1453 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 313 +{ +( 14 8192 8192 ) ( 14 -8192 8192 ) ( 14 8192 -8192 ) desktop/interface 24 120 180 0.600000 0.600000 0 0 0 +( 174 -8192 8192 ) ( 174 8192 8192 ) ( 174 8192 -8192 ) desktop/interface 24 120 180 0.600000 0.600000 0 0 0 +( -8192 -80 8192 ) ( 8192 -80 8192 ) ( -8192 -80 -8192 ) desktop/interface 24 120 180 0.600000 0.600000 0 0 0 +( 8192 80 8192 ) ( -8192 80 8192 ) ( -8192 80 -8192 ) desktop/interface 24 120 180 0.600000 0.600000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/interface 24 120 180 0.600000 0.600000 0 0 0 +( 8192 8192 -132 ) ( 8192 -8192 -132 ) ( -8192 -8192 -132 ) desktop/interface 24 120 180 0.600000 0.600000 0 0 0 +} +// brush 314 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -136 8192 ) ( 8192 -136 8192 ) ( -8192 -136 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 688 ) ( 8192 -8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 2572 -7785 8192 ) ( -1911 7973 8192 ) ( 2572 -7785 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 315 +{ +( 336 8192 8192 ) ( 336 -8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -136 8192 ) ( 8192 -136 8192 ) ( -8192 -136 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 2572 -7785 8192 ) ( -1911 7973 8192 ) ( 2572 -7785 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 316 +{ +( 336 8192 8192 ) ( 336 -8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1152 -8192 8192 ) ( 1152 8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 317 +{ +( 1152 8192 8192 ) ( 1152 -8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 688 ) ( 8192 -8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 318 +{ +( 336 8192 8192 ) ( 336 -8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1152 -8192 8192 ) ( 1152 8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -528 8192 ) ( 8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -136 8192 ) ( -8192 -136 8192 ) ( -8192 -136 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 319 +{ +( 336 8192 8192 ) ( 336 -8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1152 -8192 8192 ) ( 1152 8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -136 8192 ) ( 8192 -136 8192 ) ( -8192 -136 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 320 +{ +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -136 8192 ) ( 8192 -136 8192 ) ( -8192 -136 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 688 ) ( 8192 -8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3288 7581 8192 ) ( -1196 -8176 8192 ) ( 3288 7581 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 321 +{ +( 1152 -8192 8192 ) ( 1152 8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -136 8192 ) ( 8192 -136 8192 ) ( -8192 -136 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3288 7581 8192 ) ( -1196 -8176 8192 ) ( 3288 7581 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 322 +{ +( -384 8192 8192 ) ( -384 -8192 8192 ) ( -384 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -376 -8192 8192 ) ( -376 8192 8192 ) ( -376 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 564 8185 ) ( 8191 564 8185 ) ( 8191 -1467 -8072 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8118 -1099 ) ( 8192 -8139 932 ) ( -8192 -8139 932 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 572 8184 ) ( -8191 572 8184 ) ( 8191 -1459 -8073 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 908 ) ( 8192 8115 -1123 ) ( -8192 8115 -1123 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 323 +{ +( -384 8192 8192 ) ( -384 -8192 8192 ) ( -384 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -376 -8192 8192 ) ( -376 8192 8192 ) ( -376 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 592 8181 ) ( 8191 592 8181 ) ( 8191 -1439 -8075 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8118 -1099 ) ( 8192 -8139 933 ) ( -8192 -8139 933 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 600 8180 ) ( -8191 600 8180 ) ( -8191 -1431 -8076 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 909 ) ( 8192 8115 -1123 ) ( -8192 8115 -1123 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 324 +{ +( -384 8192 8192 ) ( -384 -8192 8192 ) ( -384 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -376 -8192 8192 ) ( -376 8192 8192 ) ( -376 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 620 8178 ) ( 8191 620 8178 ) ( 8191 -1412 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1104 ) ( 8192 -8139 927 ) ( -8192 -8139 927 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 628 8177 ) ( -8191 628 8177 ) ( -8191 -1404 -8080 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 903 ) ( 8192 8114 -1128 ) ( -8192 8114 -1128 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 325 +{ +( -384 8192 8192 ) ( -384 -8192 8192 ) ( -384 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -376 -8192 8192 ) ( -376 8192 8192 ) ( -376 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 648 8174 ) ( 8191 648 8174 ) ( 8191 -1384 -8082 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1104 ) ( 8192 -8139 928 ) ( -8192 -8139 928 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 656 8173 ) ( -8191 656 8173 ) ( -8191 -1376 -8083 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 904 ) ( 8192 8114 -1128 ) ( -8192 8114 -1128 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 326 +{ +( -384 8192 8192 ) ( -384 -8192 8192 ) ( -384 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -376 -8192 8192 ) ( -376 8192 8192 ) ( -376 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 675 8171 ) ( 8191 675 8171 ) ( 8191 -1356 -8086 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1109 ) ( 8192 -8140 922 ) ( -8192 -8140 922 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 683 8170 ) ( -8191 683 8170 ) ( -8191 -1348 -8087 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8143 898 ) ( 8192 8114 -1133 ) ( -8192 8114 -1133 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 327 +{ +( -384 8192 8192 ) ( -384 -8192 8192 ) ( -384 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -376 -8192 8192 ) ( -376 8192 8192 ) ( -376 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 703 8167 ) ( 8191 703 8167 ) ( 8191 -1328 -8089 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1109 ) ( 8192 -8140 923 ) ( -8192 -8140 923 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 711 8166 ) ( -8191 711 8166 ) ( -8191 -1320 -8090 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8143 899 ) ( 8192 8114 -1133 ) ( -8192 8114 -1133 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 328 +{ +( -384 8192 8192 ) ( -384 -8192 8192 ) ( -384 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -376 -8192 8192 ) ( -376 8192 8192 ) ( -376 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 731 8164 ) ( 8191 731 8164 ) ( 8191 -1300 -8093 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8116 -1114 ) ( 8192 -8141 917 ) ( -8192 -8141 917 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 739 8163 ) ( -8191 739 8163 ) ( -8191 -1292 -8094 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8144 893 ) ( 8192 8113 -1138 ) ( -8192 8113 -1138 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 329 +{ +( -384 8192 8192 ) ( -384 -8192 8192 ) ( -384 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -376 -8192 8192 ) ( -376 8192 8192 ) ( -376 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 755 8161 ) ( 8191 755 8161 ) ( 8191 -1276 -8096 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8116 -1113 ) ( 8192 -8140 918 ) ( -8192 -8140 918 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 763 8160 ) ( -8191 763 8160 ) ( -8191 -1268 -8097 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8143 894 ) ( 8192 8113 -1137 ) ( -8192 8113 -1137 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 330 +{ +( -372 8192 8192 ) ( -372 -8192 8192 ) ( -372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -348 -8192 8192 ) ( -348 8192 8192 ) ( -348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 755 8161 ) ( 8191 755 8161 ) ( 8191 -1276 -8096 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8116 -1113 ) ( 8192 -8140 918 ) ( -8192 -8140 918 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 763 8160 ) ( -8191 763 8160 ) ( -8191 -1268 -8097 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8143 894 ) ( 8192 8113 -1137 ) ( -8192 8113 -1137 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 331 +{ +( -372 8192 8192 ) ( -372 -8192 8192 ) ( -372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -348 -8192 8192 ) ( -348 8192 8192 ) ( -348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 731 8164 ) ( 8191 731 8164 ) ( 8191 -1300 -8093 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8116 -1114 ) ( 8192 -8141 917 ) ( -8192 -8141 917 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 739 8163 ) ( -8191 739 8163 ) ( -8191 -1292 -8094 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8144 893 ) ( 8192 8113 -1138 ) ( -8192 8113 -1138 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 332 +{ +( -372 8192 8192 ) ( -372 -8192 8192 ) ( -372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -348 -8192 8192 ) ( -348 8192 8192 ) ( -348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 703 8167 ) ( 8191 703 8167 ) ( 8191 -1328 -8089 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1109 ) ( 8192 -8140 923 ) ( -8192 -8140 923 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 711 8166 ) ( -8191 711 8166 ) ( -8191 -1320 -8090 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8143 899 ) ( 8192 8114 -1133 ) ( -8192 8114 -1133 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 333 +{ +( -372 8192 8192 ) ( -372 -8192 8192 ) ( -372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -348 -8192 8192 ) ( -348 8192 8192 ) ( -348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 675 8171 ) ( 8191 675 8171 ) ( 8191 -1356 -8086 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1109 ) ( 8192 -8140 922 ) ( -8192 -8140 922 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 683 8170 ) ( -8191 683 8170 ) ( -8191 -1348 -8087 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8143 898 ) ( 8192 8114 -1133 ) ( -8192 8114 -1133 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 334 +{ +( -372 8192 8192 ) ( -372 -8192 8192 ) ( -372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -348 -8192 8192 ) ( -348 8192 8192 ) ( -348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 648 8174 ) ( 8191 648 8174 ) ( 8191 -1384 -8082 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1104 ) ( 8192 -8139 928 ) ( -8192 -8139 928 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 656 8173 ) ( -8191 656 8173 ) ( -8191 -1376 -8083 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 904 ) ( 8192 8114 -1128 ) ( -8192 8114 -1128 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 335 +{ +( -372 8192 8192 ) ( -372 -8192 8192 ) ( -372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -348 -8192 8192 ) ( -348 8192 8192 ) ( -348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 620 8178 ) ( 8191 620 8178 ) ( 8191 -1412 -8079 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8117 -1104 ) ( 8192 -8139 927 ) ( -8192 -8139 927 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 628 8177 ) ( -8191 628 8177 ) ( -8191 -1404 -8080 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 903 ) ( 8192 8114 -1128 ) ( -8192 8114 -1128 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 336 +{ +( -372 8192 8192 ) ( -372 -8192 8192 ) ( -372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -348 -8192 8192 ) ( -348 8192 8192 ) ( -348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 592 8181 ) ( 8191 592 8181 ) ( 8191 -1439 -8075 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8118 -1099 ) ( 8192 -8139 933 ) ( -8192 -8139 933 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 600 8180 ) ( -8191 600 8180 ) ( -8191 -1431 -8076 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 909 ) ( 8192 8115 -1123 ) ( -8192 8115 -1123 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 337 +{ +( -372 8192 8192 ) ( -372 -8192 8192 ) ( -372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -348 -8192 8192 ) ( -348 8192 8192 ) ( -348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 564 8185 ) ( 8191 564 8185 ) ( 8191 -1467 -8072 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8118 -1099 ) ( 8192 -8139 932 ) ( -8192 -8139 932 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 572 8184 ) ( -8191 572 8184 ) ( 8191 -1459 -8073 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 908 ) ( 8192 8115 -1123 ) ( -8192 8115 -1123 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 338 +{ +( -664 8192 8192 ) ( -664 -8192 8192 ) ( -664 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -392 -8192 8192 ) ( -392 8192 8192 ) ( -392 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 1617 ) ( 8192 7967 -1909 ) ( -8192 7967 -1909 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 445 8200 ) ( 8191 445 8200 ) ( 8191 -1586 -8057 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 1800 7993 ) ( -8191 1800 7993 ) ( -8191 -2172 -7900 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 339 +{ +( -664 8192 8192 ) ( -664 -8192 8192 ) ( -664 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -320 -8192 8192 ) ( -320 8192 8192 ) ( -320 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 1617 ) ( 8192 7967 -1909 ) ( -8192 7967 -1909 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1540 8047 ) ( -8192 1540 8047 ) ( -8192 -1863 -7978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 1800 7993 ) ( 8191 1800 7993 ) ( -8191 -2172 -7900 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 340 +{ +( -320 8192 8192 ) ( -320 -8192 8192 ) ( -320 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -296 -8192 8192 ) ( -296 8192 8192 ) ( -296 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1540 8047 ) ( -8192 1540 8047 ) ( -8192 -1863 -7978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 1617 ) ( 8192 7967 -1909 ) ( -8192 7967 -1909 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 445 8200 ) ( 8191 445 8200 ) ( 8191 -1586 -8057 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 341 +{ +( -664 8192 8192 ) ( -664 -8192 8192 ) ( -664 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -296 -8192 8192 ) ( -296 8192 8192 ) ( -296 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1141 8133 ) ( 8192 1141 8133 ) ( 8192 -2295 -7886 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 1617 ) ( 8192 7967 -1909 ) ( -8192 7967 -1909 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 445 8200 ) ( -8191 445 8200 ) ( 8191 -1586 -8057 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 342 +{ +( -664 8192 8192 ) ( -664 -8192 8192 ) ( -664 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -296 -8192 8192 ) ( -296 8192 8192 ) ( -296 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -126 ) ( 8192 8192 -126 ) ( -8192 -8192 -126 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7967 -1909 ) ( 8192 -8032 1617 ) ( -8192 7967 -1909 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1141 8133 ) ( 8192 1141 8133 ) ( 8192 -2295 -7886 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1540 8047 ) ( -8192 1540 8047 ) ( -8192 -1863 -7978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8036 1599 ) ( 8192 7957 -1954 ) ( -8192 7957 -1954 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 343 +{ +( -294 8192 8192 ) ( -294 -8192 8192 ) ( -294 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -288 -8192 8192 ) ( -288 8192 8192 ) ( -288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -517 8192 ) ( -8192 -517 8192 ) ( -8192 -517 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1141 8133 ) ( 8192 1141 8133 ) ( 8192 -2295 -7886 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8031 1622 ) ( 8192 7965 -1917 ) ( -8191 7963 -1929 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 344 +{ +( -294 8192 8192 ) ( -294 -8192 8192 ) ( -294 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -517 8192 ) ( 8192 -517 8192 ) ( -8192 -517 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 345 +{ +( -294 8192 8192 ) ( -294 -8192 8192 ) ( -294 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -190 -8192 8192 ) ( -190 8192 8192 ) ( -190 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -38 ) ( 8192 -8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1469 8062 ) ( -8192 1469 8062 ) ( -8192 -1949 -7960 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8057 -1481 ) ( 8192 -8098 1239 ) ( -8192 -8098 1239 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 1616 ) ( 8192 7964 -1923 ) ( -8192 7964 -1923 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 346 +{ +( -294 8192 8192 ) ( -294 -8192 8192 ) ( -294 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -288 -8192 8192 ) ( -288 8192 8192 ) ( -288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1141 8133 ) ( 8192 1141 8133 ) ( 8192 -2295 -7886 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7964 -1923 ) ( 8192 -8032 1616 ) ( -8192 7964 -1923 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 347 +{ +( -294 8192 8192 ) ( -294 -8192 8192 ) ( -294 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -190 -8192 8192 ) ( -190 8192 8192 ) ( -190 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -126 ) ( 8192 8192 -126 ) ( -8192 -8192 -126 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -38 ) ( 8192 -8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8036 1599 ) ( 8192 7957 -1954 ) ( -8192 7957 -1954 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1141 8133 ) ( 8192 1141 8133 ) ( 8192 -2295 -7886 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1540 8047 ) ( -8192 1540 8047 ) ( -8192 -1863 -7978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7964 -1923 ) ( 8192 -8032 1616 ) ( -8192 7964 -1923 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 348 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -190 -8192 8192 ) ( -190 8192 8192 ) ( -190 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1141 8133 ) ( 8192 1141 8133 ) ( 8192 -2295 -7886 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 1616 ) ( 8192 7964 -1923 ) ( -8192 7964 -1923 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 349 +{ +( -294 8192 8192 ) ( -294 -8192 8192 ) ( -294 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -190 -8192 8192 ) ( -190 8192 8192 ) ( -190 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -38 ) ( 8192 -8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 588 8182 ) ( -8191 588 8182 ) ( -8191 -1443 -8075 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8098 1239 ) ( 8192 8057 -1481 ) ( -8192 -8098 1239 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 350 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -190 -8192 8192 ) ( -190 8192 8192 ) ( -190 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -38 ) ( 8192 8192 -38 ) ( -8192 -8192 -38 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1141 8133 ) ( 8192 1141 8133 ) ( 8192 -2295 -7886 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7965 -1917 ) ( 8192 -8031 1622 ) ( -8191 7963 -1929 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 351 +{ +( -294 8192 8192 ) ( -294 -8192 8192 ) ( -294 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -286 -8192 8192 ) ( -286 8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8031 1622 ) ( 8192 7965 -1917 ) ( -8191 7963 -1929 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1469 8062 ) ( 8192 1469 8062 ) ( -8192 -1949 -7960 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1540 8047 ) ( -8192 1540 8047 ) ( -8192 -1863 -7978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 352 +{ +( -294 8192 8192 ) ( -294 -8192 8192 ) ( -294 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -190 -8192 8192 ) ( -190 8192 8192 ) ( -190 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1469 8062 ) ( -8192 1469 8062 ) ( -8192 -1949 -7960 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8098 1239 ) ( 8192 8057 -1481 ) ( -8192 -8098 1239 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8191 739 8163 ) ( 8191 739 8163 ) ( -8191 -1292 -8094 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 353 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -190 -8192 8192 ) ( -190 8192 8192 ) ( -190 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1540 8047 ) ( -8192 1540 8047 ) ( -8192 -1863 -7978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1469 8062 ) ( 8192 1469 8062 ) ( -8192 -1949 -7960 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7973 -1885 ) ( 8192 -8029 1627 ) ( -8192 -8029 1627 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 1616 ) ( 8192 7964 -1923 ) ( -8192 7964 -1923 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 354 +{ +( -629 8192 8192 ) ( -629 -8192 8192 ) ( -629 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -220 -8192 8192 ) ( -220 8192 8192 ) ( -220 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -599 8192 ) ( 8192 -599 8192 ) ( -8192 -599 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -263 8192 ) ( -8192 -263 8192 ) ( -8192 -263 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7957 -1954 ) ( 8192 -8036 1599 ) ( -8192 7957 -1954 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 355 +{ +( 1487 -8192 8192 ) ( 1487 8192 8192 ) ( 1487 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -480 8192 ) ( 8192 -480 8192 ) ( -8192 -480 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -478 8192 ) ( -8192 -478 8192 ) ( -8192 -478 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -130 ) ( 8192 8192 -130 ) ( -8192 -8192 -130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -57 ) ( 8192 -8192 -57 ) ( -8192 -8192 -57 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 875 8262 8192 ) ( 1897 -8089 8192 ) ( 1897 -8089 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 356 +{ +( 1529 8192 8192 ) ( 1529 -8192 8192 ) ( 1529 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -480 8192 ) ( 8192 -480 8192 ) ( -8192 -480 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -478 8192 ) ( -8192 -478 8192 ) ( -8192 -478 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -130 ) ( 8192 8192 -130 ) ( -8192 -8192 -130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -57 ) ( 8192 -8192 -57 ) ( -8192 -8192 -57 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1106 -8277 8192 ) ( 2128 8074 8192 ) ( 2128 8074 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 357 +{ +( -8192 -480 8192 ) ( 8192 -480 8192 ) ( -8192 -480 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -478 8192 ) ( -8192 -478 8192 ) ( -8192 -478 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -57 ) ( 8192 8192 -57 ) ( -8192 -8192 -57 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1105 -8277 8192 ) ( 2127 8075 8192 ) ( 2127 8075 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 877 8262 8192 ) ( 1899 -8089 8192 ) ( 1899 -8089 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 358 +{ +( -8192 -480 8192 ) ( 8192 -480 8192 ) ( -8192 -480 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -478 8192 ) ( -8192 -478 8192 ) ( -8192 -478 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -130 ) ( 8192 -8192 -130 ) ( -8192 -8192 -130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1106 -8277 8192 ) ( 2128 8074 8192 ) ( 2128 8074 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 875 8262 8192 ) ( 1897 -8089 8192 ) ( 1897 -8089 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 359 +{ +( 1528 8192 8192 ) ( 1528 -8192 8192 ) ( 1528 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1530 -8192 8192 ) ( 1530 8192 8192 ) ( 1530 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -479 8192 ) ( 8192 -479 8192 ) ( -8192 -479 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -437 8192 ) ( -8192 -437 8192 ) ( -8192 -437 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -130 ) ( 8192 8192 -130 ) ( -8192 -8192 -130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -57 ) ( 8192 -8192 -57 ) ( -8192 -8192 -57 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 360 +{ +( -8192 -256 8192 ) ( 8192 -256 8192 ) ( -8192 -256 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8192 ) ( -8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 206 ) ( 8192 8192 206 ) ( -8192 -8192 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 2095 -8076 8192 ) ( 1073 8275 8192 ) ( 1073 8275 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1929 8087 8192 ) ( 907 -8264 8192 ) ( 907 -8264 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 361 +{ +( -8192 -256 8192 ) ( 8192 -256 8192 ) ( -8192 -256 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8192 ) ( -8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1929 8087 8192 ) ( 907 -8264 8192 ) ( 907 -8264 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 909 -8264 8192 ) ( 1931 8087 8192 ) ( 1931 8087 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 362 +{ +( -8192 -256 8192 ) ( 8192 -256 8192 ) ( -8192 -256 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8192 ) ( -8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 2095 -8076 8192 ) ( 1073 8275 8192 ) ( 1073 8275 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1071 8274 8192 ) ( 2093 -8077 8192 ) ( 2093 -8077 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 363 +{ +( -8192 -480 8192 ) ( 8192 -480 8192 ) ( -8192 -480 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -256 8192 ) ( -8192 -256 8192 ) ( -8192 -256 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -134 ) ( 8192 -8192 -134 ) ( -8192 -8192 -134 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1106 -8277 8192 ) ( 2128 8074 8192 ) ( 2128 8074 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 875 8262 8192 ) ( 1897 -8089 8192 ) ( 1897 -8089 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 364 +{ +( -8192 -480 8192 ) ( 8192 -480 8192 ) ( -8192 -480 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -256 8192 ) ( -8192 -256 8192 ) ( -8192 -256 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 206 ) ( 8192 8192 206 ) ( -8192 -8192 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1106 -8277 8192 ) ( 2128 8074 8192 ) ( 2128 8074 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 875 8262 8192 ) ( 1897 -8089 8192 ) ( 1897 -8089 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 365 +{ +( -8192 -480 8192 ) ( 8192 -480 8192 ) ( -8192 -480 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -256 8192 ) ( -8192 -256 8192 ) ( -8192 -256 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 875 8262 8192 ) ( 1897 -8089 8192 ) ( 1897 -8089 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1899 -8089 8192 ) ( 877 8262 8192 ) ( 1899 -8089 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 366 +{ +( -8192 -480 8192 ) ( 8192 -480 8192 ) ( -8192 -480 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -256 8192 ) ( -8192 -256 8192 ) ( -8192 -256 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1106 -8277 8192 ) ( 2128 8074 8192 ) ( 2128 8074 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 2126 8075 8192 ) ( 1104 -8277 8192 ) ( 1104 -8277 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 367 +{ +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -12 ) ( 8192 8192 -12 ) ( -8192 -8192 -12 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -10 ) ( 8192 -8192 -10 ) ( -8192 -8192 -10 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 2095 -8076 8192 ) ( 1073 8275 8192 ) ( 1073 8275 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1929 8087 8192 ) ( 907 -8264 8192 ) ( 907 -8264 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 368 +{ +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 206 ) ( 8192 8192 206 ) ( -8192 -8192 206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 2095 -8076 8192 ) ( 1073 8275 8192 ) ( 1073 8275 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1929 8087 8192 ) ( 907 -8264 8192 ) ( 907 -8264 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 369 +{ +( -8192 -202 8192 ) ( 8192 -202 8192 ) ( -8192 -202 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -10 ) ( 8192 8192 -10 ) ( -8192 -8192 -10 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 2095 -8076 8192 ) ( 1073 8275 8192 ) ( 1073 8275 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 1929 8087 8192 ) ( 907 -8264 8192 ) ( 907 -8264 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 370 +{ +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -202 8192 ) ( -8192 -202 8192 ) ( -8192 -202 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -10 ) ( 8192 8192 -10 ) ( -8192 -8192 -10 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 1929 8087 8192 ) ( 907 -8264 8192 ) ( 907 -8264 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 909 -8264 8192 ) ( 1931 8087 8192 ) ( 1931 8087 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 371 +{ +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -202 8192 ) ( -8192 -202 8192 ) ( -8192 -202 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -10 ) ( 8192 8192 -10 ) ( -8192 -8192 -10 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 208 ) ( 8192 -8192 208 ) ( -8192 -8192 208 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 2095 -8076 8192 ) ( 1073 8275 8192 ) ( 1073 8275 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +( 1072 8274 8192 ) ( 2094 -8077 8192 ) ( 2094 -8077 -8192 ) desktop/speaker 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 372 +{ +( -8192 -256 8192 ) ( 8192 -256 8192 ) ( -8192 -256 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8192 ) ( -8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -134 ) ( 8192 -8192 -134 ) ( -8192 -8192 -134 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 2095 -8076 8192 ) ( 1073 8275 8192 ) ( 1073 8275 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1929 8087 8192 ) ( 907 -8264 8192 ) ( 907 -8264 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 373 +{ +( 32 8192 8192 ) ( 32 -8192 8192 ) ( 32 8192 -8192 ) desktop/border 0 0 0 0.500000 0.200000 0 0 0 +( 248 -8192 8192 ) ( 248 8192 8192 ) ( 248 8192 -8192 ) desktop/jspbookside 44 -114 90 1.700000 1.200000 0 0 0 +( -8192 448 8192 ) ( 8192 448 8192 ) ( -8192 448 -8192 ) desktop/border 0 0 0 0.500000 0.200000 0 0 0 +( 8192 752 8192 ) ( -8192 752 8192 ) ( -8192 752 -8192 ) desktop/border 0 0 0 1.300000 0.200000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1120 ) ( 8192 -8192 -1120 ) ( -8192 -8192 -1120 ) desktop/jspbookcover 5 135 180 1.056250 1.187500 0 0 0 +} +// brush 374 +{ +( 1360 8192 8192 ) ( 1360 -8192 8192 ) ( 1360 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1368 -8192 8192 ) ( 1368 8192 8192 ) ( 1368 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1000 8192 ) ( 8192 1000 8192 ) ( -8192 1000 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1008 8192 ) ( -8192 1008 8192 ) ( -8192 1008 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -578 ) ( 8192 8192 -578 ) ( -8192 -8192 -578 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -360 ) ( 8192 -8192 -360 ) ( -8192 -8192 -360 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 375 +{ +( 1360 8192 8192 ) ( 1360 -8192 8192 ) ( 1360 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1368 -8192 8192 ) ( 1368 8192 8192 ) ( 1368 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1104 8192 ) ( 8192 1104 8192 ) ( -8192 1104 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1112 8192 ) ( -8192 1112 8192 ) ( -8192 1112 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -578 ) ( 8192 8192 -578 ) ( -8192 -8192 -578 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -360 ) ( 8192 -8192 -360 ) ( -8192 -8192 -360 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 376 +{ +( 1360 8192 8192 ) ( 1360 -8192 8192 ) ( 1360 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1368 -8192 8192 ) ( 1368 8192 8192 ) ( 1368 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1008 8192 ) ( 8192 1008 8192 ) ( -8192 1008 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1104 8192 ) ( -8192 1104 8192 ) ( -8192 1104 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -578 ) ( 8192 8192 -578 ) ( -8192 -8192 -578 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -570 ) ( 8192 -8192 -570 ) ( -8192 -8192 -570 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 377 +{ +( 60 8192 8192 ) ( 60 -8192 8192 ) ( 60 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 106 -8192 8192 ) ( 106 8192 8192 ) ( 106 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -118 ) ( 8192 -8192 -118 ) ( -8192 -8192 -118 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 378 +{ +( 60 8192 8192 ) ( 60 -8192 8192 ) ( 60 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 106 -8192 8192 ) ( 106 8192 8192 ) ( 106 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -284 8192 ) ( 8192 -284 8192 ) ( -8192 -284 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -252 8192 ) ( -8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -128 ) ( 8192 8192 -128 ) ( -8192 -8192 -128 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -126 ) ( 8192 -8192 -126 ) ( -8192 -8192 -126 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 379 +{ +( 106 8192 8192 ) ( 106 -8192 8192 ) ( 106 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 132 -8192 8192 ) ( 132 8192 8192 ) ( 132 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -110 ) ( 8192 8192 -110 ) ( -8192 -8192 -110 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -108 ) ( 8192 -8192 -108 ) ( -8192 -8192 -108 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 380 +{ +( 132 8192 8192 ) ( 132 -8192 8192 ) ( 132 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 158 -8192 8192 ) ( 158 8192 8192 ) ( 158 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -104 ) ( 8192 8192 -104 ) ( -8192 -8192 -104 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -102 ) ( 8192 -8192 -102 ) ( -8192 -8192 -102 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 381 +{ +( 158 8192 8192 ) ( 158 -8192 8192 ) ( 158 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 184 -8192 8192 ) ( 184 8192 8192 ) ( 184 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -96 ) ( 8192 8192 -96 ) ( -8192 -8192 -96 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -94 ) ( 8192 -8192 -94 ) ( -8192 -8192 -94 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 382 +{ +( 184 8192 8192 ) ( 184 -8192 8192 ) ( 184 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 210 -8192 8192 ) ( 210 8192 8192 ) ( 210 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -88 ) ( 8192 8192 -88 ) ( -8192 -8192 -88 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -86 ) ( 8192 -8192 -86 ) ( -8192 -8192 -86 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 383 +{ +( 210 8192 8192 ) ( 210 -8192 8192 ) ( 210 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 236 -8192 8192 ) ( 236 8192 8192 ) ( 236 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -80 ) ( 8192 8192 -80 ) ( -8192 -8192 -80 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -78 ) ( 8192 -8192 -78 ) ( -8192 -8192 -78 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 384 +{ +( 184 8192 8192 ) ( 184 -8192 8192 ) ( 184 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 210 -8192 8192 ) ( 210 8192 8192 ) ( 210 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -284 8192 ) ( 8192 -284 8192 ) ( -8192 -284 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -252 8192 ) ( -8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -72 ) ( 8192 8192 -72 ) ( -8192 -8192 -72 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -70 ) ( 8192 -8192 -70 ) ( -8192 -8192 -70 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 385 +{ +( 158 8192 8192 ) ( 158 -8192 8192 ) ( 158 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 184 -8192 8192 ) ( 184 8192 8192 ) ( 184 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -284 8192 ) ( 8192 -284 8192 ) ( -8192 -284 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -252 8192 ) ( -8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -64 ) ( 8192 8192 -64 ) ( -8192 -8192 -64 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -62 ) ( 8192 -8192 -62 ) ( -8192 -8192 -62 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 386 +{ +( 130 8192 8192 ) ( 130 -8192 8192 ) ( 130 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 156 -8192 8192 ) ( 156 8192 8192 ) ( 156 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -284 8192 ) ( 8192 -284 8192 ) ( -8192 -284 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -252 8192 ) ( -8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -56 ) ( 8192 8192 -56 ) ( -8192 -8192 -56 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -54 ) ( 8192 -8192 -54 ) ( -8192 -8192 -54 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 387 +{ +( 104 8192 8192 ) ( 104 -8192 8192 ) ( 104 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 130 -8192 8192 ) ( 130 8192 8192 ) ( 130 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -284 8192 ) ( 8192 -284 8192 ) ( -8192 -284 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -252 8192 ) ( -8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -50 ) ( 8192 8192 -50 ) ( -8192 -8192 -50 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -48 ) ( 8192 -8192 -48 ) ( -8192 -8192 -48 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 388 +{ +( 78 8192 8192 ) ( 78 -8192 8192 ) ( 78 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 104 -8192 8192 ) ( 104 8192 8192 ) ( 104 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -284 8192 ) ( 8192 -284 8192 ) ( -8192 -284 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -252 8192 ) ( -8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -42 ) ( 8192 8192 -42 ) ( -8192 -8192 -42 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -40 ) ( 8192 -8192 -40 ) ( -8192 -8192 -40 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 389 +{ +( 212 8192 8192 ) ( 212 -8192 8192 ) ( 212 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 238 -8192 8192 ) ( 238 8192 8192 ) ( 238 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -292 8192 ) ( 8192 -292 8192 ) ( -8192 -292 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 8 ) ( 8192 8192 8 ) ( -8192 -8192 8 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 10 ) ( 8192 -8192 10 ) ( -8192 -8192 10 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 390 +{ +( 186 8192 8192 ) ( 186 -8192 8192 ) ( 186 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 212 -8192 8192 ) ( 212 8192 8192 ) ( 212 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 2 ) ( 8192 -8192 2 ) ( -8192 -8192 2 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 391 +{ +( 160 8192 8192 ) ( 160 -8192 8192 ) ( 160 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 186 -8192 8192 ) ( 186 8192 8192 ) ( 186 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -8 ) ( 8192 8192 -8 ) ( -8192 -8192 -8 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -6 ) ( 8192 -8192 -6 ) ( -8192 -8192 -6 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 392 +{ +( 134 8192 8192 ) ( 134 -8192 8192 ) ( 134 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 160 -8192 8192 ) ( 160 8192 8192 ) ( 160 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -16 ) ( 8192 8192 -16 ) ( -8192 -8192 -16 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -14 ) ( 8192 -8192 -14 ) ( -8192 -8192 -14 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 393 +{ +( 108 8192 8192 ) ( 108 -8192 8192 ) ( 108 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 134 -8192 8192 ) ( 134 8192 8192 ) ( 134 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -22 ) ( 8192 8192 -22 ) ( -8192 -8192 -22 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -20 ) ( 8192 -8192 -20 ) ( -8192 -8192 -20 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 394 +{ +( 62 8192 8192 ) ( 62 -8192 8192 ) ( 62 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 108 -8192 8192 ) ( 108 8192 8192 ) ( 108 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -252 8192 ) ( 8192 -252 8192 ) ( -8192 -252 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -220 8192 ) ( -8192 -220 8192 ) ( -8192 -220 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -32 ) ( 8192 8192 -32 ) ( -8192 -8192 -32 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -30 ) ( 8192 -8192 -30 ) ( -8192 -8192 -30 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 395 +{ +( 1481 8192 8192 ) ( 1481 -8192 8192 ) ( 1481 8192 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 1520 -8192 8192 ) ( 1520 8192 8192 ) ( 1520 8192 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -8192 691 8192 ) ( 8192 691 8192 ) ( -8192 691 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 767 8192 ) ( -8192 767 8192 ) ( -8192 767 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -132 ) ( 8192 8192 -132 ) ( -8192 -8192 -132 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -87 ) ( 8192 -8192 -87 ) ( -8192 -8192 -87 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7505 -3290 ) ( 8192 -7319 3686 ) ( -8192 -7319 3686 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 396 +{ +( -74 8192 8192 ) ( -74 -8192 8192 ) ( -74 8192 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -66 -8192 8192 ) ( -66 8192 8192 ) ( -66 8192 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -241 8192 ) ( 8192 -241 8192 ) ( -8192 -241 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -195 8192 ) ( -8192 -195 8192 ) ( -8192 -195 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -116 ) ( 8192 8192 -116 ) ( -8192 -8192 -116 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -104 ) ( 8192 -8192 -104 ) ( -8192 -8192 -104 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 397 +{ +( -74 8192 8192 ) ( -74 -8192 8192 ) ( -74 8192 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -66 -8192 8192 ) ( -66 8192 8192 ) ( -66 8192 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -245 8192 ) ( 8192 -245 8192 ) ( -8192 -245 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -197 8192 ) ( -8192 -197 8192 ) ( -8192 -197 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -34 ) ( 8192 8192 -34 ) ( -8192 -8192 -34 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -14 ) ( 8192 -8192 -14 ) ( -8192 -8192 -14 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 398 +{ +( -74 8192 8192 ) ( -74 -8192 8192 ) ( -74 8192 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -66 -8192 8192 ) ( -66 8192 8192 ) ( -66 8192 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -247 8192 ) ( 8192 -247 8192 ) ( -8192 -247 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -233 8192 ) ( -8192 -233 8192 ) ( -8192 -233 -8192 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -104 ) ( 8192 8192 -104 ) ( -8192 -8192 -104 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -34 ) ( 8192 -8192 -34 ) ( -8192 -8192 -34 ) common/clip 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 399 +{ +( -8192 -218 8192 ) ( 8192 -218 8192 ) ( -8192 -218 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -216 8192 ) ( -8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -10 ) ( 8192 -8192 -10 ) ( -8192 -8192 -10 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1929 8087 8192 ) ( 907 -8264 8192 ) ( 907 -8264 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 2095 -8076 8192 ) ( 1073 8275 8192 ) ( 1073 8275 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 400 +{ +( -1592 8192 8192 ) ( -1592 -8192 8192 ) ( -1592 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1736 -8192 8192 ) ( 1736 8192 8192 ) ( 1736 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -776 8192 ) ( 8192 -776 8192 ) ( -8192 -776 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -704 8192 ) ( -8192 -704 8192 ) ( -8192 -704 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -224 ) ( 8192 8192 -224 ) ( -8192 -8192 -224 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -168 ) ( 8192 -8192 -168 ) ( -8192 -8192 -168 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 401 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1000 8192 ) ( 8192 -1000 8192 ) ( -8192 -1000 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1206 ) ( 8192 -8192 -1206 ) ( -8192 -8192 -1206 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 402 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1000 8192 ) ( 8192 -1000 8192 ) ( -8192 -1000 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -658 ) ( 8192 8192 -658 ) ( -8192 -8192 -658 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -656 ) ( 8192 -8192 -656 ) ( -8192 -8192 -656 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 403 +{ +( -1290 8192 8192 ) ( -1290 -8192 8192 ) ( -1290 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1000 8192 ) ( 8192 -1000 8192 ) ( -8192 -1000 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -656 ) ( 8192 -8192 -656 ) ( -8192 -8192 -656 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 404 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1534 -8192 8192 ) ( -1534 8192 8192 ) ( -1534 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1000 8192 ) ( 8192 -1000 8192 ) ( -8192 -1000 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -656 ) ( 8192 -8192 -656 ) ( -8192 -8192 -656 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 405 +{ +( -8192 156 8192 ) ( 8192 156 8192 ) ( -8192 156 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -898 ) ( 8192 -8192 -898 ) ( -8192 -8192 -898 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6771 -4673 8192 ) ( 5779 5856 8192 ) ( 5779 5856 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -2373 -7898 8192 ) ( 492 8232 8192 ) ( 492 8232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 5772 5864 8192 ) ( -6778 -4665 8192 ) ( -6778 -4665 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 406 +{ +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -898 ) ( 8192 -8192 -898 ) ( -8192 -8192 -898 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -2373 -7898 8192 ) ( 492 8232 8192 ) ( 492 8232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3572 -7397 8192 ) ( -4636 6781 8192 ) ( -4636 6781 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 483 8234 8192 ) ( -2382 -7897 8192 ) ( -2382 -7897 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6778 -4665 8192 ) ( 5772 5864 8192 ) ( -6778 -4665 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 407 +{ +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -898 ) ( 8192 -8192 -898 ) ( -8192 -8192 -898 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3572 -7397 8192 ) ( -4636 6781 8192 ) ( -4636 6781 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7722 -2733 8192 ) ( -7665 2890 8192 ) ( -7665 2890 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4645 6776 8192 ) ( 3563 -7402 8192 ) ( 3563 -7402 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -2382 -7897 8192 ) ( 483 8234 8192 ) ( -2382 -7897 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 408 +{ +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -898 ) ( 8192 -8192 -898 ) ( -8192 -8192 -898 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7722 -2733 8192 ) ( -7665 2890 8192 ) ( -7665 2890 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7413 3581 8192 ) ( -7975 -2043 8192 ) ( -7975 -2043 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7670 2877 8192 ) ( 7718 -2746 8192 ) ( 7718 -2746 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3563 -7402 8192 ) ( -4645 6776 8192 ) ( 3563 -7402 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 409 +{ +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -898 ) ( 8192 -8192 -898 ) ( -8192 -8192 -898 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7413 3581 8192 ) ( -7975 -2043 8192 ) ( -7975 -2043 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3032 7710 8192 ) ( -5176 -6468 8192 ) ( -5176 -6468 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7969 -2058 8192 ) ( 7418 3566 8192 ) ( 7418 3566 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7718 -2746 8192 ) ( -7670 2877 8192 ) ( 7718 -2746 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 410 +{ +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -898 ) ( 8192 -8192 -898 ) ( -8192 -8192 -898 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3032 7710 8192 ) ( -5176 -6468 8192 ) ( -5176 -6468 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -2568 7863 8192 ) ( 296 -8267 8192 ) ( 296 -8267 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5166 -6474 8192 ) ( 3042 7704 8192 ) ( 3042 7704 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7418 3566 8192 ) ( -7969 -2058 8192 ) ( 7418 3566 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 411 +{ +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -898 ) ( 8192 -8192 -898 ) ( -8192 -8192 -898 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -2568 7863 8192 ) ( 296 -8267 8192 ) ( 296 -8267 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6664 4801 8192 ) ( 5886 -5728 8192 ) ( 5886 -5728 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 308 -8265 8192 ) ( -2557 7866 8192 ) ( -2557 7866 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3042 7704 8192 ) ( -5166 -6474 8192 ) ( 3042 7704 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 412 +{ +( -8192 156 8192 ) ( 8192 156 8192 ) ( -8192 156 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -898 ) ( 8192 -8192 -898 ) ( -8192 -8192 -898 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6664 4801 8192 ) ( 5886 -5728 8192 ) ( 5886 -5728 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 5895 -5718 8192 ) ( -6656 4811 8192 ) ( -6656 4811 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -2557 7866 8192 ) ( 308 -8265 8192 ) ( -2557 7866 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 413 +{ +( -8192 156 8192 ) ( 8192 156 8192 ) ( -8192 156 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 166 8192 ) ( -8192 166 8192 ) ( -8192 166 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -898 ) ( 8192 -8192 -898 ) ( -8192 -8192 -898 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6656 4811 8192 ) ( 5895 -5718 8192 ) ( -6656 4811 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6778 -4665 8192 ) ( 5772 5864 8192 ) ( -6778 -4665 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 414 +{ +( -8192 166 8192 ) ( 8192 166 8192 ) ( -8192 166 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1192 ) ( 8192 -8192 -1192 ) ( -8192 -8192 -1192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -2557 7866 8192 ) ( 308 -8265 8192 ) ( -2557 7866 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6656 4811 8192 ) ( 5895 -5718 8192 ) ( -6656 4811 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 3563 -7402 8192 ) ( -4645 6776 8192 ) ( 3563 -7402 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 3042 7704 8192 ) ( -5166 -6474 8192 ) ( 3042 7704 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7418 3566 8192 ) ( -7969 -2058 8192 ) ( 7418 3566 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6778 -4665 8192 ) ( 5772 5864 8192 ) ( -6778 -4665 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -2382 -7897 8192 ) ( 483 8234 8192 ) ( -2382 -7897 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7718 -2746 8192 ) ( -7670 2877 8192 ) ( 7718 -2746 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 415 +{ +( -1508 8192 8192 ) ( -1508 -8192 8192 ) ( -1508 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1316 -8192 8192 ) ( -1316 8192 8192 ) ( -1316 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -678 8192 ) ( 8192 -678 8192 ) ( -8192 -678 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -814 ) ( 8192 8192 -814 ) ( -8192 -8192 -814 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -770 ) ( 8192 -8192 -770 ) ( -8192 -8192 -770 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 416 +{ +( -1460 8192 8192 ) ( -1460 -8192 8192 ) ( -1460 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1372 -8192 8192 ) ( -1372 8192 8192 ) ( -1372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -678 8192 ) ( 8192 -678 8192 ) ( -8192 -678 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -750 ) ( 8192 8192 -750 ) ( -8192 -8192 -750 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -730 ) ( 8192 -8192 -730 ) ( -8192 -8192 -730 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 417 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -814 ) ( 8192 -8192 -814 ) ( -8192 -8192 -814 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 418 +{ +( -1316 8192 8192 ) ( -1316 -8192 8192 ) ( -1316 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -814 ) ( 8192 8192 -814 ) ( -8192 -8192 -814 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -770 ) ( 8192 -8192 -770 ) ( -8192 -8192 -770 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 419 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1508 -8192 8192 ) ( -1508 8192 8192 ) ( -1508 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -814 ) ( 8192 8192 -814 ) ( -8192 -8192 -814 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -770 ) ( 8192 -8192 -770 ) ( -8192 -8192 -770 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 420 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -770 ) ( 8192 8192 -770 ) ( -8192 -8192 -770 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -750 ) ( 8192 -8192 -750 ) ( -8192 -8192 -750 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 421 +{ +( -1372 8192 8192 ) ( -1372 -8192 8192 ) ( -1372 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -750 ) ( 8192 8192 -750 ) ( -8192 -8192 -750 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -730 ) ( 8192 -8192 -730 ) ( -8192 -8192 -730 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 422 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1460 -8192 8192 ) ( -1460 8192 8192 ) ( -1460 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -750 ) ( 8192 8192 -750 ) ( -8192 -8192 -750 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -730 ) ( 8192 -8192 -730 ) ( -8192 -8192 -730 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 423 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -730 ) ( 8192 8192 -730 ) ( -8192 -8192 -730 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -718 ) ( 8192 -8192 -718 ) ( -8192 -8192 -718 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 424 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -674 ) ( 8192 8192 -674 ) ( -8192 -8192 -674 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -656 ) ( 8192 -8192 -656 ) ( -8192 -8192 -656 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 425 +{ +( -1316 8192 8192 ) ( -1316 -8192 8192 ) ( -1316 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1288 -8192 8192 ) ( -1288 8192 8192 ) ( -1288 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -718 ) ( 8192 8192 -718 ) ( -8192 -8192 -718 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -674 ) ( 8192 -8192 -674 ) ( -8192 -8192 -674 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 426 +{ +( -1536 8192 8192 ) ( -1536 -8192 8192 ) ( -1536 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1508 -8192 8192 ) ( -1508 8192 8192 ) ( -1508 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -506 8192 ) ( 8192 -506 8192 ) ( -8192 -506 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -718 ) ( 8192 8192 -718 ) ( -8192 -8192 -718 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -674 ) ( 8192 -8192 -674 ) ( -8192 -8192 -674 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 427 +{ +( -1508 8192 8192 ) ( -1508 -8192 8192 ) ( -1508 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1316 -8192 8192 ) ( -1316 8192 8192 ) ( -1316 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -678 8192 ) ( 8192 -678 8192 ) ( -8192 -678 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -718 ) ( 8192 8192 -718 ) ( -8192 -8192 -718 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -702 ) ( 8192 -8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 428 +{ +( -1508 8192 8192 ) ( -1508 -8192 8192 ) ( -1508 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1316 -8192 8192 ) ( -1316 8192 8192 ) ( -1316 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -678 8192 ) ( 8192 -678 8192 ) ( -8192 -678 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -682 ) ( 8192 8192 -682 ) ( -8192 -8192 -682 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -674 ) ( 8192 -8192 -674 ) ( -8192 -8192 -674 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 429 +{ +( -1508 8192 8192 ) ( -1508 -8192 8192 ) ( -1508 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1316 -8192 8192 ) ( -1316 8192 8192 ) ( -1316 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -678 8192 ) ( 8192 -678 8192 ) ( -8192 -678 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -654 8192 ) ( -8192 -654 8192 ) ( -8192 -654 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -682 ) ( 8192 -8192 -682 ) ( -8192 -8192 -682 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 430 +{ +( -1348 8192 8192 ) ( -1348 -8192 8192 ) ( -1348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1316 -8192 8192 ) ( -1316 8192 8192 ) ( -1316 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -654 8192 ) ( 8192 -654 8192 ) ( -8192 -654 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -682 ) ( 8192 -8192 -682 ) ( -8192 -8192 -682 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 431 +{ +( -1508 8192 8192 ) ( -1508 -8192 8192 ) ( -1508 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1476 -8192 8192 ) ( -1476 8192 8192 ) ( -1476 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -654 8192 ) ( 8192 -654 8192 ) ( -8192 -654 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -504 8192 ) ( -8192 -504 8192 ) ( -8192 -504 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -682 ) ( 8192 -8192 -682 ) ( -8192 -8192 -682 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 432 +{ +( -1496 8192 8192 ) ( -1496 -8192 8192 ) ( -1496 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1480 -8192 8192 ) ( -1480 8192 8192 ) ( -1480 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -508 8192 ) ( 8192 -508 8192 ) ( -8192 -508 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -500 8192 ) ( -8192 -500 8192 ) ( -8192 -500 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -712 ) ( 8192 8192 -712 ) ( -8192 -8192 -712 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -704 ) ( 8192 -8192 -704 ) ( -8192 -8192 -704 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 433 +{ +( -1534 8192 8192 ) ( -1534 -8192 8192 ) ( -1534 8192 -8192 ) desktop/screengrid 0 0 90 0.500000 0.500000 0 0 0 +( -1290 -8192 8192 ) ( -1290 8192 8192 ) ( -1290 8192 -8192 ) desktop/screengrid 0 0 90 0.500000 0.500000 0 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) desktop/screengrid 0 0 90 0.500000 0.500000 0 0 0 +( 8192 -994 8192 ) ( -8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/screengrid 0 0 90 0.500000 0.500000 0 0 0 +( 8192 -8192 -1206 ) ( 8192 8192 -1206 ) ( -8192 -8192 -1206 ) desktop/screengrid 0 0 90 0.500000 0.500000 0 0 0 +( 8192 8192 -734 ) ( 8192 -8192 -734 ) ( -8192 -8192 -734 ) desktop/screengrid 0 0 90 0.500000 0.500000 0 0 0 +} +// brush 434 +{ +( -1534 8192 8192 ) ( -1534 -8192 8192 ) ( -1534 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1290 -8192 8192 ) ( -1290 8192 8192 ) ( -1290 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -994 8192 ) ( -8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -666 ) ( 8192 8192 -666 ) ( -8192 -8192 -666 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -658 ) ( 8192 -8192 -658 ) ( -8192 -8192 -658 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 435 +{ +( -1316 8192 8192 ) ( -1316 -8192 8192 ) ( -1316 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1290 -8192 8192 ) ( -1290 8192 8192 ) ( -1290 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -994 8192 ) ( -8192 -994 8192 ) ( -8192 -994 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -734 ) ( 8192 8192 -734 ) ( -8192 -8192 -734 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -666 ) ( 8192 -8192 -666 ) ( -8192 -8192 -666 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 436 +{ +( -1534 8192 8192 ) ( -1534 -8192 8192 ) ( -1534 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1516 -8192 8192 ) ( -1516 8192 8192 ) ( -1516 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -994 8192 ) ( -8192 -994 8192 ) ( -8192 -994 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -734 ) ( 8192 8192 -734 ) ( -8192 -8192 -734 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -666 ) ( 8192 -8192 -666 ) ( -8192 -8192 -666 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 437 +{ +( -1514 8192 8192 ) ( -1514 -8192 8192 ) ( -1514 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1318 -8192 8192 ) ( -1318 8192 8192 ) ( -1318 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -994 8192 ) ( 8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -820 8192 ) ( -8192 -820 8192 ) ( -8192 -820 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -734 ) ( 8192 8192 -734 ) ( -8192 -8192 -734 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -732 ) ( 8192 -8192 -732 ) ( -8192 -8192 -732 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 438 +{ +( -1514 8192 8192 ) ( -1514 -8192 8192 ) ( -1514 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1318 -8192 8192 ) ( -1318 8192 8192 ) ( -1318 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -992 8192 ) ( 8192 -992 8192 ) ( -8192 -992 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -820 8192 ) ( -8192 -820 8192 ) ( -8192 -820 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -668 ) ( 8192 8192 -668 ) ( -8192 -8192 -668 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -666 ) ( 8192 -8192 -666 ) ( -8192 -8192 -666 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 439 +{ +( -1318 8192 8192 ) ( -1318 -8192 8192 ) ( -1318 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1316 -8192 8192 ) ( -1316 8192 8192 ) ( -1316 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -820 8192 ) ( -8192 -820 8192 ) ( -8192 -820 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -734 ) ( 8192 8192 -734 ) ( -8192 -8192 -734 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -666 ) ( 8192 -8192 -666 ) ( -8192 -8192 -666 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 440 +{ +( -1514 8192 8192 ) ( -1514 -8192 8192 ) ( -1514 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1318 -8192 8192 ) ( -1318 8192 8192 ) ( -1318 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -822 8192 ) ( 8192 -822 8192 ) ( -8192 -822 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -820 8192 ) ( -8192 -820 8192 ) ( -8192 -820 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -732 ) ( 8192 8192 -732 ) ( -8192 -8192 -732 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -668 ) ( 8192 -8192 -668 ) ( -8192 -8192 -668 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 441 +{ +( -1516 8192 8192 ) ( -1516 -8192 8192 ) ( -1516 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1514 -8192 8192 ) ( -1514 8192 8192 ) ( -1514 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -820 8192 ) ( -8192 -820 8192 ) ( -8192 -820 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -734 ) ( 8192 8192 -734 ) ( -8192 -8192 -734 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -666 ) ( 8192 -8192 -666 ) ( -8192 -8192 -666 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 442 +{ +( -1460 8192 8192 ) ( -1460 -8192 8192 ) ( -1460 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1322 -8192 8192 ) ( -1322 8192 8192 ) ( -1322 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -994 8192 ) ( -8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -728 ) ( 8192 8192 -728 ) ( -8192 -8192 -728 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -672 ) ( 8192 -8192 -672 ) ( -8192 -8192 -672 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 443 +{ +( -1514 8192 8192 ) ( -1514 -8192 8192 ) ( -1514 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1460 -8192 8192 ) ( -1460 8192 8192 ) ( -1460 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -994 8192 ) ( -8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -732 ) ( 8192 8192 -732 ) ( -8192 -8192 -732 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -668 ) ( 8192 -8192 -668 ) ( -8192 -8192 -668 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 444 +{ +( -1322 8192 8192 ) ( -1322 -8192 8192 ) ( -1322 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1318 -8192 8192 ) ( -1318 8192 8192 ) ( -1318 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -994 8192 ) ( -8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -732 ) ( 8192 8192 -732 ) ( -8192 -8192 -732 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -668 ) ( 8192 -8192 -668 ) ( -8192 -8192 -668 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 445 +{ +( -1460 8192 8192 ) ( -1460 -8192 8192 ) ( -1460 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1322 -8192 8192 ) ( -1322 8192 8192 ) ( -1322 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -994 8192 ) ( -8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -672 ) ( 8192 8192 -672 ) ( -8192 -8192 -672 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -668 ) ( 8192 -8192 -668 ) ( -8192 -8192 -668 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 446 +{ +( -1460 8192 8192 ) ( -1460 -8192 8192 ) ( -1460 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1322 -8192 8192 ) ( -1322 8192 8192 ) ( -1322 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -996 8192 ) ( 8192 -996 8192 ) ( -8192 -996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -994 8192 ) ( -8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -732 ) ( 8192 8192 -732 ) ( -8192 -8192 -732 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -728 ) ( 8192 -8192 -728 ) ( -8192 -8192 -728 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 447 +{ +( -1506 8192 8192 ) ( -1506 -8192 8192 ) ( -1506 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( -1504 -8192 8192 ) ( -1504 8192 8192 ) ( -1504 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -866 8192 ) ( 8192 -866 8192 ) ( -8192 -866 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -538 8192 ) ( -8192 -538 8192 ) ( -8192 -538 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -886 ) ( 8192 8192 -886 ) ( -8192 -8192 -886 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -830 ) ( 8192 -8192 -830 ) ( -8192 -8192 -830 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 448 +{ +( -1506 8192 8192 ) ( -1506 -8192 8192 ) ( -1506 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( -1504 -8192 8192 ) ( -1504 8192 8192 ) ( -1504 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -866 8192 ) ( 8192 -866 8192 ) ( -8192 -866 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -538 8192 ) ( -8192 -538 8192 ) ( -8192 -538 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1190 ) ( 8192 8192 -1190 ) ( -8192 -8192 -1190 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1106 ) ( 8192 -8192 -1106 ) ( -8192 -8192 -1106 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 449 +{ +( -1506 8192 8192 ) ( -1506 -8192 8192 ) ( -1506 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( -1504 -8192 8192 ) ( -1504 8192 8192 ) ( -1504 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -970 8192 ) ( 8192 -970 8192 ) ( -8192 -970 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -866 8192 ) ( -8192 -866 8192 ) ( -8192 -866 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1190 ) ( 8192 8192 -1190 ) ( -8192 -8192 -1190 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -970 ) ( 8192 -8192 -970 ) ( -8192 -8192 -970 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 450 +{ +( -1506 8192 8192 ) ( -1506 -8192 8192 ) ( -1506 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( -1504 -8192 8192 ) ( -1504 8192 8192 ) ( -1504 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -866 8192 ) ( 8192 -866 8192 ) ( -8192 -866 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -538 8192 ) ( -8192 -538 8192 ) ( -8192 -538 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1106 ) ( 8192 8192 -1106 ) ( -8192 -8192 -1106 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -886 ) ( 8192 -8192 -886 ) ( -8192 -8192 -886 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 451 +{ +( -1502 8192 8192 ) ( -1502 -8192 8192 ) ( -1502 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( -1418 -8192 8192 ) ( -1418 8192 8192 ) ( -1418 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -994 8192 ) ( 8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -738 8192 ) ( -8192 -738 8192 ) ( -8192 -738 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1160 ) ( 8192 8192 -1160 ) ( -8192 -8192 -1160 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1158 ) ( 8192 -8192 -1158 ) ( -8192 -8192 -1158 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 452 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1496 -8192 8192 ) ( -1496 8192 8192 ) ( -1496 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -970 8192 ) ( 8192 -970 8192 ) ( -8192 -970 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1162 ) ( 8192 8192 -1162 ) ( -8192 -8192 -1162 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1152 ) ( 8192 -8192 -1152 ) ( -8192 -8192 -1152 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 453 +{ +( -1490 8192 8192 ) ( -1490 -8192 8192 ) ( -1490 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -990 8192 ) ( 8192 -990 8192 ) ( -8192 -990 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -968 8192 ) ( -8192 -968 8192 ) ( -8192 -968 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1158 ) ( 8192 8192 -1158 ) ( -8192 -8192 -1158 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1156 ) ( 8192 -8192 -1156 ) ( -8192 -8192 -1156 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 454 +{ +( -1450 8192 8192 ) ( -1450 -8192 8192 ) ( -1450 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1426 -8192 8192 ) ( -1426 8192 8192 ) ( -1426 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -942 8192 ) ( 8192 -942 8192 ) ( -8192 -942 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -920 8192 ) ( -8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1158 ) ( 8192 8192 -1158 ) ( -8192 -8192 -1158 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1156 ) ( 8192 -8192 -1156 ) ( -8192 -8192 -1156 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 455 +{ +( -1498 8192 8192 ) ( -1498 -8192 8192 ) ( -1498 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1474 -8192 8192 ) ( -1474 8192 8192 ) ( -1474 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -924 8192 ) ( 8192 -924 8192 ) ( -8192 -924 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -902 8192 ) ( -8192 -902 8192 ) ( -8192 -902 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1158 ) ( 8192 8192 -1158 ) ( -8192 -8192 -1158 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1156 ) ( 8192 -8192 -1156 ) ( -8192 -8192 -1156 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 456 +{ +( -1452 8192 8192 ) ( -1452 -8192 8192 ) ( -1452 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1428 -8192 8192 ) ( -1428 8192 8192 ) ( -1428 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -876 8192 ) ( 8192 -876 8192 ) ( -8192 -876 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1158 ) ( 8192 8192 -1158 ) ( -8192 -8192 -1158 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1156 ) ( 8192 -8192 -1156 ) ( -8192 -8192 -1156 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 457 +{ +( -1488 8192 8192 ) ( -1488 -8192 8192 ) ( -1488 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1480 -8192 8192 ) ( -1480 8192 8192 ) ( -1480 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1158 ) ( 8192 8192 -1158 ) ( -8192 -8192 -1158 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1156 ) ( 8192 -8192 -1156 ) ( -8192 -8192 -1156 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 458 +{ +( -1472 8192 8192 ) ( -1472 -8192 8192 ) ( -1472 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1464 -8192 8192 ) ( -1464 8192 8192 ) ( -1464 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1158 ) ( 8192 8192 -1158 ) ( -8192 -8192 -1158 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1156 ) ( 8192 -8192 -1156 ) ( -8192 -8192 -1156 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 459 +{ +( -1472 8192 8192 ) ( -1472 -8192 8192 ) ( -1472 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1464 -8192 8192 ) ( -1464 8192 8192 ) ( -1464 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1062 ) ( 8192 8192 -1062 ) ( -8192 -8192 -1062 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1060 ) ( 8192 -8192 -1060 ) ( -8192 -8192 -1060 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 460 +{ +( -1488 8192 8192 ) ( -1488 -8192 8192 ) ( -1488 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1480 -8192 8192 ) ( -1480 8192 8192 ) ( -1480 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1062 ) ( 8192 8192 -1062 ) ( -8192 -8192 -1062 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1060 ) ( 8192 -8192 -1060 ) ( -8192 -8192 -1060 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 461 +{ +( -1452 8192 8192 ) ( -1452 -8192 8192 ) ( -1452 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1428 -8192 8192 ) ( -1428 8192 8192 ) ( -1428 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -876 8192 ) ( 8192 -876 8192 ) ( -8192 -876 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1062 ) ( 8192 8192 -1062 ) ( -8192 -8192 -1062 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1060 ) ( 8192 -8192 -1060 ) ( -8192 -8192 -1060 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 462 +{ +( -1490 8192 8192 ) ( -1490 -8192 8192 ) ( -1490 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -924 8192 ) ( 8192 -924 8192 ) ( -8192 -924 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -902 8192 ) ( -8192 -902 8192 ) ( -8192 -902 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1062 ) ( 8192 8192 -1062 ) ( -8192 -8192 -1062 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1060 ) ( 8192 -8192 -1060 ) ( -8192 -8192 -1060 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 463 +{ +( -1450 8192 8192 ) ( -1450 -8192 8192 ) ( -1450 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1426 -8192 8192 ) ( -1426 8192 8192 ) ( -1426 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -942 8192 ) ( 8192 -942 8192 ) ( -8192 -942 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -920 8192 ) ( -8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1062 ) ( 8192 8192 -1062 ) ( -8192 -8192 -1062 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1060 ) ( 8192 -8192 -1060 ) ( -8192 -8192 -1060 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 464 +{ +( -1490 8192 8192 ) ( -1490 -8192 8192 ) ( -1490 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -990 8192 ) ( 8192 -990 8192 ) ( -8192 -990 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -968 8192 ) ( -8192 -968 8192 ) ( -8192 -968 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1062 ) ( 8192 8192 -1062 ) ( -8192 -8192 -1062 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1060 ) ( 8192 -8192 -1060 ) ( -8192 -8192 -1060 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 465 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1496 -8192 8192 ) ( -1496 8192 8192 ) ( -1496 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -970 8192 ) ( 8192 -970 8192 ) ( -8192 -970 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1066 ) ( 8192 8192 -1066 ) ( -8192 -8192 -1066 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1056 ) ( 8192 -8192 -1056 ) ( -8192 -8192 -1056 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 466 +{ +( -1502 8192 8192 ) ( -1502 -8192 8192 ) ( -1502 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -1418 -8192 8192 ) ( -1418 8192 8192 ) ( -1418 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -994 8192 ) ( 8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -714 8192 ) ( -8192 -714 8192 ) ( -8192 -714 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1064 ) ( 8192 8192 -1064 ) ( -8192 -8192 -1064 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1062 ) ( 8192 -8192 -1062 ) ( -8192 -8192 -1062 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 467 +{ +( -1502 8192 8192 ) ( -1502 -8192 8192 ) ( -1502 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -1418 -8192 8192 ) ( -1418 8192 8192 ) ( -1418 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -994 8192 ) ( 8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -738 8192 ) ( -8192 -738 8192 ) ( -8192 -738 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1008 ) ( 8192 8192 -1008 ) ( -8192 -8192 -1008 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1006 ) ( 8192 -8192 -1006 ) ( -8192 -8192 -1006 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 468 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1496 -8192 8192 ) ( -1496 8192 8192 ) ( -1496 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -970 8192 ) ( 8192 -970 8192 ) ( -8192 -970 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1010 ) ( 8192 8192 -1010 ) ( -8192 -8192 -1010 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1000 ) ( 8192 -8192 -1000 ) ( -8192 -8192 -1000 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 469 +{ +( -1490 8192 8192 ) ( -1490 -8192 8192 ) ( -1490 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -990 8192 ) ( 8192 -990 8192 ) ( -8192 -990 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -968 8192 ) ( -8192 -968 8192 ) ( -8192 -968 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1006 ) ( 8192 8192 -1006 ) ( -8192 -8192 -1006 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1004 ) ( 8192 -8192 -1004 ) ( -8192 -8192 -1004 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 470 +{ +( -1450 8192 8192 ) ( -1450 -8192 8192 ) ( -1450 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1426 -8192 8192 ) ( -1426 8192 8192 ) ( -1426 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -942 8192 ) ( 8192 -942 8192 ) ( -8192 -942 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -920 8192 ) ( -8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1006 ) ( 8192 8192 -1006 ) ( -8192 -8192 -1006 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1004 ) ( 8192 -8192 -1004 ) ( -8192 -8192 -1004 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 471 +{ +( -1490 8192 8192 ) ( -1490 -8192 8192 ) ( -1490 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -924 8192 ) ( 8192 -924 8192 ) ( -8192 -924 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -902 8192 ) ( -8192 -902 8192 ) ( -8192 -902 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1006 ) ( 8192 8192 -1006 ) ( -8192 -8192 -1006 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1004 ) ( 8192 -8192 -1004 ) ( -8192 -8192 -1004 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 472 +{ +( -1452 8192 8192 ) ( -1452 -8192 8192 ) ( -1452 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1428 -8192 8192 ) ( -1428 8192 8192 ) ( -1428 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -876 8192 ) ( 8192 -876 8192 ) ( -8192 -876 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1006 ) ( 8192 8192 -1006 ) ( -8192 -8192 -1006 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1004 ) ( 8192 -8192 -1004 ) ( -8192 -8192 -1004 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 473 +{ +( -1488 8192 8192 ) ( -1488 -8192 8192 ) ( -1488 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1480 -8192 8192 ) ( -1480 8192 8192 ) ( -1480 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1006 ) ( 8192 8192 -1006 ) ( -8192 -8192 -1006 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1004 ) ( 8192 -8192 -1004 ) ( -8192 -8192 -1004 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 474 +{ +( -1472 8192 8192 ) ( -1472 -8192 8192 ) ( -1472 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1464 -8192 8192 ) ( -1464 8192 8192 ) ( -1464 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1006 ) ( 8192 8192 -1006 ) ( -8192 -8192 -1006 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1004 ) ( 8192 -8192 -1004 ) ( -8192 -8192 -1004 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 475 +{ +( -1472 8192 8192 ) ( -1472 -8192 8192 ) ( -1472 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1464 -8192 8192 ) ( -1464 8192 8192 ) ( -1464 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1034 ) ( 8192 8192 -1034 ) ( -8192 -8192 -1034 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1032 ) ( 8192 -8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 476 +{ +( -1488 8192 8192 ) ( -1488 -8192 8192 ) ( -1488 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1480 -8192 8192 ) ( -1480 8192 8192 ) ( -1480 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1034 ) ( 8192 8192 -1034 ) ( -8192 -8192 -1034 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1032 ) ( 8192 -8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 477 +{ +( -1452 8192 8192 ) ( -1452 -8192 8192 ) ( -1452 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1428 -8192 8192 ) ( -1428 8192 8192 ) ( -1428 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -876 8192 ) ( 8192 -876 8192 ) ( -8192 -876 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1034 ) ( 8192 8192 -1034 ) ( -8192 -8192 -1034 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1032 ) ( 8192 -8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 478 +{ +( -1490 8192 8192 ) ( -1490 -8192 8192 ) ( -1490 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -924 8192 ) ( 8192 -924 8192 ) ( -8192 -924 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -902 8192 ) ( -8192 -902 8192 ) ( -8192 -902 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1034 ) ( 8192 8192 -1034 ) ( -8192 -8192 -1034 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1032 ) ( 8192 -8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 479 +{ +( -1450 8192 8192 ) ( -1450 -8192 8192 ) ( -1450 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1426 -8192 8192 ) ( -1426 8192 8192 ) ( -1426 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -942 8192 ) ( 8192 -942 8192 ) ( -8192 -942 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -920 8192 ) ( -8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1034 ) ( 8192 8192 -1034 ) ( -8192 -8192 -1034 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1032 ) ( 8192 -8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 480 +{ +( -1490 8192 8192 ) ( -1490 -8192 8192 ) ( -1490 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -990 8192 ) ( 8192 -990 8192 ) ( -8192 -990 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -968 8192 ) ( -8192 -968 8192 ) ( -8192 -968 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1034 ) ( 8192 8192 -1034 ) ( -8192 -8192 -1034 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1032 ) ( 8192 -8192 -1032 ) ( -8192 -8192 -1032 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 481 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1496 -8192 8192 ) ( -1496 8192 8192 ) ( -1496 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -970 8192 ) ( 8192 -970 8192 ) ( -8192 -970 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1038 ) ( 8192 8192 -1038 ) ( -8192 -8192 -1038 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1028 ) ( 8192 -8192 -1028 ) ( -8192 -8192 -1028 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 482 +{ +( -1502 8192 8192 ) ( -1502 -8192 8192 ) ( -1502 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -1418 -8192 8192 ) ( -1418 8192 8192 ) ( -1418 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -994 8192 ) ( 8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -770 8192 ) ( -8192 -770 8192 ) ( -8192 -770 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1036 ) ( 8192 8192 -1036 ) ( -8192 -8192 -1036 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1034 ) ( 8192 -8192 -1034 ) ( -8192 -8192 -1034 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 483 +{ +( -1502 8192 8192 ) ( -1502 -8192 8192 ) ( -1502 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -1418 -8192 8192 ) ( -1418 8192 8192 ) ( -1418 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -994 8192 ) ( 8192 -994 8192 ) ( -8192 -994 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -778 8192 ) ( -8192 -778 8192 ) ( -8192 -778 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1084 ) ( 8192 8192 -1084 ) ( -8192 -8192 -1084 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1082 ) ( 8192 -8192 -1082 ) ( -8192 -8192 -1082 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 484 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1496 -8192 8192 ) ( -1496 8192 8192 ) ( -1496 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -970 8192 ) ( 8192 -970 8192 ) ( -8192 -970 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1086 ) ( 8192 8192 -1086 ) ( -8192 -8192 -1086 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1076 ) ( 8192 -8192 -1076 ) ( -8192 -8192 -1076 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 485 +{ +( -1490 8192 8192 ) ( -1490 -8192 8192 ) ( -1490 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -990 8192 ) ( 8192 -990 8192 ) ( -8192 -990 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -968 8192 ) ( -8192 -968 8192 ) ( -8192 -968 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1090 ) ( 8192 8192 -1090 ) ( -8192 -8192 -1090 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1088 ) ( 8192 -8192 -1088 ) ( -8192 -8192 -1088 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 486 +{ +( -1450 8192 8192 ) ( -1450 -8192 8192 ) ( -1450 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1426 -8192 8192 ) ( -1426 8192 8192 ) ( -1426 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -942 8192 ) ( 8192 -942 8192 ) ( -8192 -942 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -920 8192 ) ( -8192 -920 8192 ) ( -8192 -920 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1082 ) ( 8192 8192 -1082 ) ( -8192 -8192 -1082 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1080 ) ( 8192 -8192 -1080 ) ( -8192 -8192 -1080 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 487 +{ +( -1490 8192 8192 ) ( -1490 -8192 8192 ) ( -1490 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -924 8192 ) ( 8192 -924 8192 ) ( -8192 -924 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -902 8192 ) ( -8192 -902 8192 ) ( -8192 -902 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1082 ) ( 8192 8192 -1082 ) ( -8192 -8192 -1082 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1080 ) ( 8192 -8192 -1080 ) ( -8192 -8192 -1080 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 488 +{ +( -1452 8192 8192 ) ( -1452 -8192 8192 ) ( -1452 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1428 -8192 8192 ) ( -1428 8192 8192 ) ( -1428 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -876 8192 ) ( 8192 -876 8192 ) ( -8192 -876 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -854 8192 ) ( -8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1082 ) ( 8192 8192 -1082 ) ( -8192 -8192 -1082 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1080 ) ( 8192 -8192 -1080 ) ( -8192 -8192 -1080 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 489 +{ +( -1488 8192 8192 ) ( -1488 -8192 8192 ) ( -1488 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1480 -8192 8192 ) ( -1480 8192 8192 ) ( -1480 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1082 ) ( 8192 8192 -1082 ) ( -8192 -8192 -1082 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1080 ) ( 8192 -8192 -1080 ) ( -8192 -8192 -1080 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 490 +{ +( -1472 8192 8192 ) ( -1472 -8192 8192 ) ( -1472 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1464 -8192 8192 ) ( -1464 8192 8192 ) ( -1464 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -854 8192 ) ( 8192 -854 8192 ) ( -8192 -854 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -832 8192 ) ( -8192 -832 8192 ) ( -8192 -832 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1082 ) ( 8192 8192 -1082 ) ( -8192 -8192 -1082 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1080 ) ( 8192 -8192 -1080 ) ( -8192 -8192 -1080 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 491 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -850 8192 ) ( 8192 -850 8192 ) ( -8192 -850 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -828 8192 ) ( -8192 -828 8192 ) ( -8192 -828 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -994 ) ( 8192 8192 -994 ) ( -8192 -8192 -994 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -970 ) ( 8192 -8192 -970 ) ( -8192 -8192 -970 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 492 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -812 8192 ) ( 8192 -812 8192 ) ( -8192 -812 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -790 8192 ) ( -8192 -790 8192 ) ( -8192 -790 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -938 ) ( 8192 8192 -938 ) ( -8192 -8192 -938 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -914 ) ( 8192 -8192 -914 ) ( -8192 -8192 -914 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 493 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1498 -8192 8192 ) ( -1498 8192 8192 ) ( -1498 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -738 8192 ) ( 8192 -738 8192 ) ( -8192 -738 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -716 8192 ) ( -8192 -716 8192 ) ( -8192 -716 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1048 ) ( 8192 8192 -1048 ) ( -8192 -8192 -1048 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1036 ) ( 8192 -8192 -1036 ) ( -8192 -8192 -1036 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 494 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1498 -8192 8192 ) ( -1498 8192 8192 ) ( -1498 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -698 8192 ) ( 8192 -698 8192 ) ( -8192 -698 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -676 8192 ) ( -8192 -676 8192 ) ( -8192 -676 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1028 ) ( 8192 8192 -1028 ) ( -8192 -8192 -1028 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1016 ) ( 8192 -8192 -1016 ) ( -8192 -8192 -1016 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 495 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1498 -8192 8192 ) ( -1498 8192 8192 ) ( -1498 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -682 8192 ) ( 8192 -682 8192 ) ( -8192 -682 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -660 8192 ) ( -8192 -660 8192 ) ( -8192 -660 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1144 ) ( 8192 8192 -1144 ) ( -8192 -8192 -1144 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1132 ) ( 8192 -8192 -1132 ) ( -8192 -8192 -1132 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 496 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -708 8192 ) ( 8192 -708 8192 ) ( -8192 -708 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -686 8192 ) ( -8192 -686 8192 ) ( -8192 -686 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -934 ) ( 8192 8192 -934 ) ( -8192 -8192 -934 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -910 ) ( 8192 -8192 -910 ) ( -8192 -8192 -910 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 497 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -810 8192 ) ( 8192 -810 8192 ) ( -8192 -810 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -788 8192 ) ( -8192 -788 8192 ) ( -8192 -788 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -878 ) ( 8192 8192 -878 ) ( -8192 -8192 -878 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -854 ) ( 8192 -8192 -854 ) ( -8192 -8192 -854 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 498 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -628 8192 ) ( 8192 -628 8192 ) ( -8192 -628 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -606 8192 ) ( -8192 -606 8192 ) ( -8192 -606 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1114 ) ( 8192 8192 -1114 ) ( -8192 -8192 -1114 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1090 ) ( 8192 -8192 -1090 ) ( -8192 -8192 -1090 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 499 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -574 8192 ) ( 8192 -574 8192 ) ( -8192 -574 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -552 8192 ) ( -8192 -552 8192 ) ( -8192 -552 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1074 ) ( 8192 8192 -1074 ) ( -8192 -8192 -1074 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1050 ) ( 8192 -8192 -1050 ) ( -8192 -8192 -1050 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 500 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -582 8192 ) ( 8192 -582 8192 ) ( -8192 -582 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -560 8192 ) ( -8192 -560 8192 ) ( -8192 -560 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -976 ) ( 8192 8192 -976 ) ( -8192 -8192 -976 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -952 ) ( 8192 -8192 -952 ) ( -8192 -8192 -952 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 501 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -652 8192 ) ( 8192 -652 8192 ) ( -8192 -652 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -630 8192 ) ( -8192 -630 8192 ) ( -8192 -630 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -976 ) ( 8192 8192 -976 ) ( -8192 -8192 -976 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -952 ) ( 8192 -8192 -952 ) ( -8192 -8192 -952 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 502 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -636 8192 ) ( 8192 -636 8192 ) ( -8192 -636 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -614 8192 ) ( -8192 -614 8192 ) ( -8192 -614 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -906 ) ( 8192 8192 -906 ) ( -8192 -8192 -906 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -882 ) ( 8192 -8192 -882 ) ( -8192 -8192 -882 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 503 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1502 -8192 8192 ) ( -1502 8192 8192 ) ( -1502 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -566 8192 ) ( 8192 -566 8192 ) ( -8192 -566 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -544 8192 ) ( -8192 -544 8192 ) ( -8192 -544 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -906 ) ( 8192 8192 -906 ) ( -8192 -8192 -906 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -882 ) ( 8192 -8192 -882 ) ( -8192 -8192 -882 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 504 +{ +( -1465 8192 8192 ) ( -1465 -8192 8192 ) ( -1465 8192 -8192 ) desktop/yellowwire 0 0 45 0.500000 0.500000 0 0 0 +( -1463 -8192 8192 ) ( -1463 8192 8192 ) ( -1463 8192 -8192 ) desktop/yellowwire 0 0 45 0.500000 0.500000 0 0 0 +( -8192 -820 8192 ) ( 8192 -820 8192 ) ( -8192 -820 -8192 ) desktop/yellowwire 0 0 45 0.500000 0.500000 0 0 0 +( 8192 -678 8192 ) ( -8192 -678 8192 ) ( -8192 -678 -8192 ) desktop/yellowwire 0 0 45 0.500000 0.500000 0 0 0 +( 8192 -8192 -688 ) ( 8192 8192 -688 ) ( -8192 -8192 -688 ) desktop/yellowwire 0 0 45 0.500000 0.500000 0 0 0 +( 8192 8192 -686 ) ( 8192 -8192 -686 ) ( -8192 -8192 -686 ) desktop/yellowwire 0 0 45 0.500000 0.500000 0 0 0 +} +// brush 505 +{ +( -1474 8192 8192 ) ( -1474 -8192 8192 ) ( -1474 8192 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( -1472 -8192 8192 ) ( -1472 8192 8192 ) ( -1472 8192 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( -8192 -820 8192 ) ( 8192 -820 8192 ) ( -8192 -820 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( 8192 -678 8192 ) ( -8192 -678 8192 ) ( -8192 -678 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( 8192 -8192 -688 ) ( 8192 8192 -688 ) ( -8192 -8192 -688 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( 8192 8192 -686 ) ( 8192 -8192 -686 ) ( -8192 -8192 -686 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +} +// brush 506 +{ +( -1471 8192 8192 ) ( -1471 -8192 8192 ) ( -1471 8192 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( -1469 -8192 8192 ) ( -1469 8192 8192 ) ( -1469 8192 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( -8192 -820 8192 ) ( 8192 -820 8192 ) ( -8192 -820 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( 8192 -678 8192 ) ( -8192 -678 8192 ) ( -8192 -678 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( 8192 -8192 -688 ) ( 8192 8192 -688 ) ( -8192 -8192 -688 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( 8192 8192 -686 ) ( 8192 -8192 -686 ) ( -8192 -8192 -686 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +} +// brush 507 +{ +( -1468 8192 8192 ) ( -1468 -8192 8192 ) ( -1468 8192 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( -1466 -8192 8192 ) ( -1466 8192 8192 ) ( -1466 8192 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( -8192 -820 8192 ) ( 8192 -820 8192 ) ( -8192 -820 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( 8192 -678 8192 ) ( -8192 -678 8192 ) ( -8192 -678 -8192 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( 8192 -8192 -688 ) ( 8192 8192 -688 ) ( -8192 -8192 -688 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +( 8192 8192 -686 ) ( 8192 -8192 -686 ) ( -8192 -8192 -686 ) desktop/yellowwire 0 0 90 0.500000 0.500000 0 0 0 +} +// brush 508 +{ +( 7816 -8577 1027 ) ( 7816 6228 -5986 ) ( -8278 7539 -3218 ) desktop/yellowwire 0 0 67 0.500000 0.500000 0 0 0 +( 7830 6164 -6034 ) ( 7830 -8545 1181 ) ( -8278 -7229 3863 ) desktop/yellowwire 0 0 67 0.500000 0.500000 0 0 0 +( -6407 5892 7694 ) ( 8692 -465 7694 ) ( 5804 -7324 -6902 ) desktop/yellowwire 0 0 67 0.500000 0.500000 0 0 0 +( 8788 -238 7575 ) ( -6311 6119 7575 ) ( -9254 -868 -6948 ) desktop/yellowwire 0 0 67 0.500000 0.500000 0 0 0 +( -4087 -7174 8192 ) ( 2167 7968 8192 ) ( 2167 7968 -8192 ) desktop/yellowwire 0 0 150 0.500000 0.500000 0 0 0 +( 2156 7972 8192 ) ( -4096 -7171 8192 ) ( -4096 -7171 -8192 ) desktop/yellowwire 0 0 67 0.500000 0.500000 0 0 0 +} +// brush 509 +{ +( 92 8192 8192 ) ( 92 -8192 8192 ) ( 92 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 222 -8192 8192 ) ( 222 8192 8192 ) ( 222 8192 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -428 8192 ) ( 8192 -428 8192 ) ( -8192 -428 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -292 8192 ) ( -8192 -292 8192 ) ( -8192 -292 -8192 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 16 ) ( 8192 8192 16 ) ( -8192 -8192 16 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 18 ) ( 8192 -8192 18 ) ( -8192 -8192 18 ) desktop/ci2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 510 +{ +( 130 8192 8192 ) ( 130 -8192 8192 ) ( 130 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 136 -8192 8192 ) ( 136 8192 8192 ) ( 136 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -424 8192 ) ( 8192 -424 8192 ) ( -8192 -424 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -416 8192 ) ( -8192 -416 8192 ) ( -8192 -416 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 18 ) ( 8192 8192 18 ) ( -8192 -8192 18 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 112 ) ( 8192 -8192 112 ) ( -8192 -8192 112 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 511 +{ +( 182 8192 8192 ) ( 182 -8192 8192 ) ( 182 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 188 -8192 8192 ) ( 188 8192 8192 ) ( 188 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -424 8192 ) ( 8192 -424 8192 ) ( -8192 -424 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -416 8192 ) ( -8192 -416 8192 ) ( -8192 -416 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 18 ) ( 8192 8192 18 ) ( -8192 -8192 18 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 112 ) ( 8192 -8192 112 ) ( -8192 -8192 112 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 512 +{ +( 136 8192 8192 ) ( 136 -8192 8192 ) ( 136 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 182 -8192 8192 ) ( 182 8192 8192 ) ( 182 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -424 8192 ) ( 8192 -424 8192 ) ( -8192 -424 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -416 8192 ) ( -8192 -416 8192 ) ( -8192 -416 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 106 ) ( 8192 8192 106 ) ( -8192 -8192 106 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 112 ) ( 8192 -8192 112 ) ( -8192 -8192 112 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 513 +{ +( -1422 8192 8192 ) ( -1422 -8192 8192 ) ( -1422 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -1418 -8192 8192 ) ( -1418 8192 8192 ) ( -1418 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -962 8192 ) ( 8192 -962 8192 ) ( -8192 -962 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -954 8192 ) ( -8192 -954 8192 ) ( -8192 -954 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1006 ) ( 8192 8192 -1006 ) ( -8192 -8192 -1006 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -926 ) ( 8192 -8192 -926 ) ( -8192 -8192 -926 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 514 +{ +( -1502 8192 8192 ) ( -1502 -8192 8192 ) ( -1502 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -1422 -8192 8192 ) ( -1422 8192 8192 ) ( -1422 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -962 8192 ) ( 8192 -962 8192 ) ( -8192 -962 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -954 8192 ) ( -8192 -954 8192 ) ( -8192 -954 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -930 ) ( 8192 8192 -930 ) ( -8192 -8192 -930 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -926 ) ( 8192 -8192 -926 ) ( -8192 -8192 -926 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 515 +{ +( -1502 8192 8192 ) ( -1502 -8192 8192 ) ( -1502 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -1498 -8192 8192 ) ( -1498 8192 8192 ) ( -1498 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -962 8192 ) ( 8192 -962 8192 ) ( -8192 -962 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -954 8192 ) ( -8192 -954 8192 ) ( -8192 -954 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1006 ) ( 8192 8192 -1006 ) ( -8192 -8192 -1006 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -930 ) ( 8192 -8192 -930 ) ( -8192 -8192 -930 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 516 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1498 -8192 8192 ) ( -1498 8192 8192 ) ( -1498 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -658 8192 ) ( 8192 -658 8192 ) ( -8192 -658 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -636 8192 ) ( -8192 -636 8192 ) ( -8192 -636 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1124 ) ( 8192 8192 -1124 ) ( -8192 -8192 -1124 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1112 ) ( 8192 -8192 -1112 ) ( -8192 -8192 -1112 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 517 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1498 -8192 8192 ) ( -1498 8192 8192 ) ( -1498 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -706 8192 ) ( 8192 -706 8192 ) ( -8192 -706 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -684 8192 ) ( -8192 -684 8192 ) ( -8192 -684 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1164 ) ( 8192 8192 -1164 ) ( -8192 -8192 -1164 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1152 ) ( 8192 -8192 -1152 ) ( -8192 -8192 -1152 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 518 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1498 -8192 8192 ) ( -1498 8192 8192 ) ( -1498 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -730 8192 ) ( 8192 -730 8192 ) ( -8192 -730 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -708 8192 ) ( -8192 -708 8192 ) ( -8192 -708 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1184 ) ( 8192 8192 -1184 ) ( -8192 -8192 -1184 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1172 ) ( 8192 -8192 -1172 ) ( -8192 -8192 -1172 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 519 +{ +( -1504 8192 8192 ) ( -1504 -8192 8192 ) ( -1504 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -1498 -8192 8192 ) ( -1498 8192 8192 ) ( -1498 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -602 8192 ) ( 8192 -602 8192 ) ( -8192 -602 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -580 8192 ) ( -8192 -580 8192 ) ( -8192 -580 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1084 ) ( 8192 8192 -1084 ) ( -8192 -8192 -1084 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1072 ) ( 8192 -8192 -1072 ) ( -8192 -8192 -1072 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 520 +{ +( 1600 8192 8192 ) ( 1600 -8192 8192 ) ( 1600 8192 -8192 ) desktop/border 0 0 0 0.250000 0.250000 0 0 0 +( 1904 -8192 8192 ) ( 1904 8192 8192 ) ( 1904 8192 -8192 ) desktop/border 0 45 0 -27 0.880000 0 0 0 +( -8192 232 8192 ) ( 8192 232 8192 ) ( -8192 232 -8192 ) desktop/border 2 45 0 0.050000 0.250000 0 0 0 +( 8192 448 8192 ) ( -8192 448 8192 ) ( -8192 448 -8192 ) desktop/jspbookside -72 -56 270 -1.600000 1.100000 0 0 0 +( 8192 -8192 -136 ) ( 8192 8192 -136 ) ( -8192 -8192 -136 ) desktop/jspbookcover 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -48 ) ( 8192 -8192 -48 ) ( -8192 -8192 -48 ) desktop/jspbookcover -72 53 270 1.100000 1.200000 0 0 0 +} +// brush 521 +{ +( 436 8192 8192 ) ( 436 -8192 8192 ) ( 436 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 844 -8192 8192 ) ( 844 8192 8192 ) ( 844 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 2844 8192 ) ( 8192 2844 8192 ) ( -8192 2844 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 3216 8192 ) ( -8192 3216 8192 ) ( -8192 3216 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 1588 ) ( 8192 8192 1588 ) ( -8192 -8192 1588 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 1592 ) ( 8192 -8192 1592 ) ( -8192 -8192 1592 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 522 +{ +( -1476 8192 8192 ) ( -1476 -8192 8192 ) ( -1476 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1348 -8192 8192 ) ( -1348 8192 8192 ) ( -1348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -380 8192 ) ( 8192 -380 8192 ) ( -8192 -380 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -372 8192 ) ( -8192 -372 8192 ) ( -8192 -372 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -694 ) ( 8192 8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -682 ) ( 8192 -8192 -682 ) ( -8192 -8192 -682 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 523 +{ +( -1352 -8192 8192 ) ( -1352 8192 8192 ) ( -1352 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -404 8192 ) ( 8192 -404 8192 ) ( -8192 -404 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -380 8192 ) ( -8192 -380 8192 ) ( -8192 -380 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -694 ) ( 8192 8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -690 ) ( 8192 -8192 -690 ) ( -8192 -8192 -690 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5279 6306 8192 ) ( -6306 -5279 8192 ) ( -6306 -5279 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 524 +{ +( -1352 -8192 8192 ) ( -1352 8192 8192 ) ( -1352 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -404 8192 ) ( -8192 -404 8192 ) ( -8192 -404 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -694 ) ( 8192 8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -690 ) ( 8192 -8192 -690 ) ( -8192 -8192 -690 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6690 4895 8192 ) ( 4895 -6690 8192 ) ( 4895 -6690 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 525 +{ +( -1352 -8192 8192 ) ( -1352 8192 8192 ) ( -1352 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -522 8192 ) ( 8192 -522 8192 ) ( -8192 -522 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -694 ) ( 8192 8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -690 ) ( 8192 -8192 -690 ) ( -8192 -8192 -690 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5347 6238 8192 ) ( -6238 -5347 8192 ) ( -6238 -5347 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 526 +{ +( -1363 8192 8192 ) ( -1363 -8192 8192 ) ( -1363 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1352 -8192 8192 ) ( -1352 8192 8192 ) ( -1352 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -694 ) ( 8192 8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -690 ) ( 8192 -8192 -690 ) ( -8192 -8192 -690 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 4895 -6690 8192 ) ( -6690 4895 8192 ) ( 4895 -6690 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6238 -5347 8192 ) ( 5347 6238 8192 ) ( -6238 -5347 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 527 +{ +( -1363 8192 8192 ) ( -1363 -8192 8192 ) ( -1363 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1348 -8192 8192 ) ( -1348 8192 8192 ) ( -1348 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -522 8192 ) ( 8192 -522 8192 ) ( -8192 -522 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -372 8192 ) ( -8192 -372 8192 ) ( -8192 -372 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -694 ) ( 8192 -8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 528 +{ +( -1363 -8192 8192 ) ( -1363 8192 8192 ) ( -1363 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -372 8192 ) ( -8192 -372 8192 ) ( -8192 -372 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -694 ) ( 8192 -8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6690 4895 8192 ) ( 4895 -6690 8192 ) ( 4895 -6690 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 529 +{ +( -1459 8192 8192 ) ( -1459 -8192 8192 ) ( -1459 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -380 8192 ) ( -8192 -380 8192 ) ( -8192 -380 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -694 ) ( 8192 8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -690 ) ( 8192 -8192 -690 ) ( -8192 -8192 -690 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6306 -5279 8192 ) ( 5279 6306 8192 ) ( -6306 -5279 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 530 +{ +( -1472 8192 8192 ) ( -1472 -8192 8192 ) ( -1472 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1459 -8192 8192 ) ( -1459 8192 8192 ) ( -1459 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -380 8192 ) ( -8192 -380 8192 ) ( -8192 -380 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -694 ) ( 8192 8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -690 ) ( 8192 -8192 -690 ) ( -8192 -8192 -690 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6758 4827 8192 ) ( 4827 -6758 8192 ) ( 4827 -6758 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 531 +{ +( -1476 8192 8192 ) ( -1476 -8192 8192 ) ( -1476 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1459 -8192 8192 ) ( -1459 8192 8192 ) ( -1459 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -522 8192 ) ( 8192 -522 8192 ) ( -8192 -522 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -694 ) ( 8192 -8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5279 6306 8192 ) ( -6306 -5279 8192 ) ( -6306 -5279 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 532 +{ +( -1476 8192 8192 ) ( -1476 -8192 8192 ) ( -1476 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -404 8192 ) ( -8192 -404 8192 ) ( -8192 -404 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -694 ) ( 8192 -8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6306 -5279 8192 ) ( 5279 6306 8192 ) ( -6306 -5279 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 533 +{ +( -1443 8192 8192 ) ( -1443 -8192 8192 ) ( -1443 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -404 8192 ) ( -8192 -404 8192 ) ( -8192 -404 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -698 ) ( 8192 -8192 -698 ) ( -8192 -8192 -698 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6294 -5291 8192 ) ( 5291 6294 8192 ) ( 5291 6294 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5279 6306 8192 ) ( -6306 -5279 8192 ) ( -6306 -5279 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 534 +{ +( -8192 -420 8192 ) ( 8192 -420 8192 ) ( -8192 -420 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -404 8192 ) ( -8192 -404 8192 ) ( -8192 -404 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -698 ) ( 8192 -8192 -698 ) ( -8192 -8192 -698 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5291 6294 8192 ) ( -6294 -5291 8192 ) ( 5291 6294 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 4895 -6690 8192 ) ( -6690 4895 8192 ) ( 4895 -6690 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 535 +{ +( -1459 8192 8192 ) ( -1459 -8192 8192 ) ( -1459 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1443 -8192 8192 ) ( -1443 8192 8192 ) ( -1443 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -698 ) ( 8192 -8192 -698 ) ( -8192 -8192 -698 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6748 4837 8192 ) ( 4837 -6748 8192 ) ( 4837 -6748 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5279 6306 8192 ) ( -6306 -5279 8192 ) ( -6306 -5279 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 536 +{ +( -1459 8192 8192 ) ( -1459 -8192 8192 ) ( -1459 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -488 8192 ) ( 8192 -488 8192 ) ( -8192 -488 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -698 ) ( 8192 -8192 -698 ) ( -8192 -8192 -698 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6758 4827 8192 ) ( 4827 -6758 8192 ) ( 4827 -6758 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 4837 -6748 8192 ) ( -6748 4837 8192 ) ( 4837 -6748 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 537 +{ +( -1472 8192 8192 ) ( -1472 -8192 8192 ) ( -1472 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -500 8192 ) ( 8192 -500 8192 ) ( -8192 -500 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -694 ) ( 8192 8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -690 ) ( 8192 -8192 -690 ) ( -8192 -8192 -690 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 4827 -6758 8192 ) ( -6758 4827 8192 ) ( 4827 -6758 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 538 +{ +( -1472 8192 8192 ) ( -1472 -8192 8192 ) ( -1472 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -522 8192 ) ( 8192 -522 8192 ) ( -8192 -522 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -500 8192 ) ( -8192 -500 8192 ) ( -8192 -500 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -694 ) ( 8192 8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -690 ) ( 8192 -8192 -690 ) ( -8192 -8192 -690 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6238 -5347 8192 ) ( 5347 6238 8192 ) ( -6238 -5347 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 539 +{ +( -8192 -500 8192 ) ( 8192 -500 8192 ) ( -8192 -500 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -488 8192 ) ( -8192 -488 8192 ) ( -8192 -488 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -698 ) ( 8192 -8192 -698 ) ( -8192 -8192 -698 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6246 -5339 8192 ) ( 5339 6246 8192 ) ( 5339 6246 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6758 4827 8192 ) ( 4827 -6758 8192 ) ( 4827 -6758 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 540 +{ +( -1363 -8192 8192 ) ( -1363 8192 8192 ) ( -1363 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -522 8192 ) ( 8192 -522 8192 ) ( -8192 -522 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -500 8192 ) ( -8192 -500 8192 ) ( -8192 -500 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -694 ) ( 8192 -8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6758 4827 8192 ) ( 4827 -6758 8192 ) ( 4827 -6758 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 541 +{ +( -1459 8192 8192 ) ( -1459 -8192 8192 ) ( -1459 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -522 8192 ) ( 8192 -522 8192 ) ( -8192 -522 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -694 ) ( 8192 -8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 4827 -6758 8192 ) ( -6758 4827 8192 ) ( 4827 -6758 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 542 +{ +( -1363 -8192 8192 ) ( -1363 8192 8192 ) ( -1363 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -500 8192 ) ( 8192 -500 8192 ) ( -8192 -500 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -698 ) ( 8192 -8192 -698 ) ( -8192 -8192 -698 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6238 -5347 8192 ) ( 5347 6238 8192 ) ( -6238 -5347 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5339 6246 8192 ) ( -6246 -5339 8192 ) ( 5339 6246 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 543 +{ +( -1363 -8192 8192 ) ( -1363 8192 8192 ) ( -1363 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -500 8192 ) ( 8192 -500 8192 ) ( -8192 -500 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -694 ) ( 8192 -8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5347 6238 8192 ) ( -6238 -5347 8192 ) ( -6238 -5347 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 544 +{ +( -1375 8192 8192 ) ( -1375 -8192 8192 ) ( -1375 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1363 -8192 8192 ) ( -1363 8192 8192 ) ( -1363 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -698 ) ( 8192 -8192 -698 ) ( -8192 -8192 -698 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 4885 -6700 8192 ) ( -6700 4885 8192 ) ( -6700 4885 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6246 -5339 8192 ) ( 5339 6246 8192 ) ( 5339 6246 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 545 +{ +( -1363 -8192 8192 ) ( -1363 8192 8192 ) ( -1363 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -420 8192 ) ( -8192 -420 8192 ) ( -8192 -420 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -698 ) ( 8192 -8192 -698 ) ( -8192 -8192 -698 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 4895 -6690 8192 ) ( -6690 4895 8192 ) ( 4895 -6690 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -6700 4885 8192 ) ( 4885 -6700 8192 ) ( -6700 4885 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 546 +{ +( -1476 8192 8192 ) ( -1476 -8192 8192 ) ( -1476 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -404 8192 ) ( 8192 -404 8192 ) ( -8192 -404 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -372 8192 ) ( -8192 -372 8192 ) ( -8192 -372 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -702 ) ( 8192 8192 -702 ) ( -8192 -8192 -702 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -694 ) ( 8192 -8192 -694 ) ( -8192 -8192 -694 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 4895 -6690 8192 ) ( -6690 4895 8192 ) ( 4895 -6690 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 547 +{ +( -2160 8192 8192 ) ( -2160 -8192 8192 ) ( -2160 8192 -8192 ) desktop/ceiling 0 0 0 1.400000 1.400000 0 0 0 +( 2120 -8192 8192 ) ( 2120 8192 8192 ) ( 2120 8192 -8192 ) desktop/ceiling 0 0 0 1.400000 1.400000 0 0 0 +( -8192 -1424 8192 ) ( 8192 -1424 8192 ) ( -8192 -1424 -8192 ) desktop/ceiling 0 0 0 1.400000 1.400000 0 0 0 +( 8192 2648 8192 ) ( -8192 2648 8192 ) ( -8192 2648 -8192 ) desktop/ceiling 0 0 0 1.400000 1.400000 0 0 0 +( 8192 -8192 1596 ) ( 8192 8192 1596 ) ( -8192 -8192 1596 ) desktop/ceiling 0 0 0 1.400000 1.400000 0 0 0 +( 8192 8192 1608 ) ( 8192 -8192 1608 ) ( -8192 -8192 1608 ) desktop/ceiling 0 0 0 1.400000 1.400000 0 0 0 +} +// brush 548 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -251 8192 ) ( 8192 -251 8192 ) ( -8192 -251 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -209 8192 ) ( -8192 -209 8192 ) ( -8192 -209 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -93 ) ( 8192 8192 -93 ) ( -8192 -8192 -93 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -51 ) ( 8192 -8192 -51 ) ( -8192 -8192 -51 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5699 5885 ) ( -8192 5699 5885 ) ( -8192 -5817 -5768 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -5976 5606 ) ( 8192 5677 -5909 ) ( -8192 5677 -5909 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7876 -2255 ) ( 8192 -7936 2033 ) ( -8192 7876 -2255 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5677 -5909 ) ( 8192 -5975 5607 ) ( -8192 -5975 5607 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 549 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -399 8192 ) ( 8192 -399 8192 ) ( -8192 -399 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -251 8192 ) ( -8192 -251 8192 ) ( -8192 -251 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -51 ) ( 8192 8192 -51 ) ( -8192 -8192 -51 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -11 ) ( 8192 -8192 -11 ) ( -8192 -8192 -11 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5677 -5909 ) ( 8192 -5976 5606 ) ( -8192 5677 -5909 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7936 2033 ) ( 8192 7876 -2255 ) ( -8192 7876 -2255 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1775 8006 ) ( 8192 1775 8006 ) ( 8192 -2513 -7806 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7876 -2254 ) ( 8192 -7936 2034 ) ( -8192 -7936 2034 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 550 +{ +( 1436 8192 8192 ) ( 1436 -8192 8192 ) ( 1436 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1580 -8192 8192 ) ( 1580 8192 8192 ) ( 1580 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -215 8192 ) ( -8192 -215 8192 ) ( -8192 -215 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -30 ) ( 8192 -8192 -30 ) ( -8192 -8192 -30 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8171 -8191 -591 ) ( 8171 8191 -591 ) ( -8156 8191 769 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8177 -8191 519 ) ( 8177 8191 519 ) ( -8150 8191 -840 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 551 +{ +( 1412 8192 8192 ) ( 1412 -8192 8192 ) ( 1412 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1604 -8192 8192 ) ( 1604 8192 8192 ) ( 1604 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -215 8192 ) ( -8192 -215 8192 ) ( -8192 -215 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -30 ) ( 8192 8192 -30 ) ( -8192 -8192 -30 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -12 ) ( 8192 -8192 -12 ) ( -8192 -8192 -12 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7056 -8192 -4245 ) ( 7056 8192 -4245 ) ( -6051 8192 5585 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7136 -8192 4137 ) ( 7136 8192 4137 ) ( -5970 8192 -5692 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 552 +{ +( 1412 8192 8192 ) ( 1412 -8192 8192 ) ( 1412 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1604 -8192 8192 ) ( 1604 8192 8192 ) ( 1604 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -201 8192 ) ( 8192 -201 8192 ) ( -8192 -201 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -30 ) ( 8192 8192 -30 ) ( -8192 -8192 -30 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -12 ) ( 8192 -8192 -12 ) ( -8192 -8192 -12 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7136 -8192 4137 ) ( 7136 8192 4137 ) ( -5970 8192 -5692 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7056 -8192 -4245 ) ( 7056 8192 -4245 ) ( -6051 8192 5585 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 553 +{ +( 1436 8192 8192 ) ( 1436 -8192 8192 ) ( 1436 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1580 -8192 8192 ) ( 1580 8192 8192 ) ( 1580 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -201 8192 ) ( 8192 -201 8192 ) ( -8192 -201 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -30 ) ( 8192 -8192 -30 ) ( -8192 -8192 -30 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8177 -8191 519 ) ( 8177 8191 519 ) ( -8150 8191 -840 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8171 -8191 -591 ) ( 8171 8191 -591 ) ( -8156 8191 769 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 554 +{ +( 1412 8192 8192 ) ( 1412 -8192 8192 ) ( 1412 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1436 -8192 8192 ) ( 1436 8192 8192 ) ( 1436 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -30 ) ( 8192 8192 -30 ) ( -8192 -8192 -30 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -12 ) ( 8192 -8192 -12 ) ( -8192 -8192 -12 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7056 -8192 -4245 ) ( 7056 8192 -4245 ) ( -6051 8192 5585 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7056 8192 -4244 ) ( 7056 -8192 -4244 ) ( -6050 -8192 5586 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8171 -8191 -591 ) ( 8171 8191 -591 ) ( -8156 8191 769 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5824 8192 5871 ) ( 5824 -8192 5871 ) ( -4005 -8192 -7235 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 555 +{ +( 1436 8192 8192 ) ( 1436 -8192 8192 ) ( 1436 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1508 -8192 8192 ) ( 1508 8192 8192 ) ( 1508 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -30 ) ( 8192 -8192 -30 ) ( -8192 -8192 -30 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8171 -8191 -591 ) ( 8171 8191 -591 ) ( -8156 8191 769 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8171 8191 -590 ) ( 8171 -8191 -590 ) ( -8156 -8191 770 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8177 -8191 519 ) ( 8177 8191 519 ) ( -8150 8191 -840 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7056 -8192 -4245 ) ( 7056 8192 -4245 ) ( -6051 8192 5585 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 556 +{ +( 1508 8192 8192 ) ( 1508 -8192 8192 ) ( 1508 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1580 -8192 8192 ) ( 1580 8192 8192 ) ( 1580 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -30 ) ( 8192 -8192 -30 ) ( -8192 -8192 -30 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8177 -8191 519 ) ( 8177 8191 519 ) ( -8150 8191 -840 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8176 8191 520 ) ( 8176 -8191 520 ) ( -8150 -8191 -839 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7136 -8192 4137 ) ( 7136 8192 4137 ) ( -5970 8192 -5692 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8171 -8191 -591 ) ( 8171 8191 -591 ) ( -8156 8191 769 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 557 +{ +( 1580 8192 8192 ) ( 1580 -8192 8192 ) ( 1580 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1604 -8192 8192 ) ( 1604 8192 8192 ) ( 1604 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -216 8192 ) ( 8192 -216 8192 ) ( -8192 -216 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -200 8192 ) ( -8192 -200 8192 ) ( -8192 -200 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -30 ) ( 8192 8192 -30 ) ( -8192 -8192 -30 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -12 ) ( 8192 -8192 -12 ) ( -8192 -8192 -12 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7136 -8192 4137 ) ( 7136 8192 4137 ) ( -5970 8192 -5692 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7136 8192 4138 ) ( 7136 -8192 4138 ) ( -5970 -8192 -5692 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -3894 -8192 7319 ) ( -3894 8192 7319 ) ( 5936 8192 -5787 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8177 -8191 519 ) ( 8177 8191 519 ) ( -8150 8191 -840 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 558 +{ +( 1152 8192 8192 ) ( 1152 -8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -129 8192 ) ( 8192 -129 8192 ) ( -8192 -129 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -4868 -8192 6716 ) ( -4868 8192 6716 ) ( 6716 8192 -4868 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1152 8192 8192 ) ( 1152 -8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 559 +{ +( 1152 8192 8192 ) ( 1152 -8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -535 8192 ) ( -8192 -535 8192 ) ( -8192 -535 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -4868 -8192 6716 ) ( -4868 8192 6716 ) ( 6716 8192 -4868 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 560 +{ +( 1152 8192 8192 ) ( 1152 -8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1153 -8192 8192 ) ( 1153 8192 8192 ) ( 1153 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 692 ) ( 8192 8192 692 ) ( -8192 -8192 692 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -4868 -8192 6716 ) ( -4868 8192 6716 ) ( 6716 8192 -4868 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 561 +{ +( 1152 8192 8192 ) ( 1152 -8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -4869 8192 6715 ) ( -4869 -8192 6715 ) ( 6715 -8192 -4869 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -4868 -8192 6716 ) ( -4868 8192 6716 ) ( 6716 8192 -4868 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 562 +{ +( 1152 8192 8192 ) ( 1152 -8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1160 -8192 8192 ) ( 1160 8192 8192 ) ( 1160 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 689 ) ( 8192 -8192 689 ) ( -8192 -8192 689 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -4868 -8192 6716 ) ( -4868 8192 6716 ) ( 6716 8192 -4868 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 563 +{ +( 1152 8192 8192 ) ( 1152 -8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1153 -8192 8192 ) ( 1153 8192 8192 ) ( 1153 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 692 ) ( 8192 -8192 692 ) ( -8192 -8192 692 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 564 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 336 -8192 8192 ) ( 336 8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -129 8192 ) ( 8192 -129 8192 ) ( -8192 -129 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5612 8192 5972 ) ( 5612 -8192 5972 ) ( -5972 -8192 -5612 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 565 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 336 -8192 8192 ) ( 336 8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -535 8192 ) ( -8192 -535 8192 ) ( -8192 -535 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5612 8192 5972 ) ( 5612 -8192 5972 ) ( -5972 -8192 -5612 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 566 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 332 -8192 8192 ) ( 332 8192 8192 ) ( 332 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 689 ) ( 8192 -8192 689 ) ( -8192 -8192 689 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5612 8192 5972 ) ( 5612 -8192 5972 ) ( -5972 -8192 -5612 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 567 +{ +( 328 8192 8192 ) ( 328 -8192 8192 ) ( 328 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 336 -8192 8192 ) ( 336 8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5612 8192 5972 ) ( 5612 -8192 5972 ) ( -5972 -8192 -5612 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5613 -8192 5971 ) ( 5613 8192 5971 ) ( -5971 8192 -5613 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 568 +{ +( 335 8192 8192 ) ( 335 -8192 8192 ) ( 335 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 336 -8192 8192 ) ( 336 8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 5612 8192 5972 ) ( 5612 -8192 5972 ) ( -5972 -8192 -5612 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 569 +{ +( 332 8192 8192 ) ( 332 -8192 8192 ) ( 332 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 336 -8192 8192 ) ( 336 8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -536 8192 ) ( 8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -128 8192 ) ( -8192 -128 8192 ) ( -8192 -128 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 688 ) ( 8192 8192 688 ) ( -8192 -8192 688 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 689 ) ( 8192 -8192 689 ) ( -8192 -8192 689 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 570 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -468 8192 ) ( 8192 -468 8192 ) ( -8192 -468 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8192 ) ( -8192 -312 8192 ) ( -8192 -312 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -24 ) ( 8192 8192 -24 ) ( -8192 -8192 -24 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 10 ) ( 8192 -8192 10 ) ( -8192 -8192 10 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8018 1677 ) ( 8192 7979 -1855 ) ( -8192 7979 -1855 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8025 -1645 ) ( 8192 -8055 1488 ) ( -8192 -8055 1488 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7929 -2058 ) ( 8192 -7976 1867 ) ( -8192 -7976 1867 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 571 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -495 8192 ) ( 8192 -495 8192 ) ( -8192 -495 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -288 8192 ) ( -8192 -288 8192 ) ( -8192 -288 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 14 ) ( 8192 -8192 14 ) ( -8192 -8192 14 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7287 -3744 ) ( 8192 -7427 3459 ) ( -8192 -7427 3459 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8018 1681 ) ( 8192 7975 -1872 ) ( -8192 7975 -1872 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7979 -1855 ) ( 8192 -8018 1677 ) ( -8192 7979 -1855 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 10 ) ( 8192 -8192 10 ) ( -8192 -8192 10 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 572 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -495 8192 ) ( 8192 -495 8192 ) ( -8192 -495 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -288 8192 ) ( -8192 -288 8192 ) ( -8192 -288 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 14 ) ( 8192 -8192 14 ) ( -8192 -8192 14 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7287 -3744 ) ( 8192 -7427 3459 ) ( -8192 -7427 3459 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7979 -1855 ) ( 8192 -8018 1677 ) ( -8192 7979 -1855 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8018 1681 ) ( 8192 7975 -1872 ) ( -8192 7975 -1872 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 10 ) ( 8192 -8192 10 ) ( -8192 -8192 10 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 573 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -468 8192 ) ( 8192 -468 8192 ) ( -8192 -468 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8192 ) ( -8192 -312 8192 ) ( -8192 -312 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -24 ) ( 8192 8192 -24 ) ( -8192 -8192 -24 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 10 ) ( 8192 -8192 10 ) ( -8192 -8192 10 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8018 1677 ) ( 8192 7979 -1855 ) ( -8192 7979 -1855 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7929 -2058 ) ( 8192 -7976 1867 ) ( -8192 -7976 1867 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8025 -1645 ) ( 8192 -8055 1488 ) ( -8192 -8055 1488 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 574 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -312 8192 ) ( 8192 -312 8192 ) ( -8192 -312 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -288 8192 ) ( -8192 -288 8192 ) ( -8192 -288 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -24 ) ( 8192 -8192 -24 ) ( -8192 -8192 -24 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 3384 7464 ) ( -8192 3384 7464 ) ( -8192 -3820 -7250 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7427 3458 ) ( 8192 7287 -3745 ) ( -8192 7287 -3745 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7929 -2058 ) ( 8192 -7976 1867 ) ( -8192 -7976 1867 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7287 -3744 ) ( 8192 -7427 3459 ) ( -8192 -7427 3459 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 575 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -390 8192 ) ( 8192 -390 8192 ) ( -8192 -390 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -312 8192 ) ( -8192 -312 8192 ) ( -8192 -312 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -24 ) ( 8192 8192 -24 ) ( -8192 -8192 -24 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -5 ) ( 8192 -8192 -5 ) ( -8192 -8192 -5 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7287 -3744 ) ( 8192 -7427 3459 ) ( -8192 -7427 3459 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7977 1866 ) ( 8192 7929 -2059 ) ( -8192 7929 -2059 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8025 -1645 ) ( 8192 -8055 1488 ) ( -8192 -8055 1488 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7929 -2058 ) ( 8192 -7976 1867 ) ( -8192 -7976 1867 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 576 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -468 8192 ) ( 8192 -468 8192 ) ( -8192 -468 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -390 8192 ) ( -8192 -390 8192 ) ( -8192 -390 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -5 ) ( 8192 8192 -5 ) ( -8192 -8192 -5 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 14 ) ( 8192 -8192 14 ) ( -8192 -8192 14 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7929 -2058 ) ( 8192 -7976 1867 ) ( -8192 -7976 1867 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8056 1488 ) ( 8192 8025 -1646 ) ( -8192 8025 -1646 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8025 -1645 ) ( 8192 -8055 1488 ) ( -8192 -8055 1488 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 10 ) ( 8192 -8192 10 ) ( -8192 -8192 10 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 577 +{ +( 1728 8192 8192 ) ( 1728 -8192 8192 ) ( 1728 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1784 -8192 8192 ) ( 1784 8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1290 8192 ) ( 8192 -1290 8192 ) ( -8192 -1290 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1206 8192 ) ( -8192 -1206 8192 ) ( -8192 -1206 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1409 8165 8192 ) ( 3771 -7378 8192 ) ( 3771 -7378 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4276 -7308 8192 ) ( 7308 4276 8192 ) ( 7308 4276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4520 7128 8192 ) ( -660 -8414 8192 ) ( -660 -8414 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6060 -5524 8192 ) ( -5524 6060 8192 ) ( -5524 6060 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 578 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1304 8192 ) ( 8192 -1304 8192 ) ( -8192 -1304 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1248 8192 ) ( -8192 -1248 8192 ) ( -8192 -1248 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7984 1952 8192 ) ( 7558 -3228 8192 ) ( 7558 -3228 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7202 -4299 8192 ) ( 8341 881 8192 ) ( 8341 881 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7308 4276 8192 ) ( -4276 -7308 8192 ) ( 7308 4276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6060 -5524 8192 ) ( -5524 6060 8192 ) ( -5524 6060 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 579 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1248 8192 ) ( 8192 -1248 8192 ) ( -8192 -1248 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1192 8192 ) ( -8192 -1192 8192 ) ( -8192 -1192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5524 6060 8192 ) ( 6060 -5524 8192 ) ( -5524 6060 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4276 -7308 8192 ) ( 7308 4276 8192 ) ( 7308 4276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8307 982 8192 ) ( -7235 -4198 8192 ) ( -7235 -4198 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7592 -3128 8192 ) ( -7950 2052 8192 ) ( -7950 2052 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 580 +{ +( 1784 8192 8192 ) ( 1784 -8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1840 -8192 8192 ) ( 1840 8192 8192 ) ( 1840 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1290 8192 ) ( 8192 -1290 8192 ) ( -8192 -1290 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1206 8192 ) ( -8192 -1206 8192 ) ( -8192 -1206 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5524 6060 8192 ) ( 6060 -5524 8192 ) ( -5524 6060 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -560 -8448 8192 ) ( 4620 7094 8192 ) ( 4620 7094 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7308 4276 8192 ) ( -4276 -7308 8192 ) ( 7308 4276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3872 -7344 8192 ) ( -1308 8198 8192 ) ( -1308 8198 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 581 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -1248 8192 ) ( 8192 -1248 8192 ) ( -8192 -1248 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -1192 8192 ) ( -8192 -1192 8192 ) ( -8192 -1192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -4276 -7308 8192 ) ( 7308 4276 8192 ) ( 7308 4276 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7592 -3128 8192 ) ( -7950 2052 8192 ) ( -7950 2052 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8307 982 8192 ) ( -7235 -4198 8192 ) ( -7235 -4198 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -5524 6060 8192 ) ( 6060 -5524 8192 ) ( -5524 6060 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 582 +{ +( 1784 8192 8192 ) ( 1784 -8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1840 -8192 8192 ) ( 1840 8192 8192 ) ( 1840 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1290 8192 ) ( 8192 -1290 8192 ) ( -8192 -1290 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1206 8192 ) ( -8192 -1206 8192 ) ( -8192 -1206 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -560 -8448 8192 ) ( 4620 7094 8192 ) ( 4620 7094 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3872 -7344 8192 ) ( -1308 8198 8192 ) ( -1308 8198 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7308 4276 8192 ) ( -4276 -7308 8192 ) ( 7308 4276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5524 6060 8192 ) ( 6060 -5524 8192 ) ( -5524 6060 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 583 +{ +( 1728 8192 8192 ) ( 1728 -8192 8192 ) ( 1728 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1784 -8192 8192 ) ( 1784 8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1290 8192 ) ( 8192 -1290 8192 ) ( -8192 -1290 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1206 8192 ) ( -8192 -1206 8192 ) ( -8192 -1206 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4276 -7308 8192 ) ( 7308 4276 8192 ) ( 7308 4276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6060 -5524 8192 ) ( -5524 6060 8192 ) ( -5524 6060 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4520 7128 8192 ) ( -660 -8414 8192 ) ( -660 -8414 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1409 8165 8192 ) ( 3771 -7378 8192 ) ( 3771 -7378 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 584 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1304 8192 ) ( 8192 -1304 8192 ) ( -8192 -1304 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1248 8192 ) ( -8192 -1248 8192 ) ( -8192 -1248 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7202 -4299 8192 ) ( 8341 881 8192 ) ( 8341 881 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6060 -5524 8192 ) ( -5524 6060 8192 ) ( -5524 6060 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7308 4276 8192 ) ( -4276 -7308 8192 ) ( 7308 4276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7984 1952 8192 ) ( 7558 -3228 8192 ) ( 7558 -3228 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 585 +{ +( 1728 8192 8192 ) ( 1728 -8192 8192 ) ( 1728 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1742 -8192 8192 ) ( 1742 8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1290 8192 ) ( 8192 -1290 8192 ) ( -8192 -1290 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1248 8192 ) ( -8192 -1248 8192 ) ( -8192 -1248 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1409 8165 8192 ) ( 3771 -7378 8192 ) ( 3771 -7378 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3772 -7377 8192 ) ( -1408 8165 8192 ) ( -1408 8165 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4520 7128 8192 ) ( -660 -8414 8192 ) ( -660 -8414 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7984 1952 8192 ) ( 7558 -3228 8192 ) ( 7558 -3228 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 586 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1784 -8192 8192 ) ( 1784 8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1304 8192 ) ( 8192 -1304 8192 ) ( -8192 -1304 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1290 8192 ) ( -8192 -1290 8192 ) ( -8192 -1290 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7984 1952 8192 ) ( 7558 -3228 8192 ) ( 7558 -3228 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7559 -3227 8192 ) ( -7984 1953 8192 ) ( -7984 1953 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1409 8165 8192 ) ( 3771 -7378 8192 ) ( 3771 -7378 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7202 -4299 8192 ) ( 8341 881 8192 ) ( 8341 881 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 587 +{ +( 1784 8192 8192 ) ( 1784 -8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1304 8192 ) ( 8192 -1304 8192 ) ( -8192 -1304 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1290 8192 ) ( -8192 -1290 8192 ) ( -8192 -1290 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7202 -4299 8192 ) ( 8341 881 8192 ) ( 8341 881 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8340 882 8192 ) ( -7202 -4298 8192 ) ( -7202 -4298 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7984 1952 8192 ) ( 7558 -3228 8192 ) ( 7558 -3228 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -560 -8448 8192 ) ( 4620 7094 8192 ) ( 4620 7094 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 588 +{ +( 1826 8192 8192 ) ( 1826 -8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1840 -8192 8192 ) ( 1840 8192 8192 ) ( 1840 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1290 8192 ) ( 8192 -1290 8192 ) ( -8192 -1290 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1248 8192 ) ( -8192 -1248 8192 ) ( -8192 -1248 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -560 -8448 8192 ) ( 4620 7094 8192 ) ( 4620 7094 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4619 7095 8192 ) ( -561 -8448 8192 ) ( -561 -8448 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7202 -4299 8192 ) ( 8341 881 8192 ) ( 8341 881 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3872 -7344 8192 ) ( -1308 8198 8192 ) ( -1308 8198 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 589 +{ +( 1826 8192 8192 ) ( 1826 -8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1840 -8192 8192 ) ( 1840 8192 8192 ) ( 1840 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1248 8192 ) ( 8192 -1248 8192 ) ( -8192 -1248 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1206 8192 ) ( -8192 -1206 8192 ) ( -8192 -1206 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3872 -7344 8192 ) ( -1308 8198 8192 ) ( -1308 8198 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1309 8198 8192 ) ( 3871 -7344 8192 ) ( 3871 -7344 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -560 -8448 8192 ) ( 4620 7094 8192 ) ( 4620 7094 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7592 -3128 8192 ) ( -7950 2052 8192 ) ( -7950 2052 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 590 +{ +( 1784 8192 8192 ) ( 1784 -8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1206 8192 ) ( 8192 -1206 8192 ) ( -8192 -1206 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1192 8192 ) ( -8192 -1192 8192 ) ( -8192 -1192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7592 -3128 8192 ) ( -7950 2052 8192 ) ( -7950 2052 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7951 2051 8192 ) ( 7592 -3129 8192 ) ( 7592 -3129 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3872 -7344 8192 ) ( -1308 8198 8192 ) ( -1308 8198 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8307 982 8192 ) ( -7235 -4198 8192 ) ( -7235 -4198 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 591 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1784 -8192 8192 ) ( 1784 8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1206 8192 ) ( 8192 -1206 8192 ) ( -8192 -1206 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1192 8192 ) ( -8192 -1192 8192 ) ( -8192 -1192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8307 982 8192 ) ( -7235 -4198 8192 ) ( -7235 -4198 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7235 -4199 8192 ) ( 8307 981 8192 ) ( 8307 981 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7592 -3128 8192 ) ( -7950 2052 8192 ) ( -7950 2052 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4520 7128 8192 ) ( -660 -8414 8192 ) ( -660 -8414 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 592 +{ +( 1728 8192 8192 ) ( 1728 -8192 8192 ) ( 1728 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1742 -8192 8192 ) ( 1742 8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1248 8192 ) ( 8192 -1248 8192 ) ( -8192 -1248 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1206 8192 ) ( -8192 -1206 8192 ) ( -8192 -1206 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4520 7128 8192 ) ( -660 -8414 8192 ) ( -660 -8414 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -659 -8415 8192 ) ( 4521 7128 8192 ) ( 4521 7128 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8307 982 8192 ) ( -7235 -4198 8192 ) ( -7235 -4198 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1409 8165 8192 ) ( 3771 -7378 8192 ) ( 3771 -7378 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 593 +{ +( 1728 8192 8192 ) ( 1728 -8192 8192 ) ( 1728 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1784 -8192 8192 ) ( 1784 8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -274 8192 ) ( 8192 -274 8192 ) ( -8192 -274 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -190 8192 ) ( -8192 -190 8192 ) ( -8192 -190 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1104 8266 8192 ) ( 4076 -7276 8192 ) ( 4076 -7276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4784 -6800 8192 ) ( 6800 4784 8192 ) ( 6800 4784 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4215 7230 8192 ) ( -965 -8313 8192 ) ( -965 -8313 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6568 -5016 8192 ) ( -5016 6568 8192 ) ( -5016 6568 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 594 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -288 8192 ) ( 8192 -288 8192 ) ( -8192 -288 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -232 8192 ) ( -8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7679 2866 8192 ) ( 7863 -2314 8192 ) ( 7863 -2314 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7506 -3384 8192 ) ( 8036 1796 8192 ) ( 8036 1796 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6800 4784 8192 ) ( -4784 -6800 8192 ) ( 6800 4784 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6568 -5016 8192 ) ( -5016 6568 8192 ) ( -5016 6568 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 595 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -232 8192 ) ( 8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -176 8192 ) ( -8192 -176 8192 ) ( -8192 -176 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5016 6568 8192 ) ( 6568 -5016 8192 ) ( -5016 6568 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4784 -6800 8192 ) ( 6800 4784 8192 ) ( 6800 4784 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8002 1896 8192 ) ( -7540 -3284 8192 ) ( -7540 -3284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7897 -2213 8192 ) ( -7646 2967 8192 ) ( -7646 2967 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 596 +{ +( 1784 8192 8192 ) ( 1784 -8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1840 -8192 8192 ) ( 1840 8192 8192 ) ( 1840 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -274 8192 ) ( 8192 -274 8192 ) ( -8192 -274 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -190 8192 ) ( -8192 -190 8192 ) ( -8192 -190 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5016 6568 8192 ) ( 6568 -5016 8192 ) ( -5016 6568 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -864 -8346 8192 ) ( 4316 7196 8192 ) ( 4316 7196 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6800 4784 8192 ) ( -4784 -6800 8192 ) ( 6800 4784 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4176 -7242 8192 ) ( -1004 8300 8192 ) ( -1004 8300 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 597 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -232 8192 ) ( 8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -176 8192 ) ( -8192 -176 8192 ) ( -8192 -176 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4784 -6800 8192 ) ( 6800 4784 8192 ) ( 6800 4784 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7897 -2213 8192 ) ( -7646 2967 8192 ) ( -7646 2967 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8002 1896 8192 ) ( -7540 -3284 8192 ) ( -7540 -3284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5016 6568 8192 ) ( 6568 -5016 8192 ) ( -5016 6568 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 598 +{ +( 1784 8192 8192 ) ( 1784 -8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1840 -8192 8192 ) ( 1840 8192 8192 ) ( 1840 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -274 8192 ) ( 8192 -274 8192 ) ( -8192 -274 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -190 8192 ) ( -8192 -190 8192 ) ( -8192 -190 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -864 -8346 8192 ) ( 4316 7196 8192 ) ( 4316 7196 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4176 -7242 8192 ) ( -1004 8300 8192 ) ( -1004 8300 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6800 4784 8192 ) ( -4784 -6800 8192 ) ( 6800 4784 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5016 6568 8192 ) ( 6568 -5016 8192 ) ( -5016 6568 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 599 +{ +( 1728 8192 8192 ) ( 1728 -8192 8192 ) ( 1728 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1784 -8192 8192 ) ( 1784 8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -274 8192 ) ( 8192 -274 8192 ) ( -8192 -274 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -190 8192 ) ( -8192 -190 8192 ) ( -8192 -190 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4784 -6800 8192 ) ( 6800 4784 8192 ) ( 6800 4784 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6568 -5016 8192 ) ( -5016 6568 8192 ) ( -5016 6568 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4215 7230 8192 ) ( -965 -8313 8192 ) ( -965 -8313 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1104 8266 8192 ) ( 4076 -7276 8192 ) ( 4076 -7276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 600 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -288 8192 ) ( 8192 -288 8192 ) ( -8192 -288 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -232 8192 ) ( -8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7506 -3384 8192 ) ( 8036 1796 8192 ) ( 8036 1796 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6568 -5016 8192 ) ( -5016 6568 8192 ) ( -5016 6568 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 6800 4784 8192 ) ( -4784 -6800 8192 ) ( 6800 4784 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7679 2866 8192 ) ( 7863 -2314 8192 ) ( 7863 -2314 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 601 +{ +( 1728 8192 8192 ) ( 1728 -8192 8192 ) ( 1728 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1742 -8192 8192 ) ( 1742 8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -274 8192 ) ( 8192 -274 8192 ) ( -8192 -274 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -232 8192 ) ( -8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1104 8266 8192 ) ( 4076 -7276 8192 ) ( 4076 -7276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4077 -7276 8192 ) ( -1103 8267 8192 ) ( -1103 8267 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4215 7230 8192 ) ( -965 -8313 8192 ) ( -965 -8313 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7679 2866 8192 ) ( 7863 -2314 8192 ) ( 7863 -2314 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 602 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1784 -8192 8192 ) ( 1784 8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -288 8192 ) ( 8192 -288 8192 ) ( -8192 -288 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -274 8192 ) ( -8192 -274 8192 ) ( -8192 -274 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7679 2866 8192 ) ( 7863 -2314 8192 ) ( 7863 -2314 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7863 -2313 8192 ) ( -7679 2867 8192 ) ( -7679 2867 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1104 8266 8192 ) ( 4076 -7276 8192 ) ( 4076 -7276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7506 -3384 8192 ) ( 8036 1796 8192 ) ( 8036 1796 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 603 +{ +( 1784 8192 8192 ) ( 1784 -8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -288 8192 ) ( 8192 -288 8192 ) ( -8192 -288 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -274 8192 ) ( -8192 -274 8192 ) ( -8192 -274 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7506 -3384 8192 ) ( 8036 1796 8192 ) ( 8036 1796 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8036 1797 8192 ) ( -7507 -3383 8192 ) ( -7507 -3383 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7679 2866 8192 ) ( 7863 -2314 8192 ) ( 7863 -2314 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -864 -8346 8192 ) ( 4316 7196 8192 ) ( 4316 7196 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 604 +{ +( 1826 8192 8192 ) ( 1826 -8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1840 -8192 8192 ) ( 1840 8192 8192 ) ( 1840 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -274 8192 ) ( 8192 -274 8192 ) ( -8192 -274 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -232 8192 ) ( -8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -864 -8346 8192 ) ( 4316 7196 8192 ) ( 4316 7196 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4315 7196 8192 ) ( -865 -8346 8192 ) ( -865 -8346 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7506 -3384 8192 ) ( 8036 1796 8192 ) ( 8036 1796 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4176 -7242 8192 ) ( -1004 8300 8192 ) ( -1004 8300 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 605 +{ +( 1826 8192 8192 ) ( 1826 -8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1840 -8192 8192 ) ( 1840 8192 8192 ) ( 1840 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -232 8192 ) ( 8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -190 8192 ) ( -8192 -190 8192 ) ( -8192 -190 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4176 -7242 8192 ) ( -1004 8300 8192 ) ( -1004 8300 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1005 8300 8192 ) ( 4175 -7243 8192 ) ( 4175 -7243 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -864 -8346 8192 ) ( 4316 7196 8192 ) ( 4316 7196 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7897 -2213 8192 ) ( -7646 2967 8192 ) ( -7646 2967 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 606 +{ +( 1784 8192 8192 ) ( 1784 -8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1826 -8192 8192 ) ( 1826 8192 8192 ) ( 1826 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -190 8192 ) ( 8192 -190 8192 ) ( -8192 -190 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -176 8192 ) ( -8192 -176 8192 ) ( -8192 -176 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7897 -2213 8192 ) ( -7646 2967 8192 ) ( -7646 2967 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7646 2966 8192 ) ( 7896 -2214 8192 ) ( 7896 -2214 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4176 -7242 8192 ) ( -1004 8300 8192 ) ( -1004 8300 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8002 1896 8192 ) ( -7540 -3284 8192 ) ( -7540 -3284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 607 +{ +( 1742 8192 8192 ) ( 1742 -8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1784 -8192 8192 ) ( 1784 8192 8192 ) ( 1784 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -190 8192 ) ( 8192 -190 8192 ) ( -8192 -190 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -176 8192 ) ( -8192 -176 8192 ) ( -8192 -176 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8002 1896 8192 ) ( -7540 -3284 8192 ) ( -7540 -3284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7540 -3285 8192 ) ( 8003 1895 8192 ) ( 8003 1895 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7897 -2213 8192 ) ( -7646 2967 8192 ) ( -7646 2967 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4215 7230 8192 ) ( -965 -8313 8192 ) ( -965 -8313 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 608 +{ +( 1728 8192 8192 ) ( 1728 -8192 8192 ) ( 1728 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1742 -8192 8192 ) ( 1742 8192 8192 ) ( 1742 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -232 8192 ) ( 8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -190 8192 ) ( -8192 -190 8192 ) ( -8192 -190 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4215 7230 8192 ) ( -965 -8313 8192 ) ( -965 -8313 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -964 -8313 8192 ) ( 4216 7229 8192 ) ( 4216 7229 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8002 1896 8192 ) ( -7540 -3284 8192 ) ( -7540 -3284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1104 8266 8192 ) ( 4076 -7276 8192 ) ( 4076 -7276 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 609 +{ +( -1696 8192 8192 ) ( -1696 -8192 8192 ) ( -1696 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1640 -8192 8192 ) ( -1640 8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1322 8192 ) ( 8192 -1322 8192 ) ( -8192 -1322 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1238 8192 ) ( -8192 -1238 8192 ) ( -8192 -1238 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4500 7134 8192 ) ( 680 -8408 8192 ) ( 680 -8408 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5972 -5612 8192 ) ( 5612 5972 8192 ) ( 5612 5972 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1448 8152 8192 ) ( -3732 -7390 8192 ) ( -3732 -7390 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4332 -7252 8192 ) ( -7252 4332 8192 ) ( -7252 4332 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 610 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1336 8192 ) ( 8192 -1336 8192 ) ( -8192 -1336 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1280 8192 ) ( -8192 -1280 8192 ) ( -8192 -1280 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8336 896 8192 ) ( 7206 -4284 8192 ) ( 7206 -4284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7534 -3300 8192 ) ( 8008 1880 8192 ) ( 8008 1880 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 5612 5972 8192 ) ( -5972 -5612 8192 ) ( 5612 5972 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4332 -7252 8192 ) ( -7252 4332 8192 ) ( -7252 4332 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 611 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1280 8192 ) ( 8192 -1280 8192 ) ( -8192 -1280 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1224 8192 ) ( -8192 -1224 8192 ) ( -8192 -1224 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7252 4332 8192 ) ( 4332 -7252 8192 ) ( -7252 4332 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5972 -5612 8192 ) ( 5612 5972 8192 ) ( 5612 5972 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7974 1980 8192 ) ( -7568 -3200 8192 ) ( -7568 -3200 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7240 -4184 8192 ) ( -8302 996 8192 ) ( -8302 996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 612 +{ +( -1640 8192 8192 ) ( -1640 -8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1584 -8192 8192 ) ( -1584 8192 8192 ) ( -1584 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1322 8192 ) ( 8192 -1322 8192 ) ( -8192 -1322 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1238 8192 ) ( -8192 -1238 8192 ) ( -8192 -1238 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7252 4332 8192 ) ( 4332 -7252 8192 ) ( -7252 4332 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3632 -7424 8192 ) ( 1548 8118 8192 ) ( 1548 8118 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 5612 5972 8192 ) ( -5972 -5612 8192 ) ( 5612 5972 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 780 -8374 8192 ) ( -4400 7168 8192 ) ( -4400 7168 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 613 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -1280 8192 ) ( 8192 -1280 8192 ) ( -8192 -1280 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -1224 8192 ) ( -8192 -1224 8192 ) ( -8192 -1224 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -5972 -5612 8192 ) ( 5612 5972 8192 ) ( 5612 5972 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7240 -4184 8192 ) ( -8302 996 8192 ) ( -8302 996 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7974 1980 8192 ) ( -7568 -3200 8192 ) ( -7568 -3200 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -7252 4332 8192 ) ( 4332 -7252 8192 ) ( -7252 4332 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 614 +{ +( -1640 8192 8192 ) ( -1640 -8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1584 -8192 8192 ) ( -1584 8192 8192 ) ( -1584 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1322 8192 ) ( 8192 -1322 8192 ) ( -8192 -1322 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1238 8192 ) ( -8192 -1238 8192 ) ( -8192 -1238 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3632 -7424 8192 ) ( 1548 8118 8192 ) ( 1548 8118 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 780 -8374 8192 ) ( -4400 7168 8192 ) ( -4400 7168 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 5612 5972 8192 ) ( -5972 -5612 8192 ) ( 5612 5972 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7252 4332 8192 ) ( 4332 -7252 8192 ) ( -7252 4332 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 615 +{ +( -1696 8192 8192 ) ( -1696 -8192 8192 ) ( -1696 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1640 -8192 8192 ) ( -1640 8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1322 8192 ) ( 8192 -1322 8192 ) ( -8192 -1322 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1238 8192 ) ( -8192 -1238 8192 ) ( -8192 -1238 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -5972 -5612 8192 ) ( 5612 5972 8192 ) ( 5612 5972 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4332 -7252 8192 ) ( -7252 4332 8192 ) ( -7252 4332 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1448 8152 8192 ) ( -3732 -7390 8192 ) ( -3732 -7390 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4500 7134 8192 ) ( 680 -8408 8192 ) ( 680 -8408 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 616 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1336 8192 ) ( 8192 -1336 8192 ) ( -8192 -1336 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1280 8192 ) ( -8192 -1280 8192 ) ( -8192 -1280 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7534 -3300 8192 ) ( 8008 1880 8192 ) ( 8008 1880 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4332 -7252 8192 ) ( -7252 4332 8192 ) ( -7252 4332 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 5612 5972 8192 ) ( -5972 -5612 8192 ) ( 5612 5972 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8336 896 8192 ) ( 7206 -4284 8192 ) ( 7206 -4284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 617 +{ +( -1696 8192 8192 ) ( -1696 -8192 8192 ) ( -1696 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1682 -8192 8192 ) ( -1682 8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1322 8192 ) ( 8192 -1322 8192 ) ( -8192 -1322 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1280 8192 ) ( -8192 -1280 8192 ) ( -8192 -1280 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4500 7134 8192 ) ( 680 -8408 8192 ) ( 680 -8408 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 681 -8408 8192 ) ( -4499 7135 8192 ) ( -4499 7135 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1448 8152 8192 ) ( -3732 -7390 8192 ) ( -3732 -7390 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8336 896 8192 ) ( 7206 -4284 8192 ) ( 7206 -4284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 618 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1640 -8192 8192 ) ( -1640 8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1336 8192 ) ( 8192 -1336 8192 ) ( -8192 -1336 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1322 8192 ) ( -8192 -1322 8192 ) ( -8192 -1322 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8336 896 8192 ) ( 7206 -4284 8192 ) ( 7206 -4284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7207 -4283 8192 ) ( -8336 897 8192 ) ( -8336 897 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4500 7134 8192 ) ( 680 -8408 8192 ) ( 680 -8408 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7534 -3300 8192 ) ( 8008 1880 8192 ) ( 8008 1880 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 619 +{ +( -1640 8192 8192 ) ( -1640 -8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1336 8192 ) ( 8192 -1336 8192 ) ( -8192 -1336 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1322 8192 ) ( -8192 -1322 8192 ) ( -8192 -1322 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7534 -3300 8192 ) ( 8008 1880 8192 ) ( 8008 1880 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8008 1881 8192 ) ( -7535 -3299 8192 ) ( -7535 -3299 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8336 896 8192 ) ( 7206 -4284 8192 ) ( 7206 -4284 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3632 -7424 8192 ) ( 1548 8118 8192 ) ( 1548 8118 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 620 +{ +( -1598 8192 8192 ) ( -1598 -8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1584 -8192 8192 ) ( -1584 8192 8192 ) ( -1584 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1322 8192 ) ( 8192 -1322 8192 ) ( -8192 -1322 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1280 8192 ) ( -8192 -1280 8192 ) ( -8192 -1280 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3632 -7424 8192 ) ( 1548 8118 8192 ) ( 1548 8118 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1547 8119 8192 ) ( -3633 -7424 8192 ) ( -3633 -7424 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7534 -3300 8192 ) ( 8008 1880 8192 ) ( 8008 1880 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 780 -8374 8192 ) ( -4400 7168 8192 ) ( -4400 7168 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 621 +{ +( -1598 8192 8192 ) ( -1598 -8192 8192 ) ( -1598 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1584 -8192 8192 ) ( -1584 8192 8192 ) ( -1584 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -1280 8192 ) ( 8192 -1280 8192 ) ( -8192 -1280 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -1238 8192 ) ( -8192 -1238 8192 ) ( -8192 -1238 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 780 -8374 8192 ) ( -4400 7168 8192 ) ( -4400 7168 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -4401 7168 8192 ) ( 779 -8375 8192 ) ( 779 -8375 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -3632 -7424 8192 ) ( 1548 8118 8192 ) ( 1548 8118 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7240 -4184 8192 ) ( -8302 996 8192 ) ( -8302 996 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 622 +{ +( -1640 8192 8192 ) ( -1640 -8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1238 8192 ) ( 8192 -1238 8192 ) ( -8192 -1238 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1224 8192 ) ( -8192 -1224 8192 ) ( -8192 -1224 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7240 -4184 8192 ) ( -8302 996 8192 ) ( -8302 996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8303 995 8192 ) ( 7240 -4185 8192 ) ( 7240 -4185 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 780 -8374 8192 ) ( -4400 7168 8192 ) ( -4400 7168 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7974 1980 8192 ) ( -7568 -3200 8192 ) ( -7568 -3200 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 623 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1640 -8192 8192 ) ( -1640 8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1238 8192 ) ( 8192 -1238 8192 ) ( -8192 -1238 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1224 8192 ) ( -8192 -1224 8192 ) ( -8192 -1224 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7974 1980 8192 ) ( -7568 -3200 8192 ) ( -7568 -3200 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7568 -3201 8192 ) ( 7975 1979 8192 ) ( 7975 1979 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7240 -4184 8192 ) ( -8302 996 8192 ) ( -8302 996 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1448 8152 8192 ) ( -3732 -7390 8192 ) ( -3732 -7390 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 624 +{ +( -1696 8192 8192 ) ( -1696 -8192 8192 ) ( -1696 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1682 -8192 8192 ) ( -1682 8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -1280 8192 ) ( 8192 -1280 8192 ) ( -8192 -1280 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -1238 8192 ) ( -8192 -1238 8192 ) ( -8192 -1238 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1448 8152 8192 ) ( -3732 -7390 8192 ) ( -3732 -7390 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3731 -7391 8192 ) ( 1449 8152 8192 ) ( 1449 8152 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7974 1980 8192 ) ( -7568 -3200 8192 ) ( -7568 -3200 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4500 7134 8192 ) ( 680 -8408 8192 ) ( 680 -8408 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 625 +{ +( 565 8192 8192 ) ( 565 -8192 8192 ) ( 565 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 922 -8192 8192 ) ( 922 8192 8192 ) ( 922 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -648 8192 ) ( 8192 -648 8192 ) ( -8192 -648 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -641 8192 ) ( -8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 695 ) ( 8192 8192 695 ) ( -8192 -8192 695 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8159 -997 8192 ) ( 8212 -355 8192 ) ( 8212 -355 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8209 -296 8192 ) ( 8161 -938 8192 ) ( 8161 -938 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 626 +{ +( 438 8192 8192 ) ( 438 -8192 8192 ) ( 438 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1050 -8192 8192 ) ( 1050 8192 8192 ) ( 1050 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -641 8192 ) ( 8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -620 8192 ) ( -8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 695 ) ( 8192 8192 695 ) ( -8192 -8192 695 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8170 797 8192 ) ( 7995 -1864 8192 ) ( 7995 -1864 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7955 -2103 8192 ) ( 8210 559 8192 ) ( 8210 559 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 627 +{ +( 361 8192 8192 ) ( 361 -8192 8192 ) ( 361 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1126 -8192 8192 ) ( 1126 8192 8192 ) ( 1126 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -620 8192 ) ( 8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -585 8192 ) ( -8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 695 ) ( 8192 8192 695 ) ( -8192 -8192 695 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7608 3061 8192 ) ( 7290 -3755 8192 ) ( 7290 -3755 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7033 -4318 8192 ) ( 7865 2498 8192 ) ( 7865 2498 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 628 +{ +( 336 8192 8192 ) ( 336 -8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1152 -8192 8192 ) ( 1152 8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -585 8192 ) ( 8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -536 8192 ) ( -8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 695 ) ( 8192 8192 695 ) ( -8192 -8192 695 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -3736 7290 8192 ) ( 3826 -7243 8192 ) ( 3826 -7243 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -2655 -7852 8192 ) ( 4907 6680 8192 ) ( 4907 6680 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 629 +{ +( 336 8192 8192 ) ( 336 -8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1152 -8192 8192 ) ( 1152 8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -585 8192 ) ( 8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -536 8192 ) ( -8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 1 ) ( 8192 -8192 1 ) ( -8192 -8192 1 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -2655 -7852 8192 ) ( 4907 6680 8192 ) ( 4907 6680 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -3736 7290 8192 ) ( 3826 -7243 8192 ) ( 3826 -7243 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 630 +{ +( 361 8192 8192 ) ( 361 -8192 8192 ) ( 361 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1126 -8192 8192 ) ( 1126 8192 8192 ) ( 1126 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -620 8192 ) ( 8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -585 8192 ) ( -8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 1 ) ( 8192 -8192 1 ) ( -8192 -8192 1 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7033 -4318 8192 ) ( 7865 2498 8192 ) ( 7865 2498 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7608 3061 8192 ) ( 7290 -3755 8192 ) ( 7290 -3755 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 631 +{ +( 438 8192 8192 ) ( 438 -8192 8192 ) ( 438 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1050 -8192 8192 ) ( 1050 8192 8192 ) ( 1050 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -641 8192 ) ( 8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -620 8192 ) ( -8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 1 ) ( 8192 -8192 1 ) ( -8192 -8192 1 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7955 -2103 8192 ) ( 8210 559 8192 ) ( 8210 559 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8170 797 8192 ) ( 7995 -1864 8192 ) ( 7995 -1864 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 632 +{ +( 565 8192 8192 ) ( 565 -8192 8192 ) ( 565 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 922 -8192 8192 ) ( 922 8192 8192 ) ( 922 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -648 8192 ) ( 8192 -648 8192 ) ( -8192 -648 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -641 8192 ) ( -8192 -641 8192 ) ( -8192 -641 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 1 ) ( 8192 -8192 1 ) ( -8192 -8192 1 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8209 -296 8192 ) ( 8161 -938 8192 ) ( 8161 -938 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8159 -997 8192 ) ( 8212 -355 8192 ) ( 8212 -355 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 633 +{ +( 336 8192 8192 ) ( 336 -8192 8192 ) ( 336 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 369 -8200 8192 ) ( 369 8184 8192 ) ( 369 8184 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -585 8192 ) ( 8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -536 8192 ) ( -8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -3736 7290 8192 ) ( 3826 -7243 8192 ) ( 3826 -7243 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3835 -7243 8192 ) ( -3727 7290 8192 ) ( -3727 7290 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7557 3222 8192 ) ( -6975 -4341 8192 ) ( -6975 -4341 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7608 3061 8192 ) ( 7290 -3755 8192 ) ( 7290 -3755 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 634 +{ +( 361 8192 8192 ) ( 361 -8192 8192 ) ( 361 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 446 -8192 8192 ) ( 446 8192 8192 ) ( 446 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -620 8192 ) ( 8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -585 8192 ) ( -8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7608 3061 8192 ) ( 7290 -3755 8192 ) ( 7290 -3755 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7299 -3754 8192 ) ( -7599 3062 8192 ) ( -7599 3062 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -3736 7290 8192 ) ( 3826 -7243 8192 ) ( 3826 -7243 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8170 797 8192 ) ( 7995 -1864 8192 ) ( 7995 -1864 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 635 +{ +( 1042 8192 8192 ) ( 1042 -8192 8192 ) ( 1042 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1126 -8192 8192 ) ( 1126 8192 8192 ) ( 1126 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -620 8192 ) ( 8192 -620 8192 ) ( -8192 -620 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -585 8192 ) ( -8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7033 -4318 8192 ) ( 7865 2498 8192 ) ( 7865 2498 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7857 2499 8192 ) ( -7041 -4317 8192 ) ( -7041 -4317 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7955 -2103 8192 ) ( 8210 559 8192 ) ( 8210 559 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -2655 -7852 8192 ) ( 4907 6680 8192 ) ( 4907 6680 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 636 +{ +( 1126 8192 8192 ) ( 1126 -8192 8192 ) ( 1126 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1152 -8192 8192 ) ( 1152 8192 8192 ) ( 1152 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -585 8192 ) ( 8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -536 8192 ) ( -8192 -536 8192 ) ( -8192 -536 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 0 ) ( 8192 8192 0 ) ( -8192 -8192 0 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 696 ) ( 8192 -8192 696 ) ( -8192 -8192 696 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -2655 -7852 8192 ) ( 4907 6680 8192 ) ( 4907 6680 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 4906 6681 8192 ) ( -2656 -7852 8192 ) ( -2656 -7852 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7033 -4318 8192 ) ( 7865 2498 8192 ) ( 7865 2498 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7292 -3731 8192 ) ( -7240 3831 8192 ) ( -7240 3831 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 637 +{ +( 311 8192 8192 ) ( 311 -8192 8192 ) ( 311 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 368 -8192 8192 ) ( 368 8192 8192 ) ( 368 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 160 8192 ) ( 8192 160 8192 ) ( -8192 160 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 160 8192 ) ( -8192 160 8192 ) ( -8192 160 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -168 ) ( 8192 8192 -168 ) ( -8192 -8192 -168 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -167 ) ( 8192 -8192 -167 ) ( -8192 -8192 -167 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8193 0 8192 ) ( -8186 334 8192 ) ( 8193 0 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8164 682 8192 ) ( -8183 -405 8192 ) ( 8164 682 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 638 +{ +( 311 8192 8192 ) ( 311 -8192 8192 ) ( 311 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 368 -8192 8192 ) ( 368 8192 8192 ) ( 368 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 160 8192 ) ( 8192 160 8192 ) ( -8192 160 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 160 8192 ) ( -8192 160 8192 ) ( -8192 160 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -137 ) ( 8192 8192 -137 ) ( -8192 -8192 -137 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -136 ) ( 8192 -8192 -136 ) ( -8192 -8192 -136 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8164 682 8192 ) ( -8183 -405 8192 ) ( 8164 682 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8193 0 8192 ) ( -8186 334 8192 ) ( 8193 0 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 639 +{ +( -1696 8192 8192 ) ( -1696 -8192 8192 ) ( -1696 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1640 -8192 8192 ) ( -1640 8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -306 8192 ) ( 8192 -306 8192 ) ( -8192 -306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -222 8192 ) ( -8192 -222 8192 ) ( -8192 -222 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4196 7236 8192 ) ( 984 -8306 8192 ) ( 984 -8306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6480 -5104 8192 ) ( 5104 6480 8192 ) ( 5104 6480 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1143 8254 8192 ) ( -4037 -7289 8192 ) ( -4037 -7289 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4840 -6744 8192 ) ( -6744 4840 8192 ) ( -6744 4840 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 640 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -320 8192 ) ( 8192 -320 8192 ) ( -8192 -320 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -264 8192 ) ( -8192 -264 8192 ) ( -8192 -264 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8031 1810 8192 ) ( 7511 -3370 8192 ) ( 7511 -3370 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7839 -2386 8192 ) ( 7703 2794 8192 ) ( 7703 2794 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 5104 6480 8192 ) ( -6480 -5104 8192 ) ( 5104 6480 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 4840 -6744 8192 ) ( -6744 4840 8192 ) ( -6744 4840 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 641 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -264 8192 ) ( 8192 -264 8192 ) ( -8192 -264 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -208 8192 ) ( -8192 -208 8192 ) ( -8192 -208 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6744 4840 8192 ) ( 4840 -6744 8192 ) ( -6744 4840 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6480 -5104 8192 ) ( 5104 6480 8192 ) ( 5104 6480 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7670 2895 8192 ) ( -7873 -2285 8192 ) ( -7873 -2285 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7545 -3269 8192 ) ( -7998 1911 8192 ) ( -7998 1911 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 642 +{ +( -1640 8192 8192 ) ( -1640 -8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1584 -8192 8192 ) ( -1584 8192 8192 ) ( -1584 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -306 8192 ) ( 8192 -306 8192 ) ( -8192 -306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -222 8192 ) ( -8192 -222 8192 ) ( -8192 -222 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1145 ) ( 8192 8192 -1145 ) ( -8192 -8192 -1145 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6744 4840 8192 ) ( 4840 -6744 8192 ) ( -6744 4840 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3936 -7322 8192 ) ( 1244 8220 8192 ) ( 1244 8220 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 5104 6480 8192 ) ( -6480 -5104 8192 ) ( 5104 6480 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1085 -8273 8192 ) ( -4095 7270 8192 ) ( -4095 7270 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 643 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -264 8192 ) ( 8192 -264 8192 ) ( -8192 -264 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -208 8192 ) ( -8192 -208 8192 ) ( -8192 -208 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6480 -5104 8192 ) ( 5104 6480 8192 ) ( 5104 6480 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7545 -3269 8192 ) ( -7998 1911 8192 ) ( -7998 1911 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7670 2895 8192 ) ( -7873 -2285 8192 ) ( -7873 -2285 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6744 4840 8192 ) ( 4840 -6744 8192 ) ( -6744 4840 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 644 +{ +( -1640 8192 8192 ) ( -1640 -8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1584 -8192 8192 ) ( -1584 8192 8192 ) ( -1584 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -306 8192 ) ( 8192 -306 8192 ) ( -8192 -306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -222 8192 ) ( -8192 -222 8192 ) ( -8192 -222 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3936 -7322 8192 ) ( 1244 8220 8192 ) ( 1244 8220 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1085 -8273 8192 ) ( -4095 7270 8192 ) ( -4095 7270 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 5104 6480 8192 ) ( -6480 -5104 8192 ) ( 5104 6480 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6744 4840 8192 ) ( 4840 -6744 8192 ) ( -6744 4840 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 645 +{ +( -1696 8192 8192 ) ( -1696 -8192 8192 ) ( -1696 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1640 -8192 8192 ) ( -1640 8192 8192 ) ( -1640 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -306 8192 ) ( 8192 -306 8192 ) ( -8192 -306 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -222 8192 ) ( -8192 -222 8192 ) ( -8192 -222 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6480 -5104 8192 ) ( 5104 6480 8192 ) ( 5104 6480 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 4840 -6744 8192 ) ( -6744 4840 8192 ) ( -6744 4840 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 1143 8254 8192 ) ( -4037 -7289 8192 ) ( -4037 -7289 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -4196 7236 8192 ) ( 984 -8306 8192 ) ( 984 -8306 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 646 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -320 8192 ) ( 8192 -320 8192 ) ( -8192 -320 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -264 8192 ) ( -8192 -264 8192 ) ( -8192 -264 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -1207 ) ( 8192 -8192 -1207 ) ( -8192 -8192 -1207 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -7839 -2386 8192 ) ( 7703 2794 8192 ) ( 7703 2794 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 4840 -6744 8192 ) ( -6744 4840 8192 ) ( -6744 4840 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5104 6480 8192 ) ( -6480 -5104 8192 ) ( 5104 6480 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8031 1810 8192 ) ( 7511 -3370 8192 ) ( 7511 -3370 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 647 +{ +( -1696 8192 8192 ) ( -1696 -8192 8192 ) ( -1696 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1682 -8192 8192 ) ( -1682 8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -306 8192 ) ( 8192 -306 8192 ) ( -8192 -306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -264 8192 ) ( -8192 -264 8192 ) ( -8192 -264 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4196 7236 8192 ) ( 984 -8306 8192 ) ( 984 -8306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 985 -8306 8192 ) ( -4195 7236 8192 ) ( -4195 7236 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1143 8254 8192 ) ( -4037 -7289 8192 ) ( -4037 -7289 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8031 1810 8192 ) ( 7511 -3370 8192 ) ( 7511 -3370 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 648 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1640 -8192 8192 ) ( -1640 8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -320 8192 ) ( 8192 -320 8192 ) ( -8192 -320 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -306 8192 ) ( -8192 -306 8192 ) ( -8192 -306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8031 1810 8192 ) ( 7511 -3370 8192 ) ( 7511 -3370 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7511 -3369 8192 ) ( -8031 1811 8192 ) ( -8031 1811 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4196 7236 8192 ) ( 984 -8306 8192 ) ( 984 -8306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7839 -2386 8192 ) ( 7703 2794 8192 ) ( 7703 2794 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 649 +{ +( -1640 8192 8192 ) ( -1640 -8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -320 8192 ) ( 8192 -320 8192 ) ( -8192 -320 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -306 8192 ) ( -8192 -306 8192 ) ( -8192 -306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7839 -2386 8192 ) ( 7703 2794 8192 ) ( 7703 2794 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7703 2795 8192 ) ( -7839 -2385 8192 ) ( -7839 -2385 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8031 1810 8192 ) ( 7511 -3370 8192 ) ( 7511 -3370 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3936 -7322 8192 ) ( 1244 8220 8192 ) ( 1244 8220 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 650 +{ +( -1598 8192 8192 ) ( -1598 -8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1584 -8192 8192 ) ( -1584 8192 8192 ) ( -1584 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -306 8192 ) ( 8192 -306 8192 ) ( -8192 -306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -264 8192 ) ( -8192 -264 8192 ) ( -8192 -264 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3936 -7322 8192 ) ( 1244 8220 8192 ) ( 1244 8220 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1243 8220 8192 ) ( -3937 -7322 8192 ) ( -3937 -7322 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7839 -2386 8192 ) ( 7703 2794 8192 ) ( 7703 2794 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1085 -8273 8192 ) ( -4095 7270 8192 ) ( -4095 7270 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 651 +{ +( -1598 8192 8192 ) ( -1598 -8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1584 -8192 8192 ) ( -1584 8192 8192 ) ( -1584 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -264 8192 ) ( 8192 -264 8192 ) ( -8192 -264 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -222 8192 ) ( -8192 -222 8192 ) ( -8192 -222 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1085 -8273 8192 ) ( -4095 7270 8192 ) ( -4095 7270 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4096 7269 8192 ) ( 1084 -8273 8192 ) ( 1084 -8273 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -3936 -7322 8192 ) ( 1244 8220 8192 ) ( 1244 8220 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7545 -3269 8192 ) ( -7998 1911 8192 ) ( -7998 1911 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 652 +{ +( -1640 8192 8192 ) ( -1640 -8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1598 -8192 8192 ) ( -1598 8192 8192 ) ( -1598 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -222 8192 ) ( 8192 -222 8192 ) ( -8192 -222 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -208 8192 ) ( -8192 -208 8192 ) ( -8192 -208 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7545 -3269 8192 ) ( -7998 1911 8192 ) ( -7998 1911 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7998 1910 8192 ) ( 7544 -3270 8192 ) ( 7544 -3270 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1085 -8273 8192 ) ( -4095 7270 8192 ) ( -4095 7270 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7670 2895 8192 ) ( -7873 -2285 8192 ) ( -7873 -2285 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 653 +{ +( -1682 8192 8192 ) ( -1682 -8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1640 -8192 8192 ) ( -1640 8192 8192 ) ( -1640 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -222 8192 ) ( 8192 -222 8192 ) ( -8192 -222 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -208 8192 ) ( -8192 -208 8192 ) ( -8192 -208 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7670 2895 8192 ) ( -7873 -2285 8192 ) ( -7873 -2285 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -7872 -2286 8192 ) ( 7670 2894 8192 ) ( 7670 2894 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7545 -3269 8192 ) ( -7998 1911 8192 ) ( -7998 1911 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1143 8254 8192 ) ( -4037 -7289 8192 ) ( -4037 -7289 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 654 +{ +( -1696 8192 8192 ) ( -1696 -8192 8192 ) ( -1696 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -1682 -8192 8192 ) ( -1682 8192 8192 ) ( -1682 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -264 8192 ) ( 8192 -264 8192 ) ( -8192 -264 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -222 8192 ) ( -8192 -222 8192 ) ( -8192 -222 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1208 ) ( 8192 8192 -1208 ) ( -8192 -8192 -1208 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1144 ) ( 8192 -8192 -1144 ) ( -8192 -8192 -1144 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1143 8254 8192 ) ( -4037 -7289 8192 ) ( -4037 -7289 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4036 -7289 8192 ) ( 1144 8253 8192 ) ( 1144 8253 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7670 2895 8192 ) ( -7873 -2285 8192 ) ( -7873 -2285 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -4196 7236 8192 ) ( 984 -8306 8192 ) ( 984 -8306 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 655 +{ +( -480 8192 8192 ) ( -480 -8192 8192 ) ( -480 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -464 -8192 8192 ) ( -464 8192 8192 ) ( -464 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -550 8192 ) ( 8192 -550 8192 ) ( -8192 -550 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -519 8192 ) ( -8192 -519 8192 ) ( -8192 -519 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -31 ) ( 8192 8192 -31 ) ( -8192 -8192 -31 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8017 8336 -668 ) ( 8017 -7398 3899 ) ( -7987 -8374 536 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 3687 7832 7699 ) ( -7708 -3938 7699 ) ( -3666 -7852 -7688 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6091 5486 8217 ) ( 5657 -5932 8217 ) ( 5094 -6512 -8146 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7945 7305 -4218 ) ( 7945 -8428 349 ) ( -8060 8281 -855 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8017 -7398 3898 ) ( 8017 8335 -669 ) ( -7987 7359 -4032 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8179 447 ) ( 8192 8172 -574 ) ( -8192 8172 -574 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8172 -8192 -570 ) ( 8172 8192 -570 ) ( -8179 8192 451 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5820 5765 8192 ) ( -5765 -5820 8192 ) ( -5765 -5820 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -7359 3609 ) ( 8192 7097 -4100 ) ( -8192 7097 -4100 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7243 8191 3831 ) ( 7243 -8191 3831 ) ( -7411 -8191 -3495 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6467 5078 8192 ) ( 5484 -6127 8192 ) ( 5484 -6127 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7818 -2451 ) ( 8192 -7915 2116 ) ( -8192 -7915 2116 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 656 +{ +( -464 8192 8192 ) ( -464 -8192 8192 ) ( -464 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -448 -8192 8192 ) ( -448 8192 8192 ) ( -448 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -550 8192 ) ( 8192 -550 8192 ) ( -8192 -550 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -519 8192 ) ( -8192 -519 8192 ) ( -8192 -519 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -31 ) ( 8192 8192 -31 ) ( -8192 -8192 -31 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7945 7305 -4217 ) ( 7945 -8428 350 ) ( -8060 -7452 3713 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6107 -5469 8185 ) ( 5641 5949 8185 ) ( 6204 5369 -8178 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7286 -4347 7914 ) ( -4110 7423 7914 ) ( -8152 3509 -7473 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8017 8335 -669 ) ( 8017 -7398 3898 ) ( -7987 7359 -4032 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7945 -8428 349 ) ( 7945 7305 -4218 ) ( -8060 8281 -855 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -7359 3609 ) ( 8192 7097 -4100 ) ( -8192 7097 -4100 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7225 8192 -3866 ) ( 7225 -8192 -3866 ) ( -7428 -8192 3460 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -5918 -5664 8192 ) ( 6033 5541 8192 ) ( 6033 5541 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8179 447 ) ( 8192 8172 -574 ) ( -8192 8172 -574 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8176 -8192 509 ) ( 8176 8192 509 ) ( -8175 8192 -512 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5301 -6284 8192 ) ( -6284 5301 8192 ) ( -6284 5301 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7818 -2451 ) ( 8192 -7915 2116 ) ( -8192 -7915 2116 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 657 +{ +( -528 8192 8192 ) ( -528 -8192 8192 ) ( -528 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -512 -8192 8192 ) ( -512 8192 8192 ) ( -512 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -550 8192 ) ( 8192 -550 8192 ) ( -8192 -550 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -518 8192 ) ( -8192 -518 8192 ) ( -8192 -518 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -32 ) ( 8192 8192 -32 ) ( -8192 -8192 -32 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8052 8269 -1003 ) ( 8052 -7369 3883 ) ( -8020 -8316 851 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 3302 8014 7685 ) ( -7550 -4258 7685 ) ( -3371 -7953 -7719 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -5904 5679 8225 ) ( 5732 -5853 8225 ) ( 4855 -6738 -8111 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7982 7263 -4222 ) ( 7982 -8374 664 ) ( -8091 8210 -1190 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8052 -7369 3882 ) ( 8052 8268 -1004 ) ( -8020 7321 -4036 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8146 865 ) ( 8192 8125 -1048 ) ( -8192 8125 -1048 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8116 -8192 -1110 ) ( 8116 8192 -1110 ) ( -8140 8192 921 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5601 5977 8192 ) ( -5627 -5953 8192 ) ( -5627 -5953 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -7359 3609 ) ( 8192 7097 -4100 ) ( -8192 7097 -4100 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7233 8192 3850 ) ( 7233 -8192 3850 ) ( -7420 -8192 -3476 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6490 5054 8192 ) ( 5462 -6151 8192 ) ( 5462 -6151 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7763 -2620 ) ( 8192 -7874 2266 ) ( -8192 -7874 2266 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 658 +{ +( -512 8192 8192 ) ( -512 -8192 8192 ) ( -512 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -496 -8192 8192 ) ( -496 8192 8192 ) ( -496 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -550 8192 ) ( 8192 -550 8192 ) ( -8192 -550 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -518 8192 ) ( -8192 -518 8192 ) ( -8192 -518 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -32 ) ( 8192 8192 -32 ) ( -8192 -8192 -32 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -22 ) ( 8192 -8192 -22 ) ( -8192 -8192 -22 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7982 7263 -4221 ) ( 7982 -8374 665 ) ( -8090 -7427 3697 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6236 -5344 8170 ) ( 5400 6188 8170 ) ( 6276 5304 -8166 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7042 -4707 7931 ) ( -3810 7565 7931 ) ( -7989 3870 -7473 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8052 8268 -1004 ) ( 8052 -7369 3882 ) ( -8020 7321 -4036 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7982 -8374 664 ) ( 7982 7263 -4222 ) ( -8091 8210 -1190 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -7359 3609 ) ( 8192 7097 -4100 ) ( -8192 7097 -4100 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7215 8192 -3885 ) ( 7215 -8192 -3885 ) ( -7438 -8192 3441 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -5941 -5640 8192 ) ( 6011 5565 8192 ) ( 6011 5565 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8146 865 ) ( 8192 8125 -1048 ) ( -8192 8125 -1048 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8124 -8191 1047 ) ( 8124 8191 1047 ) ( -8132 8191 -984 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5084 -6464 8192 ) ( -6144 5466 8192 ) ( -6144 5466 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7763 -2620 ) ( 8192 -7874 2266 ) ( -8192 -7874 2266 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 659 +{ +( -528 8192 8192 ) ( -528 -8192 8192 ) ( -528 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -512 -8192 8192 ) ( -512 8192 8192 ) ( -512 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -511 8192 ) ( 8192 -511 8192 ) ( -8192 -511 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -480 8192 ) ( -8192 -480 8192 ) ( -8192 -480 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -42 ) ( 8192 8192 -42 ) ( -8192 -8192 -42 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -32 ) ( 8192 -8192 -32 ) ( -8192 -8192 -32 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7999 7247 -4215 ) ( 7999 -8344 814 ) ( -8102 -7415 3695 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5264 6321 8157 ) ( -6321 -5264 8157 ) ( -5301 -6284 -8162 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -4012 7466 7924 ) ( 7192 -4485 7924 ) ( 3096 -8325 -7466 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8067 -7358 3872 ) ( 8067 8234 -1157 ) ( -8034 7304 -4039 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7999 -8345 813 ) ( 7999 7247 -4216 ) ( -8102 8177 -1334 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7104 -4087 ) ( 8192 -7351 3623 ) ( -8192 -7351 3623 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7207 -8192 -3901 ) ( 7207 8192 -3901 ) ( -7446 8192 3425 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5976 5602 8192 ) ( -5976 -5602 8192 ) ( -5976 -5602 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8116 -1110 ) ( 8192 -8140 921 ) ( -8192 -8140 921 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8124 8191 1047 ) ( 8124 -8191 1047 ) ( -8132 8191 -984 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6304 5281 8192 ) ( 5281 -6304 8192 ) ( 5281 -6304 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -7853 2336 ) ( 8192 7738 -2693 ) ( -8192 7738 -2693 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 660 +{ +( -512 8192 8192 ) ( -512 -8192 8192 ) ( -512 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -496 -8192 8192 ) ( -496 8192 8192 ) ( -496 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -511 8192 ) ( 8192 -511 8192 ) ( -8192 -511 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -480 8192 ) ( -8192 -480 8192 ) ( -8192 -480 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -42 ) ( 8192 8192 -42 ) ( -8192 -8192 -42 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -32 ) ( 8192 -8192 -32 ) ( -8192 -8192 -32 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8067 8234 -1156 ) ( 8067 -7358 3872 ) ( -8034 -8287 991 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -7673 -4034 7684 ) ( 3531 7917 7684 ) ( 7627 4077 -7707 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5813 -5772 8221 ) ( -5772 5813 8221 ) ( -6792 4793 -8098 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7999 -8345 813 ) ( 7999 7247 -4216 ) ( -8102 8177 -1334 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8067 -7358 3872 ) ( 8067 8234 -1157 ) ( -8034 7304 -4039 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8116 -1110 ) ( 8192 -8140 921 ) ( -8192 -8140 921 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8116 8192 -1110 ) ( 8116 -8192 -1110 ) ( -8140 8192 921 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -5793 -5792 8192 ) ( 5792 5793 8192 ) ( 5792 5793 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7104 -4087 ) ( 8192 -7351 3623 ) ( -8192 -7351 3623 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7241 -8192 3834 ) ( 7241 8192 3834 ) ( -7412 8192 -3492 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5497 -6113 8192 ) ( -6455 5091 8192 ) ( -6455 5091 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -7853 2336 ) ( 8192 7738 -2693 ) ( -8192 7738 -2693 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 661 +{ +( -480 8192 8192 ) ( -480 -8192 8192 ) ( -480 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -464 -8192 8192 ) ( -464 8192 8192 ) ( -464 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -511 8192 ) ( 8192 -511 8192 ) ( -8192 -511 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -480 8192 ) ( -8192 -480 8192 ) ( -8192 -480 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -42 ) ( 8192 8192 -42 ) ( -8192 -8192 -42 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -32 ) ( 8192 -8192 -32 ) ( -8192 -8192 -32 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8001 7250 -4207 ) ( 8001 -8342 822 ) ( -8100 -7412 3704 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5287 6297 8160 ) ( -6297 -5287 8160 ) ( -5277 -6307 -8159 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -3990 7488 7913 ) ( 7215 -4464 7913 ) ( 3119 -8304 -7478 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8069 -7361 3863 ) ( 8069 8231 -1166 ) ( -8032 7301 -4047 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8001 -8342 821 ) ( 8001 7250 -4208 ) ( -8100 8179 -1326 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7104 -4087 ) ( 8192 -7351 3623 ) ( -8192 -7351 3623 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7217 -8192 -3882 ) ( 7217 8192 -3882 ) ( -7436 8192 3444 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5998 5578 8192 ) ( -5953 -5626 8192 ) ( -5953 -5626 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8116 -1110 ) ( 8192 -8140 921 ) ( -8192 -8140 921 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8125 8192 1041 ) ( 8125 -8192 1041 ) ( -8131 -8192 -990 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -6280 5305 8192 ) ( 5305 -6280 8192 ) ( 5305 -6280 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -7853 2336 ) ( 8192 7738 -2693 ) ( -8192 7738 -2693 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 662 +{ +( -464 8192 8192 ) ( -464 -8192 8192 ) ( -464 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -448 -8192 8192 ) ( -448 8192 8192 ) ( -448 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -511 8192 ) ( 8192 -511 8192 ) ( -8192 -511 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -480 8192 ) ( -8192 -480 8192 ) ( -8192 -480 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -42 ) ( 8192 8192 -42 ) ( -8192 -8192 -42 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -32 ) ( 8192 -8192 -32 ) ( -8192 -8192 -32 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8068 8231 -1165 ) ( 8068 -7361 3864 ) ( -8032 -8290 983 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -7651 -4055 7695 ) ( 3554 7896 7695 ) ( 7650 4056 -7696 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5836 -5748 8218 ) ( -5748 5836 8218 ) ( -6768 4816 -8101 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8001 -8342 821 ) ( 8001 7250 -4208 ) ( -8100 8179 -1326 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8069 -7361 3863 ) ( 8069 8231 -1166 ) ( -8032 7301 -4047 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8116 -1110 ) ( 8192 -8140 921 ) ( -8192 -8140 921 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8117 8192 -1104 ) ( 8117 -8192 -1104 ) ( -8139 -8192 927 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -5769 -5816 8192 ) ( 5816 5769 8192 ) ( 5816 5769 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7104 -4087 ) ( 8192 -7351 3623 ) ( -8192 -7351 3623 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 7251 -8192 3815 ) ( 7251 8192 3815 ) ( -7403 8192 -3511 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 5519 -6089 8192 ) ( -6432 5115 8192 ) ( -6432 5115 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -7853 2336 ) ( 8192 7738 -2693 ) ( -8192 7738 -2693 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 663 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -595 8192 ) ( 8192 -595 8192 ) ( -8192 -595 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -580 8192 ) ( -8192 -580 8192 ) ( -8192 -580 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -47 ) ( 8192 8192 -47 ) ( -8192 -8192 -47 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -30 ) ( 8192 -8192 -30 ) ( -8192 -8192 -30 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2240 7901 ) ( 8192 -2240 7901 ) ( 8192 1085 -8141 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 4493 6864 ) ( -8192 4493 6864 ) ( -8192 -5217 -6331 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7612 3032 ) ( 8192 -7734 -2705 ) ( -8192 -7734 -2705 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 664 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -602 8192 ) ( 8192 -602 8192 ) ( -8192 -602 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -544 8192 ) ( -8192 -544 8192 ) ( -8192 -544 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 18 ) ( 8192 -8192 18 ) ( -8192 -8192 18 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7734 -2705 ) ( 8192 7612 3032 ) ( -8192 -7734 -2705 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 4493 6864 ) ( -8192 4493 6864 ) ( -8192 -5217 -6331 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7600 3063 ) ( 8192 -7746 -2674 ) ( -8192 -7746 -2674 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2240 7901 ) ( 8192 -2240 7901 ) ( 8192 1085 -8141 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 665 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -592 8192 ) ( 8192 -592 8192 ) ( -8192 -592 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -542 8192 ) ( -8192 -542 8192 ) ( -8192 -542 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -47 ) ( 8192 8192 -47 ) ( -8192 -8192 -47 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -30 ) ( 8192 -8192 -30 ) ( -8192 -8192 -30 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 4493 6864 ) ( 8192 4493 6864 ) ( -8192 -5217 -6331 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8032 -1609 ) ( 8192 8001 1757 ) ( -8192 8001 1757 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8078 -1365 ) ( 8192 -8114 1130 ) ( -8192 -8114 1130 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 666 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -580 8192 ) ( 8192 -580 8192 ) ( -8192 -580 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -392 8192 ) ( -8192 -392 8192 ) ( -8192 -392 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 18 ) ( 8192 -8192 18 ) ( -8192 -8192 18 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8114 1130 ) ( 8192 8078 -1365 ) ( -8192 -8114 1130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 -1609 ) ( 8192 8001 1757 ) ( -8192 8001 1757 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8086 -1311 ) ( 8192 -8106 1183 ) ( -8192 -8106 1183 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 4493 6864 ) ( 8192 4493 6864 ) ( -8192 -5217 -6331 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 667 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -592 8192 ) ( 8192 -592 8192 ) ( -8192 -592 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -542 8192 ) ( -8192 -542 8192 ) ( -8192 -542 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -47 ) ( 8192 8192 -47 ) ( -8192 -8192 -47 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -30 ) ( 8192 -8192 -30 ) ( -8192 -8192 -30 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8032 -1609 ) ( 8192 8001 1757 ) ( -8192 8001 1757 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 4493 6864 ) ( 8192 4493 6864 ) ( -8192 -5217 -6331 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8078 -1365 ) ( 8192 -8114 1130 ) ( -8192 -8114 1130 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 668 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -580 8192 ) ( 8192 -580 8192 ) ( -8192 -580 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -392 8192 ) ( -8192 -392 8192 ) ( -8192 -392 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 18 ) ( 8192 -8192 18 ) ( -8192 -8192 18 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8114 1130 ) ( 8192 8078 -1365 ) ( -8192 -8114 1130 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 4493 6864 ) ( 8192 4493 6864 ) ( -8192 -5217 -6331 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8086 -1311 ) ( 8192 -8106 1183 ) ( -8192 -8106 1183 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8032 -1609 ) ( 8192 8001 1757 ) ( -8192 8001 1757 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 669 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -595 8192 ) ( 8192 -595 8192 ) ( -8192 -595 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -580 8192 ) ( -8192 -580 8192 ) ( -8192 -580 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -47 ) ( 8192 8192 -47 ) ( -8192 -8192 -47 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -30 ) ( 8192 -8192 -30 ) ( -8192 -8192 -30 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 4493 6864 ) ( -8192 4493 6864 ) ( -8192 -5217 -6331 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2240 7901 ) ( 8192 -2240 7901 ) ( 8192 1085 -8141 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7612 3032 ) ( 8192 -7734 -2705 ) ( -8192 -7734 -2705 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 670 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -602 8192 ) ( 8192 -602 8192 ) ( -8192 -602 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -544 8192 ) ( -8192 -544 8192 ) ( -8192 -544 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -36 ) ( 8192 8192 -36 ) ( -8192 -8192 -36 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 18 ) ( 8192 -8192 18 ) ( -8192 -8192 18 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7734 -2705 ) ( 8192 7612 3032 ) ( -8192 -7734 -2705 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2240 7901 ) ( 8192 -2240 7901 ) ( 8192 1085 -8141 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7600 3063 ) ( 8192 -7746 -2674 ) ( -8192 -7746 -2674 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 4493 6864 ) ( -8192 4493 6864 ) ( -8192 -5217 -6331 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 671 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -602 8192 ) ( 8192 -602 8192 ) ( -8192 -602 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -544 8192 ) ( -8192 -544 8192 ) ( -8192 -544 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -3 ) ( 8192 8192 -3 ) ( -8192 -8192 -3 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 18 ) ( 8192 -8192 18 ) ( -8192 -8192 18 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -3398 7475 ) ( 8192 -3398 7475 ) ( 8192 2339 -7870 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7600 3063 ) ( 8192 -7746 -2674 ) ( -8192 -7746 -2674 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8086 -1311 ) ( 8192 -8106 1183 ) ( -8192 -8106 1183 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7745 -2675 ) ( 8192 7600 3063 ) ( -8192 7600 3063 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 672 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -544 8192 ) ( 8192 -544 8192 ) ( -8192 -544 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -392 8192 ) ( -8192 -392 8192 ) ( -8192 -392 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -5 ) ( 8192 8192 -5 ) ( -8192 -8192 -5 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 18 ) ( 8192 -8192 18 ) ( -8192 -8192 18 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7600 3063 ) ( 8192 -7746 -2674 ) ( -8192 -7746 -2674 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8086 -1311 ) ( 8192 -8106 1183 ) ( -8192 -8106 1183 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 865 8155 ) ( -8191 865 8155 ) ( -8191 -1629 -8037 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8106 1182 ) ( 8192 8086 -1312 ) ( -8192 8086 -1312 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 673 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -229 8192 ) ( 8192 -229 8192 ) ( -8192 -229 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -219 8192 ) ( -8192 -219 8192 ) ( -8192 -219 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -121 ) ( 8192 8192 -121 ) ( -8192 -8192 -121 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -102 ) ( 8192 -8192 -102 ) ( -8192 -8192 -102 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8191 4432 6890 ) ( -8191 4432 6890 ) ( -8191 -4633 -6756 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2072 7929 ) ( 8192 -2072 7929 ) ( 8192 1591 -8039 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 5662 -5924 ) ( 8192 -5991 5591 ) ( -8192 -5991 5591 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 674 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -243 8192 ) ( 8192 -243 8192 ) ( -8192 -243 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -201 8192 ) ( -8192 -201 8192 ) ( -8192 -201 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -112 ) ( 8192 8192 -112 ) ( -8192 -8192 -112 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -43 ) ( 8192 -8192 -43 ) ( -8192 -8192 -43 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -5991 5591 ) ( 8192 5662 -5924 ) ( -8192 -5991 5591 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2072 7929 ) ( 8192 -2072 7929 ) ( 8192 1591 -8039 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5684 -5901 ) ( 8192 -5968 5614 ) ( -8192 -5968 5614 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 4432 6890 ) ( -8191 4432 6890 ) ( -8191 -4633 -6756 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 675 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -266 8192 ) ( 8192 -266 8192 ) ( -8192 -266 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -225 8192 ) ( -8192 -225 8192 ) ( -8192 -225 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -121 ) ( 8192 8192 -121 ) ( -8192 -8192 -121 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -92 ) ( 8192 -8192 -92 ) ( -8192 -8192 -92 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -2072 7929 ) ( -8192 -2072 7929 ) ( 8192 1591 -8039 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -6790 4587 ) ( 8192 6522 -4962 ) ( -8192 6522 -4962 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7864 -2297 ) ( 8192 -7947 1990 ) ( -8192 -7947 1990 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 676 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -391 8192 ) ( 8192 -391 8192 ) ( -8192 -391 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -229 8192 ) ( -8192 -229 8192 ) ( -8192 -229 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -102 ) ( 8192 8192 -102 ) ( -8192 -8192 -102 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -3 ) ( 8192 -8192 -3 ) ( -8192 -8192 -3 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7947 1990 ) ( 8192 7864 -2297 ) ( -8192 -7947 1990 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -6790 4587 ) ( 8192 6522 -4962 ) ( -8192 6522 -4962 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7878 -2245 ) ( 8192 -7933 2042 ) ( -8192 -7933 2042 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -2072 7929 ) ( -8192 -2072 7929 ) ( 8192 1591 -8039 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 677 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -266 8192 ) ( 8192 -266 8192 ) ( -8192 -266 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -225 8192 ) ( -8192 -225 8192 ) ( -8192 -225 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -121 ) ( 8192 8192 -121 ) ( -8192 -8192 -121 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -92 ) ( 8192 -8192 -92 ) ( -8192 -8192 -92 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -6790 4587 ) ( 8192 6522 -4962 ) ( -8192 6522 -4962 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -2072 7929 ) ( -8192 -2072 7929 ) ( 8192 1591 -8039 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7864 -2297 ) ( 8192 -7947 1990 ) ( -8192 -7947 1990 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 678 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -391 8192 ) ( 8192 -391 8192 ) ( -8192 -391 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -229 8192 ) ( -8192 -229 8192 ) ( -8192 -229 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -102 ) ( 8192 8192 -102 ) ( -8192 -8192 -102 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -3 ) ( 8192 -8192 -3 ) ( -8192 -8192 -3 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7947 1990 ) ( 8192 7864 -2297 ) ( -8192 -7947 1990 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -2072 7929 ) ( -8192 -2072 7929 ) ( 8192 1591 -8039 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7878 -2245 ) ( 8192 -7933 2042 ) ( -8192 -7933 2042 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -6790 4587 ) ( 8192 6522 -4962 ) ( -8192 6522 -4962 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 679 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -229 8192 ) ( 8192 -229 8192 ) ( -8192 -229 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -219 8192 ) ( -8192 -219 8192 ) ( -8192 -219 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -121 ) ( 8192 8192 -121 ) ( -8192 -8192 -121 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -102 ) ( 8192 -8192 -102 ) ( -8192 -8192 -102 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2072 7929 ) ( 8192 -2072 7929 ) ( 8192 1591 -8039 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8191 4432 6890 ) ( -8191 4432 6890 ) ( -8191 -4633 -6756 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 5662 -5924 ) ( 8192 -5991 5591 ) ( -8192 -5991 5591 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 680 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -243 8192 ) ( 8192 -243 8192 ) ( -8192 -243 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -201 8192 ) ( -8192 -201 8192 ) ( -8192 -201 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -112 ) ( 8192 8192 -112 ) ( -8192 -8192 -112 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -43 ) ( 8192 -8192 -43 ) ( -8192 -8192 -43 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -5991 5591 ) ( 8192 5662 -5924 ) ( -8192 -5991 5591 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 4432 6890 ) ( -8191 4432 6890 ) ( -8191 -4633 -6756 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5684 -5901 ) ( 8192 -5968 5614 ) ( -8192 -5968 5614 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2072 7929 ) ( 8192 -2072 7929 ) ( 8192 1591 -8039 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 681 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -243 8192 ) ( 8192 -243 8192 ) ( -8192 -243 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -201 8192 ) ( -8192 -201 8192 ) ( -8192 -201 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -85 ) ( 8192 8192 -85 ) ( -8192 -8192 -85 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -43 ) ( 8192 -8192 -43 ) ( -8192 -8192 -43 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5699 5885 ) ( -8192 5699 5885 ) ( -8192 -5817 -5768 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -5969 5614 ) ( 8192 5684 -5902 ) ( -8192 5684 -5902 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7878 -2245 ) ( 8192 -7933 2042 ) ( -8192 -7933 2042 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5684 -5901 ) ( 8192 -5968 5614 ) ( -8192 -5968 5614 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 682 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -391 8192 ) ( 8192 -391 8192 ) ( -8192 -391 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -243 8192 ) ( -8192 -243 8192 ) ( -8192 -243 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -43 ) ( 8192 8192 -43 ) ( -8192 -8192 -43 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -3 ) ( 8192 -8192 -3 ) ( -8192 -8192 -3 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5684 -5901 ) ( 8192 -5968 5614 ) ( -8192 -5968 5614 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7934 2041 ) ( 8192 7878 -2246 ) ( -8192 7878 -2246 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1780 8004 ) ( 8192 1780 8004 ) ( 8192 -2507 -7807 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7878 -2245 ) ( 8192 -7933 2042 ) ( -8192 -7933 2042 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 683 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -197 -8192 8192 ) ( -197 8192 8192 ) ( -197 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -580 8192 ) ( 8192 -580 8192 ) ( -8192 -580 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -566 8192 ) ( -8192 -566 8192 ) ( -8192 -566 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -29 ) ( 8192 8192 -29 ) ( -8192 -8192 -29 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -18 ) ( 8192 -8192 -18 ) ( -8192 -8192 -18 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2001 7964 ) ( 8192 -2001 7964 ) ( 8192 867 -8166 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -6363 -5171 ) ( 8192 5881 5714 ) ( -8192 5881 5714 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7939 2023 ) ( 8192 -7992 -1800 ) ( -8192 -7992 -1800 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 684 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -197 -8192 8192 ) ( -197 8192 8192 ) ( -197 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -585 8192 ) ( 8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -21 ) ( 8192 8192 -21 ) ( -8192 -8192 -21 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7992 -1800 ) ( 8192 7939 2023 ) ( -8192 -7992 -1800 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -6363 -5171 ) ( 8192 5881 5714 ) ( -8192 5881 5714 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7933 2046 ) ( 8192 -7998 -1777 ) ( -8192 -7998 -1777 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2001 7964 ) ( 8192 -2001 7964 ) ( 8192 867 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 685 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -197 -8192 8192 ) ( -197 8192 8192 ) ( -197 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -579 8192 ) ( 8192 -579 8192 ) ( -8192 -579 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -29 ) ( 8192 8192 -29 ) ( -8192 -8192 -29 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -18 ) ( 8192 -8192 -18 ) ( -8192 -8192 -18 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 5881 5714 ) ( 8192 -6363 -5171 ) ( -8192 5881 5714 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8142 -904 ) ( 8192 8133 978 ) ( -8192 8133 978 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8098 -1237 ) ( 8192 -8125 1045 ) ( -8192 -8125 1045 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 686 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -197 -8192 8192 ) ( -197 8192 8192 ) ( -197 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -566 8192 ) ( 8192 -566 8192 ) ( -8192 -566 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -376 8192 ) ( -8192 -376 8192 ) ( -8192 -376 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -23 ) ( 8192 8192 -23 ) ( -8192 -8192 -23 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8125 1045 ) ( 8192 8098 -1237 ) ( -8192 -8125 1045 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 -904 ) ( 8192 8133 978 ) ( -8192 8133 978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8103 -1199 ) ( 8192 -8120 1084 ) ( -8192 -8120 1084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5881 5714 ) ( 8192 -6363 -5171 ) ( -8192 5881 5714 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 687 +{ +( -287 8192 8192 ) ( -287 -8192 8192 ) ( -287 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -286 -8192 8192 ) ( -286 8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -579 8192 ) ( 8192 -579 8192 ) ( -8192 -579 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -29 ) ( 8192 8192 -29 ) ( -8192 -8192 -29 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -18 ) ( 8192 -8192 -18 ) ( -8192 -8192 -18 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8142 -904 ) ( 8192 8133 978 ) ( -8192 8133 978 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 5881 5714 ) ( 8192 -6363 -5171 ) ( -8192 5881 5714 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8098 -1237 ) ( 8192 -8125 1045 ) ( -8192 -8125 1045 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 688 +{ +( -287 8192 8192 ) ( -287 -8192 8192 ) ( -287 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -286 -8192 8192 ) ( -286 8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -566 8192 ) ( 8192 -566 8192 ) ( -8192 -566 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -376 8192 ) ( -8192 -376 8192 ) ( -8192 -376 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -23 ) ( 8192 8192 -23 ) ( -8192 -8192 -23 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8125 1045 ) ( 8192 8098 -1237 ) ( -8192 -8125 1045 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5881 5714 ) ( 8192 -6363 -5171 ) ( -8192 5881 5714 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8103 -1199 ) ( 8192 -8120 1084 ) ( -8192 -8120 1084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 -904 ) ( 8192 8133 978 ) ( -8192 8133 978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 689 +{ +( -287 8192 8192 ) ( -287 -8192 8192 ) ( -287 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -286 -8192 8192 ) ( -286 8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -580 8192 ) ( 8192 -580 8192 ) ( -8192 -580 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -566 8192 ) ( -8192 -566 8192 ) ( -8192 -566 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -29 ) ( 8192 8192 -29 ) ( -8192 -8192 -29 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -18 ) ( 8192 -8192 -18 ) ( -8192 -8192 -18 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -6363 -5171 ) ( 8192 5881 5714 ) ( -8192 5881 5714 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2001 7964 ) ( 8192 -2001 7964 ) ( 8192 867 -8166 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7939 2023 ) ( 8192 -7992 -1800 ) ( -8192 -7992 -1800 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 690 +{ +( -287 8192 8192 ) ( -287 -8192 8192 ) ( -287 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -286 -8192 8192 ) ( -286 8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -585 8192 ) ( 8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -21 ) ( 8192 8192 -21 ) ( -8192 -8192 -21 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7992 -1800 ) ( 8192 7939 2023 ) ( -8192 -7992 -1800 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2001 7964 ) ( 8192 -2001 7964 ) ( 8192 867 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7933 2046 ) ( 8192 -7998 -1777 ) ( -8192 -7998 -1777 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -6363 -5171 ) ( 8192 5881 5714 ) ( -8192 5881 5714 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 691 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -585 8192 ) ( 8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 2 ) ( 8192 8192 2 ) ( -8192 -8192 2 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2464 7833 ) ( 8192 -2464 7833 ) ( 8192 1359 -8098 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7933 2047 ) ( 8192 -7998 -1776 ) ( -8192 -7998 -1776 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8103 -1199 ) ( 8192 -8120 1084 ) ( -8192 -8120 1084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7998 -1777 ) ( 8192 7933 2046 ) ( -8192 -7998 -1777 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 692 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -528 8192 ) ( 8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -376 8192 ) ( -8192 -376 8192 ) ( -8192 -376 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -6 ) ( 8192 8192 -6 ) ( -8192 -8192 -6 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7933 2046 ) ( 8192 -7998 -1777 ) ( -8192 -7998 -1777 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8104 -1198 ) ( 8192 -8120 1085 ) ( -8192 -8120 1085 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 773 8163 ) ( -8192 773 8163 ) ( -8192 -1509 -8060 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8120 1084 ) ( 8192 8103 -1199 ) ( -8192 -8120 1084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 693 +{ +( 600 8192 8192 ) ( 600 -8192 8192 ) ( 600 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 630 -8192 8192 ) ( 630 8192 8192 ) ( 630 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -442 8192 ) ( 8192 -442 8192 ) ( -8192 -442 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -352 8192 ) ( -8192 -352 8192 ) ( -8192 -352 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -56 ) ( 8192 -8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -2156 7916 8192 ) ( 3024 -7626 8192 ) ( 3024 -7626 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3025 -7626 8192 ) ( -2155 7916 8192 ) ( -2155 7916 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3236 7556 8192 ) ( -1944 -7986 8192 ) ( -1944 -7986 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7841 2381 8192 ) ( 7702 -2799 8192 ) ( 7702 -2799 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 694 +{ +( 630 8192 8192 ) ( 630 -8192 8192 ) ( 630 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 720 -8192 8192 ) ( 720 8192 8192 ) ( 720 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -472 8192 ) ( 8192 -472 8192 ) ( -8192 -472 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -442 8192 ) ( -8192 -442 8192 ) ( -8192 -442 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -56 ) ( 8192 -8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7841 2381 8192 ) ( 7702 -2799 8192 ) ( 7702 -2799 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7702 -2798 8192 ) ( -7840 2382 8192 ) ( -7840 2382 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -2156 7916 8192 ) ( 3024 -7626 8192 ) ( 3024 -7626 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7558 -3231 8192 ) ( 7985 1949 8192 ) ( 7985 1949 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 695 +{ +( 720 8192 8192 ) ( 720 -8192 8192 ) ( 720 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 810 -8192 8192 ) ( 810 8192 8192 ) ( 810 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -472 8192 ) ( 8192 -472 8192 ) ( -8192 -472 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -442 8192 ) ( -8192 -442 8192 ) ( -8192 -442 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -56 ) ( 8192 -8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7558 -3231 8192 ) ( 7985 1949 8192 ) ( 7985 1949 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7984 1950 8192 ) ( -7558 -3230 8192 ) ( -7558 -3230 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7841 2381 8192 ) ( 7702 -2799 8192 ) ( 7702 -2799 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1728 -8058 8192 ) ( 3452 7484 8192 ) ( 3452 7484 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 696 +{ +( 810 8192 8192 ) ( 810 -8192 8192 ) ( 810 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 840 -8192 8192 ) ( 840 8192 8192 ) ( 840 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -442 8192 ) ( 8192 -442 8192 ) ( -8192 -442 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -352 8192 ) ( -8192 -352 8192 ) ( -8192 -352 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -56 ) ( 8192 -8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1728 -8058 8192 ) ( 3452 7484 8192 ) ( 3452 7484 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3451 7484 8192 ) ( -1729 -8058 8192 ) ( -1729 -8058 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7558 -3231 8192 ) ( 7985 1949 8192 ) ( 7985 1949 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3240 -7554 8192 ) ( -1940 7988 8192 ) ( -1940 7988 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 697 +{ +( 808 8192 8192 ) ( 808 -8192 8192 ) ( 808 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 840 -8192 8192 ) ( 840 8192 8192 ) ( 840 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -352 8192 ) ( 8192 -352 8192 ) ( -8192 -352 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -262 8192 ) ( -8192 -262 8192 ) ( -8192 -262 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -56 ) ( 8192 -8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3240 -7554 8192 ) ( -1940 7988 8192 ) ( -1940 7988 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1943 7988 8192 ) ( 3237 -7555 8192 ) ( 3237 -7555 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1728 -8058 8192 ) ( 3452 7484 8192 ) ( 3452 7484 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7774 -2583 8192 ) ( -7769 2597 8192 ) ( -7769 2597 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 698 +{ +( 720 8192 8192 ) ( 720 -8192 8192 ) ( 720 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 810 -8192 8192 ) ( 810 8192 8192 ) ( 810 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8190 -264 8192 ) ( 8194 -264 8192 ) ( -8190 -264 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -232 8192 ) ( -8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -56 ) ( 8192 -8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7774 -2583 8192 ) ( -7769 2597 8192 ) ( -7769 2597 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7767 2594 8192 ) ( 7775 -2586 8192 ) ( 7775 -2586 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3240 -7554 8192 ) ( -1940 7988 8192 ) ( -1940 7988 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7913 2165 8192 ) ( -7630 -3015 8192 ) ( -7630 -3015 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 699 +{ +( 630 8192 8192 ) ( 630 -8192 8192 ) ( 630 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 720 -8192 8192 ) ( 720 8192 8192 ) ( 720 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8196 -264 8192 ) ( 8188 -264 8192 ) ( -8196 -264 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -232 8192 ) ( -8192 -232 8192 ) ( -8192 -232 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -56 ) ( 8192 -8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7913 2165 8192 ) ( -7630 -3015 8192 ) ( -7630 -3015 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -7633 -3018 8192 ) ( 7909 2162 8192 ) ( 7909 2162 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7774 -2583 8192 ) ( -7769 2597 8192 ) ( -7769 2597 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3236 7556 8192 ) ( -1944 -7986 8192 ) ( -1944 -7986 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 700 +{ +( 600 8192 8192 ) ( 600 -8192 8192 ) ( 600 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 630 -8192 8192 ) ( 630 8192 8192 ) ( 630 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -352 8192 ) ( 8192 -352 8192 ) ( -8192 -352 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -262 8192 ) ( -8192 -262 8192 ) ( -8192 -262 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -56 ) ( 8192 -8192 -56 ) ( -8192 -8192 -56 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 3236 7556 8192 ) ( -1944 -7986 8192 ) ( -1944 -7986 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -1943 -7987 8192 ) ( 3237 7556 8192 ) ( 3237 7556 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 7913 2165 8192 ) ( -7630 -3015 8192 ) ( -7630 -3015 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -2156 7916 8192 ) ( 3024 -7626 8192 ) ( 3024 -7626 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 701 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -580 8192 ) ( 8192 -580 8192 ) ( -8192 -580 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -566 8192 ) ( -8192 -566 8192 ) ( -8192 -566 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -29 ) ( 8192 8192 -29 ) ( -8192 -8192 -29 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -18 ) ( 8192 -8192 -18 ) ( -8192 -8192 -18 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2001 7964 ) ( 8192 -2001 7964 ) ( 8192 867 -8166 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -6363 -5171 ) ( 8192 5881 5714 ) ( -8192 5881 5714 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7939 2023 ) ( 8192 -7992 -1800 ) ( -8192 -7992 -1800 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 702 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -585 8192 ) ( 8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -21 ) ( 8192 8192 -21 ) ( -8192 -8192 -21 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7992 -1800 ) ( 8192 7939 2023 ) ( -8192 -7992 -1800 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -6363 -5171 ) ( 8192 5881 5714 ) ( -8192 5881 5714 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7933 2046 ) ( 8192 -7998 -1777 ) ( -8192 -7998 -1777 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2001 7964 ) ( 8192 -2001 7964 ) ( 8192 867 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 703 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -579 8192 ) ( 8192 -579 8192 ) ( -8192 -579 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -29 ) ( 8192 8192 -29 ) ( -8192 -8192 -29 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -18 ) ( 8192 -8192 -18 ) ( -8192 -8192 -18 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 5881 5714 ) ( 8192 -6363 -5171 ) ( -8192 5881 5714 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8142 -904 ) ( 8192 8133 978 ) ( -8192 8133 978 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8098 -1237 ) ( 8192 -8125 1045 ) ( -8192 -8125 1045 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 704 +{ +( -286 8192 8192 ) ( -286 -8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -285 -8192 8192 ) ( -285 8192 8192 ) ( -285 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -566 8192 ) ( 8192 -566 8192 ) ( -8192 -566 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -376 8192 ) ( -8192 -376 8192 ) ( -8192 -376 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -23 ) ( 8192 8192 -23 ) ( -8192 -8192 -23 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8125 1045 ) ( 8192 8098 -1237 ) ( -8192 -8125 1045 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 -904 ) ( 8192 8133 978 ) ( -8192 8133 978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8103 -1199 ) ( 8192 -8120 1084 ) ( -8192 -8120 1084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5881 5714 ) ( 8192 -6363 -5171 ) ( -8192 5881 5714 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 705 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -579 8192 ) ( 8192 -579 8192 ) ( -8192 -579 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -29 ) ( 8192 8192 -29 ) ( -8192 -8192 -29 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -18 ) ( 8192 -8192 -18 ) ( -8192 -8192 -18 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8142 -904 ) ( 8192 8133 978 ) ( -8192 8133 978 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 5881 5714 ) ( 8192 -6363 -5171 ) ( -8192 5881 5714 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8098 -1237 ) ( 8192 -8125 1045 ) ( -8192 -8125 1045 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 706 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -566 8192 ) ( 8192 -566 8192 ) ( -8192 -566 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -376 8192 ) ( -8192 -376 8192 ) ( -8192 -376 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -23 ) ( 8192 8192 -23 ) ( -8192 -8192 -23 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8125 1045 ) ( 8192 8098 -1237 ) ( -8192 -8125 1045 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5881 5714 ) ( 8192 -6363 -5171 ) ( -8192 5881 5714 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8103 -1199 ) ( 8192 -8120 1084 ) ( -8192 -8120 1084 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8142 -904 ) ( 8192 8133 978 ) ( -8192 8133 978 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 707 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -580 8192 ) ( 8192 -580 8192 ) ( -8192 -580 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -566 8192 ) ( -8192 -566 8192 ) ( -8192 -566 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -29 ) ( 8192 8192 -29 ) ( -8192 -8192 -29 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -18 ) ( 8192 -8192 -18 ) ( -8192 -8192 -18 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -6363 -5171 ) ( 8192 5881 5714 ) ( -8192 5881 5714 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2001 7964 ) ( 8192 -2001 7964 ) ( 8192 867 -8166 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7939 2023 ) ( 8192 -7992 -1800 ) ( -8192 -7992 -1800 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 708 +{ +( -199 8192 8192 ) ( -199 -8192 8192 ) ( -199 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -198 -8192 8192 ) ( -198 8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -585 8192 ) ( 8192 -585 8192 ) ( -8192 -585 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -528 8192 ) ( -8192 -528 8192 ) ( -8192 -528 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -21 ) ( 8192 8192 -21 ) ( -8192 -8192 -21 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 15 ) ( 8192 -8192 15 ) ( -8192 -8192 15 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7992 -1800 ) ( 8192 7939 2023 ) ( -8192 -7992 -1800 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2001 7964 ) ( 8192 -2001 7964 ) ( 8192 867 -8166 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7933 2046 ) ( 8192 -7998 -1777 ) ( -8192 -7998 -1777 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -6363 -5171 ) ( 8192 5881 5714 ) ( -8192 5881 5714 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 709 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -197 -8192 8192 ) ( -197 8192 8192 ) ( -197 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -274 8192 ) ( 8192 -274 8192 ) ( -8192 -274 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -233 8192 ) ( -8192 -233 8192 ) ( -8192 -233 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -129 ) ( 8192 8192 -129 ) ( -8192 -8192 -129 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -100 ) ( 8192 -8192 -100 ) ( -8192 -8192 -100 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -6797 4578 ) ( 8192 6515 -4971 ) ( -8192 6515 -4971 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -2081 7927 ) ( -8192 -2081 7927 ) ( -8192 1581 -8041 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7862 -2306 ) ( 8192 -7950 1981 ) ( -8192 -7950 1981 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 710 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -197 -8192 8192 ) ( -197 8192 8192 ) ( -197 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -399 8192 ) ( 8192 -399 8192 ) ( -8192 -399 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -237 8192 ) ( -8192 -237 8192 ) ( -8192 -237 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -110 ) ( 8192 8192 -110 ) ( -8192 -8192 -110 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -11 ) ( 8192 -8192 -11 ) ( -8192 -8192 -11 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7950 1981 ) ( 8192 7862 -2306 ) ( -8192 -7950 1981 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -2081 7927 ) ( -8192 -2081 7927 ) ( -8192 1581 -8041 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7876 -2255 ) ( 8192 -7936 2033 ) ( -8192 7876 -2255 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -6797 4578 ) ( 8192 6515 -4971 ) ( -8192 6515 -4971 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 711 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -197 -8192 8192 ) ( -197 8192 8192 ) ( -197 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -237 8192 ) ( 8192 -237 8192 ) ( -8192 -237 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -227 8192 ) ( -8192 -227 8192 ) ( -8192 -227 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -129 ) ( 8192 8192 -129 ) ( -8192 -8192 -129 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -110 ) ( 8192 -8192 -110 ) ( -8192 -8192 -110 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2081 7927 ) ( 8192 -2081 7927 ) ( -8192 1581 -8041 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8191 4430 6891 ) ( -8191 4430 6891 ) ( -8191 -4635 -6755 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 5654 -5932 ) ( 8192 -5999 5583 ) ( -8192 -5999 5583 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 712 +{ +( -198 8192 8192 ) ( -198 -8192 8192 ) ( -198 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -197 -8192 8192 ) ( -197 8192 8192 ) ( -197 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -251 8192 ) ( 8192 -251 8192 ) ( -8192 -251 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -209 8192 ) ( -8192 -209 8192 ) ( -8192 -209 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -51 ) ( 8192 -8192 -51 ) ( -8192 -8192 -51 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -5999 5583 ) ( 8192 5654 -5932 ) ( -8192 -5999 5583 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 4430 6891 ) ( -8191 4430 6891 ) ( -8191 -4635 -6755 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5677 -5909 ) ( 8192 -5976 5606 ) ( -8192 5677 -5909 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2081 7927 ) ( 8192 -2081 7927 ) ( -8192 1581 -8041 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 713 +{ +( -287 8192 8192 ) ( -287 -8192 8192 ) ( -287 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -286 -8192 8192 ) ( -286 8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -237 8192 ) ( 8192 -237 8192 ) ( -8192 -237 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -227 8192 ) ( -8192 -227 8192 ) ( -8192 -227 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -129 ) ( 8192 8192 -129 ) ( -8192 -8192 -129 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -110 ) ( 8192 -8192 -110 ) ( -8192 -8192 -110 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8191 4430 6891 ) ( -8191 4430 6891 ) ( -8191 -4635 -6755 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -2081 7927 ) ( 8192 -2081 7927 ) ( -8192 1581 -8041 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 5654 -5932 ) ( 8192 -5999 5583 ) ( -8192 -5999 5583 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 714 +{ +( -287 8192 8192 ) ( -287 -8192 8192 ) ( -287 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -286 -8192 8192 ) ( -286 8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -251 8192 ) ( 8192 -251 8192 ) ( -8192 -251 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -209 8192 ) ( -8192 -209 8192 ) ( -8192 -209 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -120 ) ( 8192 8192 -120 ) ( -8192 -8192 -120 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -51 ) ( 8192 -8192 -51 ) ( -8192 -8192 -51 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -5999 5583 ) ( 8192 5654 -5932 ) ( -8192 -5999 5583 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -2081 7927 ) ( 8192 -2081 7927 ) ( -8192 1581 -8041 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 5677 -5909 ) ( 8192 -5976 5606 ) ( -8192 5677 -5909 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8191 4430 6891 ) ( -8191 4430 6891 ) ( -8191 -4635 -6755 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 715 +{ +( -287 8192 8192 ) ( -287 -8192 8192 ) ( -287 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -286 -8192 8192 ) ( -286 8192 8192 ) ( -286 8192 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( -8192 -274 8192 ) ( 8192 -274 8192 ) ( -8192 -274 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -233 8192 ) ( -8192 -233 8192 ) ( -8192 -233 -8192 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -8192 -129 ) ( 8192 8192 -129 ) ( -8192 -8192 -129 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 8192 -100 ) ( 8192 -8192 -100 ) ( -8192 -8192 -100 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -2081 7927 ) ( -8192 -2081 7927 ) ( -8192 1581 -8041 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 -6797 4578 ) ( 8192 6515 -4971 ) ( -8192 6515 -4971 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +( 8192 7862 -2306 ) ( 8192 -7950 1981 ) ( -8192 -7950 1981 ) e2u3/floor1_2 0 0 0 1 1 1 0 0 +} +// brush 716 +{ +( -287 8192 8192 ) ( -287 -8192 8192 ) ( -287 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -286 -8192 8192 ) ( -286 8192 8192 ) ( -286 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -399 8192 ) ( 8192 -399 8192 ) ( -8192 -399 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -237 8192 ) ( -8192 -237 8192 ) ( -8192 -237 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -110 ) ( 8192 8192 -110 ) ( -8192 -8192 -110 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -11 ) ( 8192 -8192 -11 ) ( -8192 -8192 -11 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -7950 1981 ) ( 8192 7862 -2306 ) ( -8192 -7950 1981 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -6797 4578 ) ( 8192 6515 -4971 ) ( -8192 6515 -4971 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7876 -2255 ) ( 8192 -7936 2033 ) ( -8192 7876 -2255 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -2081 7927 ) ( -8192 -2081 7927 ) ( -8192 1581 -8041 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 1 +{ +"classname" "path_corner" +"targetname" "topUC" +"origin" "-1467 -676 -203" +} +// entity 2 +{ +"classname" "trigger_push" +"target" "topUC" +// brush 0 +{ +( -402 656 -455 ) ( -423 632 -450 ) ( -392 612 -413 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -432 677 -471 ) ( -453 654 -466 ) ( -412 621 -464 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -459 703 -457 ) ( -480 679 -453 ) ( -453 651 -488 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -469 717 -421 ) ( -489 693 -416 ) ( -492 686 -469 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -455 712 -383 ) ( -476 688 -380 ) ( -506 707 -417 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -426 690 -367 ) ( -447 666 -363 ) ( -487 699 -365 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -399 665 -381 ) ( -419 640 -377 ) ( -445 669 -342 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -389 650 -416 ) ( -410 626 -413 ) ( -407 632 -361 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -539 644 -453 ) ( -466 582 -449 ) ( -460 595 -346 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +( -462 574 -352 ) ( -467 562 -455 ) ( -540 623 -459 ) desktop/partition 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 3 +{ +"classname" "weapon_railgun" +"origin" "-320 944 240" +} +// entity 4 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + desktop/deskwood + ( 3 3 0 0 0 ) +( +( ( -360 160 -136 0 0.250000 ) ( -360 160 -152 0 0.125000 ) ( -360 160 -168 0 0 ) ) +( ( 368 160 -136 5.687500 0.250000 ) ( 368 160 -152 5.687500 0.125000 ) ( 368 160 -168 5.687500 0 ) ) +( ( 368 928 -136 11.687500 0.250000 ) ( 368 928 -152 11.687500 0.125000 ) ( 368 928 -168 11.687500 0 ) ) +) + } + } +} +// entity 5 +{ +"origin" "-520 744 -400" +"classname" "item_health_mega" +} +// entity 6 +{ +"origin" "-1416 -288 -648" +"classname" "item_quad" +"spawnflags" "1" +} +// entity 7 +{ +"origin" "-72 -144 -104" +"classname" "weapon_rocketlauncher" +} +// entity 8 +{ +"origin" "1508 -360 234" +"classname" "info_player_deathmatch" +} +// entity 9 +{ +"origin" "576 1152 -320" +"classname" "item_health_large" +} +// entity 10 +{ +"origin" "656 1304 -320" +"classname" "item_armor_body" +} +// entity 11 +{ +"origin" "648 904 -320" +"classname" "weapon_shotgun" +} +// entity 12 +{ +"origin" "1864 1120 -320" +"classname" "weapon_railgun" +} +// entity 13 +{ +"origin" "160 -304 80" +"light" "10000" +"classname" "light" +} +// entity 14 +{ +"classname" "light" +"light" "10000" +"origin" "-1064 312 -1160" +} +// entity 15 +{ +"classname" "weapon_bfg" +"origin" "-1064 304 -1152" +} +// entity 16 +{ +"dmg" "300" +"classname" "trigger_hurt" +// brush 0 +{ +( -8192 166 8192 ) ( 8192 166 8192 ) ( -8192 166 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1192 ) ( 8192 8192 -1192 ) ( -8192 -8192 -1192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1176 ) ( 8192 -8192 -1176 ) ( -8192 -8192 -1176 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -2557 7866 8192 ) ( 308 -8265 8192 ) ( -2557 7866 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6656 4811 8192 ) ( 5895 -5718 8192 ) ( -6656 4811 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3563 -7402 8192 ) ( -4645 6776 8192 ) ( 3563 -7402 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 3042 7704 8192 ) ( -5166 -6474 8192 ) ( 3042 7704 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7418 3566 8192 ) ( -7969 -2058 8192 ) ( 7418 3566 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -6778 -4665 8192 ) ( 5772 5864 8192 ) ( -6778 -4665 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -2382 -7897 8192 ) ( 483 8234 8192 ) ( -2382 -7897 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 7718 -2746 8192 ) ( -7670 2877 8192 ) ( 7718 -2746 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 17 +{ +"classname" "info_player_deathmatch" +"origin" "-1464 -824 -976" +} +// entity 18 +{ +"light" "10000" +"origin" "-1416 -736 -792" +"classname" "light" +} +// entity 19 +{ +"origin" "-1462 -874 -982" +"classname" "item_armor_combat" +} +// entity 20 +{ +"origin" "-1462 -920 -982" +"classname" "weapon_grenadelauncher" +} +// entity 21 +{ +"origin" "160 -228 222" +"targetname" "bilbo" +"classname" "target_teleporter" +} +// entity 22 +{ +"target" "bilbo" +"classname" "trigger_teleport" +// brush 0 +{ +( -1498 8192 8192 ) ( -1498 -8192 8192 ) ( -1498 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -1422 -8192 8192 ) ( -1422 8192 8192 ) ( -1422 8192 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -962 8192 ) ( 8192 -962 8192 ) ( -8192 -962 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -954 8192 ) ( -8192 -954 8192 ) ( -8192 -954 -8192 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1006 ) ( 8192 8192 -1006 ) ( -8192 -8192 -1006 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -930 ) ( 8192 -8192 -930 ) ( -8192 -8192 -930 ) desktop/ci1 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 23 +{ +"classname" "target_teleporter" +"targetname" "central" +"origin" "-1458 -910 -1142" +} +// entity 24 +{ +"classname" "trigger_teleport" +"target" "central" +// brush 0 +{ +( 136 8192 8192 ) ( 136 -8192 8192 ) ( 136 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 182 -8192 8192 ) ( 182 8192 8192 ) ( 182 8192 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( -8192 -424 8192 ) ( 8192 -424 8192 ) ( -8192 -424 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -416 8192 ) ( -8192 -416 8192 ) ( -8192 -416 -8192 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 18 ) ( 8192 8192 18 ) ( -8192 -8192 18 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 106 ) ( 8192 -8192 106 ) ( -8192 -8192 106 ) desktop/ci3 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 25 +{ +"origin" "-1264 -240 -544" +"light" "10000" +"classname" "light" +} +// entity 26 +{ +"origin" "1984 1000 368" +"classname" "ammo_rockets" +} +// entity 27 +{ +"origin" "1984 1432 368" +"classname" "weapon_rocketlauncher" +} +// entity 28 +{ +"origin" "1624 1288 368" +"classname" "item_armor_shard" +} +// entity 29 +{ +"origin" "1376 1192 368" +"classname" "item_health" +} +// entity 30 +{ +"origin" "792 -312 720" +"classname" "item_health_large" +} +// entity 31 +{ +"classname" "func_train" +"target" "drawerclosed" +"spawnflags" "1" +"origin" "376 1096 -496" +// brush 0 +{ +( 384 8192 8192 ) ( 384 -8192 8192 ) ( 384 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 400 -8192 8192 ) ( 400 8192 8192 ) ( 400 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 736 8192 ) ( 8192 736 8192 ) ( -8192 736 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1456 8192 ) ( -8192 1456 8192 ) ( -8192 1456 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -592 ) ( 8192 8192 -592 ) ( -8192 -8192 -592 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -424 ) ( 8192 -8192 -424 ) ( -8192 -8192 -424 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 1 +{ +( 384 8192 8192 ) ( 384 -8192 8192 ) ( 384 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2000 -8192 8192 ) ( 2000 8192 8192 ) ( 2000 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 720 8192 ) ( 8192 720 8192 ) ( -8192 720 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 736 8192 ) ( -8192 736 8192 ) ( -8192 736 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -592 ) ( 8192 8192 -592 ) ( -8192 -8192 -592 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -424 ) ( 8192 -8192 -424 ) ( -8192 -8192 -424 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 2 +{ +( 384 8192 8192 ) ( 384 -8192 8192 ) ( 384 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2000 -8192 8192 ) ( 2000 8192 8192 ) ( 2000 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 720 8192 ) ( 8192 720 8192 ) ( -8192 720 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1472 8192 ) ( -8192 1472 8192 ) ( -8192 1472 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -608 ) ( 8192 8192 -608 ) ( -8192 -8192 -608 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -592 ) ( 8192 -8192 -592 ) ( -8192 -8192 -592 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 3 +{ +( 384 8192 8192 ) ( 384 -8192 8192 ) ( 384 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2000 -8192 8192 ) ( 2000 8192 8192 ) ( 2000 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1456 8192 ) ( 8192 1456 8192 ) ( -8192 1456 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1472 8192 ) ( -8192 1472 8192 ) ( -8192 1472 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -592 ) ( 8192 8192 -592 ) ( -8192 -8192 -592 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -424 ) ( 8192 -8192 -424 ) ( -8192 -8192 -424 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 4 +{ +( 1984 8192 8192 ) ( 1984 -8192 8192 ) ( 1984 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 2000 -8192 8192 ) ( 2000 8192 8192 ) ( 2000 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 736 8192 ) ( 8192 736 8192 ) ( -8192 736 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1456 8192 ) ( -8192 1456 8192 ) ( -8192 1456 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -592 ) ( 8192 8192 -592 ) ( -8192 -8192 -592 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -424 ) ( 8192 -8192 -424 ) ( -8192 -8192 -424 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 5 +{ +( 8192 -8192 -456 ) ( 8192 8192 -456 ) ( -8192 -8192 -456 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -440 ) ( 8192 -8192 -440 ) ( -8192 -8192 -440 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8281 207 8192 ) ( -7975 2240 8192 ) ( -7975 2240 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 1199 8105 8192 ) ( -832 -8151 8192 ) ( -832 -8151 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8102 1688 8192 ) ( 8249 666 8192 ) ( 8249 666 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -843 -8150 8192 ) ( 1220 8102 8192 ) ( 1220 8102 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 6 +{ +( 8192 -8192 -456 ) ( 8192 8192 -456 ) ( -8192 -8192 -456 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -440 ) ( 8192 -8192 -440 ) ( -8192 -8192 -440 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8247 -866 8192 ) ( -7583 3354 8192 ) ( -7583 3354 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 3191 7547 8192 ) ( -3531 -7393 8192 ) ( -3531 -7393 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -7594 3315 8192 ) ( 8236 -906 8192 ) ( 8236 -906 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -3517 -7400 8192 ) ( 3206 7540 8192 ) ( 3206 7540 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 7 +{ +( -8192 1131 8192 ) ( 8192 1131 8192 ) ( -8192 1131 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -456 ) ( 8192 8192 -456 ) ( -8192 -8192 -456 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -440 ) ( 8192 -8192 -440 ) ( -8192 -8192 -440 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 768 8159 8192 ) ( -253 -8192 8192 ) ( -253 -8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8249 667 8192 ) ( -8102 1689 8192 ) ( -8102 1689 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -255 -8192 8192 ) ( 782 8158 8192 ) ( 782 8158 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 8 +{ +( 330 8192 8192 ) ( 330 -8192 8192 ) ( 330 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 336 -8192 8192 ) ( 336 8192 8192 ) ( 336 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1083 8192 ) ( 8192 1083 8192 ) ( -8192 1083 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1131 8192 ) ( -8192 1131 8192 ) ( -8192 1131 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -456 ) ( 8192 8192 -456 ) ( -8192 -8192 -456 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -440 ) ( 8192 -8192 -440 ) ( -8192 -8192 -440 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 9 +{ +( 8192 1083 8192 ) ( -8192 1083 8192 ) ( -8192 1083 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -456 ) ( 8192 8192 -456 ) ( -8192 -8192 -456 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -440 ) ( 8192 -8192 -440 ) ( -8192 -8192 -440 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -115 8200 8192 ) ( 906 -8151 8192 ) ( 906 -8151 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8240 516 8192 ) ( 8111 1538 8192 ) ( 8111 1538 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 921 -8149 8192 ) ( -116 8201 8192 ) ( -116 8201 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 10 +{ +( 8192 -8192 -456 ) ( 8192 8192 -456 ) ( -8192 -8192 -456 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -440 ) ( 8192 -8192 -440 ) ( -8192 -8192 -440 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8248 -60 8192 ) ( 8009 1972 8192 ) ( 8009 1972 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -560 8185 8192 ) ( 1471 -8071 8192 ) ( 1471 -8071 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8111 1538 8192 ) ( -8240 516 8192 ) ( -8240 516 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 1495 -8067 8192 ) ( -568 8185 8192 ) ( -568 8185 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 11 +{ +( 8192 -8192 -456 ) ( 8192 8192 -456 ) ( -8192 -8192 -456 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -440 ) ( 8192 -8192 -440 ) ( -8192 -8192 -440 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 2563 -7803 8192 ) ( -1410 8091 8192 ) ( -1410 8091 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -5807 5861 8192 ) ( 7029 -4319 8192 ) ( 7029 -4319 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 6637 4844 8192 ) ( -7315 -3742 8192 ) ( -7315 -3742 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 12 +{ +( 8192 -8192 -456 ) ( 8192 8192 -456 ) ( -8192 -8192 -456 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -440 ) ( 8192 -8192 -440 ) ( -8192 -8192 -440 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8134 -1287 8192 ) ( 7695 2933 8192 ) ( 7695 2933 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -2703 7766 8192 ) ( 4020 -7174 8192 ) ( 4020 -7174 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 7685 2973 8192 ) ( -8145 -1248 8192 ) ( -8145 -1248 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 4034 -7167 8192 ) ( -2688 7773 8192 ) ( -2688 7773 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 13 +{ +( 368 8192 8192 ) ( 368 -8192 8192 ) ( 368 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 384 -8192 8192 ) ( 384 8192 8192 ) ( 384 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 720 8192 ) ( 8192 720 8192 ) ( -8192 720 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1472 8192 ) ( -8192 1472 8192 ) ( -8192 1472 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -632 ) ( 8192 8192 -632 ) ( -8192 -8192 -632 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -360 ) ( 8192 -8192 -360 ) ( -8192 -8192 -360 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 14 +{ +( 360 8192 8192 ) ( 360 -8192 8192 ) ( 360 -8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 392 -8192 8192 ) ( 392 8192 8192 ) ( 392 8192 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1080 8192 ) ( 8192 1080 8192 ) ( 8192 1080 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1112 8192 ) ( -8192 1112 8192 ) ( -8192 1112 -8192 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -512 ) ( 8192 8192 -512 ) ( -8192 8192 -512 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -480 ) ( 8192 -8192 -480 ) ( -8192 -8192 -480 ) desktop/deskwood 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 32 +{ +"origin" "-70 -144 -136" +"model" "models/mapobjects/mug/mug.md3" +"classname" "misc_model" +} +// entity 33 +{ +"classname" "trigger_push" +"target" "pathtoscreen2" +// brush 0 +{ +( 56 8192 8192 ) ( 56 -8192 8192 ) ( 56 8192 -8192 ) desktop/interface 0 0 0 0.500000 0.500000 0 0 0 +( 140 -8192 8192 ) ( 140 8192 8192 ) ( 140 8192 -8192 ) desktop/interface 0 0 0 0.500000 0.500000 0 0 0 +( -8192 32 8192 ) ( 8192 32 8192 ) ( -8192 32 -8192 ) desktop/interface 0 0 0 0.500000 0.500000 0 0 0 +( 8192 70 8192 ) ( -8192 70 8192 ) ( -8192 70 -8192 ) desktop/interface 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -132 ) ( 8192 8192 -132 ) ( -8192 -8192 -132 ) desktop/interface 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -130 ) ( 8192 -8192 -130 ) ( -8192 -8192 -130 ) desktop/interface 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 34 +{ +"origin" "1504 952 664" +"targetname" "stapleremoverpath" +"classname" "path_corner" +} +// entity 35 +{ +"target" "stapleremoverpath" +"name" "stapleremover" +"classname" "trigger_push" +// brush 0 +{ +( 1481 8192 8192 ) ( 1481 -8192 8192 ) ( 1481 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 1520 -8192 8192 ) ( 1520 8192 8192 ) ( 1520 8192 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( -8192 700 8192 ) ( 8192 700 8192 ) ( -8192 700 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 724 8192 ) ( -8192 724 8192 ) ( -8192 724 -8192 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -103 ) ( 8192 8192 -103 ) ( -8192 -8192 -103 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -87 ) ( 8192 -8192 -87 ) ( -8192 -8192 -87 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +( 8192 7506 -3288 ) ( 8192 -7318 3687 ) ( -8192 -7318 3687 ) desktop/plastic 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 36 +{ +"target" "" +"targetname" "pathtoscreen" +"origin" "144 696 -18" +"classname" "path_corner" +} +// entity 37 +{ +"target" "pathtoscreen" +"classname" "trigger_push" +// brush 0 +{ +( 96 8192 8192 ) ( 96 -8192 8192 ) ( 96 8192 -8192 ) desktop/jspbookcover 0 0 0 0.500000 0.500000 0 0 0 +( 192 -8192 8192 ) ( 192 8192 8192 ) ( 192 8192 -8192 ) desktop/jspbookcover 0 0 0 0.500000 0.500000 0 0 0 +( -8192 672 8192 ) ( 8192 672 8192 ) ( -8192 672 -8192 ) desktop/jspbookcover 0 0 0 0.500000 0.500000 0 0 0 +( 8192 728 8192 ) ( -8192 728 8192 ) ( -8192 728 -8192 ) desktop/jspbookcover 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -1120 ) ( 8192 8192 -1120 ) ( -8192 -8192 -1120 ) desktop/jspbookcover 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -1112 ) ( 8192 -8192 -1112 ) ( -8192 -8192 -1112 ) desktop/jspbookcover 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 38 +{ +"origin" "1501 728 -132" +"model" "/models/mapobjects/steprem/steprem.md3" +"classname" "misc_model" +} +// entity 39 +{ +"origin" "1248 944 -496" +"classname" "light" +"light" "10000" +} +// entity 40 +{ +"classname" "misc_model" +"model" "/models/mapobjects/bilbo/bilbo.md3" +"origin" "160 -228 234" +} +// entity 41 +{ +"target" "toptarget" +"name" "backtotop" +"classname" "trigger_teleport" +// brush 0 +{ +( 1360 8192 8192 ) ( 1360 -8192 8192 ) ( 1360 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 1368 -8192 8192 ) ( 1368 8192 8192 ) ( 1368 8192 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1008 8192 ) ( 8192 1008 8192 ) ( -8192 1008 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1104 8192 ) ( -8192 1104 8192 ) ( -8192 1104 -8192 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -570 ) ( 8192 8192 -570 ) ( -8192 -8192 -570 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -360 ) ( 8192 -8192 -360 ) ( -8192 -8192 -360 ) desktop/greenfoot 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 42 +{ +"targetname" "toptarget" +"classname" "target_teleporter" +"origin" "-460 932 230" +} +// entity 43 +{ +"classname" "path_corner" +"targetname" "draweropen" +"target" "drawerclosed" +"origin" "104 1096 -496" +} +// entity 44 +{ +"classname" "light" +"light" "10000" +"origin" "84 512 -828" +} +// entity 45 +{ +"classname" "light" +"light" "10000" +"origin" "154 -312 8" +} +// entity 46 +{ +"origin" "106 88 -298" +"radius" "5000" +"classname" "light" +"light" "10000" +} +// entity 47 +{ +"origin" "-160 80 -104" +"classname" "info_player_deathmatch" +} +// entity 48 +{ +"origin" "384 1096 -496" +"target" "draweropen" +"targetname" "drawerclosed" +"classname" "path_corner" +} +// entity 49 +{ +"origin" "1506 -312 8" +"light" "10000" +"classname" "light" +} +// entity 50 +{ +"classname" "path_corner" +"origin" "352 -144 896" +"targetname" "pathtoscreen2" +} +// entity 51 +{ +"classname" "item_health" +"origin" "1416 1192 368" +} +// entity 52 +{ +"origin" "1456 1192 368" +"classname" "item_health" +} +// entity 53 +{ +"classname" "item_health" +"origin" "1496 1192 368" +} +// entity 54 +{ +"origin" "1536 1192 368" +"classname" "item_health" +} +// entity 55 +{ +"classname" "item_health" +"origin" "1576 1192 368" +} +// entity 56 +{ +"origin" "1624 1192 368" +"classname" "item_health" +} +// entity 57 +{ +"classname" "item_armor_shard" +"origin" "1576 1288 368" +} +// entity 58 +{ +"origin" "1536 1288 368" +"classname" "item_armor_shard" +} +// entity 59 +{ +"classname" "item_armor_shard" +"origin" "1496 1288 368" +} +// entity 60 +{ +"origin" "1456 1288 368" +"classname" "item_armor_shard" +} +// entity 61 +{ +"classname" "item_armor_shard" +"origin" "1416 1288 368" +} +// entity 62 +{ +"origin" "1376 1288 368" +"classname" "item_armor_shard" +} +// entity 63 +{ +"classname" "item_armor_shard" +"origin" "1376 1240 368" +} +// entity 64 +{ +"classname" "ammo_rockets" +"origin" "1984 1040 368" +} +// entity 65 +{ +"spawnflags" "1" +"target" "t1" +"classname" "func_train" +// brush 0 +{ +( 8192 -8192 -728 ) ( 8192 8192 -728 ) ( -8192 -8192 -728 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -712 ) ( 8192 -8192 -712 ) ( -8192 -8192 -712 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8281 207 8192 ) ( -7975 2240 8192 ) ( -7975 2240 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 1199 8105 8192 ) ( -832 -8151 8192 ) ( -832 -8151 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8102 1688 8192 ) ( 8249 666 8192 ) ( 8249 666 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -843 -8150 8192 ) ( 1220 8102 8192 ) ( 1220 8102 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 1 +{ +( 8192 -8192 -728 ) ( 8192 8192 -728 ) ( -8192 -8192 -728 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -712 ) ( 8192 -8192 -712 ) ( -8192 -8192 -712 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8247 -866 8192 ) ( -7583 3354 8192 ) ( -7583 3354 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 3191 7547 8192 ) ( -3531 -7393 8192 ) ( -3531 -7393 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -7594 3315 8192 ) ( 8236 -906 8192 ) ( 8236 -906 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -3517 -7400 8192 ) ( 3206 7540 8192 ) ( 3206 7540 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 2 +{ +( -8192 1131 8192 ) ( 8192 1131 8192 ) ( -8192 1131 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -728 ) ( 8192 8192 -728 ) ( -8192 -8192 -728 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -712 ) ( 8192 -8192 -712 ) ( -8192 -8192 -712 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 768 8159 8192 ) ( -253 -8192 8192 ) ( -253 -8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8249 667 8192 ) ( -8102 1689 8192 ) ( -8102 1689 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -255 -8192 8192 ) ( 782 8158 8192 ) ( 782 8158 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 3 +{ +( 330 8192 8192 ) ( 330 -8192 8192 ) ( 330 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 336 -8192 8192 ) ( 336 8192 8192 ) ( 336 8192 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8192 1083 8192 ) ( 8192 1083 8192 ) ( -8192 1083 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 1131 8192 ) ( -8192 1131 8192 ) ( -8192 1131 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -728 ) ( 8192 8192 -728 ) ( -8192 -8192 -728 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -712 ) ( 8192 -8192 -712 ) ( -8192 -8192 -712 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 4 +{ +( 8192 1083 8192 ) ( -8192 1083 8192 ) ( -8192 1083 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 -8192 -728 ) ( 8192 8192 -728 ) ( -8192 -8192 -728 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -712 ) ( 8192 -8192 -712 ) ( -8192 -8192 -712 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -115 8200 8192 ) ( 906 -8151 8192 ) ( 906 -8151 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8240 516 8192 ) ( 8111 1538 8192 ) ( 8111 1538 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 921 -8149 8192 ) ( -116 8201 8192 ) ( -116 8201 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 5 +{ +( 8192 -8192 -728 ) ( 8192 8192 -728 ) ( -8192 -8192 -728 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -712 ) ( 8192 -8192 -712 ) ( -8192 -8192 -712 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8248 -60 8192 ) ( 8009 1972 8192 ) ( 8009 1972 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -560 8185 8192 ) ( 1471 -8071 8192 ) ( 1471 -8071 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8111 1538 8192 ) ( -8240 516 8192 ) ( -8240 516 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 1495 -8067 8192 ) ( -568 8185 8192 ) ( -568 8185 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 6 +{ +( 8192 -8192 -728 ) ( 8192 8192 -728 ) ( -8192 -8192 -728 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -712 ) ( 8192 -8192 -712 ) ( -8192 -8192 -712 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 2563 -7803 8192 ) ( -1410 8091 8192 ) ( -1410 8091 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -5807 5861 8192 ) ( 7029 -4319 8192 ) ( 7029 -4319 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 6637 4844 8192 ) ( -7315 -3742 8192 ) ( -7315 -3742 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 7 +{ +( 8192 -8192 -728 ) ( 8192 8192 -728 ) ( -8192 -8192 -728 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 8192 8192 -712 ) ( 8192 -8192 -712 ) ( -8192 -8192 -712 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -8134 -1287 8192 ) ( 7695 2933 8192 ) ( 7695 2933 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( -2703 7766 8192 ) ( 4020 -7174 8192 ) ( 4020 -7174 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 7685 2973 8192 ) ( -8145 -1248 8192 ) ( -8145 -1248 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +( 4034 -7167 8192 ) ( -2688 7773 8192 ) ( -2688 7773 -8192 ) desktop/blackdrawer 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 66 +{ +"classname" "light" +"light" "10000" +"origin" "-1392 -240 -984" +} +// entity 67 +{ +"light" "10000" +"classname" "light" +"origin" "-1416 -744 -928" +} +// entity 68 +{ +"classname" "item_health_large" +"origin" "576 1120 -320" +} +// entity 69 +{ +"origin" "576 1088 -320" +"classname" "item_health_large" +} +// entity 70 +{ +"classname" "item_health_large" +"origin" "576 1056 -320" +} +// entity 71 +{ +"classname" "info_player_deathmatch" +"origin" "878 -360 728" +} +// entity 72 +{ +"origin" "1974 1288 130" +"classname" "info_player_deathmatch" +} +// entity 73 +{ +"origin" "160 -296 232" +"classname" "info_player_deathmatch" +} +// entity 74 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -160 912 -380 0 0 ) ( -160 944 -380 0 0.750000 ) ( -160 976 -380 0 1.500000 ) ) +( ( -128 912 -380 0.500000 0 ) ( -128 944 -380 0.500000 0.750000 ) ( -128 976 -380 0.500000 1.500000 ) ) +( ( -128 912 -380 0.500000 0 ) ( -128 944 -380 0.500000 0.750000 ) ( -128 976 -380 0.500000 1.500000 ) ) +( ( -128 912 -444 1.500000 0 ) ( -128 944 -444 1.500000 0.750000 ) ( -128 976 -444 1.500000 1.500000 ) ) +( ( -192 912 -444 2.500000 0 ) ( -192 944 -444 2.500000 0.750000 ) ( -192 976 -444 2.500000 1.500000 ) ) +( ( -192 912 -444 2.500000 0 ) ( -192 944 -444 2.500000 0.750000 ) ( -192 976 -444 2.500000 1.500000 ) ) +( ( -192 912 -380 3.500000 0 ) ( -192 944 -380 3.500000 0.750000 ) ( -192 976 -380 3.500000 1.500000 ) ) +( ( -160 912 -380 4 0 ) ( -160 944 -380 4 0.750000 ) ( -160 976 -380 4 1.500000 ) ) +( ( -160 912 -380 4 0 ) ( -160 944 -380 4 0.750000 ) ( -160 976 -380 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -192 912 -380 -11.875000 5 ) ( -160 912 -380 -11.375000 5 ) ( -160 912 -380 -11.375000 5 ) ) +( ( -192 912 -444 -11.875000 6 ) ( -160 912 -412 -11.375000 5.500000 ) ( -128 912 -380 -10.875000 5 ) ) +( ( -192 912 -444 -11.875000 6 ) ( -128 912 -444 -10.875000 6 ) ( -128 912 -380 -10.875000 5 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -160 976 -380 -11.375000 5 ) ( -160 976 -380 -11.375000 5 ) ( -192 976 -380 -11.875000 5 ) ) +( ( -128 976 -380 -10.875000 5 ) ( -160 976 -412 -11.375000 5.500000 ) ( -192 976 -444 -11.875000 6 ) ) +( ( -128 976 -380 -10.875000 5 ) ( -128 976 -444 -10.875000 6 ) ( -192 976 -444 -11.875000 6 ) ) +) + } + } +} +// entity 75 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -720 912 -412 0 0 ) ( -720 944 -412 0 0.750000 ) ( -720 976 -412 0 1.500000 ) ) +( ( -720 912 -444 0.500000 0 ) ( -720 944 -444 0.500000 0.750000 ) ( -720 976 -444 0.500000 1.500000 ) ) +( ( -720 912 -444 0.500000 0 ) ( -720 944 -444 0.500000 0.750000 ) ( -720 976 -444 0.500000 1.500000 ) ) +( ( -784 912 -444 1.500000 0 ) ( -784 944 -444 1.500000 0.750000 ) ( -784 976 -444 1.500000 1.500000 ) ) +( ( -784 912 -380 2.500000 0 ) ( -784 944 -380 2.500000 0.750000 ) ( -784 976 -380 2.500000 1.500000 ) ) +( ( -784 912 -380 2.500000 0 ) ( -784 944 -380 2.500000 0.750000 ) ( -784 976 -380 2.500000 1.500000 ) ) +( ( -720 912 -380 3.500000 0 ) ( -720 944 -380 3.500000 0.750000 ) ( -720 976 -380 3.500000 1.500000 ) ) +( ( -720 912 -412 4 0 ) ( -720 944 -412 4 0.750000 ) ( -720 976 -412 4 1.500000 ) ) +( ( -720 912 -412 4 0 ) ( -720 944 -412 4 0.750000 ) ( -720 976 -412 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -720 912 -380 -20.125000 5 ) ( -720 912 -412 -20.125000 5.500000 ) ( -720 912 -412 -20.125000 5.500000 ) ) +( ( -784 912 -380 -21.125000 5 ) ( -752 912 -412 -20.625000 5.500000 ) ( -720 912 -444 -20.125000 6 ) ) +( ( -784 912 -380 -21.125000 5 ) ( -784 912 -444 -21.125000 6 ) ( -720 912 -444 -20.125000 6 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -720 976 -412 -20.125000 5.500000 ) ( -720 976 -412 -20.125000 5.500000 ) ( -720 976 -380 -20.125000 5 ) ) +( ( -720 976 -444 -20.125000 6 ) ( -752 976 -412 -20.625000 5.500000 ) ( -784 976 -380 -21.125000 5 ) ) +( ( -720 976 -444 -20.125000 6 ) ( -784 976 -444 -21.125000 6 ) ( -784 976 -380 -21.125000 5 ) ) +) + } + } +} +// entity 76 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -700 912 -251.999908 0 0 ) ( -700 944 -251.999908 0 0.750000 ) ( -700 976 -251.999908 0 1.500000 ) ) +( ( -784 912 -251.999908 0.500000 0 ) ( -784 944 -251.999908 0.500000 0.750000 ) ( -784 976 -251.999908 0.500000 1.500000 ) ) +( ( -784 912 -251.999908 0.500000 0 ) ( -784 944 -251.999908 0.500000 0.750000 ) ( -784 976 -251.999908 0.500000 1.500000 ) ) +( ( -784 912 222.000031 1.500000 0 ) ( -784 944 222.000031 1.500000 0.750000 ) ( -784 976 222.000031 1.500000 1.500000 ) ) +( ( -616 912 222.000031 2.500000 0 ) ( -616 944 222.000031 2.500000 0.750000 ) ( -616 976 222.000031 2.500000 1.500000 ) ) +( ( -616 912 222.000031 2.500000 0 ) ( -616 944 222.000031 2.500000 0.750000 ) ( -616 976 222.000031 2.500000 1.500000 ) ) +( ( -616 912 -251.999908 3.500000 0 ) ( -616 944 -251.999908 3.500000 0.750000 ) ( -616 976 -251.999908 3.500000 1.500000 ) ) +( ( -700 912 -251.999908 4 0 ) ( -700 944 -251.999908 4 0.750000 ) ( -700 976 -251.999908 4 1.500000 ) ) +( ( -700 912 -251.999908 4 0 ) ( -700 944 -251.999908 4 0.750000 ) ( -700 976 -251.999908 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -616 912 -251.999908 -18.500000 1.749999 ) ( -700 912 -251.999908 -19.812500 1.749999 ) ( -700 912 -251.999908 -19.812500 1.749999 ) ) +( ( -616 912 222.000031 -18.500000 -3.375000 ) ( -700 912 -16.445034 -19.812500 -0.796876 ) ( -784 912 -251.999908 -21.125000 1.749999 ) ) +( ( -616 912 222.000031 -18.500000 -3.375000 ) ( -784 912 222.000031 -21.125000 -3.375000 ) ( -784 912 -251.999908 -21.125000 1.749999 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -700 976 -251.999908 -19.812500 1.749999 ) ( -700 976 -251.999908 -19.812500 1.749999 ) ( -616 976 -251.999908 -18.500000 1.749999 ) ) +( ( -784 976 -251.999908 -21.125000 1.749999 ) ( -700 976 -16.445034 -19.812500 -0.796876 ) ( -616 976 222.000031 -18.500000 -3.375000 ) ) +( ( -784 976 -251.999908 -21.125000 1.749999 ) ( -784 976 222.000031 -21.125000 -3.375000 ) ( -616 976 222.000031 -18.500000 -3.375000 ) ) +) + } + } +} +// entity 77 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/chair + ( 9 3 0 0 0 ) +( +( ( -700 880 -251.999939 0 0 ) ( -700 896 -251.999939 0 0.750000 ) ( -700 912 -251.999939 0 1.500000 ) ) +( ( -784 880 -251.999939 0.500000 0 ) ( -784 896 -251.999939 0.500000 0.750000 ) ( -784 912 -251.999939 0.500000 1.500000 ) ) +( ( -784 880 -251.999939 0.500000 0 ) ( -784 896 -251.999939 0.500000 0.750000 ) ( -784 912 -251.999939 0.500000 1.500000 ) ) +( ( -784 880 222.000061 1.500000 0 ) ( -784 896 222.000061 1.500000 0.750000 ) ( -784 912 222.000061 1.500000 1.500000 ) ) +( ( -616 880 222.000061 2.500000 0 ) ( -616 896 222.000061 2.500000 0.750000 ) ( -616 912 222.000061 2.500000 1.500000 ) ) +( ( -616 880 222.000061 2.500000 0 ) ( -616 896 222.000061 2.500000 0.750000 ) ( -616 912 222.000061 2.500000 1.500000 ) ) +( ( -616 880 -251.999939 3.500000 0 ) ( -616 896 -251.999939 3.500000 0.750000 ) ( -616 912 -251.999939 3.500000 1.500000 ) ) +( ( -700 880 -251.999939 4 0 ) ( -700 896 -251.999939 4 0.750000 ) ( -700 912 -251.999939 4 1.500000 ) ) +( ( -700 880 -251.999939 4 0 ) ( -700 896 -251.999939 4 0.750000 ) ( -700 912 -251.999939 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -616 880 -251.999939 -18.500000 1.749999 ) ( -700 880 -251.999939 -19.812500 1.749999 ) ( -700 880 -251.999939 -19.812500 1.749999 ) ) +( ( -616 880 222.000061 -18.500000 -3.375000 ) ( -700 880 -16.445053 -19.812500 -0.796876 ) ( -784 880 -251.999939 -21.125000 1.749999 ) ) +( ( -616 880 222.000061 -18.500000 -3.375000 ) ( -784 880 222.000061 -21.125000 -3.375000 ) ( -784 880 -251.999939 -21.125000 1.749999 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -700 912 -251.999939 -19.812500 1.749999 ) ( -700 912 -251.999939 -19.812500 1.749999 ) ( -616 912 -251.999939 -18.500000 1.749999 ) ) +( ( -784 912 -251.999939 -21.125000 1.749999 ) ( -700 912 -16.445053 -19.812500 -0.796876 ) ( -616 912 222.000061 -18.500000 -3.375000 ) ) +( ( -784 912 -251.999939 -21.125000 1.749999 ) ( -784 912 222.000061 -21.125000 -3.375000 ) ( -616 912 222.000061 -18.500000 -3.375000 ) ) +) + } + } +} +// entity 78 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -464 652 -660 0 0 ) ( -464 652 -608 0 0.781250 ) ( -464 652 -556 0 1.562500 ) ) +( ( -464 640 -660 0.218750 0 ) ( -464 640 -608 0.218750 0.781250 ) ( -464 640 -556 0.218750 1.562500 ) ) +( ( -448 640 -660 0.468750 0 ) ( -448 640 -608 0.468750 0.781250 ) ( -448 640 -556 0.468750 1.562500 ) ) +( ( -432 640 -660 0.718750 0 ) ( -432 640 -608 0.718750 0.781250 ) ( -432 640 -556 0.718750 1.562500 ) ) +( ( -432 652 -660 0.937500 0 ) ( -432 652 -608 0.937500 0.781250 ) ( -432 652 -556 0.937500 1.562500 ) ) +( ( -432 664 -660 1.156250 0 ) ( -432 664 -608 1.156250 0.781250 ) ( -432 664 -556 1.156250 1.562500 ) ) +( ( -448 664 -660 1.406250 0 ) ( -448 664 -608 1.406250 0.781250 ) ( -448 664 -556 1.406250 1.562500 ) ) +( ( -464 664 -660 1.656250 0 ) ( -464 664 -608 1.656250 0.781250 ) ( -464 664 -556 1.656250 1.562500 ) ) +( ( -464 652 -660 1.875000 0 ) ( -464 652 -608 1.875000 0.781250 ) ( -464 652 -556 1.875000 1.562500 ) ) +) + } + } +} +// entity 79 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -472 652 -828 0 0 ) ( -472 652 -744 0 0.781250 ) ( -472 652 -660 0 1.562500 ) ) +( ( -472 628 -828 0.218750 0 ) ( -472 628 -744 0.218750 0.781250 ) ( -472 628 -660 0.218750 1.562500 ) ) +( ( -448 628 -828 0.468750 0 ) ( -448 628 -744 0.468750 0.781250 ) ( -448 628 -660 0.468750 1.562500 ) ) +( ( -424 628 -828 0.718750 0 ) ( -424 628 -744 0.718750 0.781250 ) ( -424 628 -660 0.718750 1.562500 ) ) +( ( -424 652 -828 0.937500 0 ) ( -424 652 -744 0.937500 0.781250 ) ( -424 652 -660 0.937500 1.562500 ) ) +( ( -424 676 -828 1.156250 0 ) ( -424 676 -744 1.156250 0.781250 ) ( -424 676 -660 1.156250 1.562500 ) ) +( ( -448 676 -828 1.406250 0 ) ( -448 676 -744 1.406250 0.781250 ) ( -448 676 -660 1.406250 1.562500 ) ) +( ( -472 676 -828 1.656250 0 ) ( -472 676 -744 1.656250 0.781250 ) ( -472 676 -660 1.656250 1.562500 ) ) +( ( -472 652 -828 1.875000 0 ) ( -472 652 -744 1.875000 0.781250 ) ( -472 652 -660 1.875000 1.562500 ) ) +) + } + } +} +// entity 80 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -484 652 -1120 0 0 ) ( -484 652 -974 0 0.781250 ) ( -484 652 -828 0 1.562500 ) ) +( ( -484 616 -1120 0.218750 0 ) ( -484 616 -974 0.218750 0.781250 ) ( -484 616 -828 0.218750 1.562500 ) ) +( ( -448 616 -1120 0.468750 0 ) ( -448 616 -974 0.468750 0.781250 ) ( -448 616 -828 0.468750 1.562500 ) ) +( ( -412 616 -1120 0.718750 0 ) ( -412 616 -974 0.718750 0.781250 ) ( -412 616 -828 0.718750 1.562500 ) ) +( ( -412 652 -1120 0.937500 0 ) ( -412 652 -974 0.937500 0.781250 ) ( -412 652 -828 0.937500 1.562500 ) ) +( ( -412 688 -1120 1.156250 0 ) ( -412 688 -974 1.156250 0.781250 ) ( -412 688 -828 1.156250 1.562500 ) ) +( ( -448 688 -1120 1.406250 0 ) ( -448 688 -974 1.406250 0.781250 ) ( -448 688 -828 1.406250 1.562500 ) ) +( ( -484 688 -1120 1.656250 0 ) ( -484 688 -974 1.656250 0.781250 ) ( -484 688 -828 1.656250 1.562500 ) ) +( ( -484 652 -1120 1.875000 0 ) ( -484 652 -974 1.875000 0.781250 ) ( -484 652 -828 1.875000 1.562500 ) ) +) + } + } +} +// entity 81 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -452 996 -1208 0 0 ) ( -460 996 -1208 0 0.062500 ) ( -468 996 -1208 0 0.125000 ) ) +( ( -452 968 -1208 0.218750 0 ) ( -460 968 -1208 0.218750 0.062500 ) ( -468 968 -1208 0.218750 0.125000 ) ) +( ( -452 968 -1180 0.437500 0 ) ( -460 968 -1180 0.437500 0.062500 ) ( -468 968 -1180 0.437500 0.125000 ) ) +( ( -452 968 -1152 0.656250 0 ) ( -460 968 -1152 0.656250 0.062500 ) ( -468 968 -1152 0.656250 0.125000 ) ) +( ( -452 996 -1152 0.875000 0 ) ( -460 996 -1152 0.875000 0.062500 ) ( -468 996 -1152 0.875000 0.125000 ) ) +( ( -452 1024 -1152 1.093750 0 ) ( -460 1024 -1152 1.093750 0.062500 ) ( -468 1024 -1152 1.093750 0.125000 ) ) +( ( -452 1024 -1180 1.312500 0 ) ( -460 1024 -1180 1.312500 0.062500 ) ( -468 1024 -1180 1.312500 0.125000 ) ) +( ( -452 1024 -1208 1.531250 0 ) ( -460 1024 -1208 1.531250 0.062500 ) ( -468 1024 -1208 1.531250 0.125000 ) ) +( ( -452 996 -1208 1.750000 0 ) ( -460 996 -1208 1.750000 0.062500 ) ( -468 996 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -452 1024 -1180 -8.031250 -18 ) ( -452 1024 -1208 -8.250000 -18 ) ( -452 996 -1208 -8.250000 -17.781250 ) ) +( ( -452 1024 -1152 -7.812500 -18 ) ( -452 996 -1180 -8.031250 -17.781250 ) ( -452 968 -1208 -8.250000 -17.562500 ) ) +( ( -452 996 -1152 -7.812500 -17.781250 ) ( -452 968 -1152 -7.812500 -17.562500 ) ( -452 968 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -468 996 -1208 -8.250000 -17.781250 ) ( -468 1024 -1208 -8.250000 -18 ) ( -468 1024 -1180 -8.031250 -18 ) ) +( ( -468 968 -1208 -8.250000 -17.562500 ) ( -468 996 -1180 -8.031250 -17.781250 ) ( -468 1024 -1152 -7.812500 -18 ) ) +( ( -468 968 -1180 -8.031250 -17.562500 ) ( -468 968 -1152 -7.812500 -17.562500 ) ( -468 996 -1152 -7.812500 -17.781250 ) ) +) + } + } +} +// entity 82 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -428 996 -1208 0 0 ) ( -436 996 -1208 0 0.062500 ) ( -444 996 -1208 0 0.125000 ) ) +( ( -428 968 -1208 0.218750 0 ) ( -436 968 -1208 0.218750 0.062500 ) ( -444 968 -1208 0.218750 0.125000 ) ) +( ( -428 968 -1180 0.437500 0 ) ( -436 968 -1180 0.437500 0.062500 ) ( -444 968 -1180 0.437500 0.125000 ) ) +( ( -428 968 -1152 0.656250 0 ) ( -436 968 -1152 0.656250 0.062500 ) ( -444 968 -1152 0.656250 0.125000 ) ) +( ( -428 996 -1152 0.875000 0 ) ( -436 996 -1152 0.875000 0.062500 ) ( -444 996 -1152 0.875000 0.125000 ) ) +( ( -428 1024 -1152 1.093750 0 ) ( -436 1024 -1152 1.093750 0.062500 ) ( -444 1024 -1152 1.093750 0.125000 ) ) +( ( -428 1024 -1180 1.312500 0 ) ( -436 1024 -1180 1.312500 0.062500 ) ( -444 1024 -1180 1.312500 0.125000 ) ) +( ( -428 1024 -1208 1.531250 0 ) ( -436 1024 -1208 1.531250 0.062500 ) ( -444 1024 -1208 1.531250 0.125000 ) ) +( ( -428 996 -1208 1.750000 0 ) ( -436 996 -1208 1.750000 0.062500 ) ( -444 996 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -428 1024 -1180 -8.031250 -18 ) ( -428 1024 -1208 -8.250000 -18 ) ( -428 996 -1208 -8.250000 -17.781250 ) ) +( ( -428 1024 -1152 -7.812500 -18 ) ( -428 996 -1180 -8.031250 -17.781250 ) ( -428 968 -1208 -8.250000 -17.562500 ) ) +( ( -428 996 -1152 -7.812500 -17.781250 ) ( -428 968 -1152 -7.812500 -17.562500 ) ( -428 968 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -444 996 -1208 -8.250000 -17.781250 ) ( -444 1024 -1208 -8.250000 -18 ) ( -444 1024 -1180 -8.031250 -18 ) ) +( ( -444 968 -1208 -8.250000 -17.562500 ) ( -444 996 -1180 -8.031250 -17.781250 ) ( -444 1024 -1152 -7.812500 -18 ) ) +( ( -444 968 -1180 -8.031250 -17.562500 ) ( -444 968 -1152 -7.812500 -17.562500 ) ( -444 996 -1152 -7.812500 -17.781250 ) ) +) + } + } +} +// entity 83 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -452 304 -1208 0 0 ) ( -460 304 -1208 0 0.062500 ) ( -468 304 -1208 0 0.125000 ) ) +( ( -452 276 -1208 0.218750 0 ) ( -460 276 -1208 0.218750 0.062500 ) ( -468 276 -1208 0.218750 0.125000 ) ) +( ( -452 276 -1180 0.437500 0 ) ( -460 276 -1180 0.437500 0.062500 ) ( -468 276 -1180 0.437500 0.125000 ) ) +( ( -452 276 -1152 0.656250 0 ) ( -460 276 -1152 0.656250 0.062500 ) ( -468 276 -1152 0.656250 0.125000 ) ) +( ( -452 304 -1152 0.875000 0 ) ( -460 304 -1152 0.875000 0.062500 ) ( -468 304 -1152 0.875000 0.125000 ) ) +( ( -452 332 -1152 1.093750 0 ) ( -460 332 -1152 1.093750 0.062500 ) ( -468 332 -1152 1.093750 0.125000 ) ) +( ( -452 332 -1180 1.312500 0 ) ( -460 332 -1180 1.312500 0.062500 ) ( -468 332 -1180 1.312500 0.125000 ) ) +( ( -452 332 -1208 1.531250 0 ) ( -460 332 -1208 1.531250 0.062500 ) ( -468 332 -1208 1.531250 0.125000 ) ) +( ( -452 304 -1208 1.750000 0 ) ( -460 304 -1208 1.750000 0.062500 ) ( -468 304 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -452 332 -1180 -8.031250 -18 ) ( -452 332 -1208 -8.250000 -18 ) ( -452 304 -1208 -8.250000 -17.781250 ) ) +( ( -452 332 -1152 -7.812500 -18 ) ( -452 304 -1180 -8.031250 -17.781250 ) ( -452 276 -1208 -8.250000 -17.562500 ) ) +( ( -452 304 -1152 -7.812500 -17.781250 ) ( -452 276 -1152 -7.812500 -17.562500 ) ( -452 276 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -468 304 -1208 -8.250000 -17.781250 ) ( -468 332 -1208 -8.250000 -18 ) ( -468 332 -1180 -8.031250 -18 ) ) +( ( -468 276 -1208 -8.250000 -17.562500 ) ( -468 304 -1180 -8.031250 -17.781250 ) ( -468 332 -1152 -7.812500 -18 ) ) +( ( -468 276 -1180 -8.031250 -17.562500 ) ( -468 276 -1152 -7.812500 -17.562500 ) ( -468 304 -1152 -7.812500 -17.781250 ) ) +) + } + } +} +// entity 84 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -428 304 -1208 0 0 ) ( -436 304 -1208 0 0.062500 ) ( -444 304 -1208 0 0.125000 ) ) +( ( -428 276 -1208 0.218750 0 ) ( -436 276 -1208 0.218750 0.062500 ) ( -444 276 -1208 0.218750 0.125000 ) ) +( ( -428 276 -1180 0.437500 0 ) ( -436 276 -1180 0.437500 0.062500 ) ( -444 276 -1180 0.437500 0.125000 ) ) +( ( -428 276 -1152 0.656250 0 ) ( -436 276 -1152 0.656250 0.062500 ) ( -444 276 -1152 0.656250 0.125000 ) ) +( ( -428 304 -1152 0.875000 0 ) ( -436 304 -1152 0.875000 0.062500 ) ( -444 304 -1152 0.875000 0.125000 ) ) +( ( -428 332 -1152 1.093750 0 ) ( -436 332 -1152 1.093750 0.062500 ) ( -444 332 -1152 1.093750 0.125000 ) ) +( ( -428 332 -1180 1.312500 0 ) ( -436 332 -1180 1.312500 0.062500 ) ( -444 332 -1180 1.312500 0.125000 ) ) +( ( -428 332 -1208 1.531250 0 ) ( -436 332 -1208 1.531250 0.062500 ) ( -444 332 -1208 1.531250 0.125000 ) ) +( ( -428 304 -1208 1.750000 0 ) ( -436 304 -1208 1.750000 0.062500 ) ( -444 304 -1208 1.750000 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -428 332 -1180 -8.031250 -18 ) ( -428 332 -1208 -8.250000 -18 ) ( -428 304 -1208 -8.250000 -17.781250 ) ) +( ( -428 332 -1152 -7.812500 -18 ) ( -428 304 -1180 -8.031250 -17.781250 ) ( -428 276 -1208 -8.250000 -17.562500 ) ) +( ( -428 304 -1152 -7.812500 -17.781250 ) ( -428 276 -1152 -7.812500 -17.562500 ) ( -428 276 -1180 -8.031250 -17.562500 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -444 304 -1208 -8.250000 -17.781250 ) ( -444 332 -1208 -8.250000 -18 ) ( -444 332 -1180 -8.031250 -18 ) ) +( ( -444 276 -1208 -8.250000 -17.562500 ) ( -444 304 -1180 -8.031250 -17.781250 ) ( -444 332 -1152 -7.812500 -18 ) ) +( ( -444 276 -1180 -8.031250 -17.562500 ) ( -444 276 -1152 -7.812500 -17.562500 ) ( -444 304 -1152 -7.812500 -17.781250 ) ) +) + } + } +} +// entity 85 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -752 848 -492 0 0 ) ( -752 848 -524 0 0.750000 ) ( -752 848 -556 0 1.500000 ) ) +( ( -784 848 -492 0.500000 0 ) ( -784 848 -524 0.500000 0.750000 ) ( -784 848 -556 0.500000 1.500000 ) ) +( ( -784 848 -492 0.500000 0 ) ( -784 848 -524 0.500000 0.750000 ) ( -784 848 -556 0.500000 1.500000 ) ) +( ( -784 912 -492 1.500000 0 ) ( -784 912 -524 1.500000 0.750000 ) ( -784 912 -556 1.500000 1.500000 ) ) +( ( -720 912 -492 2.500000 0 ) ( -720 912 -524 2.500000 0.750000 ) ( -720 912 -556 2.500000 1.500000 ) ) +( ( -720 912 -492 2.500000 0 ) ( -720 912 -524 2.500000 0.750000 ) ( -720 912 -556 2.500000 1.500000 ) ) +( ( -720 848 -492 3.500000 0 ) ( -720 848 -524 3.500000 0.750000 ) ( -720 848 -556 3.500000 1.500000 ) ) +( ( -752 848 -492 4 0 ) ( -752 848 -524 4 0.750000 ) ( -752 848 -556 4 1.500000 ) ) +( ( -752 848 -492 4 0 ) ( -752 848 -524 4 0.750000 ) ( -752 848 -556 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -720 848 -492 -11.875000 -34.250000 ) ( -752 848 -492 -11.875000 -34.750000 ) ( -752 848 -492 -11.875000 -34.750000 ) ) +( ( -720 912 -492 -10.875000 -34.250000 ) ( -752 880 -492 -11.375000 -34.750000 ) ( -784 848 -492 -11.875000 -35.250000 ) ) +( ( -720 912 -492 -10.875000 -34.250000 ) ( -784 912 -492 -10.875000 -35.250000 ) ( -784 848 -492 -11.875000 -35.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -752 848 -556 -11.875000 -34.750000 ) ( -752 848 -556 -11.875000 -34.750000 ) ( -720 848 -556 -11.875000 -34.250000 ) ) +( ( -784 848 -556 -11.875000 -35.250000 ) ( -752 880 -556 -11.375000 -34.750000 ) ( -720 912 -556 -10.875000 -34.250000 ) ) +( ( -784 848 -556 -11.875000 -35.250000 ) ( -784 912 -556 -10.875000 -35.250000 ) ( -720 912 -556 -10.875000 -34.250000 ) ) +) + } + } +} +// entity 86 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/chair + ( 9 3 0 0 0 ) +( +( ( -752 848 -460 0 0 ) ( -752 848 -476 0 0.750000 ) ( -752 848 -492 0 1.500000 ) ) +( ( -784 848 -460 0.500000 0 ) ( -784 848 -476 0.500000 0.750000 ) ( -784 848 -492 0.500000 1.500000 ) ) +( ( -784 848 -460 0.500000 0 ) ( -784 848 -476 0.500000 0.750000 ) ( -784 848 -492 0.500000 1.500000 ) ) +( ( -784 912 -460 1.500000 0 ) ( -784 912 -476 1.500000 0.750000 ) ( -784 912 -492 1.500000 1.500000 ) ) +( ( -720 912 -460 2.500000 0 ) ( -720 912 -476 2.500000 0.750000 ) ( -720 912 -492 2.500000 1.500000 ) ) +( ( -720 912 -460 2.500000 0 ) ( -720 912 -476 2.500000 0.750000 ) ( -720 912 -492 2.500000 1.500000 ) ) +( ( -720 848 -460 3.500000 0 ) ( -720 848 -476 3.500000 0.750000 ) ( -720 848 -492 3.500000 1.500000 ) ) +( ( -752 848 -460 4 0 ) ( -752 848 -476 4 0.750000 ) ( -752 848 -492 4 1.500000 ) ) +( ( -752 848 -460 4 0 ) ( -752 848 -476 4 0.750000 ) ( -752 848 -492 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -720 848 -460 -11.875000 -34.250000 ) ( -752 848 -460 -11.875000 -34.750000 ) ( -752 848 -460 -11.875000 -34.750000 ) ) +( ( -720 912 -460 -10.875000 -34.250000 ) ( -752 880 -460 -11.375000 -34.750000 ) ( -784 848 -460 -11.875000 -35.250000 ) ) +( ( -720 912 -460 -10.875000 -34.250000 ) ( -784 912 -460 -10.875000 -35.250000 ) ( -784 848 -460 -11.875000 -35.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -752 848 -492 -11.875000 -34.750000 ) ( -752 848 -492 -11.875000 -34.750000 ) ( -720 848 -492 -11.875000 -34.250000 ) ) +( ( -784 848 -492 -11.875000 -35.250000 ) ( -752 880 -492 -11.375000 -34.750000 ) ( -720 912 -492 -10.875000 -34.250000 ) ) +( ( -784 848 -492 -11.875000 -35.250000 ) ( -784 912 -492 -10.875000 -35.250000 ) ( -720 912 -492 -10.875000 -34.250000 ) ) +) + } + } +} +// entity 87 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + desktop/chair + ( 9 3 0 0 0 ) +( +( ( -192 880 -460 0 0 ) ( -192 880 -476 0 0.750000 ) ( -192 880 -492 0 1.500000 ) ) +( ( -192 912 -460 0.500000 0 ) ( -192 912 -476 0.500000 0.750000 ) ( -192 912 -492 0.500000 1.500000 ) ) +( ( -192 912 -460 0.500000 0 ) ( -192 912 -476 0.500000 0.750000 ) ( -192 912 -492 0.500000 1.500000 ) ) +( ( -128 912 -460 1.500000 0 ) ( -128 912 -476 1.500000 0.750000 ) ( -128 912 -492 1.500000 1.500000 ) ) +( ( -128 848 -460 2.500000 0 ) ( -128 848 -476 2.500000 0.750000 ) ( -128 848 -492 2.500000 1.500000 ) ) +( ( -128 848 -460 2.500000 0 ) ( -128 848 -476 2.500000 0.750000 ) ( -128 848 -492 2.500000 1.500000 ) ) +( ( -192 848 -460 3.500000 0 ) ( -192 848 -476 3.500000 0.750000 ) ( -192 848 -492 3.500000 1.500000 ) ) +( ( -192 880 -460 4 0 ) ( -192 880 -476 4 0.750000 ) ( -192 880 -492 4 1.500000 ) ) +( ( -192 880 -460 4 0 ) ( -192 880 -476 4 0.750000 ) ( -192 880 -492 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -192 848 -460 -11.875000 -34.250000 ) ( -192 880 -460 -11.875000 -34.750000 ) ( -192 880 -460 -11.875000 -34.750000 ) ) +( ( -128 848 -460 -10.875000 -34.250000 ) ( -160 880 -460 -11.375000 -34.750000 ) ( -192 912 -460 -11.875000 -35.250000 ) ) +( ( -128 848 -460 -10.875000 -34.250000 ) ( -128 912 -460 -10.875000 -35.250000 ) ( -192 912 -460 -11.875000 -35.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -192 880 -492 -11.875000 -34.750000 ) ( -192 880 -492 -11.875000 -34.750000 ) ( -192 848 -492 -11.875000 -34.250000 ) ) +( ( -192 912 -492 -11.875000 -35.250000 ) ( -160 880 -492 -11.375000 -34.750000 ) ( -128 848 -492 -10.875000 -34.250000 ) ) +( ( -192 912 -492 -11.875000 -35.250000 ) ( -128 912 -492 -10.875000 -35.250000 ) ( -128 848 -492 -10.875000 -34.250000 ) ) +) + } + } +} +// entity 88 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/chair + ( 9 3 0 0 0 ) +( +( ( -160 456 -460 0 0 ) ( -160 456 -476 0 0.750000 ) ( -160 456 -492 0 1.500000 ) ) +( ( -128 456 -460 0.500000 0 ) ( -128 456 -476 0.500000 0.750000 ) ( -128 456 -492 0.500000 1.500000 ) ) +( ( -128 456 -460 0.500000 0 ) ( -128 456 -476 0.500000 0.750000 ) ( -128 456 -492 0.500000 1.500000 ) ) +( ( -128 392 -460 1.500000 0 ) ( -128 392 -476 1.500000 0.750000 ) ( -128 392 -492 1.500000 1.500000 ) ) +( ( -192 392 -460 2.500000 0 ) ( -192 392 -476 2.500000 0.750000 ) ( -192 392 -492 2.500000 1.500000 ) ) +( ( -192 392 -460 2.500000 0 ) ( -192 392 -476 2.500000 0.750000 ) ( -192 392 -492 2.500000 1.500000 ) ) +( ( -192 456 -460 3.500000 0 ) ( -192 456 -476 3.500000 0.750000 ) ( -192 456 -492 3.500000 1.500000 ) ) +( ( -160 456 -460 4 0 ) ( -160 456 -476 4 0.750000 ) ( -160 456 -492 4 1.500000 ) ) +( ( -160 456 -460 4 0 ) ( -160 456 -476 4 0.750000 ) ( -160 456 -492 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -192 456 -460 -11.875000 -34.250000 ) ( -160 456 -460 -11.875000 -34.750000 ) ( -160 456 -460 -11.875000 -34.750000 ) ) +( ( -192 392 -460 -10.875000 -34.250000 ) ( -160 424 -460 -11.375000 -34.750000 ) ( -128 456 -460 -11.875000 -35.250000 ) ) +( ( -192 392 -460 -10.875000 -34.250000 ) ( -128 392 -460 -10.875000 -35.250000 ) ( -128 456 -460 -11.875000 -35.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -160 456 -492 -11.875000 -34.750000 ) ( -160 456 -492 -11.875000 -34.750000 ) ( -192 456 -492 -11.875000 -34.250000 ) ) +( ( -128 456 -492 -11.875000 -35.250000 ) ( -160 424 -492 -11.375000 -34.750000 ) ( -192 392 -492 -10.875000 -34.250000 ) ) +( ( -128 456 -492 -11.875000 -35.250000 ) ( -128 392 -492 -10.875000 -35.250000 ) ( -192 392 -492 -10.875000 -34.250000 ) ) +) + } + } +} +// entity 89 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + desktop/chair + ( 9 3 0 0 0 ) +( +( ( -712 424 -460 0 0 ) ( -712 424 -476 0 0.750000 ) ( -712 424 -492 0 1.500000 ) ) +( ( -712 392 -460 0.500000 0 ) ( -712 392 -476 0.500000 0.750000 ) ( -712 392 -492 0.500000 1.500000 ) ) +( ( -712 392 -460 0.500000 0 ) ( -712 392 -476 0.500000 0.750000 ) ( -712 392 -492 0.500000 1.500000 ) ) +( ( -784 392 -460 1.500000 0 ) ( -784 392 -476 1.500000 0.750000 ) ( -784 392 -492 1.500000 1.500000 ) ) +( ( -784 456 -460 2.500000 0 ) ( -784 456 -476 2.500000 0.750000 ) ( -784 456 -492 2.500000 1.500000 ) ) +( ( -784 456 -460 2.500000 0 ) ( -784 456 -476 2.500000 0.750000 ) ( -784 456 -492 2.500000 1.500000 ) ) +( ( -712 456 -460 3.500000 0 ) ( -712 456 -476 3.500000 0.750000 ) ( -712 456 -492 3.500000 1.500000 ) ) +( ( -712 424 -460 4 0 ) ( -712 424 -476 4 0.750000 ) ( -712 424 -492 4 1.500000 ) ) +( ( -712 424 -460 4 0 ) ( -712 424 -476 4 0.750000 ) ( -712 424 -492 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -712 456 -460 -11.875000 -34.250000 ) ( -712 424 -460 -11.875000 -34.750000 ) ( -712 424 -460 -11.875000 -34.750000 ) ) +( ( -784 456 -460 -10.875000 -34.250000 ) ( -748 424 -460 -11.375000 -34.750000 ) ( -712 392 -460 -11.875000 -35.250000 ) ) +( ( -784 456 -460 -10.875000 -34.250000 ) ( -784 392 -460 -10.875000 -35.250000 ) ( -712 392 -460 -11.875000 -35.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -712 424 -492 -11.875000 -34.750000 ) ( -712 424 -492 -11.875000 -34.750000 ) ( -712 456 -492 -11.875000 -34.250000 ) ) +( ( -712 392 -492 -11.875000 -35.250000 ) ( -748 424 -492 -11.375000 -34.750000 ) ( -784 456 -492 -10.875000 -34.250000 ) ) +( ( -712 392 -492 -11.875000 -35.250000 ) ( -784 392 -492 -10.875000 -35.250000 ) ( -784 456 -492 -10.875000 -34.250000 ) ) +) + } + } +} +// entity 90 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -192 880 -492 0 0 ) ( -192 880 -524 0 0.750000 ) ( -192 880 -556 0 1.500000 ) ) +( ( -192 912 -492 0.500000 0 ) ( -192 912 -524 0.500000 0.750000 ) ( -192 912 -556 0.500000 1.500000 ) ) +( ( -192 912 -492 0.500000 0 ) ( -192 912 -524 0.500000 0.750000 ) ( -192 912 -556 0.500000 1.500000 ) ) +( ( -128 912 -492 1.500000 0 ) ( -128 912 -524 1.500000 0.750000 ) ( -128 912 -556 1.500000 1.500000 ) ) +( ( -128 848 -492 2.500000 0 ) ( -128 848 -524 2.500000 0.750000 ) ( -128 848 -556 2.500000 1.500000 ) ) +( ( -128 848 -492 2.500000 0 ) ( -128 848 -524 2.500000 0.750000 ) ( -128 848 -556 2.500000 1.500000 ) ) +( ( -192 848 -492 3.500000 0 ) ( -192 848 -524 3.500000 0.750000 ) ( -192 848 -556 3.500000 1.500000 ) ) +( ( -192 880 -492 4 0 ) ( -192 880 -524 4 0.750000 ) ( -192 880 -556 4 1.500000 ) ) +( ( -192 880 -492 4 0 ) ( -192 880 -524 4 0.750000 ) ( -192 880 -556 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -192 848 -492 -11.875000 -34.250000 ) ( -192 880 -492 -11.875000 -34.750000 ) ( -192 880 -492 -11.875000 -34.750000 ) ) +( ( -128 848 -492 -10.875000 -34.250000 ) ( -160 880 -492 -11.375000 -34.750000 ) ( -192 912 -492 -11.875000 -35.250000 ) ) +( ( -128 848 -492 -10.875000 -34.250000 ) ( -128 912 -492 -10.875000 -35.250000 ) ( -192 912 -492 -11.875000 -35.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -192 880 -556 -11.875000 -34.750000 ) ( -192 880 -556 -11.875000 -34.750000 ) ( -192 848 -556 -11.875000 -34.250000 ) ) +( ( -192 912 -556 -11.875000 -35.250000 ) ( -160 880 -556 -11.375000 -34.750000 ) ( -128 848 -556 -10.875000 -34.250000 ) ) +( ( -192 912 -556 -11.875000 -35.250000 ) ( -128 912 -556 -10.875000 -35.250000 ) ( -128 848 -556 -10.875000 -34.250000 ) ) +) + } + } +} +// entity 91 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -160 456 -492 0 0 ) ( -160 456 -524 0 0.750000 ) ( -160 456 -556 0 1.500000 ) ) +( ( -128 456 -492 0.500000 0 ) ( -128 456 -524 0.500000 0.750000 ) ( -128 456 -556 0.500000 1.500000 ) ) +( ( -128 456 -492 0.500000 0 ) ( -128 456 -524 0.500000 0.750000 ) ( -128 456 -556 0.500000 1.500000 ) ) +( ( -128 392 -492 1.500000 0 ) ( -128 392 -524 1.500000 0.750000 ) ( -128 392 -556 1.500000 1.500000 ) ) +( ( -192 392 -492 2.500000 0 ) ( -192 392 -524 2.500000 0.750000 ) ( -192 392 -556 2.500000 1.500000 ) ) +( ( -192 392 -492 2.500000 0 ) ( -192 392 -524 2.500000 0.750000 ) ( -192 392 -556 2.500000 1.500000 ) ) +( ( -192 456 -492 3.500000 0 ) ( -192 456 -524 3.500000 0.750000 ) ( -192 456 -556 3.500000 1.500000 ) ) +( ( -160 456 -492 4 0 ) ( -160 456 -524 4 0.750000 ) ( -160 456 -556 4 1.500000 ) ) +( ( -160 456 -492 4 0 ) ( -160 456 -524 4 0.750000 ) ( -160 456 -556 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -192 456 -492 -11.875000 -34.250000 ) ( -160 456 -492 -11.875000 -34.750000 ) ( -160 456 -492 -11.875000 -34.750000 ) ) +( ( -192 392 -492 -10.875000 -34.250000 ) ( -160 424 -492 -11.375000 -34.750000 ) ( -128 456 -492 -11.875000 -35.250000 ) ) +( ( -192 392 -492 -10.875000 -34.250000 ) ( -128 392 -492 -10.875000 -35.250000 ) ( -128 456 -492 -11.875000 -35.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -160 456 -556 -11.875000 -34.750000 ) ( -160 456 -556 -11.875000 -34.750000 ) ( -192 456 -556 -11.875000 -34.250000 ) ) +( ( -128 456 -556 -11.875000 -35.250000 ) ( -160 424 -556 -11.375000 -34.750000 ) ( -192 392 -556 -10.875000 -34.250000 ) ) +( ( -128 456 -556 -11.875000 -35.250000 ) ( -128 392 -556 -10.875000 -35.250000 ) ( -192 392 -556 -10.875000 -34.250000 ) ) +) + } + } +} +// entity 92 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -712 424 -492 0 0 ) ( -712 424 -524 0 0.750000 ) ( -712 424 -556 0 1.500000 ) ) +( ( -712 392 -492 0.500000 0 ) ( -712 392 -524 0.500000 0.750000 ) ( -712 392 -556 0.500000 1.500000 ) ) +( ( -712 392 -492 0.500000 0 ) ( -712 392 -524 0.500000 0.750000 ) ( -712 392 -556 0.500000 1.500000 ) ) +( ( -784 392 -492 1.500000 0 ) ( -784 392 -524 1.500000 0.750000 ) ( -784 392 -556 1.500000 1.500000 ) ) +( ( -784 456 -492 2.500000 0 ) ( -784 456 -524 2.500000 0.750000 ) ( -784 456 -556 2.500000 1.500000 ) ) +( ( -784 456 -492 2.500000 0 ) ( -784 456 -524 2.500000 0.750000 ) ( -784 456 -556 2.500000 1.500000 ) ) +( ( -712 456 -492 3.500000 0 ) ( -712 456 -524 3.500000 0.750000 ) ( -712 456 -556 3.500000 1.500000 ) ) +( ( -712 424 -492 4 0 ) ( -712 424 -524 4 0.750000 ) ( -712 424 -556 4 1.500000 ) ) +( ( -712 424 -492 4 0 ) ( -712 424 -524 4 0.750000 ) ( -712 424 -556 4 1.500000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -712 456 -492 -11.875000 -34.250000 ) ( -712 424 -492 -11.875000 -34.750000 ) ( -712 424 -492 -11.875000 -34.750000 ) ) +( ( -784 456 -492 -10.875000 -34.250000 ) ( -748 424 -492 -11.375000 -34.750000 ) ( -712 392 -492 -11.875000 -35.250000 ) ) +( ( -784 456 -492 -10.875000 -34.250000 ) ( -784 392 -492 -10.875000 -35.250000 ) ( -712 392 -492 -11.875000 -35.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -712 424 -556 -11.875000 -34.750000 ) ( -712 424 -556 -11.875000 -34.750000 ) ( -712 456 -556 -11.875000 -34.250000 ) ) +( ( -712 392 -556 -11.875000 -35.250000 ) ( -748 424 -556 -11.375000 -34.750000 ) ( -784 456 -556 -10.875000 -34.250000 ) ) +( ( -712 392 -556 -11.875000 -35.250000 ) ( -784 392 -556 -10.875000 -35.250000 ) ( -784 456 -556 -10.875000 -34.250000 ) ) +) + } + } +} +// entity 93 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + desktop/blackdrawer + ( 9 3 0 0 0 ) +( +( ( -212 976 -252 0 1.500000 ) ( -212 944 -252 0 0.750000 ) ( -212 912 -252 0 0 ) ) +( ( -128 976 -252 0.500000 1.500000 ) ( -128 944 -252 0.500000 0.750000 ) ( -128 912 -252 0.500000 0 ) ) +( ( -128 976 -252 0.500000 1.500000 ) ( -128 944 -252 0.500000 0.750000 ) ( -128 912 -252 0.500000 0 ) ) +( ( -128 976 222.000061 1.500000 1.500000 ) ( -128 944 222.000061 1.500000 0.750000 ) ( -128 912 222.000061 1.500000 0 ) ) +( ( -296 976 222.000061 2.500000 1.500000 ) ( -296 944 222.000061 2.500000 0.750000 ) ( -296 912 222.000061 2.500000 0 ) ) +( ( -296 976 222.000061 2.500000 1.500000 ) ( -296 944 222.000061 2.500000 0.750000 ) ( -296 912 222.000061 2.500000 0 ) ) +( ( -296 976 -252 3.500000 1.500000 ) ( -296 944 -252 3.500000 0.750000 ) ( -296 912 -252 3.500000 0 ) ) +( ( -212 976 -252 4 1.500000 ) ( -212 944 -252 4 0.750000 ) ( -212 912 -252 4 0 ) ) +( ( -212 976 -252 4 1.500000 ) ( -212 944 -252 4 0.750000 ) ( -212 912 -252 4 0 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -212 912 -252 -19.812500 1.749999 ) ( -212 912 -252 -19.812500 1.749999 ) ( -296 912 -252 -18.500000 1.749999 ) ) +( ( -128 912 -252 -21.125000 1.749999 ) ( -212 912 -16.445087 -19.812500 -0.796876 ) ( -296 912 222.000061 -18.500000 -3.375000 ) ) +( ( -128 912 -252 -21.125000 1.749999 ) ( -128 912 222.000061 -21.125000 -3.375000 ) ( -296 912 222.000061 -18.500000 -3.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/blackdrawer + ( 3 3 0 0 0 ) +( +( ( -296 976 -252 -18.500000 1.749999 ) ( -212 976 -252 -19.812500 1.749999 ) ( -212 976 -252 -19.812500 1.749999 ) ) +( ( -296 976 222.000061 -18.500000 -3.375000 ) ( -212 976 -16.445087 -19.812500 -0.796876 ) ( -128 976 -252 -21.125000 1.749999 ) ) +( ( -296 976 222.000061 -18.500000 -3.375000 ) ( -128 976 222.000061 -21.125000 -3.375000 ) ( -128 976 -252 -21.125000 1.749999 ) ) +) + } + } +} +// entity 94 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + desktop/chair + ( 9 3 0 0 0 ) +( +( ( -212 912 -252 0 1.500000 ) ( -212 896 -252 0 0.750000 ) ( -212 880 -252 0 0 ) ) +( ( -128 912 -252 0.500000 1.500000 ) ( -128 896 -252 0.500000 0.750000 ) ( -128 880 -252 0.500000 0 ) ) +( ( -128 912 -252 0.500000 1.500000 ) ( -128 896 -252 0.500000 0.750000 ) ( -128 880 -252 0.500000 0 ) ) +( ( -128 912 222.000061 1.500000 1.500000 ) ( -128 896 222.000061 1.500000 0.750000 ) ( -128 880 222.000061 1.500000 0 ) ) +( ( -296 912 222.000061 2.500000 1.500000 ) ( -296 896 222.000061 2.500000 0.750000 ) ( -296 880 222.000061 2.500000 0 ) ) +( ( -296 912 222.000061 2.500000 1.500000 ) ( -296 896 222.000061 2.500000 0.750000 ) ( -296 880 222.000061 2.500000 0 ) ) +( ( -296 912 -252 3.500000 1.500000 ) ( -296 896 -252 3.500000 0.750000 ) ( -296 880 -252 3.500000 0 ) ) +( ( -212 912 -252 4 1.500000 ) ( -212 896 -252 4 0.750000 ) ( -212 880 -252 4 0 ) ) +( ( -212 912 -252 4 1.500000 ) ( -212 896 -252 4 0.750000 ) ( -212 880 -252 4 0 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -212 880 -252 -19.812500 1.749999 ) ( -212 880 -252 -19.812500 1.749999 ) ( -296 880 -252 -18.500000 1.749999 ) ) +( ( -128 880 -252 -21.125000 1.749999 ) ( -212 880 -16.445107 -19.812500 -0.796876 ) ( -296 880 222.000061 -18.500000 -3.375000 ) ) +( ( -128 880 -252 -21.125000 1.749999 ) ( -128 880 222.000061 -21.125000 -3.375000 ) ( -296 880 222.000061 -18.500000 -3.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/chair + ( 3 3 0 0 0 ) +( +( ( -296 912 -252 -18.500000 1.749999 ) ( -212 912 -252 -19.812500 1.749999 ) ( -212 912 -252 -19.812500 1.749999 ) ) +( ( -296 912 222.000061 -18.500000 -3.375000 ) ( -212 912 -16.445107 -19.812500 -0.796876 ) ( -128 912 -252 -21.125000 1.749999 ) ) +( ( -296 912 222.000061 -18.500000 -3.375000 ) ( -128 912 222.000061 -21.125000 -3.375000 ) ( -128 912 -252 -21.125000 1.749999 ) ) +) + } + } +} +// entity 95 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + desktop/plastic + ( 5 3 0 0 0 ) +( +( ( 60 -200 -12 0 0.937500 ) ( 60 -208 -12 0 0.468750 ) ( 60 -216 -12 0 0 ) ) +( ( 60 -200 -36 0.500000 0.937500 ) ( 60 -208 -36 0.500000 0.468750 ) ( 60 -216 -36 0.500000 0 ) ) +( ( 156 -200 -36 2 0.937500 ) ( 156 -208 -36 2 0.468750 ) ( 156 -216 -36 2 0 ) ) +( ( 252 -200 -36 3.500000 0.937500 ) ( 252 -208 -36 3.500000 0.468750 ) ( 252 -216 -36 3.500000 0 ) ) +( ( 252 -200 -12 4 0.937500 ) ( 252 -208 -12 4 0.468750 ) ( 252 -216 -12 4 0 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + desktop/plastic + ( 3 3 0 0 0 ) +( +( ( 60 -200 -12 1.875000 0.375000 ) ( 60 -200 -36 1.875000 1.125000 ) ( 156 -200 -36 4.875000 1.125000 ) ) +( ( 156 -200 -12 4.875000 0.375000 ) ( 156 -200 -36 4.875000 1.125000 ) ( 156 -200 -36 4.875000 1.125000 ) ) +( ( 252 -200 -12 7.875000 0.375000 ) ( 252 -200 -36 7.875000 1.125000 ) ( 156 -200 -36 4.875000 1.125000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + desktop/plastic + ( 3 3 0 0 0 ) +( +( ( 156 -216 -36 4.875000 1.125000 ) ( 60 -216 -36 1.875000 1.125000 ) ( 60 -216 -12 1.875000 0.375000 ) ) +( ( 156 -216 -36 4.875000 1.125000 ) ( 156 -216 -36 4.875000 1.125000 ) ( 156 -216 -12 4.875000 0.375000 ) ) +( ( 156 -216 -36 4.875000 1.125000 ) ( 252 -216 -36 7.875000 1.125000 ) ( 252 -216 -12 7.875000 0.375000 ) ) +) + } + } +} +// entity 96 +{ +"classname" "light" +"light" "500" +"origin" "-54 -312 8" +} diff --git a/docs/developer/TstMaps/komap1.map b/docs/developer/TstMaps/komap1.map new file mode 100644 index 00000000..a6065489 --- /dev/null +++ b/docs/developer/TstMaps/komap1.map @@ -0,0 +1,3452 @@ +{ +"classname" "worldspawn" +// brush 0 + { + patchDef2 + { + ko/flamegray1 + ( 9 3 0 0 0 ) +( +( ( -136 189 352 0 0 ) ( -136 189 372 0 0.156250 ) ( -136 189 392 0 0.312500 ) ) +( ( -136 165 352 0.375000 0 ) ( -136 165 372 0.375000 0.156250 ) ( -136 165 392 0.375000 0.312500 ) ) +( ( -112 165 352 0.750000 0 ) ( -112 165 372 0.750000 0.156250 ) ( -112 165 392 0.750000 0.312500 ) ) +( ( -88 165 352 1.125000 0 ) ( -88 165 372 1.125000 0.156250 ) ( -88 165 392 1.125000 0.312500 ) ) +( ( -88 189 352 1.500000 0 ) ( -88 189 372 1.500000 0.156250 ) ( -88 189 392 1.500000 0.312500 ) ) +( ( -88 213 352 1.875000 0 ) ( -88 213 372 1.875000 0.156250 ) ( -88 213 392 1.875000 0.312500 ) ) +( ( -112 213 352 2.250000 0 ) ( -112 213 372 2.250000 0.156250 ) ( -112 213 392 2.250000 0.312500 ) ) +( ( -136 213 352 2.625000 0 ) ( -136 213 372 2.625000 0.156250 ) ( -136 213 392 2.625000 0.312500 ) ) +( ( -136 189 352 3 0 ) ( -136 189 372 3 0.156250 ) ( -136 189 392 3 0.312500 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + cqjbko/kolamp + ( 9 3 0 0 0 ) +( +( ( -143 189 366 0 0 ) ( -143 189 343 0 0.179688 ) ( -112 189 346.285706 0 0.423232 ) ) +( ( -143 158 366 0.242188 0 ) ( -143 158 343 0.242188 0.179688 ) ( -112 189 346.285706 0.242188 0.423232 ) ) +( ( -112 158 366 0.484375 0 ) ( -112 158 343 0.484375 0.179688 ) ( -112 189 346.285706 0.484375 0.423232 ) ) +( ( -81 158 366 0.726563 0 ) ( -81 158 343 0.726563 0.179688 ) ( -112 189 346.285706 0.726563 0.423232 ) ) +( ( -81 189 366 0.968750 0 ) ( -81 189 343 0.968750 0.179688 ) ( -112 189 346.285706 0.968750 0.423232 ) ) +( ( -81 220 366 1.210938 0 ) ( -81 220 343 1.210938 0.179688 ) ( -112 189 346.285706 1.210938 0.423232 ) ) +( ( -112 220 366 1.453125 0 ) ( -112 220 343 1.453125 0.179688 ) ( -112 189 346.285706 1.453125 0.423232 ) ) +( ( -143 220 366 1.695313 0 ) ( -143 220 343 1.695313 0.179688 ) ( -112 189 346.285706 1.695313 0.423232 ) ) +( ( -143 189 366 1.937500 0 ) ( -143 189 343 1.937500 0.179688 ) ( -112 189 346.285706 1.937500 0.423232 ) ) +) + } + } +// brush 2 +{ +( -111 188 347 ) ( -111 190 347 ) ( -113 190 347 ) gothic_trim/pitted_rust3 -24 32 0 0.500000 -0.500000 134217728 0 0 +( -113 190 573 ) ( -111 190 573 ) ( -111 188 573 ) gothic_trim/pitted_rust3 -24 32 0 0.500000 -0.500000 134217728 0 0 +( -115 190 398 ) ( -115 188 398 ) ( -115 188 394 ) gothic_trim/pitted_rust3 32 -224 0 0.500000 -0.500000 134217728 0 0 +( -113 186 398 ) ( -111 186 398 ) ( -111 186 394 ) gothic_trim/pitted_rust3 -24 -224 0 0.500000 -0.500000 134217728 0 0 +( -109 188 398 ) ( -109 190 398 ) ( -109 190 394 ) gothic_trim/pitted_rust3 32 -224 0 0.500000 -0.500000 134217728 0 0 +( -111 192 398 ) ( -113 192 398 ) ( -113 192 394 ) gothic_trim/pitted_rust3 -24 -224 0 0.500000 -0.500000 134217728 0 0 +} +// brush 3 +{ +( -1344 480 0 ) ( -1376 480 0 ) ( -1376 352 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1376 352 776 ) ( -1376 480 776 ) ( -1344 480 776 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1360 -480 784 ) ( -1328 -480 784 ) ( -1328 -480 768 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1344 352 784 ) ( -1344 480 784 ) ( -1344 480 768 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -1344 480 784 ) ( -1376 480 784 ) ( -1376 480 768 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1376 480 784 ) ( -1376 352 784 ) ( -1376 352 768 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 4 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1264 -64 576 0 0 ) ( -1232 -64 576 0 0.500000 ) ( -1200 -64 576 0 1 ) ) +( ( -1264 -64 584 0.125000 0 ) ( -1232 -64 584 0.125000 0.500000 ) ( -1200 -64 584 0.125000 1 ) ) +( ( -1264 -64 592 0.250000 0 ) ( -1232 -64 592 0.250000 0.500000 ) ( -1200 -64 592 0.250000 1 ) ) +) + } + } +// brush 5 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1264 48 592 0 0 ) ( -1232 48 592 0 0.500000 ) ( -1200 48 592 0 1 ) ) +( ( -1264 56 592 0.125000 0 ) ( -1232 56 592 0.125000 0.500000 ) ( -1200 56 592 0.125000 1 ) ) +( ( -1264 64 592 0.250000 0 ) ( -1232 64 592 0.250000 0.500000 ) ( -1200 64 592 0.250000 1 ) ) +) + } + } +// brush 6 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1264 64 592 0 0 ) ( -1232 64 592 0 0.500000 ) ( -1200 64 592 0 1 ) ) +( ( -1264 63.720482 636.732056 0.698952 0 ) ( -1232 63.720482 636.732056 0.698952 0.500000 ) ( -1200 63.720482 636.732056 0.698952 1 ) ) +( ( -1264 48.007172 677.478271 1.381312 0 ) ( -1232 48.007172 677.478271 1.381312 0.500000 ) ( -1200 48.007172 677.478271 1.381312 1 ) ) +( ( -1264 34.606335 714.944580 2.003044 0 ) ( -1232 34.606335 714.944580 2.003044 0.500000 ) ( -1200 34.606335 714.944580 2.003044 1 ) ) +( ( -1264 11.439175 739.186829 2.526983 0 ) ( -1232 11.439175 739.186829 2.526983 0.500000 ) ( -1200 11.439175 739.186829 2.526983 1 ) ) +) + } + } +// brush 7 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1200 48 592 0 0 ) ( -1232 48 592 0 0.500000 ) ( -1264 48 592 0 1 ) ) +( ( -1200 48 633.754395 0.652412 0 ) ( -1232 48 633.754395 0.652412 0.500000 ) ( -1264 48 633.754395 0.652412 1 ) ) +( ( -1200 33 671.929871 1.293298 0 ) ( -1232 33 671.929871 1.293298 0.500000 ) ( -1264 33 671.929871 1.293298 1 ) ) +( ( -1200 21 706.526306 1.865462 0 ) ( -1232 21 706.526306 1.865462 0.500000 ) ( -1264 21 706.526306 1.865462 1 ) ) +( ( -1200 0 728 2.334763 0 ) ( -1232 0 728 2.334763 0.500000 ) ( -1264 0 728 2.334763 1 ) ) +) + } + } +// brush 8 +{ +( -1120 64 576 ) ( -2656 64 576 ) ( -2656 56 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -2656 56 592 ) ( -2656 64 592 ) ( -1120 64 592 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -2656 48 592 ) ( -1120 48 592 ) ( -1120 48 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -1200 56 592 ) ( -1200 64 592 ) ( -1200 64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -288 64 592 ) ( -1824 64 592 ) ( -1824 64 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -1264 64 592 ) ( -1264 56 592 ) ( -1264 56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 9 +{ +( -1344 -64 576 ) ( 192 -64 576 ) ( 192 -56 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( 192 -56 592 ) ( 192 -64 592 ) ( -1344 -64 592 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( 192 -48 592 ) ( -1344 -48 592 ) ( -1344 -48 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -1264 -56 592 ) ( -1264 -64 592 ) ( -1264 -64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -2176 -64 592 ) ( -640 -64 592 ) ( -640 -64 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -1200 -64 592 ) ( -1200 -56 592 ) ( -1200 -56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 10 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1200 -48 592 0 0 ) ( -1232 -48 592 0 0.500000 ) ( -1264 -48 592 0 1 ) ) +( ( -1200 -56 592 0.125000 0 ) ( -1232 -56 592 0.125000 0.500000 ) ( -1264 -56 592 0.125000 1 ) ) +( ( -1200 -64 592 0.250000 0 ) ( -1232 -64 592 0.250000 0.500000 ) ( -1264 -64 592 0.250000 1 ) ) +) + } + } +// brush 11 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1200 0 728 0 0 ) ( -1232 0 728 0 0.500000 ) ( -1264 0 728 0 1 ) ) +( ( -1200 5.719587 733.593384 0.125000 0 ) ( -1232 5.719587 733.593384 0.125000 0.500000 ) ( -1264 5.719587 733.593384 0.125000 1 ) ) +( ( -1200 11.439175 739.186829 0.250000 0 ) ( -1232 11.439175 739.186829 0.250000 0.500000 ) ( -1264 11.439175 739.186829 0.250000 1 ) ) +) + } + } +// brush 12 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1200 -64 592 0 0 ) ( -1232 -64 592 0 0.500000 ) ( -1264 -64 592 0 1 ) ) +( ( -1200 -64 637 0.703125 0 ) ( -1232 -64 637 0.703125 0.500000 ) ( -1264 -64 637 0.703125 1 ) ) +( ( -1200 -48 677 1.376271 0 ) ( -1232 -48 677 1.376271 0.500000 ) ( -1264 -48 677 1.376271 1 ) ) +( ( -1200 -35 715 2.003805 0 ) ( -1232 -35 715 2.003805 0.500000 ) ( -1264 -35 715 2.003805 1 ) ) +( ( -1200 -11 739 2.534135 0 ) ( -1232 -11 739 2.534135 0.500000 ) ( -1264 -11 739 2.534135 1 ) ) +) + } + } +// brush 13 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1264 0 728 0 0 ) ( -1232 0 728 0 0.500000 ) ( -1200 0 728 0 1 ) ) +( ( -1264 -6 734 0.132583 0 ) ( -1232 -6 734 0.132583 0.500000 ) ( -1200 -6 734 0.132583 1 ) ) +( ( -1264 -11 739 0.243068 0 ) ( -1232 -11 739 0.243068 0.500000 ) ( -1200 -11 739 0.243068 1 ) ) +) + } + } +// brush 14 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1200 -48 592 0 0 ) ( -1200 -56 592 0 0.125000 ) ( -1200 -64 592 0 0.250000 ) ) +( ( -1200 -48 634 0.656250 0 ) ( -1200 -56 635 0.656250 0.125000 ) ( -1200 -64 637 0.656250 0.250000 ) ) +( ( -1200 -33 672 1.294584 0 ) ( -1200 -41 675 1.294584 0.125000 ) ( -1200 -48 677 1.294584 0.250000 ) ) +( ( -1200 -21 707 1.872709 0 ) ( -1200 -28 711 1.872709 0.125000 ) ( -1200 -35 715 1.872709 0.250000 ) ) +( ( -1200 0 728 2.336748 0 ) ( -1200 0 735 2.336748 0.125000 ) ( -1200 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 15 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1264 -64 592 0 0 ) ( -1264 -56 592 0 0.125000 ) ( -1264 -48 592 0 0.250000 ) ) +( ( -1264 -64 637 0.703125 0 ) ( -1264 -56 635 0.703125 0.125000 ) ( -1264 -48 634 0.703125 0.250000 ) ) +( ( -1264 -48 677 1.376271 0 ) ( -1264 -41 675 1.376271 0.125000 ) ( -1264 -33 672 1.376271 0.250000 ) ) +( ( -1264 -35 715 2.003805 0 ) ( -1264 -28 711 2.003805 0.125000 ) ( -1264 -21 707 2.003805 0.250000 ) ) +( ( -1264 0 744 2.714012 0 ) ( -1264 0 735 2.714012 0.125000 ) ( -1264 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 16 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1264 48 592 0 0 ) ( -1264 56 592 0 0.125000 ) ( -1264 64 592 0 0.250000 ) ) +( ( -1264 48 634 0.656250 0 ) ( -1264 56 635 0.656250 0.125000 ) ( -1264 64 637 0.656250 0.250000 ) ) +( ( -1264 33 672 1.294584 0 ) ( -1264 41 675 1.294584 0.125000 ) ( -1264 48 677 1.294584 0.250000 ) ) +( ( -1264 21 707 1.872709 0 ) ( -1264 28 711 1.872709 0.125000 ) ( -1264 35 715 1.872709 0.250000 ) ) +( ( -1264 0 728 2.336748 0 ) ( -1264 0 735 2.336748 0.125000 ) ( -1264 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 17 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1200 64 592 0 0 ) ( -1200 56 592 0 0.125000 ) ( -1200 48 592 0 0.250000 ) ) +( ( -1200 64 637 0.703125 0 ) ( -1200 56 635 0.703125 0.125000 ) ( -1200 48 634 0.703125 0.250000 ) ) +( ( -1200 48 677 1.376271 0 ) ( -1200 41 675 1.376271 0.125000 ) ( -1200 33 672 1.376271 0.250000 ) ) +( ( -1200 35 715 2.003805 0 ) ( -1200 28 711 2.003805 0.125000 ) ( -1200 21 707 2.003805 0.250000 ) ) +( ( -1200 0 744 2.714012 0 ) ( -1200 0 735 2.714012 0.125000 ) ( -1200 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 18 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -976 64 592 0 0 ) ( -976 56 592 0 0.125000 ) ( -976 48 592 0 0.250000 ) ) +( ( -976 64 637 0.703125 0 ) ( -976 56 635 0.703125 0.125000 ) ( -976 48 634 0.703125 0.250000 ) ) +( ( -976 48 677 1.376271 0 ) ( -976 41 675 1.376271 0.125000 ) ( -976 33 672 1.376271 0.250000 ) ) +( ( -976 35 715 2.003805 0 ) ( -976 28 711 2.003805 0.125000 ) ( -976 21 707 2.003805 0.250000 ) ) +( ( -976 0 744 2.714012 0 ) ( -976 0 735 2.714012 0.125000 ) ( -976 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 19 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1040 48 592 0 0 ) ( -1040 56 592 0 0.125000 ) ( -1040 64 592 0 0.250000 ) ) +( ( -1040 48 634 0.656250 0 ) ( -1040 56 635 0.656250 0.125000 ) ( -1040 64 637 0.656250 0.250000 ) ) +( ( -1040 33 672 1.294584 0 ) ( -1040 41 675 1.294584 0.125000 ) ( -1040 48 677 1.294584 0.250000 ) ) +( ( -1040 21 707 1.872709 0 ) ( -1040 28 711 1.872709 0.125000 ) ( -1040 35 715 1.872709 0.250000 ) ) +( ( -1040 0 728 2.336748 0 ) ( -1040 0 735 2.336748 0.125000 ) ( -1040 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 20 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1040 -64 592 0 0 ) ( -1040 -56 592 0 0.125000 ) ( -1040 -48 592 0 0.250000 ) ) +( ( -1040 -64 637 0.703125 0 ) ( -1040 -56 635 0.703125 0.125000 ) ( -1040 -48 634 0.703125 0.250000 ) ) +( ( -1040 -48 677 1.376271 0 ) ( -1040 -41 675 1.376271 0.125000 ) ( -1040 -33 672 1.376271 0.250000 ) ) +( ( -1040 -35 715 2.003805 0 ) ( -1040 -28 711 2.003805 0.125000 ) ( -1040 -21 707 2.003805 0.250000 ) ) +( ( -1040 0 744 2.714012 0 ) ( -1040 0 735 2.714012 0.125000 ) ( -1040 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 21 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -976 -48 592 0 0 ) ( -976 -56 592 0 0.125000 ) ( -976 -64 592 0 0.250000 ) ) +( ( -976 -48 634 0.656250 0 ) ( -976 -56 635 0.656250 0.125000 ) ( -976 -64 637 0.656250 0.250000 ) ) +( ( -976 -33 672 1.294584 0 ) ( -976 -41 675 1.294584 0.125000 ) ( -976 -48 677 1.294584 0.250000 ) ) +( ( -976 -21 707 1.872709 0 ) ( -976 -28 711 1.872709 0.125000 ) ( -976 -35 715 1.872709 0.250000 ) ) +( ( -976 0 728 2.336748 0 ) ( -976 0 735 2.336748 0.125000 ) ( -976 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 22 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1040 0 728 0 0 ) ( -1008 0 728 0 0.500000 ) ( -976 0 728 0 1 ) ) +( ( -1040 -6 734 0.132583 0 ) ( -1008 -6 734 0.132583 0.500000 ) ( -976 -6 734 0.132583 1 ) ) +( ( -1040 -11 739 0.243068 0 ) ( -1008 -11 739 0.243068 0.500000 ) ( -976 -11 739 0.243068 1 ) ) +) + } + } +// brush 23 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -976 -64 592 0 0 ) ( -1008 -64 592 0 0.500000 ) ( -1040 -64 592 0 1 ) ) +( ( -976 -64 637 0.703125 0 ) ( -1008 -64 637 0.703125 0.500000 ) ( -1040 -64 637 0.703125 1 ) ) +( ( -976 -48 677 1.376271 0 ) ( -1008 -48 677 1.376271 0.500000 ) ( -1040 -48 677 1.376271 1 ) ) +( ( -976 -35 715 2.003805 0 ) ( -1008 -35 715 2.003805 0.500000 ) ( -1040 -35 715 2.003805 1 ) ) +( ( -976 -11 739 2.534135 0 ) ( -1008 -11 739 2.534135 0.500000 ) ( -1040 -11 739 2.534135 1 ) ) +) + } + } +// brush 24 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -976 0 728 0 0 ) ( -1008 0 728 0 0.500000 ) ( -1040 0 728 0 1 ) ) +( ( -976 5.719587 733.593384 0.125000 0 ) ( -1008 5.719587 733.593384 0.125000 0.500000 ) ( -1040 5.719587 733.593384 0.125000 1 ) ) +( ( -976 11.439175 739.186829 0.250000 0 ) ( -1008 11.439175 739.186829 0.250000 0.500000 ) ( -1040 11.439175 739.186829 0.250000 1 ) ) +) + } + } +// brush 25 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -976 -48 592 0 0 ) ( -1008 -48 592 0 0.500000 ) ( -1040 -48 592 0 1 ) ) +( ( -976 -56 592 0.125000 0 ) ( -1008 -56 592 0.125000 0.500000 ) ( -1040 -56 592 0.125000 1 ) ) +( ( -976 -64 592 0.250000 0 ) ( -1008 -64 592 0.250000 0.500000 ) ( -1040 -64 592 0.250000 1 ) ) +) + } + } +// brush 26 +{ +( -1120 -64 576 ) ( 416 -64 576 ) ( 416 -56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 416 -56 592 ) ( 416 -64 592 ) ( -1120 -64 592 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 416 -48 592 ) ( -1120 -48 592 ) ( -1120 -48 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1040 -56 592 ) ( -1040 -64 592 ) ( -1040 -64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1952 -64 592 ) ( -416 -64 592 ) ( -416 -64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -976 -64 592 ) ( -976 -56 592 ) ( -976 -56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 27 +{ +( -896 64 576 ) ( -2432 64 576 ) ( -2432 56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -2432 56 592 ) ( -2432 64 592 ) ( -896 64 592 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -2432 48 592 ) ( -896 48 592 ) ( -896 48 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -976 56 592 ) ( -976 64 592 ) ( -976 64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -64 64 592 ) ( -1600 64 592 ) ( -1600 64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1040 64 592 ) ( -1040 56 592 ) ( -1040 56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 28 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -976 48 592 0 0 ) ( -1008 48 592 0 0.500000 ) ( -1040 48 592 0 1 ) ) +( ( -976 48 633.754395 0.652412 0 ) ( -1008 48 633.754395 0.652412 0.500000 ) ( -1040 48 633.754395 0.652412 1 ) ) +( ( -976 33 671.929871 1.293298 0 ) ( -1008 33 671.929871 1.293298 0.500000 ) ( -1040 33 671.929871 1.293298 1 ) ) +( ( -976 21 706.526306 1.865462 0 ) ( -1008 21 706.526306 1.865462 0.500000 ) ( -1040 21 706.526306 1.865462 1 ) ) +( ( -976 0 728 2.334763 0 ) ( -1008 0 728 2.334763 0.500000 ) ( -1040 0 728 2.334763 1 ) ) +) + } + } +// brush 29 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1040 64 592 0 0 ) ( -1008 64 592 0 0.500000 ) ( -976 64 592 0 1 ) ) +( ( -1040 63.720482 636.732056 0.698952 0 ) ( -1008 63.720482 636.732056 0.698952 0.500000 ) ( -976 63.720482 636.732056 0.698952 1 ) ) +( ( -1040 48.007172 677.478271 1.381312 0 ) ( -1008 48.007172 677.478271 1.381312 0.500000 ) ( -976 48.007172 677.478271 1.381312 1 ) ) +( ( -1040 34.606335 714.944580 2.003044 0 ) ( -1008 34.606335 714.944580 2.003044 0.500000 ) ( -976 34.606335 714.944580 2.003044 1 ) ) +( ( -1040 11.439175 739.186829 2.526983 0 ) ( -1008 11.439175 739.186829 2.526983 0.500000 ) ( -976 11.439175 739.186829 2.526983 1 ) ) +) + } + } +// brush 30 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1040 48 592 0 0 ) ( -1008 48 592 0 0.500000 ) ( -976 48 592 0 1 ) ) +( ( -1040 56 592 0.125000 0 ) ( -1008 56 592 0.125000 0.500000 ) ( -976 56 592 0.125000 1 ) ) +( ( -1040 64 592 0.250000 0 ) ( -1008 64 592 0.250000 0.500000 ) ( -976 64 592 0.250000 1 ) ) +) + } + } +// brush 31 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1040 -64 576 0 0 ) ( -1008 -64 576 0 0.500000 ) ( -976 -64 576 0 1 ) ) +( ( -1040 -64 584 0.125000 0 ) ( -1008 -64 584 0.125000 0.500000 ) ( -976 -64 584 0.125000 1 ) ) +( ( -1040 -64 592 0.250000 0 ) ( -1008 -64 592 0.250000 0.500000 ) ( -976 -64 592 0.250000 1 ) ) +) + } + } +// brush 32 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -816 -64 576 0 0 ) ( -784 -64 576 0 0.500000 ) ( -752 -64 576 0 1 ) ) +( ( -816 -64 584 0.125000 0 ) ( -784 -64 584 0.125000 0.500000 ) ( -752 -64 584 0.125000 1 ) ) +( ( -816 -64 592 0.250000 0 ) ( -784 -64 592 0.250000 0.500000 ) ( -752 -64 592 0.250000 1 ) ) +) + } + } +// brush 33 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -816 48 592 0 0 ) ( -784 48 592 0 0.500000 ) ( -752 48 592 0 1 ) ) +( ( -816 56 592 0.125000 0 ) ( -784 56 592 0.125000 0.500000 ) ( -752 56 592 0.125000 1 ) ) +( ( -816 64 592 0.250000 0 ) ( -784 64 592 0.250000 0.500000 ) ( -752 64 592 0.250000 1 ) ) +) + } + } +// brush 34 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -816 64 592 0 0 ) ( -784 64 592 0 0.500000 ) ( -752 64 592 0 1 ) ) +( ( -816 63.720482 636.732056 0.698952 0 ) ( -784 63.720482 636.732056 0.698952 0.500000 ) ( -752 63.720482 636.732056 0.698952 1 ) ) +( ( -816 48.007172 677.478271 1.381312 0 ) ( -784 48.007172 677.478271 1.381312 0.500000 ) ( -752 48.007172 677.478271 1.381312 1 ) ) +( ( -816 34.606335 714.944580 2.003044 0 ) ( -784 34.606335 714.944580 2.003044 0.500000 ) ( -752 34.606335 714.944580 2.003044 1 ) ) +( ( -816 11.439175 739.186829 2.526983 0 ) ( -784 11.439175 739.186829 2.526983 0.500000 ) ( -752 11.439175 739.186829 2.526983 1 ) ) +) + } + } +// brush 35 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -752 48 592 0 0 ) ( -784 48 592 0 0.500000 ) ( -816 48 592 0 1 ) ) +( ( -752 48 633.754395 0.652412 0 ) ( -784 48 633.754395 0.652412 0.500000 ) ( -816 48 633.754395 0.652412 1 ) ) +( ( -752 33 671.929871 1.293298 0 ) ( -784 33 671.929871 1.293298 0.500000 ) ( -816 33 671.929871 1.293298 1 ) ) +( ( -752 21 706.526306 1.865462 0 ) ( -784 21 706.526306 1.865462 0.500000 ) ( -816 21 706.526306 1.865462 1 ) ) +( ( -752 0 728 2.334763 0 ) ( -784 0 728 2.334763 0.500000 ) ( -816 0 728 2.334763 1 ) ) +) + } + } +// brush 36 +{ +( -672 64 576 ) ( -2208 64 576 ) ( -2208 56 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -2208 56 592 ) ( -2208 64 592 ) ( -672 64 592 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -2208 48 592 ) ( -672 48 592 ) ( -672 48 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -752 56 592 ) ( -752 64 592 ) ( -752 64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 160 64 592 ) ( -1376 64 592 ) ( -1376 64 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -816 64 592 ) ( -816 56 592 ) ( -816 56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 37 +{ +( -896 -64 576 ) ( 640 -64 576 ) ( 640 -56 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( 640 -56 592 ) ( 640 -64 592 ) ( -896 -64 592 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( 640 -48 592 ) ( -896 -48 592 ) ( -896 -48 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -816 -56 592 ) ( -816 -64 592 ) ( -816 -64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1728 -64 592 ) ( -192 -64 592 ) ( -192 -64 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -752 -64 592 ) ( -752 -56 592 ) ( -752 -56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 38 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -752 -48 592 0 0 ) ( -784 -48 592 0 0.500000 ) ( -816 -48 592 0 1 ) ) +( ( -752 -56 592 0.125000 0 ) ( -784 -56 592 0.125000 0.500000 ) ( -816 -56 592 0.125000 1 ) ) +( ( -752 -64 592 0.250000 0 ) ( -784 -64 592 0.250000 0.500000 ) ( -816 -64 592 0.250000 1 ) ) +) + } + } +// brush 39 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -752 0 728 0 0 ) ( -784 0 728 0 0.500000 ) ( -816 0 728 0 1 ) ) +( ( -752 5.719587 733.593384 0.125000 0 ) ( -784 5.719587 733.593384 0.125000 0.500000 ) ( -816 5.719587 733.593384 0.125000 1 ) ) +( ( -752 11.439175 739.186829 0.250000 0 ) ( -784 11.439175 739.186829 0.250000 0.500000 ) ( -816 11.439175 739.186829 0.250000 1 ) ) +) + } + } +// brush 40 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -752 -64 592 0 0 ) ( -784 -64 592 0 0.500000 ) ( -816 -64 592 0 1 ) ) +( ( -752 -64 637 0.703125 0 ) ( -784 -64 637 0.703125 0.500000 ) ( -816 -64 637 0.703125 1 ) ) +( ( -752 -48 677 1.376271 0 ) ( -784 -48 677 1.376271 0.500000 ) ( -816 -48 677 1.376271 1 ) ) +( ( -752 -35 715 2.003805 0 ) ( -784 -35 715 2.003805 0.500000 ) ( -816 -35 715 2.003805 1 ) ) +( ( -752 -11 739 2.534135 0 ) ( -784 -11 739 2.534135 0.500000 ) ( -816 -11 739 2.534135 1 ) ) +) + } + } +// brush 41 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -816 0 728 0 0 ) ( -784 0 728 0 0.500000 ) ( -752 0 728 0 1 ) ) +( ( -816 -6 734 0.132583 0 ) ( -784 -6 734 0.132583 0.500000 ) ( -752 -6 734 0.132583 1 ) ) +( ( -816 -11 739 0.243068 0 ) ( -784 -11 739 0.243068 0.500000 ) ( -752 -11 739 0.243068 1 ) ) +) + } + } +// brush 42 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -752 -48 592 0 0 ) ( -752 -56 592 0 0.125000 ) ( -752 -64 592 0 0.250000 ) ) +( ( -752 -48 634 0.656250 0 ) ( -752 -56 635 0.656250 0.125000 ) ( -752 -64 637 0.656250 0.250000 ) ) +( ( -752 -33 672 1.294584 0 ) ( -752 -41 675 1.294584 0.125000 ) ( -752 -48 677 1.294584 0.250000 ) ) +( ( -752 -21 707 1.872709 0 ) ( -752 -28 711 1.872709 0.125000 ) ( -752 -35 715 1.872709 0.250000 ) ) +( ( -752 0 728 2.336748 0 ) ( -752 0 735 2.336748 0.125000 ) ( -752 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 43 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -816 -64 592 0 0 ) ( -816 -56 592 0 0.125000 ) ( -816 -48 592 0 0.250000 ) ) +( ( -816 -64 637 0.703125 0 ) ( -816 -56 635 0.703125 0.125000 ) ( -816 -48 634 0.703125 0.250000 ) ) +( ( -816 -48 677 1.376271 0 ) ( -816 -41 675 1.376271 0.125000 ) ( -816 -33 672 1.376271 0.250000 ) ) +( ( -816 -35 715 2.003805 0 ) ( -816 -28 711 2.003805 0.125000 ) ( -816 -21 707 2.003805 0.250000 ) ) +( ( -816 0 744 2.714012 0 ) ( -816 0 735 2.714012 0.125000 ) ( -816 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 44 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -816 48 592 0 0 ) ( -816 56 592 0 0.125000 ) ( -816 64 592 0 0.250000 ) ) +( ( -816 48 634 0.656250 0 ) ( -816 56 635 0.656250 0.125000 ) ( -816 64 637 0.656250 0.250000 ) ) +( ( -816 33 672 1.294584 0 ) ( -816 41 675 1.294584 0.125000 ) ( -816 48 677 1.294584 0.250000 ) ) +( ( -816 21 707 1.872709 0 ) ( -816 28 711 1.872709 0.125000 ) ( -816 35 715 1.872709 0.250000 ) ) +( ( -816 0 728 2.336748 0 ) ( -816 0 735 2.336748 0.125000 ) ( -816 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 45 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -752 64 592 0 0 ) ( -752 56 592 0 0.125000 ) ( -752 48 592 0 0.250000 ) ) +( ( -752 64 637 0.703125 0 ) ( -752 56 635 0.703125 0.125000 ) ( -752 48 634 0.703125 0.250000 ) ) +( ( -752 48 677 1.376271 0 ) ( -752 41 675 1.376271 0.125000 ) ( -752 33 672 1.376271 0.250000 ) ) +( ( -752 35 715 2.003805 0 ) ( -752 28 711 2.003805 0.125000 ) ( -752 21 707 2.003805 0.250000 ) ) +( ( -752 0 744 2.714012 0 ) ( -752 0 735 2.714012 0.125000 ) ( -752 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 46 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -528 64 592 0 0 ) ( -528 56 592 0 0.125000 ) ( -528 48 592 0 0.250000 ) ) +( ( -528 64 637 0.703125 0 ) ( -528 56 635 0.703125 0.125000 ) ( -528 48 634 0.703125 0.250000 ) ) +( ( -528 48 677 1.376271 0 ) ( -528 41 675 1.376271 0.125000 ) ( -528 33 672 1.376271 0.250000 ) ) +( ( -528 35 715 2.003805 0 ) ( -528 28 711 2.003805 0.125000 ) ( -528 21 707 2.003805 0.250000 ) ) +( ( -528 0 744 2.714012 0 ) ( -528 0 735 2.714012 0.125000 ) ( -528 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 47 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -592 48 592 0 0 ) ( -592 56 592 0 0.125000 ) ( -592 64 592 0 0.250000 ) ) +( ( -592 48 634 0.656250 0 ) ( -592 56 635 0.656250 0.125000 ) ( -592 64 637 0.656250 0.250000 ) ) +( ( -592 33 672 1.294584 0 ) ( -592 41 675 1.294584 0.125000 ) ( -592 48 677 1.294584 0.250000 ) ) +( ( -592 21 707 1.872709 0 ) ( -592 28 711 1.872709 0.125000 ) ( -592 35 715 1.872709 0.250000 ) ) +( ( -592 0 728 2.336748 0 ) ( -592 0 735 2.336748 0.125000 ) ( -592 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 48 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -592 -64 592 0 0 ) ( -592 -56 592 0 0.125000 ) ( -592 -48 592 0 0.250000 ) ) +( ( -592 -64 637 0.703125 0 ) ( -592 -56 635 0.703125 0.125000 ) ( -592 -48 634 0.703125 0.250000 ) ) +( ( -592 -48 677 1.376271 0 ) ( -592 -41 675 1.376271 0.125000 ) ( -592 -33 672 1.376271 0.250000 ) ) +( ( -592 -35 715 2.003805 0 ) ( -592 -28 711 2.003805 0.125000 ) ( -592 -21 707 2.003805 0.250000 ) ) +( ( -592 0 744 2.714012 0 ) ( -592 0 735 2.714012 0.125000 ) ( -592 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 49 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -528 -48 592 0 0 ) ( -528 -56 592 0 0.125000 ) ( -528 -64 592 0 0.250000 ) ) +( ( -528 -48 634 0.656250 0 ) ( -528 -56 635 0.656250 0.125000 ) ( -528 -64 637 0.656250 0.250000 ) ) +( ( -528 -33 672 1.294584 0 ) ( -528 -41 675 1.294584 0.125000 ) ( -528 -48 677 1.294584 0.250000 ) ) +( ( -528 -21 707 1.872709 0 ) ( -528 -28 711 1.872709 0.125000 ) ( -528 -35 715 1.872709 0.250000 ) ) +( ( -528 0 728 2.336748 0 ) ( -528 0 735 2.336748 0.125000 ) ( -528 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 50 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -592 0 728 0 0 ) ( -560 0 728 0 0.500000 ) ( -528 0 728 0 1 ) ) +( ( -592 -6 734 0.132583 0 ) ( -560 -6 734 0.132583 0.500000 ) ( -528 -6 734 0.132583 1 ) ) +( ( -592 -11 739 0.243068 0 ) ( -560 -11 739 0.243068 0.500000 ) ( -528 -11 739 0.243068 1 ) ) +) + } + } +// brush 51 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -528 -64 592 0 0 ) ( -560 -64 592 0 0.500000 ) ( -592 -64 592 0 1 ) ) +( ( -528 -64 637 0.703125 0 ) ( -560 -64 637 0.703125 0.500000 ) ( -592 -64 637 0.703125 1 ) ) +( ( -528 -48 677 1.376271 0 ) ( -560 -48 677 1.376271 0.500000 ) ( -592 -48 677 1.376271 1 ) ) +( ( -528 -35 715 2.003805 0 ) ( -560 -35 715 2.003805 0.500000 ) ( -592 -35 715 2.003805 1 ) ) +( ( -528 -11 739 2.534135 0 ) ( -560 -11 739 2.534135 0.500000 ) ( -592 -11 739 2.534135 1 ) ) +) + } + } +// brush 52 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -528 0 728 0 0 ) ( -560 0 728 0 0.500000 ) ( -592 0 728 0 1 ) ) +( ( -528 5.719587 733.593384 0.125000 0 ) ( -560 5.719587 733.593384 0.125000 0.500000 ) ( -592 5.719587 733.593384 0.125000 1 ) ) +( ( -528 11.439175 739.186829 0.250000 0 ) ( -560 11.439175 739.186829 0.250000 0.500000 ) ( -592 11.439175 739.186829 0.250000 1 ) ) +) + } + } +// brush 53 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -528 -48 592 0 0 ) ( -560 -48 592 0 0.500000 ) ( -592 -48 592 0 1 ) ) +( ( -528 -56 592 0.125000 0 ) ( -560 -56 592 0.125000 0.500000 ) ( -592 -56 592 0.125000 1 ) ) +( ( -528 -64 592 0.250000 0 ) ( -560 -64 592 0.250000 0.500000 ) ( -592 -64 592 0.250000 1 ) ) +) + } + } +// brush 54 +{ +( -672 -64 576 ) ( 864 -64 576 ) ( 864 -56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 864 -56 592 ) ( 864 -64 592 ) ( -672 -64 592 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 864 -48 592 ) ( -672 -48 592 ) ( -672 -48 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -592 -56 592 ) ( -592 -64 592 ) ( -592 -64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1504 -64 592 ) ( 32 -64 592 ) ( 32 -64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -528 -64 592 ) ( -528 -56 592 ) ( -528 -56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 55 +{ +( -448 64 576 ) ( -1984 64 576 ) ( -1984 56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1984 56 592 ) ( -1984 64 592 ) ( -448 64 592 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1984 48 592 ) ( -448 48 592 ) ( -448 48 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -528 56 592 ) ( -528 64 592 ) ( -528 64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 384 64 592 ) ( -1152 64 592 ) ( -1152 64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -592 64 592 ) ( -592 56 592 ) ( -592 56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 56 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -528 48 592 0 0 ) ( -560 48 592 0 0.500000 ) ( -592 48 592 0 1 ) ) +( ( -528 48 633.754395 0.652412 0 ) ( -560 48 633.754395 0.652412 0.500000 ) ( -592 48 633.754395 0.652412 1 ) ) +( ( -528 33 671.929871 1.293298 0 ) ( -560 33 671.929871 1.293298 0.500000 ) ( -592 33 671.929871 1.293298 1 ) ) +( ( -528 21 706.526306 1.865462 0 ) ( -560 21 706.526306 1.865462 0.500000 ) ( -592 21 706.526306 1.865462 1 ) ) +( ( -528 0 728 2.334763 0 ) ( -560 0 728 2.334763 0.500000 ) ( -592 0 728 2.334763 1 ) ) +) + } + } +// brush 57 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -592 64 592 0 0 ) ( -560 64 592 0 0.500000 ) ( -528 64 592 0 1 ) ) +( ( -592 63.720482 636.732056 0.698952 0 ) ( -560 63.720482 636.732056 0.698952 0.500000 ) ( -528 63.720482 636.732056 0.698952 1 ) ) +( ( -592 48.007172 677.478271 1.381312 0 ) ( -560 48.007172 677.478271 1.381312 0.500000 ) ( -528 48.007172 677.478271 1.381312 1 ) ) +( ( -592 34.606335 714.944580 2.003044 0 ) ( -560 34.606335 714.944580 2.003044 0.500000 ) ( -528 34.606335 714.944580 2.003044 1 ) ) +( ( -592 11.439175 739.186829 2.526983 0 ) ( -560 11.439175 739.186829 2.526983 0.500000 ) ( -528 11.439175 739.186829 2.526983 1 ) ) +) + } + } +// brush 58 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -592 48 592 0 0 ) ( -560 48 592 0 0.500000 ) ( -528 48 592 0 1 ) ) +( ( -592 56 592 0.125000 0 ) ( -560 56 592 0.125000 0.500000 ) ( -528 56 592 0.125000 1 ) ) +( ( -592 64 592 0.250000 0 ) ( -560 64 592 0.250000 0.500000 ) ( -528 64 592 0.250000 1 ) ) +) + } + } +// brush 59 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -592 -64 576 0 0 ) ( -560 -64 576 0 0.500000 ) ( -528 -64 576 0 1 ) ) +( ( -592 -64 584 0.125000 0 ) ( -560 -64 584 0.125000 0.500000 ) ( -528 -64 584 0.125000 1 ) ) +( ( -592 -64 592 0.250000 0 ) ( -560 -64 592 0.250000 0.500000 ) ( -528 -64 592 0.250000 1 ) ) +) + } + } +// brush 60 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -368 -64 576 0 0 ) ( -336 -64 576 0 0.500000 ) ( -304 -64 576 0 1 ) ) +( ( -368 -64 584 0.125000 0 ) ( -336 -64 584 0.125000 0.500000 ) ( -304 -64 584 0.125000 1 ) ) +( ( -368 -64 592 0.250000 0 ) ( -336 -64 592 0.250000 0.500000 ) ( -304 -64 592 0.250000 1 ) ) +) + } + } +// brush 61 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -368 48 592 0 0 ) ( -336 48 592 0 0.500000 ) ( -304 48 592 0 1 ) ) +( ( -368 56 592 0.125000 0 ) ( -336 56 592 0.125000 0.500000 ) ( -304 56 592 0.125000 1 ) ) +( ( -368 64 592 0.250000 0 ) ( -336 64 592 0.250000 0.500000 ) ( -304 64 592 0.250000 1 ) ) +) + } + } +// brush 62 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -368 64 592 0 0 ) ( -336 64 592 0 0.500000 ) ( -304 64 592 0 1 ) ) +( ( -368 63.720482 636.732056 0.698952 0 ) ( -336 63.720482 636.732056 0.698952 0.500000 ) ( -304 63.720482 636.732056 0.698952 1 ) ) +( ( -368 48.007172 677.478271 1.381312 0 ) ( -336 48.007172 677.478271 1.381312 0.500000 ) ( -304 48.007172 677.478271 1.381312 1 ) ) +( ( -368 34.606335 714.944580 2.003044 0 ) ( -336 34.606335 714.944580 2.003044 0.500000 ) ( -304 34.606335 714.944580 2.003044 1 ) ) +( ( -368 11.439175 739.186829 2.526983 0 ) ( -336 11.439175 739.186829 2.526983 0.500000 ) ( -304 11.439175 739.186829 2.526983 1 ) ) +) + } + } +// brush 63 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -304 48 592 0 0 ) ( -336 48 592 0 0.500000 ) ( -368 48 592 0 1 ) ) +( ( -304 48 633.754395 0.652412 0 ) ( -336 48 633.754395 0.652412 0.500000 ) ( -368 48 633.754395 0.652412 1 ) ) +( ( -304 33 671.929871 1.293298 0 ) ( -336 33 671.929871 1.293298 0.500000 ) ( -368 33 671.929871 1.293298 1 ) ) +( ( -304 21 706.526306 1.865462 0 ) ( -336 21 706.526306 1.865462 0.500000 ) ( -368 21 706.526306 1.865462 1 ) ) +( ( -304 0 728 2.334763 0 ) ( -336 0 728 2.334763 0.500000 ) ( -368 0 728 2.334763 1 ) ) +) + } + } +// brush 64 +{ +( -224 64 576 ) ( -1760 64 576 ) ( -1760 56 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -1760 56 592 ) ( -1760 64 592 ) ( -224 64 592 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -1760 48 592 ) ( -224 48 592 ) ( -224 48 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -304 56 592 ) ( -304 64 592 ) ( -304 64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 608 64 592 ) ( -928 64 592 ) ( -928 64 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -368 64 592 ) ( -368 56 592 ) ( -368 56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 65 +{ +( -448 -64 576 ) ( 1088 -64 576 ) ( 1088 -56 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( 1088 -56 592 ) ( 1088 -64 592 ) ( -448 -64 592 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( 1088 -48 592 ) ( -448 -48 592 ) ( -448 -48 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -368 -56 592 ) ( -368 -64 592 ) ( -368 -64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1280 -64 592 ) ( 256 -64 592 ) ( 256 -64 576 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -304 -64 592 ) ( -304 -56 592 ) ( -304 -56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 66 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -304 -48 592 0 0 ) ( -336 -48 592 0 0.500000 ) ( -368 -48 592 0 1 ) ) +( ( -304 -56 592 0.125000 0 ) ( -336 -56 592 0.125000 0.500000 ) ( -368 -56 592 0.125000 1 ) ) +( ( -304 -64 592 0.250000 0 ) ( -336 -64 592 0.250000 0.500000 ) ( -368 -64 592 0.250000 1 ) ) +) + } + } +// brush 67 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -304 0 728 0 0 ) ( -336 0 728 0 0.500000 ) ( -368 0 728 0 1 ) ) +( ( -304 5.719587 733.593384 0.125000 0 ) ( -336 5.719587 733.593384 0.125000 0.500000 ) ( -368 5.719587 733.593384 0.125000 1 ) ) +( ( -304 11.439175 739.186829 0.250000 0 ) ( -336 11.439175 739.186829 0.250000 0.500000 ) ( -368 11.439175 739.186829 0.250000 1 ) ) +) + } + } +// brush 68 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -304 -64 592 0 0 ) ( -336 -64 592 0 0.500000 ) ( -368 -64 592 0 1 ) ) +( ( -304 -64 637 0.703125 0 ) ( -336 -64 637 0.703125 0.500000 ) ( -368 -64 637 0.703125 1 ) ) +( ( -304 -48 677 1.376271 0 ) ( -336 -48 677 1.376271 0.500000 ) ( -368 -48 677 1.376271 1 ) ) +( ( -304 -35 715 2.003805 0 ) ( -336 -35 715 2.003805 0.500000 ) ( -368 -35 715 2.003805 1 ) ) +( ( -304 -11 739 2.534135 0 ) ( -336 -11 739 2.534135 0.500000 ) ( -368 -11 739 2.534135 1 ) ) +) + } + } +// brush 69 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -368 0 728 0 0 ) ( -336 0 728 0 0.500000 ) ( -304 0 728 0 1 ) ) +( ( -368 -6 734 0.132583 0 ) ( -336 -6 734 0.132583 0.500000 ) ( -304 -6 734 0.132583 1 ) ) +( ( -368 -11 739 0.243068 0 ) ( -336 -11 739 0.243068 0.500000 ) ( -304 -11 739 0.243068 1 ) ) +) + } + } +// brush 70 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -304 -48 592 0 0 ) ( -304 -56 592 0 0.125000 ) ( -304 -64 592 0 0.250000 ) ) +( ( -304 -48 634 0.656250 0 ) ( -304 -56 635 0.656250 0.125000 ) ( -304 -64 637 0.656250 0.250000 ) ) +( ( -304 -33 672 1.294584 0 ) ( -304 -41 675 1.294584 0.125000 ) ( -304 -48 677 1.294584 0.250000 ) ) +( ( -304 -21 707 1.872709 0 ) ( -304 -28 711 1.872709 0.125000 ) ( -304 -35 715 1.872709 0.250000 ) ) +( ( -304 0 728 2.336748 0 ) ( -304 0 735 2.336748 0.125000 ) ( -304 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 71 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -368 -64 592 0 0 ) ( -368 -56 592 0 0.125000 ) ( -368 -48 592 0 0.250000 ) ) +( ( -368 -64 637 0.703125 0 ) ( -368 -56 635 0.703125 0.125000 ) ( -368 -48 634 0.703125 0.250000 ) ) +( ( -368 -48 677 1.376271 0 ) ( -368 -41 675 1.376271 0.125000 ) ( -368 -33 672 1.376271 0.250000 ) ) +( ( -368 -35 715 2.003805 0 ) ( -368 -28 711 2.003805 0.125000 ) ( -368 -21 707 2.003805 0.250000 ) ) +( ( -368 0 744 2.714012 0 ) ( -368 0 735 2.714012 0.125000 ) ( -368 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 72 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -368 48 592 0 0 ) ( -368 56 592 0 0.125000 ) ( -368 64 592 0 0.250000 ) ) +( ( -368 48 634 0.656250 0 ) ( -368 56 635 0.656250 0.125000 ) ( -368 64 637 0.656250 0.250000 ) ) +( ( -368 33 672 1.294584 0 ) ( -368 41 675 1.294584 0.125000 ) ( -368 48 677 1.294584 0.250000 ) ) +( ( -368 21 707 1.872709 0 ) ( -368 28 711 1.872709 0.125000 ) ( -368 35 715 1.872709 0.250000 ) ) +( ( -368 0 728 2.336748 0 ) ( -368 0 735 2.336748 0.125000 ) ( -368 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 73 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -304 64 592 0 0 ) ( -304 56 592 0 0.125000 ) ( -304 48 592 0 0.250000 ) ) +( ( -304 64 637 0.703125 0 ) ( -304 56 635 0.703125 0.125000 ) ( -304 48 634 0.703125 0.250000 ) ) +( ( -304 48 677 1.376271 0 ) ( -304 41 675 1.376271 0.125000 ) ( -304 33 672 1.376271 0.250000 ) ) +( ( -304 35 715 2.003805 0 ) ( -304 28 711 2.003805 0.125000 ) ( -304 21 707 2.003805 0.250000 ) ) +( ( -304 0 744 2.714012 0 ) ( -304 0 735 2.714012 0.125000 ) ( -304 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 74 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -80 64 592 0 0 ) ( -80 56 592 0 0.125000 ) ( -80 48 592 0 0.250000 ) ) +( ( -80 64 637 0.703125 0 ) ( -80 56 635 0.703125 0.125000 ) ( -80 48 634 0.703125 0.250000 ) ) +( ( -80 48 677 1.376271 0 ) ( -80 41 675 1.376271 0.125000 ) ( -80 33 672 1.376271 0.250000 ) ) +( ( -80 35 715 2.003805 0 ) ( -80 28 711 2.003805 0.125000 ) ( -80 21 707 2.003805 0.250000 ) ) +( ( -80 0 744 2.714012 0 ) ( -80 0 735 2.714012 0.125000 ) ( -80 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 75 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -144 48 592 0 0 ) ( -144 56 592 0 0.125000 ) ( -144 64 592 0 0.250000 ) ) +( ( -144 48 634 0.656250 0 ) ( -144 56 635 0.656250 0.125000 ) ( -144 64 637 0.656250 0.250000 ) ) +( ( -144 33 672 1.294584 0 ) ( -144 41 675 1.294584 0.125000 ) ( -144 48 677 1.294584 0.250000 ) ) +( ( -144 21 707 1.872709 0 ) ( -144 28 711 1.872709 0.125000 ) ( -144 35 715 1.872709 0.250000 ) ) +( ( -144 0 728 2.336748 0 ) ( -144 0 735 2.336748 0.125000 ) ( -144 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 76 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -144 -64 592 0 0 ) ( -144 -56 592 0 0.125000 ) ( -144 -48 592 0 0.250000 ) ) +( ( -144 -64 637 0.703125 0 ) ( -144 -56 635 0.703125 0.125000 ) ( -144 -48 634 0.703125 0.250000 ) ) +( ( -144 -48 677 1.376271 0 ) ( -144 -41 675 1.376271 0.125000 ) ( -144 -33 672 1.376271 0.250000 ) ) +( ( -144 -35 715 2.003805 0 ) ( -144 -28 711 2.003805 0.125000 ) ( -144 -21 707 2.003805 0.250000 ) ) +( ( -144 0 744 2.714012 0 ) ( -144 0 735 2.714012 0.125000 ) ( -144 0 728 2.714012 0.250000 ) ) +) + } + } +// brush 77 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -80 -48 592 0 0 ) ( -80 -56 592 0 0.125000 ) ( -80 -64 592 0 0.250000 ) ) +( ( -80 -48 634 0.656250 0 ) ( -80 -56 635 0.656250 0.125000 ) ( -80 -64 637 0.656250 0.250000 ) ) +( ( -80 -33 672 1.294584 0 ) ( -80 -41 675 1.294584 0.125000 ) ( -80 -48 677 1.294584 0.250000 ) ) +( ( -80 -21 707 1.872709 0 ) ( -80 -28 711 1.872709 0.125000 ) ( -80 -35 715 1.872709 0.250000 ) ) +( ( -80 0 728 2.336748 0 ) ( -80 0 735 2.336748 0.125000 ) ( -80 0 744 2.336748 0.250000 ) ) +) + } + } +// brush 78 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -144 0 728 0 0 ) ( -112 0 728 0 0.500000 ) ( -80 0 728 0 1 ) ) +( ( -144 -6 734 0.132583 0 ) ( -112 -6 734 0.132583 0.500000 ) ( -80 -6 734 0.132583 1 ) ) +( ( -144 -11 739 0.243068 0 ) ( -112 -11 739 0.243068 0.500000 ) ( -80 -11 739 0.243068 1 ) ) +) + } + } +// brush 79 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -80 -64 592 0 0 ) ( -112 -64 592 0 0.500000 ) ( -144 -64 592 0 1 ) ) +( ( -80 -64 637 0.703125 0 ) ( -112 -64 637 0.703125 0.500000 ) ( -144 -64 637 0.703125 1 ) ) +( ( -80 -48 677 1.376271 0 ) ( -112 -48 677 1.376271 0.500000 ) ( -144 -48 677 1.376271 1 ) ) +( ( -80 -35 715 2.003805 0 ) ( -112 -35 715 2.003805 0.500000 ) ( -144 -35 715 2.003805 1 ) ) +( ( -80 -11 739 2.534135 0 ) ( -112 -11 739 2.534135 0.500000 ) ( -144 -11 739 2.534135 1 ) ) +) + } + } +// brush 80 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -80 0 728 0 0 ) ( -111.999992 0 728 0 0.500000 ) ( -144 0 728 0 1 ) ) +( ( -80 5.719587 733.593384 0.125000 0 ) ( -111.999992 5.719587 733.593384 0.125000 0.500000 ) ( -144 5.719587 733.593384 0.125000 1 ) ) +( ( -80 11.439175 739.186829 0.250000 0 ) ( -111.999992 11.439175 739.186829 0.250000 0.500000 ) ( -144 11.439175 739.186829 0.250000 1 ) ) +) + } + } +// brush 81 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -80 -48 592 0 0 ) ( -112 -48 592 0 0.500000 ) ( -144 -48 592 0 1 ) ) +( ( -80 -56 592 0.125000 0 ) ( -112 -56 592 0.125000 0.500000 ) ( -144 -56 592 0.125000 1 ) ) +( ( -80 -64 592 0.250000 0 ) ( -112 -64 592 0.250000 0.500000 ) ( -144 -64 592 0.250000 1 ) ) +) + } + } +// brush 82 +{ +( -224 -64 576 ) ( 1312 -64 576 ) ( 1312 -56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 1312 -56 592 ) ( 1312 -64 592 ) ( -224 -64 592 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 1312 -48 592 ) ( -224 -48 592 ) ( -224 -48 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -144 -56 592 ) ( -144 -64 592 ) ( -144 -64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1056 -64 592 ) ( 480 -64 592 ) ( 480 -64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -80 -64 592 ) ( -80 -56 592 ) ( -80 -56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 83 +{ +( 0 64 576 ) ( -1536 64 576 ) ( -1536 56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1536 56 592 ) ( -1536 64 592 ) ( 0 64 592 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1536 48 592 ) ( 0 48 592 ) ( 0 48 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -80 56 592 ) ( -80 64 592 ) ( -80 64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 832 64 592 ) ( -704 64 592 ) ( -704 64 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -144 64 592 ) ( -144 56 592 ) ( -144 56 576 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 84 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -80 48 592 0 0 ) ( -111.999992 48 592 0 0.500000 ) ( -144 48 592 0 1 ) ) +( ( -80 48 633.754395 0.652412 0 ) ( -111.999992 48 633.754395 0.652412 0.500000 ) ( -144 48 633.754395 0.652412 1 ) ) +( ( -80 33 671.929871 1.293298 0 ) ( -111.999992 33 671.929871 1.293298 0.500000 ) ( -144 33 671.929871 1.293298 1 ) ) +( ( -80 21 706.526306 1.865462 0 ) ( -111.999992 21 706.526306 1.865462 0.500000 ) ( -144 21 706.526306 1.865462 1 ) ) +( ( -80 0 728 2.334763 0 ) ( -111.999992 0 728 2.334763 0.500000 ) ( -144 0 728 2.334763 1 ) ) +) + } + } +// brush 85 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -144 64 592 0 0 ) ( -111.999992 64 592 0 0.500000 ) ( -80 64 592 0 1 ) ) +( ( -144 63.720482 636.732056 0.698952 0 ) ( -111.999992 63.720482 636.732056 0.698952 0.500000 ) ( -80 63.720482 636.732056 0.698952 1 ) ) +( ( -144 48.007172 677.478271 1.381312 0 ) ( -111.999992 48.007172 677.478271 1.381312 0.500000 ) ( -80 48.007172 677.478271 1.381312 1 ) ) +( ( -144 34.606335 714.944580 2.003044 0 ) ( -111.999992 34.606335 714.944580 2.003044 0.500000 ) ( -80 34.606335 714.944580 2.003044 1 ) ) +( ( -144 11.439175 739.186829 2.526983 0 ) ( -111.999992 11.439175 739.186829 2.526983 0.500000 ) ( -80 11.439175 739.186829 2.526983 1 ) ) +) + } + } +// brush 86 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -144 48 592 0 0 ) ( -111.999992 48 592 0 0.500000 ) ( -80 48 592 0 1 ) ) +( ( -144 56 592 0.125000 0 ) ( -111.999992 56 592 0.125000 0.500000 ) ( -80 56 592 0.125000 1 ) ) +( ( -144 64 592 0.250000 0 ) ( -111.999992 64 592 0.250000 0.500000 ) ( -80 64 592 0.250000 1 ) ) +) + } + } +// brush 87 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -144 -64 576 0 0 ) ( -112 -64 576 0 0.500000 ) ( -80 -64 576 0 1 ) ) +( ( -144 -64 584 0.125000 0 ) ( -112 -64 584 0.125000 0.500000 ) ( -80 -64 584 0.125000 1 ) ) +( ( -144 -64 592 0.250000 0 ) ( -112 -64 592 0.250000 0.500000 ) ( -80 -64 592 0.250000 1 ) ) +) + } + } +// brush 88 + { + patchDef2 + { + gothic_trim/pitted_rust3 + ( 5 3 0 0 0 ) +( +( ( -32.000008 64 592 0 0 ) ( -687.999939 64 592 0 5.875000 ) ( -1344 64 592 0 11.750000 ) ) +( ( -32.000008 64 638.666687 0.364583 0 ) ( -687.999939 64 638.666687 0.364583 5.875000 ) ( -1344 64 638.666687 0.364583 11.750000 ) ) +( ( -32.000008 44 681.333374 0.732721 0 ) ( -687.999939 44 681.333374 0.732721 5.875000 ) ( -1344 44 681.333374 0.732721 11.750000 ) ) +( ( -32.000008 28 720 1.059645 0 ) ( -687.999939 28 720 1.059645 5.875000 ) ( -1344 28 720 1.059645 11.750000 ) ) +( ( -32.000008 0 744 1.347756 0 ) ( -687.999939 0 744 1.347756 5.875000 ) ( -1344 0 744 1.347756 11.750000 ) ) +) + } + } +// brush 89 +{ +( 256 -464 256 ) ( 256 -448 256 ) ( 176 -448 256 ) common/caulk 0 32 0 0.500000 0.500000 0 0 0 +( 176 -448 776 ) ( 256 -448 776 ) ( 256 -464 776 ) common/caulk 0 32 0 0.500000 0.500000 0 0 0 +( -1344 -448 1024 ) ( -1344 -464 1024 ) ( -1344 -464 320 ) common/caulk -32 0 0 0.500000 0.500000 0 0 0 +( -720 -464 1024 ) ( -640 -464 1024 ) ( -640 -464 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -496 1024 ) ( 0 -480 1024 ) ( 0 -480 320 ) common/caulk -32 0 0 0.500000 0.500000 0 0 0 +( 448 -448 1024 ) ( 368 -448 1024 ) ( 368 -448 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 90 +{ +( 256 448 256 ) ( 256 464 256 ) ( 176 464 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 176 464 776 ) ( 256 464 776 ) ( 256 448 776 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1344 464 1024 ) ( -1344 448 1024 ) ( -1344 448 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -528 448 1024 ) ( -448 448 1024 ) ( -448 448 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 416 1024 ) ( 0 432 1024 ) ( 0 432 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 256 464 1024 ) ( 176 464 1024 ) ( 176 464 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 91 +{ +( -1168 -448 256 ) ( -1168 -80 256 ) ( -1168 -80 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -1280 -448 256 ) ( -1168 -448 256 ) ( -1168 -448 224 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -1296 -80 256 ) ( -1296 -448 256 ) ( -1296 -448 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -1168 -432 224 ) ( -1280 -432 224 ) ( -1280 -432 192 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -1168 -80 256 ) ( -1168 -448 256 ) ( -1280 -448 256 ) base_trim/spidertrim 0 0 -180 0.500000 0.500000 0 0 0 +( -1280 -448 224 ) ( -1168 -448 224 ) ( -1168 -80 224 ) base_trim/spidertrim 0 0 -180 0.500000 0.500000 0 0 0 +} +// brush 92 +{ +( -1240 -480 216 ) ( -1240 -552 216 ) ( -1240 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -992 -428 216 ) ( -664 -428 216 ) ( -664 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1256 -500 216 ) ( -1256 -428 216 ) ( -1256 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -688 -432 216 ) ( -1016 -432 216 ) ( -1016 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -640 -496 224 ) ( -640 -424 224 ) ( -968 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -1248 -428 258 ) ( -1240 -428 232 ) ( -1240 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1248 -428 258 ) ( -1256 -432 232 ) ( -1256 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 93 +{ +( -1240 -428 220 ) ( -1240 -438 220 ) ( -1240 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1256 -428 220 ) ( -1240 -428 220 ) ( -1240 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1256 -438 220 ) ( -1256 -428 220 ) ( -1256 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1240 -448 220 ) ( -1256 -448 220 ) ( -1256 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1240 -438 220 ) ( -1240 -428 220 ) ( -1256 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -1256 -428 224 ) ( -1240 -428 224 ) ( -1240 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +} +// brush 94 +{ +( -1208 -480 216 ) ( -1208 -552 216 ) ( -1208 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -960 -428 216 ) ( -632 -428 216 ) ( -632 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -1224 -500 216 ) ( -1224 -428 216 ) ( -1224 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -656 -432 216 ) ( -984 -432 216 ) ( -984 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -608 -496 224 ) ( -608 -424 224 ) ( -936 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -1216 -428 258 ) ( -1208 -428 232 ) ( -1208 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1216 -428 258 ) ( -1224 -432 232 ) ( -1224 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 95 +{ +( -1208 -428 220 ) ( -1208 -438 220 ) ( -1208 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1224 -428 220 ) ( -1208 -428 220 ) ( -1208 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -1224 -438 220 ) ( -1224 -428 220 ) ( -1224 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1208 -448 220 ) ( -1224 -448 220 ) ( -1224 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -1208 -438 220 ) ( -1208 -428 220 ) ( -1224 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -1224 -428 224 ) ( -1208 -428 224 ) ( -1208 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +} +// brush 96 +{ +( -1272 -480 216 ) ( -1272 -552 216 ) ( -1272 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1024 -428 216 ) ( -696 -428 216 ) ( -696 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1288 -500 216 ) ( -1288 -428 216 ) ( -1288 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -720 -432 216 ) ( -1048 -432 216 ) ( -1048 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -672 -496 224 ) ( -672 -424 224 ) ( -1000 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -1280 -428 258 ) ( -1272 -428 232 ) ( -1272 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1280 -428 258 ) ( -1288 -432 232 ) ( -1288 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 97 +{ +( -1272 -428 220 ) ( -1272 -438 220 ) ( -1272 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1288 -428 220 ) ( -1272 -428 220 ) ( -1272 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1288 -438 220 ) ( -1288 -428 220 ) ( -1288 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1272 -448 220 ) ( -1288 -448 220 ) ( -1288 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1272 -438 220 ) ( -1272 -428 220 ) ( -1288 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -1288 -428 224 ) ( -1272 -428 224 ) ( -1272 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +} +// brush 98 +{ +( -1176 -480 216 ) ( -1176 -552 216 ) ( -1176 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -928 -428 216 ) ( -600 -428 216 ) ( -600 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1192 -500 216 ) ( -1192 -428 216 ) ( -1192 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -624 -432 216 ) ( -952 -432 216 ) ( -952 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -576 -496 224 ) ( -576 -424 224 ) ( -904 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -1184 -428 258 ) ( -1176 -428 232 ) ( -1176 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1184 -428 258 ) ( -1192 -432 232 ) ( -1192 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 99 +{ +( -1176 -428 220 ) ( -1176 -438 220 ) ( -1176 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1192 -428 220 ) ( -1176 -428 220 ) ( -1176 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1192 -438 220 ) ( -1192 -428 220 ) ( -1192 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1176 -448 220 ) ( -1192 -448 220 ) ( -1192 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1176 -438 220 ) ( -1176 -428 220 ) ( -1192 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -1192 -428 224 ) ( -1176 -428 224 ) ( -1176 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +} +// brush 100 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1264 -448 256 0 0 ) ( -1264 -440 256 0 0.125000 ) ( -1264 -432 256 0 0.250000 ) ) +( ( -1264 -448 592 5.250000 0 ) ( -1264 -440 584 5.250000 0.125000 ) ( -1264 -440 584 5.250000 0.250000 ) ) +( ( -1264 -64 592 11.250000 0 ) ( -1264 -64 584 11.250000 0.125000 ) ( -1264 -64 576 11.250000 0.250000 ) ) +) + } + } +// brush 101 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1200 -432 256 0 0 ) ( -1200 -440 256 0 0.125000 ) ( -1200 -448 256 0 0.250000 ) ) +( ( -1200 -440 584 5.126524 0 ) ( -1200 -440 584 5.126524 0.125000 ) ( -1200 -448 592 5.126524 0.250000 ) ) +( ( -1200 -64 576 11.002853 0 ) ( -1200 -64 584 11.002853 0.125000 ) ( -1200 -64 592 11.002853 0.250000 ) ) +) + } + } +// brush 102 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1200 -448 256 0 0 ) ( -1232 -448 256 0 0.500000 ) ( -1264 -448 256 0 1 ) ) +( ( -1200 -448 592 5.250000 0 ) ( -1232 -448 592 5.250000 0.500000 ) ( -1264 -448 592 5.250000 1 ) ) +( ( -1200 -64 592 11.250000 0 ) ( -1232 -64 592 11.250000 0.500000 ) ( -1264 -64 592 11.250000 1 ) ) +) + } + } +// brush 103 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -976 -448 256 0 0 ) ( -1008 -448 256 0 0.500000 ) ( -1040 -448 256 0 1 ) ) +( ( -976 -448 592 5.250000 0 ) ( -1008 -448 592 5.250000 0.500000 ) ( -1040 -448 592 5.250000 1 ) ) +( ( -976 -64 592 11.250000 0 ) ( -1008 -64 592 11.250000 0.500000 ) ( -1040 -64 592 11.250000 1 ) ) +) + } + } +// brush 104 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -976 -432 256 0 0 ) ( -976 -440 256 0 0.125000 ) ( -976 -448 256 0 0.250000 ) ) +( ( -976 -440 584 5.126524 0 ) ( -976 -440 584 5.126524 0.125000 ) ( -976 -448 592 5.126524 0.250000 ) ) +( ( -976 -64 576 11.002853 0 ) ( -976 -64 584 11.002853 0.125000 ) ( -976 -64 592 11.002853 0.250000 ) ) +) + } + } +// brush 105 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1040 -448 256 0 0 ) ( -1040 -440 256 0 0.125000 ) ( -1040 -432 256 0 0.250000 ) ) +( ( -1040 -448 592 5.250000 0 ) ( -1040 -440 584 5.250000 0.125000 ) ( -1040 -440 584 5.250000 0.250000 ) ) +( ( -1040 -64 592 11.250000 0 ) ( -1040 -64 584 11.250000 0.125000 ) ( -1040 -64 576 11.250000 0.250000 ) ) +) + } + } +// brush 106 +{ +( -968 -428 224 ) ( -952 -428 224 ) ( -952 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -952 -438 220 ) ( -952 -428 220 ) ( -968 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -952 -448 220 ) ( -968 -448 220 ) ( -968 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -968 -438 220 ) ( -968 -428 220 ) ( -968 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -968 -428 220 ) ( -952 -428 220 ) ( -952 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -952 -428 220 ) ( -952 -438 220 ) ( -952 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 107 +{ +( -960 -428 258 ) ( -968 -432 232 ) ( -968 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -960 -428 258 ) ( -952 -428 232 ) ( -952 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -352 -496 224 ) ( -352 -424 224 ) ( -680 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -400 -432 216 ) ( -728 -432 216 ) ( -728 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -968 -500 216 ) ( -968 -428 216 ) ( -968 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -704 -428 216 ) ( -376 -428 216 ) ( -376 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -952 -480 216 ) ( -952 -552 216 ) ( -952 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 108 +{ +( -1064 -428 224 ) ( -1048 -428 224 ) ( -1048 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -1048 -438 220 ) ( -1048 -428 220 ) ( -1064 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -1048 -448 220 ) ( -1064 -448 220 ) ( -1064 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -1064 -438 220 ) ( -1064 -428 220 ) ( -1064 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1064 -428 220 ) ( -1048 -428 220 ) ( -1048 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -1048 -428 220 ) ( -1048 -438 220 ) ( -1048 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 109 +{ +( -1056 -428 258 ) ( -1064 -432 232 ) ( -1064 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1056 -428 258 ) ( -1048 -428 232 ) ( -1048 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -448 -496 224 ) ( -448 -424 224 ) ( -776 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -496 -432 216 ) ( -824 -432 216 ) ( -824 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1064 -500 216 ) ( -1064 -428 216 ) ( -1064 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -800 -428 216 ) ( -472 -428 216 ) ( -472 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -1048 -480 216 ) ( -1048 -552 216 ) ( -1048 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 110 +{ +( -1000 -428 224 ) ( -984 -428 224 ) ( -984 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -984 -438 220 ) ( -984 -428 220 ) ( -1000 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -984 -448 220 ) ( -1000 -448 220 ) ( -1000 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1000 -438 220 ) ( -1000 -428 220 ) ( -1000 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1000 -428 220 ) ( -984 -428 220 ) ( -984 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -984 -428 220 ) ( -984 -438 220 ) ( -984 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 111 +{ +( -992 -428 258 ) ( -1000 -432 232 ) ( -1000 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -992 -428 258 ) ( -984 -428 232 ) ( -984 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -384 -496 224 ) ( -384 -424 224 ) ( -712 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -432 -432 216 ) ( -760 -432 216 ) ( -760 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1000 -500 216 ) ( -1000 -428 216 ) ( -1000 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -736 -428 216 ) ( -408 -428 216 ) ( -408 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -984 -480 216 ) ( -984 -552 216 ) ( -984 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 112 +{ +( -1032 -428 224 ) ( -1016 -428 224 ) ( -1016 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -1016 -438 220 ) ( -1016 -428 220 ) ( -1032 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -1016 -448 220 ) ( -1032 -448 220 ) ( -1032 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -1032 -438 220 ) ( -1032 -428 220 ) ( -1032 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1032 -428 220 ) ( -1016 -428 220 ) ( -1016 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -1016 -428 220 ) ( -1016 -438 220 ) ( -1016 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 113 +{ +( -1024 -428 258 ) ( -1032 -432 232 ) ( -1032 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1024 -428 258 ) ( -1016 -428 232 ) ( -1016 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -416 -496 224 ) ( -416 -424 224 ) ( -744 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -464 -432 216 ) ( -792 -432 216 ) ( -792 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -1032 -500 216 ) ( -1032 -428 216 ) ( -1032 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -768 -428 216 ) ( -440 -428 216 ) ( -440 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -1016 -480 216 ) ( -1016 -552 216 ) ( -1016 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 114 +{ +( -1056 -448 224 ) ( -944 -448 224 ) ( -944 -80 224 ) base_trim/spidertrim -63 0 -180 0.500000 0.500000 0 0 0 +( -944 -80 256 ) ( -944 -448 256 ) ( -1056 -448 256 ) base_trim/spidertrim -63 0 -180 0.500000 0.500000 0 0 0 +( -944 -432 224 ) ( -1056 -432 224 ) ( -1056 -432 192 ) base_trim/spidertrim -64 0 -180 0.500000 -0.500000 0 0 0 +( -1072 -80 256 ) ( -1072 -448 256 ) ( -1072 -448 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -1056 -448 256 ) ( -944 -448 256 ) ( -944 -448 224 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -944 -448 256 ) ( -944 -80 256 ) ( -944 -80 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 115 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1040 -432 256 0 0 ) ( -1008 -432 256 0 0.250000 ) ( -976 -432 256 0 0.500001 ) ) +( ( -1040 -440 584 5.000002 0 ) ( -1008 -440 584 5.000002 0.250000 ) ( -976 -440 584 5.000002 0.500001 ) ) +( ( -1040 -64 576 10.750113 0 ) ( -1008 -64 576 10.750113 0.250000 ) ( -976 -64 576 10.750113 0.500001 ) ) +) + } + } +// brush 116 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -816 -432 256 0 0 ) ( -784 -432 256 0 0.250000 ) ( -752 -432 256 0 0.500001 ) ) +( ( -816 -440 584 5.000002 0 ) ( -784 -440 584 5.000002 0.250000 ) ( -752 -440 584 5.000002 0.500001 ) ) +( ( -816 -64 576 10.750113 0 ) ( -784 -64 576 10.750113 0.250000 ) ( -752 -64 576 10.750113 0.500001 ) ) +) + } + } +// brush 117 +{ +( -832 -448 224 ) ( -720 -448 224 ) ( -720 -80 224 ) base_trim/spidertrim 0 0 -180 0.500000 0.500000 0 0 0 +( -720 -80 256 ) ( -720 -448 256 ) ( -832 -448 256 ) base_trim/spidertrim 0 0 -180 0.500000 0.500000 0 0 0 +( -720 -432 224 ) ( -832 -432 224 ) ( -832 -432 192 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -848 -80 256 ) ( -848 -448 256 ) ( -848 -448 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -832 -448 256 ) ( -720 -448 256 ) ( -720 -448 224 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -720 -448 256 ) ( -720 -80 256 ) ( -720 -80 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 118 +{ +( -800 -428 258 ) ( -808 -432 232 ) ( -808 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -800 -428 258 ) ( -792 -428 232 ) ( -792 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -192 -496 224 ) ( -192 -424 224 ) ( -520 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -240 -432 216 ) ( -568 -432 216 ) ( -568 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -808 -500 216 ) ( -808 -428 216 ) ( -808 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -544 -428 216 ) ( -216 -428 216 ) ( -216 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -792 -480 216 ) ( -792 -552 216 ) ( -792 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 119 +{ +( -808 -428 224 ) ( -792 -428 224 ) ( -792 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -792 -438 220 ) ( -792 -428 220 ) ( -808 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -792 -448 220 ) ( -808 -448 220 ) ( -808 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -808 -438 220 ) ( -808 -428 220 ) ( -808 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -808 -428 220 ) ( -792 -428 220 ) ( -792 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -792 -428 220 ) ( -792 -438 220 ) ( -792 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 120 +{ +( -768 -428 258 ) ( -776 -432 232 ) ( -776 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -768 -428 258 ) ( -760 -428 232 ) ( -760 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -160 -496 224 ) ( -160 -424 224 ) ( -488 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -208 -432 216 ) ( -536 -432 216 ) ( -536 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -776 -500 216 ) ( -776 -428 216 ) ( -776 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -512 -428 216 ) ( -184 -428 216 ) ( -184 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -760 -480 216 ) ( -760 -552 216 ) ( -760 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 121 +{ +( -776 -428 224 ) ( -760 -428 224 ) ( -760 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -760 -438 220 ) ( -760 -428 220 ) ( -776 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -760 -448 220 ) ( -776 -448 220 ) ( -776 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -776 -438 220 ) ( -776 -428 220 ) ( -776 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -776 -428 220 ) ( -760 -428 220 ) ( -760 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -760 -428 220 ) ( -760 -438 220 ) ( -760 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 122 +{ +( -832 -428 258 ) ( -840 -432 232 ) ( -840 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -832 -428 258 ) ( -824 -428 232 ) ( -824 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -224 -496 224 ) ( -224 -424 224 ) ( -552 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -272 -432 216 ) ( -600 -432 216 ) ( -600 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -840 -500 216 ) ( -840 -428 216 ) ( -840 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -576 -428 216 ) ( -248 -428 216 ) ( -248 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -824 -480 216 ) ( -824 -552 216 ) ( -824 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 123 +{ +( -840 -428 224 ) ( -824 -428 224 ) ( -824 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -824 -438 220 ) ( -824 -428 220 ) ( -840 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -824 -448 220 ) ( -840 -448 220 ) ( -840 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -840 -438 220 ) ( -840 -428 220 ) ( -840 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -840 -428 220 ) ( -824 -428 220 ) ( -824 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -824 -428 220 ) ( -824 -438 220 ) ( -824 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 124 +{ +( -736 -428 258 ) ( -744 -432 232 ) ( -744 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -736 -428 258 ) ( -728 -428 232 ) ( -728 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -128 -496 224 ) ( -128 -424 224 ) ( -456 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -176 -432 216 ) ( -504 -432 216 ) ( -504 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -744 -500 216 ) ( -744 -428 216 ) ( -744 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -480 -428 216 ) ( -152 -428 216 ) ( -152 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -728 -480 216 ) ( -728 -552 216 ) ( -728 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 125 +{ +( -744 -428 224 ) ( -728 -428 224 ) ( -728 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -728 -438 220 ) ( -728 -428 220 ) ( -744 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -728 -448 220 ) ( -744 -448 220 ) ( -744 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -744 -438 220 ) ( -744 -428 220 ) ( -744 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -744 -428 220 ) ( -728 -428 220 ) ( -728 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -728 -428 220 ) ( -728 -438 220 ) ( -728 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 126 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -816 -448 256 0 0 ) ( -816 -440 256 0 0.125000 ) ( -816 -432 256 0 0.250000 ) ) +( ( -816 -448 592 5.250000 0 ) ( -816 -440 584 5.250000 0.125000 ) ( -816 -440 584 5.250000 0.250000 ) ) +( ( -816 -64 592 11.250000 0 ) ( -816 -64 584 11.250000 0.125000 ) ( -816 -64 576 11.250000 0.250000 ) ) +) + } + } +// brush 127 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -752 -432 256 0 0 ) ( -752 -440 256 0 0.125000 ) ( -752 -448 256 0 0.250000 ) ) +( ( -752 -440 584 5.126524 0 ) ( -752 -440 584 5.126524 0.125000 ) ( -752 -448 592 5.126524 0.250000 ) ) +( ( -752 -64 576 11.002853 0 ) ( -752 -64 584 11.002853 0.125000 ) ( -752 -64 592 11.002853 0.250000 ) ) +) + } + } +// brush 128 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -752 -448 256 0 0 ) ( -784 -448 256 0 0.500000 ) ( -816 -448 256 0 1 ) ) +( ( -752 -448 592 5.250000 0 ) ( -784 -448 592 5.250000 0.500000 ) ( -816 -448 592 5.250000 1 ) ) +( ( -752 -64 592 11.250000 0 ) ( -784 -64 592 11.250000 0.500000 ) ( -816 -64 592 11.250000 1 ) ) +) + } + } +// brush 129 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -528 -448 256 0 0 ) ( -560 -448 256 0 0.500000 ) ( -592 -448 256 0 1 ) ) +( ( -528 -448 592 5.250000 0 ) ( -560 -448 592 5.250000 0.500000 ) ( -592 -448 592 5.250000 1 ) ) +( ( -528 -64 592 11.250000 0 ) ( -560 -64 592 11.250000 0.500000 ) ( -592 -64 592 11.250000 1 ) ) +) + } + } +// brush 130 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -528 -432 256 0 0 ) ( -528 -440 256 0 0.125000 ) ( -528 -448 256 0 0.250000 ) ) +( ( -528 -440 584 5.126524 0 ) ( -528 -440 584 5.126524 0.125000 ) ( -528 -448 592 5.126524 0.250000 ) ) +( ( -528 -64 576 11.002853 0 ) ( -528 -64 584 11.002853 0.125000 ) ( -528 -64 592 11.002853 0.250000 ) ) +) + } + } +// brush 131 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -592 -448 256 0 0 ) ( -592 -440 256 0 0.125000 ) ( -592 -432 256 0 0.250000 ) ) +( ( -592 -448 592 5.250000 0 ) ( -592 -440 584 5.250000 0.125000 ) ( -592 -440 584 5.250000 0.250000 ) ) +( ( -592 -64 592 11.250000 0 ) ( -592 -64 584 11.250000 0.125000 ) ( -592 -64 576 11.250000 0.250000 ) ) +) + } + } +// brush 132 +{ +( -520 -428 224 ) ( -504 -428 224 ) ( -504 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -504 -438 220 ) ( -504 -428 220 ) ( -520 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -504 -448 220 ) ( -520 -448 220 ) ( -520 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -520 -438 220 ) ( -520 -428 220 ) ( -520 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -520 -428 220 ) ( -504 -428 220 ) ( -504 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -504 -428 220 ) ( -504 -438 220 ) ( -504 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 133 +{ +( -512 -428 258 ) ( -520 -432 232 ) ( -520 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -512 -428 258 ) ( -504 -428 232 ) ( -504 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 96 -496 224 ) ( 96 -424 224 ) ( -232 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( 48 -432 216 ) ( -280 -432 216 ) ( -280 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -520 -500 216 ) ( -520 -428 216 ) ( -520 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -256 -428 216 ) ( 72 -428 216 ) ( 72 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -504 -480 216 ) ( -504 -552 216 ) ( -504 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 134 +{ +( -616 -428 224 ) ( -600 -428 224 ) ( -600 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -600 -438 220 ) ( -600 -428 220 ) ( -616 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -600 -448 220 ) ( -616 -448 220 ) ( -616 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -616 -438 220 ) ( -616 -428 220 ) ( -616 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -616 -428 220 ) ( -600 -428 220 ) ( -600 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -600 -428 220 ) ( -600 -438 220 ) ( -600 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 135 +{ +( -608 -428 258 ) ( -616 -432 232 ) ( -616 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -608 -428 258 ) ( -600 -428 232 ) ( -600 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 0 -496 224 ) ( 0 -424 224 ) ( -328 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -48 -432 216 ) ( -376 -432 216 ) ( -376 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -616 -500 216 ) ( -616 -428 216 ) ( -616 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -352 -428 216 ) ( -24 -428 216 ) ( -24 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -600 -480 216 ) ( -600 -552 216 ) ( -600 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 136 +{ +( -552 -428 224 ) ( -536 -428 224 ) ( -536 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -536 -438 220 ) ( -536 -428 220 ) ( -552 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -536 -448 220 ) ( -552 -448 220 ) ( -552 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -552 -438 220 ) ( -552 -428 220 ) ( -552 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -552 -428 220 ) ( -536 -428 220 ) ( -536 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -536 -428 220 ) ( -536 -438 220 ) ( -536 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 137 +{ +( -544 -428 258 ) ( -552 -432 232 ) ( -552 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -544 -428 258 ) ( -536 -428 232 ) ( -536 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 64 -496 224 ) ( 64 -424 224 ) ( -264 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( 16 -432 216 ) ( -312 -432 216 ) ( -312 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -552 -500 216 ) ( -552 -428 216 ) ( -552 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -288 -428 216 ) ( 40 -428 216 ) ( 40 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -536 -480 216 ) ( -536 -552 216 ) ( -536 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 138 +{ +( -584 -428 224 ) ( -568 -428 224 ) ( -568 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -568 -438 220 ) ( -568 -428 220 ) ( -584 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -568 -448 220 ) ( -584 -448 220 ) ( -584 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -584 -438 220 ) ( -584 -428 220 ) ( -584 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -584 -428 220 ) ( -568 -428 220 ) ( -568 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -568 -428 220 ) ( -568 -438 220 ) ( -568 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 139 +{ +( -576 -428 258 ) ( -584 -432 232 ) ( -584 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -576 -428 258 ) ( -568 -428 232 ) ( -568 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 32 -496 224 ) ( 32 -424 224 ) ( -296 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -16 -432 216 ) ( -344 -432 216 ) ( -344 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -584 -500 216 ) ( -584 -428 216 ) ( -584 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -320 -428 216 ) ( 8 -428 216 ) ( 8 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -568 -480 216 ) ( -568 -552 216 ) ( -568 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 140 +{ +( -608 -448 224 ) ( -496 -448 224 ) ( -496 -80 224 ) base_trim/spidertrim -63 0 -180 0.500000 0.500000 0 0 0 +( -496 -80 256 ) ( -496 -448 256 ) ( -608 -448 256 ) base_trim/spidertrim -63 0 -180 0.500000 0.500000 0 0 0 +( -496 -432 224 ) ( -608 -432 224 ) ( -608 -432 192 ) base_trim/spidertrim -64 0 -180 0.500000 -0.500000 0 0 0 +( -624 -80 256 ) ( -624 -448 256 ) ( -624 -448 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -608 -448 256 ) ( -496 -448 256 ) ( -496 -448 224 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -496 -448 256 ) ( -496 -80 256 ) ( -496 -80 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 141 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -592 -432 256 0 0 ) ( -560 -432 256 0 0.250000 ) ( -528 -432 256 0 0.500001 ) ) +( ( -592 -440 584 5.000002 0 ) ( -560 -440 584 5.000002 0.250000 ) ( -528 -440 584 5.000002 0.500001 ) ) +( ( -592 -64 576 10.750113 0 ) ( -560 -64 576 10.750113 0.250000 ) ( -528 -64 576 10.750113 0.500001 ) ) +) + } + } +// brush 142 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -368 -432 256 0 0 ) ( -336 -432 256 0 0.250000 ) ( -304 -432 256 0 0.500001 ) ) +( ( -368 -440 584 5.000002 0 ) ( -336 -440 584 5.000002 0.250000 ) ( -304 -440 584 5.000002 0.500001 ) ) +( ( -368 -64 576 10.750113 0 ) ( -336 -64 576 10.750113 0.250000 ) ( -304 -64 576 10.750113 0.500001 ) ) +) + } + } +// brush 143 +{ +( -384 -448 224 ) ( -272 -448 224 ) ( -272 -80 224 ) base_trim/spidertrim 0 0 -180 0.500000 0.500000 0 0 0 +( -272 -80 256 ) ( -272 -448 256 ) ( -384 -448 256 ) base_trim/spidertrim 0 0 -180 0.500000 0.500000 0 0 0 +( -272 -432 224 ) ( -384 -432 224 ) ( -384 -432 192 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -400 -80 256 ) ( -400 -448 256 ) ( -400 -448 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -384 -448 256 ) ( -272 -448 256 ) ( -272 -448 224 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -272 -448 256 ) ( -272 -80 256 ) ( -272 -80 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 144 +{ +( -352 -428 258 ) ( -360 -432 232 ) ( -360 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -352 -428 258 ) ( -344 -428 232 ) ( -344 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 256 -496 224 ) ( 256 -424 224 ) ( -72 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( 208 -432 216 ) ( -120 -432 216 ) ( -120 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -360 -500 216 ) ( -360 -428 216 ) ( -360 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -96 -428 216 ) ( 232 -428 216 ) ( 232 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -344 -480 216 ) ( -344 -552 216 ) ( -344 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 145 +{ +( -360 -428 224 ) ( -344 -428 224 ) ( -344 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -344 -438 220 ) ( -344 -428 220 ) ( -360 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -344 -448 220 ) ( -360 -448 220 ) ( -360 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -360 -438 220 ) ( -360 -428 220 ) ( -360 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -360 -428 220 ) ( -344 -428 220 ) ( -344 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -344 -428 220 ) ( -344 -438 220 ) ( -344 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 146 +{ +( -320 -428 258 ) ( -328 -432 232 ) ( -328 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -320 -428 258 ) ( -312 -428 232 ) ( -312 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 288 -496 224 ) ( 288 -424 224 ) ( -40 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( 240 -432 216 ) ( -88 -432 216 ) ( -88 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -328 -500 216 ) ( -328 -428 216 ) ( -328 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -64 -428 216 ) ( 264 -428 216 ) ( 264 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -312 -480 216 ) ( -312 -552 216 ) ( -312 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 147 +{ +( -328 -428 224 ) ( -312 -428 224 ) ( -312 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -312 -438 220 ) ( -312 -428 220 ) ( -328 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -312 -448 220 ) ( -328 -448 220 ) ( -328 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -328 -438 220 ) ( -328 -428 220 ) ( -328 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -328 -428 220 ) ( -312 -428 220 ) ( -312 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -312 -428 220 ) ( -312 -438 220 ) ( -312 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 148 +{ +( -384 -428 258 ) ( -392 -432 232 ) ( -392 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -384 -428 258 ) ( -376 -428 232 ) ( -376 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 224 -496 224 ) ( 224 -424 224 ) ( -104 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( 176 -432 216 ) ( -152 -432 216 ) ( -152 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -392 -500 216 ) ( -392 -428 216 ) ( -392 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -128 -428 216 ) ( 200 -428 216 ) ( 200 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -376 -480 216 ) ( -376 -552 216 ) ( -376 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 149 +{ +( -392 -428 224 ) ( -376 -428 224 ) ( -376 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -376 -438 220 ) ( -376 -428 220 ) ( -392 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -376 -448 220 ) ( -392 -448 220 ) ( -392 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -392 -438 220 ) ( -392 -428 220 ) ( -392 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -392 -428 220 ) ( -376 -428 220 ) ( -376 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -376 -428 220 ) ( -376 -438 220 ) ( -376 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 150 +{ +( -288 -428 258 ) ( -296 -432 232 ) ( -296 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -288 -428 258 ) ( -280 -428 232 ) ( -280 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 320 -496 224 ) ( 320 -424 224 ) ( -8 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( 272 -432 216 ) ( -56 -432 216 ) ( -56 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -296 -500 216 ) ( -296 -428 216 ) ( -296 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -32 -428 216 ) ( 296 -428 216 ) ( 296 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -280 -480 216 ) ( -280 -552 216 ) ( -280 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 151 +{ +( -296 -428 224 ) ( -280 -428 224 ) ( -280 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -280 -438 220 ) ( -280 -428 220 ) ( -296 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -280 -448 220 ) ( -296 -448 220 ) ( -296 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -296 -438 220 ) ( -296 -428 220 ) ( -296 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -296 -428 220 ) ( -280 -428 220 ) ( -280 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -280 -428 220 ) ( -280 -438 220 ) ( -280 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 152 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -368 -448 256 0 0 ) ( -368 -440 256 0 0.125000 ) ( -368 -432 256 0 0.250000 ) ) +( ( -368 -448 592 5.250000 0 ) ( -368 -440 584 5.250000 0.125000 ) ( -368 -440 584 5.250000 0.250000 ) ) +( ( -368 -64 592 11.250000 0 ) ( -368 -64 584 11.250000 0.125000 ) ( -368 -64 576 11.250000 0.250000 ) ) +) + } + } +// brush 153 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -304 -432 256 0 0 ) ( -304 -440 256 0 0.125000 ) ( -304 -448 256 0 0.250000 ) ) +( ( -304 -440 584 5.126524 0 ) ( -304 -440 584 5.126524 0.125000 ) ( -304 -448 592 5.126524 0.250000 ) ) +( ( -304 -64 576 11.002853 0 ) ( -304 -64 584 11.002853 0.125000 ) ( -304 -64 592 11.002853 0.250000 ) ) +) + } + } +// brush 154 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -304 -448 256 0 0 ) ( -336 -448 256 0 0.500000 ) ( -368 -448 256 0 1 ) ) +( ( -304 -448 592 5.250000 0 ) ( -336 -448 592 5.250000 0.500000 ) ( -368 -448 592 5.250000 1 ) ) +( ( -304 -64 592 11.250000 0 ) ( -336 -64 592 11.250000 0.500000 ) ( -368 -64 592 11.250000 1 ) ) +) + } + } +// brush 155 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -80 -448 256 0 0 ) ( -112 -448 256 0 0.500000 ) ( -144 -448 256 0 1 ) ) +( ( -80 -448 592 5.250000 0 ) ( -112 -448 592 5.250000 0.500000 ) ( -144 -448 592 5.250000 1 ) ) +( ( -80 -64 592 11.250000 0 ) ( -112 -64 592 11.250000 0.500000 ) ( -144 -64 592 11.250000 1 ) ) +) + } + } +// brush 156 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -80 -432 256 0 0 ) ( -80 -440 256 0 0.125000 ) ( -80 -448 256 0 0.250000 ) ) +( ( -80 -440 584 5.126524 0 ) ( -80 -440 584 5.126524 0.125000 ) ( -80 -448 592 5.126524 0.250000 ) ) +( ( -80 -64 576 11.002853 0 ) ( -80 -64 584 11.002853 0.125000 ) ( -80 -64 592 11.002853 0.250000 ) ) +) + } + } +// brush 157 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -144 -448 256 0 0 ) ( -144 -440 256 0 0.125000 ) ( -144 -432 256 0 0.250000 ) ) +( ( -144 -448 592 5.250000 0 ) ( -144 -440 584 5.250000 0.125000 ) ( -144 -440 584 5.250000 0.250000 ) ) +( ( -144 -64 592 11.250000 0 ) ( -144 -64 584 11.250000 0.125000 ) ( -144 -64 576 11.250000 0.250000 ) ) +) + } + } +// brush 158 +{ +( -72 -428 224 ) ( -56 -428 224 ) ( -56 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -56 -438 220 ) ( -56 -428 220 ) ( -72 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -56 -448 220 ) ( -72 -448 220 ) ( -72 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -72 -438 220 ) ( -72 -428 220 ) ( -72 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -72 -428 220 ) ( -56 -428 220 ) ( -56 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -56 -428 220 ) ( -56 -438 220 ) ( -56 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 159 +{ +( -64 -428 258 ) ( -72 -432 232 ) ( -72 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -64 -428 258 ) ( -56 -428 232 ) ( -56 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 544 -496 224 ) ( 544 -424 224 ) ( 216 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( 496 -432 216 ) ( 168 -432 216 ) ( 168 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -72 -500 216 ) ( -72 -428 216 ) ( -72 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 192 -428 216 ) ( 520 -428 216 ) ( 520 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -56 -480 216 ) ( -56 -552 216 ) ( -56 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 160 +{ +( -168 -428 224 ) ( -152 -428 224 ) ( -152 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -152 -438 220 ) ( -152 -428 220 ) ( -168 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -152 -448 220 ) ( -168 -448 220 ) ( -168 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -168 -438 220 ) ( -168 -428 220 ) ( -168 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -168 -428 220 ) ( -152 -428 220 ) ( -152 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -152 -428 220 ) ( -152 -438 220 ) ( -152 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 161 +{ +( -160 -428 258 ) ( -168 -432 232 ) ( -168 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -160 -428 258 ) ( -152 -428 232 ) ( -152 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 448 -496 224 ) ( 448 -424 224 ) ( 120 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( 400 -432 216 ) ( 72 -432 216 ) ( 72 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -168 -500 216 ) ( -168 -428 216 ) ( -168 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 96 -428 216 ) ( 424 -428 216 ) ( 424 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -152 -480 216 ) ( -152 -552 216 ) ( -152 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 162 +{ +( -104 -428 224 ) ( -88 -428 224 ) ( -88 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -88 -438 220 ) ( -88 -428 220 ) ( -104 -428 220 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( -88 -448 220 ) ( -104 -448 220 ) ( -104 -448 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -104 -438 220 ) ( -104 -428 220 ) ( -104 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -104 -428 220 ) ( -88 -428 220 ) ( -88 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -88 -428 220 ) ( -88 -438 220 ) ( -88 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 163 +{ +( -96 -428 258 ) ( -104 -432 232 ) ( -104 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -96 -428 258 ) ( -88 -428 232 ) ( -88 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 512 -496 224 ) ( 512 -424 224 ) ( 184 -424 224 ) base_trim/pewter 0 0 -180 0.500000 0.500000 134217728 0 0 +( 464 -432 216 ) ( 136 -432 216 ) ( 136 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -104 -500 216 ) ( -104 -428 216 ) ( -104 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 160 -428 216 ) ( 488 -428 216 ) ( 488 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -88 -480 216 ) ( -88 -552 216 ) ( -88 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 164 +{ +( -136 -428 224 ) ( -120 -428 224 ) ( -120 -438 224 ) common/caulk 0 0 -180 0.500000 0.500000 134217728 0 0 +( -120 -438 220 ) ( -120 -428 220 ) ( -136 -428 220 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( -120 -448 220 ) ( -136 -448 220 ) ( -136 -448 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -136 -438 220 ) ( -136 -428 220 ) ( -136 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -136 -428 220 ) ( -120 -428 220 ) ( -120 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -120 -428 220 ) ( -120 -438 220 ) ( -120 -438 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 165 +{ +( -128 -428 258 ) ( -136 -432 232 ) ( -136 -428 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -128 -428 258 ) ( -120 -428 232 ) ( -120 -432 232 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 480 -496 224 ) ( 480 -424 224 ) ( 152 -424 224 ) base_trim/pewter -63 0 -180 0.500000 0.500000 134217728 0 0 +( 432 -432 216 ) ( 104 -432 216 ) ( 104 -432 224 ) common/caulk 0 0 -180 0.500000 -0.500000 134217728 0 0 +( -136 -500 216 ) ( -136 -428 216 ) ( -136 -428 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +( 128 -428 216 ) ( 456 -428 216 ) ( 456 -428 224 ) base_trim/pewter -64 0 -180 0.500000 -0.500000 134217728 0 0 +( -120 -480 216 ) ( -120 -552 216 ) ( -120 -552 224 ) base_trim/pewter 0 0 -180 0.500000 -0.500000 134217728 0 0 +} +// brush 166 +{ +( -160 -448 224 ) ( -48 -448 224 ) ( -48 -80 224 ) base_trim/spidertrim -63 0 -180 0.500000 0.500000 0 0 0 +( -48 -80 256 ) ( -48 -448 256 ) ( -160 -448 256 ) base_trim/spidertrim -63 0 -180 0.500000 0.500000 0 0 0 +( -48 -432 224 ) ( -160 -432 224 ) ( -160 -432 192 ) base_trim/spidertrim -64 0 -180 0.500000 -0.500000 0 0 0 +( -176 -80 256 ) ( -176 -448 256 ) ( -176 -448 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +( -160 -448 256 ) ( -48 -448 256 ) ( -48 -448 224 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -48 -448 256 ) ( -48 -80 256 ) ( -48 -80 224 ) base_trim/spidertrim 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 167 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -144 -432 256 0 0 ) ( -112 -432 256 0 0.250000 ) ( -80 -432 256 0 0.500001 ) ) +( ( -144 -440 584 5.000002 0 ) ( -112 -440 584 5.000002 0.250000 ) ( -80 -440 584 5.000002 0.500001 ) ) +( ( -144 -64 576 10.750113 0 ) ( -112 -64 576 10.750113 0.250000 ) ( -80 -64 576 10.750113 0.500001 ) ) +) + } + } +// brush 168 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1200 432 256 0 0 ) ( -1232 432 256 0 0.250000 ) ( -1264 432 256 0 0.500001 ) ) +( ( -1200 440 584 5.000002 0 ) ( -1232 440 584 5.000002 0.250000 ) ( -1264 440 584 5.000002 0.500001 ) ) +( ( -1200 64 576 10.750113 0 ) ( -1232 64 576 10.750113 0.250000 ) ( -1264 64 576 10.750113 0.500001 ) ) +) + } + } +// brush 169 +{ +( -1184 448 224 ) ( -1296 448 224 ) ( -1296 80 224 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -1296 80 256 ) ( -1296 448 256 ) ( -1184 448 256 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -1296 432 224 ) ( -1184 432 224 ) ( -1184 432 192 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -1168 80 256 ) ( -1168 448 256 ) ( -1168 448 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1184 448 256 ) ( -1296 448 256 ) ( -1296 448 224 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1296 448 256 ) ( -1296 80 256 ) ( -1296 80 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 170 +{ +( -1216 428 258 ) ( -1208 432 232 ) ( -1208 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1216 428 258 ) ( -1224 428 232 ) ( -1224 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1824 496 224 ) ( -1824 424 224 ) ( -1496 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1776 432 216 ) ( -1448 432 216 ) ( -1448 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1208 500 216 ) ( -1208 428 216 ) ( -1208 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1472 428 216 ) ( -1800 428 216 ) ( -1800 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1224 480 216 ) ( -1224 552 216 ) ( -1224 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 171 +{ +( -1208 428 224 ) ( -1224 428 224 ) ( -1224 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1224 438 220 ) ( -1224 428 220 ) ( -1208 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1224 448 220 ) ( -1208 448 220 ) ( -1208 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1208 438 220 ) ( -1208 428 220 ) ( -1208 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1208 428 220 ) ( -1224 428 220 ) ( -1224 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1224 428 220 ) ( -1224 438 220 ) ( -1224 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 172 +{ +( -1248 428 258 ) ( -1240 432 232 ) ( -1240 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1248 428 258 ) ( -1256 428 232 ) ( -1256 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1856 496 224 ) ( -1856 424 224 ) ( -1528 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1808 432 216 ) ( -1480 432 216 ) ( -1480 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1240 500 216 ) ( -1240 428 216 ) ( -1240 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1504 428 216 ) ( -1832 428 216 ) ( -1832 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1256 480 216 ) ( -1256 552 216 ) ( -1256 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 173 +{ +( -1240 428 224 ) ( -1256 428 224 ) ( -1256 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1256 438 220 ) ( -1256 428 220 ) ( -1240 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1256 448 220 ) ( -1240 448 220 ) ( -1240 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1240 438 220 ) ( -1240 428 220 ) ( -1240 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1240 428 220 ) ( -1256 428 220 ) ( -1256 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1256 428 220 ) ( -1256 438 220 ) ( -1256 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 174 +{ +( -1184 428 258 ) ( -1176 432 232 ) ( -1176 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1184 428 258 ) ( -1192 428 232 ) ( -1192 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1792 496 224 ) ( -1792 424 224 ) ( -1464 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1744 432 216 ) ( -1416 432 216 ) ( -1416 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1176 500 216 ) ( -1176 428 216 ) ( -1176 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1440 428 216 ) ( -1768 428 216 ) ( -1768 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1192 480 216 ) ( -1192 552 216 ) ( -1192 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 175 +{ +( -1176 428 224 ) ( -1192 428 224 ) ( -1192 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1192 438 220 ) ( -1192 428 220 ) ( -1176 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1192 448 220 ) ( -1176 448 220 ) ( -1176 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1176 438 220 ) ( -1176 428 220 ) ( -1176 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1176 428 220 ) ( -1192 428 220 ) ( -1192 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1192 428 220 ) ( -1192 438 220 ) ( -1192 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 176 +{ +( -1280 428 258 ) ( -1272 432 232 ) ( -1272 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1280 428 258 ) ( -1288 428 232 ) ( -1288 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1888 496 224 ) ( -1888 424 224 ) ( -1560 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1840 432 216 ) ( -1512 432 216 ) ( -1512 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1272 500 216 ) ( -1272 428 216 ) ( -1272 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1536 428 216 ) ( -1864 428 216 ) ( -1864 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1288 480 216 ) ( -1288 552 216 ) ( -1288 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 177 +{ +( -1272 428 224 ) ( -1288 428 224 ) ( -1288 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1288 438 220 ) ( -1288 428 220 ) ( -1272 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1288 448 220 ) ( -1272 448 220 ) ( -1272 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1272 438 220 ) ( -1272 428 220 ) ( -1272 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1272 428 220 ) ( -1288 428 220 ) ( -1288 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1288 428 220 ) ( -1288 438 220 ) ( -1288 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 178 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1200 448 256 0 0 ) ( -1200 440 256 0 0.125000 ) ( -1200 432 256 0 0.250000 ) ) +( ( -1200 448 592 5.250000 0 ) ( -1200 440 584 5.250000 0.125000 ) ( -1200 440 584 5.250000 0.250000 ) ) +( ( -1200 64 592 11.250000 0 ) ( -1200 64 584 11.250000 0.125000 ) ( -1200 64 576 11.250000 0.250000 ) ) +) + } + } +// brush 179 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1264 432 256 0 0 ) ( -1264 440 256 0 0.125000 ) ( -1264 448 256 0 0.250000 ) ) +( ( -1264 440 584 5.126524 0 ) ( -1264 440 584 5.126524 0.125000 ) ( -1264 448 592 5.126524 0.250000 ) ) +( ( -1264 64 576 11.002853 0 ) ( -1264 64 584 11.002853 0.125000 ) ( -1264 64 592 11.002853 0.250000 ) ) +) + } + } +// brush 180 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1264 448 256 0 0 ) ( -1232 448 256 0 0.500000 ) ( -1200 448 256 0 1 ) ) +( ( -1264 448 592 5.250000 0 ) ( -1232 448 592 5.250000 0.500000 ) ( -1200 448 592 5.250000 1 ) ) +( ( -1264 64 592 11.250000 0 ) ( -1232 64 592 11.250000 0.500000 ) ( -1200 64 592 11.250000 1 ) ) +) + } + } +// brush 181 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1040 448 256 0 0 ) ( -1008 448 256 0 0.500000 ) ( -976 448 256 0 1 ) ) +( ( -1040 448 592 5.250000 0 ) ( -1008 448 592 5.250000 0.500000 ) ( -976 448 592 5.250000 1 ) ) +( ( -1040 64 592 11.250000 0 ) ( -1008 64 592 11.250000 0.500000 ) ( -976 64 592 11.250000 1 ) ) +) + } + } +// brush 182 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1040 432 256 0 0 ) ( -1040 440 256 0 0.125000 ) ( -1040 448 256 0 0.250000 ) ) +( ( -1040 440 584 5.126524 0 ) ( -1040 440 584 5.126524 0.125000 ) ( -1040 448 592 5.126524 0.250000 ) ) +( ( -1040 64 576 11.002853 0 ) ( -1040 64 584 11.002853 0.125000 ) ( -1040 64 592 11.002853 0.250000 ) ) +) + } + } +// brush 183 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -976 448 256 0 0 ) ( -976 440 256 0 0.125000 ) ( -976 432 256 0 0.250000 ) ) +( ( -976 448 592 5.250000 0 ) ( -976 440 584 5.250000 0.125000 ) ( -976 440 584 5.250000 0.250000 ) ) +( ( -976 64 592 11.250000 0 ) ( -976 64 584 11.250000 0.125000 ) ( -976 64 576 11.250000 0.250000 ) ) +) + } + } +// brush 184 +{ +( -1048 428 224 ) ( -1064 428 224 ) ( -1064 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1064 438 220 ) ( -1064 428 220 ) ( -1048 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1064 448 220 ) ( -1048 448 220 ) ( -1048 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1048 438 220 ) ( -1048 428 220 ) ( -1048 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1048 428 220 ) ( -1064 428 220 ) ( -1064 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1064 428 220 ) ( -1064 438 220 ) ( -1064 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 185 +{ +( -1056 428 258 ) ( -1048 432 232 ) ( -1048 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1056 428 258 ) ( -1064 428 232 ) ( -1064 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1664 496 224 ) ( -1664 424 224 ) ( -1336 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1616 432 216 ) ( -1288 432 216 ) ( -1288 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1048 500 216 ) ( -1048 428 216 ) ( -1048 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1312 428 216 ) ( -1640 428 216 ) ( -1640 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1064 480 216 ) ( -1064 552 216 ) ( -1064 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 186 +{ +( -952 428 224 ) ( -968 428 224 ) ( -968 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -968 438 220 ) ( -968 428 220 ) ( -952 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -968 448 220 ) ( -952 448 220 ) ( -952 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -952 438 220 ) ( -952 428 220 ) ( -952 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -952 428 220 ) ( -968 428 220 ) ( -968 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -968 428 220 ) ( -968 438 220 ) ( -968 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 187 +{ +( -960 428 258 ) ( -952 432 232 ) ( -952 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -960 428 258 ) ( -968 428 232 ) ( -968 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1568 496 224 ) ( -1568 424 224 ) ( -1240 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1520 432 216 ) ( -1192 432 216 ) ( -1192 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -952 500 216 ) ( -952 428 216 ) ( -952 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1216 428 216 ) ( -1544 428 216 ) ( -1544 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -968 480 216 ) ( -968 552 216 ) ( -968 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 188 +{ +( -1016 428 224 ) ( -1032 428 224 ) ( -1032 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1032 438 220 ) ( -1032 428 220 ) ( -1016 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1032 448 220 ) ( -1016 448 220 ) ( -1016 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1016 438 220 ) ( -1016 428 220 ) ( -1016 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1016 428 220 ) ( -1032 428 220 ) ( -1032 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1032 428 220 ) ( -1032 438 220 ) ( -1032 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 189 +{ +( -1024 428 258 ) ( -1016 432 232 ) ( -1016 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1024 428 258 ) ( -1032 428 232 ) ( -1032 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1632 496 224 ) ( -1632 424 224 ) ( -1304 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1584 432 216 ) ( -1256 432 216 ) ( -1256 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1016 500 216 ) ( -1016 428 216 ) ( -1016 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1280 428 216 ) ( -1608 428 216 ) ( -1608 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1032 480 216 ) ( -1032 552 216 ) ( -1032 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 190 +{ +( -984 428 224 ) ( -1000 428 224 ) ( -1000 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -1000 438 220 ) ( -1000 428 220 ) ( -984 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1000 448 220 ) ( -984 448 220 ) ( -984 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -984 438 220 ) ( -984 428 220 ) ( -984 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -984 428 220 ) ( -1000 428 220 ) ( -1000 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1000 428 220 ) ( -1000 438 220 ) ( -1000 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 191 +{ +( -992 428 258 ) ( -984 432 232 ) ( -984 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -992 428 258 ) ( -1000 428 232 ) ( -1000 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1600 496 224 ) ( -1600 424 224 ) ( -1272 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1552 432 216 ) ( -1224 432 216 ) ( -1224 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -984 500 216 ) ( -984 428 216 ) ( -984 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1248 428 216 ) ( -1576 428 216 ) ( -1576 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1000 480 216 ) ( -1000 552 216 ) ( -1000 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 192 +{ +( -960 448 224 ) ( -1072 448 224 ) ( -1072 80 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1072 80 256 ) ( -1072 448 256 ) ( -960 448 256 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -1072 432 224 ) ( -960 432 224 ) ( -960 432 192 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -944 80 256 ) ( -944 448 256 ) ( -944 448 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -960 448 256 ) ( -1072 448 256 ) ( -1072 448 224 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1072 448 256 ) ( -1072 80 256 ) ( -1072 80 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 193 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -976 432 256 0 0 ) ( -1008 432 256 0 0.250000 ) ( -1040 432 256 0 0.500001 ) ) +( ( -976 440 584 5.000002 0 ) ( -1008 440 584 5.000002 0.250000 ) ( -1040 440 584 5.000002 0.500001 ) ) +( ( -976 64 576 10.750113 0 ) ( -1008 64 576 10.750113 0.250000 ) ( -1040 64 576 10.750113 0.500001 ) ) +) + } + } +// brush 194 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -752 432 256 0 0 ) ( -784 432 256 0 0.250000 ) ( -816 432 256 0 0.500001 ) ) +( ( -752 440 584 5.000002 0 ) ( -784 440 584 5.000002 0.250000 ) ( -816 440 584 5.000002 0.500001 ) ) +( ( -752 64 576 10.750113 0 ) ( -784 64 576 10.750113 0.250000 ) ( -816 64 576 10.750113 0.500001 ) ) +) + } + } +// brush 195 +{ +( -736 448 224 ) ( -848 448 224 ) ( -848 80 224 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -848 80 256 ) ( -848 448 256 ) ( -736 448 256 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -848 432 224 ) ( -736 432 224 ) ( -736 432 192 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -720 80 256 ) ( -720 448 256 ) ( -720 448 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -736 448 256 ) ( -848 448 256 ) ( -848 448 224 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -848 448 256 ) ( -848 80 256 ) ( -848 80 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 196 +{ +( -768 428 258 ) ( -760 432 232 ) ( -760 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -768 428 258 ) ( -776 428 232 ) ( -776 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1376 496 224 ) ( -1376 424 224 ) ( -1048 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1328 432 216 ) ( -1000 432 216 ) ( -1000 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -760 500 216 ) ( -760 428 216 ) ( -760 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1024 428 216 ) ( -1352 428 216 ) ( -1352 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -776 480 216 ) ( -776 552 216 ) ( -776 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 197 +{ +( -760 428 224 ) ( -776 428 224 ) ( -776 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -776 438 220 ) ( -776 428 220 ) ( -760 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -776 448 220 ) ( -760 448 220 ) ( -760 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -760 438 220 ) ( -760 428 220 ) ( -760 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -760 428 220 ) ( -776 428 220 ) ( -776 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -776 428 220 ) ( -776 438 220 ) ( -776 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 198 +{ +( -800 428 258 ) ( -792 432 232 ) ( -792 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -800 428 258 ) ( -808 428 232 ) ( -808 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1408 496 224 ) ( -1408 424 224 ) ( -1080 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1360 432 216 ) ( -1032 432 216 ) ( -1032 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -792 500 216 ) ( -792 428 216 ) ( -792 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1056 428 216 ) ( -1384 428 216 ) ( -1384 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -808 480 216 ) ( -808 552 216 ) ( -808 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 199 +{ +( -792 428 224 ) ( -808 428 224 ) ( -808 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -808 438 220 ) ( -808 428 220 ) ( -792 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -808 448 220 ) ( -792 448 220 ) ( -792 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -792 438 220 ) ( -792 428 220 ) ( -792 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -792 428 220 ) ( -808 428 220 ) ( -808 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -808 428 220 ) ( -808 438 220 ) ( -808 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 200 +{ +( -736 428 258 ) ( -728 432 232 ) ( -728 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -736 428 258 ) ( -744 428 232 ) ( -744 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1344 496 224 ) ( -1344 424 224 ) ( -1016 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1296 432 216 ) ( -968 432 216 ) ( -968 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -728 500 216 ) ( -728 428 216 ) ( -728 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -992 428 216 ) ( -1320 428 216 ) ( -1320 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -744 480 216 ) ( -744 552 216 ) ( -744 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 201 +{ +( -728 428 224 ) ( -744 428 224 ) ( -744 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -744 438 220 ) ( -744 428 220 ) ( -728 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -744 448 220 ) ( -728 448 220 ) ( -728 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -728 438 220 ) ( -728 428 220 ) ( -728 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -728 428 220 ) ( -744 428 220 ) ( -744 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -744 428 220 ) ( -744 438 220 ) ( -744 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 202 +{ +( -832 428 258 ) ( -824 432 232 ) ( -824 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -832 428 258 ) ( -840 428 232 ) ( -840 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1440 496 224 ) ( -1440 424 224 ) ( -1112 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1392 432 216 ) ( -1064 432 216 ) ( -1064 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -824 500 216 ) ( -824 428 216 ) ( -824 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1088 428 216 ) ( -1416 428 216 ) ( -1416 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -840 480 216 ) ( -840 552 216 ) ( -840 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 203 +{ +( -824 428 224 ) ( -840 428 224 ) ( -840 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -840 438 220 ) ( -840 428 220 ) ( -824 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -840 448 220 ) ( -824 448 220 ) ( -824 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -824 438 220 ) ( -824 428 220 ) ( -824 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -824 428 220 ) ( -840 428 220 ) ( -840 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -840 428 220 ) ( -840 438 220 ) ( -840 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 204 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -752 448 256 0 0 ) ( -752 440 256 0 0.125000 ) ( -752 432 256 0 0.250000 ) ) +( ( -752 448 592 5.250000 0 ) ( -752 440 584 5.250000 0.125000 ) ( -752 440 584 5.250000 0.250000 ) ) +( ( -752 64 592 11.250000 0 ) ( -752 64 584 11.250000 0.125000 ) ( -752 64 576 11.250000 0.250000 ) ) +) + } + } +// brush 205 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -816 432 256 0 0 ) ( -816 440 256 0 0.125000 ) ( -816 448 256 0 0.250000 ) ) +( ( -816 440 584 5.126524 0 ) ( -816 440 584 5.126524 0.125000 ) ( -816 448 592 5.126524 0.250000 ) ) +( ( -816 64 576 11.002853 0 ) ( -816 64 584 11.002853 0.125000 ) ( -816 64 592 11.002853 0.250000 ) ) +) + } + } +// brush 206 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -816 448 256 0 0 ) ( -784 448 256 0 0.500000 ) ( -752 448 256 0 1 ) ) +( ( -816 448 592 5.250000 0 ) ( -784 448 592 5.250000 0.500000 ) ( -752 448 592 5.250000 1 ) ) +( ( -816 64 592 11.250000 0 ) ( -784 64 592 11.250000 0.500000 ) ( -752 64 592 11.250000 1 ) ) +) + } + } +// brush 207 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -592 448 256 0 0 ) ( -560 448 256 0 0.500000 ) ( -528 448 256 0 1 ) ) +( ( -592 448 592 5.250000 0 ) ( -560 448 592 5.250000 0.500000 ) ( -528 448 592 5.250000 1 ) ) +( ( -592 64 592 11.250000 0 ) ( -560 64 592 11.250000 0.500000 ) ( -528 64 592 11.250000 1 ) ) +) + } + } +// brush 208 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -592 432 256 0 0 ) ( -592 440 256 0 0.125000 ) ( -592 448 256 0 0.250000 ) ) +( ( -592 440 584 5.126524 0 ) ( -592 440 584 5.126524 0.125000 ) ( -592 448 592 5.126524 0.250000 ) ) +( ( -592 64 576 11.002853 0 ) ( -592 64 584 11.002853 0.125000 ) ( -592 64 592 11.002853 0.250000 ) ) +) + } + } +// brush 209 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -528 448 256 0 0 ) ( -528 440 256 0 0.125000 ) ( -528 432 256 0 0.250000 ) ) +( ( -528 448 592 5.250000 0 ) ( -528 440 584 5.250000 0.125000 ) ( -528 440 584 5.250000 0.250000 ) ) +( ( -528 64 592 11.250000 0 ) ( -528 64 584 11.250000 0.125000 ) ( -528 64 576 11.250000 0.250000 ) ) +) + } + } +// brush 210 +{ +( -600 428 224 ) ( -616 428 224 ) ( -616 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -616 438 220 ) ( -616 428 220 ) ( -600 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -616 448 220 ) ( -600 448 220 ) ( -600 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -600 438 220 ) ( -600 428 220 ) ( -600 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -600 428 220 ) ( -616 428 220 ) ( -616 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -616 428 220 ) ( -616 438 220 ) ( -616 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 211 +{ +( -608 428 258 ) ( -600 432 232 ) ( -600 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -608 428 258 ) ( -616 428 232 ) ( -616 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1216 496 224 ) ( -1216 424 224 ) ( -888 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1168 432 216 ) ( -840 432 216 ) ( -840 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -600 500 216 ) ( -600 428 216 ) ( -600 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -864 428 216 ) ( -1192 428 216 ) ( -1192 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -616 480 216 ) ( -616 552 216 ) ( -616 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 212 +{ +( -504 428 224 ) ( -520 428 224 ) ( -520 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -520 438 220 ) ( -520 428 220 ) ( -504 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -520 448 220 ) ( -504 448 220 ) ( -504 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -504 438 220 ) ( -504 428 220 ) ( -504 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -504 428 220 ) ( -520 428 220 ) ( -520 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -520 428 220 ) ( -520 438 220 ) ( -520 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 213 +{ +( -512 428 258 ) ( -504 432 232 ) ( -504 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -512 428 258 ) ( -520 428 232 ) ( -520 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1120 496 224 ) ( -1120 424 224 ) ( -792 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1072 432 216 ) ( -744 432 216 ) ( -744 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -504 500 216 ) ( -504 428 216 ) ( -504 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -768 428 216 ) ( -1096 428 216 ) ( -1096 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -520 480 216 ) ( -520 552 216 ) ( -520 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 214 +{ +( -568 428 224 ) ( -584 428 224 ) ( -584 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -584 438 220 ) ( -584 428 220 ) ( -568 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -584 448 220 ) ( -568 448 220 ) ( -568 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -568 438 220 ) ( -568 428 220 ) ( -568 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -568 428 220 ) ( -584 428 220 ) ( -584 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -584 428 220 ) ( -584 438 220 ) ( -584 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 215 +{ +( -576 428 258 ) ( -568 432 232 ) ( -568 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -576 428 258 ) ( -584 428 232 ) ( -584 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1184 496 224 ) ( -1184 424 224 ) ( -856 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -1136 432 216 ) ( -808 432 216 ) ( -808 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -568 500 216 ) ( -568 428 216 ) ( -568 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -832 428 216 ) ( -1160 428 216 ) ( -1160 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -584 480 216 ) ( -584 552 216 ) ( -584 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 216 +{ +( -536 428 224 ) ( -552 428 224 ) ( -552 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -552 438 220 ) ( -552 428 220 ) ( -536 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -552 448 220 ) ( -536 448 220 ) ( -536 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -536 438 220 ) ( -536 428 220 ) ( -536 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -536 428 220 ) ( -552 428 220 ) ( -552 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -552 428 220 ) ( -552 438 220 ) ( -552 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 217 +{ +( -544 428 258 ) ( -536 432 232 ) ( -536 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -544 428 258 ) ( -552 428 232 ) ( -552 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1152 496 224 ) ( -1152 424 224 ) ( -824 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -1104 432 216 ) ( -776 432 216 ) ( -776 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -536 500 216 ) ( -536 428 216 ) ( -536 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -800 428 216 ) ( -1128 428 216 ) ( -1128 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -552 480 216 ) ( -552 552 216 ) ( -552 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 218 +{ +( -512 448 224 ) ( -624 448 224 ) ( -624 80 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -624 80 256 ) ( -624 448 256 ) ( -512 448 256 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -624 432 224 ) ( -512 432 224 ) ( -512 432 192 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -496 80 256 ) ( -496 448 256 ) ( -496 448 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -512 448 256 ) ( -624 448 256 ) ( -624 448 224 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -624 448 256 ) ( -624 80 256 ) ( -624 80 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 219 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -528 432 256 0 0 ) ( -560 432 256 0 0.250000 ) ( -592 432 256 0 0.500001 ) ) +( ( -528 440 584 5.000002 0 ) ( -560 440 584 5.000002 0.250000 ) ( -592 440 584 5.000002 0.500001 ) ) +( ( -528 64 576 10.750113 0 ) ( -560 64 576 10.750113 0.250000 ) ( -592 64 576 10.750113 0.500001 ) ) +) + } + } +// brush 220 +{ +( -1376 480 784 ) ( -1376 -472 784 ) ( -1376 -472 8 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 480 784 ) ( -672 480 784 ) ( -672 480 8 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 -472 784 ) ( 24 480 784 ) ( 24 480 8 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -672 -480 784 ) ( 24 -480 784 ) ( 24 -480 8 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -672 -472 784 ) ( -672 480 784 ) ( 24 480 784 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 480 776 ) ( -672 480 776 ) ( -672 -472 776 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 221 +{ +( -896 -464 768 ) ( -816 -464 768 ) ( -816 -464 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1344 -416 768 ) ( -1344 -432 768 ) ( -1344 -432 64 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -1520 -448 768 ) ( -1600 -448 768 ) ( -1600 -448 64 ) gothic_block/killblock -128 0 0 0.500000 0.500000 0 0 0 +( 0 -464 768 ) ( 0 -448 768 ) ( 0 -448 64 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -816 -464 256 ) ( -896 -464 256 ) ( -896 -448 256 ) common/caulk 0 -63 -90 0.500000 0.500000 0 0 0 +( -896 -448 0 ) ( -896 -464 0 ) ( -816 -464 0 ) common/caulk 0 -63 -90 0.500000 0.500000 0 0 0 +} +// brush 222 +{ +( -1344 448 0 ) ( -1344 -448 0 ) ( -1344 -448 -144 ) gothic_trim/pitted_rust 0 0 0 0.500000 0.500000 0 0 0 +( -688 448 0 ) ( -1344 448 0 ) ( -1344 448 -144 ) gothic_trim/pitted_rust 0 0 0 0.500000 0.500000 0 0 0 +( 16 -448 0 ) ( 16 448 0 ) ( 16 448 -144 ) gothic_trim/pitted_rust 0 0 0 0.500000 0.500000 0 0 0 +( -1344 -448 0 ) ( -688 -448 0 ) ( -688 -448 -144 ) gothic_trim/pitted_rust 0 0 0 0.500000 0.500000 0 0 0 +( -640 -448 0 ) ( -640 448 0 ) ( 16 448 0 ) gothic_trim/pitted_rust 0 0 0 0.500000 0.500000 0 0 0 +( 16 448 -16 ) ( -640 448 -16 ) ( -640 -448 -16 ) gothic_trim/pitted_rust 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 223 +{ +( 256 448 0 ) ( 256 464 0 ) ( 176 464 0 ) common/caulk 0 0 90 0.500000 0.500000 0 0 0 +( 176 464 256 ) ( 256 464 256 ) ( 256 448 256 ) common/caulk 0 0 90 0.500000 0.500000 0 0 0 +( -1344 464 768 ) ( -1344 448 768 ) ( -1344 448 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -528 448 768 ) ( -448 448 768 ) ( -448 448 64 ) gothic_block/killblock 128 0 -180 0.500000 -0.500000 0 0 0 +( 0 416 768 ) ( 0 432 768 ) ( 0 432 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 256 464 768 ) ( 176 464 768 ) ( 176 464 64 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 224 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -304 432 256 0 0 ) ( -336 432 256 0 0.250000 ) ( -368 432 256 0 0.500001 ) ) +( ( -304 440 584 5.000002 0 ) ( -336 440 584 5.000002 0.250000 ) ( -368 440 584 5.000002 0.500001 ) ) +( ( -304 64 576 10.750113 0 ) ( -336 64 576 10.750113 0.250000 ) ( -368 64 576 10.750113 0.500001 ) ) +) + } + } +// brush 225 +{ +( -288 448 224 ) ( -400 448 224 ) ( -400 80 224 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -400 80 256 ) ( -400 448 256 ) ( -288 448 256 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -400 432 224 ) ( -288 432 224 ) ( -288 432 192 ) base_trim/spidertrim 64 0 0 0.500000 0.500000 0 0 0 +( -272 80 256 ) ( -272 448 256 ) ( -272 448 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -288 448 256 ) ( -400 448 256 ) ( -400 448 224 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -400 448 256 ) ( -400 80 256 ) ( -400 80 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 226 +{ +( -320 428 258 ) ( -312 432 232 ) ( -312 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -320 428 258 ) ( -328 428 232 ) ( -328 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -928 496 224 ) ( -928 424 224 ) ( -600 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -880 432 216 ) ( -552 432 216 ) ( -552 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -312 500 216 ) ( -312 428 216 ) ( -312 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -576 428 216 ) ( -904 428 216 ) ( -904 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -328 480 216 ) ( -328 552 216 ) ( -328 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 227 +{ +( -312 428 224 ) ( -328 428 224 ) ( -328 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -328 438 220 ) ( -328 428 220 ) ( -312 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -328 448 220 ) ( -312 448 220 ) ( -312 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -312 438 220 ) ( -312 428 220 ) ( -312 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -312 428 220 ) ( -328 428 220 ) ( -328 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -328 428 220 ) ( -328 438 220 ) ( -328 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 228 +{ +( -352 428 258 ) ( -344 432 232 ) ( -344 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -352 428 258 ) ( -360 428 232 ) ( -360 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -960 496 224 ) ( -960 424 224 ) ( -632 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -912 432 216 ) ( -584 432 216 ) ( -584 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -344 500 216 ) ( -344 428 216 ) ( -344 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -608 428 216 ) ( -936 428 216 ) ( -936 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -360 480 216 ) ( -360 552 216 ) ( -360 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 229 +{ +( -344 428 224 ) ( -360 428 224 ) ( -360 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -360 438 220 ) ( -360 428 220 ) ( -344 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -360 448 220 ) ( -344 448 220 ) ( -344 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -344 438 220 ) ( -344 428 220 ) ( -344 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -344 428 220 ) ( -360 428 220 ) ( -360 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -360 428 220 ) ( -360 438 220 ) ( -360 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 230 +{ +( -288 428 258 ) ( -280 432 232 ) ( -280 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -288 428 258 ) ( -296 428 232 ) ( -296 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -896 496 224 ) ( -896 424 224 ) ( -568 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -848 432 216 ) ( -520 432 216 ) ( -520 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -280 500 216 ) ( -280 428 216 ) ( -280 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -544 428 216 ) ( -872 428 216 ) ( -872 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -296 480 216 ) ( -296 552 216 ) ( -296 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 231 +{ +( -280 428 224 ) ( -296 428 224 ) ( -296 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -296 438 220 ) ( -296 428 220 ) ( -280 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -296 448 220 ) ( -280 448 220 ) ( -280 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -280 438 220 ) ( -280 428 220 ) ( -280 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -280 428 220 ) ( -296 428 220 ) ( -296 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -296 428 220 ) ( -296 438 220 ) ( -296 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 232 +{ +( -384 428 258 ) ( -376 432 232 ) ( -376 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -384 428 258 ) ( -392 428 232 ) ( -392 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -992 496 224 ) ( -992 424 224 ) ( -664 424 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -944 432 216 ) ( -616 432 216 ) ( -616 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -376 500 216 ) ( -376 428 216 ) ( -376 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -640 428 216 ) ( -968 428 216 ) ( -968 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -392 480 216 ) ( -392 552 216 ) ( -392 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 233 +{ +( -376 428 224 ) ( -392 428 224 ) ( -392 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -392 438 220 ) ( -392 428 220 ) ( -376 428 220 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -392 448 220 ) ( -376 448 220 ) ( -376 448 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -376 438 220 ) ( -376 428 220 ) ( -376 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -376 428 220 ) ( -392 428 220 ) ( -392 428 224 ) base_trim/pewter 64 0 0 0.500000 0.500000 134217728 0 0 +( -392 428 220 ) ( -392 438 220 ) ( -392 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 234 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -304 448 256 0 0 ) ( -304 440 256 0 0.125000 ) ( -304 432 256 0 0.250000 ) ) +( ( -304 448 592 5.250000 0 ) ( -304 440 584 5.250000 0.125000 ) ( -304 440 584 5.250000 0.250000 ) ) +( ( -304 64 592 11.250000 0 ) ( -304 64 584 11.250000 0.125000 ) ( -304 64 576 11.250000 0.250000 ) ) +) + } + } +// brush 235 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -368 432 256 0 0 ) ( -368 440 256 0 0.125000 ) ( -368 448 256 0 0.250000 ) ) +( ( -368 440 584 5.126524 0 ) ( -368 440 584 5.126524 0.125000 ) ( -368 448 592 5.126524 0.250000 ) ) +( ( -368 64 576 11.002853 0 ) ( -368 64 584 11.002853 0.125000 ) ( -368 64 592 11.002853 0.250000 ) ) +) + } + } +// brush 236 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -368 448 256 0 0 ) ( -336 448 256 0 0.500000 ) ( -304 448 256 0 1 ) ) +( ( -368 448 592 5.250000 0 ) ( -336 448 592 5.250000 0.500000 ) ( -304 448 592 5.250000 1 ) ) +( ( -368 64 592 11.250000 0 ) ( -336 64 592 11.250000 0.500000 ) ( -304 64 592 11.250000 1 ) ) +) + } + } +// brush 237 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -144 448 256 0 0 ) ( -112 448 256 0 0.500000 ) ( -80 448 256 0 1 ) ) +( ( -144 448 592 5.250000 0 ) ( -112 448 592 5.250000 0.500000 ) ( -80 448 592 5.250000 1 ) ) +( ( -144 64 592 11.250000 0 ) ( -112 64 592 11.250000 0.500000 ) ( -80 64 592 11.250000 1 ) ) +) + } + } +// brush 238 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -144 432 256 0 0 ) ( -144 440 256 0 0.125000 ) ( -144 448 256 0 0.250000 ) ) +( ( -144 440 584 5.126524 0 ) ( -144 440 584 5.126524 0.125000 ) ( -144 448 592 5.126524 0.250000 ) ) +( ( -144 64 576 11.002853 0 ) ( -144 64 584 11.002853 0.125000 ) ( -144 64 592 11.002853 0.250000 ) ) +) + } + } +// brush 239 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -80 448 256 0 0 ) ( -80 440 256 0 0.125000 ) ( -80 432 256 0 0.250000 ) ) +( ( -80 448 592 5.250000 0 ) ( -80 440 584 5.250000 0.125000 ) ( -80 440 584 5.250000 0.250000 ) ) +( ( -80 64 592 11.250000 0 ) ( -80 64 584 11.250000 0.125000 ) ( -80 64 576 11.250000 0.250000 ) ) +) + } + } +// brush 240 +{ +( -168 428 220 ) ( -168 438 220 ) ( -168 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -152 428 220 ) ( -168 428 220 ) ( -168 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -152 438 220 ) ( -152 428 220 ) ( -152 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -168 448 220 ) ( -152 448 220 ) ( -152 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -168 438 220 ) ( -168 428 220 ) ( -152 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -152 428 224 ) ( -168 428 224 ) ( -168 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 241 +{ +( -168 480 216 ) ( -168 552 216 ) ( -168 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -416 428 216 ) ( -744 428 216 ) ( -744 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -152 500 216 ) ( -152 428 216 ) ( -152 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -720 432 216 ) ( -392 432 216 ) ( -392 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -768 496 224 ) ( -768 424 224 ) ( -440 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -160 428 258 ) ( -168 428 232 ) ( -168 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -160 428 258 ) ( -152 432 232 ) ( -152 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 242 +{ +( -72 428 220 ) ( -72 438 220 ) ( -72 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -56 428 220 ) ( -72 428 220 ) ( -72 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -56 438 220 ) ( -56 428 220 ) ( -56 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -72 448 220 ) ( -56 448 220 ) ( -56 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -72 438 220 ) ( -72 428 220 ) ( -56 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -56 428 224 ) ( -72 428 224 ) ( -72 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 243 +{ +( -72 480 216 ) ( -72 552 216 ) ( -72 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -320 428 216 ) ( -648 428 216 ) ( -648 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -56 500 216 ) ( -56 428 216 ) ( -56 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -624 432 216 ) ( -296 432 216 ) ( -296 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -672 496 224 ) ( -672 424 224 ) ( -344 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -64 428 258 ) ( -72 428 232 ) ( -72 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -64 428 258 ) ( -56 432 232 ) ( -56 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 244 +{ +( -136 428 220 ) ( -136 438 220 ) ( -136 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -120 428 220 ) ( -136 428 220 ) ( -136 428 224 ) base_trim/pewter -64 0 0 0.500000 0.500000 134217728 0 0 +( -120 438 220 ) ( -120 428 220 ) ( -120 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -136 448 220 ) ( -120 448 220 ) ( -120 448 224 ) base_trim/pewter -64 0 0 0.500000 0.500000 134217728 0 0 +( -136 438 220 ) ( -136 428 220 ) ( -120 428 220 ) base_trim/pewter -64 0 0 0.500000 0.500000 134217728 0 0 +( -120 428 224 ) ( -136 428 224 ) ( -136 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 245 +{ +( -136 480 216 ) ( -136 552 216 ) ( -136 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -384 428 216 ) ( -712 428 216 ) ( -712 428 224 ) base_trim/pewter -64 0 0 0.500000 0.500000 134217728 0 0 +( -120 500 216 ) ( -120 428 216 ) ( -120 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -688 432 216 ) ( -360 432 216 ) ( -360 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -736 496 224 ) ( -736 424 224 ) ( -408 424 224 ) base_trim/pewter -64 0 0 0.500000 0.500000 134217728 0 0 +( -128 428 258 ) ( -136 428 232 ) ( -136 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -128 428 258 ) ( -120 432 232 ) ( -120 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 246 +{ +( -104 428 220 ) ( -104 438 220 ) ( -104 438 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -88 428 220 ) ( -104 428 220 ) ( -104 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -88 438 220 ) ( -88 428 220 ) ( -88 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -104 448 220 ) ( -88 448 220 ) ( -88 448 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -104 438 220 ) ( -104 428 220 ) ( -88 428 220 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -88 428 224 ) ( -104 428 224 ) ( -104 438 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 247 +{ +( -104 480 216 ) ( -104 552 216 ) ( -104 552 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -352 428 216 ) ( -680 428 216 ) ( -680 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -88 500 216 ) ( -88 428 216 ) ( -88 428 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -656 432 216 ) ( -328 432 216 ) ( -328 432 224 ) common/caulk 0 0 0 0.500000 0.500000 134217728 0 0 +( -704 496 224 ) ( -704 424 224 ) ( -376 424 224 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -96 428 258 ) ( -104 428 232 ) ( -104 432 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +( -96 428 258 ) ( -88 432 232 ) ( -88 428 232 ) base_trim/pewter 0 0 0 0.500000 0.500000 134217728 0 0 +} +// brush 248 +{ +( -176 448 256 ) ( -176 80 256 ) ( -176 80 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -64 448 256 ) ( -176 448 256 ) ( -176 448 224 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -48 80 256 ) ( -48 448 256 ) ( -48 448 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -176 432 224 ) ( -64 432 224 ) ( -64 432 192 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -176 80 256 ) ( -176 448 256 ) ( -64 448 256 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -64 448 224 ) ( -176 448 224 ) ( -176 80 224 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 249 + { + patchDef2 + { + gothic_trim/pitted_rust3 + ( 3 3 0 0 0 ) +( +( ( -0.000038 448 256 0 0 ) ( -672.000061 448 256 0 6 ) ( -1344 448 256 0 12 ) ) +( ( -0.000038 448 592 2.625000 0 ) ( -672.000061 448 592 2.625000 6 ) ( -1344 448 592 2.625000 12 ) ) +( ( -0.000038 64 592 5.625000 0 ) ( -672.000061 64 592 5.625000 6 ) ( -1344 64 592 5.625000 12 ) ) +) + } + } +// brush 250 +{ +( 40 192 336 ) ( 24 192 336 ) ( 24 144 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 144 464 ) ( 24 192 464 ) ( 40 192 464 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 144 464 ) ( 32 144 464 ) ( 32 144 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 40 144 464 ) ( 40 192 464 ) ( 40 192 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 192 464 ) ( 16 192 464 ) ( 16 192 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 192 464 ) ( 16 144 464 ) ( 16 144 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 251 +{ +( 40 368 336 ) ( 24 368 336 ) ( 24 320 336 ) common/caulk 0 32 0 0.500000 0.500000 0 0 0 +( 24 320 464 ) ( 24 368 464 ) ( 40 368 464 ) common/caulk 0 32 0 0.500000 0.500000 0 0 0 +( 16 320 464 ) ( 32 320 464 ) ( 32 320 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 40 320 464 ) ( 40 368 464 ) ( 40 368 240 ) common/caulk -32 0 0 0.500000 0.500000 0 0 0 +( 40 368 464 ) ( 24 368 464 ) ( 24 368 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 368 464 ) ( 16 320 464 ) ( 16 320 240 ) common/caulk -32 0 0 0.500000 0.500000 0 0 0 +} +// brush 252 +{ +( 40 320 432 ) ( 24 320 432 ) ( 24 304 432 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( 24 304 464 ) ( 24 320 464 ) ( 40 320 464 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( 16 192 464 ) ( 32 192 464 ) ( 32 192 336 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( 40 304 464 ) ( 40 320 464 ) ( 40 320 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 320 464 ) ( 16 320 464 ) ( 16 320 336 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( 16 320 464 ) ( 16 304 464 ) ( 16 304 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 253 +{ +( 40 -192 432 ) ( 24 -192 432 ) ( 24 -208 432 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( 24 -208 464 ) ( 24 -192 464 ) ( 40 -192 464 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( 16 -320 464 ) ( 32 -320 464 ) ( 32 -320 336 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( 40 -208 464 ) ( 40 -192 464 ) ( 40 -192 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 -192 464 ) ( 16 -192 464 ) ( 16 -192 336 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( 16 -192 464 ) ( 16 -208 464 ) ( 16 -208 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 254 +{ +( 40 -144 336 ) ( 24 -144 336 ) ( 24 -192 336 ) common/caulk 0 32 0 0.500000 0.500000 0 0 0 +( 24 -192 464 ) ( 24 -144 464 ) ( 40 -144 464 ) common/caulk 0 32 0 0.500000 0.500000 0 0 0 +( 16 -192 464 ) ( 32 -192 464 ) ( 32 -192 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 40 -192 464 ) ( 40 -144 464 ) ( 40 -144 240 ) common/caulk -32 0 0 0.500000 0.500000 0 0 0 +( 40 -144 464 ) ( 24 -144 464 ) ( 24 -144 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -144 464 ) ( 16 -192 464 ) ( 16 -192 240 ) common/caulk -32 0 0 0.500000 0.500000 0 0 0 +} +// brush 255 +{ +( 40 -320 336 ) ( 24 -320 336 ) ( 24 -368 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 -368 464 ) ( 24 -320 464 ) ( 40 -320 464 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 -368 464 ) ( 40 -368 464 ) ( 40 -368 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 40 -368 464 ) ( 40 -320 464 ) ( 40 -320 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 -320 464 ) ( 16 -320 464 ) ( 16 -320 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -320 464 ) ( 16 -368 464 ) ( 16 -368 240 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 256 +{ +( 16 384 64 ) ( 0 384 64 ) ( 0 352 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 352 776 ) ( 0 384 776 ) ( 16 384 776 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 352 768 ) ( 16 352 768 ) ( 16 352 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 704 768 ) ( 16 736 768 ) ( 16 736 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 384 768 ) ( 0 352 768 ) ( 0 352 0 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 16 448 400 ) ( -624 448 400 ) ( 16 448 80 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 257 +{ +( 0 64 776 ) ( 0 96 776 ) ( 16 96 776 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 416 768 ) ( 16 448 768 ) ( 16 448 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 96 768 ) ( 0 64 768 ) ( 0 64 0 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 16 352 384 ) ( -624 352 384 ) ( -624 352 64 ) gothic_block/killblock -128 10 0 0.500000 0.500000 0 0 0 +( -624 160 400 ) ( 16 160 400 ) ( 16 160 80 ) gothic_block/killblock -128 10 0 0.500000 0.500000 0 0 0 +( -624 384 464 ) ( -624 160 464 ) ( 16 384 464 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 258 +{ +( 16 96 64 ) ( 0 96 64 ) ( 0 64 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 416 768 ) ( 16 448 768 ) ( 16 448 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 96 768 ) ( 0 64 768 ) ( 0 64 0 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 16 352 384 ) ( -624 352 384 ) ( -624 352 64 ) gothic_block/killblock -128 10 0 0.500000 0.500000 0 0 0 +( -624 160 400 ) ( 16 160 400 ) ( 16 160 80 ) gothic_block/killblock -128 10 0 0.500000 0.500000 0 0 0 +( -624 384 176 ) ( 16 384 176 ) ( -624 160 176 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 259 +{ +( 16 320 176 ) ( -16 320 176 ) ( -16 192 176 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 192 208 ) ( -16 320 208 ) ( 16 320 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 160 208 ) ( 16 160 208 ) ( 16 160 176 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 24 192 208 ) ( 24 320 208 ) ( 24 320 176 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 352 208 ) ( -16 352 208 ) ( -16 352 176 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 320 208 ) ( -16 192 208 ) ( -16 192 176 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 260 +{ +( 56 320 208 ) ( 24 320 208 ) ( 24 192 208 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 192 432 ) ( 24 320 432 ) ( 56 320 432 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 192 432 ) ( 56 192 432 ) ( 56 192 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 40 192 432 ) ( 40 320 432 ) ( 40 320 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 56 320 432 ) ( 24 320 432 ) ( 24 320 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 320 432 ) ( 24 192 432 ) ( 24 192 256 ) skies/hellsky2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 261 +{ +( 32 352 208 ) ( -32 352 208 ) ( -32 320 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -32 320 304 ) ( -32 352 304 ) ( 32 352 304 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -32 320 304 ) ( 32 320 304 ) ( 32 320 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 24 320 304 ) ( 24 352 304 ) ( 24 352 208 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 352 304 ) ( -32 352 304 ) ( -32 352 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 352 304 ) ( -16 320 304 ) ( -16 320 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 262 +{ +( 16 368 304 ) ( -16 368 304 ) ( -16 304 304 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 304 336 ) ( -16 368 336 ) ( 16 368 336 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 304 336 ) ( 16 304 336 ) ( 16 304 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 40 304 336 ) ( 40 368 336 ) ( 40 368 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 368 336 ) ( -16 368 336 ) ( -16 368 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -32 368 336 ) ( -32 304 336 ) ( -32 304 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 263 +{ +( 16 208 304 ) ( -16 208 304 ) ( -16 144 304 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 144 336 ) ( -16 208 336 ) ( 16 208 336 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 144 336 ) ( 16 144 336 ) ( 16 144 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 40 144 336 ) ( 40 208 336 ) ( 40 208 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 208 336 ) ( -16 208 336 ) ( -16 208 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -32 208 336 ) ( -32 144 336 ) ( -32 144 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 264 +{ +( 32 192 208 ) ( -32 192 208 ) ( -32 160 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -32 160 304 ) ( -32 192 304 ) ( 32 192 304 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -32 160 304 ) ( 32 160 304 ) ( 32 160 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 24 160 304 ) ( 24 192 304 ) ( 24 192 208 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 192 304 ) ( -32 192 304 ) ( -32 192 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 192 304 ) ( -16 160 304 ) ( -16 160 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 265 +{ +( 0 256 464 ) ( 0 160 336 ) ( 16 208 400 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 256 464 ) ( 0 160 464 ) ( 0 160 336 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 16 160 464 ) ( 16 256 464 ) ( 16 256 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -16 160 464 ) ( 16 160 464 ) ( 16 160 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -16 160 464 ) ( -16 256 464 ) ( 16 256 464 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 266 + { + patchDef2 + { + gothic_block/killblock + ( 9 3 0 0 0 ) +( +( ( -16 256 432 0 0 ) ( -16 208 400 0 0.450694 ) ( -16 192 336 0 0.966082 ) ) +( ( 4 256 432 0.156250 0 ) ( 4 208 400 0.156250 0.450694 ) ( 4 192 336 0.156250 0.966082 ) ) +( ( 24 256 432 0.312500 0 ) ( 24 208 400 0.312500 0.450694 ) ( 24 192 336 0.312500 0.966082 ) ) +( ( 24 256 448 0.437500 0 ) ( 24 197 411 0.437500 0.450694 ) ( 24 176 336 0.437500 0.966082 ) ) +( ( 24 256 464 0.562500 0 ) ( 24 185 423 0.562500 0.450694 ) ( 24 160 336 0.562500 0.966082 ) ) +( ( 4 256 464 0.718750 0 ) ( 4 185 423 0.718750 0.450694 ) ( 4 160 336 0.718750 0.966082 ) ) +( ( -16 256 464 0.875000 0 ) ( -16 185 423 0.875000 0.450694 ) ( -16 160 336 0.875000 0.966082 ) ) +( ( -16 256 448 1 0 ) ( -16 197 411 1 0.450694 ) ( -16 176 336 1 0.966082 ) ) +( ( -16 256 432 1.125000 0 ) ( -16 208 400 1.125000 0.450694 ) ( -16 192 336 1.125000 0.966082 ) ) +) + } + } +// brush 267 +{ +( 16 256 464 ) ( 16 352 336 ) ( 0 304 400 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 256 464 ) ( 16 352 464 ) ( 16 352 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 352 464 ) ( 0 256 464 ) ( 0 256 336 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 32 352 464 ) ( 0 352 464 ) ( 0 352 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 352 464 ) ( 32 256 464 ) ( 0 256 464 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 268 + { + patchDef2 + { + gothic_block/killblock + ( 9 3 0 0 0 ) +( +( ( 24 256 432 0 0 ) ( 24 304 400 0 0.450694 ) ( 24 320 336 0 0.966082 ) ) +( ( 4 256 432 0.156250 0 ) ( 4 304 400 0.156250 0.450694 ) ( 4 320 336 0.156250 0.966082 ) ) +( ( -16 256 432 0.312500 0 ) ( -16 304 400 0.312500 0.450694 ) ( -16 320 336 0.312500 0.966082 ) ) +( ( -16 256 448 0.437500 0 ) ( -16 315 411 0.437500 0.450694 ) ( -16 336 336 0.437500 0.966082 ) ) +( ( -16 256 464 0.562500 0 ) ( -16 327 423 0.562500 0.450694 ) ( -16 352 336 0.562500 0.966082 ) ) +( ( 4 256 464 0.718750 0 ) ( 4 327 423 0.718750 0.450694 ) ( 4 352 336 0.718750 0.966082 ) ) +( ( 24 256 464 0.875000 0 ) ( 24 327 423 0.875000 0.450694 ) ( 24 352 336 0.875000 0.966082 ) ) +( ( 24 256 448 1 0 ) ( 24 315 411 1 0.450694 ) ( 24 336 336 1 0.966082 ) ) +( ( 24 256 432 1.125000 0 ) ( 24 304 400 1.125000 0.450694 ) ( 24 320 336 1.125000 0.966082 ) ) +) + } + } +// brush 269 + { + patchDef2 + { + gothic_block/killblock + ( 9 3 0 0 0 ) +( +( ( 24 -256 432 0 0 ) ( 24 -208 400 0 0.450694 ) ( 24 -192 336 0 0.966082 ) ) +( ( 4 -256 432 0.156250 0 ) ( 4 -208 400 0.156250 0.450694 ) ( 4 -192 336 0.156250 0.966082 ) ) +( ( -16 -256 432 0.312500 0 ) ( -16 -208 400 0.312500 0.450694 ) ( -16 -192 336 0.312500 0.966082 ) ) +( ( -16 -256 448 0.437500 0 ) ( -16 -197 411 0.437500 0.450694 ) ( -16 -176 336 0.437500 0.966082 ) ) +( ( -16 -256 464 0.562500 0 ) ( -16 -185 423 0.562500 0.450694 ) ( -16 -160 336 0.562500 0.966082 ) ) +( ( 4 -256 464 0.718750 0 ) ( 4 -185 423 0.718750 0.450694 ) ( 4 -160 336 0.718750 0.966082 ) ) +( ( 24 -256 464 0.875000 0 ) ( 24 -185 423 0.875000 0.450694 ) ( 24 -160 336 0.875000 0.966082 ) ) +( ( 24 -256 448 1 0 ) ( 24 -197 411 1 0.450694 ) ( 24 -176 336 1 0.966082 ) ) +( ( 24 -256 432 1.125000 0 ) ( 24 -208 400 1.125000 0.450694 ) ( 24 -192 336 1.125000 0.966082 ) ) +) + } + } +// brush 270 +{ +( 16 -256 464 ) ( 16 -160 336 ) ( 0 -208 400 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -256 464 ) ( 16 -160 464 ) ( 16 -160 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -160 464 ) ( 0 -256 464 ) ( 0 -256 336 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 32 -160 464 ) ( 0 -160 464 ) ( 0 -160 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 -160 464 ) ( 32 -256 464 ) ( 0 -256 464 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 271 + { + patchDef2 + { + gothic_block/killblock + ( 9 3 0 0 0 ) +( +( ( -16 -256 432 0 0 ) ( -16 -304 400 0 0.450694 ) ( -16 -320 336 0 0.966082 ) ) +( ( 4 -256 432 0.156250 0 ) ( 4 -304 400 0.156250 0.450694 ) ( 4 -320 336 0.156250 0.966082 ) ) +( ( 24 -256 432 0.312500 0 ) ( 24 -304 400 0.312500 0.450694 ) ( 24 -320 336 0.312500 0.966082 ) ) +( ( 24 -256 448 0.437500 0 ) ( 24 -315 411 0.437500 0.450694 ) ( 24 -336 336 0.437500 0.966082 ) ) +( ( 24 -256 464 0.562500 0 ) ( 24 -327 423 0.562500 0.450694 ) ( 24 -352 336 0.562500 0.966082 ) ) +( ( 4 -256 464 0.718750 0 ) ( 4 -327 423 0.718750 0.450694 ) ( 4 -352 336 0.718750 0.966082 ) ) +( ( -16 -256 464 0.875000 0 ) ( -16 -327 423 0.875000 0.450694 ) ( -16 -352 336 0.875000 0.966082 ) ) +( ( -16 -256 448 1 0 ) ( -16 -315 411 1 0.450694 ) ( -16 -336 336 1 0.966082 ) ) +( ( -16 -256 432 1.125000 0 ) ( -16 -304 400 1.125000 0.450694 ) ( -16 -320 336 1.125000 0.966082 ) ) +) + } + } +// brush 272 +{ +( 0 -256 464 ) ( 0 -352 336 ) ( 16 -304 400 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -256 464 ) ( 0 -352 464 ) ( 0 -352 336 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 16 -352 464 ) ( 16 -256 464 ) ( 16 -256 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -16 -352 464 ) ( 16 -352 464 ) ( 16 -352 336 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -16 -352 464 ) ( -16 -256 464 ) ( 16 -256 464 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 273 +{ +( 32 -320 208 ) ( -32 -320 208 ) ( -32 -352 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -32 -352 304 ) ( -32 -320 304 ) ( 32 -320 304 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -32 -352 304 ) ( 32 -352 304 ) ( 32 -352 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 24 -352 304 ) ( 24 -320 304 ) ( 24 -320 208 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 -320 304 ) ( -32 -320 304 ) ( -32 -320 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 -320 304 ) ( -16 -352 304 ) ( -16 -352 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 274 +{ +( 16 -304 304 ) ( -16 -304 304 ) ( -16 -368 304 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 -368 336 ) ( -16 -304 336 ) ( 16 -304 336 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 -368 336 ) ( 16 -368 336 ) ( 16 -368 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 40 -368 336 ) ( 40 -304 336 ) ( 40 -304 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -304 336 ) ( -16 -304 336 ) ( -16 -304 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -32 -304 336 ) ( -32 -368 336 ) ( -32 -368 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 275 +{ +( 16 -144 304 ) ( -16 -144 304 ) ( -16 -208 304 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 -208 336 ) ( -16 -144 336 ) ( 16 -144 336 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 -208 336 ) ( 16 -208 336 ) ( 16 -208 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 40 -208 336 ) ( 40 -144 336 ) ( 40 -144 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -144 336 ) ( -16 -144 336 ) ( -16 -144 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -32 -144 336 ) ( -32 -208 336 ) ( -32 -208 320 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 276 +{ +( 32 -160 208 ) ( -32 -160 208 ) ( -32 -192 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -32 -192 304 ) ( -32 -160 304 ) ( 32 -160 304 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -32 -192 304 ) ( 32 -192 304 ) ( 32 -192 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 24 -192 304 ) ( 24 -160 304 ) ( 24 -160 208 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 32 -160 304 ) ( -32 -160 304 ) ( -32 -160 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 -160 304 ) ( -16 -192 304 ) ( -16 -192 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 277 +{ +( 56 -192 208 ) ( 24 -192 208 ) ( 24 -320 208 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 -320 432 ) ( 24 -192 432 ) ( 56 -192 432 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 -320 432 ) ( 56 -320 432 ) ( 56 -320 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 40 -320 432 ) ( 40 -192 432 ) ( 40 -192 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 56 -192 432 ) ( 24 -192 432 ) ( 24 -192 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 24 -192 432 ) ( 24 -320 432 ) ( 24 -320 256 ) skies/hellsky2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 278 +{ +( 16 -192 176 ) ( -16 -192 176 ) ( -16 -320 176 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 -320 208 ) ( -16 -192 208 ) ( 16 -192 208 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 -352 208 ) ( 16 -352 208 ) ( 16 -352 176 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 24 -320 208 ) ( 24 -192 208 ) ( 24 -192 176 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -160 208 ) ( -16 -160 208 ) ( -16 -160 176 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -16 -192 208 ) ( -16 -320 208 ) ( -16 -320 176 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 279 +{ +( 16 -416 64 ) ( 0 -416 64 ) ( 0 -448 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -96 768 ) ( 16 -64 768 ) ( 16 -64 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -416 768 ) ( 0 -448 768 ) ( 0 -448 0 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 16 -160 384 ) ( -624 -160 384 ) ( -624 -160 64 ) gothic_block/killblock -384 10 0 0.500000 0.500000 0 0 0 +( -624 -352 400 ) ( 16 -352 400 ) ( 16 -352 80 ) gothic_block/killblock -384 10 0 0.500000 0.500000 0 0 0 +( -624 -128 176 ) ( 16 -128 176 ) ( -624 -352 176 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 280 +{ +( 0 -448 776 ) ( 0 -416 776 ) ( 16 -416 776 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -96 768 ) ( 16 -64 768 ) ( 16 -64 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -416 768 ) ( 0 -448 768 ) ( 0 -448 0 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 16 -160 384 ) ( -624 -160 384 ) ( -624 -160 64 ) gothic_block/killblock -384 10 0 0.500000 0.500000 0 0 0 +( -624 -352 400 ) ( 16 -352 400 ) ( 16 -352 80 ) gothic_block/killblock -384 10 0 0.500000 0.500000 0 0 0 +( -624 -128 464 ) ( -624 -352 464 ) ( 16 -128 464 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 281 +{ +( 16 -416 64 ) ( 0 -416 64 ) ( 0 -448 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -448 776 ) ( 0 -416 776 ) ( 16 -416 776 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -448 768 ) ( 16 -448 768 ) ( 16 -448 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -96 768 ) ( 16 -64 768 ) ( 16 -64 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -416 768 ) ( 0 -448 768 ) ( 0 -448 0 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( 16 -352 400 ) ( -624 -352 400 ) ( 16 -352 80 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 282 +{ +( 16 -416 64 ) ( 0 -416 64 ) ( 0 -448 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -448 776 ) ( 0 -416 776 ) ( 16 -416 776 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -96 768 ) ( 16 -64 768 ) ( 16 -64 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 -64 768 ) ( 0 -64 768 ) ( 0 -64 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 -416 768 ) ( 0 -448 768 ) ( 0 -448 0 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +( -624 -160 384 ) ( 16 -160 384 ) ( -624 -160 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 283 + { + patchDef2 + { + gothic_trim/pitted_rust3 + ( 3 3 0 0 0 ) +( +( ( -1344 -448 255.999985 0 0 ) ( -672.000061 -448 255.999985 0 6 ) ( -0.000038 -448 255.999985 0 12 ) ) +( ( -1344 -448 592 2.625000 0 ) ( -672.000061 -448 592 2.625000 6 ) ( -0.000038 -448 592 2.625000 12 ) ) +( ( -1344 -64 592 5.625000 0 ) ( -672.000061 -64 592 5.625000 6 ) ( -0.000038 -64 592 5.625000 12 ) ) +) + } + } +// brush 284 + { + patchDef2 + { + gothic_trim/pitted_rust3 + ( 5 3 0 0 0 ) +( +( ( -1344 -64 592 0 0 ) ( -687.999939 -64 592 0 5.875000 ) ( -32.000008 -64 592 0 11.750000 ) ) +( ( -1344 -64 639 0.367188 0 ) ( -687.999939 -64 639 0.367188 5.875000 ) ( -32.000008 -64 639 0.367188 11.750000 ) ) +( ( -1344 -44 681 0.730616 0 ) ( -687.999939 -44 681 0.730616 5.875000 ) ( -32.000008 -44 681 0.730616 11.750000 ) ) +( ( -1344 -28 720 1.059948 0 ) ( -687.999939 -28 720 1.059948 5.875000 ) ( -32.000008 -28 720 1.059948 11.750000 ) ) +( ( -1344 0 744 1.348058 0 ) ( -687.999939 0 744 1.348058 5.875000 ) ( -32.000008 0 744 1.348058 11.750000 ) ) +) + } + } +// brush 285 +{ +( 0 -64 0 ) ( -16 -64 0 ) ( -16 -448 0 ) common/caulk 34 0 0 0.500000 0.500000 0 0 0 +( 0 -96 80 ) ( 0 -448 80 ) ( -16 -448 64 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -16 -448 704 ) ( 0 -448 704 ) ( 0 -448 0 ) common/caulk 34 0 0 0.500000 0.500000 0 0 0 +( 0 -448 80 ) ( 0 -96 80 ) ( 0 -96 0 ) common/caulk 2 0 0 0.500000 0.500000 0 0 0 +( 0 -96 0 ) ( 0 -96 64 ) ( -16 -80 64 ) common/caulk 34 0 0 0.500000 0.500000 0 0 0 +( -16 -80 0 ) ( -16 -80 64 ) ( -16 -448 64 ) gothic_trim/baseboard09_i -28 0 0 0.500000 0.500000 0 0 0 +} +// brush 286 +{ +( 0 448 0 ) ( -16 448 0 ) ( -16 64 0 ) common/caulk 32 0 0 0.500000 0.500000 0 0 0 +( 0 448 80 ) ( 0 96 80 ) ( -16 80 64 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 0 96 64 ) ( 0 96 0 ) ( -16 80 0 ) common/caulk 32 0 0 0.500000 0.500000 0 0 0 +( 0 96 80 ) ( 0 448 80 ) ( 0 448 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 448 704 ) ( -16 448 704 ) ( -16 448 0 ) common/caulk 32 0 0 0.500000 0.500000 0 0 0 +( -16 80 64 ) ( -16 80 0 ) ( -16 448 0 ) gothic_trim/baseboard09_i 27 0 0 0.500000 0.500000 0 0 0 +} +// brush 287 +{ +( 16 96 64 ) ( 0 96 64 ) ( 0 64 64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 64 776 ) ( 0 96 776 ) ( 16 96 776 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 64 768 ) ( 16 64 768 ) ( 16 64 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 416 768 ) ( 16 448 768 ) ( 16 448 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 16 160 736 ) ( 0 160 736 ) ( 0 160 -32 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 0 96 768 ) ( 0 64 768 ) ( 0 64 0 ) gothic_block/killblock 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 288 +{ +( -16 256 0 ) ( -32 256 0 ) ( -32 -256 0 ) common/caulk 1 0 0 0.500000 0.500000 0 0 0 +( -32 -256 776 ) ( -32 256 776 ) ( -16 256 776 ) common/caulk 1 0 0 0.500000 0.500000 0 0 0 +( 0 -96 784 ) ( 0 -96 0 ) ( -32 -64 0 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( 0 -96 0 ) ( 0 -96 784 ) ( 0 96 784 ) common/caulk 1 0 0 0.500000 0.500000 0 0 0 +( 0 96 0 ) ( 0 96 784 ) ( -32 64 784 ) base_trim/spidertrim 0 0 0 0.500000 0.500000 0 0 0 +( -32 256 16 ) ( -32 -256 16 ) ( -32 -256 0 ) gothic_wall/xiantourneywall_c1 126 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 1 +{ +"classname" "info_player_deathmatch" +"origin" "-1280 0 24" +} +// entity 2 +{ +"type" "patchThick" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -144 -48 592 0 0 ) ( -112 -48 592 0 0.500000 ) ( -80 -48 592 0 1 ) ) +( ( -144 -48 634 0.656250 0 ) ( -112 -48 634 0.656250 0.500000 ) ( -80 -48 634 0.656250 1 ) ) +( ( -144 -33 672 1.294584 0 ) ( -112 -33 672 1.294584 0.500000 ) ( -80 -33 672 1.294584 1 ) ) +( ( -144 -21 707 1.872709 0 ) ( -112 -21 707 1.872709 0.500000 ) ( -80 -21 707 1.872709 1 ) ) +( ( -144 0 728 2.336748 0 ) ( -112 0 728 2.336748 0.500000 ) ( -80 0 728 2.336748 1 ) ) +) + } + } +} +// entity 3 +{ +"classname" "func_group" +"type" "patchThick" +// brush 0 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -80 432 256 0 0 ) ( -112 432 256 0 0.250000 ) ( -144 432 256 0 0.500001 ) ) +( ( -80 440 584 5.000002 0 ) ( -112 440 584 5.000002 0.250000 ) ( -144 440 584 5.000002 0.500001 ) ) +( ( -80 64 576 10.750113 0 ) ( -112 64 576 10.750113 0.250000 ) ( -144 64 576 10.750113 0.500001 ) ) +) + } + } +} +// entity 4 +{ +"type" "patchThick" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_trim/spidertrim + ( 3 3 0 0 0 ) +( +( ( -1264 -432 256 0 0 ) ( -1232 -432 256 0 0.250000 ) ( -1200 -432 256 0 0.500001 ) ) +( ( -1264 -440 584 5.000002 0 ) ( -1232 -440 584 5.000002 0.250000 ) ( -1200 -440 584 5.000002 0.500001 ) ) +( ( -1264 -64 576 10.750113 0 ) ( -1232 -64 576 10.750113 0.250000 ) ( -1200 -64 576 10.750113 0.500001 ) ) +) + } + } +} +// entity 5 +{ +"classname" "func_group" +"type" "patchThick" +// brush 0 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -368 -48 592 0 0 ) ( -336 -48 592 0 0.500000 ) ( -304 -48 592 0 1 ) ) +( ( -368 -48 634 0.656250 0 ) ( -336 -48 634 0.656250 0.500000 ) ( -304 -48 634 0.656250 1 ) ) +( ( -368 -33 672 1.294584 0 ) ( -336 -33 672 1.294584 0.500000 ) ( -304 -33 672 1.294584 1 ) ) +( ( -368 -21 707 1.872709 0 ) ( -336 -21 707 1.872709 0.500000 ) ( -304 -21 707 1.872709 1 ) ) +( ( -368 0 728 2.336748 0 ) ( -336 0 728 2.336748 0.500000 ) ( -304 0 728 2.336748 1 ) ) +) + } + } +} +// entity 6 +{ +"type" "patchThick" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -592 -48 592 0 0 ) ( -560 -48 592 0 0.500000 ) ( -528 -48 592 0 1 ) ) +( ( -592 -48 634 0.656250 0 ) ( -560 -48 634 0.656250 0.500000 ) ( -528 -48 634 0.656250 1 ) ) +( ( -592 -33 672 1.294584 0 ) ( -560 -33 672 1.294584 0.500000 ) ( -528 -33 672 1.294584 1 ) ) +( ( -592 -21 707 1.872709 0 ) ( -560 -21 707 1.872709 0.500000 ) ( -528 -21 707 1.872709 1 ) ) +( ( -592 0 728 2.336748 0 ) ( -560 0 728 2.336748 0.500000 ) ( -528 0 728 2.336748 1 ) ) +) + } + } +} +// entity 7 +{ +"classname" "func_group" +"type" "patchThick" +// brush 0 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -816 -48 592 0 0 ) ( -784 -48 592 0 0.500000 ) ( -752 -48 592 0 1 ) ) +( ( -816 -48 634 0.656250 0 ) ( -784 -48 634 0.656250 0.500000 ) ( -752 -48 634 0.656250 1 ) ) +( ( -816 -33 672 1.294584 0 ) ( -784 -33 672 1.294584 0.500000 ) ( -752 -33 672 1.294584 1 ) ) +( ( -816 -21 707 1.872709 0 ) ( -784 -21 707 1.872709 0.500000 ) ( -752 -21 707 1.872709 1 ) ) +( ( -816 0 728 2.336748 0 ) ( -784 0 728 2.336748 0.500000 ) ( -752 0 728 2.336748 1 ) ) +) + } + } +} +// entity 8 +{ +"type" "patchThick" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1040 -48 592 0 0 ) ( -1008 -48 592 0 0.500000 ) ( -976 -48 592 0 1 ) ) +( ( -1040 -48 634 0.656250 0 ) ( -1008 -48 634 0.656250 0.500000 ) ( -976 -48 634 0.656250 1 ) ) +( ( -1040 -33 672 1.294584 0 ) ( -1008 -33 672 1.294584 0.500000 ) ( -976 -33 672 1.294584 1 ) ) +( ( -1040 -21 707 1.872709 0 ) ( -1008 -21 707 1.872709 0.500000 ) ( -976 -21 707 1.872709 1 ) ) +( ( -1040 0 728 2.336748 0 ) ( -1008 0 728 2.336748 0.500000 ) ( -976 0 728 2.336748 1 ) ) +) + } + } +} +// entity 9 +{ +"classname" "func_group" +"type" "patchThick" +// brush 0 + { + patchDef2 + { + base_trim/spidertrim + ( 5 3 0 0 0 ) +( +( ( -1264 -48 592 0 0 ) ( -1232 -48 592 0 0.500000 ) ( -1200 -48 592 0 1 ) ) +( ( -1264 -48 634 0.656250 0 ) ( -1232 -48 634 0.656250 0.500000 ) ( -1200 -48 634 0.656250 1 ) ) +( ( -1264 -33 672 1.294584 0 ) ( -1232 -33 672 1.294584 0.500000 ) ( -1200 -33 672 1.294584 1 ) ) +( ( -1264 -21 707 1.872709 0 ) ( -1232 -21 707 1.872709 0.500000 ) ( -1200 -21 707 1.872709 1 ) ) +( ( -1264 0 728 2.336748 0 ) ( -1232 0 728 2.336748 0.500000 ) ( -1200 0 728 2.336748 1 ) ) +) + } + } +} +// entity 10 +{ +"spawnflags" "1" +"origin" "-112 189 328" +"noise" "sound/world/firesoft.wav" +"classname" "target_speaker" +} diff --git a/docs/developer/TstMaps/realloc.map b/docs/developer/TstMaps/realloc.map new file mode 100644 index 00000000..5db05676 --- /dev/null +++ b/docs/developer/TstMaps/realloc.map @@ -0,0 +1,4661 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +brushDef +{ +( -128 128 576 ) ( -128 0 576 ) ( -128 0 320 ) ( ( 0.007813 0 0.062500 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 120 128 576 ) ( -128 128 576 ) ( -128 128 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 16 576 ) ( 640 144 576 ) ( 640 144 320 ) ( ( 0.007813 0 -0.062500 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 0 576 ) ( 120 0 576 ) ( 120 0 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -120 0 328 ) ( -120 128 328 ) ( 128 128 328 ) ( ( 0.007813 0 -0.062500 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 120 128 320 ) ( -128 128 320 ) ( -128 0 320 ) ( ( 0.007813 0 -0.062500 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 1 +{ +brushDef +{ +( 128 0 304 ) ( 128 -8 304 ) ( 128 -8 296 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 392 0 304 ) ( 128 0 304 ) ( 128 0 296 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) clan_xb/logo7 0 0 0 +( 384 -8 304 ) ( 384 0 304 ) ( 384 0 296 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 120 -8 304 ) ( 384 -8 304 ) ( 384 -8 296 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) clan_xb/logo7 0 0 0 +( 128 -8 328 ) ( 128 0 328 ) ( 392 0 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 392 0 280 ) ( 128 0 280 ) ( 128 -8 280 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 2 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 144 232 ) ( 56 136 232 ) ( 160 144 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 328 ) ( -128 128 328 ) ( 32 136 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 3 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 376 ) ( 640 136 376 ) ( -128 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 328 ) ( 192 128 328 ) ( 32 136 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 4 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -760 872 -8 ) ( -760 1200 -8 ) ( -760 872 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +} +} +// brush 5 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 1200 -8 ) ( -8 1200 -8 ) ( -384 1200 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +} +} +// brush 6 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1272 -320 -8 ) ( 1272 -648 -8 ) ( 1272 -320 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +} +} +// brush 7 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1016 -640 -8 ) ( 640 -640 -8 ) ( 1016 -640 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +} +} +// brush 8 +{ +brushDef +{ +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( -384 1216 888 ) ( -384 888 888 ) ( -8 1216 888 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +} +} +// brush 9 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( -384 1208 -48 ) ( -8 1208 -48 ) ( -384 880 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +} +} +// brush 10 +{ +brushDef +{ +( 320 192 296 ) ( 192 192 296 ) ( 192 176 296 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 168 304 ) ( 192 184 304 ) ( 320 184 304 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 168 304 ) ( 320 168 304 ) ( 320 168 280 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 168 304 ) ( 320 184 304 ) ( 320 184 280 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 184 304 ) ( 192 184 304 ) ( 192 184 280 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 184 304 ) ( 192 168 304 ) ( 192 168 280 ) ( ( 0.007813 0 0.250016 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 11 +{ +brushDef +{ +( 320 168 296 ) ( 192 168 296 ) ( 192 152 296 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 152 312 ) ( 192 168 312 ) ( 320 168 312 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 152 312 ) ( 320 152 312 ) ( 320 152 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 152 312 ) ( 320 168 312 ) ( 320 168 288 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 168 312 ) ( 192 168 312 ) ( 192 168 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 168 312 ) ( 192 152 312 ) ( 192 152 288 ) ( ( 0.007813 0 0.125008 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 12 +{ +brushDef +{ +( 320 152 296 ) ( 192 152 296 ) ( 192 136 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 136 320 ) ( 192 152 320 ) ( 320 152 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 136 320 ) ( 320 136 320 ) ( 320 136 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 136 320 ) ( 320 152 320 ) ( 320 152 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 152 320 ) ( 192 152 320 ) ( 192 152 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 152 320 ) ( 192 136 320 ) ( 192 136 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 13 +{ +brushDef +{ +( 320 200 296 ) ( 192 200 296 ) ( 192 184 296 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 184 304 ) ( 192 200 304 ) ( 320 200 304 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 184 304 ) ( 320 184 304 ) ( 320 184 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 184 304 ) ( 320 200 304 ) ( 320 200 296 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 200 304 ) ( 192 200 304 ) ( 192 200 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 200 304 ) ( 192 184 304 ) ( 192 184 296 ) ( ( 0.007813 0 0.375024 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 14 +{ +brushDef +{ +( 320 184 304 ) ( 192 184 304 ) ( 192 168 304 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 168 312 ) ( 192 184 312 ) ( 320 184 312 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 168 312 ) ( 320 168 312 ) ( 320 168 304 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 168 312 ) ( 320 184 312 ) ( 320 184 304 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 184 312 ) ( 192 184 312 ) ( 192 184 304 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 184 312 ) ( 192 168 312 ) ( 192 168 304 ) ( ( 0.007813 0 0.250016 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 15 +{ +brushDef +{ +( 320 168 312 ) ( 192 168 312 ) ( 192 152 312 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 152 320 ) ( 192 168 320 ) ( 320 168 320 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 152 320 ) ( 320 152 320 ) ( 320 152 312 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 152 320 ) ( 320 168 320 ) ( 320 168 312 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 168 320 ) ( 192 168 320 ) ( 192 168 312 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 168 320 ) ( 192 152 320 ) ( 192 152 312 ) ( ( 0.007813 0 0.125008 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 16 +{ +brushDef +{ +( 320 152 320 ) ( 192 152 320 ) ( 192 136 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 136 328 ) ( 192 152 328 ) ( 320 152 328 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 136 328 ) ( 320 136 328 ) ( 320 136 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 136 328 ) ( 320 152 328 ) ( 320 152 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 320 152 328 ) ( 192 152 328 ) ( 192 152 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 192 152 328 ) ( 192 136 328 ) ( 192 136 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 17 +{ +brushDef +{ +( -40 136 376 ) ( -48 136 376 ) ( -48 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -48 128 392 ) ( -40 128 392 ) ( -40 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -40 128 392 ) ( -40 136 392 ) ( -40 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -40 136 392 ) ( -48 136 392 ) ( -48 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -48 136 392 ) ( -48 128 392 ) ( -48 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -8 128 424 ) ( -8 136 424 ) ( 0 128 424 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 18 +{ +brushDef +{ +( -40 128 480 ) ( -40 136 480 ) ( -32 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -48 128 392 ) ( -40 128 392 ) ( -40 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -40 128 392 ) ( -40 136 392 ) ( -40 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -40 136 392 ) ( -48 136 392 ) ( -48 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -48 136 392 ) ( -48 128 392 ) ( -48 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -8 136 432 ) ( -8 128 432 ) ( 0 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 19 +{ +brushDef +{ +( 8 136 432 ) ( 8 136 424 ) ( 8 128 424 ) ( ( -0.015625 0 0.250000 ) ( 0 -0.015625 -5.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -96 128 432 ) ( -96 136 432 ) ( -96 136 440 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 5.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -8 128 424 ) ( -8 128 432 ) ( 0 128 432 ) ( ( 0 0.015625 5.875000 ) ( -0.015625 0 -7.250001 ) ) gothic_trim/wood2 134217728 0 0 +( -8 128 432 ) ( -8 136 432 ) ( 0 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 11.500000 ) ) gothic_trim/wood2 134217728 0 0 +( -8 136 432 ) ( -8 136 424 ) ( 0 136 424 ) ( ( 0 -0.015625 -5.875000 ) ( 0.015625 0 -7.250000 ) ) gothic_trim/wood2 134217728 0 0 +( -8 136 424 ) ( -8 128 424 ) ( 0 128 424 ) ( ( -0.015625 0 0 ) ( 0 -0.015625 11.500000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 20 +{ +brushDef +{ +( 112 136 376 ) ( 104 136 376 ) ( 104 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 104 128 392 ) ( 112 128 392 ) ( 112 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 112 128 392 ) ( 112 136 392 ) ( 112 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 112 136 392 ) ( 104 136 392 ) ( 104 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 104 136 392 ) ( 104 128 392 ) ( 104 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 144 128 424 ) ( 144 136 424 ) ( 152 128 424 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 21 +{ +brushDef +{ +( 112 128 480 ) ( 112 136 480 ) ( 120 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 104 128 392 ) ( 112 128 392 ) ( 112 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 112 128 392 ) ( 112 136 392 ) ( 112 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 112 136 392 ) ( 104 136 392 ) ( 104 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 104 136 392 ) ( 104 128 392 ) ( 104 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 144 136 432 ) ( 144 128 432 ) ( 152 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 22 +{ +brushDef +{ +( 160 136 432 ) ( 160 136 424 ) ( 160 128 424 ) ( ( -0.015625 0 0.250000 ) ( 0 -0.015625 -5.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 56 128 432 ) ( 56 136 432 ) ( 56 136 440 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 5.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 144 128 424 ) ( 144 128 432 ) ( 152 128 432 ) ( ( 0 0.015625 5.875000 ) ( -0.015625 0 -4.875001 ) ) gothic_trim/wood2 134217728 0 0 +( 144 128 432 ) ( 144 136 432 ) ( 152 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 144 136 432 ) ( 144 136 424 ) ( 152 136 424 ) ( ( 0 -0.015625 -5.875000 ) ( 0.015625 0 -4.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 144 136 424 ) ( 144 128 424 ) ( 152 128 424 ) ( ( -0.015625 0 0 ) ( 0 -0.015625 9.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 23 +{ +brushDef +{ +( 408 136 376 ) ( 400 136 376 ) ( 400 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 400 128 392 ) ( 408 128 392 ) ( 408 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 408 128 392 ) ( 408 136 392 ) ( 408 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 408 136 392 ) ( 400 136 392 ) ( 400 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 400 136 392 ) ( 400 128 392 ) ( 400 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 128 424 ) ( 440 136 424 ) ( 448 128 424 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 24 +{ +brushDef +{ +( 408 128 480 ) ( 408 136 480 ) ( 416 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 400 128 392 ) ( 408 128 392 ) ( 408 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 408 128 392 ) ( 408 136 392 ) ( 408 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 408 136 392 ) ( 400 136 392 ) ( 400 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 400 136 392 ) ( 400 128 392 ) ( 400 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 136 432 ) ( 440 128 432 ) ( 448 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 25 +{ +brushDef +{ +( 456 136 432 ) ( 456 136 424 ) ( 456 128 424 ) ( ( -0.015625 0 0.250000 ) ( 0 -0.015625 -5.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 352 128 432 ) ( 352 136 432 ) ( 352 136 440 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 5.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 128 424 ) ( 440 128 432 ) ( 448 128 432 ) ( ( 0 0.015625 5.875000 ) ( -0.015625 0 -0.250000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 128 432 ) ( 440 136 432 ) ( 448 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 4.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 136 432 ) ( 440 136 424 ) ( 448 136 424 ) ( ( 0 -0.015625 -5.875000 ) ( 0.015625 0 -0.250000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 136 424 ) ( 440 128 424 ) ( 448 128 424 ) ( ( -0.015625 0 0 ) ( 0 -0.015625 4.500000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 26 +{ +brushDef +{ +( 560 136 376 ) ( 552 136 376 ) ( 552 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 552 128 392 ) ( 560 128 392 ) ( 560 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 560 128 392 ) ( 560 136 392 ) ( 560 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 560 136 392 ) ( 552 136 392 ) ( 552 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 552 136 392 ) ( 552 128 392 ) ( 552 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 592 128 424 ) ( 592 136 424 ) ( 600 128 424 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 27 +{ +brushDef +{ +( 560 128 480 ) ( 560 136 480 ) ( 568 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 552 128 392 ) ( 560 128 392 ) ( 560 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 560 128 392 ) ( 560 136 392 ) ( 560 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 560 136 392 ) ( 552 136 392 ) ( 552 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 552 136 392 ) ( 552 128 392 ) ( 552 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 592 136 432 ) ( 592 128 432 ) ( 600 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 28 +{ +brushDef +{ +( 608 136 432 ) ( 608 136 424 ) ( 608 128 424 ) ( ( -0.015625 0 0.250000 ) ( 0 -0.015625 -5.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 504 128 432 ) ( 504 136 432 ) ( 504 136 440 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 5.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 592 128 424 ) ( 592 128 432 ) ( 600 128 432 ) ( ( 0 0.015625 5.875000 ) ( -0.015625 0 2.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 592 128 432 ) ( 592 136 432 ) ( 600 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 592 136 432 ) ( 592 136 424 ) ( 600 136 424 ) ( ( 0 -0.015625 -5.875000 ) ( 0.015625 0 2.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 592 136 424 ) ( 592 128 424 ) ( 600 128 424 ) ( ( -0.015625 0 0 ) ( 0 -0.015625 2.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 29 +{ +brushDef +{ +( 648 128 328 ) ( 632 128 328 ) ( 632 120 328 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 120 384 ) ( 632 128 384 ) ( 648 128 384 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 120 336 ) ( 648 120 336 ) ( 648 120 328 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 120 336 ) ( 640 128 336 ) ( 640 128 328 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 648 128 336 ) ( 632 128 336 ) ( 632 128 328 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 632 128 336 ) ( 632 120 336 ) ( 632 120 328 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 30 +{ +brushDef +{ +( -112 128 328 ) ( -128 128 328 ) ( -128 120 328 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 120 384 ) ( -128 128 384 ) ( -112 128 384 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 120 336 ) ( -112 120 336 ) ( -112 120 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -120 120 336 ) ( -120 128 336 ) ( -120 128 328 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -112 128 336 ) ( -128 128 336 ) ( -128 128 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 128 336 ) ( -128 120 336 ) ( -128 120 328 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 31 +{ +brushDef +{ +( 192 128 512 ) ( 192 136 512 ) ( 224 136 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 512 ) ( 224 128 512 ) ( 224 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 512 ) ( 320 136 512 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 512 ) ( 288 136 512 ) ( 288 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 512 ) ( 192 128 512 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 144 480 ) ( 192 136 480 ) ( 320 144 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 32 +{ +brushDef +{ +( 216 136 224 ) ( 184 136 224 ) ( 184 128 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 512 ) ( 224 128 512 ) ( 224 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 512 ) ( 320 136 512 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 512 ) ( 288 136 512 ) ( 288 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 512 ) ( 192 128 512 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 328 ) ( 320 136 328 ) ( 192 128 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 33 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 1088 136 376 ) ( 320 136 376 ) ( 320 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 480 ) ( 320 136 480 ) ( 1088 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 480 ) ( 456 128 480 ) ( 456 136 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 504 128 480 ) ( 504 136 480 ) ( 504 128 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 34 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 1088 136 376 ) ( 320 136 376 ) ( 320 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 480 ) ( 320 136 480 ) ( 1088 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 608 136 480 ) ( 608 128 480 ) ( 608 136 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 35 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 1088 136 376 ) ( 320 136 376 ) ( 320 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 480 ) ( 320 136 480 ) ( 1088 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 480 ) ( 352 136 480 ) ( 352 128 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 36 +{ +brushDef +{ +( 320 128 512 ) ( 320 136 512 ) ( 640 136 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 480 ) ( 320 128 480 ) ( 1088 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 37 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 136 232 ) ( 352 128 232 ) ( 456 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 376 ) ( 1088 136 376 ) ( 320 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 38 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 376 ) ( -128 136 376 ) ( -128 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 480 ) ( -128 136 480 ) ( 640 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 8 136 480 ) ( 8 128 480 ) ( 8 136 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 128 480 ) ( 56 136 480 ) ( 56 128 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 39 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 376 ) ( -128 136 376 ) ( -128 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 480 ) ( -128 136 480 ) ( 640 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 136 480 ) ( 160 128 480 ) ( 160 136 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 40 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 376 ) ( -128 136 376 ) ( -128 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 480 ) ( -128 136 480 ) ( 640 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -96 128 480 ) ( -96 136 480 ) ( -96 128 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 41 +{ +brushDef +{ +( -128 128 512 ) ( -128 136 512 ) ( 192 136 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 480 ) ( -128 128 480 ) ( 640 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 42 +{ +brushDef +{ +( 640 968 512 ) ( 568 968 512 ) ( 568 920 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 448 776 768 ) ( 448 320 768 ) ( 64 320 768 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 320 768 ) ( 640 320 768 ) ( 640 128 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +( 448 320 768 ) ( 448 776 768 ) ( 640 968 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +( 640 776 768 ) ( -128 776 768 ) ( -128 968 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +( 64 776 768 ) ( 64 320 768 ) ( -128 128 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +} +} +// brush 43 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 560 824 8 0 0 ) ( 560 824 40 0 0.500000 ) ( 560 824 72 0 1 ) ) +( ( 560 816 8 0.125000 0 ) ( 560 816 40 0.125000 0.500000 ) ( 560 816 72 0.125000 1 ) ) +( ( 568 816 8 0.250000 0 ) ( 568 816 40 0.250000 0.500000 ) ( 568 816 72 0.250000 1 ) ) +( ( 576 816 8 0.375000 0 ) ( 576 816 40 0.375000 0.500000 ) ( 576 816 72 0.375000 1 ) ) +( ( 576 824 8 0.500000 0 ) ( 576 824 40 0.500000 0.500000 ) ( 576 824 72 0.500000 1 ) ) +( ( 576 832 8 0.625000 0 ) ( 576 832 40 0.625000 0.500000 ) ( 576 832 72 0.625000 1 ) ) +( ( 568 832 8 0.750000 0 ) ( 568 832 40 0.750000 0.500000 ) ( 568 832 72 0.750000 1 ) ) +( ( 560 832 8 0.875000 0 ) ( 560 832 40 0.875000 0.500000 ) ( 560 832 72 0.875000 1 ) ) +( ( 560 824 8 1 0 ) ( 560 824 40 1 0.500000 ) ( 560 824 72 1 1 ) ) +) + } + } +// brush 44 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( -64 824 8 0 0 ) ( -64 824 40 0 0.500000 ) ( -64 824 72 0 1 ) ) +( ( -64 816 8 0.125000 0 ) ( -64 816 40 0.125000 0.500000 ) ( -64 816 72 0.125000 1 ) ) +( ( -56 816 8 0.250000 0 ) ( -56 816 40 0.250000 0.500000 ) ( -56 816 72 0.250000 1 ) ) +( ( -48 816 8 0.375000 0 ) ( -48 816 40 0.375000 0.500000 ) ( -48 816 72 0.375000 1 ) ) +( ( -48 824 8 0.500000 0 ) ( -48 824 40 0.500000 0.500000 ) ( -48 824 72 0.500000 1 ) ) +( ( -48 832 8 0.625000 0 ) ( -48 832 40 0.625000 0.500000 ) ( -48 832 72 0.625000 1 ) ) +( ( -56 832 8 0.750000 0 ) ( -56 832 40 0.750000 0.500000 ) ( -56 832 72 0.750000 1 ) ) +( ( -64 832 8 0.875000 0 ) ( -64 832 40 0.875000 0.500000 ) ( -64 832 72 0.875000 1 ) ) +( ( -64 824 8 1 0 ) ( -64 824 40 1 0.500000 ) ( -64 824 72 1 1 ) ) +) + } + } +// brush 45 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( -64 928 8 0 0 ) ( -64 928 40 0 0.500000 ) ( -64 928 72 0 1 ) ) +( ( -64 920 8 0.125000 0 ) ( -64 920 40 0.125000 0.500000 ) ( -64 920 72 0.125000 1 ) ) +( ( -56 920 8 0.250000 0 ) ( -56 920 40 0.250000 0.500000 ) ( -56 920 72 0.250000 1 ) ) +( ( -48 920 8 0.375000 0 ) ( -48 920 40 0.375000 0.500000 ) ( -48 920 72 0.375000 1 ) ) +( ( -48 928 8 0.500000 0 ) ( -48 928 40 0.500000 0.500000 ) ( -48 928 72 0.500000 1 ) ) +( ( -48 936 8 0.625000 0 ) ( -48 936 40 0.625000 0.500000 ) ( -48 936 72 0.625000 1 ) ) +( ( -56 936 8 0.750000 0 ) ( -56 936 40 0.750000 0.500000 ) ( -56 936 72 0.750000 1 ) ) +( ( -64 936 8 0.875000 0 ) ( -64 936 40 0.875000 0.500000 ) ( -64 936 72 0.875000 1 ) ) +( ( -64 928 8 1 0 ) ( -64 928 40 1 0.500000 ) ( -64 928 72 1 1 ) ) +) + } + } +// brush 46 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 8 744 8 0 0 ) ( 8 744 40 0 0.500000 ) ( 8 744 72 0 1 ) ) +( ( 8 736 8 0.125000 0 ) ( 8 736 40 0.125000 0.500000 ) ( 8 736 72 0.125000 1 ) ) +( ( 16 736 8 0.250000 0 ) ( 16 736 40 0.250000 0.500000 ) ( 16 736 72 0.250000 1 ) ) +( ( 24 736 8 0.375000 0 ) ( 24 736 40 0.375000 0.500000 ) ( 24 736 72 0.375000 1 ) ) +( ( 24 744 8 0.500000 0 ) ( 24 744 40 0.500000 0.500000 ) ( 24 744 72 0.500000 1 ) ) +( ( 24 752 8 0.625000 0 ) ( 24 752 40 0.625000 0.500000 ) ( 24 752 72 0.625000 1 ) ) +( ( 16 752 8 0.750000 0 ) ( 16 752 40 0.750000 0.500000 ) ( 16 752 72 0.750000 1 ) ) +( ( 8 752 8 0.875000 0 ) ( 8 752 40 0.875000 0.500000 ) ( 8 752 72 0.875000 1 ) ) +( ( 8 744 8 1 0 ) ( 8 744 40 1 0.500000 ) ( 8 744 72 1 1 ) ) +) + } + } +// brush 47 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 104 744 8 0 0 ) ( 104 744 40 0 0.500000 ) ( 104 744 72 0 1 ) ) +( ( 104 736 8 0.125000 0 ) ( 104 736 40 0.125000 0.500000 ) ( 104 736 72 0.125000 1 ) ) +( ( 112 736 8 0.250000 0 ) ( 112 736 40 0.250000 0.500000 ) ( 112 736 72 0.250000 1 ) ) +( ( 120 736 8 0.375000 0 ) ( 120 736 40 0.375000 0.500000 ) ( 120 736 72 0.375000 1 ) ) +( ( 120 744 8 0.500000 0 ) ( 120 744 40 0.500000 0.500000 ) ( 120 744 72 0.500000 1 ) ) +( ( 120 752 8 0.625000 0 ) ( 120 752 40 0.625000 0.500000 ) ( 120 752 72 0.625000 1 ) ) +( ( 112 752 8 0.750000 0 ) ( 112 752 40 0.750000 0.500000 ) ( 112 752 72 0.750000 1 ) ) +( ( 104 752 8 0.875000 0 ) ( 104 752 40 0.875000 0.500000 ) ( 104 752 72 0.875000 1 ) ) +( ( 104 744 8 1 0 ) ( 104 744 40 1 0.500000 ) ( 104 744 72 1 1 ) ) +) + } + } +// brush 48 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 272 744 8 0 0 ) ( 272 744 40 0 0.500000 ) ( 272 744 72 0 1 ) ) +( ( 272 736 8 0.125000 0 ) ( 272 736 40 0.125000 0.500000 ) ( 272 736 72 0.125000 1 ) ) +( ( 280 736 8 0.250000 0 ) ( 280 736 40 0.250000 0.500000 ) ( 280 736 72 0.250000 1 ) ) +( ( 288 736 8 0.375000 0 ) ( 288 736 40 0.375000 0.500000 ) ( 288 736 72 0.375000 1 ) ) +( ( 288 744 8 0.500000 0 ) ( 288 744 40 0.500000 0.500000 ) ( 288 744 72 0.500000 1 ) ) +( ( 288 752 8 0.625000 0 ) ( 288 752 40 0.625000 0.500000 ) ( 288 752 72 0.625000 1 ) ) +( ( 280 752 8 0.750000 0 ) ( 280 752 40 0.750000 0.500000 ) ( 280 752 72 0.750000 1 ) ) +( ( 272 752 8 0.875000 0 ) ( 272 752 40 0.875000 0.500000 ) ( 272 752 72 0.875000 1 ) ) +( ( 272 744 8 1 0 ) ( 272 744 40 1 0.500000 ) ( 272 744 72 1 1 ) ) +) + } + } +// brush 49 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 376 744 8 0 0 ) ( 376 744 40 0 0.500000 ) ( 376 744 72 0 1 ) ) +( ( 376 736 8 0.125000 0 ) ( 376 736 40 0.125000 0.500000 ) ( 376 736 72 0.125000 1 ) ) +( ( 384 736 8 0.250000 0 ) ( 384 736 40 0.250000 0.500000 ) ( 384 736 72 0.250000 1 ) ) +( ( 392 736 8 0.375000 0 ) ( 392 736 40 0.375000 0.500000 ) ( 392 736 72 0.375000 1 ) ) +( ( 392 744 8 0.500000 0 ) ( 392 744 40 0.500000 0.500000 ) ( 392 744 72 0.500000 1 ) ) +( ( 392 752 8 0.625000 0 ) ( 392 752 40 0.625000 0.500000 ) ( 392 752 72 0.625000 1 ) ) +( ( 384 752 8 0.750000 0 ) ( 384 752 40 0.750000 0.500000 ) ( 384 752 72 0.750000 1 ) ) +( ( 376 752 8 0.875000 0 ) ( 376 752 40 0.875000 0.500000 ) ( 376 752 72 0.875000 1 ) ) +( ( 376 744 8 1 0 ) ( 376 744 40 1 0.500000 ) ( 376 744 72 1 1 ) ) +) + } + } +// brush 50 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 464 744 8 0 0 ) ( 464 744 40 0 0.500000 ) ( 464 744 72 0 1 ) ) +( ( 464 736 8 0.125000 0 ) ( 464 736 40 0.125000 0.500000 ) ( 464 736 72 0.125000 1 ) ) +( ( 472 736 8 0.250000 0 ) ( 472 736 40 0.250000 0.500000 ) ( 472 736 72 0.250000 1 ) ) +( ( 480 736 8 0.375000 0 ) ( 480 736 40 0.375000 0.500000 ) ( 480 736 72 0.375000 1 ) ) +( ( 480 744 8 0.500000 0 ) ( 480 744 40 0.500000 0.500000 ) ( 480 744 72 0.500000 1 ) ) +( ( 480 752 8 0.625000 0 ) ( 480 752 40 0.625000 0.500000 ) ( 480 752 72 0.625000 1 ) ) +( ( 472 752 8 0.750000 0 ) ( 472 752 40 0.750000 0.500000 ) ( 472 752 72 0.750000 1 ) ) +( ( 464 752 8 0.875000 0 ) ( 464 752 40 0.875000 0.500000 ) ( 464 752 72 0.875000 1 ) ) +( ( 464 744 8 1 0 ) ( 464 744 40 1 0.500000 ) ( 464 744 72 1 1 ) ) +) + } + } +// brush 51 +{ +brushDef +{ +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 312 104 ) ( 528 304 104 ) ( 520 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 524 336 72 ) ( 524 304 72 ) ( 532 304 72 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 524 304 80 ) ( 524 336 80 ) ( 524 304 24 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 52 +{ +brushDef +{ +( 536 304 104 ) ( 536 312 104 ) ( 528 312 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 532 304 80 ) ( 524 304 80 ) ( 524 336 80 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 532 336 128 ) ( 532 304 128 ) ( 532 336 72 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 53 +{ +brushDef +{ +( 536 304 104 ) ( 536 312 104 ) ( 528 312 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 312 104 ) ( 528 304 104 ) ( 520 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 304 96 ) ( 528 336 96 ) ( 536 304 96 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 524 304 80 ) ( 532 304 80 ) ( 524 336 80 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 54 +{ +brushDef +{ +( 520 312 48 ) ( 520 304 48 ) ( 528 304 48 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 536 304 104 ) ( 536 312 104 ) ( 528 312 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 312 104 ) ( 528 304 104 ) ( 520 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 524 304 72 ) ( 524 336 72 ) ( 532 304 72 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 55 +{ +brushDef +{ +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 104 ) ( 528 328 104 ) ( 520 328 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 524 344 72 ) ( 524 312 72 ) ( 532 312 72 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 524 312 80 ) ( 524 344 80 ) ( 524 312 24 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 56 +{ +brushDef +{ +( 536 328 104 ) ( 536 336 104 ) ( 528 336 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 532 312 80 ) ( 524 312 80 ) ( 524 344 80 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 532 344 128 ) ( 532 312 128 ) ( 532 344 72 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 57 +{ +brushDef +{ +( 536 328 104 ) ( 536 336 104 ) ( 528 336 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 104 ) ( 528 328 104 ) ( 520 328 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 304 96 ) ( 528 336 96 ) ( 536 304 96 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 524 312 80 ) ( 532 312 80 ) ( 524 344 80 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 58 +{ +brushDef +{ +( 520 336 48 ) ( 520 328 48 ) ( 528 328 48 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 536 328 104 ) ( 536 336 104 ) ( 528 336 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 104 ) ( 528 328 104 ) ( 520 328 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 524 312 72 ) ( 524 344 72 ) ( 532 312 72 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 59 +{ +brushDef +{ +( 524 336 72 ) ( 524 304 72 ) ( 532 304 72 ) ( ( 0 -0.015625 -4.187500 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 532 304 80 ) ( 524 304 80 ) ( 524 336 80 ) ( ( 0 0.015625 -4.187500 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 532 304 128 ) ( 532 336 128 ) ( 532 336 72 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 532 336 80 ) ( 524 336 80 ) ( 524 336 24 ) ( ( 0.015625 0 5.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 524 336 80 ) ( 524 304 80 ) ( 524 304 24 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 524 304 80 ) ( 532 304 80 ) ( 532 304 24 ) ( ( 0.015625 0 -5.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 60 +{ +brushDef +{ +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 312 104 ) ( 528 304 104 ) ( 520 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 96 ) ( 528 304 96 ) ( 536 304 96 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 528 304 104 ) ( 528 336 104 ) ( 528 304 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 61 +{ +brushDef +{ +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 104 ) ( 528 328 104 ) ( 520 328 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 134217728 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 96 ) ( 528 304 96 ) ( 536 304 96 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 528 304 104 ) ( 528 336 104 ) ( 528 304 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 62 +{ +brushDef +{ +( 528 336 96 ) ( 528 304 96 ) ( 536 304 96 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 536 304 104 ) ( 528 304 104 ) ( 528 336 104 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 536 304 152 ) ( 536 336 152 ) ( 536 336 96 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 536 336 104 ) ( 528 336 104 ) ( 528 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 104 ) ( 528 304 104 ) ( 528 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 304 104 ) ( 536 304 104 ) ( 536 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 63 +{ +brushDef +{ +( 488 336 8 ) ( 496 336 8 ) ( 496 344 8 ) ( ( -0.015625 0 8.125000 ) ( 0 -0.015625 -15 ) ) gothic_trim/wood2 134217728 0 0 +( 504 336 40 ) ( 504 328 40 ) ( 496 328 40 ) ( ( -0.015625 0 8.125000 ) ( 0 -0.015625 15 ) ) gothic_trim/wood2 134217728 0 0 +( 488 344 8 ) ( 496 344 8 ) ( 504 336 40 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 -3.368932 ) ) gothic_trim/wood2 134217728 0 0 +( 488 328 8 ) ( 488 336 8 ) ( 496 336 40 ) ( ( 0.015625 0 13.375000 ) ( 0 0.015625 -1.216441 ) ) gothic_trim/wood2 134217728 0 0 +( 496 336 8 ) ( 488 336 8 ) ( 496 328 40 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 -3.368936 ) ) gothic_trim/wood2 134217728 0 0 +( 496 336 8 ) ( 496 328 8 ) ( 504 328 40 ) ( ( 0.015625 0 -13.375000 ) ( 0 0.015625 -1.216413 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 64 +{ +brushDef +{ +( 496 296 8 ) ( 496 304 8 ) ( 488 304 8 ) ( ( 0 0.015625 11.625000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 496 312 40 ) ( 504 312 40 ) ( 504 304 40 ) ( ( 0 -0.015625 11.625000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 488 296 8 ) ( 488 304 8 ) ( 496 312 40 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -2.580697 ) ) gothic_trim/wood2 134217728 0 0 +( 504 296 8 ) ( 496 296 8 ) ( 496 304 40 ) ( ( 0.015625 0 10.125000 ) ( 0 0.015625 0.299379 ) ) gothic_trim/wood2 134217728 0 0 +( 496 304 8 ) ( 496 296 8 ) ( 504 304 40 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 -2.580694 ) ) gothic_trim/wood2 134217728 0 0 +( 496 304 8 ) ( 504 304 8 ) ( 504 312 40 ) ( ( 0.015625 0 -10.125000 ) ( 0 0.015625 0.299380 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 65 +{ +brushDef +{ +( 536 304 8 ) ( 528 304 8 ) ( 528 296 8 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 520 304 40 ) ( 520 312 40 ) ( 528 312 40 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 -0.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 536 296 8 ) ( 528 296 8 ) ( 520 304 40 ) ( ( 0.015625 0 -1.500000 ) ( 0 0.015625 -0.761721 ) ) gothic_trim/wood2 134217728 0 0 +( 536 312 8 ) ( 536 304 8 ) ( 528 304 40 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -0.488851 ) ) gothic_trim/wood2 134217728 0 0 +( 528 304 8 ) ( 536 304 8 ) ( 528 312 40 ) ( ( 0.015625 0 1.500000 ) ( 0 0.015625 -0.761720 ) ) gothic_trim/wood2 134217728 0 0 +( 528 304 8 ) ( 528 312 8 ) ( 520 312 40 ) ( ( 0.015625 0 -2.625000 ) ( 0 0.015625 -0.488853 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 66 +{ +brushDef +{ +( 528 344 8 ) ( 528 336 8 ) ( 536 336 8 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 528 328 40 ) ( 520 328 40 ) ( 520 336 40 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 536 344 8 ) ( 536 336 8 ) ( 528 328 40 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 -1.368011 ) ) gothic_trim/wood2 134217728 0 0 +( 520 344 8 ) ( 528 344 8 ) ( 528 336 40 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 -2.125928 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 8 ) ( 528 344 8 ) ( 520 336 40 ) ( ( 0.015625 0 8.250001 ) ( 0 0.015625 -1.368012 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 8 ) ( 520 336 8 ) ( 520 328 40 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 -2.125930 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 67 +{ +brushDef +{ +( 496 328 40 ) ( 496 304 40 ) ( 528 304 40 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 528 304 48 ) ( 496 304 48 ) ( 496 328 48 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 528 304 48 ) ( 528 328 48 ) ( 528 328 40 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 528 336 48 ) ( 496 336 48 ) ( 496 336 40 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 496 328 48 ) ( 496 304 48 ) ( 496 304 40 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 496 304 48 ) ( 528 304 48 ) ( 528 304 40 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 68 +{ +brushDef +{ +( 440 352 40 ) ( 464 352 40 ) ( 464 384 40 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 384 48 ) ( 464 352 48 ) ( 440 352 48 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 384 48 ) ( 440 384 48 ) ( 440 384 40 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 48 ) ( 432 352 48 ) ( 432 352 40 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 352 48 ) ( 464 352 48 ) ( 464 352 40 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 352 48 ) ( 464 384 48 ) ( 464 384 40 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 69 +{ +brushDef +{ +( 424 384 8 ) ( 432 384 8 ) ( 432 392 8 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 384 40 ) ( 440 376 40 ) ( 432 376 40 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 424 392 8 ) ( 432 392 8 ) ( 440 384 40 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 -4.035891 ) ) gothic_trim/wood2 134217728 0 0 +( 424 376 8 ) ( 424 384 8 ) ( 432 384 40 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 -1.883390 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 8 ) ( 424 384 8 ) ( 432 376 40 ) ( ( 0.015625 0 7.250001 ) ( 0 0.015625 -4.035891 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 8 ) ( 432 376 8 ) ( 440 376 40 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 -1.883390 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 70 +{ +brushDef +{ +( 464 392 8 ) ( 464 384 8 ) ( 472 384 8 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -13 ) ) gothic_trim/wood2 134217728 0 0 +( 464 376 40 ) ( 456 376 40 ) ( 456 384 40 ) ( ( 0 0.015625 -3.375000 ) ( -0.015625 0 13 ) ) gothic_trim/wood2 134217728 0 0 +( 472 392 8 ) ( 472 384 8 ) ( 464 376 40 ) ( ( 0.015625 0 -12.500000 ) ( 0 0.015625 -1.004194 ) ) gothic_trim/wood2 134217728 0 0 +( 456 392 8 ) ( 464 392 8 ) ( 464 384 40 ) ( ( 0.015625 0 3.625000 ) ( 0 0.015625 -3.156694 ) ) gothic_trim/wood2 134217728 0 0 +( 464 384 8 ) ( 464 392 8 ) ( 456 384 40 ) ( ( 0.015625 0 12.500000 ) ( 0 0.015625 -1.004192 ) ) gothic_trim/wood2 134217728 0 0 +( 464 384 8 ) ( 456 384 8 ) ( 456 376 40 ) ( ( 0.015625 0 -3.625000 ) ( 0 0.015625 -3.156695 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 71 +{ +brushDef +{ +( 472 352 8 ) ( 464 352 8 ) ( 464 344 8 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 352 40 ) ( 456 360 40 ) ( 464 360 40 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 472 344 8 ) ( 464 344 8 ) ( 456 352 40 ) ( ( 0.015625 0 0.750000 ) ( 0 0.015625 0.087216 ) ) gothic_trim/wood2 134217728 0 0 +( 472 360 8 ) ( 472 352 8 ) ( 464 352 40 ) ( ( 0.015625 0 -0.875000 ) ( 0 0.015625 0.056903 ) ) gothic_trim/wood2 134217728 0 0 +( 464 352 8 ) ( 472 352 8 ) ( 464 360 40 ) ( ( 0.015625 0 -0.750000 ) ( 0 0.015625 0.087221 ) ) gothic_trim/wood2 134217728 0 0 +( 464 352 8 ) ( 464 360 8 ) ( 456 360 40 ) ( ( 0.015625 0 0.875000 ) ( 0 0.015625 0.056905 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 72 +{ +brushDef +{ +( 432 344 8 ) ( 432 352 8 ) ( 424 352 8 ) ( ( 0 0.015625 9.875000 ) ( -0.015625 0 -1.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 432 360 40 ) ( 440 360 40 ) ( 440 352 40 ) ( ( 0 -0.015625 9.875000 ) ( 0.015625 0 1.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 424 344 8 ) ( 424 352 8 ) ( 432 360 40 ) ( ( 0.015625 0 6.500000 ) ( 0 0.015625 -3.126388 ) ) gothic_trim/wood2 134217728 0 0 +( 440 344 8 ) ( 432 344 8 ) ( 432 352 40 ) ( ( 0.015625 0 12.375000 ) ( 0 0.015625 1.451483 ) ) gothic_trim/wood2 134217728 0 0 +( 432 352 8 ) ( 432 344 8 ) ( 440 352 40 ) ( ( 0.015625 0 -6.500000 ) ( 0 0.015625 -3.126389 ) ) gothic_trim/wood2 134217728 0 0 +( 432 352 8 ) ( 440 352 8 ) ( 440 360 40 ) ( ( 0.015625 0 -12.375000 ) ( 0 0.015625 1.451492 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 73 +{ +brushDef +{ +( 432 384 96 ) ( 464 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 392 104 ) ( 464 384 104 ) ( 432 384 104 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 392 152 ) ( 432 392 152 ) ( 432 392 96 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 392 104 ) ( 432 384 104 ) ( 432 384 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 104 ) ( 464 384 104 ) ( 464 384 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 384 104 ) ( 464 392 104 ) ( 464 392 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 74 +{ +brushDef +{ +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 104 ) ( 440 384 104 ) ( 440 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 96 ) ( 464 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 384 104 ) ( 432 384 104 ) ( 464 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 75 +{ +brushDef +{ +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 384 104 ) ( 464 384 104 ) ( 464 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 96 ) ( 464 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 384 104 ) ( 432 384 104 ) ( 464 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 76 +{ +brushDef +{ +( 432 380 72 ) ( 464 380 72 ) ( 464 388 72 ) ( ( -0.015625 0 9.312500 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 388 80 ) ( 464 380 80 ) ( 432 380 80 ) ( ( -0.015625 0 9.312500 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 388 128 ) ( 432 388 128 ) ( 432 388 72 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 432 388 80 ) ( 432 380 80 ) ( 432 380 24 ) ( ( 0.015625 0 16.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 432 380 80 ) ( 464 380 80 ) ( 464 380 24 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 380 80 ) ( 464 388 80 ) ( 464 388 24 ) ( ( 0.015625 0 -16.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 77 +{ +brushDef +{ +( 432 376 48 ) ( 440 376 48 ) ( 440 384 48 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 392 104 ) ( 432 392 104 ) ( 432 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 104 ) ( 440 384 104 ) ( 440 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 380 72 ) ( 424 380 72 ) ( 456 388 72 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 78 +{ +brushDef +{ +( 440 392 104 ) ( 432 392 104 ) ( 432 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 104 ) ( 440 384 104 ) ( 440 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 384 96 ) ( 432 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 456 380 80 ) ( 456 388 80 ) ( 424 380 80 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 79 +{ +brushDef +{ +( 440 392 104 ) ( 432 392 104 ) ( 432 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 388 80 ) ( 456 380 80 ) ( 424 380 80 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 424 388 128 ) ( 456 388 128 ) ( 424 388 72 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 80 +{ +brushDef +{ +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 384 104 ) ( 440 384 104 ) ( 440 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 424 380 72 ) ( 456 380 72 ) ( 456 388 72 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 456 380 80 ) ( 424 380 80 ) ( 456 380 24 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 81 +{ +brushDef +{ +( 456 376 48 ) ( 464 376 48 ) ( 464 384 48 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 392 104 ) ( 456 392 104 ) ( 456 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 384 104 ) ( 464 384 104 ) ( 464 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 380 72 ) ( 432 380 72 ) ( 464 388 72 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 82 +{ +brushDef +{ +( 464 392 104 ) ( 456 392 104 ) ( 456 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 384 104 ) ( 464 384 104 ) ( 464 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 384 96 ) ( 432 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 380 80 ) ( 464 388 80 ) ( 432 380 80 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 83 +{ +brushDef +{ +( 464 392 104 ) ( 456 392 104 ) ( 456 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 388 80 ) ( 464 380 80 ) ( 432 380 80 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 432 388 128 ) ( 464 388 128 ) ( 432 388 72 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 84 +{ +brushDef +{ +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 384 104 ) ( 464 384 104 ) ( 464 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 134217728 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 380 72 ) ( 464 380 72 ) ( 464 388 72 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 380 80 ) ( 432 380 80 ) ( 464 380 24 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 85 +{ +brushDef +{ +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 216 104 ) ( 432 216 104 ) ( 432 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 220 72 ) ( 432 220 72 ) ( 432 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 220 80 ) ( 464 220 80 ) ( 432 220 24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 86 +{ +brushDef +{ +( 432 208 104 ) ( 440 208 104 ) ( 440 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 212 80 ) ( 432 220 80 ) ( 464 220 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 212 128 ) ( 432 212 128 ) ( 464 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 87 +{ +brushDef +{ +( 432 208 104 ) ( 440 208 104 ) ( 440 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 216 104 ) ( 432 216 104 ) ( 432 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 216 96 ) ( 464 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 220 80 ) ( 432 212 80 ) ( 464 220 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 88 +{ +brushDef +{ +( 440 224 48 ) ( 432 224 48 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 208 104 ) ( 440 208 104 ) ( 440 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 216 104 ) ( 432 216 104 ) ( 432 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 220 72 ) ( 464 220 72 ) ( 432 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 89 +{ +brushDef +{ +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 328 104 ) ( 360 336 104 ) ( 368 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 364 304 72 ) ( 364 336 72 ) ( 356 336 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 364 336 80 ) ( 364 304 80 ) ( 364 336 24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 90 +{ +brushDef +{ +( 352 336 104 ) ( 352 328 104 ) ( 360 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 356 336 80 ) ( 364 336 80 ) ( 364 304 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 356 304 128 ) ( 356 336 128 ) ( 356 304 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 91 +{ +brushDef +{ +( 352 336 104 ) ( 352 328 104 ) ( 360 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 328 104 ) ( 360 336 104 ) ( 368 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 336 96 ) ( 360 304 96 ) ( 352 336 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 364 336 80 ) ( 356 336 80 ) ( 364 304 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 92 +{ +brushDef +{ +( 368 328 48 ) ( 368 336 48 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 352 336 104 ) ( 352 328 104 ) ( 360 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 328 104 ) ( 360 336 104 ) ( 368 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 364 336 72 ) ( 364 304 72 ) ( 356 336 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 93 +{ +brushDef +{ +( 392 312 40 ) ( 392 336 40 ) ( 360 336 40 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 360 336 48 ) ( 392 336 48 ) ( 392 312 48 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 360 336 48 ) ( 360 312 48 ) ( 360 312 40 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 48 ) ( 392 304 48 ) ( 392 304 40 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 392 312 48 ) ( 392 336 48 ) ( 392 336 40 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 392 336 48 ) ( 360 336 48 ) ( 360 336 40 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 94 +{ +brushDef +{ +( 360 296 8 ) ( 360 304 8 ) ( 352 304 8 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 360 312 40 ) ( 368 312 40 ) ( 368 304 40 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 352 296 8 ) ( 352 304 8 ) ( 360 312 40 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 -2.914160 ) ) gothic_trim/wood2 134217728 0 0 +( 368 296 8 ) ( 360 296 8 ) ( 360 304 40 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0.966415 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 8 ) ( 360 296 8 ) ( 368 304 40 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 -2.914160 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 8 ) ( 368 304 8 ) ( 368 312 40 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0.966415 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 95 +{ +brushDef +{ +( 352 336 8 ) ( 360 336 8 ) ( 360 344 8 ) ( ( -0.015625 0 8.375000 ) ( 0 -0.015625 -13.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 368 336 40 ) ( 368 328 40 ) ( 360 328 40 ) ( ( -0.015625 0 8.375000 ) ( 0 -0.015625 13.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 352 344 8 ) ( 360 344 8 ) ( 368 336 40 ) ( ( 0.015625 0 -7.875000 ) ( 0 0.015625 -3.853989 ) ) gothic_trim/wood2 134217728 0 0 +( 352 328 8 ) ( 352 336 8 ) ( 360 336 40 ) ( ( 0.015625 0 15.375000 ) ( 0 0.015625 -2.034964 ) ) gothic_trim/wood2 134217728 0 0 +( 360 336 8 ) ( 352 336 8 ) ( 360 328 40 ) ( ( 0.015625 0 7.875002 ) ( 0 0.015625 -3.853986 ) ) gothic_trim/wood2 134217728 0 0 +( 360 336 8 ) ( 360 328 8 ) ( 368 328 40 ) ( ( 0.015625 0 -15.375000 ) ( 0 0.015625 -2.034965 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 96 +{ +brushDef +{ +( 392 344 8 ) ( 392 336 8 ) ( 400 336 8 ) ( ( 0 -0.015625 -2 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 392 328 40 ) ( 384 328 40 ) ( 384 336 40 ) ( ( 0 0.015625 -2 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 400 344 8 ) ( 400 336 8 ) ( 392 328 40 ) ( ( 0.015625 0 -11 ) ( 0 0.015625 -1.034511 ) ) gothic_trim/wood2 134217728 0 0 +( 384 344 8 ) ( 392 344 8 ) ( 392 336 40 ) ( ( 0.015625 0 3.750001 ) ( 0 0.015625 -2.792890 ) ) gothic_trim/wood2 134217728 0 0 +( 392 336 8 ) ( 392 344 8 ) ( 384 336 40 ) ( ( 0.015625 0 11 ) ( 0 0.015625 -1.034512 ) ) gothic_trim/wood2 134217728 0 0 +( 392 336 8 ) ( 384 336 8 ) ( 384 328 40 ) ( ( 0.015625 0 -3.750000 ) ( 0 0.015625 -2.792888 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 97 +{ +brushDef +{ +( 400 304 8 ) ( 392 304 8 ) ( 392 296 8 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 -1.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 384 304 40 ) ( 384 312 40 ) ( 392 312 40 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 1.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 400 296 8 ) ( 392 296 8 ) ( 384 304 40 ) ( ( 0.015625 0 1.875001 ) ( 0 0.015625 -0.276583 ) ) gothic_trim/wood2 134217728 0 0 +( 400 312 8 ) ( 400 304 8 ) ( 392 304 40 ) ( ( 0.015625 0 0.625000 ) ( 0 0.015625 0.329756 ) ) gothic_trim/wood2 134217728 0 0 +( 392 304 8 ) ( 400 304 8 ) ( 392 312 40 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 -0.276584 ) ) gothic_trim/wood2 134217728 0 0 +( 392 304 8 ) ( 392 312 8 ) ( 384 312 40 ) ( ( 0.015625 0 -0.625000 ) ( 0 0.015625 0.329758 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 98 +{ +brushDef +{ +( 360 304 96 ) ( 360 336 96 ) ( 352 336 96 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 352 336 104 ) ( 360 336 104 ) ( 360 304 104 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 352 336 152 ) ( 352 304 152 ) ( 352 304 96 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 352 304 104 ) ( 360 304 104 ) ( 360 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 104 ) ( 360 336 104 ) ( 360 336 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 336 104 ) ( 352 336 104 ) ( 352 336 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 99 +{ +brushDef +{ +( 360 304 80 ) ( 368 304 80 ) ( 368 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 104 ) ( 360 312 104 ) ( 368 312 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 134217728 0 0 +( 368 312 80 ) ( 360 312 80 ) ( 360 312 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 96 ) ( 360 336 96 ) ( 352 336 96 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 360 336 104 ) ( 360 304 104 ) ( 360 336 48 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 100 +{ +brushDef +{ +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 328 104 ) ( 360 336 104 ) ( 368 336 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 134217728 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 96 ) ( 360 336 96 ) ( 352 336 96 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 360 336 104 ) ( 360 304 104 ) ( 360 336 48 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 101 +{ +brushDef +{ +( 364 304 72 ) ( 364 336 72 ) ( 356 336 72 ) ( ( 0 0.015625 9.437500 ) ( -0.015625 0 -1.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 356 336 80 ) ( 364 336 80 ) ( 364 304 80 ) ( ( 0 -0.015625 9.437500 ) ( 0.015625 0 1.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 356 336 128 ) ( 356 304 128 ) ( 356 304 72 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 356 304 80 ) ( 364 304 80 ) ( 364 304 24 ) ( ( 0.015625 0 11.437500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 364 304 80 ) ( 364 336 80 ) ( 364 336 24 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 364 336 80 ) ( 356 336 80 ) ( 356 336 24 ) ( ( 0.015625 0 -11.437500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 102 +{ +brushDef +{ +( 368 304 48 ) ( 368 312 48 ) ( 360 312 48 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 352 312 104 ) ( 352 304 104 ) ( 360 304 48 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 80 ) ( 368 304 80 ) ( 368 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 104 ) ( 360 312 104 ) ( 368 312 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 134217728 0 0 +( 368 312 80 ) ( 360 312 80 ) ( 360 312 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 364 328 72 ) ( 364 296 72 ) ( 356 328 72 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 103 +{ +brushDef +{ +( 352 312 104 ) ( 352 304 104 ) ( 360 304 48 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 80 ) ( 368 304 80 ) ( 368 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 104 ) ( 360 312 104 ) ( 368 312 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 134217728 0 0 +( 368 312 80 ) ( 360 312 80 ) ( 360 312 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 336 96 ) ( 360 304 96 ) ( 352 336 96 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 364 328 80 ) ( 356 328 80 ) ( 364 296 80 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 104 +{ +brushDef +{ +( 360 304 80 ) ( 368 304 80 ) ( 368 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 360 304 104 ) ( 360 312 104 ) ( 368 312 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 134217728 0 0 +( 368 312 80 ) ( 360 312 80 ) ( 360 312 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 364 296 72 ) ( 364 328 72 ) ( 356 328 72 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 364 328 80 ) ( 364 296 80 ) ( 364 328 24 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 105 +{ +brushDef +{ +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 104 ) ( 456 216 104 ) ( 456 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 472 220 72 ) ( 440 220 72 ) ( 440 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 220 80 ) ( 472 220 80 ) ( 440 220 24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 106 +{ +brushDef +{ +( 456 208 104 ) ( 464 208 104 ) ( 464 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 212 80 ) ( 440 220 80 ) ( 472 220 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 472 212 128 ) ( 440 212 128 ) ( 472 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 107 +{ +brushDef +{ +( 456 208 104 ) ( 464 208 104 ) ( 464 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 104 ) ( 456 216 104 ) ( 456 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 216 96 ) ( 464 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 220 80 ) ( 440 212 80 ) ( 472 220 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 108 +{ +brushDef +{ +( 464 224 48 ) ( 456 224 48 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 208 104 ) ( 464 208 104 ) ( 464 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 104 ) ( 456 216 104 ) ( 456 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 220 72 ) ( 472 220 72 ) ( 440 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 109 +{ +brushDef +{ +( 464 220 72 ) ( 432 220 72 ) ( 432 212 72 ) ( ( 0.015625 0 -0.062500 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 212 80 ) ( 432 220 80 ) ( 464 220 80 ) ( ( 0.015625 0 -0.062500 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 212 128 ) ( 464 212 128 ) ( 464 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 212 80 ) ( 464 220 80 ) ( 464 220 24 ) ( ( 0.015625 0 -0.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 220 80 ) ( 432 220 80 ) ( 432 220 24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 432 220 80 ) ( 432 212 80 ) ( 432 212 24 ) ( ( 0.015625 0 0.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 110 +{ +brushDef +{ +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 216 104 ) ( 432 216 104 ) ( 432 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 96 ) ( 432 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 216 104 ) ( 464 216 104 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 111 +{ +brushDef +{ +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 104 ) ( 456 216 104 ) ( 456 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 96 ) ( 432 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 216 104 ) ( 464 216 104 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 112 +{ +brushDef +{ +( 464 216 96 ) ( 432 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 208 104 ) ( 432 216 104 ) ( 464 216 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 208 152 ) ( 464 208 152 ) ( 464 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 208 104 ) ( 464 216 104 ) ( 464 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 104 ) ( 432 216 104 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 216 104 ) ( 432 208 104 ) ( 432 208 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 113 +{ +brushDef +{ +( 464 256 8 ) ( 464 248 8 ) ( 472 248 8 ) ( ( 0 -0.015625 -3.625000 ) ( 0.015625 0 -10.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 240 40 ) ( 456 240 40 ) ( 456 248 40 ) ( ( 0 0.015625 -3.625000 ) ( -0.015625 0 10.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 472 256 8 ) ( 472 248 8 ) ( 464 240 40 ) ( ( 0.015625 0 -9.625000 ) ( 0 0.015625 -1.367998 ) ) gothic_trim/wood2 134217728 0 0 +( 456 256 8 ) ( 464 256 8 ) ( 464 248 40 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 -2.459404 ) ) gothic_trim/wood2 134217728 0 0 +( 464 248 8 ) ( 464 256 8 ) ( 456 248 40 ) ( ( 0.015625 0 9.625000 ) ( 0 0.015625 -1.367999 ) ) gothic_trim/wood2 134217728 0 0 +( 464 248 8 ) ( 456 248 8 ) ( 456 240 40 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 -2.459402 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 114 +{ +brushDef +{ +( 424 248 8 ) ( 432 248 8 ) ( 432 256 8 ) ( ( -0.015625 0 7.500000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 248 40 ) ( 440 240 40 ) ( 432 240 40 ) ( ( -0.015625 0 7.500000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 424 256 8 ) ( 432 256 8 ) ( 440 248 40 ) ( ( 0.015625 0 -6.500000 ) ( 0 0.015625 -3.823671 ) ) gothic_trim/wood2 134217728 0 0 +( 424 240 8 ) ( 424 248 8 ) ( 432 248 40 ) ( ( 0.015625 0 15.250000 ) ( 0 0.015625 -1.701477 ) ) gothic_trim/wood2 134217728 0 0 +( 432 248 8 ) ( 424 248 8 ) ( 432 240 40 ) ( ( 0.015625 0 6.500000 ) ( 0 0.015625 -3.823672 ) ) gothic_trim/wood2 134217728 0 0 +( 432 248 8 ) ( 432 240 8 ) ( 440 240 40 ) ( ( 0.015625 0 -15.250000 ) ( 0 0.015625 -1.701478 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 115 +{ +brushDef +{ +( 432 208 8 ) ( 432 216 8 ) ( 424 216 8 ) ( ( 0 0.015625 10.125000 ) ( -0.015625 0 -3.625000 ) ) gothic_trim/wood2 134217728 0 0 +( 432 224 40 ) ( 440 224 40 ) ( 440 216 40 ) ( ( 0 -0.015625 10.125000 ) ( 0.015625 0 3.625000 ) ) gothic_trim/wood2 134217728 0 0 +( 424 208 8 ) ( 424 216 8 ) ( 432 224 40 ) ( ( 0.015625 0 3.625000 ) ( 0 0.015625 -2.762575 ) ) gothic_trim/wood2 134217728 0 0 +( 440 208 8 ) ( 432 208 8 ) ( 432 216 40 ) ( ( 0.015625 0 10.875000 ) ( 0 0.015625 0.754196 ) ) gothic_trim/wood2 134217728 0 0 +( 432 216 8 ) ( 432 208 8 ) ( 440 216 40 ) ( ( 0.015625 0 -3.625000 ) ( 0 0.015625 -2.762575 ) ) gothic_trim/wood2 134217728 0 0 +( 432 216 8 ) ( 440 216 8 ) ( 440 224 40 ) ( ( 0.015625 0 -10.875000 ) ( 0 0.015625 0.754195 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 116 +{ +brushDef +{ +( 472 216 8 ) ( 464 216 8 ) ( 464 208 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 216 40 ) ( 456 224 40 ) ( 464 224 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 472 208 8 ) ( 464 208 8 ) ( 456 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 472 224 8 ) ( 472 216 8 ) ( 464 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 8 ) ( 472 216 8 ) ( 464 224 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 8 ) ( 464 224 8 ) ( 456 224 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 117 +{ +brushDef +{ +( 456 248 40 ) ( 432 248 40 ) ( 432 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 216 48 ) ( 432 248 48 ) ( 456 248 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 216 48 ) ( 456 216 48 ) ( 456 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 464 216 48 ) ( 464 248 48 ) ( 464 248 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 248 48 ) ( 432 248 48 ) ( 432 248 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 432 248 48 ) ( 432 216 48 ) ( 432 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 118 +{ +brushDef +{ +( 336 256 288 ) ( 0 256 288 ) ( 0 136 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 136 296 ) ( 0 256 296 ) ( 336 256 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 136 296 ) ( 336 136 296 ) ( 336 136 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 512 128 296 ) ( 512 248 296 ) ( 512 248 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 336 256 296 ) ( 0 256 296 ) ( 0 256 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 256 296 ) ( 0 136 296 ) ( 0 136 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 119 +{ +brushDef +{ +( 632 96 288 ) ( 512 96 288 ) ( 512 40 288 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 4.937803 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 512 8 296 ) ( 512 64 296 ) ( 632 64 296 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 -4.937810 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 544 136 296 ) ( 664 136 296 ) ( 664 136 -208 ) ( ( 0.007813 0 -4.937810 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 632 8 296 ) ( 632 64 296 ) ( 632 64 -208 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 632 448 296 ) ( 512 448 296 ) ( 512 448 -208 ) ( ( 0.007812 0 4.937197 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 512 64 296 ) ( 512 8 296 ) ( 512 8 -208 ) ( ( 0.007813 0 -2.937500 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 120 +{ +brushDef +{ +( 0 96 288 ) ( -120 96 288 ) ( -120 40 288 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -120 8 296 ) ( -120 64 296 ) ( 0 64 296 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -88 136 296 ) ( 32 136 296 ) ( 32 136 -208 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 8 296 ) ( 0 64 296 ) ( 0 64 -208 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 448 296 ) ( -120 448 296 ) ( -120 448 -208 ) ( ( 0.007812 0 0 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -120 64 296 ) ( -120 8 296 ) ( -120 8 -208 ) ( ( 0.007813 0 -2.937500 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 121 +{ +brushDef +{ +( 48 680 8 ) ( 32 680 8 ) ( 32 664 8 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 -1.000055 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 32 664 512 ) ( 32 680 512 ) ( 48 680 512 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 1.000055 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 24 664 112 ) ( 40 664 112 ) ( 40 664 104 ) ( ( 0.007813 0 1.000055 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 40 664 112 ) ( 40 680 112 ) ( 40 680 104 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 40 680 112 ) ( 24 680 112 ) ( 24 680 104 ) ( ( 0.007813 0 -1.000055 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 24 680 112 ) ( 24 664 112 ) ( 24 664 104 ) ( ( 0.007813 0 2.000125 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 122 +{ +brushDef +{ +( 496 680 8 ) ( 480 680 8 ) ( 480 664 8 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 2.500159 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 480 664 512 ) ( 480 680 512 ) ( 496 680 512 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 -2.500159 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 472 664 112 ) ( 488 664 112 ) ( 488 664 104 ) ( ( 0.007813 0 -2.500159 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 488 664 112 ) ( 488 680 112 ) ( 488 680 104 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 488 680 112 ) ( 472 680 112 ) ( 472 680 104 ) ( ( 0.007813 0 2.500159 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 472 680 112 ) ( 472 664 112 ) ( 472 664 104 ) ( ( 0.007813 0 2.000125 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 123 +{ +brushDef +{ +( 368 424 8 ) ( 352 424 8 ) ( 352 408 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 1.500098 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 352 408 512 ) ( 352 424 512 ) ( 368 424 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.500098 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 344 408 112 ) ( 360 408 112 ) ( 360 408 104 ) ( ( 0.007813 0 -1.500098 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 360 408 112 ) ( 360 424 112 ) ( 360 424 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 360 424 112 ) ( 344 424 112 ) ( 344 424 104 ) ( ( 0.007813 0 1.500098 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 344 424 112 ) ( 344 408 112 ) ( 344 408 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 124 +{ +brushDef +{ +( 176 424 8 ) ( 160 424 8 ) ( 160 408 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 160 408 512 ) ( 160 424 512 ) ( 176 424 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 152 408 112 ) ( 168 408 112 ) ( 168 408 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 168 408 112 ) ( 168 424 112 ) ( 168 424 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 168 424 112 ) ( 152 424 112 ) ( 152 424 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 152 424 112 ) ( 152 408 112 ) ( 152 408 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 125 +{ +brushDef +{ +( 640 968 0 ) ( 336 968 0 ) ( 336 960 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 336 960 512 ) ( 336 968 512 ) ( 640 968 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -96 960 512 ) ( 208 960 512 ) ( 208 960 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 960 512 ) ( 640 968 512 ) ( 640 968 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 968 512 ) ( 336 968 512 ) ( 336 968 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 944 512 ) ( -128 936 512 ) ( -128 936 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 126 +{ +brushDef +{ +( 640 600 8 ) ( 640 632 8 ) ( 632 632 8 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 640 512 ) ( 640 640 512 ) ( 640 608 512 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 632 640 512 ) ( 632 608 512 ) ( 632 608 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 512 512 ) ( 640 512 512 ) ( 640 512 8 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 512 512 ) ( 640 544 512 ) ( 640 544 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 512 ) ( 632 640 512 ) ( 632 640 8 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 127 +{ +brushDef +{ +( 640 192 8 ) ( 640 512 8 ) ( 632 512 8 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 136 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 640 456 16 ) ( 640 456 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 512 208 ) ( 632 512 208 ) ( 632 512 200 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 480 104 ) ( 640 376 104 ) ( 632 480 104 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 128 +{ +brushDef +{ +( 632 512 512 ) ( 640 512 512 ) ( 640 192 512 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 136 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 640 456 16 ) ( 640 456 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 512 208 ) ( 632 512 208 ) ( 632 512 200 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 480 232 ) ( 632 480 232 ) ( 640 376 232 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 129 +{ +brushDef +{ +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 192 16 ) ( 640 512 16 ) ( 640 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 512 208 ) ( 632 512 208 ) ( 632 512 200 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 376 104 ) ( 640 480 104 ) ( 632 480 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 480 232 ) ( 640 480 232 ) ( 640 376 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 632 480 128 ) ( 640 480 128 ) ( 632 480 104 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 130 +{ +brushDef +{ +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 136 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 640 456 16 ) ( 640 456 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 376 104 ) ( 640 480 104 ) ( 632 480 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 480 232 ) ( 640 480 232 ) ( 640 376 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 640 224 128 ) ( 632 224 128 ) ( 640 224 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 131 +{ +brushDef +{ +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 192 16 ) ( 640 512 16 ) ( 640 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 376 104 ) ( 640 480 104 ) ( 632 480 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 480 232 ) ( 640 480 232 ) ( 640 376 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 640 376 128 ) ( 632 376 128 ) ( 640 376 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 328 128 ) ( 640 328 128 ) ( 632 328 104 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 132 +{ +brushDef +{ +( 640 640 8 ) ( 640 960 8 ) ( 632 960 8 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 640 208 ) ( 640 640 208 ) ( 640 640 200 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 960 16 ) ( 632 960 16 ) ( 632 960 8 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 776 104 ) ( 648 672 104 ) ( 640 776 104 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 133 +{ +brushDef +{ +( 632 960 512 ) ( 640 960 512 ) ( 640 640 512 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 640 208 ) ( 640 640 208 ) ( 640 640 200 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 960 16 ) ( 632 960 16 ) ( 632 960 8 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 776 232 ) ( 640 776 232 ) ( 648 672 232 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 134 +{ +brushDef +{ +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 640 208 ) ( 640 640 208 ) ( 640 640 200 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 672 104 ) ( 648 776 104 ) ( 640 776 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 640 776 232 ) ( 648 776 232 ) ( 648 672 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 648 672 128 ) ( 640 672 128 ) ( 648 672 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 135 +{ +brushDef +{ +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 672 104 ) ( 648 776 104 ) ( 640 776 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 640 776 232 ) ( 648 776 232 ) ( 648 672 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 640 776 128 ) ( 648 776 128 ) ( 640 776 104 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 824 128 ) ( 640 824 128 ) ( 648 824 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 136 +{ +brushDef +{ +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 960 16 ) ( 632 960 16 ) ( 632 960 8 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 672 104 ) ( 648 776 104 ) ( 640 776 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 640 776 232 ) ( 648 776 232 ) ( 648 672 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 640 928 128 ) ( 648 928 128 ) ( 640 928 104 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 137 +{ +brushDef +{ +( 632 824 176 ) ( 640 824 176 ) ( 640 824 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 3.000001 ) ) gothic_trim/wood2 134217728 0 0 +( 640 928 168 ) ( 640 928 176 ) ( 632 928 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.999999 ) ) gothic_trim/wood2 134217728 0 0 +( 640 824 168 ) ( 632 824 168 ) ( 632 800 168 ) ( ( 0 -0.015625 -14.500000 ) ( 0.015625 0 -8.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 832 168 ) ( 632 832 176 ) ( 632 808 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -12.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 824 176 ) ( 640 824 176 ) ( 640 800 176 ) ( ( 0 -0.015625 14.500000 ) ( 0.015625 0 -8.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 640 848 176 ) ( 640 848 168 ) ( 640 824 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -12.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 138 +{ +brushDef +{ +( 640 872 104 ) ( 640 880 104 ) ( 632 880 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 134217728 0 0 +( 632 880 128 ) ( 632 872 128 ) ( 632 872 104 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 872 136 ) ( 640 872 136 ) ( 640 872 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 872 128 ) ( 640 880 128 ) ( 640 880 104 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 880 128 ) ( 632 880 128 ) ( 632 880 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 824 168 ) ( 640 824 168 ) ( 632 800 168 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 139 +{ +brushDef +{ +( 632 880 232 ) ( 640 880 232 ) ( 640 872 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 134217728 0 0 +( 632 880 128 ) ( 632 872 128 ) ( 632 872 104 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 872 136 ) ( 640 872 136 ) ( 640 872 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 872 128 ) ( 640 880 128 ) ( 640 880 104 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 880 128 ) ( 632 880 128 ) ( 632 880 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 824 176 ) ( 632 824 176 ) ( 640 800 176 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 140 +{ +brushDef +{ +( 632 728 232 ) ( 640 728 232 ) ( 640 720 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -7.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 728 128 ) ( 632 720 128 ) ( 632 720 104 ) ( ( 0.015625 0 6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 720 136 ) ( 640 720 136 ) ( 640 720 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 720 128 ) ( 640 728 128 ) ( 640 728 104 ) ( ( 0.015625 0 -6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 728 128 ) ( 632 728 128 ) ( 632 728 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 672 176 ) ( 632 672 176 ) ( 640 648 176 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 7.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 141 +{ +brushDef +{ +( 640 720 104 ) ( 640 728 104 ) ( 632 728 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 7.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 728 128 ) ( 632 720 128 ) ( 632 720 104 ) ( ( 0.015625 0 6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 720 136 ) ( 640 720 136 ) ( 640 720 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 720 128 ) ( 640 728 128 ) ( 640 728 104 ) ( ( 0.015625 0 -6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 728 128 ) ( 632 728 128 ) ( 632 728 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 672 168 ) ( 640 672 168 ) ( 632 648 168 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -7.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 142 +{ +brushDef +{ +( 632 672 176 ) ( 640 672 176 ) ( 640 672 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 3.000001 ) ) gothic_trim/wood2 134217728 0 0 +( 640 776 168 ) ( 640 776 176 ) ( 632 776 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.999999 ) ) gothic_trim/wood2 134217728 0 0 +( 640 672 168 ) ( 632 672 168 ) ( 632 648 168 ) ( ( 0 -0.015625 -14.500000 ) ( 0.015625 0 -10.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 680 168 ) ( 632 680 176 ) ( 632 656 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -10 ) ) gothic_trim/wood2 134217728 0 0 +( 632 672 176 ) ( 640 672 176 ) ( 640 648 176 ) ( ( 0 -0.015625 14.500000 ) ( 0.015625 0 -10.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 640 696 176 ) ( 640 696 168 ) ( 640 672 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -10 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 143 +{ +brushDef +{ +( 632 376 176 ) ( 640 376 176 ) ( 640 376 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 3.000001 ) ) gothic_trim/wood2 134217728 0 0 +( 640 480 168 ) ( 640 480 176 ) ( 632 480 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.999999 ) ) gothic_trim/wood2 134217728 0 0 +( 640 376 168 ) ( 632 376 168 ) ( 632 352 168 ) ( ( 0 -0.015625 -14.500000 ) ( 0.015625 0 -15.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 384 168 ) ( 632 384 176 ) ( 632 360 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -5.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 376 176 ) ( 640 376 176 ) ( 640 352 176 ) ( ( 0 -0.015625 14.500000 ) ( 0.015625 0 -15.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 640 400 176 ) ( 640 400 168 ) ( 640 376 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -5.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 144 +{ +brushDef +{ +( 640 424 104 ) ( 640 432 104 ) ( 632 432 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 12 ) ) gothic_trim/wood2 134217728 0 0 +( 632 432 128 ) ( 632 424 128 ) ( 632 424 104 ) ( ( 0.015625 0 2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 424 136 ) ( 640 424 136 ) ( 640 424 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 424 128 ) ( 640 432 128 ) ( 640 432 104 ) ( ( 0.015625 0 -2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 432 128 ) ( 632 432 128 ) ( 632 432 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 376 168 ) ( 640 376 168 ) ( 632 352 168 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -12 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 145 +{ +brushDef +{ +( 632 432 232 ) ( 640 432 232 ) ( 640 424 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -12 ) ) gothic_trim/wood2 134217728 0 0 +( 632 432 128 ) ( 632 424 128 ) ( 632 424 104 ) ( ( 0.015625 0 2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 424 136 ) ( 640 424 136 ) ( 640 424 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 424 128 ) ( 640 432 128 ) ( 640 432 104 ) ( ( 0.015625 0 -2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 432 128 ) ( 632 432 128 ) ( 632 432 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 376 176 ) ( 632 376 176 ) ( 640 352 176 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 12 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 146 +{ +brushDef +{ +( 632 280 232 ) ( 640 280 232 ) ( 640 272 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -14.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 280 128 ) ( 632 272 128 ) ( 632 272 104 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 272 136 ) ( 640 272 136 ) ( 640 272 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 272 128 ) ( 640 280 128 ) ( 640 280 104 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 280 128 ) ( 632 280 128 ) ( 632 280 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 224 176 ) ( 632 224 176 ) ( 640 200 176 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 14.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 147 +{ +brushDef +{ +( 640 272 104 ) ( 640 280 104 ) ( 632 280 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 14.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 280 128 ) ( 632 272 128 ) ( 632 272 104 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 272 136 ) ( 640 272 136 ) ( 640 272 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 272 128 ) ( 640 280 128 ) ( 640 280 104 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 280 128 ) ( 632 280 128 ) ( 632 280 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 224 168 ) ( 640 224 168 ) ( 632 200 168 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -14.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 148 +{ +brushDef +{ +( 632 224 176 ) ( 640 224 176 ) ( 640 224 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 3.000001 ) ) gothic_trim/wood2 134217728 0 0 +( 640 328 168 ) ( 640 328 176 ) ( 632 328 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.999999 ) ) gothic_trim/wood2 134217728 0 0 +( 640 224 168 ) ( 632 224 168 ) ( 632 200 168 ) ( ( 0 -0.015625 -14.500000 ) ( 0.015625 0 -17.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 232 168 ) ( 632 232 176 ) ( 632 208 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -3 ) ) gothic_trim/wood2 134217728 0 0 +( 632 224 176 ) ( 640 224 176 ) ( 640 200 176 ) ( ( 0 -0.015625 14.500000 ) ( 0.015625 0 -17.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 640 248 176 ) ( 640 248 168 ) ( 640 224 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -3 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 149 +{ +brushDef +{ +( -120 616 8 ) ( -120 648 8 ) ( -128 648 8 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 640 512 ) ( -120 640 512 ) ( -120 608 512 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -128 640 512 ) ( -128 608 512 ) ( -128 608 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 512 512 ) ( -120 512 512 ) ( -120 512 8 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 512 512 ) ( -120 544 512 ) ( -120 544 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 512 ) ( -128 640 512 ) ( -128 640 8 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 150 +{ +brushDef +{ +( -120 192 8 ) ( -120 512 8 ) ( -128 512 8 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -120 136 16 ) ( -120 136 8 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 136 16 ) ( -120 456 16 ) ( -120 456 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 512 208 ) ( -128 512 208 ) ( -128 512 200 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 480 104 ) ( -120 376 104 ) ( -128 480 104 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 151 +{ +brushDef +{ +( -128 512 512 ) ( -120 512 512 ) ( -120 192 512 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -120 136 16 ) ( -120 136 8 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 192 16 ) ( -120 512 16 ) ( -120 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 512 208 ) ( -128 512 208 ) ( -128 512 200 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 480 232 ) ( -128 480 232 ) ( -120 376 232 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 152 +{ +brushDef +{ +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 192 16 ) ( -120 512 16 ) ( -120 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 512 208 ) ( -128 512 208 ) ( -128 512 200 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 376 104 ) ( -120 480 104 ) ( -128 480 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 480 232 ) ( -120 480 232 ) ( -120 376 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -128 480 128 ) ( -120 480 128 ) ( -128 480 104 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 153 +{ +brushDef +{ +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -120 136 16 ) ( -120 136 8 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 192 16 ) ( -120 512 16 ) ( -120 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 376 104 ) ( -120 480 104 ) ( -128 480 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 480 232 ) ( -120 480 232 ) ( -120 376 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -120 224 128 ) ( -128 224 128 ) ( -120 224 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 154 +{ +brushDef +{ +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 192 16 ) ( -120 512 16 ) ( -120 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 376 104 ) ( -120 480 104 ) ( -128 480 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 480 232 ) ( -120 480 232 ) ( -120 376 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -120 376 128 ) ( -128 376 128 ) ( -120 376 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 328 128 ) ( -120 328 128 ) ( -128 328 104 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 155 +{ +brushDef +{ +( -120 640 8 ) ( -120 960 8 ) ( -128 960 8 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 640 208 ) ( -120 640 208 ) ( -120 640 200 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 960 16 ) ( -128 960 16 ) ( -128 960 8 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 776 104 ) ( -112 672 104 ) ( -120 776 104 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 156 +{ +brushDef +{ +( -128 960 512 ) ( -120 960 512 ) ( -120 640 512 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 640 208 ) ( -120 640 208 ) ( -120 640 200 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 960 16 ) ( -128 960 16 ) ( -128 960 8 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 776 232 ) ( -120 776 232 ) ( -112 672 232 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 157 +{ +brushDef +{ +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 640 208 ) ( -120 640 208 ) ( -120 640 200 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 672 104 ) ( -112 776 104 ) ( -120 776 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -120 776 232 ) ( -112 776 232 ) ( -112 672 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -112 672 128 ) ( -120 672 128 ) ( -112 672 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 158 +{ +brushDef +{ +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 672 104 ) ( -112 776 104 ) ( -120 776 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -120 776 232 ) ( -112 776 232 ) ( -112 672 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -120 776 128 ) ( -112 776 128 ) ( -120 776 104 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 824 128 ) ( -120 824 128 ) ( -112 824 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 159 +{ +brushDef +{ +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 960 16 ) ( -128 960 16 ) ( -128 960 8 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 672 104 ) ( -112 776 104 ) ( -120 776 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -120 776 232 ) ( -112 776 232 ) ( -112 672 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -120 928 128 ) ( -112 928 128 ) ( -120 928 104 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 160 +{ +brushDef +{ +( -128 824 176 ) ( -120 824 176 ) ( -120 824 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 14.875021 ) ) gothic_trim/wood2 134217728 0 0 +( -120 928 168 ) ( -120 928 176 ) ( -128 928 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -14.874980 ) ) gothic_trim/wood2 134217728 0 0 +( -120 824 168 ) ( -128 824 168 ) ( -128 800 168 ) ( ( 0 -0.015625 -2.625000 ) ( 0.015625 0 -8.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 832 168 ) ( -128 832 176 ) ( -128 808 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -12.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 824 176 ) ( -120 824 176 ) ( -120 800 176 ) ( ( 0 -0.015625 2.625000 ) ( 0.015625 0 -8.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -120 848 176 ) ( -120 848 168 ) ( -120 824 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -12.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 161 +{ +brushDef +{ +( -120 872 104 ) ( -120 880 104 ) ( -128 880 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 134217728 0 0 +( -128 880 128 ) ( -128 872 128 ) ( -128 872 104 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 872 136 ) ( -120 872 136 ) ( -120 872 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 872 128 ) ( -120 880 128 ) ( -120 880 104 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 880 128 ) ( -128 880 128 ) ( -128 880 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 824 168 ) ( -120 824 168 ) ( -128 800 168 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 162 +{ +brushDef +{ +( -128 880 232 ) ( -120 880 232 ) ( -120 872 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 134217728 0 0 +( -128 880 128 ) ( -128 872 128 ) ( -128 872 104 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 872 136 ) ( -120 872 136 ) ( -120 872 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 872 128 ) ( -120 880 128 ) ( -120 880 104 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 880 128 ) ( -128 880 128 ) ( -128 880 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 824 176 ) ( -128 824 176 ) ( -120 800 176 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 163 +{ +brushDef +{ +( -128 728 232 ) ( -120 728 232 ) ( -120 720 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -7.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 728 128 ) ( -128 720 128 ) ( -128 720 104 ) ( ( 0.015625 0 6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 720 136 ) ( -120 720 136 ) ( -120 720 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 720 128 ) ( -120 728 128 ) ( -120 728 104 ) ( ( 0.015625 0 -6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 728 128 ) ( -128 728 128 ) ( -128 728 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 672 176 ) ( -128 672 176 ) ( -120 648 176 ) ( ( 0 0.015625 0 ) ( -0.015625 0 7.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 164 +{ +brushDef +{ +( -120 720 104 ) ( -120 728 104 ) ( -128 728 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 7.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 728 128 ) ( -128 720 128 ) ( -128 720 104 ) ( ( 0.015625 0 6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 720 136 ) ( -120 720 136 ) ( -120 720 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 720 128 ) ( -120 728 128 ) ( -120 728 104 ) ( ( 0.015625 0 -6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 728 128 ) ( -128 728 128 ) ( -128 728 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 672 168 ) ( -120 672 168 ) ( -128 648 168 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -7.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 165 +{ +brushDef +{ +( -128 672 176 ) ( -120 672 176 ) ( -120 672 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 14.875021 ) ) gothic_trim/wood2 134217728 0 0 +( -120 776 168 ) ( -120 776 176 ) ( -128 776 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -14.874980 ) ) gothic_trim/wood2 134217728 0 0 +( -120 672 168 ) ( -128 672 168 ) ( -128 648 168 ) ( ( 0 -0.015625 -2.625000 ) ( 0.015625 0 -10.750000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 680 168 ) ( -128 680 176 ) ( -128 656 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -10 ) ) gothic_trim/wood2 134217728 0 0 +( -128 672 176 ) ( -120 672 176 ) ( -120 648 176 ) ( ( 0 -0.015625 2.625000 ) ( 0.015625 0 -10.750000 ) ) gothic_trim/wood2 134217728 0 0 +( -120 696 176 ) ( -120 696 168 ) ( -120 672 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -10 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 166 +{ +brushDef +{ +( -128 376 176 ) ( -120 376 176 ) ( -120 376 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 14.875021 ) ) gothic_trim/wood2 134217728 0 0 +( -120 480 168 ) ( -120 480 176 ) ( -128 480 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -14.874980 ) ) gothic_trim/wood2 134217728 0 0 +( -120 376 168 ) ( -128 376 168 ) ( -128 352 168 ) ( ( 0 -0.015625 -2.625000 ) ( 0.015625 0 -15.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 384 168 ) ( -128 384 176 ) ( -128 360 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -5.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 376 176 ) ( -120 376 176 ) ( -120 352 176 ) ( ( 0 -0.015625 2.625000 ) ( 0.015625 0 -15.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -120 400 176 ) ( -120 400 168 ) ( -120 376 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -5.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 167 +{ +brushDef +{ +( -120 424 104 ) ( -120 432 104 ) ( -128 432 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 12 ) ) gothic_trim/wood2 134217728 0 0 +( -128 432 128 ) ( -128 424 128 ) ( -128 424 104 ) ( ( 0.015625 0 2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 424 136 ) ( -120 424 136 ) ( -120 424 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 424 128 ) ( -120 432 128 ) ( -120 432 104 ) ( ( 0.015625 0 -2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 432 128 ) ( -128 432 128 ) ( -128 432 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 376 168 ) ( -120 376 168 ) ( -128 352 168 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -12 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 168 +{ +brushDef +{ +( -128 432 232 ) ( -120 432 232 ) ( -120 424 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -12 ) ) gothic_trim/wood2 134217728 0 0 +( -128 432 128 ) ( -128 424 128 ) ( -128 424 104 ) ( ( 0.015625 0 2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 424 136 ) ( -120 424 136 ) ( -120 424 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 424 128 ) ( -120 432 128 ) ( -120 432 104 ) ( ( 0.015625 0 -2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 432 128 ) ( -128 432 128 ) ( -128 432 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 376 176 ) ( -128 376 176 ) ( -120 352 176 ) ( ( 0 0.015625 0 ) ( -0.015625 0 12 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 169 +{ +brushDef +{ +( -128 280 232 ) ( -120 280 232 ) ( -120 272 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -14.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 280 128 ) ( -128 272 128 ) ( -128 272 104 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 272 136 ) ( -120 272 136 ) ( -120 272 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 272 128 ) ( -120 280 128 ) ( -120 280 104 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 280 128 ) ( -128 280 128 ) ( -128 280 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 224 176 ) ( -128 224 176 ) ( -120 200 176 ) ( ( 0 0.015625 0 ) ( -0.015625 0 14.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 170 +{ +brushDef +{ +( -120 272 104 ) ( -120 280 104 ) ( -128 280 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 14.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 280 128 ) ( -128 272 128 ) ( -128 272 104 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 272 136 ) ( -120 272 136 ) ( -120 272 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 272 128 ) ( -120 280 128 ) ( -120 280 104 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 280 128 ) ( -128 280 128 ) ( -128 280 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 224 168 ) ( -120 224 168 ) ( -128 200 168 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -14.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 171 +{ +brushDef +{ +( -128 224 176 ) ( -120 224 176 ) ( -120 224 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 14.875021 ) ) gothic_trim/wood2 134217728 0 0 +( -120 328 168 ) ( -120 328 176 ) ( -128 328 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -14.874980 ) ) gothic_trim/wood2 134217728 0 0 +( -120 224 168 ) ( -128 224 168 ) ( -128 200 168 ) ( ( 0 -0.015625 -2.625000 ) ( 0.015625 0 -17.750000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 232 168 ) ( -128 232 176 ) ( -128 208 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -3 ) ) gothic_trim/wood2 134217728 0 0 +( -128 224 176 ) ( -120 224 176 ) ( -120 200 176 ) ( ( 0 -0.015625 2.625000 ) ( 0.015625 0 -17.750000 ) ) gothic_trim/wood2 134217728 0 0 +( -120 248 176 ) ( -120 248 168 ) ( -120 224 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -3 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 172 +{ +brushDef +{ +( 384 952 176 ) ( 80 952 176 ) ( 80 920 176 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 104 920 184 ) ( 104 952 184 ) ( 408 952 184 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 104 920 184 ) ( 408 920 184 ) ( 408 920 -64 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562469 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 408 920 184 ) ( 408 952 184 ) ( 408 952 -64 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562469 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 408 952 184 ) ( 104 952 184 ) ( 104 952 -64 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562469 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 104 952 184 ) ( 104 920 184 ) ( 104 920 -64 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562469 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 173 +{ +brushDef +{ +( 384 952 112 ) ( 80 952 112 ) ( 80 920 112 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 104 920 120 ) ( 104 952 120 ) ( 408 952 120 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 104 920 120 ) ( 408 920 120 ) ( 408 920 -128 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.062500 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 408 920 120 ) ( 408 952 120 ) ( 408 952 -128 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.062500 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 408 952 120 ) ( 104 952 120 ) ( 104 952 -128 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.062500 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 104 952 120 ) ( 104 920 120 ) ( 104 920 -128 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.062500 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 174 +{ +brushDef +{ +( 416 960 8 ) ( 96 960 8 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 256 ) ( 96 960 256 ) ( 416 960 256 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 104 ) ( 416 920 104 ) ( 416 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 104 ) ( 96 920 104 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 104 920 104 ) ( 104 960 104 ) ( 104 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 175 +{ +brushDef +{ +( 416 960 8 ) ( 96 960 8 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 256 ) ( 96 960 256 ) ( 416 960 256 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 920 104 ) ( 416 960 104 ) ( 416 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 104 ) ( 96 920 104 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 952 104 ) ( 416 952 104 ) ( 96 952 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 176 +{ +brushDef +{ +( 416 960 8 ) ( 96 960 8 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 256 ) ( 96 960 256 ) ( 416 960 256 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 104 ) ( 416 920 104 ) ( 416 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 920 104 ) ( 416 960 104 ) ( 416 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 408 960 104 ) ( 408 920 104 ) ( 408 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 177 +{ +brushDef +{ +( 96 920 256 ) ( 96 960 256 ) ( 416 960 256 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 104 ) ( 416 920 104 ) ( 416 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 920 104 ) ( 416 960 104 ) ( 416 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 104 ) ( 96 920 104 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 248 ) ( 96 920 248 ) ( 416 960 248 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 178 +{ +brushDef +{ +( 416 960 8 ) ( 96 960 8 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 104 ) ( 416 920 104 ) ( 416 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 920 104 ) ( 416 960 104 ) ( 416 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 104 ) ( 96 920 104 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 16 ) ( 416 960 16 ) ( 96 920 16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 179 +{ +brushDef +{ +( 144 776 8 ) ( 144 792 8 ) ( -24 792 8 ) ( ( 0 0.007813 7.250462 ) ( -0.007813 0 2.000121 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 792 104 ) ( 144 792 104 ) ( 144 776 104 ) ( ( 0 -0.007813 7.250462 ) ( 0.007813 0 -2.000121 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 792 104 ) ( -24 776 104 ) ( -24 776 96 ) ( ( 0.007813 0 -3.500212 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 776 104 ) ( 144 776 104 ) ( 144 776 96 ) ( ( 0.007813 0 6.125393 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 536 768 104 ) ( 536 784 104 ) ( 536 784 96 ) ( ( 0.007813 0 3.500212 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 792 104 ) ( -24 792 104 ) ( -24 792 96 ) ( ( 0.007813 0 -6.125392 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 180 +{ +brushDef +{ +( -8 960 8 ) ( -24 960 8 ) ( -24 792 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -4.250261 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 792 104 ) ( -24 960 104 ) ( -8 960 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 4.250261 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 792 104 ) ( -8 792 104 ) ( -8 792 96 ) ( ( 0.007813 0 4.250261 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -8 792 104 ) ( -8 960 104 ) ( -8 960 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -8 960 104 ) ( -24 960 104 ) ( -24 960 96 ) ( ( 0.007813 0 -4.250261 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 960 104 ) ( -24 792 104 ) ( -24 792 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 181 +{ +brushDef +{ +( 536 960 8 ) ( 520 960 8 ) ( 520 792 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 520 792 104 ) ( 520 960 104 ) ( 536 960 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 520 792 104 ) ( 536 792 104 ) ( 536 792 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 536 792 104 ) ( 536 960 104 ) ( 536 960 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 536 960 104 ) ( 520 960 104 ) ( 520 960 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 520 960 104 ) ( 520 792 104 ) ( 520 792 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 182 +{ +brushDef +{ +( 272 832 104 ) ( 32 832 104 ) ( 32 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 134217728 0 0 +( 32 768 112 ) ( 32 832 112 ) ( 272 832 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 134217728 0 0 +( 32 768 112 ) ( 272 768 112 ) ( 272 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 134217728 0 0 +( 480 760 112 ) ( 480 824 112 ) ( 480 824 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 134217728 0 0 +( 272 832 112 ) ( 32 832 112 ) ( 32 832 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 134217728 0 0 +( 32 832 112 ) ( 32 768 112 ) ( 32 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 134217728 0 0 +} +} +// brush 183 +{ +brushDef +{ +( 544 960 104 ) ( 480 960 104 ) ( 480 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 5.500000 ) ) base_trim/pewter_spec 134217728 0 0 +( 480 768 112 ) ( 480 960 112 ) ( 544 960 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -5.500000 ) ) base_trim/pewter_spec 134217728 0 0 +( 480 768 112 ) ( 544 768 112 ) ( 544 768 104 ) ( ( 0.015625 0 -5.500000 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 134217728 0 0 +( 544 768 112 ) ( 544 960 112 ) ( 544 960 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 134217728 0 0 +( 544 960 112 ) ( 480 960 112 ) ( 480 960 104 ) ( ( 0.015625 0 5.500000 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 134217728 0 0 +( 480 960 112 ) ( 480 768 112 ) ( 480 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 134217728 0 0 +} +} +// brush 184 +{ +brushDef +{ +( 32 960 104 ) ( -32 960 104 ) ( -32 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2.500000 ) ) base_trim/pewter_spec 134217728 0 0 +( -32 768 112 ) ( -32 960 112 ) ( 32 960 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.500000 ) ) base_trim/pewter_spec 134217728 0 0 +( -32 768 112 ) ( 32 768 112 ) ( 32 768 104 ) ( ( 0.015625 0 2.500000 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 134217728 0 0 +( 32 768 112 ) ( 32 960 112 ) ( 32 960 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 134217728 0 0 +( 32 960 112 ) ( -32 960 112 ) ( -32 960 104 ) ( ( 0.015625 0 -2.500000 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 134217728 0 0 +( -32 960 112 ) ( -32 768 112 ) ( -32 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 134217728 0 0 +} +} +// brush 185 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 440 512 8.000001 0 0 ) ( 440 512 36 0 0.687500 ) ( 440 512 64 0 1.375000 ) ) +( ( 440 504 8.000001 0.125000 0 ) ( 440 504 36 0.125000 0.687500 ) ( 440 504 64 0.125000 1.375000 ) ) +( ( 448 504 8.000001 0.250000 0 ) ( 448 504 36 0.250000 0.687500 ) ( 448 504 64 0.250000 1.375000 ) ) +( ( 456 504 8.000001 0.375000 0 ) ( 456 504 36 0.375000 0.687500 ) ( 456 504 64 0.375000 1.375000 ) ) +( ( 456 512 8.000001 0.500000 0 ) ( 456 512 36 0.500000 0.687500 ) ( 456 512 64 0.500000 1.375000 ) ) +( ( 456 520 8.000001 0.625000 0 ) ( 456 520 36 0.625000 0.687500 ) ( 456 520 64 0.625000 1.375000 ) ) +( ( 448 520 8.000001 0.750000 0 ) ( 448 520 36 0.750000 0.687500 ) ( 448 520 64 0.750000 1.375000 ) ) +( ( 440 520 8.000001 0.875000 0 ) ( 440 520 36 0.875000 0.687500 ) ( 440 520 64 0.875000 1.375000 ) ) +( ( 440 512 8.000001 1 0 ) ( 440 512 36 1 0.687500 ) ( 440 512 64 1 1.375000 ) ) +) + } + } +// brush 186 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 440 320 8.000001 0 0 ) ( 440 320 36 0 0.687500 ) ( 440 320 64 0 1.375000 ) ) +( ( 440 312 8.000001 0.125000 0 ) ( 440 312 36 0.125000 0.687500 ) ( 440 312 64 0.125000 1.375000 ) ) +( ( 448 312 8.000001 0.250000 0 ) ( 448 312 36 0.250000 0.687500 ) ( 448 312 64 0.250000 1.375000 ) ) +( ( 456 312 8.000001 0.375000 0 ) ( 456 312 36 0.375000 0.687500 ) ( 456 312 64 0.375000 1.375000 ) ) +( ( 456 320 8.000001 0.500000 0 ) ( 456 320 36 0.500000 0.687500 ) ( 456 320 64 0.500000 1.375000 ) ) +( ( 456 328 8.000001 0.625000 0 ) ( 456 328 36 0.625000 0.687500 ) ( 456 328 64 0.625000 1.375000 ) ) +( ( 448 328 8.000001 0.750000 0 ) ( 448 328 36 0.750000 0.687500 ) ( 448 328 64 0.750000 1.375000 ) ) +( ( 440 328 8.000001 0.875000 0 ) ( 440 328 36 0.875000 0.687500 ) ( 440 328 64 0.875000 1.375000 ) ) +( ( 440 320 8.000001 1 0 ) ( 440 320 36 1 0.687500 ) ( 440 320 64 1 1.375000 ) ) +) + } + } +// brush 187 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 56 320 8.000001 0 0 ) ( 56 320 36 0 0.687500 ) ( 56 320 64 0 1.375000 ) ) +( ( 56 312 8.000001 0.125000 0 ) ( 56 312 36 0.125000 0.687500 ) ( 56 312 64 0.125000 1.375000 ) ) +( ( 64 312 8.000001 0.250000 0 ) ( 64 312 36 0.250000 0.687500 ) ( 64 312 64 0.250000 1.375000 ) ) +( ( 72 312 8.000001 0.375000 0 ) ( 72 312 36 0.375000 0.687500 ) ( 72 312 64 0.375000 1.375000 ) ) +( ( 72 320 8.000001 0.500000 0 ) ( 72 320 36 0.500000 0.687500 ) ( 72 320 64 0.500000 1.375000 ) ) +( ( 72 328 8.000001 0.625000 0 ) ( 72 328 36 0.625000 0.687500 ) ( 72 328 64 0.625000 1.375000 ) ) +( ( 64 328 8.000001 0.750000 0 ) ( 64 328 36 0.750000 0.687500 ) ( 64 328 64 0.750000 1.375000 ) ) +( ( 56 328 8.000001 0.875000 0 ) ( 56 328 36 0.875000 0.687500 ) ( 56 328 64 0.875000 1.375000 ) ) +( ( 56 320 8.000001 1 0 ) ( 56 320 36 1 0.687500 ) ( 56 320 64 1 1.375000 ) ) +) + } + } +// brush 188 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 56 512 8.000001 0 0 ) ( 56 512 36 0 0.687500 ) ( 56 512 64 0 1.375000 ) ) +( ( 56 504 8.000001 0.125000 0 ) ( 56 504 36 0.125000 0.687500 ) ( 56 504 64 0.125000 1.375000 ) ) +( ( 64 504 8.000001 0.250000 0 ) ( 64 504 36 0.250000 0.687500 ) ( 64 504 64 0.250000 1.375000 ) ) +( ( 72 504 8.000001 0.375000 0 ) ( 72 504 36 0.375000 0.687500 ) ( 72 504 64 0.375000 1.375000 ) ) +( ( 72 512 8.000001 0.500000 0 ) ( 72 512 36 0.500000 0.687500 ) ( 72 512 64 0.500000 1.375000 ) ) +( ( 72 520 8.000001 0.625000 0 ) ( 72 520 36 0.625000 0.687500 ) ( 72 520 64 0.625000 1.375000 ) ) +( ( 64 520 8.000001 0.750000 0 ) ( 64 520 36 0.750000 0.687500 ) ( 64 520 64 0.750000 1.375000 ) ) +( ( 56 520 8.000001 0.875000 0 ) ( 56 520 36 0.875000 0.687500 ) ( 56 520 64 0.875000 1.375000 ) ) +( ( 56 512 8.000001 1 0 ) ( 56 512 36 1 0.687500 ) ( 56 512 64 1 1.375000 ) ) +) + } + } +// brush 189 +{ +brushDef +{ +( 608 128 176 ) ( 608 136 176 ) ( 608 136 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 2.625000 ) ) gothic_trim/wood2 134217728 0 0 +( 504 136 168 ) ( 504 136 176 ) ( 504 128 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.625000 ) ) gothic_trim/wood2 134217728 0 0 +( 608 136 168 ) ( 608 128 168 ) ( 632 128 168 ) ( ( -0.015625 0 -2.625000 ) ( 0 -0.015625 -12.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 600 128 168 ) ( 600 128 176 ) ( 624 128 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 6.250000 ) ) gothic_trim/wood2 134217728 0 0 +( 608 128 176 ) ( 608 136 176 ) ( 632 136 176 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -12.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 584 136 176 ) ( 584 136 168 ) ( 608 136 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 6.250000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 190 +{ +brushDef +{ +( 560 136 104 ) ( 552 136 104 ) ( 552 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 552 128 128 ) ( 560 128 128 ) ( 560 128 104 ) ( ( 0.015625 0 -9.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 560 128 136 ) ( 560 136 136 ) ( 560 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 560 136 128 ) ( 552 136 128 ) ( 552 136 104 ) ( ( 0.015625 0 9.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 552 136 128 ) ( 552 128 128 ) ( 552 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 608 128 168 ) ( 608 136 168 ) ( 632 128 168 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 191 +{ +brushDef +{ +( 552 128 232 ) ( 552 136 232 ) ( 560 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 552 128 128 ) ( 560 128 128 ) ( 560 128 104 ) ( ( 0.015625 0 -9.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 560 128 136 ) ( 560 136 136 ) ( 560 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 560 136 128 ) ( 552 136 128 ) ( 552 136 104 ) ( ( 0.015625 0 9.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 552 136 128 ) ( 552 128 128 ) ( 552 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 608 136 176 ) ( 608 128 176 ) ( 632 136 176 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 192 +{ +brushDef +{ +( 400 128 232 ) ( 400 136 232 ) ( 408 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7 ) ) gothic_trim/wood2 134217728 0 0 +( 400 128 128 ) ( 408 128 128 ) ( 408 128 104 ) ( ( 0.015625 0 -7 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 408 128 136 ) ( 408 136 136 ) ( 408 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 408 136 128 ) ( 400 136 128 ) ( 400 136 104 ) ( ( 0.015625 0 7 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 400 136 128 ) ( 400 128 128 ) ( 400 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 136 176 ) ( 456 128 176 ) ( 480 136 176 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 193 +{ +brushDef +{ +( 408 136 104 ) ( 400 136 104 ) ( 400 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7 ) ) gothic_trim/wood2 134217728 0 0 +( 400 128 128 ) ( 408 128 128 ) ( 408 128 104 ) ( ( 0.015625 0 -7 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 408 128 136 ) ( 408 136 136 ) ( 408 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 408 136 128 ) ( 400 136 128 ) ( 400 136 104 ) ( ( 0.015625 0 7 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 400 136 128 ) ( 400 128 128 ) ( 400 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 456 128 168 ) ( 456 136 168 ) ( 480 128 168 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 194 +{ +brushDef +{ +( 456 128 176 ) ( 456 136 176 ) ( 456 136 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 2.625000 ) ) gothic_trim/wood2 134217728 0 0 +( 352 136 168 ) ( 352 136 176 ) ( 352 128 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.625000 ) ) gothic_trim/wood2 134217728 0 0 +( 456 136 168 ) ( 456 128 168 ) ( 480 128 168 ) ( ( -0.015625 0 -2.625000 ) ( 0 -0.015625 -10.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 448 128 168 ) ( 448 128 176 ) ( 472 128 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 3.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 456 128 176 ) ( 456 136 176 ) ( 480 136 176 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -10.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 432 136 176 ) ( 432 136 168 ) ( 456 136 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 3.875000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 195 +{ +brushDef +{ +( 160 128 176 ) ( 160 136 176 ) ( 160 136 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 2.625000 ) ) gothic_trim/wood2 134217728 0 0 +( 56 136 168 ) ( 56 136 176 ) ( 56 128 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.625000 ) ) gothic_trim/wood2 134217728 0 0 +( 160 136 168 ) ( 160 128 168 ) ( 184 128 168 ) ( ( -0.015625 0 -2.625000 ) ( 0 -0.015625 -5.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 152 128 168 ) ( 152 128 176 ) ( 176 128 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -0.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 160 128 176 ) ( 160 136 176 ) ( 184 136 176 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -5.750000 ) ) gothic_trim/wood2 134217728 0 0 +( 136 136 176 ) ( 136 136 168 ) ( 160 136 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -0.750000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 196 +{ +brushDef +{ +( 112 136 104 ) ( 104 136 104 ) ( 104 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 104 128 128 ) ( 112 128 128 ) ( 112 128 104 ) ( ( 0.015625 0 -2.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 112 128 136 ) ( 112 136 136 ) ( 112 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 112 136 128 ) ( 104 136 128 ) ( 104 136 104 ) ( ( 0.015625 0 2.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 104 136 128 ) ( 104 128 128 ) ( 104 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 160 128 168 ) ( 160 136 168 ) ( 184 128 168 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 197 +{ +brushDef +{ +( 104 128 232 ) ( 104 136 232 ) ( 112 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 104 128 128 ) ( 112 128 128 ) ( 112 128 104 ) ( ( 0.015625 0 -2.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 112 128 136 ) ( 112 136 136 ) ( 112 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 112 136 128 ) ( 104 136 128 ) ( 104 136 104 ) ( ( 0.015625 0 2.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 104 136 128 ) ( 104 128 128 ) ( 104 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 160 136 176 ) ( 160 128 176 ) ( 184 136 176 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.375000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 198 +{ +brushDef +{ +( -48 128 232 ) ( -48 136 232 ) ( -40 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -48 128 128 ) ( -40 128 128 ) ( -40 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -40 128 136 ) ( -40 136 136 ) ( -40 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -40 136 128 ) ( -48 136 128 ) ( -48 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -48 136 128 ) ( -48 128 128 ) ( -48 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 8 136 176 ) ( 8 128 176 ) ( 32 136 176 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 199 +{ +brushDef +{ +( -40 136 104 ) ( -48 136 104 ) ( -48 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -48 128 128 ) ( -40 128 128 ) ( -40 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -40 128 136 ) ( -40 136 136 ) ( -40 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -40 136 128 ) ( -48 136 128 ) ( -48 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -48 136 128 ) ( -48 128 128 ) ( -48 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 8 128 168 ) ( 8 136 168 ) ( 32 128 168 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 200 +{ +brushDef +{ +( 8 128 176 ) ( 8 136 176 ) ( 8 136 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 2.625000 ) ) gothic_trim/wood2 134217728 0 0 +( -96 136 168 ) ( -96 136 176 ) ( -96 128 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.625000 ) ) gothic_trim/wood2 134217728 0 0 +( 8 136 168 ) ( 8 128 168 ) ( 32 128 168 ) ( ( -0.015625 0 -2.625000 ) ( 0 -0.015625 -3.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 0 128 168 ) ( 0 128 176 ) ( 24 128 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -3.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 8 128 176 ) ( 8 136 176 ) ( 32 136 176 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -3.375000 ) ) gothic_trim/wood2 134217728 0 0 +( -16 136 176 ) ( -16 136 168 ) ( 8 136 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -3.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 201 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 144 104 ) ( 56 144 104 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 136 232 ) ( 56 144 232 ) ( 160 144 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -96 136 128 ) ( -96 144 128 ) ( -96 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 202 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 144 104 ) ( 56 144 104 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 136 232 ) ( 56 144 232 ) ( 160 144 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 136 128 ) ( 56 144 128 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 8 144 128 ) ( 8 136 128 ) ( 8 144 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 203 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 144 104 ) ( 56 144 104 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 136 232 ) ( 56 144 232 ) ( 160 144 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 144 128 ) ( 160 136 128 ) ( 160 144 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 204 +{ +brushDef +{ +( 192 136 8 ) ( -128 136 8 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 144 104 ) ( 160 144 104 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 205 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 104 ) ( 352 136 104 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 232 ) ( 352 136 232 ) ( 456 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 128 ) ( 456 128 128 ) ( 456 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 504 128 128 ) ( 504 136 128 ) ( 504 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 206 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 104 ) ( 352 136 104 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 232 ) ( 352 136 232 ) ( 456 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 608 136 128 ) ( 608 128 128 ) ( 608 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 207 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 104 ) ( 352 136 104 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 232 ) ( 352 136 232 ) ( 456 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 128 ) ( 352 136 128 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 208 +{ +brushDef +{ +( 640 136 8 ) ( 320 136 8 ) ( 320 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 136 104 ) ( 456 136 104 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 209 +{ +brushDef +{ +( 624 -144 -40 ) ( 408 -144 -40 ) ( 408 -184 -40 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 408 -184 -16 ) ( 408 -144 -16 ) ( 624 -144 -16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 408 -184 0 ) ( 624 -184 0 ) ( 624 -184 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 624 -184 0 ) ( 624 -144 0 ) ( 624 -144 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 624 -144 0 ) ( 408 -144 0 ) ( 408 -144 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 408 -144 0 ) ( 408 -184 0 ) ( 408 -184 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +} +} +// brush 210 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 0 ) ( 400 -136 0 ) ( 632 -136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 24 ) ( 632 -192 24 ) ( 632 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -136 24 ) ( 400 -136 24 ) ( 400 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 24 ) ( 400 -192 24 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 -192 24 ) ( 408 -136 24 ) ( 408 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 211 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 0 ) ( 400 -136 0 ) ( 632 -136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -192 24 ) ( 632 -136 24 ) ( 632 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -136 24 ) ( 400 -136 24 ) ( 400 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 24 ) ( 400 -192 24 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -144 24 ) ( 632 -144 24 ) ( 400 -144 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 212 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 0 ) ( 400 -136 0 ) ( 632 -136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 24 ) ( 632 -192 24 ) ( 632 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -192 24 ) ( 632 -136 24 ) ( 632 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -136 24 ) ( 400 -136 24 ) ( 400 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 624 -136 24 ) ( 624 -192 24 ) ( 624 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 213 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 0 ) ( 400 -136 0 ) ( 632 -136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 24 ) ( 632 -192 24 ) ( 632 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -192 24 ) ( 632 -136 24 ) ( 632 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 24 ) ( 400 -192 24 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -184 24 ) ( 400 -184 24 ) ( 632 -184 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 214 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 24 ) ( 632 -192 24 ) ( 632 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -192 24 ) ( 632 -136 24 ) ( 632 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -136 24 ) ( 400 -136 24 ) ( 400 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 24 ) ( 400 -192 24 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 -40 ) ( 632 -136 -40 ) ( 400 -192 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 215 +{ +brushDef +{ +( 304 192 152 ) ( 304 144 152 ) ( 304 144 64 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 144 152 ) ( 312 192 152 ) ( 312 192 64 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 184 152 ) ( 304 184 152 ) ( 304 184 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 152 72 ) ( 312 176 72 ) ( 304 176 72 ) ( ( 0 0.015625 6.750000 ) ( -0.015625 0 -2 ) ) gothic_trim/wood2 134217728 0 0 +( 304 176 144 ) ( 312 176 144 ) ( 312 152 144 ) ( ( 0 -0.015625 6.750000 ) ( 0.015625 0 2 ) ) gothic_trim/wood2 134217728 0 0 +( 304 176 128 ) ( 312 176 128 ) ( 304 176 120 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 216 +{ +brushDef +{ +( 304 192 152 ) ( 304 144 152 ) ( 304 144 64 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 304 144 152 ) ( 312 144 152 ) ( 312 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 144 152 ) ( 312 192 152 ) ( 312 192 64 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 152 72 ) ( 312 176 72 ) ( 304 176 72 ) ( ( 0 0.015625 6.750000 ) ( -0.015625 0 -2 ) ) gothic_trim/wood2 134217728 0 0 +( 304 176 144 ) ( 312 176 144 ) ( 312 152 144 ) ( ( 0 -0.015625 6.750000 ) ( 0.015625 0 2 ) ) gothic_trim/wood2 134217728 0 0 +( 312 152 128 ) ( 304 152 128 ) ( 312 152 120 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 217 +{ +brushDef +{ +( 304 192 152 ) ( 312 192 152 ) ( 312 144 152 ) ( ( 0 -0.015625 6.750000 ) ( 0.015625 0 2 ) ) gothic_trim/wood2 134217728 0 0 +( 304 192 152 ) ( 304 144 152 ) ( 304 144 64 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 304 144 152 ) ( 312 144 152 ) ( 312 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 144 152 ) ( 312 192 152 ) ( 312 192 64 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 184 152 ) ( 304 184 152 ) ( 304 184 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 176 144 ) ( 304 176 144 ) ( 312 152 144 ) ( ( 0 0.015625 6.750000 ) ( -0.015625 0 -2 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 218 +{ +brushDef +{ +( 312 144 64 ) ( 312 192 64 ) ( 304 192 64 ) ( ( 0 0.015625 6.750000 ) ( -0.015625 0 -2 ) ) gothic_trim/wood2 134217728 0 0 +( 304 192 152 ) ( 304 144 152 ) ( 304 144 64 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 304 144 152 ) ( 312 144 152 ) ( 312 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 144 152 ) ( 312 192 152 ) ( 312 192 64 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 184 152 ) ( 304 184 152 ) ( 304 184 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 312 176 72 ) ( 312 152 72 ) ( 304 176 72 ) ( ( 0 -0.015625 6.750000 ) ( 0.015625 0 2 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 219 +{ +brushDef +{ +( 312 152 72 ) ( 312 176 72 ) ( 304 176 72 ) ( ( 0 0.007813 3.375216 ) ( -0.007813 0 -0.562538 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 304 176 144 ) ( 312 176 144 ) ( 312 152 144 ) ( ( 0 -0.007813 3.375216 ) ( 0.007813 0 0.562536 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 304 176 128 ) ( 304 152 128 ) ( 304 152 120 ) ( ( 0.007813 0 1.062570 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 304 152 128 ) ( 312 152 128 ) ( 312 152 120 ) ( ( 0.007813 0 3.125201 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 312 152 128 ) ( 312 176 128 ) ( 312 176 120 ) ( ( 0.007813 0 -1.062568 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 312 176 128 ) ( 304 176 128 ) ( 304 176 120 ) ( ( 0.007813 0 -3.125200 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 220 +{ +brushDef +{ +( 208 144 152 ) ( 208 192 152 ) ( 208 192 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 192 152 ) ( 200 144 152 ) ( 200 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 144 152 ) ( 208 144 152 ) ( 208 144 64 ) ( ( 0.015625 0 -1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 176 72 ) ( 200 152 72 ) ( 208 152 72 ) ( ( 0 -0.015625 -1 ) ( 0.015625 0 -6 ) ) gothic_trim/wood2 134217728 0 0 +( 208 152 144 ) ( 200 152 144 ) ( 200 176 144 ) ( ( 0 0.015625 -1 ) ( -0.015625 0 6 ) ) gothic_trim/wood2 134217728 0 0 +( 208 152 128 ) ( 200 152 128 ) ( 208 152 120 ) ( ( 0.015625 0 1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 221 +{ +brushDef +{ +( 208 144 152 ) ( 208 192 152 ) ( 208 192 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 208 184 152 ) ( 200 184 152 ) ( 200 184 64 ) ( ( 0.015625 0 1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 192 152 ) ( 200 144 152 ) ( 200 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 176 72 ) ( 200 152 72 ) ( 208 152 72 ) ( ( 0 -0.015625 -1 ) ( 0.015625 0 -6 ) ) gothic_trim/wood2 134217728 0 0 +( 208 152 144 ) ( 200 152 144 ) ( 200 176 144 ) ( ( 0 0.015625 -1 ) ( -0.015625 0 6 ) ) gothic_trim/wood2 134217728 0 0 +( 200 176 128 ) ( 208 176 128 ) ( 200 176 120 ) ( ( 0.015625 0 -1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 222 +{ +brushDef +{ +( 208 144 152 ) ( 200 144 152 ) ( 200 192 152 ) ( ( 0 0.015625 -1 ) ( -0.015625 0 6 ) ) gothic_trim/wood2 134217728 0 0 +( 208 144 152 ) ( 208 192 152 ) ( 208 192 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 208 184 152 ) ( 200 184 152 ) ( 200 184 64 ) ( ( 0.015625 0 1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 192 152 ) ( 200 144 152 ) ( 200 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 144 152 ) ( 208 144 152 ) ( 208 144 64 ) ( ( 0.015625 0 -1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 152 144 ) ( 208 152 144 ) ( 200 176 144 ) ( ( 0 -0.015625 -1 ) ( 0.015625 0 -6 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 223 +{ +brushDef +{ +( 200 192 64 ) ( 200 144 64 ) ( 208 144 64 ) ( ( 0 -0.015625 -1 ) ( 0.015625 0 -6 ) ) gothic_trim/wood2 134217728 0 0 +( 208 144 152 ) ( 208 192 152 ) ( 208 192 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 208 184 152 ) ( 200 184 152 ) ( 200 184 64 ) ( ( 0.015625 0 1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 192 152 ) ( 200 144 152 ) ( 200 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 144 152 ) ( 208 144 152 ) ( 208 144 64 ) ( ( 0.015625 0 -1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 200 152 72 ) ( 200 176 72 ) ( 208 152 72 ) ( ( 0 0.015625 -1 ) ( -0.015625 0 6 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 224 +{ +brushDef +{ +( 200 176 72 ) ( 200 152 72 ) ( 208 152 72 ) ( ( 0 -0.007813 -0.500000 ) ( 0.007813 0 -3 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 208 152 144 ) ( 200 152 144 ) ( 200 176 144 ) ( ( 0 0.007813 -0.500000 ) ( -0.007813 0 3 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 208 152 128 ) ( 208 176 128 ) ( 208 176 120 ) ( ( 0.007813 0 -3.125000 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 208 176 128 ) ( 200 176 128 ) ( 200 176 120 ) ( ( 0.007813 0 0.625000 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 200 176 128 ) ( 200 152 128 ) ( 200 152 120 ) ( ( 0.007813 0 3.125000 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 200 152 128 ) ( 208 152 128 ) ( 208 152 120 ) ( ( 0.007813 0 -0.625000 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 225 +{ +brushDef +{ +( 136 -128 -48 ) ( 136 -152 -48 ) ( 144 -152 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 3.125198 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -152 0 ) ( 136 -152 0 ) ( 136 -128 0 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -3.125198 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -152 8 ) ( 144 -128 8 ) ( 144 -128 0 ) ( ( 0.007813 0 -0.875060 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -128 8 ) ( 136 -128 8 ) ( 136 -128 0 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -128 8 ) ( 136 -152 8 ) ( 136 -152 0 ) ( ( 0.007813 0 0.875061 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -152 8 ) ( 144 -152 8 ) ( 144 -152 0 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 226 +{ +brushDef +{ +( 136 -152 -48 ) ( 136 -176 -48 ) ( 144 -176 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.937688 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -176 -8 ) ( 136 -176 -8 ) ( 136 -152 -8 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.937688 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -176 0 ) ( 144 -152 0 ) ( 144 -152 -8 ) ( ( 0.007813 0 -0.687551 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -152 0 ) ( 136 -152 0 ) ( 136 -152 -8 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -152 0 ) ( 136 -176 0 ) ( 136 -176 -8 ) ( ( 0.007813 0 0.687551 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -176 0 ) ( 144 -176 0 ) ( 144 -176 -8 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 227 +{ +brushDef +{ +( 136 -176 -48 ) ( 136 -200 -48 ) ( 144 -200 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.750176 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -200 -16 ) ( 136 -200 -16 ) ( 136 -176 -16 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.750176 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -200 -8 ) ( 144 -176 -8 ) ( 144 -176 -16 ) ( ( 0.007813 0 -0.500039 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -176 -8 ) ( 136 -176 -8 ) ( 136 -176 -16 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -176 -8 ) ( 136 -200 -8 ) ( 136 -200 -16 ) ( ( 0.007813 0 0.500039 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -200 -8 ) ( 144 -200 -8 ) ( 144 -200 -16 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 228 +{ +brushDef +{ +( 136 -200 -48 ) ( 136 -224 -48 ) ( 144 -224 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.562655 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -224 -24 ) ( 136 -224 -24 ) ( 136 -200 -24 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.562655 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -224 -16 ) ( 144 -200 -16 ) ( 144 -200 -24 ) ( ( 0.007813 0 -0.312517 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -200 -16 ) ( 136 -200 -16 ) ( 136 -200 -24 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -200 -16 ) ( 136 -224 -16 ) ( 136 -224 -24 ) ( ( 0.007813 0 0.312517 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -224 -16 ) ( 144 -224 -16 ) ( 144 -224 -24 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 229 +{ +brushDef +{ +( 136 -224 -48 ) ( 136 -248 -48 ) ( 144 -248 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.375144 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -248 -32 ) ( 136 -248 -32 ) ( 136 -224 -32 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.375144 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -248 -24 ) ( 144 -224 -24 ) ( 144 -224 -32 ) ( ( 0.007813 0 -0.125006 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -224 -24 ) ( 136 -224 -24 ) ( 136 -224 -32 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -224 -24 ) ( 136 -248 -24 ) ( 136 -248 -32 ) ( ( 0.007813 0 0.125006 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -248 -24 ) ( 144 -248 -24 ) ( 144 -248 -32 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 230 +{ +brushDef +{ +( 136 -248 -48 ) ( 136 -272 -48 ) ( 144 -272 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.187633 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -272 -40 ) ( 136 -272 -40 ) ( 136 -248 -40 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.187633 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -272 -32 ) ( 144 -248 -32 ) ( 144 -248 -40 ) ( ( 0.007813 0 0.062505 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 144 -248 -32 ) ( 136 -248 -32 ) ( 136 -248 -40 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -248 -32 ) ( 136 -272 -32 ) ( 136 -272 -40 ) ( ( 0.007813 0 -0.062505 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 136 -272 -32 ) ( 144 -272 -32 ) ( 144 -272 -40 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 231 +{ +brushDef +{ +( 368 -248 -48 ) ( 368 -272 -48 ) ( 376 -272 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.187633 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -272 -40 ) ( 368 -272 -40 ) ( 368 -248 -40 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.187633 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -272 -32 ) ( 376 -248 -32 ) ( 376 -248 -40 ) ( ( 0.007813 0 0.062505 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -248 -32 ) ( 368 -248 -32 ) ( 368 -248 -40 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -248 -32 ) ( 368 -272 -32 ) ( 368 -272 -40 ) ( ( 0.007813 0 -0.062505 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -272 -32 ) ( 376 -272 -32 ) ( 376 -272 -40 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 232 +{ +brushDef +{ +( 368 -224 -48 ) ( 368 -248 -48 ) ( 376 -248 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.375144 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -248 -32 ) ( 368 -248 -32 ) ( 368 -224 -32 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.375144 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -248 -24 ) ( 376 -224 -24 ) ( 376 -224 -32 ) ( ( 0.007813 0 -0.125006 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -224 -24 ) ( 368 -224 -24 ) ( 368 -224 -32 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -224 -24 ) ( 368 -248 -24 ) ( 368 -248 -32 ) ( ( 0.007813 0 0.125006 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -248 -24 ) ( 376 -248 -24 ) ( 376 -248 -32 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 233 +{ +brushDef +{ +( 368 -200 -48 ) ( 368 -224 -48 ) ( 376 -224 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.562655 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -224 -24 ) ( 368 -224 -24 ) ( 368 -200 -24 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.562655 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -224 -16 ) ( 376 -200 -16 ) ( 376 -200 -24 ) ( ( 0.007813 0 -0.312517 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -200 -16 ) ( 368 -200 -16 ) ( 368 -200 -24 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -200 -16 ) ( 368 -224 -16 ) ( 368 -224 -24 ) ( ( 0.007813 0 0.312517 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -224 -16 ) ( 376 -224 -16 ) ( 376 -224 -24 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 234 +{ +brushDef +{ +( 368 -176 -48 ) ( 368 -200 -48 ) ( 376 -200 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.750176 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -200 -16 ) ( 368 -200 -16 ) ( 368 -176 -16 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.750176 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -200 -8 ) ( 376 -176 -8 ) ( 376 -176 -16 ) ( ( 0.007813 0 -0.500039 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -176 -8 ) ( 368 -176 -8 ) ( 368 -176 -16 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -176 -8 ) ( 368 -200 -8 ) ( 368 -200 -16 ) ( ( 0.007813 0 0.500039 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -200 -8 ) ( 376 -200 -8 ) ( 376 -200 -16 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 235 +{ +brushDef +{ +( 368 -152 -48 ) ( 368 -176 -48 ) ( 376 -176 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.937688 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -176 -8 ) ( 368 -176 -8 ) ( 368 -152 -8 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.937688 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -176 0 ) ( 376 -152 0 ) ( 376 -152 -8 ) ( ( 0.007813 0 -0.687551 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -152 0 ) ( 368 -152 0 ) ( 368 -152 -8 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -152 0 ) ( 368 -176 0 ) ( 368 -176 -8 ) ( ( 0.007813 0 0.687551 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -176 0 ) ( 376 -176 0 ) ( 376 -176 -8 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 236 +{ +brushDef +{ +( 368 -128 -48 ) ( 368 -152 -48 ) ( 376 -152 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 3.125198 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -152 0 ) ( 368 -152 0 ) ( 368 -128 0 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -3.125198 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -152 8 ) ( 376 -128 8 ) ( 376 -128 0 ) ( ( 0.007813 0 -0.875060 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 376 -128 8 ) ( 368 -128 8 ) ( 368 -128 0 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -128 8 ) ( 368 -152 8 ) ( 368 -152 0 ) ( ( 0.007813 0 0.875061 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 368 -152 8 ) ( 376 -152 8 ) ( 376 -152 0 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 237 +{ +brushDef +{ +( 640 -128 -48 ) ( 664 -128 -48 ) ( 664 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.000237 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 -120 0 ) ( 664 -128 0 ) ( 640 -128 0 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.000237 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 -120 8 ) ( 640 -120 8 ) ( 640 -120 0 ) ( ( 0.007813 0 5.250314 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -120 8 ) ( 640 -128 8 ) ( 640 -128 0 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -128 8 ) ( 664 -128 8 ) ( 664 -128 0 ) ( ( 0.007813 0 -5.250313 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 -128 8 ) ( 664 -120 8 ) ( 664 -120 0 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 238 +{ +brushDef +{ +( 664 -128 -48 ) ( 688 -128 -48 ) ( 688 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.187747 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 -120 -8 ) ( 688 -128 -8 ) ( 664 -128 -8 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.187747 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 -120 0 ) ( 664 -120 0 ) ( 664 -120 -8 ) ( ( 0.007813 0 5.437823 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 664 -120 0 ) ( 664 -128 0 ) ( 664 -128 -8 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 664 -128 0 ) ( 688 -128 0 ) ( 688 -128 -8 ) ( ( 0.007813 0 -5.437823 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 -128 0 ) ( 688 -120 0 ) ( 688 -120 -8 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 239 +{ +brushDef +{ +( 688 -128 -48 ) ( 712 -128 -48 ) ( 712 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.375259 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 -120 -16 ) ( 712 -128 -16 ) ( 688 -128 -16 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.375259 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 -120 -8 ) ( 688 -120 -8 ) ( 688 -120 -16 ) ( ( 0.007813 0 5.625335 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 -120 -8 ) ( 688 -128 -8 ) ( 688 -128 -16 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 -128 -8 ) ( 712 -128 -8 ) ( 712 -128 -16 ) ( ( 0.007813 0 -5.625335 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 -128 -8 ) ( 712 -120 -8 ) ( 712 -120 -16 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 240 +{ +brushDef +{ +( 712 -128 -48 ) ( 736 -128 -48 ) ( 736 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.562780 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 -120 -24 ) ( 736 -128 -24 ) ( 712 -128 -24 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.562780 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 -120 -16 ) ( 712 -120 -16 ) ( 712 -120 -24 ) ( ( 0.007813 0 5.812857 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 -120 -16 ) ( 712 -128 -16 ) ( 712 -128 -24 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 -128 -16 ) ( 736 -128 -16 ) ( 736 -128 -24 ) ( ( 0.007813 0 -5.812857 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 -128 -16 ) ( 736 -120 -16 ) ( 736 -120 -24 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 241 +{ +brushDef +{ +( 736 -128 -48 ) ( 760 -128 -48 ) ( 760 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.750291 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 -120 -32 ) ( 760 -128 -32 ) ( 736 -128 -32 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.750291 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 -120 -24 ) ( 736 -120 -24 ) ( 736 -120 -32 ) ( ( 0.007813 0 6.000368 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 -120 -24 ) ( 736 -128 -24 ) ( 736 -128 -32 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 -128 -24 ) ( 760 -128 -24 ) ( 760 -128 -32 ) ( ( 0.007813 0 -6.000368 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 -128 -24 ) ( 760 -120 -24 ) ( 760 -120 -32 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 242 +{ +brushDef +{ +( 760 -128 -48 ) ( 784 -128 -48 ) ( 784 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.937802 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 784 -120 -40 ) ( 784 -128 -40 ) ( 760 -128 -40 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.937802 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 784 -120 -32 ) ( 760 -120 -32 ) ( 760 -120 -40 ) ( ( 0.007813 0 6.187879 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 -120 -32 ) ( 760 -128 -32 ) ( 760 -128 -40 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 -128 -32 ) ( 784 -128 -32 ) ( 784 -128 -40 ) ( ( 0.007813 0 -6.187879 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 784 -128 -32 ) ( 784 -120 -32 ) ( 784 -120 -40 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 243 +{ +brushDef +{ +( 760 120 -48 ) ( 784 120 -48 ) ( 784 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.937802 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 784 128 -40 ) ( 784 120 -40 ) ( 760 120 -40 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.937802 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 784 128 -32 ) ( 760 128 -32 ) ( 760 128 -40 ) ( ( 0.007813 0 6.187879 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 128 -32 ) ( 760 120 -32 ) ( 760 120 -40 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 120 -32 ) ( 784 120 -32 ) ( 784 120 -40 ) ( ( 0.007813 0 -6.187878 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 784 120 -32 ) ( 784 128 -32 ) ( 784 128 -40 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 244 +{ +brushDef +{ +( 736 120 -48 ) ( 760 120 -48 ) ( 760 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.750291 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 128 -32 ) ( 760 120 -32 ) ( 736 120 -32 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.750291 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 128 -24 ) ( 736 128 -24 ) ( 736 128 -32 ) ( ( 0.007813 0 6.000368 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 128 -24 ) ( 736 120 -24 ) ( 736 120 -32 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 120 -24 ) ( 760 120 -24 ) ( 760 120 -32 ) ( ( 0.007813 0 -6.000367 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 760 120 -24 ) ( 760 128 -24 ) ( 760 128 -32 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 245 +{ +brushDef +{ +( 712 120 -48 ) ( 736 120 -48 ) ( 736 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.562780 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 128 -24 ) ( 736 120 -24 ) ( 712 120 -24 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.562780 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 128 -16 ) ( 712 128 -16 ) ( 712 128 -24 ) ( ( 0.007813 0 5.812857 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 128 -16 ) ( 712 120 -16 ) ( 712 120 -24 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 120 -16 ) ( 736 120 -16 ) ( 736 120 -24 ) ( ( 0.007813 0 -5.812856 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 736 120 -16 ) ( 736 128 -16 ) ( 736 128 -24 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 246 +{ +brushDef +{ +( 688 120 -48 ) ( 712 120 -48 ) ( 712 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.375259 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 128 -16 ) ( 712 120 -16 ) ( 688 120 -16 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.375259 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 128 -8 ) ( 688 128 -8 ) ( 688 128 -16 ) ( ( 0.007813 0 5.625335 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 128 -8 ) ( 688 120 -8 ) ( 688 120 -16 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 120 -8 ) ( 712 120 -8 ) ( 712 120 -16 ) ( ( 0.007813 0 -5.625335 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 712 120 -8 ) ( 712 128 -8 ) ( 712 128 -16 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 247 +{ +brushDef +{ +( 664 120 -48 ) ( 688 120 -48 ) ( 688 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.187747 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 128 -8 ) ( 688 120 -8 ) ( 664 120 -8 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.187747 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 128 0 ) ( 664 128 0 ) ( 664 128 -8 ) ( ( 0.007813 0 5.437823 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 664 128 0 ) ( 664 120 0 ) ( 664 120 -8 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 664 120 0 ) ( 688 120 0 ) ( 688 120 -8 ) ( ( 0.007813 0 -5.437823 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( 688 120 0 ) ( 688 128 0 ) ( 688 128 -8 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 248 +{ +brushDef +{ +( 640 120 -48 ) ( 664 120 -48 ) ( 664 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.000237 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 128 0 ) ( 664 120 0 ) ( 640 120 0 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.000237 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 128 8 ) ( 640 128 8 ) ( 640 128 0 ) ( ( 0.007813 0 5.250314 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 128 8 ) ( 640 120 8 ) ( 640 120 0 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 120 8 ) ( 664 120 8 ) ( 664 120 0 ) ( ( 0.007813 0 -5.250313 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 120 8 ) ( 664 128 8 ) ( 664 128 0 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 249 +{ +brushDef +{ +( -128 128 -48 ) ( -152 128 -48 ) ( -152 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -152 120 0 ) ( -152 128 0 ) ( -128 128 0 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -152 120 8 ) ( -128 120 8 ) ( -128 120 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -128 120 8 ) ( -128 128 8 ) ( -128 128 0 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -128 128 8 ) ( -152 128 8 ) ( -152 128 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -152 128 8 ) ( -152 120 8 ) ( -152 120 0 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 250 +{ +brushDef +{ +( -152 128 -48 ) ( -176 128 -48 ) ( -176 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 120 -8 ) ( -176 128 -8 ) ( -152 128 -8 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 120 0 ) ( -152 120 0 ) ( -152 120 -8 ) ( ( 0.007813 0 0.187512 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -152 120 0 ) ( -152 128 0 ) ( -152 128 -8 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -152 128 0 ) ( -176 128 0 ) ( -176 128 -8 ) ( ( 0.007813 0 -0.187512 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 128 0 ) ( -176 120 0 ) ( -176 120 -8 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 251 +{ +brushDef +{ +( -176 128 -48 ) ( -200 128 -48 ) ( -200 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.375024 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 120 -16 ) ( -200 128 -16 ) ( -176 128 -16 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.375024 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 120 -8 ) ( -176 120 -8 ) ( -176 120 -16 ) ( ( 0.007813 0 0.375024 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 120 -8 ) ( -176 128 -8 ) ( -176 128 -16 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 128 -8 ) ( -200 128 -8 ) ( -200 128 -16 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 128 -8 ) ( -200 120 -8 ) ( -200 120 -16 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 252 +{ +brushDef +{ +( -200 128 -48 ) ( -224 128 -48 ) ( -224 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.562536 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 120 -24 ) ( -224 128 -24 ) ( -200 128 -24 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.562536 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 120 -16 ) ( -200 120 -16 ) ( -200 120 -24 ) ( ( 0.007813 0 0.562536 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 120 -16 ) ( -200 128 -16 ) ( -200 128 -24 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 128 -16 ) ( -224 128 -16 ) ( -224 128 -24 ) ( ( 0.007813 0 -0.562536 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 128 -16 ) ( -224 120 -16 ) ( -224 120 -24 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 253 +{ +brushDef +{ +( -224 128 -48 ) ( -248 128 -48 ) ( -248 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.750047 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 120 -32 ) ( -248 128 -32 ) ( -224 128 -32 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.750047 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 120 -24 ) ( -224 120 -24 ) ( -224 120 -32 ) ( ( 0.007813 0 0.750047 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 120 -24 ) ( -224 128 -24 ) ( -224 128 -32 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 128 -24 ) ( -248 128 -24 ) ( -248 128 -32 ) ( ( 0.007813 0 -0.750047 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 128 -24 ) ( -248 120 -24 ) ( -248 120 -32 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 254 +{ +brushDef +{ +( -248 128 -48 ) ( -272 128 -48 ) ( -272 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.937558 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -272 120 -40 ) ( -272 128 -40 ) ( -248 128 -40 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.937558 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -272 120 -32 ) ( -248 120 -32 ) ( -248 120 -40 ) ( ( 0.007813 0 0.937558 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 120 -32 ) ( -248 128 -32 ) ( -248 128 -40 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 128 -32 ) ( -272 128 -32 ) ( -272 128 -40 ) ( ( 0.007813 0 -0.937558 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -272 128 -32 ) ( -272 120 -32 ) ( -272 120 -40 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 255 +{ +brushDef +{ +( -248 -120 -48 ) ( -272 -120 -48 ) ( -272 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.937558 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -272 -128 -40 ) ( -272 -120 -40 ) ( -248 -120 -40 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.937558 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -272 -128 -32 ) ( -248 -128 -32 ) ( -248 -128 -40 ) ( ( 0.007813 0 0.937558 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 -128 -32 ) ( -248 -120 -32 ) ( -248 -120 -40 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 -120 -32 ) ( -272 -120 -32 ) ( -272 -120 -40 ) ( ( 0.007813 0 -0.937558 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -272 -120 -32 ) ( -272 -128 -32 ) ( -272 -128 -40 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 256 +{ +brushDef +{ +( -224 -120 -48 ) ( -248 -120 -48 ) ( -248 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.750047 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 -128 -32 ) ( -248 -120 -32 ) ( -224 -120 -32 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.750047 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 -128 -24 ) ( -224 -128 -24 ) ( -224 -128 -32 ) ( ( 0.007813 0 0.750047 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 -128 -24 ) ( -224 -120 -24 ) ( -224 -120 -32 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 -120 -24 ) ( -248 -120 -24 ) ( -248 -120 -32 ) ( ( 0.007813 0 -0.750047 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -248 -120 -24 ) ( -248 -128 -24 ) ( -248 -128 -32 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 257 +{ +brushDef +{ +( -200 -120 -48 ) ( -224 -120 -48 ) ( -224 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562536 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 -128 -24 ) ( -224 -120 -24 ) ( -200 -120 -24 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.562536 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 -128 -16 ) ( -200 -128 -16 ) ( -200 -128 -24 ) ( ( 0.007813 0 0.562536 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 -128 -16 ) ( -200 -120 -16 ) ( -200 -120 -24 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 -120 -16 ) ( -224 -120 -16 ) ( -224 -120 -24 ) ( ( 0.007813 0 -0.562536 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -224 -120 -16 ) ( -224 -128 -16 ) ( -224 -128 -24 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 258 +{ +brushDef +{ +( -176 -120 -48 ) ( -200 -120 -48 ) ( -200 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.375024 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 -128 -16 ) ( -200 -120 -16 ) ( -176 -120 -16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.375024 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 -128 -8 ) ( -176 -128 -8 ) ( -176 -128 -16 ) ( ( 0.007813 0 0.375024 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 -128 -8 ) ( -176 -120 -8 ) ( -176 -120 -16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 -120 -8 ) ( -200 -120 -8 ) ( -200 -120 -16 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -200 -120 -8 ) ( -200 -128 -8 ) ( -200 -128 -16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 259 +{ +brushDef +{ +( -152 -120 -48 ) ( -176 -120 -48 ) ( -176 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 -128 -8 ) ( -176 -120 -8 ) ( -152 -120 -8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.187512 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 -128 0 ) ( -152 -128 0 ) ( -152 -128 -8 ) ( ( 0.007813 0 0.187512 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -152 -128 0 ) ( -152 -120 0 ) ( -152 -120 -8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -152 -120 0 ) ( -176 -120 0 ) ( -176 -120 -8 ) ( ( 0.007813 0 -0.187512 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +( -176 -120 0 ) ( -176 -128 0 ) ( -176 -128 -8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 134217728 0 0 +} +} +// brush 260 +{ +brushDef +{ +( -128 -120 -48 ) ( -152 -120 -48 ) ( -152 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 -128 0 ) ( -152 -120 0 ) ( -128 -120 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 -128 8 ) ( -128 -128 8 ) ( -128 -128 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 -128 8 ) ( -128 -120 8 ) ( -128 -120 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 -120 8 ) ( -152 -120 8 ) ( -152 -120 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 -120 8 ) ( -152 -128 8 ) ( -152 -128 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 261 +{ +brushDef +{ +( 384 -152 0 ) ( 384 -128 0 ) ( 128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -128 8 ) ( 384 -128 8 ) ( 384 -152 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -128 8 ) ( 136 -152 8 ) ( 136 -152 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -152 8 ) ( 384 -152 8 ) ( 384 -152 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -152 8 ) ( 376 -128 8 ) ( 376 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -128 8 ) ( 128 -128 8 ) ( 128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 262 +{ +brushDef +{ +( 384 -176 -8 ) ( 384 -152 -8 ) ( 128 -152 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -152 0 ) ( 384 -152 0 ) ( 384 -176 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -152 0 ) ( 136 -176 0 ) ( 136 -176 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -176 0 ) ( 384 -176 0 ) ( 384 -176 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -176 0 ) ( 376 -152 0 ) ( 376 -152 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -152 0 ) ( 128 -152 0 ) ( 128 -152 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 263 +{ +brushDef +{ +( 384 -200 -16 ) ( 384 -176 -16 ) ( 128 -176 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -176 -8 ) ( 384 -176 -8 ) ( 384 -200 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -176 -8 ) ( 136 -200 -8 ) ( 136 -200 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -200 -8 ) ( 384 -200 -8 ) ( 384 -200 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -200 -8 ) ( 376 -176 -8 ) ( 376 -176 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -176 -8 ) ( 128 -176 -8 ) ( 128 -176 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 264 +{ +brushDef +{ +( 384 -224 -24 ) ( 384 -200 -24 ) ( 128 -200 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -200 -16 ) ( 384 -200 -16 ) ( 384 -224 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -200 -16 ) ( 136 -224 -16 ) ( 136 -224 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -224 -16 ) ( 384 -224 -16 ) ( 384 -224 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -224 -16 ) ( 376 -200 -16 ) ( 376 -200 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -200 -16 ) ( 128 -200 -16 ) ( 128 -200 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 265 +{ +brushDef +{ +( 384 -248 -32 ) ( 384 -224 -32 ) ( 128 -224 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -224 -24 ) ( 384 -224 -24 ) ( 384 -248 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -224 -24 ) ( 136 -248 -24 ) ( 136 -248 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -248 -24 ) ( 384 -248 -24 ) ( 384 -248 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -248 -24 ) ( 376 -224 -24 ) ( 376 -224 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -224 -24 ) ( 128 -224 -24 ) ( 128 -224 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 266 +{ +brushDef +{ +( 384 -272 -40 ) ( 384 -248 -40 ) ( 128 -248 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -248 -32 ) ( 384 -248 -32 ) ( 384 -272 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -248 -32 ) ( 136 -272 -32 ) ( 136 -272 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -272 -32 ) ( 384 -272 -32 ) ( 384 -272 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -272 -32 ) ( 376 -248 -32 ) ( 376 -248 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -248 -32 ) ( 128 -248 -32 ) ( 128 -248 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 267 +{ +brushDef +{ +( 384 -296 -48 ) ( 384 -272 -48 ) ( 128 -272 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -272 -40 ) ( 384 -272 -40 ) ( 384 -296 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -272 -40 ) ( 136 -296 -40 ) ( 136 -296 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -296 -40 ) ( 384 -296 -40 ) ( 384 -296 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -296 -40 ) ( 376 -272 -40 ) ( 376 -272 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -272 -40 ) ( 128 -272 -40 ) ( 128 -272 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 268 +{ +brushDef +{ +( 136 -120 -48 ) ( 24 -120 -48 ) ( 24 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 24 -128 0 ) ( 24 -120 0 ) ( 136 -120 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 24 -128 -40 ) ( 136 -128 -40 ) ( 136 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -144 -40 ) ( 640 -136 -40 ) ( 640 -136 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -120 -40 ) ( 24 -120 -40 ) ( 24 -120 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 -128 -40 ) ( -128 -136 -40 ) ( -128 -136 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 269 +{ +brushDef +{ +( -152 -128 0 ) ( -128 -128 0 ) ( -128 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 128 8 ) ( -128 -128 8 ) ( -152 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 128 8 ) ( -152 128 8 ) ( -152 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -152 128 8 ) ( -152 -128 8 ) ( -152 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -152 -128 8 ) ( -128 -128 8 ) ( -128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -128 8 ) ( -128 128 8 ) ( -128 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 270 +{ +brushDef +{ +( -176 -128 -8 ) ( -152 -128 -8 ) ( -152 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -152 128 0 ) ( -152 -128 0 ) ( -176 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -152 128 0 ) ( -176 128 0 ) ( -176 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -176 128 0 ) ( -176 -128 0 ) ( -176 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -176 -128 0 ) ( -152 -128 0 ) ( -152 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -152 -128 0 ) ( -152 128 0 ) ( -152 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 271 +{ +brushDef +{ +( -200 -128 -16 ) ( -176 -128 -16 ) ( -176 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -176 128 -8 ) ( -176 -128 -8 ) ( -200 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -176 128 -8 ) ( -200 128 -8 ) ( -200 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -200 128 -8 ) ( -200 -128 -8 ) ( -200 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -200 -128 -8 ) ( -176 -128 -8 ) ( -176 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -176 -128 -8 ) ( -176 128 -8 ) ( -176 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 272 +{ +brushDef +{ +( -224 -128 -24 ) ( -200 -128 -24 ) ( -200 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -200 128 -16 ) ( -200 -128 -16 ) ( -224 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -200 128 -16 ) ( -224 128 -16 ) ( -224 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -224 128 -16 ) ( -224 -128 -16 ) ( -224 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -224 -128 -16 ) ( -200 -128 -16 ) ( -200 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -200 -128 -16 ) ( -200 128 -16 ) ( -200 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 273 +{ +brushDef +{ +( -248 -128 -32 ) ( -224 -128 -32 ) ( -224 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -224 128 -24 ) ( -224 -128 -24 ) ( -248 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -224 128 -24 ) ( -248 128 -24 ) ( -248 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -248 128 -24 ) ( -248 -128 -24 ) ( -248 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -248 -128 -24 ) ( -224 -128 -24 ) ( -224 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -224 -128 -24 ) ( -224 128 -24 ) ( -224 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 274 +{ +brushDef +{ +( -272 -128 -40 ) ( -248 -128 -40 ) ( -248 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -248 128 -32 ) ( -248 -128 -32 ) ( -272 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -248 128 -32 ) ( -272 128 -32 ) ( -272 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -272 128 -32 ) ( -272 -128 -32 ) ( -272 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -272 -128 -32 ) ( -248 -128 -32 ) ( -248 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -248 -128 -32 ) ( -248 128 -32 ) ( -248 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 275 +{ +brushDef +{ +( -296 -128 -48 ) ( -272 -128 -48 ) ( -272 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -272 128 -40 ) ( -272 -128 -40 ) ( -296 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -272 128 -40 ) ( -296 128 -40 ) ( -296 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -296 128 -40 ) ( -296 -128 -40 ) ( -296 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -296 -128 -40 ) ( -272 -128 -40 ) ( -272 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -272 -128 -40 ) ( -272 128 -40 ) ( -272 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 276 +{ +brushDef +{ +( 808 128 -48 ) ( 784 128 -48 ) ( 784 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 784 -128 -40 ) ( 784 128 -40 ) ( 808 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 784 -128 -40 ) ( 808 -128 -40 ) ( 808 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 808 -128 -40 ) ( 808 128 -40 ) ( 808 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 808 128 -40 ) ( 784 128 -40 ) ( 784 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 784 128 -40 ) ( 784 -128 -40 ) ( 784 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 277 +{ +brushDef +{ +( 784 128 -40 ) ( 760 128 -40 ) ( 760 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 760 -128 -32 ) ( 760 128 -32 ) ( 784 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 760 -128 -32 ) ( 784 -128 -32 ) ( 784 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 784 -128 -32 ) ( 784 128 -32 ) ( 784 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 784 128 -32 ) ( 760 128 -32 ) ( 760 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 760 128 -32 ) ( 760 -128 -32 ) ( 760 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 278 +{ +brushDef +{ +( 760 128 -32 ) ( 736 128 -32 ) ( 736 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 736 -128 -24 ) ( 736 128 -24 ) ( 760 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 736 -128 -24 ) ( 760 -128 -24 ) ( 760 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 760 -128 -24 ) ( 760 128 -24 ) ( 760 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 760 128 -24 ) ( 736 128 -24 ) ( 736 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 736 128 -24 ) ( 736 -128 -24 ) ( 736 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 279 +{ +brushDef +{ +( 736 128 -24 ) ( 712 128 -24 ) ( 712 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 712 -128 -16 ) ( 712 128 -16 ) ( 736 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 712 -128 -16 ) ( 736 -128 -16 ) ( 736 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 736 -128 -16 ) ( 736 128 -16 ) ( 736 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 736 128 -16 ) ( 712 128 -16 ) ( 712 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 712 128 -16 ) ( 712 -128 -16 ) ( 712 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 280 +{ +brushDef +{ +( 712 128 -16 ) ( 688 128 -16 ) ( 688 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 688 -128 -8 ) ( 688 128 -8 ) ( 712 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 688 -128 -8 ) ( 712 -128 -8 ) ( 712 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 712 -128 -8 ) ( 712 128 -8 ) ( 712 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 712 128 -8 ) ( 688 128 -8 ) ( 688 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 688 128 -8 ) ( 688 -128 -8 ) ( 688 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 281 +{ +brushDef +{ +( 688 128 -8 ) ( 664 128 -8 ) ( 664 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 664 -128 0 ) ( 664 128 0 ) ( 688 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 664 -128 0 ) ( 688 -128 0 ) ( 688 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 688 -128 0 ) ( 688 128 0 ) ( 688 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 688 128 0 ) ( 664 128 0 ) ( 664 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 664 128 0 ) ( 664 -128 0 ) ( 664 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 282 +{ +brushDef +{ +( 664 128 0 ) ( 640 128 0 ) ( 640 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 -128 8 ) ( 640 128 8 ) ( 664 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 -128 8 ) ( 664 -128 8 ) ( 664 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 664 -128 8 ) ( 664 128 8 ) ( 664 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 664 128 8 ) ( 640 128 8 ) ( 640 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 8 ) ( 640 -128 8 ) ( 640 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 283 +{ +brushDef +{ +( -120 -120 72 ) ( -888 -120 72 ) ( -888 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -888 -128 224 ) ( -888 -120 224 ) ( -120 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -888 -128 232 ) ( -120 -128 232 ) ( -120 -128 72 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 -128 232 ) ( -120 -120 232 ) ( -120 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -120 -120 232 ) ( -888 -120 232 ) ( -888 -120 72 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -120 232 ) ( -128 -128 232 ) ( -128 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 284 +{ +brushDef +{ +( -56 -120 72 ) ( -824 -120 72 ) ( -824 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -10.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -824 -128 224 ) ( -824 -120 224 ) ( -56 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 10.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -824 -128 232 ) ( -56 -128 232 ) ( -56 -128 72 ) ( ( 0.015625 0 10.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -56 -128 232 ) ( -56 -120 232 ) ( -56 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -56 -120 232 ) ( -824 -120 232 ) ( -824 -120 72 ) ( ( 0.015625 0 -10.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -64 -120 232 ) ( -64 -128 232 ) ( -64 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 285 +{ +brushDef +{ +( 8 -120 72 ) ( -760 -120 72 ) ( -760 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -760 -128 224 ) ( -760 -120 224 ) ( 8 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -760 -128 232 ) ( 8 -128 232 ) ( 8 -128 72 ) ( ( 0.015625 0 9.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 8 -128 232 ) ( 8 -120 232 ) ( 8 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 8 -120 232 ) ( -760 -120 232 ) ( -760 -120 72 ) ( ( 0.015625 0 -9.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 0 -120 232 ) ( 0 -128 232 ) ( 0 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 286 +{ +brushDef +{ +( 72 -120 72 ) ( -696 -120 72 ) ( -696 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -8.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -696 -128 224 ) ( -696 -120 224 ) ( 72 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 8.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -696 -128 232 ) ( 72 -128 232 ) ( 72 -128 72 ) ( ( 0.015625 0 8.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 72 -128 232 ) ( 72 -120 232 ) ( 72 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 72 -120 232 ) ( -696 -120 232 ) ( -696 -120 72 ) ( ( 0.015625 0 -8.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 64 -120 232 ) ( 64 -128 232 ) ( 64 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 287 +{ +brushDef +{ +( 136 -120 72 ) ( -632 -120 72 ) ( -632 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -632 -128 224 ) ( -632 -120 224 ) ( 136 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7.875000 ) ) gothic_trim/wood2 134217728 0 0 +( -632 -128 232 ) ( 136 -128 232 ) ( 136 -128 72 ) ( ( 0.015625 0 7.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -128 232 ) ( 136 -120 232 ) ( 136 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -120 232 ) ( -632 -120 232 ) ( -632 -120 72 ) ( ( 0.015625 0 -7.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -120 232 ) ( 128 -128 232 ) ( 128 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 288 +{ +brushDef +{ +( 384 -120 72 ) ( -384 -120 72 ) ( -384 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -4 ) ) gothic_trim/wood2 134217728 0 0 +( -384 -128 224 ) ( -384 -120 224 ) ( 384 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 4 ) ) gothic_trim/wood2 134217728 0 0 +( -384 -128 232 ) ( 384 -128 232 ) ( 384 -128 72 ) ( ( 0.015625 0 4 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -128 232 ) ( 384 -120 232 ) ( 384 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -120 232 ) ( -384 -120 232 ) ( -384 -120 72 ) ( ( 0.015625 0 -4 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -120 232 ) ( 376 -128 232 ) ( 376 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 289 +{ +brushDef +{ +( 448 -120 72 ) ( -320 -120 72 ) ( -320 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -3 ) ) gothic_trim/wood2 134217728 0 0 +( -320 -128 224 ) ( -320 -120 224 ) ( 448 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 3 ) ) gothic_trim/wood2 134217728 0 0 +( -320 -128 232 ) ( 448 -128 232 ) ( 448 -128 72 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 448 -128 232 ) ( 448 -120 232 ) ( 448 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 448 -120 232 ) ( -320 -120 232 ) ( -320 -120 72 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 440 -120 232 ) ( 440 -128 232 ) ( 440 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 290 +{ +brushDef +{ +( 512 -120 72 ) ( -256 -120 72 ) ( -256 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2 ) ) gothic_trim/wood2 134217728 0 0 +( -256 -128 224 ) ( -256 -120 224 ) ( 512 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2 ) ) gothic_trim/wood2 134217728 0 0 +( -256 -128 232 ) ( 512 -128 232 ) ( 512 -128 72 ) ( ( 0.015625 0 2 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 512 -128 232 ) ( 512 -120 232 ) ( 512 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 512 -120 232 ) ( -256 -120 232 ) ( -256 -120 72 ) ( ( 0.015625 0 -2 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 504 -120 232 ) ( 504 -128 232 ) ( 504 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 291 +{ +brushDef +{ +( 576 -120 72 ) ( -192 -120 72 ) ( -192 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -1 ) ) gothic_trim/wood2 134217728 0 0 +( -192 -128 224 ) ( -192 -120 224 ) ( 576 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 1 ) ) gothic_trim/wood2 134217728 0 0 +( -192 -128 232 ) ( 576 -128 232 ) ( 576 -128 72 ) ( ( 0.015625 0 1 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 576 -128 232 ) ( 576 -120 232 ) ( 576 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 576 -120 232 ) ( -192 -120 232 ) ( -192 -120 72 ) ( ( 0.015625 0 -1 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 568 -120 232 ) ( 568 -128 232 ) ( 568 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 292 +{ +brushDef +{ +( 640 -120 72 ) ( -128 -120 72 ) ( -128 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -128 224 ) ( -128 -120 224 ) ( 640 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -128 232 ) ( 640 -128 232 ) ( 640 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 -128 232 ) ( 640 -120 232 ) ( 640 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 640 -120 232 ) ( -128 -120 232 ) ( -128 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( 632 -120 232 ) ( 632 -128 232 ) ( 632 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 293 +{ +brushDef +{ +( -128 -128 224 ) ( 640 -128 224 ) ( 640 128 312 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -128 232 ) ( -128 -128 232 ) ( -128 128 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +( -128 -128 224 ) ( -128 -128 232 ) ( 640 -128 232 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -128 320 ) ( 640 128 320 ) ( 640 128 8 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -32 128 320 ) ( -128 128 320 ) ( -128 128 8 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 -128 232 ) ( -128 -128 224 ) ( -128 128 312 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 294 +{ +brushDef +{ +( 664 -120 64 ) ( 384 -120 64 ) ( 384 -128 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -128 72 ) ( 376 -120 72 ) ( 656 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -128 72 ) ( 656 -128 72 ) ( 656 -128 16 ) ( ( 0.015625 0 -7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 640 -128 72 ) ( 640 -120 72 ) ( 640 -120 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 656 -120 72 ) ( 376 -120 72 ) ( 376 -120 16 ) ( ( 0.015625 0 7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -120 72 ) ( 376 -128 72 ) ( 376 -128 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 295 +{ +brushDef +{ +( 160 -120 64 ) ( -120 -120 64 ) ( -120 -128 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -128 72 ) ( -128 -120 72 ) ( 152 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -128 72 ) ( 152 -128 72 ) ( 152 -128 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -128 72 ) ( 136 -120 72 ) ( 136 -120 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 152 -120 72 ) ( -128 -120 72 ) ( -128 -120 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -120 72 ) ( -128 -128 72 ) ( -128 -128 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 296 +{ +brushDef +{ +( 384 -120 8 ) ( 376 -120 8 ) ( 376 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -128 64 ) ( 376 -120 64 ) ( 384 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -128 16 ) ( 384 -128 16 ) ( 384 -128 8 ) ( ( 0.015625 0 -7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -128 16 ) ( 384 -120 16 ) ( 384 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 384 -120 16 ) ( 376 -120 16 ) ( 376 -120 8 ) ( ( 0.015625 0 7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 376 -120 16 ) ( 376 -128 16 ) ( 376 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 297 +{ +brushDef +{ +( 416 -120 8 ) ( 408 -120 8 ) ( 408 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 8.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 408 -128 64 ) ( 408 -120 64 ) ( 416 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -8.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 408 -128 16 ) ( 416 -128 16 ) ( 416 -128 8 ) ( ( 0.015625 0 -8.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 416 -128 16 ) ( 416 -120 16 ) ( 416 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 416 -120 16 ) ( 408 -120 16 ) ( 408 -120 8 ) ( ( 0.015625 0 8.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 408 -120 16 ) ( 408 -128 16 ) ( 408 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 298 +{ +brushDef +{ +( 448 -120 8 ) ( 440 -120 8 ) ( 440 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 8.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 -128 64 ) ( 440 -120 64 ) ( 448 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -8.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 -128 16 ) ( 448 -128 16 ) ( 448 -128 8 ) ( ( 0.015625 0 -8.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 448 -128 16 ) ( 448 -120 16 ) ( 448 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 448 -120 16 ) ( 440 -120 16 ) ( 440 -120 8 ) ( ( 0.015625 0 8.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 440 -120 16 ) ( 440 -128 16 ) ( 440 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 299 +{ +brushDef +{ +( 480 -120 8 ) ( 472 -120 8 ) ( 472 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 472 -128 64 ) ( 472 -120 64 ) ( 480 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 472 -128 16 ) ( 480 -128 16 ) ( 480 -128 8 ) ( ( 0.015625 0 -9.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 480 -128 16 ) ( 480 -120 16 ) ( 480 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 480 -120 16 ) ( 472 -120 16 ) ( 472 -120 8 ) ( ( 0.015625 0 9.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 472 -120 16 ) ( 472 -128 16 ) ( 472 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 300 +{ +brushDef +{ +( 512 -120 8 ) ( 504 -120 8 ) ( 504 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 504 -128 64 ) ( 504 -120 64 ) ( 512 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 504 -128 16 ) ( 512 -128 16 ) ( 512 -128 8 ) ( ( 0.015625 0 -9.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 512 -128 16 ) ( 512 -120 16 ) ( 512 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 512 -120 16 ) ( 504 -120 16 ) ( 504 -120 8 ) ( ( 0.015625 0 9.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 504 -120 16 ) ( 504 -128 16 ) ( 504 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 301 +{ +brushDef +{ +( 544 -120 8 ) ( 536 -120 8 ) ( 536 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 10.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 536 -128 64 ) ( 536 -120 64 ) ( 544 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -10.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 536 -128 16 ) ( 544 -128 16 ) ( 544 -128 8 ) ( ( 0.015625 0 -10.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 544 -128 16 ) ( 544 -120 16 ) ( 544 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 544 -120 16 ) ( 536 -120 16 ) ( 536 -120 8 ) ( ( 0.015625 0 10.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 536 -120 16 ) ( 536 -128 16 ) ( 536 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 302 +{ +brushDef +{ +( 576 -120 8 ) ( 568 -120 8 ) ( 568 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 10.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 568 -128 64 ) ( 568 -120 64 ) ( 576 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -10.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 568 -128 16 ) ( 576 -128 16 ) ( 576 -128 8 ) ( ( 0.015625 0 -10.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 576 -128 16 ) ( 576 -120 16 ) ( 576 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 576 -120 16 ) ( 568 -120 16 ) ( 568 -120 8 ) ( ( 0.015625 0 10.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 568 -120 16 ) ( 568 -128 16 ) ( 568 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 303 +{ +brushDef +{ +( 608 -120 8 ) ( 600 -120 8 ) ( 600 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 11.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 600 -128 64 ) ( 600 -120 64 ) ( 608 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -11.375000 ) ) gothic_trim/wood2 134217728 0 0 +( 600 -128 16 ) ( 608 -128 16 ) ( 608 -128 8 ) ( ( 0.015625 0 -11.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 608 -128 16 ) ( 608 -120 16 ) ( 608 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 608 -120 16 ) ( 600 -120 16 ) ( 600 -120 8 ) ( ( 0.015625 0 11.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 600 -120 16 ) ( 600 -128 16 ) ( 600 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 304 +{ +brushDef +{ +( 640 -120 8 ) ( 632 -120 8 ) ( 632 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 -128 64 ) ( 632 -120 64 ) ( 640 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 -128 16 ) ( 640 -128 16 ) ( 640 -128 8 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 640 -128 16 ) ( 640 -120 16 ) ( 640 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 640 -120 16 ) ( 632 -120 16 ) ( 632 -120 8 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 632 -120 16 ) ( 632 -128 16 ) ( 632 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 305 +{ +brushDef +{ +( -88 -120 8 ) ( -96 -120 8 ) ( -96 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.500000 ) ) gothic_trim/wood2 134217728 0 0 +( -96 -128 64 ) ( -96 -120 64 ) ( -88 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.500000 ) ) gothic_trim/wood2 134217728 0 0 +( -96 -128 16 ) ( -88 -128 16 ) ( -88 -128 8 ) ( ( 0.015625 0 -0.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -88 -128 16 ) ( -88 -120 16 ) ( -88 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -88 -120 16 ) ( -96 -120 16 ) ( -96 -120 8 ) ( ( 0.015625 0 0.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -96 -120 16 ) ( -96 -128 16 ) ( -96 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 306 +{ +brushDef +{ +( -24 -120 8 ) ( -32 -120 8 ) ( -32 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 1.500000 ) ) gothic_trim/wood2 134217728 0 0 +( -32 -128 64 ) ( -32 -120 64 ) ( -24 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -1.500000 ) ) gothic_trim/wood2 134217728 0 0 +( -32 -128 16 ) ( -24 -128 16 ) ( -24 -128 8 ) ( ( 0.015625 0 -1.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -24 -128 16 ) ( -24 -120 16 ) ( -24 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -24 -120 16 ) ( -32 -120 16 ) ( -32 -120 8 ) ( ( 0.015625 0 1.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -32 -120 16 ) ( -32 -128 16 ) ( -32 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 307 +{ +brushDef +{ +( 40 -120 8 ) ( 32 -120 8 ) ( 32 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 32 -128 64 ) ( 32 -120 64 ) ( 40 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 32 -128 16 ) ( 40 -128 16 ) ( 40 -128 8 ) ( ( 0.015625 0 -2.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 40 -128 16 ) ( 40 -120 16 ) ( 40 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 40 -120 16 ) ( 32 -120 16 ) ( 32 -120 8 ) ( ( 0.015625 0 2.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 32 -120 16 ) ( 32 -128 16 ) ( 32 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 308 +{ +brushDef +{ +( 104 -120 8 ) ( 96 -120 8 ) ( 96 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 3.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 96 -128 64 ) ( 96 -120 64 ) ( 104 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -3.500000 ) ) gothic_trim/wood2 134217728 0 0 +( 96 -128 16 ) ( 104 -128 16 ) ( 104 -128 8 ) ( ( 0.015625 0 -3.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 104 -128 16 ) ( 104 -120 16 ) ( 104 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 104 -120 16 ) ( 96 -120 16 ) ( 96 -120 8 ) ( ( 0.015625 0 3.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 96 -120 16 ) ( 96 -128 16 ) ( 96 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 309 +{ +brushDef +{ +( 136 -120 8 ) ( 128 -120 8 ) ( 128 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 4 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -128 64 ) ( 128 -120 64 ) ( 136 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -4 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -128 16 ) ( 136 -128 16 ) ( 136 -128 8 ) ( ( 0.015625 0 -4 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -128 16 ) ( 136 -120 16 ) ( 136 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 136 -120 16 ) ( 128 -120 16 ) ( 128 -120 8 ) ( ( 0.015625 0 4 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 128 -120 16 ) ( 128 -128 16 ) ( 128 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 310 +{ +brushDef +{ +( 72 -120 8 ) ( 64 -120 8 ) ( 64 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 3 ) ) gothic_trim/wood2 134217728 0 0 +( 64 -128 64 ) ( 64 -120 64 ) ( 72 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -3 ) ) gothic_trim/wood2 134217728 0 0 +( 64 -128 16 ) ( 72 -128 16 ) ( 72 -128 8 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 72 -128 16 ) ( 72 -120 16 ) ( 72 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 72 -120 16 ) ( 64 -120 16 ) ( 64 -120 8 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 64 -120 16 ) ( 64 -128 16 ) ( 64 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 311 +{ +brushDef +{ +( 8 -120 8 ) ( 0 -120 8 ) ( 0 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2 ) ) gothic_trim/wood2 134217728 0 0 +( 0 -128 64 ) ( 0 -120 64 ) ( 8 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2 ) ) gothic_trim/wood2 134217728 0 0 +( 0 -128 16 ) ( 8 -128 16 ) ( 8 -128 8 ) ( ( 0.015625 0 -2 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 8 -128 16 ) ( 8 -120 16 ) ( 8 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 8 -120 16 ) ( 0 -120 16 ) ( 0 -120 8 ) ( ( 0.015625 0 2 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( 0 -120 16 ) ( 0 -128 16 ) ( 0 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 312 +{ +brushDef +{ +( -56 -120 8 ) ( -64 -120 8 ) ( -64 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 1 ) ) gothic_trim/wood2 134217728 0 0 +( -64 -128 64 ) ( -64 -120 64 ) ( -56 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -1 ) ) gothic_trim/wood2 134217728 0 0 +( -64 -128 16 ) ( -56 -128 16 ) ( -56 -128 8 ) ( ( 0.015625 0 -1 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -56 -128 16 ) ( -56 -120 16 ) ( -56 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -56 -120 16 ) ( -64 -120 16 ) ( -64 -120 8 ) ( ( 0.015625 0 1 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -64 -120 16 ) ( -64 -128 16 ) ( -64 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 313 +{ +brushDef +{ +( -120 -120 8 ) ( -128 -120 8 ) ( -128 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -128 64 ) ( -128 -120 64 ) ( -120 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -128 16 ) ( -120 -128 16 ) ( -120 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -120 -128 16 ) ( -120 -120 16 ) ( -120 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -120 -120 16 ) ( -128 -120 16 ) ( -128 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +( -128 -120 16 ) ( -128 -128 16 ) ( -128 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 134217728 0 0 +} +} +// brush 314 +{ +brushDef +{ +( 256 128 0 ) ( -128 128 0 ) ( -128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 8 ) ( -128 128 8 ) ( 256 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 8 ) ( 256 -128 8 ) ( 256 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 -120 8 ) ( 640 136 8 ) ( 640 136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 960 8 ) ( -64 960 8 ) ( -64 960 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 8 ) ( -128 -128 8 ) ( -128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +} +// entity 1 +{ +"origin" "248 512 336" +"light" "600" +"classname" "light" +} +// entity 2 +{ +"origin" "576 -64 32" +"classname" "info_player_start" +} +// entity 3 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 456 744 72 0 0 ) ( 456 744 76 0 0.062500 ) ( 456 744 80 0 0.125000 ) ) +( ( 456 728 72 0.250000 0 ) ( 456 728 76 0.250000 0.062500 ) ( 456 728 80 0.250000 0.125000 ) ) +( ( 472 728 72 0.500000 0 ) ( 472 728 76 0.500000 0.062500 ) ( 472 728 80 0.500000 0.125000 ) ) +( ( 488 728 72 0.750000 0 ) ( 488 728 76 0.750000 0.062500 ) ( 488 728 80 0.750000 0.125000 ) ) +( ( 488 744 72 1 0 ) ( 488 744 76 1 0.062500 ) ( 488 744 80 1 0.125000 ) ) +( ( 488 760 72 1.250000 0 ) ( 488 760 76 1.250000 0.062500 ) ( 488 760 80 1.250000 0.125000 ) ) +( ( 472 760 72 1.500000 0 ) ( 472 760 76 1.500000 0.062500 ) ( 472 760 80 1.500000 0.125000 ) ) +( ( 456 760 72 1.750000 0 ) ( 456 760 76 1.750000 0.062500 ) ( 456 760 80 1.750000 0.125000 ) ) +( ( 456 744 72 2 0 ) ( 456 744 76 2 0.062500 ) ( 456 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 472 760 72 7.375000 -11.875000 ) ( 456 760 72 7.125000 -11.875000 ) ( 456 744 72 7.125000 -11.625000 ) ) +( ( 488 760 72 7.625000 -11.875000 ) ( 472 744 72 7.375000 -11.625000 ) ( 456 728 72 7.125000 -11.375000 ) ) +( ( 488 744 72 7.625000 -11.625000 ) ( 488 728 72 7.625000 -11.375000 ) ( 472 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 456 744 80 7.125000 -11.625000 ) ( 456 760 80 7.125000 -11.875000 ) ( 472 760 80 7.375000 -11.875000 ) ) +( ( 456 728 80 7.125000 -11.375000 ) ( 472 744 80 7.375000 -11.625000 ) ( 488 760 80 7.625000 -11.875000 ) ) +( ( 472 728 80 7.375000 -11.375000 ) ( 488 728 80 7.625000 -11.375000 ) ( 488 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 4 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 400 320 64 0 0 ) ( 400 320 68 0 0.062500 ) ( 400 320 72 0 0.125000 ) ) +( ( 400 272 64 0.750000 0 ) ( 400 272 68 0.750000 0.062500 ) ( 400 272 72 0.750000 0.125000 ) ) +( ( 448 272 64 1.500000 0 ) ( 448 272 68 1.500000 0.062500 ) ( 448 272 72 1.500000 0.125000 ) ) +( ( 496 272 64 2.250000 0 ) ( 496 272 68 2.250000 0.062500 ) ( 496 272 72 2.250000 0.125000 ) ) +( ( 496 320 64 3 0 ) ( 496 320 68 3 0.062500 ) ( 496 320 72 3 0.125000 ) ) +( ( 496 368 64 3.750000 0 ) ( 496 368 68 3.750000 0.062500 ) ( 496 368 72 3.750000 0.125000 ) ) +( ( 448 368 64 4.500000 0 ) ( 448 368 68 4.500000 0.062500 ) ( 448 368 72 4.500000 0.125000 ) ) +( ( 400 368 64 5.250000 0 ) ( 400 368 68 5.250000 0.062500 ) ( 400 368 72 5.250000 0.125000 ) ) +( ( 400 320 64 6 0 ) ( 400 320 68 6 0.062500 ) ( 400 320 72 6 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 448 368 64 7 -5.750000 ) ( 400 368 64 6.250000 -5.750000 ) ( 400 320 64 6.250000 -5 ) ) +( ( 496 368 64 7.750000 -5.750000 ) ( 448 320 64 7 -5 ) ( 400 272 64 6.250000 -4.250000 ) ) +( ( 496 320 64 7.750000 -5 ) ( 496 272 64 7.750000 -4.250000 ) ( 448 272 64 7 -4.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 400 320 72 6.250000 -5 ) ( 400 368 72 6.250000 -5.750000 ) ( 448 368 72 7 -5.750000 ) ) +( ( 400 272 72 6.250000 -4.250000 ) ( 448 320 72 7 -5 ) ( 496 368 72 7.750000 -5.750000 ) ) +( ( 448 272 72 7 -4.250000 ) ( 496 272 72 7.750000 -4.250000 ) ( 496 320 72 7.750000 -5 ) ) +) + } + } +} +// entity 5 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 192 132 88 0 0 ) ( 192 132 108 0 0.312500 ) ( 192 132 128 0 0.625000 ) ) +( ( 192 128 88 0.062500 0 ) ( 192 128 108 0.062500 0.312500 ) ( 192 128 128 0.062500 0.625000 ) ) +( ( 196 128 88 0.125000 0 ) ( 196 128 108 0.125000 0.312500 ) ( 196 128 128 0.125000 0.625000 ) ) +( ( 200 128 88 0.187500 0 ) ( 200 128 108 0.187500 0.312500 ) ( 200 128 128 0.187500 0.625000 ) ) +( ( 200 132 88 0.250000 0 ) ( 200 132 108 0.250000 0.312500 ) ( 200 132 128 0.250000 0.625000 ) ) +( ( 200 136 88 0.312500 0 ) ( 200 136 108 0.312500 0.312500 ) ( 200 136 128 0.312500 0.625000 ) ) +( ( 196 136 88 0.375000 0 ) ( 196 136 108 0.375000 0.312500 ) ( 196 136 128 0.375000 0.625000 ) ) +( ( 192 136 88 0.437500 0 ) ( 192 136 108 0.437500 0.312500 ) ( 192 136 128 0.437500 0.625000 ) ) +( ( 192 132 88 0.500000 0 ) ( 192 132 108 0.500000 0.312500 ) ( 192 132 128 0.500000 0.625000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 196 136 88 3.062500 -2.125000 ) ( 192 136 88 3 -2.125000 ) ( 192 132 88 3 -2.062500 ) ) +( ( 200 136 88 3.125000 -2.125000 ) ( 196 132 88 3.062500 -2.062500 ) ( 192 128 88 3 -2 ) ) +( ( 200 132 88 3.125000 -2.062500 ) ( 200 128 88 3.125000 -2 ) ( 196 128 88 3.062500 -2 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 192 132 128 3 -2.062500 ) ( 192 136 128 3 -2.125000 ) ( 196 136 128 3.062500 -2.125000 ) ) +( ( 192 128 128 3 -2 ) ( 196 132 128 3.062500 -2.062500 ) ( 200 136 128 3.125000 -2.125000 ) ) +( ( 196 128 128 3.062500 -2 ) ( 200 128 128 3.125000 -2 ) ( 200 132 128 3.125000 -2.062500 ) ) +) + } + } +} +// entity 6 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 204 136 88 0 0 ) ( 204 136 108 0 0.312500 ) ( 204 136 128 0 0.625000 ) ) +( ( 208 136 88 0.062500 0 ) ( 208 136 108 0.062500 0.312500 ) ( 208 136 128 0.062500 0.625000 ) ) +( ( 208 140 88 0.125000 0 ) ( 208 140 108 0.125000 0.312500 ) ( 208 140 128 0.125000 0.625000 ) ) +( ( 208 144 88 0.187500 0 ) ( 208 144 108 0.187500 0.312500 ) ( 208 144 128 0.187500 0.625000 ) ) +( ( 204 144 88 0.250000 0 ) ( 204 144 108 0.250000 0.312500 ) ( 204 144 128 0.250000 0.625000 ) ) +( ( 200 144 88 0.312500 0 ) ( 200 144 108 0.312500 0.312500 ) ( 200 144 128 0.312500 0.625000 ) ) +( ( 200 140 88 0.375000 0 ) ( 200 140 108 0.375000 0.312500 ) ( 200 140 128 0.375000 0.625000 ) ) +( ( 200 136 88 0.437500 0 ) ( 200 136 108 0.437500 0.312500 ) ( 200 136 128 0.437500 0.625000 ) ) +( ( 204 136 88 0.500000 0 ) ( 204 136 108 0.500000 0.312500 ) ( 204 136 128 0.500000 0.625000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 200 140 88 3.187500 -2.125000 ) ( 200 136 88 3.125000 -2.125000 ) ( 204 136 88 3.125000 -2.062500 ) ) +( ( 200 144 88 3.250000 -2.125000 ) ( 204 140 88 3.187500 -2.062500 ) ( 208 136 88 3.125000 -2 ) ) +( ( 204 144 88 3.250000 -2.062500 ) ( 208 144 88 3.250000 -2 ) ( 208 140 88 3.187500 -2 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 204 136 128 3.125000 -2.062500 ) ( 200 136 128 3.125000 -2.125000 ) ( 200 140 128 3.187500 -2.125000 ) ) +( ( 208 136 128 3.125000 -2 ) ( 204 140 128 3.187500 -2.062500 ) ( 200 144 128 3.250000 -2.125000 ) ) +( ( 208 140 128 3.187500 -2 ) ( 208 144 128 3.250000 -2 ) ( 204 144 128 3.250000 -2.062500 ) ) +) + } + } +} +// entity 7 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 312 132 88 0 0 ) ( 312 132 108 0 0.312500 ) ( 312 132 128 0 0.625000 ) ) +( ( 312 128 88 0.062500 0 ) ( 312 128 108 0.062500 0.312500 ) ( 312 128 128 0.062500 0.625000 ) ) +( ( 316 128 88 0.125000 0 ) ( 316 128 108 0.125000 0.312500 ) ( 316 128 128 0.125000 0.625000 ) ) +( ( 320 128 88 0.187500 0 ) ( 320 128 108 0.187500 0.312500 ) ( 320 128 128 0.187500 0.625000 ) ) +( ( 320 132 88 0.250000 0 ) ( 320 132 108 0.250000 0.312500 ) ( 320 132 128 0.250000 0.625000 ) ) +( ( 320 136 88 0.312500 0 ) ( 320 136 108 0.312500 0.312500 ) ( 320 136 128 0.312500 0.625000 ) ) +( ( 316 136 88 0.375000 0 ) ( 316 136 108 0.375000 0.312500 ) ( 316 136 128 0.375000 0.625000 ) ) +( ( 312 136 88 0.437500 0 ) ( 312 136 108 0.437500 0.312500 ) ( 312 136 128 0.437500 0.625000 ) ) +( ( 312 132 88 0.500000 0 ) ( 312 132 108 0.500000 0.312500 ) ( 312 132 128 0.500000 0.625000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 316 136 88 4.937500 -2.125000 ) ( 312 136 88 4.875000 -2.125000 ) ( 312 132 88 4.875000 -2.062500 ) ) +( ( 320 136 88 5 -2.125000 ) ( 316 132 88 4.937500 -2.062500 ) ( 312 128 88 4.875000 -2 ) ) +( ( 320 132 88 5 -2.062500 ) ( 320 128 88 5 -2 ) ( 316 128 88 4.937500 -2 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 312 132 128 4.875000 -2.062500 ) ( 312 136 128 4.875000 -2.125000 ) ( 316 136 128 4.937500 -2.125000 ) ) +( ( 312 128 128 4.875000 -2 ) ( 316 132 128 4.937500 -2.062500 ) ( 320 136 128 5 -2.125000 ) ) +( ( 316 128 128 4.937500 -2 ) ( 320 128 128 5 -2 ) ( 320 132 128 5 -2.062500 ) ) +) + } + } +} +// entity 8 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 308 144 88 0 0 ) ( 308 144 108 0 0.312500 ) ( 308 144 128 0 0.625000 ) ) +( ( 304 144 88 0.062500 0 ) ( 304 144 108 0.062500 0.312500 ) ( 304 144 128 0.062500 0.625000 ) ) +( ( 304 140 88 0.125000 0 ) ( 304 140 108 0.125000 0.312500 ) ( 304 140 128 0.125000 0.625000 ) ) +( ( 304 136 88 0.187500 0 ) ( 304 136 108 0.187500 0.312500 ) ( 304 136 128 0.187500 0.625000 ) ) +( ( 308 136 88 0.250000 0 ) ( 308 136 108 0.250000 0.312500 ) ( 308 136 128 0.250000 0.625000 ) ) +( ( 312 136 88 0.312500 0 ) ( 312 136 108 0.312500 0.312500 ) ( 312 136 128 0.312500 0.625000 ) ) +( ( 312 140 88 0.375000 0 ) ( 312 140 108 0.375000 0.312500 ) ( 312 140 128 0.375000 0.625000 ) ) +( ( 312 144 88 0.437500 0 ) ( 312 144 108 0.437500 0.312500 ) ( 312 144 128 0.437500 0.625000 ) ) +( ( 308 144 88 0.500000 0 ) ( 308 144 108 0.500000 0.312500 ) ( 308 144 128 0.500000 0.625000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 312 140 88 4.812500 -2.125000 ) ( 312 144 88 4.750000 -2.125000 ) ( 308 144 88 4.750000 -2.062500 ) ) +( ( 312 136 88 4.875000 -2.125000 ) ( 308 140 88 4.812500 -2.062500 ) ( 304 144 88 4.750000 -2 ) ) +( ( 308 136 88 4.875000 -2.062500 ) ( 304 136 88 4.875000 -2 ) ( 304 140 88 4.812500 -2 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 308 144 128 4.750000 -2.062500 ) ( 312 144 128 4.750000 -2.125000 ) ( 312 140 128 4.812500 -2.125000 ) ) +( ( 304 144 128 4.750000 -2 ) ( 308 140 128 4.812500 -2.062500 ) ( 312 136 128 4.875000 -2.125000 ) ) +( ( 304 140 128 4.812500 -2 ) ( 304 136 128 4.875000 -2 ) ( 308 136 128 4.875000 -2.062500 ) ) +) + } + } +} +// entity 9 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 400 512 64 0 0 ) ( 400 512 68 0 0.062500 ) ( 400 512 72 0 0.125000 ) ) +( ( 400 464 64 0.750000 0 ) ( 400 464 68 0.750000 0.062500 ) ( 400 464 72 0.750000 0.125000 ) ) +( ( 448 464 64 1.500000 0 ) ( 448 464 68 1.500000 0.062500 ) ( 448 464 72 1.500000 0.125000 ) ) +( ( 496 464 64 2.250000 0 ) ( 496 464 68 2.250000 0.062500 ) ( 496 464 72 2.250000 0.125000 ) ) +( ( 496 512 64 3 0 ) ( 496 512 68 3 0.062500 ) ( 496 512 72 3 0.125000 ) ) +( ( 496 560 64 3.750000 0 ) ( 496 560 68 3.750000 0.062500 ) ( 496 560 72 3.750000 0.125000 ) ) +( ( 448 560 64 4.500000 0 ) ( 448 560 68 4.500000 0.062500 ) ( 448 560 72 4.500000 0.125000 ) ) +( ( 400 560 64 5.250000 0 ) ( 400 560 68 5.250000 0.062500 ) ( 400 560 72 5.250000 0.125000 ) ) +( ( 400 512 64 6 0 ) ( 400 512 68 6 0.062500 ) ( 400 512 72 6 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 448 560 64 7 -5.750000 ) ( 400 560 64 6.250000 -5.750000 ) ( 400 512 64 6.250000 -5 ) ) +( ( 496 560 64 7.750000 -5.750000 ) ( 448 512 64 7 -5 ) ( 400 464 64 6.250000 -4.250000 ) ) +( ( 496 512 64 7.750000 -5 ) ( 496 464 64 7.750000 -4.250000 ) ( 448 464 64 7 -4.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 400 512 72 6.250000 -5 ) ( 400 560 72 6.250000 -5.750000 ) ( 448 560 72 7 -5.750000 ) ) +( ( 400 464 72 6.250000 -4.250000 ) ( 448 512 72 7 -5 ) ( 496 560 72 7.750000 -5.750000 ) ) +( ( 448 464 72 7 -4.250000 ) ( 496 464 72 7.750000 -4.250000 ) ( 496 512 72 7.750000 -5 ) ) +) + } + } +} +// entity 10 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 16 320 64 0 0 ) ( 16 320 68 0 0.062500 ) ( 16 320 72 0 0.125000 ) ) +( ( 16 272 64 0.750000 0 ) ( 16 272 68 0.750000 0.062500 ) ( 16 272 72 0.750000 0.125000 ) ) +( ( 64 272 64 1.500000 0 ) ( 64 272 68 1.500000 0.062500 ) ( 64 272 72 1.500000 0.125000 ) ) +( ( 112 272 64 2.250000 0 ) ( 112 272 68 2.250000 0.062500 ) ( 112 272 72 2.250000 0.125000 ) ) +( ( 112 320 64 3 0 ) ( 112 320 68 3 0.062500 ) ( 112 320 72 3 0.125000 ) ) +( ( 112 368 64 3.750000 0 ) ( 112 368 68 3.750000 0.062500 ) ( 112 368 72 3.750000 0.125000 ) ) +( ( 64 368 64 4.500000 0 ) ( 64 368 68 4.500000 0.062500 ) ( 64 368 72 4.500000 0.125000 ) ) +( ( 16 368 64 5.250000 0 ) ( 16 368 68 5.250000 0.062500 ) ( 16 368 72 5.250000 0.125000 ) ) +( ( 16 320 64 6 0 ) ( 16 320 68 6 0.062500 ) ( 16 320 72 6 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 64 368 64 7 -5.750000 ) ( 16 368 64 6.250000 -5.750000 ) ( 16 320 64 6.250000 -5 ) ) +( ( 112 368 64 7.750000 -5.750000 ) ( 64 320 64 7 -5 ) ( 16 272 64 6.250000 -4.250000 ) ) +( ( 112 320 64 7.750000 -5 ) ( 112 272 64 7.750000 -4.250000 ) ( 64 272 64 7 -4.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 16 320 72 6.250000 -5 ) ( 16 368 72 6.250000 -5.750000 ) ( 64 368 72 7 -5.750000 ) ) +( ( 16 272 72 6.250000 -4.250000 ) ( 64 320 72 7 -5 ) ( 112 368 72 7.750000 -5.750000 ) ) +( ( 64 272 72 7 -4.250000 ) ( 112 272 72 7.750000 -4.250000 ) ( 112 320 72 7.750000 -5 ) ) +) + } + } +} +// entity 11 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 16 512 64 0 0 ) ( 16 512 68 0 0.062500 ) ( 16 512 72 0 0.125000 ) ) +( ( 16 464 64 0.750000 0 ) ( 16 464 68 0.750000 0.062500 ) ( 16 464 72 0.750000 0.125000 ) ) +( ( 64 464 64 1.500000 0 ) ( 64 464 68 1.500000 0.062500 ) ( 64 464 72 1.500000 0.125000 ) ) +( ( 112 464 64 2.250000 0 ) ( 112 464 68 2.250000 0.062500 ) ( 112 464 72 2.250000 0.125000 ) ) +( ( 112 512 64 3 0 ) ( 112 512 68 3 0.062500 ) ( 112 512 72 3 0.125000 ) ) +( ( 112 560 64 3.750000 0 ) ( 112 560 68 3.750000 0.062500 ) ( 112 560 72 3.750000 0.125000 ) ) +( ( 64 560 64 4.500000 0 ) ( 64 560 68 4.500000 0.062500 ) ( 64 560 72 4.500000 0.125000 ) ) +( ( 16 560 64 5.250000 0 ) ( 16 560 68 5.250000 0.062500 ) ( 16 560 72 5.250000 0.125000 ) ) +( ( 16 512 64 6 0 ) ( 16 512 68 6 0.062500 ) ( 16 512 72 6 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 64 560 64 7 -5.750000 ) ( 16 560 64 6.250000 -5.750000 ) ( 16 512 64 6.250000 -5 ) ) +( ( 112 560 64 7.750000 -5.750000 ) ( 64 512 64 7 -5 ) ( 16 464 64 6.250000 -4.250000 ) ) +( ( 112 512 64 7.750000 -5 ) ( 112 464 64 7.750000 -4.250000 ) ( 64 464 64 7 -4.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 16 512 72 6.250000 -5 ) ( 16 560 72 6.250000 -5.750000 ) ( 64 560 72 7 -5.750000 ) ) +( ( 16 464 72 6.250000 -4.250000 ) ( 64 512 72 7 -5 ) ( 112 560 72 7.750000 -5.750000 ) ) +( ( 64 464 72 7 -4.250000 ) ( 112 464 72 7.750000 -4.250000 ) ( 112 512 72 7.750000 -5 ) ) +) + } + } +} +// entity 12 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 368 744 72 0 0 ) ( 368 744 76 0 0.062500 ) ( 368 744 80 0 0.125000 ) ) +( ( 368 728 72 0.250000 0 ) ( 368 728 76 0.250000 0.062500 ) ( 368 728 80 0.250000 0.125000 ) ) +( ( 384 728 72 0.500000 0 ) ( 384 728 76 0.500000 0.062500 ) ( 384 728 80 0.500000 0.125000 ) ) +( ( 400 728 72 0.750000 0 ) ( 400 728 76 0.750000 0.062500 ) ( 400 728 80 0.750000 0.125000 ) ) +( ( 400 744 72 1 0 ) ( 400 744 76 1 0.062500 ) ( 400 744 80 1 0.125000 ) ) +( ( 400 760 72 1.250000 0 ) ( 400 760 76 1.250000 0.062500 ) ( 400 760 80 1.250000 0.125000 ) ) +( ( 384 760 72 1.500000 0 ) ( 384 760 76 1.500000 0.062500 ) ( 384 760 80 1.500000 0.125000 ) ) +( ( 368 760 72 1.750000 0 ) ( 368 760 76 1.750000 0.062500 ) ( 368 760 80 1.750000 0.125000 ) ) +( ( 368 744 72 2 0 ) ( 368 744 76 2 0.062500 ) ( 368 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 384 760 72 7.375000 -11.875000 ) ( 368 760 72 7.125000 -11.875000 ) ( 368 744 72 7.125000 -11.625000 ) ) +( ( 400 760 72 7.625000 -11.875000 ) ( 384 744 72 7.375000 -11.625000 ) ( 368 728 72 7.125000 -11.375000 ) ) +( ( 400 744 72 7.625000 -11.625000 ) ( 400 728 72 7.625000 -11.375000 ) ( 384 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 368 744 80 7.125000 -11.625000 ) ( 368 760 80 7.125000 -11.875000 ) ( 384 760 80 7.375000 -11.875000 ) ) +( ( 368 728 80 7.125000 -11.375000 ) ( 384 744 80 7.375000 -11.625000 ) ( 400 760 80 7.625000 -11.875000 ) ) +( ( 384 728 80 7.375000 -11.375000 ) ( 400 728 80 7.625000 -11.375000 ) ( 400 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 13 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 264 744 72 0 0 ) ( 264 744 76 0 0.062500 ) ( 264 744 80 0 0.125000 ) ) +( ( 264 728 72 0.250000 0 ) ( 264 728 76 0.250000 0.062500 ) ( 264 728 80 0.250000 0.125000 ) ) +( ( 280 728 72 0.500000 0 ) ( 280 728 76 0.500000 0.062500 ) ( 280 728 80 0.500000 0.125000 ) ) +( ( 296 728 72 0.750000 0 ) ( 296 728 76 0.750000 0.062500 ) ( 296 728 80 0.750000 0.125000 ) ) +( ( 296 744 72 1 0 ) ( 296 744 76 1 0.062500 ) ( 296 744 80 1 0.125000 ) ) +( ( 296 760 72 1.250000 0 ) ( 296 760 76 1.250000 0.062500 ) ( 296 760 80 1.250000 0.125000 ) ) +( ( 280 760 72 1.500000 0 ) ( 280 760 76 1.500000 0.062500 ) ( 280 760 80 1.500000 0.125000 ) ) +( ( 264 760 72 1.750000 0 ) ( 264 760 76 1.750000 0.062500 ) ( 264 760 80 1.750000 0.125000 ) ) +( ( 264 744 72 2 0 ) ( 264 744 76 2 0.062500 ) ( 264 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 280 760 72 7.375000 -11.875000 ) ( 264 760 72 7.125000 -11.875000 ) ( 264 744 72 7.125000 -11.625000 ) ) +( ( 296 760 72 7.625000 -11.875000 ) ( 280 744 72 7.375000 -11.625000 ) ( 264 728 72 7.125000 -11.375000 ) ) +( ( 296 744 72 7.625000 -11.625000 ) ( 296 728 72 7.625000 -11.375000 ) ( 280 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 264 744 80 7.125000 -11.625000 ) ( 264 760 80 7.125000 -11.875000 ) ( 280 760 80 7.375000 -11.875000 ) ) +( ( 264 728 80 7.125000 -11.375000 ) ( 280 744 80 7.375000 -11.625000 ) ( 296 760 80 7.625000 -11.875000 ) ) +( ( 280 728 80 7.375000 -11.375000 ) ( 296 728 80 7.625000 -11.375000 ) ( 296 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 14 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 96 744 72 0 0 ) ( 96 744 76 0 0.062500 ) ( 96 744 80 0 0.125000 ) ) +( ( 96 728 72 0.250000 0 ) ( 96 728 76 0.250000 0.062500 ) ( 96 728 80 0.250000 0.125000 ) ) +( ( 112 728 72 0.500000 0 ) ( 112 728 76 0.500000 0.062500 ) ( 112 728 80 0.500000 0.125000 ) ) +( ( 128 728 72 0.750000 0 ) ( 128 728 76 0.750000 0.062500 ) ( 128 728 80 0.750000 0.125000 ) ) +( ( 128 744 72 1 0 ) ( 128 744 76 1 0.062500 ) ( 128 744 80 1 0.125000 ) ) +( ( 128 760 72 1.250000 0 ) ( 128 760 76 1.250000 0.062500 ) ( 128 760 80 1.250000 0.125000 ) ) +( ( 112 760 72 1.500000 0 ) ( 112 760 76 1.500000 0.062500 ) ( 112 760 80 1.500000 0.125000 ) ) +( ( 96 760 72 1.750000 0 ) ( 96 760 76 1.750000 0.062500 ) ( 96 760 80 1.750000 0.125000 ) ) +( ( 96 744 72 2 0 ) ( 96 744 76 2 0.062500 ) ( 96 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 112 760 72 7.375000 -11.875000 ) ( 96 760 72 7.125000 -11.875000 ) ( 96 744 72 7.125000 -11.625000 ) ) +( ( 128 760 72 7.625000 -11.875000 ) ( 112 744 72 7.375000 -11.625000 ) ( 96 728 72 7.125000 -11.375000 ) ) +( ( 128 744 72 7.625000 -11.625000 ) ( 128 728 72 7.625000 -11.375000 ) ( 112 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 96 744 80 7.125000 -11.625000 ) ( 96 760 80 7.125000 -11.875000 ) ( 112 760 80 7.375000 -11.875000 ) ) +( ( 96 728 80 7.125000 -11.375000 ) ( 112 744 80 7.375000 -11.625000 ) ( 128 760 80 7.625000 -11.875000 ) ) +( ( 112 728 80 7.375000 -11.375000 ) ( 128 728 80 7.625000 -11.375000 ) ( 128 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 15 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 0 744 72 0 0 ) ( 0 744 76 0 0.062500 ) ( 0 744 80 0 0.125000 ) ) +( ( 0 728 72 0.250000 0 ) ( 0 728 76 0.250000 0.062500 ) ( 0 728 80 0.250000 0.125000 ) ) +( ( 16 728 72 0.500000 0 ) ( 16 728 76 0.500000 0.062500 ) ( 16 728 80 0.500000 0.125000 ) ) +( ( 32 728 72 0.750000 0 ) ( 32 728 76 0.750000 0.062500 ) ( 32 728 80 0.750000 0.125000 ) ) +( ( 32 744 72 1 0 ) ( 32 744 76 1 0.062500 ) ( 32 744 80 1 0.125000 ) ) +( ( 32 760 72 1.250000 0 ) ( 32 760 76 1.250000 0.062500 ) ( 32 760 80 1.250000 0.125000 ) ) +( ( 16 760 72 1.500000 0 ) ( 16 760 76 1.500000 0.062500 ) ( 16 760 80 1.500000 0.125000 ) ) +( ( 0 760 72 1.750000 0 ) ( 0 760 76 1.750000 0.062500 ) ( 0 760 80 1.750000 0.125000 ) ) +( ( 0 744 72 2 0 ) ( 0 744 76 2 0.062500 ) ( 0 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 16 760 72 7.375000 -11.875000 ) ( 0 760 72 7.125000 -11.875000 ) ( 0 744 72 7.125000 -11.625000 ) ) +( ( 32 760 72 7.625000 -11.875000 ) ( 16 744 72 7.375000 -11.625000 ) ( 0 728 72 7.125000 -11.375000 ) ) +( ( 32 744 72 7.625000 -11.625000 ) ( 32 728 72 7.625000 -11.375000 ) ( 16 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 0 744 80 7.125000 -11.625000 ) ( 0 760 80 7.125000 -11.875000 ) ( 16 760 80 7.375000 -11.875000 ) ) +( ( 0 728 80 7.125000 -11.375000 ) ( 16 744 80 7.375000 -11.625000 ) ( 32 760 80 7.625000 -11.875000 ) ) +( ( 16 728 80 7.375000 -11.375000 ) ( 32 728 80 7.625000 -11.375000 ) ( 32 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 16 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( -72 928 72 0 0 ) ( -72 928 76 0 0.062500 ) ( -72 928 80 0 0.125000 ) ) +( ( -72 912 72 0.250000 0 ) ( -72 912 76 0.250000 0.062500 ) ( -72 912 80 0.250000 0.125000 ) ) +( ( -56 912 72 0.500000 0 ) ( -56 912 76 0.500000 0.062500 ) ( -56 912 80 0.500000 0.125000 ) ) +( ( -40 912 72 0.750000 0 ) ( -40 912 76 0.750000 0.062500 ) ( -40 912 80 0.750000 0.125000 ) ) +( ( -40 928 72 1 0 ) ( -40 928 76 1 0.062500 ) ( -40 928 80 1 0.125000 ) ) +( ( -40 944 72 1.250000 0 ) ( -40 944 76 1.250000 0.062500 ) ( -40 944 80 1.250000 0.125000 ) ) +( ( -56 944 72 1.500000 0 ) ( -56 944 76 1.500000 0.062500 ) ( -56 944 80 1.500000 0.125000 ) ) +( ( -72 944 72 1.750000 0 ) ( -72 944 76 1.750000 0.062500 ) ( -72 944 80 1.750000 0.125000 ) ) +( ( -72 928 72 2 0 ) ( -72 928 76 2 0.062500 ) ( -72 928 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( -56 944 72 7.375000 -11.875000 ) ( -72 944 72 7.125000 -11.875000 ) ( -72 928 72 7.125000 -11.625000 ) ) +( ( -40 944 72 7.625000 -11.875000 ) ( -56 928 72 7.375000 -11.625000 ) ( -72 912 72 7.125000 -11.375000 ) ) +( ( -40 928 72 7.625000 -11.625000 ) ( -40 912 72 7.625000 -11.375000 ) ( -56 912 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( -72 928 80 7.125000 -11.625000 ) ( -72 944 80 7.125000 -11.875000 ) ( -56 944 80 7.375000 -11.875000 ) ) +( ( -72 912 80 7.125000 -11.375000 ) ( -56 928 80 7.375000 -11.625000 ) ( -40 944 80 7.625000 -11.875000 ) ) +( ( -56 912 80 7.375000 -11.375000 ) ( -40 912 80 7.625000 -11.375000 ) ( -40 928 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 17 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( -72 824 72 0 0 ) ( -72 824 76 0 0.062500 ) ( -72 824 80 0 0.125000 ) ) +( ( -72 808 72 0.250000 0 ) ( -72 808 76 0.250000 0.062500 ) ( -72 808 80 0.250000 0.125000 ) ) +( ( -56 808 72 0.500000 0 ) ( -56 808 76 0.500000 0.062500 ) ( -56 808 80 0.500000 0.125000 ) ) +( ( -40 808 72 0.750000 0 ) ( -40 808 76 0.750000 0.062500 ) ( -40 808 80 0.750000 0.125000 ) ) +( ( -40 824 72 1 0 ) ( -40 824 76 1 0.062500 ) ( -40 824 80 1 0.125000 ) ) +( ( -40 840 72 1.250000 0 ) ( -40 840 76 1.250000 0.062500 ) ( -40 840 80 1.250000 0.125000 ) ) +( ( -56 840 72 1.500000 0 ) ( -56 840 76 1.500000 0.062500 ) ( -56 840 80 1.500000 0.125000 ) ) +( ( -72 840 72 1.750000 0 ) ( -72 840 76 1.750000 0.062500 ) ( -72 840 80 1.750000 0.125000 ) ) +( ( -72 824 72 2 0 ) ( -72 824 76 2 0.062500 ) ( -72 824 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( -56 840 72 7.375000 -11.875000 ) ( -72 840 72 7.125000 -11.875000 ) ( -72 824 72 7.125000 -11.625000 ) ) +( ( -40 840 72 7.625000 -11.875000 ) ( -56 824 72 7.375000 -11.625000 ) ( -72 808 72 7.125000 -11.375000 ) ) +( ( -40 824 72 7.625000 -11.625000 ) ( -40 808 72 7.625000 -11.375000 ) ( -56 808 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( -72 824 80 7.125000 -11.625000 ) ( -72 840 80 7.125000 -11.875000 ) ( -56 840 80 7.375000 -11.875000 ) ) +( ( -72 808 80 7.125000 -11.375000 ) ( -56 824 80 7.375000 -11.625000 ) ( -40 840 80 7.625000 -11.875000 ) ) +( ( -56 808 80 7.375000 -11.375000 ) ( -40 808 80 7.625000 -11.375000 ) ( -40 824 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 18 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + radiant/notex + ( 9 3 0 0 0 ) +( +( ( 552 824 72 0 0 ) ( 552 824 76 0 0.062500 ) ( 552 824 80 0 0.125000 ) ) +( ( 552 808 72 0.250000 0 ) ( 552 808 76 0.250000 0.062500 ) ( 552 808 80 0.250000 0.125000 ) ) +( ( 568 808 72 0.500000 0 ) ( 568 808 76 0.500000 0.062500 ) ( 568 808 80 0.500000 0.125000 ) ) +( ( 584 808 72 0.750000 0 ) ( 584 808 76 0.750000 0.062500 ) ( 584 808 80 0.750000 0.125000 ) ) +( ( 584 824 72 1 0 ) ( 584 824 76 1 0.062500 ) ( 584 824 80 1 0.125000 ) ) +( ( 584 840 72 1.250000 0 ) ( 584 840 76 1.250000 0.062500 ) ( 584 840 80 1.250000 0.125000 ) ) +( ( 568 840 72 1.500000 0 ) ( 568 840 76 1.500000 0.062500 ) ( 568 840 80 1.500000 0.125000 ) ) +( ( 552 840 72 1.750000 0 ) ( 552 840 76 1.750000 0.062500 ) ( 552 840 80 1.750000 0.125000 ) ) +( ( 552 824 72 2 0 ) ( 552 824 76 2 0.062500 ) ( 552 824 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 568 840 72 7.375000 -11.875000 ) ( 552 840 72 7.125000 -11.875000 ) ( 552 824 72 7.125000 -11.625000 ) ) +( ( 584 840 72 7.625000 -11.875000 ) ( 568 824 72 7.375000 -11.625000 ) ( 552 808 72 7.125000 -11.375000 ) ) +( ( 584 824 72 7.625000 -11.625000 ) ( 584 808 72 7.625000 -11.375000 ) ( 568 808 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + radiant/notex + ( 3 3 0 0 0 ) +( +( ( 552 824 80 7.125000 -11.625000 ) ( 552 840 80 7.125000 -11.875000 ) ( 568 840 80 7.375000 -11.875000 ) ) +( ( 552 808 80 7.125000 -11.375000 ) ( 568 824 80 7.375000 -11.625000 ) ( 584 840 80 7.625000 -11.875000 ) ) +( ( 568 808 80 7.375000 -11.375000 ) ( 584 808 80 7.625000 -11.375000 ) ( 584 824 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 19 +{ +"classname" "light" +"light" "600" +"origin" "256 -448 336" +} diff --git a/docs/developer/TstMaps/sput.map b/docs/developer/TstMaps/sput.map new file mode 100644 index 00000000..81836e0e --- /dev/null +++ b/docs/developer/TstMaps/sput.map @@ -0,0 +1,1887 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +( 3344 -592 -64 ) ( 2760 -592 -64 ) ( 2760 -1240 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2760 -1240 0 ) ( 2760 -592 0 ) ( 3344 -592 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2752 -1216 8 ) ( 3336 -1216 8 ) ( 3336 -1216 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3392 -1240 8 ) ( 3392 -592 8 ) ( 3392 -592 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3344 -576 8 ) ( 2760 -576 8 ) ( 2760 -576 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2752 -592 8 ) ( 2752 -1240 8 ) ( 2752 -1240 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 1 +{ +( 824 3312 -64 ) ( 200 3312 -64 ) ( 200 2688 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 208 2688 0 ) ( 208 3312 0 ) ( 832 3312 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 200 2688 256 ) ( 824 2688 256 ) ( 824 2688 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 2688 256 ) ( 832 3312 256 ) ( 832 3312 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 824 3328 256 ) ( 200 3328 256 ) ( 200 3328 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 3296 256 ) ( -832 2672 256 ) ( -832 2672 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 2 +{ +( 3408 3328 -64 ) ( 2776 3328 -64 ) ( 2776 2680 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2760 2680 0 ) ( 2760 3328 0 ) ( 3392 3328 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2760 2688 40 ) ( 3392 2688 40 ) ( 3392 2688 32 ) common/caulk 0 16 0 0.500000 0.500000 0 0 0 +( 3392 2680 40 ) ( 3392 3328 40 ) ( 3392 3328 32 ) common/caulk 0 16 0 0.500000 0.500000 0 0 0 +( 3392 3328 40 ) ( 2760 3328 40 ) ( 2760 3328 32 ) common/caulk 0 16 0 0.500000 0.500000 0 0 0 +( 2752 3328 40 ) ( 2752 2680 40 ) ( 2752 2680 32 ) common/caulk 0 16 0 0.500000 0.500000 0 0 0 +} +// brush 3 +{ +( -2752 3328 -64 ) ( -3384 3328 -64 ) ( -3384 2704 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3352 2704 0 ) ( -3352 3328 0 ) ( -2720 3328 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3384 2688 1512 ) ( -2752 2688 1512 ) ( -2752 2688 -24 ) common/caulk 0 -48 0 0.500000 0.500000 0 0 0 +( -2752 2704 1512 ) ( -2752 3328 1512 ) ( -2752 3328 -24 ) common/caulk 0 -48 0 0.500000 0.500000 0 0 0 +( -2752 3328 1512 ) ( -3384 3328 1512 ) ( -3384 3328 -24 ) common/caulk 0 -48 0 0.500000 0.500000 0 0 0 +( -3392 3320 1512 ) ( -3392 2696 1512 ) ( -3392 2696 -24 ) common/caulk 0 -48 0 0.500000 0.500000 0 0 0 +} +// brush 4 +{ +( -192 3328 -64 ) ( -840 3328 -64 ) ( -840 2688 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 2688 0 ) ( -832 3328 0 ) ( -184 3328 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -800 2432 296 ) ( -152 2432 296 ) ( -152 2432 -24 ) common/caulk 0 16 0 0.500000 0.500000 0 0 0 +( -192 2688 296 ) ( -192 3328 296 ) ( -192 3328 -24 ) common/caulk 0 16 0 0.500000 0.500000 0 0 0 +( -192 3328 296 ) ( -840 3328 296 ) ( -840 3328 -24 ) common/caulk 0 16 0 0.500000 0.500000 0 0 0 +( -832 3328 296 ) ( -832 2688 296 ) ( -832 2688 -24 ) common/caulk 0 16 0 0.500000 0.500000 0 0 0 +} +// brush 5 +{ +( -2768 -584 -64 ) ( -3312 -584 -64 ) ( -3312 -1184 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3312 -1184 0 ) ( -3312 -584 0 ) ( -2768 -584 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3320 -1216 0 ) ( -2776 -1216 0 ) ( -2776 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 -1176 0 ) ( -2752 -576 0 ) ( -2752 -576 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2768 -576 0 ) ( -3312 -576 0 ) ( -3312 -576 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3392 -600 0 ) ( -3392 -1200 0 ) ( -3392 -1200 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 6 +{ +( -1216 -192 -64 ) ( -2752 -192 -64 ) ( -2752 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 -576 0 ) ( -2752 448 0 ) ( -1216 448 0 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( -832 -552 0 ) ( -832 472 0 ) ( -832 472 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1208 2688 -16 ) ( -2744 2688 -16 ) ( -2744 2688 -80 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1864 2560 -64 ) ( -1888 2560 -64 ) ( -1876 2560 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1728 2672 -64 ) ( -1728 2688 -64 ) ( -1728 2680 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 7 +{ +( -1216 -192 -64 ) ( -2752 -192 -64 ) ( -2752 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 -576 0 ) ( -2752 448 0 ) ( -1216 448 0 ) sfx/jumppadsmall 128 0 0 -0.500000 0.500000 0 0 0 +( -1208 2688 -16 ) ( -2744 2688 -16 ) ( -2744 2688 -80 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1864 2560 -64 ) ( -1888 2560 -64 ) ( -1876 2560 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1856 2672 -64 ) ( -1856 2688 -64 ) ( -1856 2680 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1728 2688 -64 ) ( -1728 2672 -64 ) ( -1728 2680 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 8 +{ +( -1216 -192 -64 ) ( -2752 -192 -64 ) ( -2752 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 -576 0 ) ( -2752 448 0 ) ( -1216 448 0 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( -1208 2688 -16 ) ( -2744 2688 -16 ) ( -2744 2688 -80 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 520 8 ) ( -2752 -504 8 ) ( -2752 -504 -56 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1864 2560 -64 ) ( -1888 2560 -64 ) ( -1876 2560 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1856 2688 -64 ) ( -1856 2672 -64 ) ( -1856 2680 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 9 +{ +( -1216 -192 -64 ) ( -2752 -192 -64 ) ( -2752 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 -576 0 ) ( -2752 448 0 ) ( -1216 448 0 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( -2752 -1216 8 ) ( -1216 -1216 8 ) ( -1216 -1216 -56 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 -552 0 ) ( -832 472 0 ) ( -832 472 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 520 8 ) ( -2752 -504 8 ) ( -2752 -504 -56 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1888 2560 -64 ) ( -1864 2560 -64 ) ( -1876 2560 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 10 +{ +( 2368 -192 -64 ) ( 832 -192 -64 ) ( 832 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 -576 0 ) ( 832 448 0 ) ( 2368 448 0 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( 2752 -552 0 ) ( 2752 472 0 ) ( 2752 472 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2376 2688 -16 ) ( 840 2688 -16 ) ( 840 2688 -80 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1720 2560 -64 ) ( 1664 2560 -64 ) ( 1692 2560 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1856 2664 -64 ) ( 1856 2688 -64 ) ( 1856 2676 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 11 +{ +( 2368 -192 -64 ) ( 832 -192 -64 ) ( 832 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 -576 0 ) ( 832 448 0 ) ( 2368 448 0 ) sfx/jumppadsmall 128 0 0 -0.500000 0.500000 0 0 0 +( 2376 2688 -16 ) ( 840 2688 -16 ) ( 840 2688 -80 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1720 2560 -64 ) ( 1664 2560 -64 ) ( 1692 2560 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1728 2616 -64 ) ( 1728 2688 -64 ) ( 1728 2652 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1856 2688 -64 ) ( 1856 2664 -64 ) ( 1856 2676 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 12 +{ +( 2368 -192 -64 ) ( 832 -192 -64 ) ( 832 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 -576 0 ) ( 832 448 0 ) ( 2368 448 0 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( 2376 2688 -16 ) ( 840 2688 -16 ) ( 840 2688 -80 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 520 8 ) ( 832 -504 8 ) ( 832 -504 -56 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1720 2560 -64 ) ( 1664 2560 -64 ) ( 1692 2560 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1728 2688 -64 ) ( 1728 2616 -64 ) ( 1728 2652 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 13 +{ +( 2368 -192 -64 ) ( 832 -192 -64 ) ( 832 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 -576 0 ) ( 832 448 0 ) ( 2368 448 0 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( 832 -1216 8 ) ( 2368 -1216 8 ) ( 2368 -1216 -56 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2752 -552 0 ) ( 2752 472 0 ) ( 2752 472 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 520 8 ) ( 832 -504 8 ) ( 832 -504 -56 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1664 2560 -64 ) ( 1720 2560 -64 ) ( 1692 2560 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 14 + { + patchDef2 + { + base_wall/bluemetal2_shiny + ( 3 3 0 0 0 ) +( +( ( 384 -320 448 0 0 ) ( 448 -320 448 0 0.500000 ) ( 512 -320 448 0 1 ) ) +( ( 384 -320 896 3.500000 0 ) ( 448 -320 896 3.500000 0.500000 ) ( 512 -320 896 3.500000 1 ) ) +( ( 384 0 896 6 0 ) ( 448 0 896 6 0.500000 ) ( 512 0 896 6 1 ) ) +) + } + } +// brush 15 + { + patchDef2 + { + base_wall/bluemetal2_shiny + ( 3 3 0 0 0 ) +( +( ( 512 320 448 0 0 ) ( 448 320 448 0 0.500000 ) ( 384 320 448 0 1 ) ) +( ( 512 320 896 3.500000 0 ) ( 448 320 896 3.500000 0.500000 ) ( 384 320 896 3.500000 1 ) ) +( ( 512 0 896 6 0 ) ( 448 0 896 6 0.500000 ) ( 384 0 896 6 1 ) ) +) + } + } +// brush 16 +{ +( 1112 3296 1536 ) ( -3392 3296 1536 ) ( -3392 1384 1536 ) skies/kcbasesky_arena1_sky 0 0 0 0.500000 0.500000 0 0 0 +( -3384 1384 1600 ) ( -3384 3296 1600 ) ( 1120 3296 1600 ) common/caulk 32 0 0 0.500000 0.500000 0 0 0 +( -3392 -1216 1600 ) ( 1112 -1216 1600 ) ( 1112 -1216 384 ) common/caulk 32 48 0 0.500000 0.500000 0 0 0 +( 3392 1384 1536 ) ( 3392 3296 1536 ) ( 3392 3296 320 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 +( 1112 3328 1560 ) ( -3392 3328 1560 ) ( -3392 3328 344 ) common/caulk 32 48 0 0.500000 0.500000 0 0 0 +( -3392 3296 1560 ) ( -3392 1384 1560 ) ( -3392 1384 344 ) common/caulk 0 48 0 0.500000 0.500000 0 0 0 +} +// brush 17 +{ +( 4104 3352 -8 ) ( 5376 3352 -8 ) ( 5376 3384 -8 ) common/caulk -63 1 -180 0.500000 0.500000 0 0 0 +( 5344 3384 1536 ) ( 5344 3352 1536 ) ( 4072 3352 1536 ) common/caulk -63 1 -180 0.500000 0.500000 0 0 0 +( 5344 3392 1536 ) ( 4072 3392 1536 ) ( 4072 3392 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 2752 3384 1536 ) ( 2752 3352 1536 ) ( 2752 3352 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 3440 3328 1536 ) ( 4712 3328 1536 ) ( 4712 3328 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 3456 3464 1536 ) ( 3456 3496 1536 ) ( 3456 3496 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 18 +{ +( 3456 4008 0 ) ( 3456 5280 0 ) ( 3424 5280 0 ) common/caulk 1 1 90 0.500000 0.500000 0 0 0 +( 3400 5280 1536 ) ( 3432 5280 1536 ) ( 3432 4008 1536 ) common/caulk 1 1 90 0.500000 0.500000 0 0 0 +( 3392 5280 1536 ) ( 3392 4008 1536 ) ( 3392 4008 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3400 2688 1536 ) ( 3432 2688 1536 ) ( 3432 2688 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 3456 3376 1536 ) ( 3456 4648 1536 ) ( 3456 4648 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3336 3328 1536 ) ( 3304 3328 1536 ) ( 3304 3328 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 19 +{ +( -3400 4008 0 ) ( -3400 5280 0 ) ( -3432 5280 0 ) common/caulk -63 -63 90 0.500000 0.500000 0 0 0 +( -3448 5280 1536 ) ( -3416 5280 1536 ) ( -3416 4008 1536 ) common/caulk -63 -63 90 0.500000 0.500000 0 0 0 +( -3456 5280 1536 ) ( -3456 4008 1536 ) ( -3456 4008 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3448 2688 1536 ) ( -3416 2688 1536 ) ( -3416 2688 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -3392 3376 1536 ) ( -3392 4648 1536 ) ( -3392 4648 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3512 3328 1536 ) ( -3544 3328 1536 ) ( -3544 3328 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 20 +{ +( -4136 3368 0 ) ( -5408 3368 0 ) ( -5408 3336 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -5408 3336 1536 ) ( -5408 3368 1536 ) ( -4136 3368 1536 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -5408 3328 1536 ) ( -4136 3328 1536 ) ( -4136 3328 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 3304 1216 ) ( -2752 3336 1216 ) ( -2752 3336 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3504 3392 1536 ) ( -4776 3392 1536 ) ( -4776 3392 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3456 3272 1536 ) ( -3456 3240 1536 ) ( -3456 3240 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 21 +{ +( 3432 -1272 0 ) ( 3432 0 0 ) ( 3400 0 0 ) common/caulk 0 -31 -180 0.500000 0.500000 0 0 0 +( 3400 0 1536 ) ( 3432 0 1536 ) ( 3432 -1272 1536 ) common/caulk 0 -31 -180 0.500000 0.500000 0 0 0 +( 3392 64 1536 ) ( 3392 -1208 1536 ) ( 3392 -1208 320 ) common/caulk 32 0 -180 0.500000 -0.500000 0 0 0 +( 3384 -1280 1536 ) ( 3416 -1280 1536 ) ( 3416 -1280 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 3456 -1904 1536 ) ( 3456 -632 1536 ) ( 3456 -632 320 ) common/caulk 32 0 -180 0.500000 -0.500000 0 0 0 +( 3496 1344 1536 ) ( 3464 1344 1536 ) ( 3464 1344 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 22 +{ +( 3416 -1240 -8 ) ( 2144 -1240 -8 ) ( 2144 -1272 -8 ) common/caulk -63 -31 90 0.500000 0.500000 0 0 0 +( 2112 -1272 1536 ) ( 2112 -1240 1536 ) ( 3384 -1240 1536 ) common/caulk -63 -31 90 0.500000 0.500000 0 0 0 +( 2048 -1280 1536 ) ( 3320 -1280 1536 ) ( 3320 -1280 320 ) common/caulk 32 0 -180 0.500000 -0.500000 0 0 0 +( 3392 -1288 1536 ) ( 3392 -1256 1536 ) ( 3392 -1256 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 4016 -1216 1536 ) ( 2744 -1216 1536 ) ( 2744 -1216 320 ) common/caulk 32 0 -180 0.500000 -0.500000 0 0 0 +( 832 -1184 1536 ) ( 832 -1216 1536 ) ( 832 -1216 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 23 +{ +( -840 -1192 0 ) ( -2112 -1192 0 ) ( -2112 -1224 0 ) common/caulk 0 -31 90 0.500000 0.500000 0 0 0 +( -2112 -1272 1536 ) ( -2112 -1240 1536 ) ( -840 -1240 1536 ) common/caulk 0 -31 90 0.500000 0.500000 0 0 0 +( -2176 -1280 1536 ) ( -904 -1280 1536 ) ( -904 -1280 320 ) common/caulk -32 0 -180 0.500000 -0.500000 0 0 0 +( -832 -1288 1536 ) ( -832 -1256 1536 ) ( -832 -1256 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -208 -1216 1536 ) ( -1480 -1216 1536 ) ( -1480 -1216 320 ) common/caulk -32 0 -180 0.500000 -0.500000 0 0 0 +( -3392 -1184 1536 ) ( -3392 -1216 1536 ) ( -3392 -1216 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 24 +{ +( -3432 1296 0 ) ( -3432 24 0 ) ( -3400 24 0 ) common/caulk 0 32 0 0.500000 0.500000 0 0 0 +( -3400 0 1536 ) ( -3432 0 1536 ) ( -3432 1272 1536 ) common/caulk 0 32 0 0.500000 0.500000 0 0 0 +( -3392 0 1536 ) ( -3392 1272 1536 ) ( -3392 1272 320 ) common/caulk -32 0 0 0.500000 0.500000 0 0 0 +( -3384 1344 1536 ) ( -3416 1344 1536 ) ( -3416 1344 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3456 1904 1536 ) ( -3456 632 1536 ) ( -3456 632 320 ) common/caulk -32 0 0 0.500000 0.500000 0 0 0 +( -3488 -1280 1536 ) ( -3456 -1280 1536 ) ( -3456 -1280 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 25 +{ +( 168 3048 320 ) ( 168 4320 320 ) ( 136 4320 320 ) common/caulk 0 0 90 0.500000 0.500000 0 0 0 +( 136 4320 1536 ) ( 168 4320 1536 ) ( 168 3048 1536 ) common/caulk 0 0 90 0.500000 0.500000 0 0 0 +( 128 4320 1536 ) ( 128 3048 1536 ) ( 128 3048 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 160 2688 1536 ) ( 192 2688 1536 ) ( 192 2688 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 192 2416 1536 ) ( 192 3688 1536 ) ( 192 3688 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 112 3328 1536 ) ( 80 3328 1536 ) ( 80 3328 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 26 +{ +( -184 3048 0 ) ( -184 4320 0 ) ( -216 4320 0 ) common/caulk 0 0 90 0.500000 0.500000 0 0 0 +( -184 4320 1536 ) ( -152 4320 1536 ) ( -152 3048 1536 ) common/caulk 0 0 90 0.500000 0.500000 0 0 0 +( -192 4320 1536 ) ( -192 3048 1536 ) ( -192 3048 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -160 2688 1536 ) ( -128 2688 1536 ) ( -128 2688 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -128 2416 1536 ) ( -128 3688 1536 ) ( -128 3688 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -208 3328 1536 ) ( -240 3328 1536 ) ( -240 3328 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 27 +{ +( -544 3368 0 ) ( -1816 3368 0 ) ( -1816 3336 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1824 3336 1536 ) ( -1824 3368 1536 ) ( -552 3368 1536 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1824 3328 1536 ) ( -552 3328 1536 ) ( -552 3328 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 3304 1536 ) ( 832 3336 1536 ) ( 832 3336 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 80 3392 1536 ) ( -1192 3392 1536 ) ( -1192 3392 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 3312 1536 ) ( -832 3280 1536 ) ( -832 3280 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 28 +{ +( -3432 2616 320 ) ( -3432 1344 320 ) ( -3400 1344 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3400 1344 1536 ) ( -3432 1344 1536 ) ( -3432 2616 1536 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3392 1344 1536 ) ( -3392 2616 1536 ) ( -3392 2616 320 ) gothic_wall/support2b 0 67 0 -5.250000 4.750000 0 0 0 +( -3384 2688 1536 ) ( -3416 2688 1536 ) ( -3416 2688 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3456 3248 1536 ) ( -3456 1976 1536 ) ( -3456 1976 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3432 1344 1536 ) ( -3400 1344 1536 ) ( -3400 1344 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 29 +{ +( -1480 3368 320 ) ( -2752 3368 320 ) ( -2752 3336 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 3336 1536 ) ( -2752 3368 1536 ) ( -1480 3368 1536 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 3328 1536 ) ( -1480 3328 1536 ) ( -1480 3328 320 ) gothic_wall/support2b 145 67 0 -7.500000 4.750000 0 0 0 +( -832 3336 1536 ) ( -832 3368 1536 ) ( -832 3368 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -848 3392 1536 ) ( -2120 3392 1536 ) ( -2120 3392 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 3368 1536 ) ( -2752 3336 1536 ) ( -2752 3336 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 30 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( -2752 3328 1536 0 0 ) ( -2752 3328 928 0 0.500000 ) ( -2752 3328 320 0 1 ) ) +( ( -3392 3328 1536 0.500000 0 ) ( -3392 3328 928 0.500000 0.500000 ) ( -3392 3328 320 0.500000 1 ) ) +( ( -3392 2688 1536 1 0 ) ( -3392 2688 928 1 0.500000 ) ( -3392 2688 320 1 1 ) ) +) + } + } +// brush 31 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( -192 2688 1536 0 0 ) ( -192 2688 928 0 0.500000 ) ( -192 2688 320 0 1 ) ) +( ( -192 3328 1536 0.500000 0 ) ( -192 3328 928 0.500000 0.500000 ) ( -192 3328 320 0.500000 1 ) ) +( ( -832 3328 1536 1 0 ) ( -832 3328 928 1 0.500000 ) ( -832 3328 320 1 1 ) ) +) + } + } +// brush 32 +{ +( 3448 1416 0 ) ( 3448 2688 0 ) ( 3416 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3400 2688 1536 ) ( 3432 2688 1536 ) ( 3432 1416 1536 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3392 2688 1536 ) ( 3392 1416 1536 ) ( 3392 1416 320 ) gothic_wall/support2b 0 67 0 -5.250000 4.750000 0 0 0 +( 3384 1344 1536 ) ( 3416 1344 1536 ) ( 3416 1344 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3456 784 1536 ) ( 3456 2056 1536 ) ( 3456 2056 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3432 2688 1536 ) ( 3400 2688 1536 ) ( 3400 2688 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 33 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( 3392 2688 1536 0 0 ) ( 3392 2688 928 0 0.500000 ) ( 3392 2688 320 0 1 ) ) +( ( 3392 3328 1536 0.500000 0 ) ( 3392 3328 928 0.500000 0.500000 ) ( 3392 3328 320 0.500000 1 ) ) +( ( 2752 3328 1536 1 0 ) ( 2752 3328 928 1 0.500000 ) ( 2752 3328 320 1 1 ) ) +) + } + } +// brush 34 +{ +( 2112 3368 0 ) ( 840 3368 0 ) ( 840 3336 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 3336 1536 ) ( 832 3368 1536 ) ( 2104 3368 1536 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 3328 1536 ) ( 2104 3328 1536 ) ( 2104 3328 320 ) gothic_wall/support2b 110 67 0 -7.500000 4.750000 0 0 0 +( 2752 3336 1536 ) ( 2752 3368 1536 ) ( 2752 3368 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2736 3392 1536 ) ( 1464 3392 1536 ) ( 1464 3392 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 3368 1536 ) ( 832 3336 1536 ) ( 832 3336 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 35 +{ +( 192 2688 320 ) ( -192 2688 320 ) ( -192 2648 320 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( -208 2648 1536 ) ( -208 2688 1536 ) ( 176 2688 1536 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( -192 2624 448 ) ( 192 2624 448 ) ( 192 2624 320 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( 192 2648 448 ) ( 192 2688 448 ) ( 192 2688 320 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( 192 2688 448 ) ( -192 2688 448 ) ( -192 2688 320 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( -192 2688 448 ) ( -192 2648 448 ) ( -192 2648 320 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 36 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( 832 3328 1536 0 0 ) ( 832 3328 928 0 0.500000 ) ( 832 3328 320 0 1 ) ) +( ( 192 3328 1536 0.500000 0 ) ( 192 3328 928 0.500000 0.500000 ) ( 192 3328 320 0.500000 1 ) ) +( ( 192 2688 1536 1 0 ) ( 192 2688 928 1 0.500000 ) ( 192 2688 320 1 1 ) ) +) + } + } +// brush 37 +{ +( 16 40 1088 ) ( -288 40 1088 ) ( -288 -32 1088 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -192 1 1152 ) ( 192 1 1152 ) ( 195 -1 1152 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -256 -40 1088 ) ( -192 -1 1152 ) ( 195 -1 1152 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 192 -1 1152 ) ( 256 40 1088 ) ( 256 -40 1088 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -256 40 1088 ) ( 256 40 1088 ) ( 256 1 1152 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -256 40 1088 ) ( -192 1 1152 ) ( -256 -40 1088 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 38 +{ +( -384 112 960 ) ( -368 112 960 ) ( -368 128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -368 128 1024 ) ( -368 112 1024 ) ( -1136 112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -368 128 1024 ) ( -1136 128 1024 ) ( -1136 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -384 128 1024 ) ( -384 112 1024 ) ( -384 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -1136 112 1024 ) ( -368 112 1024 ) ( -368 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -368 112 1024 ) ( -368 128 1024 ) ( -368 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 39 +{ +( -272 112 960 ) ( -256 112 960 ) ( -256 128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -256 128 1024 ) ( -256 112 1024 ) ( -1024 112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -256 128 1024 ) ( -1024 128 1024 ) ( -1024 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -272 128 1024 ) ( -272 112 1024 ) ( -272 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -1024 112 1024 ) ( -256 112 1024 ) ( -256 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -256 112 1024 ) ( -256 128 1024 ) ( -256 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 40 +{ +( -144 112 960 ) ( -128 112 960 ) ( -128 128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -128 128 1024 ) ( -128 112 1024 ) ( -896 112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -128 128 1024 ) ( -896 128 1024 ) ( -896 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -144 128 1024 ) ( -144 112 1024 ) ( -144 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -896 112 1024 ) ( -128 112 1024 ) ( -128 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -128 112 1024 ) ( -128 128 1024 ) ( -128 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 41 +{ +( 0 112 960 ) ( 16 112 960 ) ( 16 128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 16 128 1024 ) ( 16 112 1024 ) ( -752 112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 16 128 1024 ) ( -752 128 1024 ) ( -752 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 0 128 1024 ) ( 0 112 1024 ) ( 0 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -752 112 1024 ) ( 16 112 1024 ) ( 16 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 16 112 1024 ) ( 16 128 1024 ) ( 16 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 42 +{ +( 368 112 960 ) ( 384 112 960 ) ( 384 128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 384 128 1024 ) ( 384 112 1024 ) ( -384 112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 384 128 1024 ) ( -384 128 1024 ) ( -384 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 368 128 1024 ) ( 368 112 1024 ) ( 368 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -384 112 1024 ) ( 384 112 1024 ) ( 384 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 384 112 1024 ) ( 384 128 1024 ) ( 384 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 43 +{ +( 256 112 960 ) ( 272 112 960 ) ( 272 128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 272 128 1024 ) ( 272 112 1024 ) ( -496 112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 272 128 1024 ) ( -496 128 1024 ) ( -496 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 256 128 1024 ) ( 256 112 1024 ) ( 256 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -496 112 1024 ) ( 272 112 1024 ) ( 272 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 272 112 1024 ) ( 272 128 1024 ) ( 272 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 44 +{ +( 128 112 960 ) ( 144 112 960 ) ( 144 128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 144 128 1024 ) ( 144 112 1024 ) ( -624 112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 144 128 1024 ) ( -624 128 1024 ) ( -624 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 128 128 1024 ) ( 128 112 1024 ) ( 128 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -624 112 1024 ) ( 144 112 1024 ) ( 144 112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 144 112 1024 ) ( 144 128 1024 ) ( 144 128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 45 +{ +( 272 -112 960 ) ( 256 -112 960 ) ( 256 -128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 256 -128 1024 ) ( 256 -112 1024 ) ( 1024 -112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 256 -128 1024 ) ( 1024 -128 1024 ) ( 1024 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 272 -128 1024 ) ( 272 -112 1024 ) ( 272 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 1024 -112 1024 ) ( 256 -112 1024 ) ( 256 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 256 -112 1024 ) ( 256 -128 1024 ) ( 256 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 46 +{ +( 384 -112 960 ) ( 368 -112 960 ) ( 368 -128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 368 -128 1024 ) ( 368 -112 1024 ) ( 1136 -112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 368 -128 1024 ) ( 1136 -128 1024 ) ( 1136 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 384 -128 1024 ) ( 384 -112 1024 ) ( 384 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 1136 -112 1024 ) ( 368 -112 1024 ) ( 368 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 368 -112 1024 ) ( 368 -128 1024 ) ( 368 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 47 +{ +( 144 -112 960 ) ( 128 -112 960 ) ( 128 -128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 128 -128 1024 ) ( 128 -112 1024 ) ( 896 -112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 128 -128 1024 ) ( 896 -128 1024 ) ( 896 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 144 -128 1024 ) ( 144 -112 1024 ) ( 144 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 896 -112 1024 ) ( 128 -112 1024 ) ( 128 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 128 -112 1024 ) ( 128 -128 1024 ) ( 128 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 48 +{ +( 16 -112 960 ) ( 0 -112 960 ) ( 0 -128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 0 -128 1024 ) ( 0 -112 1024 ) ( 768 -112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 0 -128 1024 ) ( 768 -128 1024 ) ( 768 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 16 -128 1024 ) ( 16 -112 1024 ) ( 16 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 768 -112 1024 ) ( 0 -112 1024 ) ( 0 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 0 -112 1024 ) ( 0 -128 1024 ) ( 0 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 49 +{ +( -128 -112 960 ) ( -144 -112 960 ) ( -144 -128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -144 -128 1024 ) ( -144 -112 1024 ) ( 624 -112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -144 -128 1024 ) ( 624 -128 1024 ) ( 624 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -128 -128 1024 ) ( -128 -112 1024 ) ( -128 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 624 -112 1024 ) ( -144 -112 1024 ) ( -144 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -144 -112 1024 ) ( -144 -128 1024 ) ( -144 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 50 +{ +( -272 -112 960 ) ( -272 -128 936 ) ( -256 -128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -272 -128 1024 ) ( -272 -112 1024 ) ( 496 -112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -272 -128 1024 ) ( 496 -128 1024 ) ( 496 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -256 -128 1024 ) ( -256 -112 1024 ) ( -256 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 496 -112 1024 ) ( -272 -112 1024 ) ( -272 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -272 -112 1024 ) ( -272 -128 1024 ) ( -272 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 51 +{ +( -384 -112 960 ) ( -384 -128 936 ) ( -368 -128 936 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -384 -128 1024 ) ( -384 -112 1024 ) ( 384 -112 1024 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -384 -128 1024 ) ( 384 -128 1024 ) ( 384 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -368 -128 1024 ) ( -368 -112 1024 ) ( -368 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 384 -112 1024 ) ( -384 -112 1024 ) ( -384 -112 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -384 -112 1024 ) ( -384 -128 1024 ) ( -384 -128 960 ) base_wall/bluemetal1b_shiny 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 52 +{ +( 160 120 1024 ) ( -376 120 1024 ) ( -376 -48 1024 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 320 -64 1088 ) ( -320 -64 1088 ) ( -320 72 1088 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -320 -64 1088 ) ( 384 -128 1024 ) ( -384 -128 1024 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 384 128 1024 ) ( 384 -128 1024 ) ( 320 128 1088 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 384 128 1024 ) ( 320 64 1088 ) ( -384 128 1024 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -384 -128 1024 ) ( -384 128 1024 ) ( -320 72 1088 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 53 +{ +( 368 -312 896 ) ( 480 -312 896 ) ( 480 -216 896 ) common/caulk 0 0 -180 0.500000 0.500000 0 0 0 +( 504 -216 960 ) ( 504 -312 960 ) ( 392 -312 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 504 320 960 ) ( 392 320 960 ) ( 392 320 448 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 384 -216 960 ) ( 384 -312 960 ) ( 384 -312 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 392 -320 960 ) ( 504 -320 960 ) ( 504 -320 448 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 512 -312 960 ) ( 512 -216 960 ) ( 512 -216 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 54 +{ +( -368 312 896 ) ( -480 312 896 ) ( -480 216 896 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -504 216 960 ) ( -504 312 960 ) ( -392 312 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -504 -320 960 ) ( -392 -320 960 ) ( -392 -320 448 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -384 216 960 ) ( -384 312 960 ) ( -384 312 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -392 320 960 ) ( -504 320 960 ) ( -504 320 448 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -512 312 960 ) ( -512 216 960 ) ( -512 216 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 55 +{ +( 384 -576 448 ) ( 544 -576 448 ) ( 544 -480 448 ) common/caulk -15 0 -180 0.500000 0.500000 0 0 0 +( 512 -480 960 ) ( 512 -576 960 ) ( 352 -576 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 536 -320 576 ) ( 376 -320 576 ) ( 376 -320 448 ) common/caulk -16 0 -180 0.500000 -0.500000 0 0 0 +( 384 -480 576 ) ( 384 -576 576 ) ( 384 -576 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 384 -576 576 ) ( 544 -576 576 ) ( 544 -576 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( 512 -584 576 ) ( 512 -488 576 ) ( 512 -488 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 56 +{ +( -512 -576 448 ) ( -352 -576 448 ) ( -352 -480 448 ) common/caulk -15 0 -180 0.500000 0.500000 0 0 0 +( -336 -480 960 ) ( -336 -576 960 ) ( -496 -576 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -360 -320 576 ) ( -520 -320 576 ) ( -520 -320 448 ) common/caulk -16 0 -180 0.500000 -0.500000 0 0 0 +( -512 -480 576 ) ( -512 -576 576 ) ( -512 -576 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( -512 -576 576 ) ( -352 -576 576 ) ( -352 -576 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( -384 -584 576 ) ( -384 -488 576 ) ( -384 -488 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 57 +{ +( -96 -568 896 ) ( 120 -568 896 ) ( 120 -400 896 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 128 -400 960 ) ( 128 -568 960 ) ( -88 -568 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 104 -128 960 ) ( -112 -128 960 ) ( -112 -128 704 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -128 -400 960 ) ( -128 -568 960 ) ( -128 -568 704 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -88 -576 960 ) ( 128 -576 960 ) ( 128 -576 704 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( 128 -568 960 ) ( 128 -400 960 ) ( 128 -400 704 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 58 +{ +( 160 -568 896 ) ( 376 -568 896 ) ( 376 -400 896 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( 384 -400 960 ) ( 384 -568 960 ) ( 168 -568 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 360 -128 960 ) ( 144 -128 960 ) ( 144 -128 704 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 128 -400 960 ) ( 128 -568 960 ) ( 128 -568 704 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 168 -576 960 ) ( 384 -576 960 ) ( 384 -576 704 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( 384 -568 960 ) ( 384 -400 960 ) ( 384 -400 704 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 59 +{ +( -352 -568 896 ) ( -136 -568 896 ) ( -136 -400 896 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( -128 -400 960 ) ( -128 -568 960 ) ( -344 -568 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -152 -128 960 ) ( -368 -128 960 ) ( -368 -128 704 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -384 -400 960 ) ( -384 -568 960 ) ( -384 -568 704 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( -344 -576 960 ) ( -128 -576 960 ) ( -128 -576 704 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( -128 -568 960 ) ( -128 -400 960 ) ( -128 -400 704 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 60 +{ +( 352 568 896 ) ( 136 568 896 ) ( 136 400 896 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( 128 400 960 ) ( 128 568 960 ) ( 344 568 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 152 128 960 ) ( 368 128 960 ) ( 368 128 704 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 384 400 960 ) ( 384 568 960 ) ( 384 568 704 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 344 576 960 ) ( 128 576 960 ) ( 128 576 704 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( 128 568 960 ) ( 128 400 960 ) ( 128 400 704 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 61 +{ +( -160 568 896 ) ( -376 568 896 ) ( -376 400 896 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( -384 400 960 ) ( -384 568 960 ) ( -168 568 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -360 128 960 ) ( -144 128 960 ) ( -144 128 704 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -128 400 960 ) ( -128 568 960 ) ( -128 568 704 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -168 576 960 ) ( -384 576 960 ) ( -384 576 704 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( -384 568 960 ) ( -384 400 960 ) ( -384 400 704 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 62 +{ +( 96 568 896 ) ( -120 568 896 ) ( -120 400 896 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -128 400 960 ) ( -128 568 960 ) ( 88 568 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -104 128 960 ) ( 112 128 960 ) ( 112 128 704 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 128 400 960 ) ( 128 568 960 ) ( 128 568 704 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 88 576 960 ) ( -128 576 960 ) ( -128 576 704 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( -128 568 960 ) ( -128 400 960 ) ( -128 400 704 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 63 +{ +( 512 576 448 ) ( 352 576 448 ) ( 352 480 448 ) common/caulk -16 0 0 0.500000 0.500000 0 0 0 +( 336 480 960 ) ( 336 576 960 ) ( 496 576 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 360 320 576 ) ( 520 320 576 ) ( 520 320 448 ) common/caulk -16 0 0 0.500000 0.500000 0 0 0 +( 512 480 576 ) ( 512 576 576 ) ( 512 576 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( 512 576 576 ) ( 352 576 576 ) ( 352 576 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( 384 584 576 ) ( 384 488 576 ) ( 384 488 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 64 +{ +( -384 576 448 ) ( -544 576 448 ) ( -544 480 448 ) common/caulk -16 0 0 0.500000 0.500000 0 0 0 +( -512 480 960 ) ( -512 576 960 ) ( -352 576 960 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -536 320 576 ) ( -376 320 576 ) ( -376 320 448 ) common/caulk -16 0 0 0.500000 0.500000 0 0 0 +( -384 480 576 ) ( -384 576 576 ) ( -384 576 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -384 576 576 ) ( -544 576 576 ) ( -544 576 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +( -512 584 576 ) ( -512 488 576 ) ( -512 488 448 ) base_wall/c_met7_2 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 65 +{ +( -1640 1784 0 ) ( -1952 1784 0 ) ( -1952 1536 0 ) gothic_wall/support2b 230 153 0 -1.250000 1.250000 0 0 0 +( -1928 1536 256 ) ( -1928 1784 256 ) ( -1616 1784 256 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( -1960 1472 640 ) ( -1648 1472 640 ) ( -1648 1472 0 ) gothic_wall/support2b 230 153 0 -1.250000 1.250000 0 0 0 +( -1632 1536 640 ) ( -1632 1784 640 ) ( -1632 1784 0 ) gothic_wall/support2b 230 153 0 -1.250000 1.250000 0 0 0 +( -1640 1792 640 ) ( -1952 1792 640 ) ( -1952 1792 0 ) gothic_wall/support2b 230 153 0 -1.250000 1.250000 0 0 0 +( -1952 1784 640 ) ( -1952 1536 640 ) ( -1952 1536 0 ) gothic_wall/support2b 230 153 0 -1.250000 1.250000 0 0 0 +} +// brush 66 + { + patchDef2 + { + base_wall/bluemetal1b_shiny + ( 9 3 0 0 0 ) +( +( ( -1888 1632 256 0 0 ) ( -1888 1632 896 0 0.500000 ) ( -1888 1632 1536 0 1 ) ) +( ( -1888 1536 256 0.125000 0 ) ( -1888 1536 896 0.125000 0.500000 ) ( -1888 1536 1536 0.125000 1 ) ) +( ( -1792 1536 256 0.250000 0 ) ( -1792 1536 896 0.250000 0.500000 ) ( -1792 1536 1536 0.250000 1 ) ) +( ( -1696 1536 256 0.375000 0 ) ( -1696 1536 896 0.375000 0.500000 ) ( -1696 1536 1536 0.375000 1 ) ) +( ( -1696 1632 256 0.500000 0 ) ( -1696 1632 896 0.500000 0.500000 ) ( -1696 1632 1536 0.500000 1 ) ) +( ( -1696 1728 256 0.625000 0 ) ( -1696 1728 896 0.625000 0.500000 ) ( -1696 1728 1536 0.625000 1 ) ) +( ( -1792 1728 256 0.750000 0 ) ( -1792 1728 896 0.750000 0.500000 ) ( -1792 1728 1536 0.750000 1 ) ) +( ( -1888 1728 256 0.875000 0 ) ( -1888 1728 896 0.875000 0.500000 ) ( -1888 1728 1536 0.875000 1 ) ) +( ( -1888 1632 256 1 0 ) ( -1888 1632 896 1 0.500000 ) ( -1888 1632 1536 1 1 ) ) +) + } + } +// brush 67 + { + patchDef2 + { + base_wall/bluemetal1b_shiny + ( 9 3 0 0 0 ) +( +( ( 1688 1568 256 0 0 ) ( 1688 1568 896 0 0.500000 ) ( 1688 1568 1536 0 1 ) ) +( ( 1688 1472 256 0.125000 0 ) ( 1688 1472 896 0.125000 0.500000 ) ( 1688 1472 1536 0.125000 1 ) ) +( ( 1784 1472 256 0.250000 0 ) ( 1784 1472 896 0.250000 0.500000 ) ( 1784 1472 1536 0.250000 1 ) ) +( ( 1880 1472 256 0.375000 0 ) ( 1880 1472 896 0.375000 0.500000 ) ( 1880 1472 1536 0.375000 1 ) ) +( ( 1880 1568 256 0.500000 0 ) ( 1880 1568 896 0.500000 0.500000 ) ( 1880 1568 1536 0.500000 1 ) ) +( ( 1880 1664 256 0.625000 0 ) ( 1880 1664 896 0.625000 0.500000 ) ( 1880 1664 1536 0.625000 1 ) ) +( ( 1784 1664 256 0.750000 0 ) ( 1784 1664 896 0.750000 0.500000 ) ( 1784 1664 1536 0.750000 1 ) ) +( ( 1688 1664 256 0.875000 0 ) ( 1688 1664 896 0.875000 0.500000 ) ( 1688 1664 1536 0.875000 1 ) ) +( ( 1688 1568 256 1 0 ) ( 1688 1568 896 1 0.500000 ) ( 1688 1568 1536 1 1 ) ) +) + } + } +// brush 68 +{ +( 1936 1720 0 ) ( 1624 1720 0 ) ( 1624 1472 0 ) gothic_wall/support2b 19 102 0 -1.250000 1.250000 0 0 0 +( 1648 1472 256 ) ( 1648 1720 256 ) ( 1960 1720 256 ) base_wall/bluemetal2_shiny 0 0 0 0.500000 0.500000 0 0 0 +( 1616 1408 640 ) ( 1928 1408 640 ) ( 1928 1408 0 ) gothic_wall/support2b 19 0 0 -1.250000 1 0 0 0 +( 1944 1472 640 ) ( 1944 1720 640 ) ( 1944 1720 0 ) gothic_wall/support2b 102 0 0 -1.250000 1 0 0 0 +( 1936 1728 640 ) ( 1624 1728 640 ) ( 1624 1728 0 ) gothic_wall/support2b 19 0 0 -1.250000 1 0 0 0 +( 1624 1720 640 ) ( 1624 1472 640 ) ( 1624 1472 0 ) gothic_wall/support2b 102 0 0 -1.250000 1 0 0 0 +} +// brush 69 +{ +( 832 576 320 ) ( 384 576 320 ) ( 384 320 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 384 320 448 ) ( 384 576 448 ) ( 832 576 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 384 320 424 ) ( 832 320 424 ) ( 832 320 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 832 320 424 ) ( 832 576 424 ) ( 832 576 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 832 576 424 ) ( 384 576 424 ) ( 384 576 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 384 576 424 ) ( 384 320 424 ) ( 384 320 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 70 +{ +( -384 576 320 ) ( -832 576 320 ) ( -832 320 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 320 448 ) ( -832 576 448 ) ( -384 576 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -832 320 424 ) ( -384 320 424 ) ( -384 320 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -384 320 424 ) ( -384 576 424 ) ( -384 576 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -384 576 424 ) ( -832 576 424 ) ( -832 576 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -832 576 424 ) ( -832 320 424 ) ( -832 320 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 71 +{ +( -384 -320 320 ) ( -832 -320 320 ) ( -832 -576 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 -576 448 ) ( -832 -320 448 ) ( -384 -320 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -832 -576 424 ) ( -384 -576 424 ) ( -384 -576 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -384 -576 424 ) ( -384 -320 424 ) ( -384 -320 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -384 -320 424 ) ( -832 -320 424 ) ( -832 -320 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( -832 -320 424 ) ( -832 -576 424 ) ( -832 -576 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 72 +{ +( 832 -320 320 ) ( 384 -320 320 ) ( 384 -576 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 384 -576 448 ) ( 384 -320 448 ) ( 832 -320 448 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 384 -576 424 ) ( 832 -576 424 ) ( 832 -576 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 832 -576 424 ) ( 832 -320 424 ) ( 832 -320 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +( 832 -320 424 ) ( 384 -320 424 ) ( 384 -320 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 384 -320 424 ) ( 384 -576 424 ) ( 384 -576 320 ) base_wall/bluemetalsupport2e 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 73 +{ +( 832 -320 320 ) ( 832 -320 322 ) ( 832 320 325 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 712 -320 424 ) ( 808 -320 424 ) ( 808 -320 320 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +( 704 320 424 ) ( 704 -320 424 ) ( 704 -320 320 ) common/caulk 0 0 -180 0.500000 -0.500000 0 0 0 +( 808 320 424 ) ( 712 320 424 ) ( 712 320 320 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +( 704 320 424 ) ( 832 320 322 ) ( 704 -320 424 ) gothic_wall/support2b 0 120 90 0.391030 0.500000 0 0 0 +( 712 -320 320 ) ( 808 -320 320 ) ( 808 320 320 ) common/caulk 0 0 -180 0.500000 0.500000 0 0 0 +} +// brush 74 +{ +( -712 320 320 ) ( -808 320 320 ) ( -808 -320 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -704 -320 424 ) ( -832 -320 322 ) ( -704 320 424 ) gothic_wall/support2b 0 120 270 0.500000 0.500000 0 0 0 +( -808 -320 424 ) ( -712 -320 424 ) ( -712 -320 320 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +( -704 -320 424 ) ( -704 320 424 ) ( -704 320 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -712 320 424 ) ( -808 320 424 ) ( -808 320 320 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +( -832 320 320 ) ( -832 320 322 ) ( -832 -320 325 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 75 +{ +( 248 312 320 ) ( -384 312 320 ) ( -384 72 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -384 72 424 ) ( -384 312 424 ) ( 248 312 424 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( -352 -320 424 ) ( 280 -320 424 ) ( 280 -320 320 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +( 704 129 424 ) ( 704 369 424 ) ( 704 369 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 247 320 424 ) ( -385 320 424 ) ( -385 320 320 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +( -705 311 424 ) ( -705 71 424 ) ( -705 71 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 76 +{ +( -832 -576 320 ) ( 832 -576 320 ) ( 832 -488 320 ) common/caulk -15 16 -180 0.500000 0.500000 0 0 0 +( 384 -576 321 ) ( -384 -576 321 ) ( -384 -320 427 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( -384 -320 320 ) ( 384 -320 320 ) ( 384 -320 424 ) common/caulk -16 0 -180 0.500000 -0.500000 0 0 0 +( -384 -472 384 ) ( -384 -560 384 ) ( -384 -560 328 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +( -384 -576 320 ) ( -384 -576 321 ) ( 384 -576 321 ) common/caulk -16 0 -180 0.500000 -0.500000 0 0 0 +( 384 -568 384 ) ( 384 -480 384 ) ( 384 -480 328 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 77 +{ +( 832 576 320 ) ( -832 576 320 ) ( -832 488 320 ) common/caulk -16 16 0 0.500000 0.500000 0 0 0 +( -384 576 321 ) ( 384 576 321 ) ( 384 320 427 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( 384 320 320 ) ( -384 320 320 ) ( -384 320 424 ) common/caulk -16 0 0 0.500000 0.500000 0 0 0 +( 384 472 384 ) ( 384 560 384 ) ( 384 560 328 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +( 384 576 320 ) ( 384 576 321 ) ( -384 576 321 ) common/caulk -16 0 0 0.500000 0.500000 0 0 0 +( -384 568 384 ) ( -384 480 384 ) ( -384 480 328 ) gothic_wall/support2b 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 78 +{ +( -440 576 264 ) ( -832 576 264 ) ( -832 -48 264 ) common/caulk 16 -16 0 0.500000 0.500000 0 0 0 +( -832 -48 320 ) ( -832 576 320 ) ( -440 576 320 ) common/caulk 16 -16 0 0.500000 0.500000 0 0 0 +( -840 -576 320 ) ( -448 -576 320 ) ( -448 -576 0 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( 832 8 320 ) ( 832 632 320 ) ( 832 632 0 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( -440 576 320 ) ( -832 576 320 ) ( -832 576 0 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( -832 576 320 ) ( -832 -48 320 ) ( -832 -48 0 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +} +// brush 79 +{ +( 1224 568 0 ) ( 192 568 0 ) ( 192 -584 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 200 -584 264 ) ( 200 568 264 ) ( 1232 568 264 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 208 -128 320 ) ( 1240 -128 320 ) ( 1240 -128 0 ) gothic_wall/support2b 76 0 0 -2.500000 1.031250 0 0 0 +( 832 -512 320 ) ( 832 640 320 ) ( 832 640 0 ) gothic_wall/support2b 128 0 0 -1 1.031250 0 0 0 +( 1280 128 320 ) ( 248 128 320 ) ( 248 128 0 ) gothic_wall/support2b 76 0 0 -2.500000 1.031250 0 0 0 +( 192 568 320 ) ( 192 -584 320 ) ( 192 -584 0 ) gothic_wall/support2b 128 0 0 -1 1.031250 0 0 0 +} +// brush 80 +{ +( 200 568 0 ) ( -832 568 0 ) ( -832 -584 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 -584 264 ) ( -832 568 264 ) ( 200 568 264 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -816 -128 320 ) ( 216 -128 320 ) ( 216 -128 0 ) gothic_wall/support2b 179 0 0 -2.500000 1.031250 0 0 0 +( -192 -512 320 ) ( -192 640 320 ) ( -192 640 0 ) gothic_wall/support2b 128 0 0 -1 1.031250 0 0 0 +( 256 128 320 ) ( -776 128 320 ) ( -776 128 0 ) gothic_wall/support2b 179 0 0 -2.500000 1.031250 0 0 0 +( -832 568 320 ) ( -832 -584 320 ) ( -832 -584 0 ) gothic_wall/support2b 128 0 0 -1 1.031250 0 0 0 +} +// brush 81 +{ +( -680 -1216 320 ) ( -832 -1216 320 ) ( -832 -1272 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -888 -1272 1536 ) ( -888 -1216 1536 ) ( -736 -1216 1536 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -696 -1280 768 ) ( -544 -1280 768 ) ( -544 -1280 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 -1280 768 ) ( 832 -1224 768 ) ( 832 -1224 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -680 -1216 768 ) ( -832 -1216 768 ) ( -832 -1216 320 ) gothic_wall/support2b 128 67 0 -6.500000 4.750000 0 0 0 +( -832 -1216 768 ) ( -832 -1272 768 ) ( -832 -1272 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 82 +{ +( 64 1320 576 ) ( -64 1320 576 ) ( -64 1224 576 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -64 1224 1536 ) ( -64 1320 1536 ) ( 64 1320 1536 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -64 1216 704 ) ( 64 1216 704 ) ( 64 1216 576 ) gothic_wall/support2b 128 153 0 -0.500000 3.750000 0 0 0 +( 64 1224 704 ) ( 64 1320 704 ) ( 64 1320 576 ) gothic_wall/support2b 221 153 0 -5.500000 3.750000 0 0 0 +( 112 2624 704 ) ( -16 2624 704 ) ( -16 2624 576 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -64 1320 704 ) ( -64 1224 704 ) ( -64 1224 576 ) gothic_wall/support2b 221 153 0 -5.500000 3.750000 0 0 0 +} +// brush 83 +{ +( 160 1280 448 ) ( -224 1280 448 ) ( -224 1216 448 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -64 1216 576 ) ( -64 2688 576 ) ( 72 2688 576 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -192 1216 768 ) ( 192 1216 768 ) ( 192 1216 760 ) gothic_wall/support2b 128 118 180 -1.500000 0.500000 0 0 0 +( 192 2688 448 ) ( 192 1216 448 ) ( 64 2688 576 ) gothic_wall/support2b 0 -140 270 0.500000 0.500000 0 0 0 +( 88 2624 768 ) ( -296 2624 768 ) ( -296 2624 760 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -192 1216 448 ) ( -192 2688 448 ) ( -64 2688 576 ) gothic_wall/support2b 0 -140 90 0.500000 0.500000 0 0 0 +} +// brush 84 +{ +( 160 1280 320 ) ( -224 1280 320 ) ( -224 1216 320 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -192 1216 448 ) ( -192 1280 448 ) ( 192 1280 448 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -192 1216 640 ) ( 192 1216 640 ) ( 192 1216 632 ) gothic_wall/support2b 128 128 0 -1.500000 0.500000 0 0 0 +( 192 1216 640 ) ( 192 1280 640 ) ( 192 1280 632 ) gothic_wall/support2b 0 117 0 0.500000 0.500000 0 0 0 +( 112 2624 640 ) ( -272 2624 640 ) ( -272 2624 632 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -192 1280 640 ) ( -192 1216 640 ) ( -192 1216 632 ) gothic_wall/support2b 0 117 0 0.500000 0.500000 0 0 0 +} +// brush 85 +{ +( -3392 64 320 ) ( -3392 -128 320 ) ( -3392 -128 256 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( -2752 1344 320 ) ( -3392 1344 320 ) ( -3392 1344 256 ) common/caulk -16 0 0 0.500000 0.500000 0 0 0 +( -2752 -128 320 ) ( -2752 64 320 ) ( -2752 64 256 ) common/caulk 16 0 0 0.500000 0.500000 0 0 0 +( -3008 -576 320 ) ( -2368 -576 320 ) ( -2368 -576 256 ) common/caulk -16 0 0 0.500000 0.500000 0 0 0 +( -3392 -128 320 ) ( -3392 64 320 ) ( -2752 64 320 ) mrcleantex_1/floortile4 -80 -16 0 0.500000 0.500000 0 0 0 +( -2752 64 0 ) ( -3392 64 0 ) ( -3392 -128 0 ) common/caulk -16 -16 0 0.500000 0.500000 0 0 0 +} +// brush 86 +{ +( -2248 -576 320 ) ( -2440 -576 320 ) ( -2440 -576 256 ) common/caulk -16 0 -180 0.500000 -0.500000 0 0 0 +( -832 -1200 320 ) ( -832 -560 320 ) ( -832 -560 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2440 -1216 320 ) ( -2248 -1216 320 ) ( -2248 -1216 256 ) common/caulk -16 0 -180 0.500000 -0.500000 0 0 0 +( -2752 -496 320 ) ( -2752 -1136 320 ) ( -2752 -1136 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2440 -576 320 ) ( -2248 -576 320 ) ( -2248 -1216 320 ) mrcleantex_1/floortile4 0 64 0 0.500000 0.500000 0 0 0 +( -2248 -1216 0 ) ( -2248 -576 0 ) ( -2440 -576 0 ) common/caulk 0 14 90 0.500000 0.500000 0 0 0 +} +// brush 87 +{ +( 3392 64 0 ) ( 2752 64 0 ) ( 2752 -128 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2752 -128 320 ) ( 2752 64 320 ) ( 3392 64 320 ) mrcleantex_1/floortile4 96 0 0 0.500000 0.500000 0 0 0 +( 2736 -576 320 ) ( 3376 -576 320 ) ( 3376 -576 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3392 -128 320 ) ( 3392 64 320 ) ( 3392 64 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3392 1344 320 ) ( 2752 1344 320 ) ( 2752 1344 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2752 64 320 ) ( 2752 -128 320 ) ( 2752 -128 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 88 +{ +( 1080 -1216 0 ) ( 1080 -576 0 ) ( 888 -576 0 ) common/caulk 0 14 90 0.500000 0.500000 0 0 0 +( 888 -576 320 ) ( 1080 -576 320 ) ( 1080 -1216 320 ) mrcleantex_1/floortile4 0 80 0 0.500000 0.500000 0 0 0 +( 832 -488 320 ) ( 832 -1128 320 ) ( 832 -1128 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 888 -1216 320 ) ( 1080 -1216 320 ) ( 1080 -1216 256 ) common/caulk -16 0 -180 0.500000 -0.500000 0 0 0 +( 2752 -1184 320 ) ( 2752 -544 320 ) ( 2752 -544 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1080 -576 320 ) ( 888 -576 320 ) ( 888 -576 256 ) common/caulk -16 0 -180 0.500000 -0.500000 0 0 0 +} +// brush 89 +{ +( -2112 3136 0 ) ( -2752 3136 0 ) ( -2752 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 2688 320 ) ( -2752 3136 320 ) ( -2112 3136 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( -2752 2688 320 ) ( -2112 2688 320 ) ( -2112 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2112 2624 320 ) ( -2112 3072 320 ) ( -2112 3072 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2112 3328 320 ) ( -2752 3328 320 ) ( -2752 3328 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 3136 320 ) ( -2752 2688 320 ) ( -2752 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 90 +{ +( -1472 3136 0 ) ( -2112 3136 0 ) ( -2112 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2112 2688 320 ) ( -2112 3136 320 ) ( -1472 3136 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( -2112 2688 320 ) ( -1472 2688 320 ) ( -1472 2688 0 ) gothic_wall/support2b 179 0 0 -2.500000 1.250000 0 0 0 +( -1472 2624 320 ) ( -1472 3072 320 ) ( -1472 3072 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1472 3328 320 ) ( -2112 3328 320 ) ( -2112 3328 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2112 3136 320 ) ( -2112 2688 320 ) ( -2112 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 91 +{ +( -584 -1216 0 ) ( -584 -576 0 ) ( -776 -576 0 ) common/caulk 0 16 90 0.500000 0.500000 0 0 0 +( -776 -576 320 ) ( -584 -576 320 ) ( -584 -1216 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( -832 -488 320 ) ( -832 -1128 320 ) ( -832 -1128 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -776 -1216 320 ) ( -584 -1216 320 ) ( -584 -1216 256 ) common/caulk -16 0 -180 0.500000 -0.500000 0 0 0 +( 832 -1200 320 ) ( 832 -560 320 ) ( 832 -560 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -584 -576 320 ) ( -776 -576 320 ) ( -776 -576 256 ) gothic_wall/support2b 128 0 0 -6.500000 1.250000 0 0 0 +} +// brush 92 +{ +( -2752 1408 0 ) ( -3392 1408 0 ) ( -3392 1216 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3392 1216 320 ) ( -3392 1408 320 ) ( -2752 1408 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( -3000 1344 320 ) ( -2360 1344 320 ) ( -2360 1344 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -2752 1216 320 ) ( -2752 1408 320 ) ( -2752 1408 256 ) gothic_wall/support2b 0 0 0 -5.250000 1.250000 0 0 0 +( -2752 2688 320 ) ( -3392 2688 320 ) ( -3392 2688 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -3392 1408 320 ) ( -3392 1216 320 ) ( -3392 1216 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 93 +{ +( -832 3136 0 ) ( -1472 3136 0 ) ( -1472 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1472 2688 320 ) ( -1472 3136 320 ) ( -832 3136 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( -1472 2688 320 ) ( -832 2688 320 ) ( -832 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 2624 320 ) ( -832 3072 320 ) ( -832 3072 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 3328 320 ) ( -1472 3328 320 ) ( -1472 3328 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -1472 3136 320 ) ( -1472 2688 320 ) ( -1472 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 94 +{ +( -192 1408 0 ) ( -832 1408 0 ) ( -832 1216 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 1216 320 ) ( -832 1408 320 ) ( -192 1408 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( -752 576 320 ) ( -112 576 320 ) ( -112 576 256 ) gothic_wall/support2b 179 0 0 -2.500000 1.250000 0 0 0 +( -192 1216 320 ) ( -192 1408 320 ) ( -192 1408 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -192 2688 320 ) ( -832 2688 320 ) ( -832 2688 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 1408 320 ) ( -832 1216 320 ) ( -832 1216 256 ) gothic_wall/support2b 211 0 0 -5.750000 1.250000 0 0 0 +} +// brush 95 +{ +( 3392 1408 0 ) ( 2752 1408 0 ) ( 2752 1216 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2752 1216 320 ) ( 2752 1408 320 ) ( 3392 1408 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( 2752 1344 320 ) ( 3392 1344 320 ) ( 3392 1344 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3392 1216 320 ) ( 3392 1408 320 ) ( 3392 1408 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 3392 2688 320 ) ( 2752 2688 320 ) ( 2752 2688 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2752 1408 320 ) ( 2752 1216 320 ) ( 2752 1216 256 ) gothic_wall/support2b 0 0 0 -5.250000 1.250000 0 0 0 +} +// brush 96 +{ +( 2752 3136 0 ) ( 2112 3136 0 ) ( 2112 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2112 2688 320 ) ( 2112 3136 320 ) ( 2752 3136 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( 2112 2688 320 ) ( 2752 2688 320 ) ( 2752 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2752 2624 320 ) ( 2752 3072 320 ) ( 2752 3072 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2752 3328 320 ) ( 2112 3328 320 ) ( 2112 3328 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2112 3136 320 ) ( 2112 2688 320 ) ( 2112 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 97 +{ +( 2112 3136 0 ) ( 1472 3136 0 ) ( 1472 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1472 2688 320 ) ( 1472 3136 320 ) ( 2112 3136 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( 1472 2688 320 ) ( 2112 2688 320 ) ( 2112 2688 0 ) gothic_wall/support2b 76 0 0 -2.500000 1.250000 0 0 0 +( 2112 2624 320 ) ( 2112 3072 320 ) ( 2112 3072 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 2112 3328 320 ) ( 1472 3328 320 ) ( 1472 3328 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1472 3136 320 ) ( 1472 2688 320 ) ( 1472 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 98 +{ +( 1472 3136 0 ) ( 832 3136 0 ) ( 832 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 2688 320 ) ( 832 3136 320 ) ( 1472 3136 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( 832 2688 320 ) ( 1472 2688 320 ) ( 1472 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1472 2624 320 ) ( 1472 3072 320 ) ( 1472 3072 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 1472 3328 320 ) ( 832 3328 320 ) ( 832 3328 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 3136 320 ) ( 832 2688 320 ) ( 832 2688 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 99 +{ +( 832 1408 0 ) ( 192 1408 0 ) ( 192 1216 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 192 1216 320 ) ( 192 1408 320 ) ( 832 1408 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( 256 576 320 ) ( 896 576 320 ) ( 896 576 256 ) gothic_wall/support2b 76 0 0 -2.500000 1.250000 0 0 0 +( 832 1216 320 ) ( 832 1408 320 ) ( 832 1408 256 ) gothic_wall/support2b 211 0 0 -5.750000 1.250000 0 0 0 +( 832 2688 320 ) ( 192 2688 320 ) ( 192 2688 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 192 1408 320 ) ( 192 1216 320 ) ( 192 1216 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 100 +{ +( 512 1216 0 ) ( -128 1216 0 ) ( -128 576 0 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -192 576 320 ) ( -192 1216 320 ) ( 448 1216 320 ) mrcleantex_1/floortile4 0 0 0 0.500000 0.500000 0 0 0 +( -192 576 320 ) ( 448 576 320 ) ( 448 576 256 ) gothic_wall/support2b 128 0 0 -1.500000 1.250000 0 0 0 +( 192 576 320 ) ( 192 1216 320 ) ( 192 1216 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 448 1216 320 ) ( -192 1216 320 ) ( -192 1216 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -192 1216 320 ) ( -192 576 320 ) ( -192 576 256 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +// brush 101 +{ +( 704 -192 -64 ) ( -832 -192 -64 ) ( -832 -1216 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 -576 0 ) ( -832 448 0 ) ( 704 448 0 ) gothic_floor/q1metal7_98 0 0 0 0.500000 0.500000 0 0 0 +( -832 -1216 8 ) ( 704 -1216 8 ) ( 704 -1216 -56 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 832 -576 0 ) ( 832 448 0 ) ( 832 448 -64 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( 768 1216 -16 ) ( -768 1216 -16 ) ( -768 1216 -80 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +( -832 520 8 ) ( -832 -504 8 ) ( -832 -504 -56 ) common/caulk 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 1 +{ +"classname" "target_position" +"targetname" "jump2" +"origin" "-1792 2632 520" +} +// entity 2 +{ +"classname" "trigger_push" +"target" "jump2" +// brush 0 +{ +( -1216 -192 0 ) ( -2752 -192 0 ) ( -2752 -1216 0 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( -2752 -576 32 ) ( -2752 448 32 ) ( -1216 448 32 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( -1208 2688 24 ) ( -2744 2688 24 ) ( -2744 2688 -40 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( -1864 2560 -24 ) ( -1888 2560 -24 ) ( -1876 2560 40 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( -1856 2672 -24 ) ( -1856 2688 -24 ) ( -1856 2680 40 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( -1728 2688 -24 ) ( -1728 2672 -24 ) ( -1728 2680 40 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 3 +{ +"classname" "target_position" +"targetname" "jump1" +"origin" "1792 2632 520" +} +// entity 4 +{ +"classname" "trigger_push" +"target" "jump1" +// brush 0 +{ +( 2376 -192 0 ) ( 840 -192 0 ) ( 840 -1216 0 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( 832 -576 32 ) ( 832 448 32 ) ( 2368 448 32 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( 2376 2688 16 ) ( 840 2688 16 ) ( 840 2688 -48 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( 1720 2560 -32 ) ( 1664 2560 -32 ) ( 1692 2560 32 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( 1728 2616 -32 ) ( 1728 2688 -32 ) ( 1728 2652 32 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +( 1856 2688 -32 ) ( 1856 2664 -32 ) ( 1856 2676 32 ) common/trigger 0 0 0 0.500000 0.500000 0 0 0 +} +} +// entity 5 +{ +"classname" "info_player_deathmatch" +"origin" "-552 992 344" +} +// entity 6 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_wall/bluemetal2_shiny + ( 3 3 0 0 0 ) +( +( ( -512 -320 448 0 0 ) ( -448 -320 448 0 0.500000 ) ( -384 -320 448 0 1 ) ) +( ( -512 -320 896 3.500000 0 ) ( -448 -320 896 3.500000 0.500000 ) ( -384 -320 896 3.500000 1 ) ) +( ( -512 0.000025 896 6 0 ) ( -448 0.000025 896 6 0.500000 ) ( -384 0.000025 896 6 1 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_wall/c_met7_2 + ( 3 3 0 0 0 ) +( +( ( -512 -320 448 -8 -7 ) ( -512 -320 896 -8 -14 ) ( -512 0.000025 896 -8 -14 ) ) +( ( -512 -320 896 -8 -14 ) ( -512 -320 896 -8 -14 ) ( -512 -320 896 -8 -14 ) ) +( ( -512 -320 896 -8 -14 ) ( -512 -320 896 -8 -14 ) ( -512 -320 896 -8 -14 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_wall/bluemetalsupport2e + ( 3 3 0 0 0 ) +( +( ( -384 0.000025 896 -6 -28 ) ( -384 -320 896 -6 -28 ) ( -384 -320 448 -6 -14 ) ) +( ( -384 -320 896 -6 -28 ) ( -384 -320 896 -6 -28 ) ( -384 -320 896 -6 -28 ) ) +( ( -384 -320 896 -6 -28 ) ( -384 -320 896 -6 -28 ) ( -384 -320 896 -6 -28 ) ) +) + } + } +} +// entity 7 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_wall/bluemetal2_shiny + ( 3 3 0 0 0 ) +( +( ( -384 576 640 0 0 ) ( -384 448 640 0 1 ) ( -384 320 640 0 2 ) ) +( ( -384 576 896 2 0 ) ( -384 448 896 2 1 ) ( -384 320 896 2 2 ) ) +( ( -128 576 896 4 0 ) ( -128 448 896 4 1 ) ( -128 320 896 4 2 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_wall/c_met7_2 + ( 3 3 0 0 0 ) +( +( ( -384 576 640 -6 -10 ) ( -384 576 896 -6 -14 ) ( -128 576 896 -2 -14 ) ) +( ( -384 576 896 -6 -14 ) ( -384 576 896 -6 -14 ) ( -384 576 896 -6 -14 ) ) +( ( -384 576 896 -6 -14 ) ( -384 576 896 -6 -14 ) ( -384 576 896 -6 -14 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_wall/bluemetalsupport2e + ( 3 3 0 0 0 ) +( +( ( -128 320 896 -2 -28 ) ( -384 320 896 -6 -28 ) ( -384 320 640 -6 -20 ) ) +( ( -384 320 896 -6 -28 ) ( -384 320 896 -6 -28 ) ( -384 320 896 -6 -28 ) ) +( ( -384 320 896 -6 -28 ) ( -384 320 896 -6 -28 ) ( -384 320 896 -6 -28 ) ) +) + } + } +} +// entity 8 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( -2752 1344 320 0 0 ) ( -2752 1344 160 0 0.500000 ) ( -2752 1344 0 0 1 ) ) +( ( -2752 -576.000244 320 0.500000 0 ) ( -2752 -576.000244 160 0.500000 0.500000 ) ( -2752 -576.000244 0 0.500000 1 ) ) +( ( -832 -576.000244 320 1 0 ) ( -832 -576.000244 160 1 0.500000 ) ( -832 -576.000244 0 1 1 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( -2752 1344 320 -43 -21 ) ( -2752 -576.000244 320 -43 9.000004 ) ( -832 -576.000244 320 -13 9.000004 ) ) +( ( -2752 -576.000244 320 -43 9.000004 ) ( -2752 -576.000244 320 -43 9.000004 ) ( -2752 -576.000244 320 -43 9.000004 ) ) +( ( -2752 -576.000244 320 -43 9.000004 ) ( -2752 -576.000244 320 -43 9.000004 ) ( -2752 -576.000244 320 -43 9.000004 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( -832 -576.000244 0 0 0 ) ( -2752 -576.000244 0 0 0.500000 ) ( -2752 1344 0 0 1 ) ) +( ( -2752 -576.000244 0 0.500000 0 ) ( -2752 -576.000244 0 0.500000 0.500000 ) ( -2752 -576.000244 0 0.500000 1 ) ) +( ( -2752 -576.000244 0 1 0 ) ( -2752 -576.000244 0 1 0.500000 ) ( -2752 -576.000244 0 1 1 ) ) +) + } + } +} +// entity 9 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( 3392 2688 0 0 0 ) ( 3392 2688 160 0 5 ) ( 3392 2688 320 0 10 ) ) +( ( 3392 3328 0 20 0 ) ( 3392 3328 160 20 5 ) ( 3392 3328 320 20 10 ) ) +( ( 2752 3328 0 40 0 ) ( 2752 3328 160 40 5 ) ( 2752 3328 320 40 10 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( 2752 2688 0 86 -84 ) ( 2752 2688 0 86 -84 ) ( 2752 2688 0 86 -84 ) ) +( ( 2752 2688 0 86 -84 ) ( 2752 2688 0 86 -84 ) ( 2752 2688 0 86 -84 ) ) +( ( 3392 2688 0 106 -84 ) ( 3392 3328 0 106 -104 ) ( 2752 3328 0 86 -104 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( 2752 2688 320 43 -42 ) ( 2752 2688 320 43 -42 ) ( 2752 2688 320 43 -42 ) ) +( ( 2752 2688 320 43 -42 ) ( 2752 2688 320 43 -42 ) ( 2752 2688 320 43 -42 ) ) +( ( 3392 2688 320 53 -42 ) ( 3392 3328 320 53 -52 ) ( 2752 3328 320 43 -52 ) ) +) + } + } +} +// entity 10 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( 1472 2688 320 0 0 ) ( 1472 2688 160 0 0.500000 ) ( 1472 2688 0 0 1 ) ) +( ( 832 2688 320 0.500000 0 ) ( 832 2688 160 0.500000 0.500000 ) ( 832 2688 0 0.500000 1 ) ) +( ( 832 2048 320 1 0 ) ( 832 2048 160 1 0.500000 ) ( 832 2048 0 1 1 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( 1472 2688 320 23 -42 ) ( 832 2688 320 13 -42 ) ( 832 2048 320 13 -32 ) ) +( ( 832 2688 320 13 -42 ) ( 832 2688 320 13 -42 ) ( 832 2688 320 13 -42 ) ) +( ( 832 2688 320 13 -42 ) ( 832 2688 320 13 -42 ) ( 832 2688 320 13 -42 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( 832 2048 0 26 -64 ) ( 832 2688 0 0 0.500000 ) ( 1472 2688 0 0 1 ) ) +( ( 832 2688 0 0.500000 0 ) ( 832 2688 0 0.500000 0.500000 ) ( 832 2688 0 0.500000 1 ) ) +( ( 832 2688 0 1 0 ) ( 832 2688 0 1 0.500000 ) ( 832 2688 0 1 1 ) ) +) + } + } +} +// entity 11 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( 2752 2048 320 0 0 ) ( 2752 2048 160 0 0.500000 ) ( 2752 2048 0 0 1 ) ) +( ( 2752 2688 320 0.500000 0 ) ( 2752 2688 160 0.500000 0.500000 ) ( 2752 2688 0 0.500000 1 ) ) +( ( 2112 2688 320 1 0 ) ( 2112 2688 160 1 0.500000 ) ( 2112 2688 0 1 1 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( 2752 2048 320 43 -32 ) ( 2752 2688 320 43 -42 ) ( 2112 2688 320 33 -42 ) ) +( ( 2752 2688 320 43 -42 ) ( 2752 2688 320 43 -42 ) ( 2752 2688 320 43 -42 ) ) +( ( 2752 2688 320 43 -42 ) ( 2752 2688 320 43 -42 ) ( 2752 2688 320 43 -42 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( 2112 2688 0 26 -64 ) ( 2752 2688 0 26 -84 ) ( 2752 2048 0 46 -84 ) ) +( ( 2752 2688 0 26 -84 ) ( 2752 2688 0 26 -84 ) ( 2752 2688 0 26 -84 ) ) +( ( 2752 2688 0 26 -84 ) ( 2752 2688 0 26 -84 ) ( 2752 2688 0 26 -84 ) ) +) + } + } +} +// entity 12 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( 832 3328 0 0 0 ) ( 832 3328 160 0 5 ) ( 832 3328 320 0 10 ) ) +( ( 192 3328 0 20 0 ) ( 192 3328 160 20 5 ) ( 192 3328 320 20 10 ) ) +( ( 192 2688 0 40 0 ) ( 192 2688 160 40 5 ) ( 192 2688 320 40 10 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( 832 2688 0 86 -84 ) ( 832 2688 0 86 -84 ) ( 832 2688 0 86 -84 ) ) +( ( 832 2688 0 86 -84 ) ( 832 2688 0 86 -84 ) ( 832 2688 0 86 -84 ) ) +( ( 832 3328 0 106 -84 ) ( 192 3328 0 106 -104 ) ( 192 2688 0 86 -104 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( 832 2688 320 13 -42 ) ( 832 2688 320 13 -42 ) ( 832 2688 320 13 -42 ) ) +( ( 832 2688 320 13 -42 ) ( 832 2688 320 13 -42 ) ( 832 2688 320 13 -42 ) ) +( ( 832 3328 320 13 -52 ) ( 192 3328 320 3 -52 ) ( 192 2688 320 3 -42 ) ) +) + } + } +} +// entity 13 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( -192 2688 0 0 0 ) ( -192 2688 160 0 5 ) ( -192 2688 320 0 10 ) ) +( ( -192 3328 0 20 0 ) ( -192 3328 160 20 5 ) ( -192 3328 320 20 10 ) ) +( ( -832 3328 0 40 0 ) ( -832 3328 160 40 5 ) ( -832 3328 320 40 10 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( -832 2688 0 86 -84 ) ( -832 2688 0 86 -84 ) ( -832 2688 0 86 -84 ) ) +( ( -832 2688 0 86 -84 ) ( -832 2688 0 86 -84 ) ( -832 2688 0 86 -84 ) ) +( ( -192 2688 0 106 -84 ) ( -192 3328 0 106 -104 ) ( -832 3328 0 86 -104 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( -832 2688 320 -13 -42 ) ( -832 2688 320 -13 -42 ) ( -832 2688 320 -13 -42 ) ) +( ( -832 2688 320 -13 -42 ) ( -832 2688 320 -13 -42 ) ( -832 2688 320 -13 -42 ) ) +( ( -192 2688 320 -3 -42 ) ( -192 3328 320 -3 -52 ) ( -832 3328 320 -13 -52 ) ) +) + } + } +} +// entity 14 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( -832 2048 320 0 0 ) ( -832 2048 160 0 0.500000 ) ( -832 2048 0 0 1 ) ) +( ( -832 2688 320 0.500000 0 ) ( -832 2688 160 0.500000 0.500000 ) ( -832 2688 0 0.500000 1 ) ) +( ( -1472 2688 320 1 0 ) ( -1472 2688 160 1 0.500000 ) ( -1472 2688 0 1 1 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( -832 2048 320 -13 -32 ) ( -832 2688 320 -13 -42 ) ( -1472 2688 320 -23 -42 ) ) +( ( -832 2688 320 -13 -42 ) ( -832 2688 320 -13 -42 ) ( -832 2688 320 -13 -42 ) ) +( ( -832 2688 320 -13 -42 ) ( -832 2688 320 -13 -42 ) ( -832 2688 320 -13 -42 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( -1472 2688 0 0 0 ) ( -832 2688 0 0 0.500000 ) ( -832 2048 0 0 1 ) ) +( ( -832 2688 0 0.500000 0 ) ( -832 2688 0 0.500000 0.500000 ) ( -832 2688 0 0.500000 1 ) ) +( ( -832 2688 0 1 0 ) ( -832 2688 0 1 0.500000 ) ( -832 2688 0 1 1 ) ) +) + } + } +} +// entity 15 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( -2752 3328 0 0 0 ) ( -2752 3328 160 0 5 ) ( -2752 3328 320 0 10 ) ) +( ( -3392 3328 0 20 0 ) ( -3392 3328 160 20 5 ) ( -3392 3328 320 20 10 ) ) +( ( -3392 2688 0 40 0 ) ( -3392 2688 160 40 5 ) ( -3392 2688 320 40 10 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( -2752 2688 0 86 -84 ) ( -2752 2688 0 86 -84 ) ( -2752 2688 0 86 -84 ) ) +( ( -2752 2688 0 86 -84 ) ( -2752 2688 0 86 -84 ) ( -2752 2688 0 86 -84 ) ) +( ( -2752 3328 0 106 -84 ) ( -3392 3328 0 106 -104 ) ( -3392 2688 0 86 -104 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( -2752 2688 320 -43 -42 ) ( -2752 2688 320 -43 -42 ) ( -2752 2688 320 -43 -42 ) ) +( ( -2752 2688 320 -43 -42 ) ( -2752 2688 320 -43 -42 ) ( -2752 2688 320 -43 -42 ) ) +( ( -2752 3328 320 -43 -52 ) ( -3392 3328 320 -53 -52 ) ( -3392 2688 320 -53 -42 ) ) +) + } + } +} +// entity 16 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( -2112 2688 320 0 0 ) ( -2112 2688 160 0 0.500000 ) ( -2112 2688 0 0 1 ) ) +( ( -2752 2688 320 0.500000 0 ) ( -2752 2688 160 0.500000 0.500000 ) ( -2752 2688 0 0.500000 1 ) ) +( ( -2752 2048 320 1 0 ) ( -2752 2048 160 1 0.500000 ) ( -2752 2048 0 1 1 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( -2112 2688 320 -33 -42 ) ( -2752 2688 320 -43 -42 ) ( -2752 2048 320 -43 -32 ) ) +( ( -2752 2688 320 -43 -42 ) ( -2752 2688 320 -43 -42 ) ( -2752 2688 320 -43 -42 ) ) +( ( -2752 2688 320 -43 -42 ) ( -2752 2688 320 -43 -42 ) ( -2752 2688 320 -43 -42 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( -2752 2048 0 0 0 ) ( -2752 2688 0 0 0.500000 ) ( -2112 2688 0 0 1 ) ) +( ( -2752 2688 0 0.500000 0 ) ( -2752 2688 0 0.500000 0.500000 ) ( -2752 2688 0 0.500000 1 ) ) +( ( -2752 2688 0 1 0 ) ( -2752 2688 0 1 0.500000 ) ( -2752 2688 0 1 1 ) ) +) + } + } +} +// entity 17 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( 832 -576 320 0 0 ) ( 832 -576 160 0 0.500000 ) ( 832 -576 0 0 1 ) ) +( ( 2752 -576 320 0.500000 0 ) ( 2752 -576 160 0.500000 0.500000 ) ( 2752 -576 0 0.500000 1 ) ) +( ( 2752 1344 320 1 0 ) ( 2752 1344 160 1 0.500000 ) ( 2752 1344 0 1 1 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + mrcleantex_1/floortile4 + ( 3 3 0 0 0 ) +( +( ( 832 -576 320 13 9 ) ( 2752 -576 320 43 9 ) ( 2752 1344 320 43 -21 ) ) +( ( 2752 -576 320 43 9 ) ( 2752 -576 320 43 9 ) ( 2752 -576 320 43 9 ) ) +( ( 2752 -576 320 43 9 ) ( 2752 -576 320 43 9 ) ( 2752 -576 320 43 9 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( 2752 1344 0 -26 18.000008 ) ( 2752 -576 0 -86 18.000008 ) ( 832 -576 0 -86 -42 ) ) +( ( 2752 -576 0 -86 18.000008 ) ( 2752 -576 0 -86 18.000008 ) ( 2752 -576 0 -86 18.000008 ) ) +( ( 2752 -576 0 -86 18.000008 ) ( 2752 -576 0 -86 18.000008 ) ( 2752 -576 0 -86 18.000008 ) ) +) + } + } +} +// entity 18 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( -3392 1343.999756 320 -86 -42 ) ( -3392 -1216.000488 320 -86 18.000008 ) ( -832.000427 -1216.000488 320 -26 18.000008 ) ) +( ( -3392 -1216.000488 320 -86 18.000008 ) ( -3392 -1216.000488 320 -86 18.000008 ) ( -3392 -1216.000488 320 -86 18.000008 ) ) +( ( -3392 -1216.000488 320 -86 18.000008 ) ( -3392 -1216.000488 320 -86 18.000008 ) ( -3392 -1216.000488 320 -86 18.000008 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( -832.000427 -1216.000488 0 -26 18.000008 ) ( -3392 -1216.000488 0 -86 18.000008 ) ( -3392 1343.999756 0 -86 -42 ) ) +( ( -3392 -1216.000488 0 -86 18.000008 ) ( -3392 -1216.000488 0 -86 18.000008 ) ( -3392 -1216.000488 0 -86 18.000008 ) ) +( ( -3392 -1216.000488 0 -86 18.000008 ) ( -3392 -1216.000488 0 -86 18.000008 ) ( -3392 -1216.000488 0 -86 18.000008 ) ) +) + } + } +} +// entity 19 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( -3392 1343.999756 1536 0 0 ) ( -3392 1343.999756 927.999939 0 0.500000 ) ( -3392 1343.999756 320 0 1 ) ) +( ( -3392 -1216.000488 1536 0.500000 0 ) ( -3392 -1216.000488 927.999939 0.500000 0.500000 ) ( -3392 -1216.000488 320 0.500000 1 ) ) +( ( -832.000427 -1216.000488 1536 1 0 ) ( -832.000427 -1216.000488 927.999939 1 0.500000 ) ( -832.000427 -1216.000488 320 1 1 ) ) +) + } + } +} +// entity 20 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( 832 -1216 320 0 10 ) ( 832 -1216 160 0 5 ) ( 832 -1216 0 0 0 ) ) +( ( 3392 -1216 320 80 10 ) ( 3392 -1216 160 80 5 ) ( 3392 -1216 0 80 0 ) ) +( ( 3392 1344 320 160 10 ) ( 3392 1344 160 160 5 ) ( 3392 1344 0 160 0 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( 832 -1216 320 -86 -42 ) ( 3392 -1216 320 -86 18.000008 ) ( 3392 1344 320 -26 18.000008 ) ) +( ( 3392 -1216 320 -86 18.000008 ) ( 3392 -1216 320 -86 18.000008 ) ( 3392 -1216 320 -86 18.000008 ) ) +( ( 3392 -1216 320 -86 18.000008 ) ( 3392 -1216 320 -86 18.000008 ) ( 3392 -1216 320 -86 18.000008 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + common/caulk + ( 3 3 0 0 0 ) +( +( ( 3392 1344 0 -26 18.000008 ) ( 3392 -1216 0 -86 18.000008 ) ( 832 -1216 0 -86 -42 ) ) +( ( 3392 -1216 0 -86 18.000008 ) ( 3392 -1216 0 -86 18.000008 ) ( 3392 -1216 0 -86 18.000008 ) ) +( ( 3392 -1216 0 -86 18.000008 ) ( 3392 -1216 0 -86 18.000008 ) ( 3392 -1216 0 -86 18.000008 ) ) +) + } + } +} +// entity 21 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_wall/support2b + ( 3 3 0 0 0 ) +( +( ( 832 -1216 1536 0 0 ) ( 832 -1216 928 0 0.500000 ) ( 832 -1216 320 0 1 ) ) +( ( 3392 -1216 1536 0.500000 0 ) ( 3392 -1216 928 0.500000 0.500000 ) ( 3392 -1216 320 0.500000 1 ) ) +( ( 3392 1344 1536 1 0 ) ( 3392 1344 928 1 0.500000 ) ( 3392 1344 320 1 1 ) ) +) + } + } +} +// entity 22 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + base_wall/bluemetal2_shiny + ( 3 3 0 0 0 ) +( +( ( 384 320 640 0 0 ) ( 384 448 640 0 1 ) ( 384 576 640 0 2 ) ) +( ( 384 320 896 2 0 ) ( 384 448 896 2 1 ) ( 384 576 896 2 2 ) ) +( ( 128 320 896 4 0 ) ( 128 448 896 4 1 ) ( 128 576 896 4 2 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_wall/bluemetalsupport2e + ( 3 3 0 0 0 ) +( +( ( 384 320 640 6 -20 ) ( 384 320 896 6 -28 ) ( 128 320 896 2 -28 ) ) +( ( 384 320 896 6 -28 ) ( 384 320 896 6 -28 ) ( 384 320 896 6 -28 ) ) +( ( 384 320 896 6 -28 ) ( 384 320 896 6 -28 ) ( 384 320 896 6 -28 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_wall/c_met7_2 + ( 3 3 0 0 0 ) +( +( ( 128 576 896 9 -14 ) ( 384 576 896 9 -14 ) ( 384 576 640 9 -10 ) ) +( ( 384 576 896 9 -14 ) ( 384 576 896 9 -14 ) ( 384 576 896 9 -14 ) ) +( ( 384 576 896 9 -14 ) ( 384 576 896 9 -14 ) ( 384 576 896 9 -14 ) ) +) + } + } +} +// entity 23 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + base_wall/bluemetal2_shiny + ( 3 3 0 0 0 ) +( +( ( 384 -576 640 0 0 ) ( 384 -448 640 0 1 ) ( 384 -320 640 0 2 ) ) +( ( 384 -576 896 2 0 ) ( 384 -448 896 2 1 ) ( 384 -320 896 2 2 ) ) +( ( 128 -576 896 4 0 ) ( 128 -448 896 4 1 ) ( 128 -320 896 4 2 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_wall/c_met7_2 + ( 3 3 0 0 0 ) +( +( ( 384 -576 640 6 -10 ) ( 384 -576 896 6 -14 ) ( 128 -576 896 2 -14 ) ) +( ( 384 -576 896 6 -14 ) ( 384 -576 896 6 -14 ) ( 384 -576 896 6 -14 ) ) +( ( 384 -576 896 6 -14 ) ( 384 -576 896 6 -14 ) ( 384 -576 896 6 -14 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_wall/bluemetalsupport2e + ( 3 3 0 0 0 ) +( +( ( 128 -320 896 2 -28 ) ( 384 -320 896 6 -28 ) ( 384 -320 640 6 -20 ) ) +( ( 384 -320 896 6 -28 ) ( 384 -320 896 6 -28 ) ( 384 -320 896 6 -28 ) ) +( ( 384 -320 896 6 -28 ) ( 384 -320 896 6 -28 ) ( 384 -320 896 6 -28 ) ) +) + } + } +} +// entity 24 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_wall/bluemetal2_shiny + ( 3 3 0 0 0 ) +( +( ( -384 -320 640 0 0 ) ( -384 -448 640 0 1 ) ( -384 -576 640 0 2 ) ) +( ( -384 -320 896 2 0 ) ( -384 -448 896 2 1 ) ( -384 -576 896 2 2 ) ) +( ( -128 -320 896 4 0 ) ( -128 -448 896 4 1 ) ( -128 -576 896 4 2 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_wall/bluemetalsupport2e + ( 3 3 0 0 0 ) +( +( ( -384 -320 640 -5 -20 ) ( -384 -320 896 -5 -28 ) ( -128 -320 896 -5 -28 ) ) +( ( -384 -320 896 -5 -28 ) ( -384 -320 896 -5 -28 ) ( -384 -320 896 -5 -28 ) ) +( ( -384 -320 896 -5 -28 ) ( -384 -320 896 -5 -28 ) ( -384 -320 896 -5 -28 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_wall/c_met7_2 + ( 3 3 0 0 0 ) +( +( ( -128 -576 896 -2 -14 ) ( -384 -576 896 -6 -14 ) ( -384 -576 640 -6 -10 ) ) +( ( -384 -576 896 -6 -14 ) ( -384 -576 896 -6 -14 ) ( -384 -576 896 -6 -14 ) ) +( ( -384 -576 896 -6 -14 ) ( -384 -576 896 -6 -14 ) ( -384 -576 896 -6 -14 ) ) +) + } + } +} +// entity 25 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + base_wall/bluemetal2_shiny + ( 3 3 0 0 0 ) +( +( ( -384 320 448 0 0 ) ( -448 320 448 0 0.500000 ) ( -512 320 448 0 1 ) ) +( ( -384 320 896 3.500000 0 ) ( -448 320 896 3.500000 0.500000 ) ( -512 320 896 3.500000 1 ) ) +( ( -384 0 896 6 0 ) ( -448 0 896 6 0.500000 ) ( -512 0 896 6 1 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_wall/bluemetalsupport2e + ( 3 3 0 0 0 ) +( +( ( -384 320 448 5 -14 ) ( -384 320 896 5 -28 ) ( -384 0 896 0 -28 ) ) +( ( -384 320 896 5 -28 ) ( -384 320 896 5 -28 ) ( -384 320 896 5 -28 ) ) +( ( -384 320 896 5 -28 ) ( -384 320 896 5 -28 ) ( -384 320 896 5 -28 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_wall/c_met7_2 + ( 3 3 0 0 0 ) +( +( ( -512 0 896 0 -14 ) ( -512 320 896 5 -14 ) ( -512 320 448 5 -7 ) ) +( ( -512 320 896 5 -14 ) ( -512 320 896 5 -14 ) ( -512 320 896 5 -14 ) ) +( ( -512 320 896 5 -14 ) ( -512 320 896 5 -14 ) ( -512 320 896 5 -14 ) ) +) + } + } +} +// entity 26 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + base_wall/c_met7_2 + ( 3 3 0 0 0 ) +( +( ( 512 320 448 8 -7 ) ( 512 320 896 8 -14 ) ( 512 0 896 8 -14 ) ) +( ( 512 320 896 8 -14 ) ( 512 320 896 8 -14 ) ( 512 320 896 8 -14 ) ) +( ( 512 320 896 8 -14 ) ( 512 320 896 8 -14 ) ( 512 320 896 8 -14 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_wall/bluemetalsupport2e + ( 3 3 0 0 0 ) +( +( ( 384 0 896 0 -28 ) ( 384 320 896 5 -28 ) ( 384 320 448 5 -14 ) ) +( ( 384 320 896 5 -28 ) ( 384 320 896 5 -28 ) ( 384 320 896 5 -28 ) ) +( ( 384 320 896 5 -28 ) ( 384 320 896 5 -28 ) ( 384 320 896 5 -28 ) ) +) + } + } +} +// entity 27 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_wall/bluemetalsupport2e + ( 3 3 0 0 0 ) +( +( ( 384 -320 448 -5 -14 ) ( 384 -320 896 -5 -28 ) ( 384 0 896 0 -28 ) ) +( ( 384 -320 896 -5 -28 ) ( 384 -320 896 -5 -28 ) ( 384 -320 896 -5 -28 ) ) +( ( 384 -320 896 -5 -28 ) ( 384 -320 896 -5 -28 ) ( 384 -320 896 -5 -28 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_wall/c_met7_2 + ( 3 3 0 0 0 ) +( +( ( 512 0 896 0 -14 ) ( 512 -320 896 -5 -14 ) ( 512 -320 448 -5 -7 ) ) +( ( 512 -320 896 -5 -14 ) ( 512 -320 896 -5 -14 ) ( 512 -320 896 -5 -14 ) ) +( ( 512 -320 896 -5 -14 ) ( 512 -320 896 -5 -14 ) ( 512 -320 896 -5 -14 ) ) +) + } + } +} diff --git a/docs/developer/TstMaps/ttq3dm3.map b/docs/developer/TstMaps/ttq3dm3.map new file mode 100644 index 00000000..e17645bf --- /dev/null +++ b/docs/developer/TstMaps/ttq3dm3.map @@ -0,0 +1,1099 @@ +{ +"spawnflags" "0" +"classname" "worldspawn" +// brush 0 +{ +brushDef +{ +( 1176 -448 0 ) ( 1160 -448 0 ) ( 1160 -472 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/clip 0 0 0 +( 1160 -472 64 ) ( 1160 -448 64 ) ( 1176 -448 64 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/clip 0 0 0 +( 1160 -472 64 ) ( 1176 -472 64 ) ( 1176 -472 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/clip 0 0 0 +( 1176 -472 64 ) ( 1176 -448 64 ) ( 1176 -448 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/clip 0 0 0 +( 1176 -448 64 ) ( 1160 -448 64 ) ( 1160 -448 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/clip 0 0 0 +( 1152 -448 64 ) ( 1152 -472 64 ) ( 1152 -472 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/clip 0 0 0 +} +} +// brush 1 +{ +brushDef +{ +( 448 -768 8 ) ( 448 -640 8 ) ( 448 -640 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 448 -640 8 ) ( 424 -640 8 ) ( 424 -640 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 416 -640 192 ) ( 416 -704 384 ) ( 448 -672 288 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 386 -448 192 ) ( 322 -192 192 ) ( 354 -320 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 432 -712 384 ) ( 432 -640 320 ) ( 448 -676 352 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 2 +{ +brushDef +{ +( -2432 4784 -768 ) ( -2432 792 -768 ) ( -2432 792 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -296 3136 -768 ) ( -4328 3136 -768 ) ( -4328 3136 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 2432 -1736 -768 ) ( 2432 2256 -768 ) ( 2432 2256 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -1592 -1728 -768 ) ( 2440 -1728 -768 ) ( 2440 -1728 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -248 4944 -960 ) ( -4280 4944 -960 ) ( -4280 952 -960 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -4280 4944 -952 ) ( -248 4944 -952 ) ( -4280 952 -952 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) sfx/pureblack 0 0 0 +} +} +// brush 3 +{ +brushDef +{ +( -2432 4784 -768 ) ( -2432 792 -768 ) ( -2432 792 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -296 3136 -768 ) ( -4328 3136 -768 ) ( -4328 3136 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 2432 -1736 -768 ) ( 2432 2256 -768 ) ( 2432 2256 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -1592 -1728 -768 ) ( 2440 -1728 -768 ) ( 2440 -1728 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -4344 952 1088 ) ( -4344 4944 1088 ) ( -312 4944 1088 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -4344 4944 1080 ) ( -4344 952 1080 ) ( -312 4944 1080 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) sfx/pureblack 0 0 0 +} +} +// brush 4 +{ +brushDef +{ +( -2432 4784 -768 ) ( -2432 792 -768 ) ( -2432 792 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 2432 -1736 -768 ) ( 2432 2256 -768 ) ( 2432 2256 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -1592 -1728 -768 ) ( 2440 -1728 -768 ) ( 2440 -1728 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -4344 952 1088 ) ( -4344 4944 1088 ) ( -312 4944 1088 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -248 4944 -960 ) ( -4280 4944 -960 ) ( -4280 952 -960 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 2440 -1720 -768 ) ( -1592 -1720 -768 ) ( 2440 -1720 -776 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) sfx/pureblack 0 0 0 +} +} +// brush 5 +{ +brushDef +{ +( -296 3136 -768 ) ( -4328 3136 -768 ) ( -4328 3136 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 2432 -1736 -768 ) ( 2432 2256 -768 ) ( 2432 2256 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -1592 -1728 -768 ) ( 2440 -1728 -768 ) ( 2440 -1728 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -4344 952 1088 ) ( -4344 4944 1088 ) ( -312 4944 1088 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -248 4944 -960 ) ( -4280 4944 -960 ) ( -4280 952 -960 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 2424 2256 -768 ) ( 2424 -1736 -768 ) ( 2424 2256 -776 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) sfx/pureblack 0 0 0 +} +} +// brush 6 +{ +brushDef +{ +( -2432 4784 -768 ) ( -2432 792 -768 ) ( -2432 792 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -296 3136 -768 ) ( -4328 3136 -768 ) ( -4328 3136 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 2432 -1736 -768 ) ( 2432 2256 -768 ) ( 2432 2256 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -4344 952 1088 ) ( -4344 4944 1088 ) ( -312 4944 1088 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -248 4944 -960 ) ( -4280 4944 -960 ) ( -4280 952 -960 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -4328 3128 -768 ) ( -296 3128 -768 ) ( -4328 3128 -776 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) sfx/pureblack 0 0 0 +} +} +// brush 7 +{ +brushDef +{ +( -2432 4784 -768 ) ( -2432 792 -768 ) ( -2432 792 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -296 3136 -768 ) ( -4328 3136 -768 ) ( -4328 3136 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -1592 -1728 -768 ) ( 2440 -1728 -768 ) ( 2440 -1728 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -4344 952 1088 ) ( -4344 4944 1088 ) ( -312 4944 1088 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -248 4944 -960 ) ( -4280 4944 -960 ) ( -4280 952 -960 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -2424 792 -768 ) ( -2424 4784 -768 ) ( -2424 792 -776 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) sfx/pureblack 0 0 0 +} +} +// brush 8 +{ +brushDef +{ +( 1176 -448 -256 ) ( 1152 -448 -256 ) ( 1152 -472 -256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1152 -472 0 ) ( 1152 -448 0 ) ( 1176 -448 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1152 -472 0 ) ( 1176 -472 0 ) ( 1176 -472 -256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1176 -472 0 ) ( 1176 -448 0 ) ( 1176 -448 -256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1176 -448 0 ) ( 1152 -448 0 ) ( 1152 -448 -256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1152 -448 0 ) ( 1152 -472 0 ) ( 1152 -472 -256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 9 +{ +brushDef +{ +( 1720 -448 -448 ) ( 1168 -448 -448 ) ( 1168 -472 -448 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1176 -472 0 ) ( 1176 -448 0 ) ( 1728 -448 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1176 -472 0 ) ( 1728 -472 0 ) ( 1728 -472 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1728 -472 0 ) ( 1728 -448 0 ) ( 1728 -448 -776 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1728 -448 0 ) ( 1176 -448 0 ) ( 1176 -448 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1176 -448 0 ) ( 1176 -472 0 ) ( 1176 -472 -776 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 10 +{ +brushDef +{ +( 448 248 -8 ) ( 448 248 0 ) ( 448 -1024 0 ) ( ( 0.031250 0 -50 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 448 -1024 0 ) ( 448 248 0 ) ( 1736 248 0 ) ( ( 0 -0.015625 11 ) ( 0.015625 0 25 ) ) base_floor/concrete 134217728 0 0 +( 1736 248 -256 ) ( 448 248 -256 ) ( 448 -1024 -256 ) ( ( 0 0.031250 22 ) ( -0.031250 0 -50 ) ) common/caulk 134217728 0 0 +( 800 -448 0 ) ( 448 -448 -776 ) ( 1152 -448 -776 ) ( ( 0.031250 0 -29.500002 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 800 -472 520 ) ( 1152 -472 -256 ) ( 448 -472 -256 ) ( ( 0.031250 0 29.499998 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 576 -460 0 ) ( 576 -448 -776 ) ( 576 -472 -776 ) ( ( 0.031250 0 50 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +} +} +// brush 11 +{ +brushDef +{ +( 800 -472 520 ) ( 1152 -472 -256 ) ( 448 -472 -256 ) ( ( 0.031250 0 29.499998 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 800 -448 0 ) ( 448 -448 -776 ) ( 1152 -448 -776 ) ( ( 0.015625 0 -14.750001 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1152 -388 0 ) ( 1152 256 -776 ) ( 1152 -1032 -776 ) ( ( 0.031250 0 50 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1736 248 -256 ) ( 448 248 -256 ) ( 448 -1024 -256 ) ( ( 0 0.031250 22 ) ( -0.031250 0 -50 ) ) common/caulk 134217728 0 0 +( 640 -460 0 ) ( 640 -472 -776 ) ( 640 -448 -776 ) ( ( 0.031250 0 -50 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 640 -460 -12 ) ( 1152 -448 -24 ) ( 1152 -472 0 ) ( ( 0.015625 0 -14.750001 ) ( 0 0.015625 -16.086678 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 12 +{ +brushDef +{ +( 576 -460 0 ) ( 576 -472 -776 ) ( 576 -448 -776 ) ( ( 0.031250 0 -50 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 800 -472 520 ) ( 1152 -472 -256 ) ( 448 -472 -256 ) ( ( 0.031250 0 29.499998 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 800 -448 0 ) ( 448 -448 -776 ) ( 1152 -448 -776 ) ( ( 0.015625 0 -14.750001 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1736 248 -256 ) ( 448 248 -256 ) ( 448 -1024 -256 ) ( ( 0 0.031250 22 ) ( -0.031250 0 -50 ) ) common/caulk 134217728 0 0 +( 448 -1024 0 ) ( 448 248 0 ) ( 1736 248 0 ) ( ( 0 -0.015625 11 ) ( 0.015625 0 25 ) ) base_floor/concrete 134217728 0 0 +( 640 -460 0 ) ( 640 -448 -776 ) ( 640 -472 -776 ) ( ( 0.031250 0 50 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 576 -448 0 ) ( 640 -448 -24 ) ( 640 -472 0 ) ( ( 0.015625 0 -5.032391 ) ( -0.000002 0.015625 -17.199825 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 13 +{ +brushDef +{ +( 1152 128 -776 ) ( 1176 128 -776 ) ( 1164 128 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1176 256 -256 ) ( 1176 -448 -256 ) ( 1176 -96 520 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1152 -448 -776 ) ( 1152 256 -776 ) ( 1152 -96 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1728 256 -256 ) ( 456 256 -256 ) ( 456 -1032 -256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 456 -1032 0 ) ( 456 256 0 ) ( 1728 256 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1176 64 -776 ) ( 1152 64 -776 ) ( 1164 64 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1176 64 0 ) ( 1152 64 -24 ) ( 1152 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 14 +{ +brushDef +{ +( 1176 256 -256 ) ( 1176 -448 -256 ) ( 1176 -96 520 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1152 -448 -776 ) ( 1152 256 -776 ) ( 1152 -96 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1736 -448 -776 ) ( 448 -448 -776 ) ( 1092 -448 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1728 256 -256 ) ( 456 256 -256 ) ( 456 -1032 -256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1152 64 -776 ) ( 1176 64 -776 ) ( 1164 64 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1176 -448 0 ) ( 1152 -448 -24 ) ( 1164 64 -12 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 15 +{ +brushDef +{ +( 1728 256 0 ) ( 456 256 0 ) ( 456 256 -8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 456 -1032 0 ) ( 456 256 0 ) ( 1728 256 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1728 256 -256 ) ( 456 256 -256 ) ( 456 -1032 -256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1152 -448 -776 ) ( 1152 256 -776 ) ( 1152 -96 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1176 256 -256 ) ( 1176 -448 -256 ) ( 1176 -96 520 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1176 128 -776 ) ( 1152 128 -776 ) ( 1164 128 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +} +} +// brush 16 +{ +brushDef +{ +( 1728 256 0 ) ( 456 256 0 ) ( 456 256 -8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1728 -1032 0 ) ( 1728 256 0 ) ( 1728 256 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 456 -1032 0 ) ( 456 256 0 ) ( 1728 256 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1720 256 -448 ) ( 448 256 -448 ) ( 448 -1032 -448 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1736 -448 -776 ) ( 448 -448 -776 ) ( 1092 -448 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1176 -448 -776 ) ( 1176 256 -776 ) ( 1176 -96 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 17 +{ +brushDef +{ +( 448 256 0 ) ( 448 -1032 0 ) ( 448 -1032 -8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1728 256 0 ) ( 456 256 0 ) ( 456 256 -8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 456 -1032 -256 ) ( 456 256 -256 ) ( 1728 256 -256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1712 256 -448 ) ( 440 256 -448 ) ( 440 -1032 -448 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1736 -472 -776 ) ( 448 -472 -776 ) ( 1092 -472 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1176 248 -776 ) ( 1176 -456 -776 ) ( 1176 -104 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 18 +{ +brushDef +{ +( 448 256 328 ) ( 448 -1032 328 ) ( 448 -1032 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1728 -1032 0 ) ( 1728 256 0 ) ( 1728 256 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 456 -1024 0 ) ( 1728 -1024 0 ) ( 1728 -1024 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 456 -1032 0 ) ( 456 256 0 ) ( 1728 256 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1728 256 -448 ) ( 456 256 -448 ) ( 456 -1032 -448 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 -472 -776 ) ( 1736 -472 -776 ) ( 1092 -472 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 19 +{ +brushDef +{ +( 1280 -832 0 ) ( 1280 -520 0 ) ( 1280 -676 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1280 -576 0 ) ( 1536 -576 0 ) ( 1408 -576 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1280 -832 192 ) ( 1544 -832 192 ) ( 1412 -576 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1536 -832 320 ) ( 1280 -832 320 ) ( 1408 -576 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1536 -640 192 ) ( 1280 -640 192 ) ( 1408 -640 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1344 -576 192 ) ( 1344 -648 192 ) ( 1344 -612 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 20 +{ +brushDef +{ +( 1536 -832 704 ) ( 1536 256 704 ) ( 1536 256 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1280 -576 0 ) ( 1536 -576 0 ) ( 1408 -576 704 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1280 -832 192 ) ( 1544 -832 192 ) ( 1412 -576 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1536 -832 320 ) ( 1280 -832 320 ) ( 1408 -576 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1536 -640 192 ) ( 1280 -640 192 ) ( 1408 -640 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1344 -648 192 ) ( 1344 -576 192 ) ( 1344 -612 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 21 +{ +brushDef +{ +( 1280 256 320 ) ( 1344 256 320 ) ( 1344 -576 320 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 32 ) ) common/caulk 134217728 0 0 +( 1280 256 264 ) ( 1280 -576 264 ) ( 1280 -576 256 ) ( ( 0.015625 0 17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1344 -576 264 ) ( 1344 256 264 ) ( 1344 256 256 ) ( ( 0.015625 0 -17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1344 256 264 ) ( 1280 256 264 ) ( 1280 256 256 ) ( ( 0.031250 0 -5.500002 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1280 128 192 ) ( 1280 128 312 ) ( 1344 128 252 ) ( ( 0.031250 0 5.499998 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1280 256 192 ) ( 1280 128 240 ) ( 1344 192 216 ) ( ( 0.031250 0 5.499998 ) ( 0 0.031254 -33.244408 ) ) base_ceiling/metceil1d 134217728 0 0 +} +} +// brush 22 +{ +brushDef +{ +( 1280 256 320 ) ( 1344 256 320 ) ( 1344 -576 320 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 32 ) ) common/caulk 134217728 0 0 +( 1280 256 264 ) ( 1280 -576 264 ) ( 1280 -576 256 ) ( ( 0.015625 0 17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1344 -576 264 ) ( 1344 256 264 ) ( 1344 256 256 ) ( ( 0.015625 0 -17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1280 0 192 ) ( 1280 0 320 ) ( 1344 0 256 ) ( ( 0.031250 0 5.499998 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1280 128 312 ) ( 1280 128 192 ) ( 1344 128 252 ) ( ( 0.031250 0 -5.500002 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1280 128 240 ) ( 1280 0 264 ) ( 1344 64 252 ) ( ( 0.031250 0 5.500037 ) ( 0 0.031250 -34.891960 ) ) base_ceiling/metceil1d 134217728 0 0 +} +} +// brush 23 +{ +brushDef +{ +( 1280 256 320 ) ( 1344 256 320 ) ( 1344 -576 320 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 32 ) ) common/caulk 134217728 0 0 +( 1280 256 264 ) ( 1280 -576 264 ) ( 1280 -576 256 ) ( ( 0.015625 0 17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1344 -576 264 ) ( 1344 256 264 ) ( 1344 256 256 ) ( ( 0.015625 0 -17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1280 -160 192 ) ( 1280 -160 320 ) ( 1344 -160 256 ) ( ( 0.031250 0 5.499998 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1280 0 320 ) ( 1280 0 192 ) ( 1344 0 256 ) ( ( 0.031250 0 -5.500002 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1280 0 264 ) ( 1280 -160 272 ) ( 1344 -80 268 ) ( ( 0.031250 0 5.499999 ) ( 0 0.031246 -35.450680 ) ) base_ceiling/metceil1d 134217728 0 0 +} +} +// brush 24 +{ +brushDef +{ +( 1344 -240 268 ) ( 1280 -160 272 ) ( 1280 -320 264 ) ( ( 0.031250 0 -5.500003 ) ( 0 0.031250 35.455704 ) ) base_ceiling/metceil1d 134217728 0 0 +( 1344 -320 256 ) ( 1280 -320 192 ) ( 1280 -320 320 ) ( ( 0.031250 0 5.499998 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1344 -160 256 ) ( 1280 -160 320 ) ( 1280 -160 192 ) ( ( 0.031250 0 -5.500002 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1344 -576 256 ) ( 1344 -576 264 ) ( 1344 256 264 ) ( ( 0.015625 0 -17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1280 256 256 ) ( 1280 256 264 ) ( 1280 -576 264 ) ( ( 0.015625 0 17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1344 256 320 ) ( 1344 -576 320 ) ( 1280 -576 320 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 23.750000 ) ) common/caulk 134217728 0 0 +} +} +// brush 25 +{ +brushDef +{ +( 1344 -384 252 ) ( 1280 -320 264 ) ( 1280 -448 240 ) ( ( 0.031250 0 -5.500002 ) ( 0 0.031246 34.887020 ) ) base_ceiling/metceil1d 134217728 0 0 +( 1344 -448 252 ) ( 1280 -448 192 ) ( 1280 -448 312 ) ( ( 0.031250 0 5.499998 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1344 -320 256 ) ( 1280 -320 320 ) ( 1280 -320 192 ) ( ( 0.031250 0 -5.500002 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1344 -576 256 ) ( 1344 -576 264 ) ( 1344 256 264 ) ( ( 0.015625 0 -17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1280 256 256 ) ( 1280 256 264 ) ( 1280 -576 264 ) ( ( 0.015625 0 17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1344 256 320 ) ( 1344 -576 320 ) ( 1280 -576 320 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 23.750000 ) ) common/caulk 134217728 0 0 +} +} +// brush 26 +{ +brushDef +{ +( 1344 -512 216 ) ( 1280 -448 240 ) ( 1280 -576 192 ) ( ( 0.031250 0 -5.500002 ) ( 0 0.031254 33.244404 ) ) base_ceiling/metceil1d 134217728 0 0 +( 1344 -448 252 ) ( 1280 -448 312 ) ( 1280 -448 192 ) ( ( 0.031250 0 -5.500002 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1280 -576 256 ) ( 1280 -576 264 ) ( 1344 -576 264 ) ( ( 0.031250 0 5.499998 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1344 -576 256 ) ( 1344 -576 264 ) ( 1344 256 264 ) ( ( 0.015625 0 -17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1280 256 256 ) ( 1280 256 264 ) ( 1280 -576 264 ) ( ( 0.015625 0 17.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1344 256 320 ) ( 1344 -576 320 ) ( 1280 -576 320 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 23.750000 ) ) common/caulk 134217728 0 0 +} +} +// brush 27 +{ +brushDef +{ +( 128 -80 0 ) ( 128 64 0 ) ( 64 64 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -448 -8 ) ( 448 -448 8 ) ( 448 -304 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 -640 192 ) ( 192 -640 192 ) ( 96 -384 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -64 0 ) ( 192 -128 0 ) ( 128 -96 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 384 -440 0 ) ( 320 -184 0 ) ( 352 -312 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 322 -576 0 ) ( 322 -640 192 ) ( 448 -608 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 28 +{ +brushDef +{ +( 1216 -576 216 ) ( 1152 -640 240 ) ( 1280 -640 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) base_ceiling/metceil1d 134217728 0 0 +( 1152 -576 252 ) ( 1152 -640 312 ) ( 1152 -640 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1280 -640 256 ) ( 1280 -640 264 ) ( 1280 -576 264 ) ( ( 0.031250 0 0 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1280 -576 256 ) ( 1280 -576 264 ) ( 448 -576 264 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 448 -640 256 ) ( 448 -640 264 ) ( 1280 -640 264 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 448 -576 320 ) ( 1280 -576 320 ) ( 1280 -640 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 -8.250000 ) ) common/caulk 134217728 0 0 +} +} +// brush 29 +{ +brushDef +{ +( 1088 -576 252 ) ( 1024 -640 264 ) ( 1152 -640 240 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) base_ceiling/metceil1d 134217728 0 0 +( 1152 -576 252 ) ( 1152 -640 192 ) ( 1152 -640 312 ) ( ( 0.031250 0 0 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1024 -576 256 ) ( 1024 -640 320 ) ( 1024 -640 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1280 -576 256 ) ( 1280 -576 264 ) ( 448 -576 264 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 448 -640 256 ) ( 448 -640 264 ) ( 1280 -640 264 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 448 -576 320 ) ( 1280 -576 320 ) ( 1280 -640 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 -8.250000 ) ) common/caulk 134217728 0 0 +} +} +// brush 30 +{ +brushDef +{ +( 944 -576 268 ) ( 864 -640 272 ) ( 1024 -640 264 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) base_ceiling/metceil1d 134217728 0 0 +( 1024 -576 256 ) ( 1024 -640 192 ) ( 1024 -640 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 864 -576 256 ) ( 864 -640 320 ) ( 864 -640 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 4.250000 ) ) common/caulk 134217728 0 0 +( 1280 -576 256 ) ( 1280 -576 264 ) ( 448 -576 264 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 448 -640 256 ) ( 448 -640 264 ) ( 1280 -640 264 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 448 -576 320 ) ( 1280 -576 320 ) ( 1280 -640 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 -8.250000 ) ) common/caulk 134217728 0 0 +} +} +// brush 31 +{ +brushDef +{ +( 448 -640 320 ) ( 448 -576 320 ) ( 1280 -576 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 448 -640 264 ) ( 1280 -640 264 ) ( 1280 -640 256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1280 -576 264 ) ( 448 -576 264 ) ( 448 -576 256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 864 -640 192 ) ( 864 -640 320 ) ( 864 -576 256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 704 -640 320 ) ( 704 -640 192 ) ( 704 -576 256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 704 -640 264 ) ( 864 -640 272 ) ( 784 -576 268 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) base_ceiling/metceil1d 134217728 0 0 +} +} +// brush 32 +{ +brushDef +{ +( 448 -640 320 ) ( 448 -576 320 ) ( 1280 -576 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 448 -640 264 ) ( 1280 -640 264 ) ( 1280 -640 256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1280 -576 264 ) ( 448 -576 264 ) ( 448 -576 256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 704 -640 192 ) ( 704 -640 320 ) ( 704 -576 256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 576 -640 312 ) ( 576 -640 192 ) ( 576 -576 252 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 576 -640 240 ) ( 704 -640 264 ) ( 640 -576 252 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) base_ceiling/metceil1d 134217728 0 0 +} +} +// brush 33 +{ +brushDef +{ +( 448 -640 320 ) ( 448 -576 320 ) ( 1280 -576 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 448 -640 264 ) ( 1280 -640 264 ) ( 1280 -640 256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 1280 -576 264 ) ( 448 -576 264 ) ( 448 -576 256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( 448 -576 264 ) ( 448 -640 264 ) ( 448 -640 256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 576 -640 192 ) ( 576 -640 312 ) ( 576 -576 252 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 448 -640 192 ) ( 576 -640 240 ) ( 512 -576 216 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) base_ceiling/metceil1d 134217728 0 0 +} +} +// brush 34 +{ +brushDef +{ +( 448 -640 0 ) ( 128 -640 0 ) ( 128 -640 256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 -448 -8 ) ( 448 -448 8 ) ( 448 -304 8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 146 -512 256 ) ( 192 -640 0 ) ( 100 -384 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -640 192 ) ( 448 -640 192 ) ( 256 256 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -576 400 ) ( 64 -576 192 ) ( 448 -576 296 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 169 -640 320 ) ( 169 -576 320 ) ( 448 -608 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 35 +{ +brushDef +{ +( 48 64 704 ) ( 112 64 704 ) ( 112 -80 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -640 0 ) ( 128 -640 0 ) ( 128 -640 256 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 -448 -8 ) ( 448 -448 8 ) ( 448 -304 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 146 -512 256 ) ( 192 -640 0 ) ( 100 -384 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -576 400 ) ( 64 -576 192 ) ( 448 -576 296 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 169 -576 320 ) ( 169 -640 320 ) ( 448 -608 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 36 +{ +brushDef +{ +( 48 64 704 ) ( 112 64 704 ) ( 112 -80 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 64 64 -8 ) ( 64 64 8 ) ( 64 -80 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 128 256 -8 ) ( 128 256 8 ) ( 64 256 8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -448 -8 ) ( 448 -448 8 ) ( 448 -304 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -64 256 ) ( 128 -640 256 ) ( 128 -640 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 146 -512 256 ) ( 192 -640 0 ) ( 100 -384 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -640 192 ) ( 448 -640 192 ) ( 256 256 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -576 192 ) ( 64 -576 400 ) ( 448 -576 296 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 37 +{ +brushDef +{ +( 448 -832 704 ) ( 1536 -832 704 ) ( 1536 -832 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1536 -832 704 ) ( 1536 256 704 ) ( 1536 256 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1280 -832 0 ) ( 1280 -520 0 ) ( 1280 -676 704 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1280 -832 192 ) ( 1544 -832 192 ) ( 1412 -576 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1536 -832 320 ) ( 1280 -832 320 ) ( 1408 -576 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1280 -640 192 ) ( 1536 -640 192 ) ( 1408 -640 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 38 +{ +brushDef +{ +( 448 -832 704 ) ( 448 256 704 ) ( 1536 256 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -832 704 ) ( 1536 -832 704 ) ( 1536 -832 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1536 -832 704 ) ( 1536 256 704 ) ( 1536 256 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1280 -832 0 ) ( 1280 -520 0 ) ( 1280 -676 704 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1280 -576 0 ) ( 1536 -576 0 ) ( 1408 -576 704 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1280 -832 320 ) ( 1536 -832 320 ) ( 1408 -576 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 39 +{ +brushDef +{ +( 1536 256 0 ) ( 448 256 0 ) ( 448 -832 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -832 704 ) ( 1536 -832 704 ) ( 1536 -832 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1536 -832 704 ) ( 1536 256 704 ) ( 1536 256 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1280 -832 0 ) ( 1280 -520 0 ) ( 1280 -676 704 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1280 -576 0 ) ( 1536 -576 0 ) ( 1408 -576 704 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1544 -832 192 ) ( 1280 -832 192 ) ( 1412 -576 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 40 +{ +brushDef +{ +( 448 256 704 ) ( 448 -832 704 ) ( 448 -832 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1536 256 704 ) ( 448 256 704 ) ( 448 256 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -832 704 ) ( 448 256 704 ) ( 1536 256 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1536 256 -256 ) ( 448 256 -256 ) ( 448 -832 -256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1280 256 0 ) ( 448 -576 0 ) ( 864 -160 704 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 41 +{ +brushDef +{ +( 1288 -576 0 ) ( 448 -576 0 ) ( 868 -576 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1280 -520 0 ) ( 1280 -832 0 ) ( 1280 -676 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -832 704 ) ( 448 256 704 ) ( 1536 256 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1528 256 320 ) ( 440 256 320 ) ( 440 -832 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) base_ceiling/metceil1d 0 0 0 +( 448 -576 0 ) ( 1280 256 0 ) ( 864 -160 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 42 +{ +brushDef +{ +( 1528 256 320 ) ( 440 256 320 ) ( 440 -832 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -832 704 ) ( 448 256 704 ) ( 1536 256 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -640 704 ) ( 1536 -640 704 ) ( 1536 -640 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 256 704 ) ( 448 -832 704 ) ( 448 -832 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1280 -520 0 ) ( 1280 -832 0 ) ( 1280 -676 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -576 0 ) ( 1288 -576 0 ) ( 868 -576 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 43 +{ +brushDef +{ +( 1560 256 320 ) ( 472 256 320 ) ( 472 -832 320 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -832 704 ) ( 448 256 704 ) ( 1536 256 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1344 -840 704 ) ( 1344 248 704 ) ( 1344 248 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1536 256 704 ) ( 448 256 704 ) ( 448 256 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1280 -832 0 ) ( 1280 -520 0 ) ( 1280 -676 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1536 -576 0 ) ( 1280 -576 0 ) ( 1408 -576 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 44 +{ +brushDef +{ +( 440 768 0 ) ( -64 768 0 ) ( -64 264 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -56 264 192 ) ( -56 768 192 ) ( 448 768 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -72 256 400 ) ( 432 256 400 ) ( 432 256 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 280 400 ) ( -64 784 400 ) ( -64 784 208 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -72 760 400 ) ( -72 256 400 ) ( -72 256 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -72 576 0 ) ( -64 576 0 ) ( -68 576 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 45 +{ +brushDef +{ +( 440 768 0 ) ( -64 768 0 ) ( -64 264 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -56 264 192 ) ( -56 768 192 ) ( 448 768 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 280 400 ) ( -64 784 400 ) ( -64 784 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 440 768 400 ) ( -64 768 400 ) ( -64 768 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -72 760 400 ) ( -72 256 400 ) ( -72 256 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 576 0 ) ( -72 576 0 ) ( -68 576 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 46 +{ +brushDef +{ +( 448 776 0 ) ( -56 776 0 ) ( -56 272 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -48 272 192 ) ( -48 776 192 ) ( 456 776 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 256 768 400 ) ( 760 768 400 ) ( 760 768 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 776 400 ) ( -56 776 400 ) ( -56 776 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 768 400 ) ( -64 264 400 ) ( -64 264 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 128 776 0 ) ( 128 768 0 ) ( 128 772 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 47 +{ +brushDef +{ +( 448 776 0 ) ( -56 776 0 ) ( -56 272 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -48 272 192 ) ( -48 776 192 ) ( 456 776 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 256 768 400 ) ( 760 768 400 ) ( 760 768 208 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 792 400 ) ( 448 1296 400 ) ( 448 1296 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 776 400 ) ( -56 776 400 ) ( -56 776 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 128 768 0 ) ( 128 776 0 ) ( 128 772 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 48 + { + patchDef2 + { + base_floor/concrete + ( 3 3 0 0 0 ) +( +( ( -64 576 0 0 0 ) ( -64 576 96 0 1.500000 ) ( -64 576 192 0 3 ) ) +( ( -64 768 0 3 0 ) ( -64 768 96 3 1.500000 ) ( -64 768 192 3 3 ) ) +( ( 128 768 0 6 0 ) ( 128 768 96 6 1.500000 ) ( 128 768 192 6 3 ) ) +) + } + } +// brush 49 + { + patchDef2 + { + base_floor/concrete + ( 3 3 0 0 0 ) +( +( ( 64 448 192 0 0 ) ( 64 448 96 0 1.500000 ) ( 64 448 0 0 3 ) ) +( ( 64 640 192 3 0 ) ( 64 640 96 3 1.500000 ) ( 64 640 0 3 3 ) ) +( ( 256 640 192 6 0 ) ( 256 640 96 6 1.500000 ) ( 256 640 0 6 3 ) ) +) + } + } +// brush 50 +{ +brushDef +{ +( 264 632 0 ) ( 72 632 0 ) ( 72 440 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 72 440 192 ) ( 72 632 192 ) ( 264 632 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 72 440 192 ) ( 264 440 192 ) ( 264 440 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 264 440 192 ) ( 264 632 192 ) ( 264 632 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 264 632 192 ) ( 72 632 192 ) ( 72 632 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 72 632 192 ) ( 72 440 192 ) ( 72 440 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 72 448 0 ) ( 256 632 0 ) ( 164 540 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 51 +{ +brushDef +{ +( 72 248 0 ) ( 72 752 0 ) ( -432 752 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -432 744 192 ) ( 72 744 192 ) ( 72 240 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 64 480 400 ) ( 64 -24 400 ) ( 64 -24 208 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 88 256 400 ) ( 592 256 400 ) ( 592 256 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 72 248 400 ) ( 72 752 400 ) ( 72 752 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 64 448 400 ) ( -440 448 400 ) ( -440 448 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 52 +{ +brushDef +{ +( 456 640 0 ) ( -48 640 0 ) ( -48 136 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -40 136 192 ) ( -40 640 192 ) ( 464 640 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 264 632 400 ) ( 768 632 400 ) ( 768 632 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 656 400 ) ( 448 1160 400 ) ( 448 1160 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 456 640 400 ) ( -48 640 400 ) ( -48 640 208 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 256 632 400 ) ( 256 128 400 ) ( 256 128 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 53 +{ +brushDef +{ +( 448 768 192 ) ( -56 768 192 ) ( -56 264 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -48 264 200 ) ( -48 768 200 ) ( 456 768 200 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 256 400 ) ( 440 256 400 ) ( 440 256 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 264 400 ) ( 448 768 400 ) ( 448 768 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 768 400 ) ( -56 768 400 ) ( -56 768 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 760 400 ) ( -64 256 400 ) ( -64 256 208 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 54 +{ +brushDef +{ +( 448 768 -8 ) ( -56 768 -8 ) ( -56 264 -8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -48 264 0 ) ( -48 768 0 ) ( 456 768 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -64 256 200 ) ( 440 256 200 ) ( 440 256 8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 264 200 ) ( 448 768 200 ) ( 448 768 8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 768 200 ) ( -56 768 200 ) ( -56 768 8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 760 200 ) ( -64 256 200 ) ( -64 256 8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 55 +{ +brushDef +{ +( 640 960 -8 ) ( 640 872 -8 ) ( 760 872 -8 ) ( ( 0 0.031250 17.750000 ) ( -0.031250 0 32 ) ) common/caulk 0 0 0 +( 760 872 0 ) ( 640 872 0 ) ( 640 960 0 ) ( ( 0 -0.007813 5.503094 ) ( 0.007813 0 -5.500553 ) ) base_floor/concrete 0 0 0 +( 1728 632 0 ) ( 1728 720 0 ) ( 1728 720 -8 ) ( ( 0.031250 0 7 ) ( 0 0.031250 -0.250000 ) ) common/caulk 0 0 0 +( 760 1152 0 ) ( 640 1152 0 ) ( 640 1152 -8 ) ( ( 0.031250 0 168.250000 ) ( 0 0.031250 -0.250000 ) ) common/caulk 0 0 0 +( 448 960 0 ) ( 448 872 0 ) ( 448 872 -8 ) ( ( 0.007813 0 -4.249445 ) ( 0 0.007813 0 ) ) base_floor/concrete 0 0 0 +( 896 256 0 ) ( 1016 256 0 ) ( 1016 256 -8 ) ( ( 0.031250 0 -168.250000 ) ( 0 0.031250 -0.250000 ) ) common/caulk 0 0 0 +} +} +// brush 56 +{ +brushDef +{ +( 448 768 192 ) ( 448 640 192 ) ( 768 640 192 ) ( ( 0 0.015625 11 ) ( -0.015625 0 11 ) ) base_floor/concrete 0 0 0 +( 768 632 704 ) ( 448 632 704 ) ( 448 760 704 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 -22 ) ) common/caulk 0 0 0 +( 768 640 832 ) ( 768 768 832 ) ( 768 768 256 ) ( ( 0.031250 0 17 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 768 768 832 ) ( 448 768 832 ) ( 448 768 256 ) ( ( 0.031250 0 172.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 768 832 ) ( 448 640 832 ) ( 448 640 256 ) ( ( 0.031250 0 -17 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 640 832 ) ( 768 640 832 ) ( 768 640 256 ) ( ( 0.031250 0 -172.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 57 +{ +brushDef +{ +( 1088 624 704 ) ( 768 624 704 ) ( 768 752 704 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 -22 ) ) common/caulk 0 0 0 +( 1088 640 328 ) ( 1088 768 328 ) ( 1088 768 192 ) ( ( 0.015625 0 8.500000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 768 768 328 ) ( 768 640 328 ) ( 768 640 192 ) ( ( 0.031250 0 -17 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1088 604 192 ) ( 768 640 192 ) ( 928 622 704 ) ( ( 0.031250 0 -173.292160 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 768 768 192 ) ( 1088 804 192 ) ( 928 786 704 ) ( ( 0.031250 0 169.518250 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 768 604 296 ) ( 1088 604 296 ) ( 928 804 296 ) ( ( 0 0.031250 22 ) ( -0.031250 0 22 ) ) common/caulk 0 0 0 +} +} +// brush 58 +{ +brushDef +{ +( 768 768 328 ) ( 768 640 328 ) ( 768 640 192 ) ( ( 0.031250 0 -17 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1088 604 192 ) ( 768 640 192 ) ( 928 622 704 ) ( ( 0.031250 0 -173.292160 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 768 768 192 ) ( 1088 804 192 ) ( 928 786 704 ) ( ( 0.031250 0 169.518250 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 768 604 192 ) ( 1088 604 296 ) ( 928 804 244 ) ( ( 0.015625 0 8.500000 ) ( 0 0.015625 82.021614 ) ) base_floor/concrete 134217728 0 0 +( 1088 604 296 ) ( 768 604 296 ) ( 928 804 296 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 -22 ) ) common/caulk 134217728 0 0 +( 832 604 260 ) ( 976 604 260 ) ( 904 804 260 ) ( ( 0 0.015625 11 ) ( -0.015625 0 11 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 59 +{ +brushDef +{ +( 768 768 328 ) ( 768 640 328 ) ( 768 640 192 ) ( ( 0.031250 0 -17 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 1088 604 192 ) ( 768 640 192 ) ( 928 622 704 ) ( ( 0.031250 0 -173.292160 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 768 768 192 ) ( 1088 804 192 ) ( 928 786 704 ) ( ( 0.031250 0 169.518250 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 768 604 192 ) ( 1088 604 296 ) ( 928 804 244 ) ( ( 0.015625 0 8.500000 ) ( 0 0.015625 82.021614 ) ) base_floor/concrete 134217728 0 0 +( 976 604 260 ) ( 832 604 260 ) ( 904 804 260 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 -22 ) ) common/caulk 134217728 0 0 +( 868 616 224 ) ( 868 616 260 ) ( 868 792 242 ) ( ( 0.015625 0 8.500000 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 60 +{ +brushDef +{ +( 440 1152 704 ) ( 440 264 704 ) ( 1720 264 704 ) ( ( 0 0.031250 22 ) ( -0.031250 0 22 ) ) common/caulk 0 0 0 +( 1720 264 832 ) ( 440 264 832 ) ( 440 1152 832 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 -22 ) ) common/caulk 0 0 0 +( 448 248 832 ) ( 448 1136 832 ) ( 448 1136 704 ) ( ( 0.031250 0 17 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1720 1152 832 ) ( 440 1152 832 ) ( 440 1152 704 ) ( ( 0.031250 0 172.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 440 1152 832 ) ( 440 264 832 ) ( 440 264 704 ) ( ( 0.031250 0 -17 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 440 256 832 ) ( 1720 256 832 ) ( 1720 256 704 ) ( ( 0.031250 0 -172.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 61 +{ +brushDef +{ +( 640 752 704 ) ( 640 816 704 ) ( 784 816 704 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 -22 ) ) common/caulk 0 0 0 +( 1344 1152 0 ) ( 1344 832 0 ) ( 1344 832 256 ) ( ( 0.015625 0 8.500000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 640 768 -8 ) ( 640 768 8 ) ( 784 768 8 ) ( ( 0.015625 0 -86.250000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 832 -8 ) ( 448 832 8 ) ( 448 768 8 ) ( ( 0.031250 0 -17 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1152 1152 -8 ) ( 1152 1152 8 ) ( 1008 1152 8 ) ( ( 0.031250 0 172.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 768 768 256 ) ( 1344 832 256 ) ( 1344 832 0 ) ( ( 0.015625 0 -84.783813 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1216 850 256 ) ( 1344 896 0 ) ( 1088 804 0 ) ( ( 0.015625 0 -78.292961 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1344 768 192 ) ( 1344 1152 192 ) ( 448 960 192 ) ( ( 0 0.015625 11 ) ( -0.015625 0 11 ) ) base_floor/concrete 0 0 0 +} +} +// brush 62 +{ +brushDef +{ +( 784 832 0 ) ( 640 832 0 ) ( 640 768 0 ) ( ( 0 0.031250 22 ) ( -0.031250 0 22 ) ) common/caulk 0 0 0 +( 640 768 -8 ) ( 640 768 8 ) ( 784 768 8 ) ( ( 0.015625 0 -86.250000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 832 -8 ) ( 448 832 8 ) ( 448 768 8 ) ( ( 0.031250 0 -17 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1152 1152 -8 ) ( 1152 1152 8 ) ( 1008 1152 8 ) ( ( 0.031250 0 172.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1344 1152 192 ) ( 1344 896 192 ) ( 1088 800 192 ) ( ( 0 -0.015625 11 ) ( 0.015625 0 -11 ) ) base_floor/concrete 0 0 0 +( 768 768 0 ) ( 768 768 192 ) ( 768 1152 96 ) ( ( 0.015625 0 8.500000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 63 +{ +brushDef +{ +( 784 832 0 ) ( 640 832 0 ) ( 640 768 0 ) ( ( 0 0.031250 22 ) ( -0.031250 0 22 ) ) common/caulk 0 0 0 +( 1152 1152 -8 ) ( 1152 1152 8 ) ( 1008 1152 8 ) ( ( 0.031250 0 172.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1344 1152 192 ) ( 1344 896 192 ) ( 1088 800 192 ) ( ( 0 -0.015625 11 ) ( 0.015625 0 -11 ) ) base_floor/concrete 0 0 0 +( 768 768 192 ) ( 768 768 0 ) ( 768 1152 96 ) ( ( 0.015625 0 -8.500000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 832 896 0 ) ( 768 768 0 ) ( 800 832 192 ) ( ( 0.015625 0 -30.969723 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 64 +{ +brushDef +{ +( 784 832 0 ) ( 640 832 0 ) ( 640 768 0 ) ( ( 0 0.031250 22 ) ( -0.031250 0 22 ) ) common/caulk 0 0 0 +( 1344 896 272 ) ( 1344 1152 272 ) ( 1344 1152 0 ) ( ( 0.015625 0 8.500000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1152 1152 -8 ) ( 1152 1152 8 ) ( 1008 1152 8 ) ( ( 0.031250 0 172.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1344 1152 192 ) ( 1344 896 192 ) ( 1088 800 192 ) ( ( 0 -0.015625 11 ) ( 0.015625 0 -11 ) ) base_floor/concrete 0 0 0 +( 768 768 0 ) ( 832 896 0 ) ( 800 832 192 ) ( ( 0.015625 0 30.969532 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1144 1088 0 ) ( 888 1024 0 ) ( 1016 1056 192 ) ( ( 0.015625 0 -81.613266 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 65 +{ +brushDef +{ +( 640 640 0 ) ( 640 576 0 ) ( 784 576 0 ) ( ( 0 0.031250 22 ) ( -0.031250 0 6.500000 ) ) common/caulk 0 0 0 +( 1344 256 0 ) ( 1344 256 272 ) ( 1344 512 272 ) ( ( 0.015625 0 16.250000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1008 256 8 ) ( 1152 256 8 ) ( 1152 256 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1088 608 192 ) ( 1344 512 192 ) ( 1344 256 192 ) ( ( 0 -0.015625 11 ) ( 0.015625 0 -3.250000 ) ) base_floor/concrete 0 0 0 +( 800 576 192 ) ( 832 512 0 ) ( 768 640 0 ) ( ( 0.015625 0 -52.435787 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1016 352 192 ) ( 888 384 0 ) ( 1144 320 0 ) ( ( 0.015625 0 86.160866 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 66 +{ +brushDef +{ +( 640 640 0 ) ( 640 576 0 ) ( 784 576 0 ) ( ( 0 0.031250 22 ) ( -0.031250 0 6.500000 ) ) common/caulk 0 0 0 +( 1008 256 8 ) ( 1152 256 8 ) ( 1152 256 -8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1088 608 192 ) ( 1344 512 192 ) ( 1344 256 192 ) ( ( 0 -0.015625 11 ) ( 0.015625 0 -3.250000 ) ) base_floor/concrete 0 0 0 +( 768 256 96 ) ( 768 640 0 ) ( 768 640 192 ) ( ( 0.015625 0 -16.250000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 800 576 192 ) ( 768 640 0 ) ( 832 512 0 ) ( ( 0.015625 0 52.435787 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 67 +{ +brushDef +{ +( 640 640 0 ) ( 640 576 0 ) ( 784 576 0 ) ( ( 0 0.031250 22 ) ( -0.031250 0 6.500000 ) ) common/caulk 0 0 0 +( 784 640 8 ) ( 640 640 8 ) ( 640 640 -8 ) ( ( 0.015625 0 84.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 640 8 ) ( 448 576 8 ) ( 448 576 -8 ) ( ( 0.031250 0 -32.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1008 256 8 ) ( 1152 256 8 ) ( 1152 256 -8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1088 608 192 ) ( 1344 512 192 ) ( 1344 256 192 ) ( ( 0 -0.015625 11 ) ( 0.015625 0 -3.250000 ) ) base_floor/concrete 0 0 0 +( 768 256 96 ) ( 768 640 192 ) ( 768 640 0 ) ( ( 0.015625 0 16.250000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 68 +{ +brushDef +{ +( 784 592 704 ) ( 640 592 704 ) ( 640 656 704 ) ( ( 0 -0.031250 22 ) ( 0.031250 0 -6.500000 ) ) common/caulk 0 0 0 +( 1344 576 256 ) ( 1344 576 0 ) ( 1344 256 0 ) ( ( 0.015625 0 16.250000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 784 640 8 ) ( 640 640 8 ) ( 640 640 -8 ) ( ( 0.015625 0 84.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 640 8 ) ( 448 576 8 ) ( 448 576 -8 ) ( ( 0.031250 0 -32.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 1008 256 8 ) ( 1152 256 8 ) ( 1152 256 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1344 576 0 ) ( 1344 576 256 ) ( 768 640 256 ) ( ( 0.015625 0 86.026184 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 1088 604 0 ) ( 1344 512 0 ) ( 1216 558 256 ) ( ( 0.015625 0 85.251816 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 448 192 ) ( 1344 256 192 ) ( 1344 640 192 ) ( ( 0 0.015625 11 ) ( -0.015625 0 3.250000 ) ) base_floor/concrete 0 0 0 +} +} +// brush 69 +{ +brushDef +{ +( -112 -80 704 ) ( -112 64 704 ) ( -48 64 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 15.500000 ) ) common/caulk 0 0 0 +( -128 -640 256 ) ( -128 -640 0 ) ( -448 -640 0 ) ( ( 0.015625 0 7.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -64 -80 8 ) ( -64 64 8 ) ( -64 64 -8 ) ( ( 0.015625 0 -1.500000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -64 256 8 ) ( -128 256 8 ) ( -128 256 -8 ) ( ( 0.031250 0 -15.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -448 -304 8 ) ( -448 -448 8 ) ( -448 -448 -8 ) ( ( 0.031250 0 3 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -128 -640 0 ) ( -128 -640 256 ) ( -64 -64 256 ) ( ( 0.015625 0 -0.634981 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -100 -384 0 ) ( -192 -640 0 ) ( -146 -512 256 ) ( ( 0.015625 0 1.209426 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -256 256 192 ) ( -448 -640 192 ) ( -64 -640 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7.750000 ) ) base_floor/concrete 0 0 0 +} +} +// brush 70 +{ +brushDef +{ +( -64 64 0 ) ( -128 64 0 ) ( -128 -80 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 -15.500000 ) ) common/caulk 0 0 0 +( -64 -80 8 ) ( -64 64 8 ) ( -64 64 -8 ) ( ( 0.015625 0 -1.500000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -64 256 8 ) ( -128 256 8 ) ( -128 256 -8 ) ( ( 0.031250 0 -15.500000 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -448 -304 8 ) ( -448 -448 8 ) ( -448 -448 -8 ) ( ( 0.031250 0 3 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -96 -384 192 ) ( -192 -640 192 ) ( -448 -640 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7.750000 ) ) base_floor/concrete 0 0 0 +( -448 -64 96 ) ( -64 -64 192 ) ( -64 -64 0 ) ( ( 0.015625 0 7.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 71 +{ +brushDef +{ +( -64 64 0 ) ( -128 64 0 ) ( -128 -80 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 -15.500000 ) ) common/caulk 0 0 0 +( -448 -304 8 ) ( -448 -448 8 ) ( -448 -448 -8 ) ( ( 0.031250 0 3 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -96 -384 192 ) ( -192 -640 192 ) ( -448 -640 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7.750000 ) ) base_floor/concrete 0 0 0 +( -448 -64 96 ) ( -64 -64 0 ) ( -64 -64 192 ) ( ( 0.015625 0 -7.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -128 -96 192 ) ( -64 -64 0 ) ( -192 -128 0 ) ( ( 0.015625 0 6.260992 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 72 +{ +brushDef +{ +( -64 64 0 ) ( -128 64 0 ) ( -128 -80 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 -15.500000 ) ) common/caulk 0 0 0 +( -448 -640 0 ) ( -448 -640 272 ) ( -192 -640 272 ) ( ( 0.015625 0 7.750000 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -448 -304 8 ) ( -448 -448 8 ) ( -448 -448 -8 ) ( ( 0.031250 0 3 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -96 -384 192 ) ( -192 -640 192 ) ( -448 -640 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7.750000 ) ) base_floor/concrete 0 0 0 +( -128 -96 192 ) ( -192 -128 0 ) ( -64 -64 0 ) ( ( 0.015625 0 -6.260992 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -352 -312 192 ) ( -320 -184 0 ) ( -384 -440 0 ) ( ( 0.015625 0 0.424437 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 73 +{ +brushDef +{ +( 128 -80 0 ) ( 128 64 0 ) ( 64 64 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -448 -8 ) ( 448 -448 8 ) ( 448 -304 8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -640 192 ) ( 192 -640 192 ) ( 96 -384 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -64 192 ) ( 64 -64 0 ) ( 448 -64 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 192 -128 0 ) ( 64 -64 0 ) ( 128 -96 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 74 +{ +brushDef +{ +( 128 -80 0 ) ( 128 64 0 ) ( 64 64 0 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 64 64 -8 ) ( 64 64 8 ) ( 64 -80 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 128 256 -8 ) ( 128 256 8 ) ( 64 256 8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -448 -8 ) ( 448 -448 8 ) ( 448 -304 8 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -640 192 ) ( 192 -640 192 ) ( 96 -384 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -64 0 ) ( 64 -64 192 ) ( 448 -64 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +} +} +// brush 75 +{ +brushDef +{ +( 448 264 704 ) ( -440 264 704 ) ( -440 -1016 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -440 -1016 832 ) ( -440 264 832 ) ( 448 264 832 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -456 256 832 ) ( 432 256 832 ) ( 432 256 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 -1016 832 ) ( 448 264 832 ) ( 448 264 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 448 264 832 ) ( -440 264 832 ) ( -440 264 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -448 264 832 ) ( -448 -1016 832 ) ( -448 -1016 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 76 +{ +brushDef +{ +( 64 -64 328 ) ( -64 -64 328 ) ( -64 -64 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( -100 -384 192 ) ( -64 -64 192 ) ( -82 -224 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 64 -64 192 ) ( 100 -384 192 ) ( 82 -224 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( -100 -64 192 ) ( -100 -384 296 ) ( 100 -224 244 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( -100 -272 260 ) ( -100 -128 260 ) ( 100 -200 260 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( -88 -164 224 ) ( -88 -164 260 ) ( 88 -164 242 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 77 +{ +brushDef +{ +( 64 -64 328 ) ( -64 -64 328 ) ( -64 -64 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( -100 -384 192 ) ( -64 -64 192 ) ( -82 -224 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( 64 -64 192 ) ( 100 -384 192 ) ( 82 -224 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( -100 -64 192 ) ( -100 -384 296 ) ( 100 -224 244 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +( -100 -384 296 ) ( -100 -64 296 ) ( 100 -224 296 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 134217728 0 0 +( -100 -128 260 ) ( -100 -272 260 ) ( 100 -200 260 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 134217728 0 0 +} +} +// brush 78 +{ +brushDef +{ +( -80 -384 704 ) ( -80 -64 704 ) ( 48 -64 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 -384 328 ) ( 64 -384 328 ) ( 64 -384 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 64 -64 328 ) ( -64 -64 328 ) ( -64 -64 192 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -100 -384 192 ) ( -64 -64 192 ) ( -82 -224 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 64 -64 192 ) ( 100 -384 192 ) ( 82 -224 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -100 -64 296 ) ( -100 -384 296 ) ( 100 -224 296 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 79 +{ +brushDef +{ +( 64 256 192 ) ( -64 256 192 ) ( -64 -64 192 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( -72 -64 704 ) ( -72 256 704 ) ( 56 256 704 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 -64 832 ) ( 64 -64 832 ) ( 64 -64 256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 64 -64 832 ) ( 64 256 832 ) ( 64 256 256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( 64 256 832 ) ( -64 256 832 ) ( -64 256 256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +( -64 256 832 ) ( -64 -64 832 ) ( -64 -64 256 ) ( ( 0.031250 0 0 ) ( 0 0.031250 0 ) ) common/caulk 0 0 0 +} +} +// brush 80 +{ +brushDef +{ +( 256 104 -448 ) ( 168 104 -448 ) ( 168 -16 -448 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 168 -56 0 ) ( 168 64 0 ) ( 256 64 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) base_floor/concrete 0 0 0 +( -72 -1024 0 ) ( 16 -1024 0 ) ( 16 -1024 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_floor/concrete 0 0 0 +( 448 -56 328 ) ( 448 64 328 ) ( 448 64 320 ) ( ( 0.031250 0 -4.250000 ) ( 0 0.031250 -0.250000 ) ) common/caulk 0 0 0 +( 256 256 0 ) ( 168 256 0 ) ( 168 256 -8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) base_floor/concrete 0 0 0 +( -448 -192 0 ) ( -448 -312 0 ) ( -448 -312 -8 ) ( ( 0.031250 0 4.250000 ) ( 0 0.031250 -0.250000 ) ) common/caulk 0 0 0 +} +} +} +// entity 1 +{ +"classname" "light" +"light" "600" +"origin" "-320 -832 320" +} +// entity 2 +{ +"origin" "1164 -460 0" +"model" "models/mapobjects/kmlamp1.md3" +"classname" "misc_model" +} +// entity 3 +{ +"classname" "light" +"light" "300" +"origin" "-64 -216 240" +} +// entity 4 +{ +"origin" "64 -216 240" +"light" "300" +"classname" "light" +} +// entity 5 +{ +"origin" "0 -768 24" +"classname" "info_player_deathmatch" +"angle" "270" +} +// entity 6 +{ +"angle" "0" +"origin" "920 640 240" +"light" "300" +"classname" "light" +} +// entity 7 +{ +"angle" "0" +"classname" "light" +"light" "300" +"origin" "920 768 240" +} +// entity 8 +{ +"_color" "1 0.9 0.9" +"origin" "0 512 128" +"light" "200" +"classname" "light" +} +// entity 9 +{ +"classname" "light" +"light" "200" +"origin" "48 656 128" +"_color" "1 0.9 0.9" +} +// entity 10 +{ +"_color" "1 0.9 0.9" +"origin" "192 704 128" +"light" "200" +"classname" "light" +} +// entity 11 +{ +"classname" "light" +"light" "200" +"origin" "0 384 128" +"_color" "1 0.9 0.9" +} +// entity 12 +{ +"_color" "1 0.9 0.9" +"origin" "0 256 128" +"light" "200" +"classname" "light" +} +// entity 13 +{ +"classname" "light" +"light" "200" +"origin" "320 704 128" +"_color" "1 0.9 0.9" +} +// entity 14 +{ +"_color" "1 0.9 0.9" +"origin" "448 704 128" +"light" "200" +"classname" "light" +} +// entity 15 +{ +"origin" "64 -832 320" +"light" "600" +"classname" "light" +} +// entity 16 +{ +"classname" "light" +"light" "600" +"origin" "448 -832 320" +} +// entity 17 +{ +"origin" "832 -832 320" +"light" "600" +"classname" "light" +} +// entity 18 +{ +"classname" "light" +"light" "600" +"origin" "1408 -1088 256" +} diff --git a/docs/developer/TstMaps/western.map b/docs/developer/TstMaps/western.map new file mode 100644 index 00000000..2141709e --- /dev/null +++ b/docs/developer/TstMaps/western.map @@ -0,0 +1,5062 @@ +{ +"classname" "worldspawn" +// brush 0 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -760 872 -8 ) ( -760 1200 -8 ) ( -760 872 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +} +} +// brush 1 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 1200 -8 ) ( -8 1200 -8 ) ( -384 1200 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +} +} +// brush 2 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1272 -320 -8 ) ( 1272 -648 -8 ) ( 1272 -320 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +} +} +// brush 3 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +( 1016 -640 -8 ) ( 640 -640 -8 ) ( 1016 -640 -56 ) ( ( 0.062500 0 0 ) ( 0 0.062500 0 ) ) common/invisible 0 0 0 +} +} +// brush 4 +{ +brushDef +{ +( -384 888 896 ) ( -384 1216 896 ) ( -8 1216 896 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +( -384 1216 888 ) ( -384 888 888 ) ( -8 1216 888 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) skies/mkc_sky 0 0 0 +} +} +// brush 5 +{ +brushDef +{ +( -8 1208 -56 ) ( -384 1208 -56 ) ( -384 880 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( 640 -648 -8 ) ( 1016 -648 -8 ) ( 1016 -648 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( 1280 -648 -8 ) ( 1280 -320 -8 ) ( 1280 -320 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( -8 1208 -8 ) ( -384 1208 -8 ) ( -384 1208 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( -768 1200 -8 ) ( -768 872 -8 ) ( -768 872 -56 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +( -384 1208 -48 ) ( -8 1208 -48 ) ( -384 880 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_floor/metalbridge06 0 0 0 +} +} +// brush 6 +{ +brushDef +{ +( 392 0 280 ) ( 128 0 280 ) ( 128 -8 280 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -8 328 ) ( 128 0 328 ) ( 392 0 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 120 -8 304 ) ( 384 -8 304 ) ( 384 -8 296 ) ( ( 0.003906 0 -0.500000 ) ( 0 0.020833 6.833333 ) ) clan_xb/logo7 0 0 0 +( 384 -8 304 ) ( 384 0 304 ) ( 384 0 296 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 392 0 304 ) ( 128 0 304 ) ( 128 0 296 ) ( ( 0.003906 0 1.500000 ) ( 0 0.020833 6.833333 ) ) clan_xb/logo7 0 0 0 +( 128 0 304 ) ( 128 -8 304 ) ( 128 -8 296 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 7 +{ +brushDef +{ +( 320 192 296 ) ( 192 192 296 ) ( 192 176 296 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 168 304 ) ( 192 184 304 ) ( 320 184 304 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 168 304 ) ( 320 168 304 ) ( 320 168 280 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 168 304 ) ( 320 184 304 ) ( 320 184 280 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 184 304 ) ( 192 184 304 ) ( 192 184 280 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 184 304 ) ( 192 168 304 ) ( 192 168 280 ) ( ( 0.007813 0 0.250016 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 8 +{ +brushDef +{ +( 320 168 296 ) ( 192 168 296 ) ( 192 152 296 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 152 312 ) ( 192 168 312 ) ( 320 168 312 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 152 312 ) ( 320 152 312 ) ( 320 152 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 152 312 ) ( 320 168 312 ) ( 320 168 288 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 168 312 ) ( 192 168 312 ) ( 192 168 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 168 312 ) ( 192 152 312 ) ( 192 152 288 ) ( ( 0.007813 0 0.125008 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 9 +{ +brushDef +{ +( 320 152 296 ) ( 192 152 296 ) ( 192 136 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 136 320 ) ( 192 152 320 ) ( 320 152 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 136 320 ) ( 320 136 320 ) ( 320 136 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 136 320 ) ( 320 152 320 ) ( 320 152 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 152 320 ) ( 192 152 320 ) ( 192 152 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 152 320 ) ( 192 136 320 ) ( 192 136 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 10 +{ +brushDef +{ +( 320 200 296 ) ( 192 200 296 ) ( 192 184 296 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 184 304 ) ( 192 200 304 ) ( 320 200 304 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 184 304 ) ( 320 184 304 ) ( 320 184 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 184 304 ) ( 320 200 304 ) ( 320 200 296 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 200 304 ) ( 192 200 304 ) ( 192 200 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 200 304 ) ( 192 184 304 ) ( 192 184 296 ) ( ( 0.007813 0 0.375024 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 11 +{ +brushDef +{ +( 320 184 304 ) ( 192 184 304 ) ( 192 168 304 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 168 312 ) ( 192 184 312 ) ( 320 184 312 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 168 312 ) ( 320 168 312 ) ( 320 168 304 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 168 312 ) ( 320 184 312 ) ( 320 184 304 ) ( ( 0.007813 0 -0.250016 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 184 312 ) ( 192 184 312 ) ( 192 184 304 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 184 312 ) ( 192 168 312 ) ( 192 168 304 ) ( ( 0.007813 0 0.250016 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 12 +{ +brushDef +{ +( 320 168 312 ) ( 192 168 312 ) ( 192 152 312 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 152 320 ) ( 192 168 320 ) ( 320 168 320 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 152 320 ) ( 320 152 320 ) ( 320 152 312 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 152 320 ) ( 320 168 320 ) ( 320 168 312 ) ( ( 0.007813 0 -0.125008 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 168 320 ) ( 192 168 320 ) ( 192 168 312 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 168 320 ) ( 192 152 320 ) ( 192 152 312 ) ( ( 0.007813 0 0.125008 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 13 +{ +brushDef +{ +( 320 152 320 ) ( 192 152 320 ) ( 192 136 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 136 328 ) ( 192 152 328 ) ( 320 152 328 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 136 328 ) ( 320 136 328 ) ( 320 136 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 136 328 ) ( 320 152 328 ) ( 320 152 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 320 152 328 ) ( 192 152 328 ) ( 192 152 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 192 152 328 ) ( 192 136 328 ) ( 192 136 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 14 +{ +brushDef +{ +( -40 136 376 ) ( -48 136 376 ) ( -48 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -48 128 392 ) ( -40 128 392 ) ( -40 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -40 128 392 ) ( -40 136 392 ) ( -40 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -40 136 392 ) ( -48 136 392 ) ( -48 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -48 136 392 ) ( -48 128 392 ) ( -48 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -8 128 424 ) ( -8 136 424 ) ( 0 128 424 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 15 +{ +brushDef +{ +( -40 128 480 ) ( -40 136 480 ) ( -32 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -48 128 392 ) ( -40 128 392 ) ( -40 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -40 128 392 ) ( -40 136 392 ) ( -40 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -40 136 392 ) ( -48 136 392 ) ( -48 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -48 136 392 ) ( -48 128 392 ) ( -48 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -8 136 432 ) ( -8 128 432 ) ( 0 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 16 +{ +brushDef +{ +( 8 136 432 ) ( 8 136 424 ) ( 8 128 424 ) ( ( -0.015625 0 0.250000 ) ( 0 -0.015625 -5.875000 ) ) gothic_trim/wood2 0 0 0 +( -96 128 432 ) ( -96 136 432 ) ( -96 136 440 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 5.875000 ) ) gothic_trim/wood2 0 0 0 +( -8 128 424 ) ( -8 128 432 ) ( 0 128 432 ) ( ( 0 0.015625 5.875000 ) ( -0.015625 0 -7.250001 ) ) gothic_trim/wood2 0 0 0 +( -8 128 432 ) ( -8 136 432 ) ( 0 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 11.500000 ) ) gothic_trim/wood2 0 0 0 +( -8 136 432 ) ( -8 136 424 ) ( 0 136 424 ) ( ( 0 -0.015625 -5.875000 ) ( 0.015625 0 -7.250000 ) ) gothic_trim/wood2 0 0 0 +( -8 136 424 ) ( -8 128 424 ) ( 0 128 424 ) ( ( -0.015625 0 0 ) ( 0 -0.015625 11.500000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 17 +{ +brushDef +{ +( 112 136 376 ) ( 104 136 376 ) ( 104 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 104 128 392 ) ( 112 128 392 ) ( 112 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 112 128 392 ) ( 112 136 392 ) ( 112 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 112 136 392 ) ( 104 136 392 ) ( 104 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 104 136 392 ) ( 104 128 392 ) ( 104 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 144 128 424 ) ( 144 136 424 ) ( 152 128 424 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 18 +{ +brushDef +{ +( 112 128 480 ) ( 112 136 480 ) ( 120 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 104 128 392 ) ( 112 128 392 ) ( 112 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 112 128 392 ) ( 112 136 392 ) ( 112 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 112 136 392 ) ( 104 136 392 ) ( 104 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 104 136 392 ) ( 104 128 392 ) ( 104 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 144 136 432 ) ( 144 128 432 ) ( 152 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 19 +{ +brushDef +{ +( 160 136 432 ) ( 160 136 424 ) ( 160 128 424 ) ( ( -0.015625 0 0.250000 ) ( 0 -0.015625 -5.875000 ) ) gothic_trim/wood2 0 0 0 +( 56 128 432 ) ( 56 136 432 ) ( 56 136 440 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 5.875000 ) ) gothic_trim/wood2 0 0 0 +( 144 128 424 ) ( 144 128 432 ) ( 152 128 432 ) ( ( 0 0.015625 5.875000 ) ( -0.015625 0 -4.875001 ) ) gothic_trim/wood2 0 0 0 +( 144 128 432 ) ( 144 136 432 ) ( 152 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.125000 ) ) gothic_trim/wood2 0 0 0 +( 144 136 432 ) ( 144 136 424 ) ( 152 136 424 ) ( ( 0 -0.015625 -5.875000 ) ( 0.015625 0 -4.875000 ) ) gothic_trim/wood2 0 0 0 +( 144 136 424 ) ( 144 128 424 ) ( 152 128 424 ) ( ( -0.015625 0 0 ) ( 0 -0.015625 9.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 20 +{ +brushDef +{ +( 408 136 376 ) ( 400 136 376 ) ( 400 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 128 392 ) ( 408 128 392 ) ( 408 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 128 392 ) ( 408 136 392 ) ( 408 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 136 392 ) ( 400 136 392 ) ( 400 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 136 392 ) ( 400 128 392 ) ( 400 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 128 424 ) ( 440 136 424 ) ( 448 128 424 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 21 +{ +brushDef +{ +( 408 128 480 ) ( 408 136 480 ) ( 416 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 128 392 ) ( 408 128 392 ) ( 408 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 128 392 ) ( 408 136 392 ) ( 408 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 136 392 ) ( 400 136 392 ) ( 400 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 136 392 ) ( 400 128 392 ) ( 400 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 136 432 ) ( 440 128 432 ) ( 448 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 22 +{ +brushDef +{ +( 456 136 432 ) ( 456 136 424 ) ( 456 128 424 ) ( ( -0.015625 0 0.250000 ) ( 0 -0.015625 -5.875000 ) ) gothic_trim/wood2 0 0 0 +( 352 128 432 ) ( 352 136 432 ) ( 352 136 440 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 5.875000 ) ) gothic_trim/wood2 0 0 0 +( 440 128 424 ) ( 440 128 432 ) ( 448 128 432 ) ( ( 0 0.015625 5.875000 ) ( -0.015625 0 -0.250000 ) ) gothic_trim/wood2 0 0 0 +( 440 128 432 ) ( 440 136 432 ) ( 448 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 4.500000 ) ) gothic_trim/wood2 0 0 0 +( 440 136 432 ) ( 440 136 424 ) ( 448 136 424 ) ( ( 0 -0.015625 -5.875000 ) ( 0.015625 0 -0.250000 ) ) gothic_trim/wood2 0 0 0 +( 440 136 424 ) ( 440 128 424 ) ( 448 128 424 ) ( ( -0.015625 0 0 ) ( 0 -0.015625 4.500000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 23 +{ +brushDef +{ +( 560 136 376 ) ( 552 136 376 ) ( 552 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 552 128 392 ) ( 560 128 392 ) ( 560 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 560 128 392 ) ( 560 136 392 ) ( 560 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 560 136 392 ) ( 552 136 392 ) ( 552 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 552 136 392 ) ( 552 128 392 ) ( 552 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 592 128 424 ) ( 592 136 424 ) ( 600 128 424 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 24 +{ +brushDef +{ +( 560 128 480 ) ( 560 136 480 ) ( 568 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 552 128 392 ) ( 560 128 392 ) ( 560 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 560 128 392 ) ( 560 136 392 ) ( 560 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 560 136 392 ) ( 552 136 392 ) ( 552 136 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 552 136 392 ) ( 552 128 392 ) ( 552 128 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 592 136 432 ) ( 592 128 432 ) ( 600 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 25 +{ +brushDef +{ +( 608 136 432 ) ( 608 136 424 ) ( 608 128 424 ) ( ( -0.015625 0 0.250000 ) ( 0 -0.015625 -5.875000 ) ) gothic_trim/wood2 0 0 0 +( 504 128 432 ) ( 504 136 432 ) ( 504 136 440 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 5.875000 ) ) gothic_trim/wood2 0 0 0 +( 592 128 424 ) ( 592 128 432 ) ( 600 128 432 ) ( ( 0 0.015625 5.875000 ) ( -0.015625 0 2.125000 ) ) gothic_trim/wood2 0 0 0 +( 592 128 432 ) ( 592 136 432 ) ( 600 136 432 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.125000 ) ) gothic_trim/wood2 0 0 0 +( 592 136 432 ) ( 592 136 424 ) ( 600 136 424 ) ( ( 0 -0.015625 -5.875000 ) ( 0.015625 0 2.125000 ) ) gothic_trim/wood2 0 0 0 +( 592 136 424 ) ( 592 128 424 ) ( 600 128 424 ) ( ( -0.015625 0 0 ) ( 0 -0.015625 2.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 26 +{ +brushDef +{ +( 632 0 384 ) ( 632 8 384 ) ( 504 8 384 ) ( ( 0 0.015625 9.875000 ) ( -0.015625 0 2.125000 ) ) gothic_trim/wood2 0 0 0 +( 504 8 392 ) ( 632 8 392 ) ( 632 0 392 ) ( ( 0 -0.015625 9.875000 ) ( 0.015625 0 -2.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 8 392 ) ( -120 0 392 ) ( -120 0 336 ) ( ( 0.015625 0 -4.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 504 0 392 ) ( 632 0 392 ) ( 632 0 336 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 632 0 392 ) ( 632 8 392 ) ( 632 8 336 ) ( ( 0.015625 0 4.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 8 8 392 ) ( -120 8 392 ) ( -120 8 336 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 27 +{ +brushDef +{ +( 640 128 384 ) ( 632 128 384 ) ( 632 0 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 0 392 ) ( 632 128 392 ) ( 640 128 392 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 0 392 ) ( 640 0 392 ) ( 640 0 336 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 0 392 ) ( 640 128 392 ) ( 640 128 336 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 128 392 ) ( 632 128 392 ) ( 632 128 336 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 632 128 392 ) ( 632 0 392 ) ( 632 0 336 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 28 +{ +brushDef +{ +( -120 128 384 ) ( -128 128 384 ) ( -128 0 384 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 0 392 ) ( -128 128 392 ) ( -120 128 392 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 0 392 ) ( -120 0 392 ) ( -120 0 336 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 0 392 ) ( -120 128 392 ) ( -120 128 336 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 128 392 ) ( -128 128 392 ) ( -128 128 336 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -128 128 392 ) ( -128 0 392 ) ( -128 0 336 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 29 +{ +brushDef +{ +( 648 104 328 ) ( 632 104 328 ) ( 632 96 328 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 96 384 ) ( 632 104 384 ) ( 648 104 384 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 88 336 ) ( 648 88 336 ) ( 648 88 328 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 80 336 ) ( 640 88 336 ) ( 640 88 328 ) ( ( 0.015625 0 0.250000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 648 96 336 ) ( 632 96 336 ) ( 632 96 328 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 632 104 336 ) ( 632 96 336 ) ( 632 96 328 ) ( ( 0.015625 0 -0.250000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 30 +{ +brushDef +{ +( 648 48 328 ) ( 632 48 328 ) ( 632 40 328 ) ( ( 0.015625 0 1.125000 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 40 384 ) ( 632 48 384 ) ( 648 48 384 ) ( ( 0.015625 0 1.125000 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 32 336 ) ( 648 32 336 ) ( 648 32 328 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 24 336 ) ( 640 32 336 ) ( 640 32 328 ) ( ( 0.015625 0 1.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 648 40 336 ) ( 632 40 336 ) ( 632 40 328 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 632 48 336 ) ( 632 40 336 ) ( 632 40 328 ) ( ( 0.015625 0 -1.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 31 +{ +brushDef +{ +( 616 16 328 ) ( 600 16 328 ) ( 600 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 11.375000 ) ) gothic_trim/wood2 0 0 0 +( 600 8 384 ) ( 600 16 384 ) ( 616 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -11.375000 ) ) gothic_trim/wood2 0 0 0 +( 600 0 336 ) ( 616 0 336 ) ( 616 0 328 ) ( ( 0.015625 0 -11.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 608 -8 336 ) ( 608 0 336 ) ( 608 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 616 8 336 ) ( 600 8 336 ) ( 600 8 328 ) ( ( 0.015625 0 11.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 600 16 336 ) ( 600 8 336 ) ( 600 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 32 +{ +brushDef +{ +( 552 16 328 ) ( 536 16 328 ) ( 536 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 10.375000 ) ) gothic_trim/wood2 0 0 0 +( 536 8 384 ) ( 536 16 384 ) ( 552 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -10.375000 ) ) gothic_trim/wood2 0 0 0 +( 536 0 336 ) ( 552 0 336 ) ( 552 0 328 ) ( ( 0.015625 0 -10.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 544 -8 336 ) ( 544 0 336 ) ( 544 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 552 8 336 ) ( 536 8 336 ) ( 536 8 328 ) ( ( 0.015625 0 10.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 536 16 336 ) ( 536 8 336 ) ( 536 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 33 +{ +brushDef +{ +( 488 16 328 ) ( 472 16 328 ) ( 472 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 9.375000 ) ) gothic_trim/wood2 0 0 0 +( 472 8 384 ) ( 472 16 384 ) ( 488 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -9.375000 ) ) gothic_trim/wood2 0 0 0 +( 472 0 336 ) ( 488 0 336 ) ( 488 0 328 ) ( ( 0.015625 0 -9.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 480 -8 336 ) ( 480 0 336 ) ( 480 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 488 8 336 ) ( 472 8 336 ) ( 472 8 328 ) ( ( 0.015625 0 9.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 472 16 336 ) ( 472 8 336 ) ( 472 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 34 +{ +brushDef +{ +( 424 16 328 ) ( 408 16 328 ) ( 408 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 8.375000 ) ) gothic_trim/wood2 0 0 0 +( 408 8 384 ) ( 408 16 384 ) ( 424 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -8.375000 ) ) gothic_trim/wood2 0 0 0 +( 408 0 336 ) ( 424 0 336 ) ( 424 0 328 ) ( ( 0.015625 0 -8.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 416 -8 336 ) ( 416 0 336 ) ( 416 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 424 8 336 ) ( 408 8 336 ) ( 408 8 328 ) ( ( 0.015625 0 8.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 408 16 336 ) ( 408 8 336 ) ( 408 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 35 +{ +brushDef +{ +( 360 16 328 ) ( 344 16 328 ) ( 344 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 7.375000 ) ) gothic_trim/wood2 0 0 0 +( 344 8 384 ) ( 344 16 384 ) ( 360 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -7.375000 ) ) gothic_trim/wood2 0 0 0 +( 344 0 336 ) ( 360 0 336 ) ( 360 0 328 ) ( ( 0.015625 0 -7.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 352 -8 336 ) ( 352 0 336 ) ( 352 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 360 8 336 ) ( 344 8 336 ) ( 344 8 328 ) ( ( 0.015625 0 7.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 344 16 336 ) ( 344 8 336 ) ( 344 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 36 +{ +brushDef +{ +( 296 16 328 ) ( 280 16 328 ) ( 280 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 6.375000 ) ) gothic_trim/wood2 0 0 0 +( 280 8 384 ) ( 280 16 384 ) ( 296 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -6.375000 ) ) gothic_trim/wood2 0 0 0 +( 280 0 336 ) ( 296 0 336 ) ( 296 0 328 ) ( ( 0.015625 0 -6.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 288 -8 336 ) ( 288 0 336 ) ( 288 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 296 8 336 ) ( 280 8 336 ) ( 280 8 328 ) ( ( 0.015625 0 6.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 280 16 336 ) ( 280 8 336 ) ( 280 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 37 +{ +brushDef +{ +( 240 16 328 ) ( 224 16 328 ) ( 224 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 5.500000 ) ) gothic_trim/wood2 0 0 0 +( 224 8 384 ) ( 224 16 384 ) ( 240 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -5.500000 ) ) gothic_trim/wood2 0 0 0 +( 224 0 336 ) ( 240 0 336 ) ( 240 0 328 ) ( ( 0.015625 0 -5.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 232 -8 336 ) ( 232 0 336 ) ( 232 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 240 8 336 ) ( 224 8 336 ) ( 224 8 328 ) ( ( 0.015625 0 5.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 224 16 336 ) ( 224 8 336 ) ( 224 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 38 +{ +brushDef +{ +( 264 16 328 ) ( 248 16 328 ) ( 248 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 5.875000 ) ) gothic_trim/wood2 0 0 0 +( 248 8 384 ) ( 248 16 384 ) ( 264 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -5.875000 ) ) gothic_trim/wood2 0 0 0 +( 248 0 336 ) ( 264 0 336 ) ( 264 0 328 ) ( ( 0.015625 0 -5.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 264 -8 336 ) ( 264 0 336 ) ( 264 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 264 8 336 ) ( 248 8 336 ) ( 248 8 328 ) ( ( 0.015625 0 5.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 248 16 336 ) ( 248 8 336 ) ( 248 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 39 +{ +brushDef +{ +( 176 16 328 ) ( 160 16 328 ) ( 160 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 4.500000 ) ) gothic_trim/wood2 0 0 0 +( 160 8 384 ) ( 160 16 384 ) ( 176 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -4.500000 ) ) gothic_trim/wood2 0 0 0 +( 160 0 336 ) ( 176 0 336 ) ( 176 0 328 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 168 -8 336 ) ( 168 0 336 ) ( 168 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 176 8 336 ) ( 160 8 336 ) ( 160 8 328 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 160 16 336 ) ( 160 8 336 ) ( 160 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 40 +{ +brushDef +{ +( 112 16 328 ) ( 96 16 328 ) ( 96 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 3.500000 ) ) gothic_trim/wood2 0 0 0 +( 96 8 384 ) ( 96 16 384 ) ( 112 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -3.500000 ) ) gothic_trim/wood2 0 0 0 +( 96 0 336 ) ( 112 0 336 ) ( 112 0 328 ) ( ( 0.015625 0 -3.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 104 -8 336 ) ( 104 0 336 ) ( 104 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 112 8 336 ) ( 96 8 336 ) ( 96 8 328 ) ( ( 0.015625 0 3.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 96 16 336 ) ( 96 8 336 ) ( 96 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 41 +{ +brushDef +{ +( 48 16 328 ) ( 32 16 328 ) ( 32 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 2.500000 ) ) gothic_trim/wood2 0 0 0 +( 32 8 384 ) ( 32 16 384 ) ( 48 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -2.500000 ) ) gothic_trim/wood2 0 0 0 +( 32 0 336 ) ( 48 0 336 ) ( 48 0 328 ) ( ( 0.015625 0 -2.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 40 -8 336 ) ( 40 0 336 ) ( 40 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 48 8 336 ) ( 32 8 336 ) ( 32 8 328 ) ( ( 0.015625 0 2.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 32 16 336 ) ( 32 8 336 ) ( 32 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 42 +{ +brushDef +{ +( -16 16 328 ) ( -32 16 328 ) ( -32 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 1.500000 ) ) gothic_trim/wood2 0 0 0 +( -32 8 384 ) ( -32 16 384 ) ( -16 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -1.500000 ) ) gothic_trim/wood2 0 0 0 +( -32 0 336 ) ( -16 0 336 ) ( -16 0 328 ) ( ( 0.015625 0 -1.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -24 -8 336 ) ( -24 0 336 ) ( -24 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -16 8 336 ) ( -32 8 336 ) ( -32 8 328 ) ( ( 0.015625 0 1.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -32 16 336 ) ( -32 8 336 ) ( -32 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 43 +{ +brushDef +{ +( -80 16 328 ) ( -96 16 328 ) ( -96 8 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.500000 ) ) gothic_trim/wood2 0 0 0 +( -96 8 384 ) ( -96 16 384 ) ( -80 16 384 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 -0.500000 ) ) gothic_trim/wood2 0 0 0 +( -96 0 336 ) ( -80 0 336 ) ( -80 0 328 ) ( ( 0.015625 0 -0.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -88 -8 336 ) ( -88 0 336 ) ( -88 0 328 ) ( ( 0.015625 0 1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -80 8 336 ) ( -96 8 336 ) ( -96 8 328 ) ( ( 0.015625 0 0.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -96 16 336 ) ( -96 8 336 ) ( -96 8 328 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 44 +{ +brushDef +{ +( -112 72 328 ) ( -128 72 328 ) ( -128 64 328 ) ( ( 0.015625 0 0.750000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 64 384 ) ( -128 72 384 ) ( -112 72 384 ) ( ( 0.015625 0 0.750000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 56 336 ) ( -112 56 336 ) ( -112 56 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 56 336 ) ( -120 64 336 ) ( -120 64 328 ) ( ( 0.015625 0 0.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -112 72 336 ) ( -128 72 336 ) ( -128 72 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -128 72 336 ) ( -128 64 336 ) ( -128 64 328 ) ( ( 0.015625 0 -0.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 45 +{ +brushDef +{ +( 648 72 328 ) ( 632 72 328 ) ( 632 64 328 ) ( ( 0.015625 0 0.750000 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 64 384 ) ( 632 72 384 ) ( 648 72 384 ) ( ( 0.015625 0 0.750000 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 56 336 ) ( 648 56 336 ) ( 648 56 328 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 56 336 ) ( 640 64 336 ) ( 640 64 328 ) ( ( 0.015625 0 0.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 648 72 336 ) ( 632 72 336 ) ( 632 72 328 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 632 72 336 ) ( 632 64 336 ) ( 632 64 328 ) ( ( 0.015625 0 -0.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 46 +{ +brushDef +{ +( 648 128 328 ) ( 632 128 328 ) ( 632 120 328 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 120 384 ) ( 632 128 384 ) ( 648 128 384 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 120 336 ) ( 648 120 336 ) ( 648 120 328 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 120 336 ) ( 640 128 336 ) ( 640 128 328 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 648 128 336 ) ( 632 128 336 ) ( 632 128 328 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 632 128 336 ) ( 632 120 336 ) ( 632 120 328 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 47 +{ +brushDef +{ +( 648 8 328 ) ( 632 8 328 ) ( 632 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 0 384 ) ( 632 8 384 ) ( 648 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 0 336 ) ( 648 0 336 ) ( 648 0 328 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 0 336 ) ( 640 8 336 ) ( 640 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 648 8 336 ) ( 632 8 336 ) ( 632 8 328 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 632 8 336 ) ( 632 0 336 ) ( 632 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 48 +{ +brushDef +{ +( 584 8 328 ) ( 568 8 328 ) ( 568 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 10.875000 ) ) gothic_trim/wood2 0 0 0 +( 568 0 384 ) ( 568 8 384 ) ( 584 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -10.875000 ) ) gothic_trim/wood2 0 0 0 +( 568 0 336 ) ( 584 0 336 ) ( 584 0 328 ) ( ( 0.015625 0 -10.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 576 0 336 ) ( 576 8 336 ) ( 576 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 584 8 336 ) ( 568 8 336 ) ( 568 8 328 ) ( ( 0.015625 0 10.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 568 8 336 ) ( 568 0 336 ) ( 568 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 49 +{ +brushDef +{ +( 520 8 328 ) ( 504 8 328 ) ( 504 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 9.875000 ) ) gothic_trim/wood2 0 0 0 +( 504 0 384 ) ( 504 8 384 ) ( 520 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -9.875000 ) ) gothic_trim/wood2 0 0 0 +( 504 0 336 ) ( 520 0 336 ) ( 520 0 328 ) ( ( 0.015625 0 -9.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 512 0 336 ) ( 512 8 336 ) ( 512 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 520 8 336 ) ( 504 8 336 ) ( 504 8 328 ) ( ( 0.015625 0 9.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 504 8 336 ) ( 504 0 336 ) ( 504 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 50 +{ +brushDef +{ +( 456 8 328 ) ( 440 8 328 ) ( 440 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 8.875000 ) ) gothic_trim/wood2 0 0 0 +( 440 0 384 ) ( 440 8 384 ) ( 456 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -8.875000 ) ) gothic_trim/wood2 0 0 0 +( 440 0 336 ) ( 456 0 336 ) ( 456 0 328 ) ( ( 0.015625 0 -8.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 448 0 336 ) ( 448 8 336 ) ( 448 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 456 8 336 ) ( 440 8 336 ) ( 440 8 328 ) ( ( 0.015625 0 8.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 440 8 336 ) ( 440 0 336 ) ( 440 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 51 +{ +brushDef +{ +( 392 8 328 ) ( 376 8 328 ) ( 376 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 7.875000 ) ) gothic_trim/wood2 0 0 0 +( 376 0 384 ) ( 376 8 384 ) ( 392 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -7.875000 ) ) gothic_trim/wood2 0 0 0 +( 376 0 336 ) ( 392 0 336 ) ( 392 0 328 ) ( ( 0.015625 0 -7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 384 0 336 ) ( 384 8 336 ) ( 384 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 392 8 336 ) ( 376 8 336 ) ( 376 8 328 ) ( ( 0.015625 0 7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 376 8 336 ) ( 376 0 336 ) ( 376 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 52 +{ +brushDef +{ +( 328 8 328 ) ( 312 8 328 ) ( 312 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 6.875000 ) ) gothic_trim/wood2 0 0 0 +( 312 0 384 ) ( 312 8 384 ) ( 328 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -6.875000 ) ) gothic_trim/wood2 0 0 0 +( 312 0 336 ) ( 328 0 336 ) ( 328 0 328 ) ( ( 0.015625 0 -6.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 320 0 336 ) ( 320 8 336 ) ( 320 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 328 8 336 ) ( 312 8 336 ) ( 312 8 328 ) ( ( 0.015625 0 6.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 312 8 336 ) ( 312 0 336 ) ( 312 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 53 +{ +brushDef +{ +( 208 8 328 ) ( 192 8 328 ) ( 192 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 5 ) ) gothic_trim/wood2 0 0 0 +( 192 0 384 ) ( 192 8 384 ) ( 208 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -5 ) ) gothic_trim/wood2 0 0 0 +( 192 0 336 ) ( 208 0 336 ) ( 208 0 328 ) ( ( 0.015625 0 -5 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 200 0 336 ) ( 200 8 336 ) ( 200 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 208 8 336 ) ( 192 8 336 ) ( 192 8 328 ) ( ( 0.015625 0 5 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 192 8 336 ) ( 192 0 336 ) ( 192 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 54 +{ +brushDef +{ +( 144 8 328 ) ( 128 8 328 ) ( 128 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 4 ) ) gothic_trim/wood2 0 0 0 +( 128 0 384 ) ( 128 8 384 ) ( 144 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -4 ) ) gothic_trim/wood2 0 0 0 +( 128 0 336 ) ( 144 0 336 ) ( 144 0 328 ) ( ( 0.015625 0 -4 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 136 0 336 ) ( 136 8 336 ) ( 136 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 144 8 336 ) ( 128 8 336 ) ( 128 8 328 ) ( ( 0.015625 0 4 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 128 8 336 ) ( 128 0 336 ) ( 128 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 55 +{ +brushDef +{ +( 80 8 328 ) ( 64 8 328 ) ( 64 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 3 ) ) gothic_trim/wood2 0 0 0 +( 64 0 384 ) ( 64 8 384 ) ( 80 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -3 ) ) gothic_trim/wood2 0 0 0 +( 64 0 336 ) ( 80 0 336 ) ( 80 0 328 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 72 0 336 ) ( 72 8 336 ) ( 72 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 80 8 336 ) ( 64 8 336 ) ( 64 8 328 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 64 8 336 ) ( 64 0 336 ) ( 64 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 56 +{ +brushDef +{ +( 16 8 328 ) ( 0 8 328 ) ( 0 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 2 ) ) gothic_trim/wood2 0 0 0 +( 0 0 384 ) ( 0 8 384 ) ( 16 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -2 ) ) gothic_trim/wood2 0 0 0 +( 0 0 336 ) ( 16 0 336 ) ( 16 0 328 ) ( ( 0.015625 0 -2 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 8 0 336 ) ( 8 8 336 ) ( 8 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 16 8 336 ) ( 0 8 336 ) ( 0 8 328 ) ( ( 0.015625 0 2 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 0 8 336 ) ( 0 0 336 ) ( 0 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 57 +{ +brushDef +{ +( -48 8 328 ) ( -64 8 328 ) ( -64 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 1 ) ) gothic_trim/wood2 0 0 0 +( -64 0 384 ) ( -64 8 384 ) ( -48 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -1 ) ) gothic_trim/wood2 0 0 0 +( -64 0 336 ) ( -48 0 336 ) ( -48 0 328 ) ( ( 0.015625 0 -1 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -56 0 336 ) ( -56 8 336 ) ( -56 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -48 8 336 ) ( -64 8 336 ) ( -64 8 328 ) ( ( 0.015625 0 1 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -64 8 336 ) ( -64 0 336 ) ( -64 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 58 +{ +brushDef +{ +( -112 32 328 ) ( -128 32 328 ) ( -128 24 328 ) ( ( 0.015625 0 1.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 24 384 ) ( -128 32 384 ) ( -112 32 384 ) ( ( 0.015625 0 1.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 24 336 ) ( -112 24 336 ) ( -112 24 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 24 336 ) ( -120 32 336 ) ( -120 32 328 ) ( ( 0.015625 0 1.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -112 32 336 ) ( -128 32 336 ) ( -128 32 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -128 32 336 ) ( -128 24 336 ) ( -128 24 328 ) ( ( 0.015625 0 -1.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 59 +{ +brushDef +{ +( -112 96 328 ) ( -128 96 328 ) ( -128 88 328 ) ( ( 0.015625 0 0.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 88 384 ) ( -128 96 384 ) ( -112 96 384 ) ( ( 0.015625 0 0.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 88 336 ) ( -112 88 336 ) ( -112 88 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 88 336 ) ( -120 96 336 ) ( -120 96 328 ) ( ( 0.015625 0 0.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -112 96 336 ) ( -128 96 336 ) ( -128 96 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -128 96 336 ) ( -128 88 336 ) ( -128 88 328 ) ( ( 0.015625 0 -0.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 60 +{ +brushDef +{ +( -112 8 328 ) ( -128 8 328 ) ( -128 0 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 0 384 ) ( -128 8 384 ) ( -112 8 384 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 0 336 ) ( -112 0 336 ) ( -112 0 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 0 336 ) ( -120 8 336 ) ( -120 8 328 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -112 8 336 ) ( -128 8 336 ) ( -128 8 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -128 8 336 ) ( -128 0 336 ) ( -128 0 328 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 61 +{ +brushDef +{ +( -112 128 328 ) ( -128 128 328 ) ( -128 120 328 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 120 384 ) ( -128 128 384 ) ( -112 128 384 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 120 336 ) ( -112 120 336 ) ( -112 120 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 120 336 ) ( -120 128 336 ) ( -120 128 328 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -112 128 336 ) ( -128 128 336 ) ( -128 128 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -128 128 336 ) ( -128 120 336 ) ( -128 120 328 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 62 +{ +brushDef +{ +( 192 128 512 ) ( 192 136 512 ) ( 224 136 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 512 ) ( 224 128 512 ) ( 224 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 512 ) ( 320 136 512 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 512 ) ( 288 136 512 ) ( 288 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 512 ) ( 192 128 512 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 144 480 ) ( 192 136 480 ) ( 320 144 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 63 +{ +brushDef +{ +( 216 136 224 ) ( 184 136 224 ) ( 184 128 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 512 ) ( 224 128 512 ) ( 224 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 512 ) ( 320 136 512 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 512 ) ( 288 136 512 ) ( 288 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 512 ) ( 192 128 512 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 328 ) ( 320 136 328 ) ( 192 128 328 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 64 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 1088 136 376 ) ( 320 136 376 ) ( 320 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 480 ) ( 320 136 480 ) ( 1088 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 480 ) ( 456 128 480 ) ( 456 136 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 504 128 480 ) ( 504 136 480 ) ( 504 128 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 65 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 1088 136 376 ) ( 320 136 376 ) ( 320 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 480 ) ( 320 136 480 ) ( 1088 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 608 136 480 ) ( 608 128 480 ) ( 608 136 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 66 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 1088 136 376 ) ( 320 136 376 ) ( 320 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 480 ) ( 320 136 480 ) ( 1088 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 480 ) ( 352 136 480 ) ( 352 128 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 67 +{ +brushDef +{ +( 320 128 512 ) ( 320 136 512 ) ( 640 136 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 480 ) ( 320 128 480 ) ( 1088 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 68 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 136 232 ) ( 352 128 232 ) ( 456 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 376 ) ( 1088 136 376 ) ( 320 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 69 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 376 ) ( -128 136 376 ) ( -128 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 480 ) ( -128 136 480 ) ( 640 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 8 136 480 ) ( 8 128 480 ) ( 8 136 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 128 480 ) ( 56 136 480 ) ( 56 128 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 70 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 376 ) ( -128 136 376 ) ( -128 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 480 ) ( -128 136 480 ) ( 640 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 136 480 ) ( 160 128 480 ) ( 160 136 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 71 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 376 ) ( -128 136 376 ) ( -128 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 480 ) ( -128 136 480 ) ( 640 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -96 128 480 ) ( -96 136 480 ) ( -96 128 368 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 72 +{ +brushDef +{ +( -128 128 512 ) ( -128 136 512 ) ( 192 136 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 480 ) ( -128 128 480 ) ( 640 136 480 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 73 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 144 232 ) ( 56 136 232 ) ( 160 144 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 376 ) ( 640 136 376 ) ( -128 128 376 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 74 +{ +brushDef +{ +( 120 128 320 ) ( -128 128 320 ) ( -128 0 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -120 0 328 ) ( -120 128 328 ) ( 128 128 328 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 0 576 ) ( 120 0 576 ) ( 120 0 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 16 576 ) ( 640 144 576 ) ( 640 144 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 120 128 576 ) ( -128 128 576 ) ( -128 128 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 128 576 ) ( -128 0 576 ) ( -128 0 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 75 +{ +brushDef +{ +( 640 968 512 ) ( 568 968 512 ) ( 568 920 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 448 776 768 ) ( 448 320 768 ) ( 64 320 768 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 320 768 ) ( 640 320 768 ) ( 640 128 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +( 448 320 768 ) ( 448 776 768 ) ( 640 968 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +( 640 776 768 ) ( -128 776 768 ) ( -128 968 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +( 64 776 768 ) ( 64 320 768 ) ( -128 128 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +} +} +// brush 76 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 560 824 8 0 0 ) ( 560 824 40 0 0.500000 ) ( 560 824 72 0 1 ) ) +( ( 560 816 8 0.125000 0 ) ( 560 816 40 0.125000 0.500000 ) ( 560 816 72 0.125000 1 ) ) +( ( 568 816 8 0.250000 0 ) ( 568 816 40 0.250000 0.500000 ) ( 568 816 72 0.250000 1 ) ) +( ( 576 816 8 0.375000 0 ) ( 576 816 40 0.375000 0.500000 ) ( 576 816 72 0.375000 1 ) ) +( ( 576 824 8 0.500000 0 ) ( 576 824 40 0.500000 0.500000 ) ( 576 824 72 0.500000 1 ) ) +( ( 576 832 8 0.625000 0 ) ( 576 832 40 0.625000 0.500000 ) ( 576 832 72 0.625000 1 ) ) +( ( 568 832 8 0.750000 0 ) ( 568 832 40 0.750000 0.500000 ) ( 568 832 72 0.750000 1 ) ) +( ( 560 832 8 0.875000 0 ) ( 560 832 40 0.875000 0.500000 ) ( 560 832 72 0.875000 1 ) ) +( ( 560 824 8 1 0 ) ( 560 824 40 1 0.500000 ) ( 560 824 72 1 1 ) ) +) + } + } +// brush 77 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( -64 824 8 0 0 ) ( -64 824 40 0 0.500000 ) ( -64 824 72 0 1 ) ) +( ( -64 816 8 0.125000 0 ) ( -64 816 40 0.125000 0.500000 ) ( -64 816 72 0.125000 1 ) ) +( ( -56 816 8 0.250000 0 ) ( -56 816 40 0.250000 0.500000 ) ( -56 816 72 0.250000 1 ) ) +( ( -48 816 8 0.375000 0 ) ( -48 816 40 0.375000 0.500000 ) ( -48 816 72 0.375000 1 ) ) +( ( -48 824 8 0.500000 0 ) ( -48 824 40 0.500000 0.500000 ) ( -48 824 72 0.500000 1 ) ) +( ( -48 832 8 0.625000 0 ) ( -48 832 40 0.625000 0.500000 ) ( -48 832 72 0.625000 1 ) ) +( ( -56 832 8 0.750000 0 ) ( -56 832 40 0.750000 0.500000 ) ( -56 832 72 0.750000 1 ) ) +( ( -64 832 8 0.875000 0 ) ( -64 832 40 0.875000 0.500000 ) ( -64 832 72 0.875000 1 ) ) +( ( -64 824 8 1 0 ) ( -64 824 40 1 0.500000 ) ( -64 824 72 1 1 ) ) +) + } + } +// brush 78 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( -64 928 8 0 0 ) ( -64 928 40 0 0.500000 ) ( -64 928 72 0 1 ) ) +( ( -64 920 8 0.125000 0 ) ( -64 920 40 0.125000 0.500000 ) ( -64 920 72 0.125000 1 ) ) +( ( -56 920 8 0.250000 0 ) ( -56 920 40 0.250000 0.500000 ) ( -56 920 72 0.250000 1 ) ) +( ( -48 920 8 0.375000 0 ) ( -48 920 40 0.375000 0.500000 ) ( -48 920 72 0.375000 1 ) ) +( ( -48 928 8 0.500000 0 ) ( -48 928 40 0.500000 0.500000 ) ( -48 928 72 0.500000 1 ) ) +( ( -48 936 8 0.625000 0 ) ( -48 936 40 0.625000 0.500000 ) ( -48 936 72 0.625000 1 ) ) +( ( -56 936 8 0.750000 0 ) ( -56 936 40 0.750000 0.500000 ) ( -56 936 72 0.750000 1 ) ) +( ( -64 936 8 0.875000 0 ) ( -64 936 40 0.875000 0.500000 ) ( -64 936 72 0.875000 1 ) ) +( ( -64 928 8 1 0 ) ( -64 928 40 1 0.500000 ) ( -64 928 72 1 1 ) ) +) + } + } +// brush 79 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 8 744 8 0 0 ) ( 8 744 40 0 0.500000 ) ( 8 744 72 0 1 ) ) +( ( 8 736 8 0.125000 0 ) ( 8 736 40 0.125000 0.500000 ) ( 8 736 72 0.125000 1 ) ) +( ( 16 736 8 0.250000 0 ) ( 16 736 40 0.250000 0.500000 ) ( 16 736 72 0.250000 1 ) ) +( ( 24 736 8 0.375000 0 ) ( 24 736 40 0.375000 0.500000 ) ( 24 736 72 0.375000 1 ) ) +( ( 24 744 8 0.500000 0 ) ( 24 744 40 0.500000 0.500000 ) ( 24 744 72 0.500000 1 ) ) +( ( 24 752 8 0.625000 0 ) ( 24 752 40 0.625000 0.500000 ) ( 24 752 72 0.625000 1 ) ) +( ( 16 752 8 0.750000 0 ) ( 16 752 40 0.750000 0.500000 ) ( 16 752 72 0.750000 1 ) ) +( ( 8 752 8 0.875000 0 ) ( 8 752 40 0.875000 0.500000 ) ( 8 752 72 0.875000 1 ) ) +( ( 8 744 8 1 0 ) ( 8 744 40 1 0.500000 ) ( 8 744 72 1 1 ) ) +) + } + } +// brush 80 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 104 744 8 0 0 ) ( 104 744 40 0 0.500000 ) ( 104 744 72 0 1 ) ) +( ( 104 736 8 0.125000 0 ) ( 104 736 40 0.125000 0.500000 ) ( 104 736 72 0.125000 1 ) ) +( ( 112 736 8 0.250000 0 ) ( 112 736 40 0.250000 0.500000 ) ( 112 736 72 0.250000 1 ) ) +( ( 120 736 8 0.375000 0 ) ( 120 736 40 0.375000 0.500000 ) ( 120 736 72 0.375000 1 ) ) +( ( 120 744 8 0.500000 0 ) ( 120 744 40 0.500000 0.500000 ) ( 120 744 72 0.500000 1 ) ) +( ( 120 752 8 0.625000 0 ) ( 120 752 40 0.625000 0.500000 ) ( 120 752 72 0.625000 1 ) ) +( ( 112 752 8 0.750000 0 ) ( 112 752 40 0.750000 0.500000 ) ( 112 752 72 0.750000 1 ) ) +( ( 104 752 8 0.875000 0 ) ( 104 752 40 0.875000 0.500000 ) ( 104 752 72 0.875000 1 ) ) +( ( 104 744 8 1 0 ) ( 104 744 40 1 0.500000 ) ( 104 744 72 1 1 ) ) +) + } + } +// brush 81 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 272 744 8 0 0 ) ( 272 744 40 0 0.500000 ) ( 272 744 72 0 1 ) ) +( ( 272 736 8 0.125000 0 ) ( 272 736 40 0.125000 0.500000 ) ( 272 736 72 0.125000 1 ) ) +( ( 280 736 8 0.250000 0 ) ( 280 736 40 0.250000 0.500000 ) ( 280 736 72 0.250000 1 ) ) +( ( 288 736 8 0.375000 0 ) ( 288 736 40 0.375000 0.500000 ) ( 288 736 72 0.375000 1 ) ) +( ( 288 744 8 0.500000 0 ) ( 288 744 40 0.500000 0.500000 ) ( 288 744 72 0.500000 1 ) ) +( ( 288 752 8 0.625000 0 ) ( 288 752 40 0.625000 0.500000 ) ( 288 752 72 0.625000 1 ) ) +( ( 280 752 8 0.750000 0 ) ( 280 752 40 0.750000 0.500000 ) ( 280 752 72 0.750000 1 ) ) +( ( 272 752 8 0.875000 0 ) ( 272 752 40 0.875000 0.500000 ) ( 272 752 72 0.875000 1 ) ) +( ( 272 744 8 1 0 ) ( 272 744 40 1 0.500000 ) ( 272 744 72 1 1 ) ) +) + } + } +// brush 82 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 376 744 8 0 0 ) ( 376 744 40 0 0.500000 ) ( 376 744 72 0 1 ) ) +( ( 376 736 8 0.125000 0 ) ( 376 736 40 0.125000 0.500000 ) ( 376 736 72 0.125000 1 ) ) +( ( 384 736 8 0.250000 0 ) ( 384 736 40 0.250000 0.500000 ) ( 384 736 72 0.250000 1 ) ) +( ( 392 736 8 0.375000 0 ) ( 392 736 40 0.375000 0.500000 ) ( 392 736 72 0.375000 1 ) ) +( ( 392 744 8 0.500000 0 ) ( 392 744 40 0.500000 0.500000 ) ( 392 744 72 0.500000 1 ) ) +( ( 392 752 8 0.625000 0 ) ( 392 752 40 0.625000 0.500000 ) ( 392 752 72 0.625000 1 ) ) +( ( 384 752 8 0.750000 0 ) ( 384 752 40 0.750000 0.500000 ) ( 384 752 72 0.750000 1 ) ) +( ( 376 752 8 0.875000 0 ) ( 376 752 40 0.875000 0.500000 ) ( 376 752 72 0.875000 1 ) ) +( ( 376 744 8 1 0 ) ( 376 744 40 1 0.500000 ) ( 376 744 72 1 1 ) ) +) + } + } +// brush 83 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 464 744 8 0 0 ) ( 464 744 40 0 0.500000 ) ( 464 744 72 0 1 ) ) +( ( 464 736 8 0.125000 0 ) ( 464 736 40 0.125000 0.500000 ) ( 464 736 72 0.125000 1 ) ) +( ( 472 736 8 0.250000 0 ) ( 472 736 40 0.250000 0.500000 ) ( 472 736 72 0.250000 1 ) ) +( ( 480 736 8 0.375000 0 ) ( 480 736 40 0.375000 0.500000 ) ( 480 736 72 0.375000 1 ) ) +( ( 480 744 8 0.500000 0 ) ( 480 744 40 0.500000 0.500000 ) ( 480 744 72 0.500000 1 ) ) +( ( 480 752 8 0.625000 0 ) ( 480 752 40 0.625000 0.500000 ) ( 480 752 72 0.625000 1 ) ) +( ( 472 752 8 0.750000 0 ) ( 472 752 40 0.750000 0.500000 ) ( 472 752 72 0.750000 1 ) ) +( ( 464 752 8 0.875000 0 ) ( 464 752 40 0.875000 0.500000 ) ( 464 752 72 0.875000 1 ) ) +( ( 464 744 8 1 0 ) ( 464 744 40 1 0.500000 ) ( 464 744 72 1 1 ) ) +) + } + } +// brush 84 +{ +brushDef +{ +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 312 104 ) ( 528 304 104 ) ( 520 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 524 336 72 ) ( 524 304 72 ) ( 532 304 72 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 524 304 80 ) ( 524 336 80 ) ( 524 304 24 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 85 +{ +brushDef +{ +( 536 304 104 ) ( 536 312 104 ) ( 528 312 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 532 304 80 ) ( 524 304 80 ) ( 524 336 80 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +( 532 336 128 ) ( 532 304 128 ) ( 532 336 72 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 86 +{ +brushDef +{ +( 536 304 104 ) ( 536 312 104 ) ( 528 312 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 312 104 ) ( 528 304 104 ) ( 520 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 304 96 ) ( 528 336 96 ) ( 536 304 96 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +( 524 304 80 ) ( 532 304 80 ) ( 524 336 80 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 87 +{ +brushDef +{ +( 520 312 48 ) ( 520 304 48 ) ( 528 304 48 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 536 304 104 ) ( 536 312 104 ) ( 528 312 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 312 104 ) ( 528 304 104 ) ( 520 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 524 304 72 ) ( 524 336 72 ) ( 532 304 72 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 88 +{ +brushDef +{ +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 336 104 ) ( 528 328 104 ) ( 520 328 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 524 344 72 ) ( 524 312 72 ) ( 532 312 72 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 524 312 80 ) ( 524 344 80 ) ( 524 312 24 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 89 +{ +brushDef +{ +( 536 328 104 ) ( 536 336 104 ) ( 528 336 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 532 312 80 ) ( 524 312 80 ) ( 524 344 80 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +( 532 344 128 ) ( 532 312 128 ) ( 532 344 72 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 90 +{ +brushDef +{ +( 536 328 104 ) ( 536 336 104 ) ( 528 336 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 336 104 ) ( 528 328 104 ) ( 520 328 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 304 96 ) ( 528 336 96 ) ( 536 304 96 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +( 524 312 80 ) ( 532 312 80 ) ( 524 344 80 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 91 +{ +brushDef +{ +( 520 336 48 ) ( 520 328 48 ) ( 528 328 48 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 536 328 104 ) ( 536 336 104 ) ( 528 336 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 336 104 ) ( 528 328 104 ) ( 520 328 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 524 312 72 ) ( 524 344 72 ) ( 532 312 72 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 92 +{ +brushDef +{ +( 524 336 72 ) ( 524 304 72 ) ( 532 304 72 ) ( ( 0 -0.015625 -4.187500 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 532 304 80 ) ( 524 304 80 ) ( 524 336 80 ) ( ( 0 0.015625 -4.187500 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +( 532 304 128 ) ( 532 336 128 ) ( 532 336 72 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 532 336 80 ) ( 524 336 80 ) ( 524 336 24 ) ( ( 0.015625 0 5.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 524 336 80 ) ( 524 304 80 ) ( 524 304 24 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 524 304 80 ) ( 532 304 80 ) ( 532 304 24 ) ( ( 0.015625 0 -5.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 93 +{ +brushDef +{ +( 528 312 80 ) ( 520 312 80 ) ( 520 312 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 312 104 ) ( 528 304 104 ) ( 520 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 520 304 80 ) ( 528 304 80 ) ( 528 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 336 96 ) ( 528 304 96 ) ( 536 304 96 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 528 304 104 ) ( 528 336 104 ) ( 528 304 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 94 +{ +brushDef +{ +( 528 336 80 ) ( 520 336 80 ) ( 520 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 336 104 ) ( 528 328 104 ) ( 520 328 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0.724778 ) ) gothic_trim/wood2 0 0 0 +( 520 328 80 ) ( 528 328 80 ) ( 528 328 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 336 96 ) ( 528 304 96 ) ( 536 304 96 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 528 304 104 ) ( 528 336 104 ) ( 528 304 48 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 95 +{ +brushDef +{ +( 528 336 96 ) ( 528 304 96 ) ( 536 304 96 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 536 304 104 ) ( 528 304 104 ) ( 528 336 104 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +( 536 304 152 ) ( 536 336 152 ) ( 536 336 96 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 536 336 104 ) ( 528 336 104 ) ( 528 336 48 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 336 104 ) ( 528 304 104 ) ( 528 304 48 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 304 104 ) ( 536 304 104 ) ( 536 304 48 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 96 +{ +brushDef +{ +( 488 336 8 ) ( 496 336 8 ) ( 496 344 8 ) ( ( -0.015625 0 8.125000 ) ( 0 -0.015625 -15 ) ) gothic_trim/wood2 0 0 0 +( 504 336 40 ) ( 504 328 40 ) ( 496 328 40 ) ( ( -0.015625 0 8.125000 ) ( 0 -0.015625 15 ) ) gothic_trim/wood2 0 0 0 +( 488 344 8 ) ( 496 344 8 ) ( 504 336 40 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 -3.368932 ) ) gothic_trim/wood2 0 0 0 +( 488 328 8 ) ( 488 336 8 ) ( 496 336 40 ) ( ( 0.015625 0 13.375000 ) ( 0 0.015625 -1.216441 ) ) gothic_trim/wood2 0 0 0 +( 496 336 8 ) ( 488 336 8 ) ( 496 328 40 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 -3.368936 ) ) gothic_trim/wood2 0 0 0 +( 496 336 8 ) ( 496 328 8 ) ( 504 328 40 ) ( ( 0.015625 0 -13.375000 ) ( 0 0.015625 -1.216413 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 97 +{ +brushDef +{ +( 496 296 8 ) ( 496 304 8 ) ( 488 304 8 ) ( ( 0 0.015625 11.625000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 0 0 0 +( 496 312 40 ) ( 504 312 40 ) ( 504 304 40 ) ( ( 0 -0.015625 11.625000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 0 0 0 +( 488 296 8 ) ( 488 304 8 ) ( 496 312 40 ) ( ( 0.015625 0 1.750000 ) ( 0 0.015625 -2.580697 ) ) gothic_trim/wood2 0 0 0 +( 504 296 8 ) ( 496 296 8 ) ( 496 304 40 ) ( ( 0.015625 0 10.125000 ) ( 0 0.015625 0.299379 ) ) gothic_trim/wood2 0 0 0 +( 496 304 8 ) ( 496 296 8 ) ( 504 304 40 ) ( ( 0.015625 0 -1.750000 ) ( 0 0.015625 -2.580694 ) ) gothic_trim/wood2 0 0 0 +( 496 304 8 ) ( 504 304 8 ) ( 504 312 40 ) ( ( 0.015625 0 -10.125000 ) ( 0 0.015625 0.299380 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 98 +{ +brushDef +{ +( 536 304 8 ) ( 528 304 8 ) ( 528 296 8 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 0.500000 ) ) gothic_trim/wood2 0 0 0 +( 520 304 40 ) ( 520 312 40 ) ( 528 312 40 ) ( ( 0.015625 0 -1.625000 ) ( 0 0.015625 -0.500000 ) ) gothic_trim/wood2 0 0 0 +( 536 296 8 ) ( 528 296 8 ) ( 520 304 40 ) ( ( 0.015625 0 -1.500000 ) ( 0 0.015625 -0.761721 ) ) gothic_trim/wood2 0 0 0 +( 536 312 8 ) ( 536 304 8 ) ( 528 304 40 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -0.488851 ) ) gothic_trim/wood2 0 0 0 +( 528 304 8 ) ( 536 304 8 ) ( 528 312 40 ) ( ( 0.015625 0 1.500000 ) ( 0 0.015625 -0.761720 ) ) gothic_trim/wood2 0 0 0 +( 528 304 8 ) ( 528 312 8 ) ( 520 312 40 ) ( ( 0.015625 0 -2.625000 ) ( 0 0.015625 -0.488853 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 99 +{ +brushDef +{ +( 528 344 8 ) ( 528 336 8 ) ( 536 336 8 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 528 328 40 ) ( 520 328 40 ) ( 520 336 40 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +( 536 344 8 ) ( 536 336 8 ) ( 528 328 40 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 -1.368011 ) ) gothic_trim/wood2 0 0 0 +( 520 344 8 ) ( 528 344 8 ) ( 528 336 40 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 -2.125928 ) ) gothic_trim/wood2 0 0 0 +( 528 336 8 ) ( 528 344 8 ) ( 520 336 40 ) ( ( 0.015625 0 8.250001 ) ( 0 0.015625 -1.368012 ) ) gothic_trim/wood2 0 0 0 +( 528 336 8 ) ( 520 336 8 ) ( 520 328 40 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 -2.125930 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 100 +{ +brushDef +{ +( 496 328 40 ) ( 496 304 40 ) ( 528 304 40 ) ( ( 0 -0.015625 -4.125000 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 528 304 48 ) ( 496 304 48 ) ( 496 328 48 ) ( ( 0 0.015625 -4.125000 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +( 528 304 48 ) ( 528 328 48 ) ( 528 328 40 ) ( ( 0.015625 0 -8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 528 336 48 ) ( 496 336 48 ) ( 496 336 40 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 496 328 48 ) ( 496 304 48 ) ( 496 304 40 ) ( ( 0.015625 0 8.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 496 304 48 ) ( 528 304 48 ) ( 528 304 40 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 101 +{ +brushDef +{ +( 440 352 40 ) ( 464 352 40 ) ( 464 384 40 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 384 48 ) ( 464 352 48 ) ( 440 352 48 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 384 48 ) ( 440 384 48 ) ( 440 384 40 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 384 48 ) ( 432 352 48 ) ( 432 352 40 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 352 48 ) ( 464 352 48 ) ( 464 352 40 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 352 48 ) ( 464 384 48 ) ( 464 384 40 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 102 +{ +brushDef +{ +( 424 384 8 ) ( 432 384 8 ) ( 432 392 8 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 440 384 40 ) ( 440 376 40 ) ( 432 376 40 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +( 424 392 8 ) ( 432 392 8 ) ( 440 384 40 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 -4.035891 ) ) gothic_trim/wood2 0 0 0 +( 424 376 8 ) ( 424 384 8 ) ( 432 384 40 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 -1.883390 ) ) gothic_trim/wood2 0 0 0 +( 432 384 8 ) ( 424 384 8 ) ( 432 376 40 ) ( ( 0.015625 0 7.250001 ) ( 0 0.015625 -4.035891 ) ) gothic_trim/wood2 0 0 0 +( 432 384 8 ) ( 432 376 8 ) ( 440 376 40 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 -1.883390 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 103 +{ +brushDef +{ +( 464 392 8 ) ( 464 384 8 ) ( 472 384 8 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -13 ) ) gothic_trim/wood2 0 0 0 +( 464 376 40 ) ( 456 376 40 ) ( 456 384 40 ) ( ( 0 0.015625 -3.375000 ) ( -0.015625 0 13 ) ) gothic_trim/wood2 0 0 0 +( 472 392 8 ) ( 472 384 8 ) ( 464 376 40 ) ( ( 0.015625 0 -12.500000 ) ( 0 0.015625 -1.004194 ) ) gothic_trim/wood2 0 0 0 +( 456 392 8 ) ( 464 392 8 ) ( 464 384 40 ) ( ( 0.015625 0 3.625000 ) ( 0 0.015625 -3.156694 ) ) gothic_trim/wood2 0 0 0 +( 464 384 8 ) ( 464 392 8 ) ( 456 384 40 ) ( ( 0.015625 0 12.500000 ) ( 0 0.015625 -1.004192 ) ) gothic_trim/wood2 0 0 0 +( 464 384 8 ) ( 456 384 8 ) ( 456 376 40 ) ( ( 0.015625 0 -3.625000 ) ( 0 0.015625 -3.156695 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 104 +{ +brushDef +{ +( 472 352 8 ) ( 464 352 8 ) ( 464 344 8 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 352 40 ) ( 456 360 40 ) ( 464 360 40 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 472 344 8 ) ( 464 344 8 ) ( 456 352 40 ) ( ( 0.015625 0 0.750000 ) ( 0 0.015625 0.087216 ) ) gothic_trim/wood2 0 0 0 +( 472 360 8 ) ( 472 352 8 ) ( 464 352 40 ) ( ( 0.015625 0 -0.875000 ) ( 0 0.015625 0.056903 ) ) gothic_trim/wood2 0 0 0 +( 464 352 8 ) ( 472 352 8 ) ( 464 360 40 ) ( ( 0.015625 0 -0.750000 ) ( 0 0.015625 0.087221 ) ) gothic_trim/wood2 0 0 0 +( 464 352 8 ) ( 464 360 8 ) ( 456 360 40 ) ( ( 0.015625 0 0.875000 ) ( 0 0.015625 0.056905 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 105 +{ +brushDef +{ +( 432 344 8 ) ( 432 352 8 ) ( 424 352 8 ) ( ( 0 0.015625 9.875000 ) ( -0.015625 0 -1.500000 ) ) gothic_trim/wood2 0 0 0 +( 432 360 40 ) ( 440 360 40 ) ( 440 352 40 ) ( ( 0 -0.015625 9.875000 ) ( 0.015625 0 1.500000 ) ) gothic_trim/wood2 0 0 0 +( 424 344 8 ) ( 424 352 8 ) ( 432 360 40 ) ( ( 0.015625 0 6.500000 ) ( 0 0.015625 -3.126388 ) ) gothic_trim/wood2 0 0 0 +( 440 344 8 ) ( 432 344 8 ) ( 432 352 40 ) ( ( 0.015625 0 12.375000 ) ( 0 0.015625 1.451483 ) ) gothic_trim/wood2 0 0 0 +( 432 352 8 ) ( 432 344 8 ) ( 440 352 40 ) ( ( 0.015625 0 -6.500000 ) ( 0 0.015625 -3.126389 ) ) gothic_trim/wood2 0 0 0 +( 432 352 8 ) ( 440 352 8 ) ( 440 360 40 ) ( ( 0.015625 0 -12.375000 ) ( 0 0.015625 1.451492 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 106 +{ +brushDef +{ +( 432 384 96 ) ( 464 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 392 104 ) ( 464 384 104 ) ( 432 384 104 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 392 152 ) ( 432 392 152 ) ( 432 392 96 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 392 104 ) ( 432 384 104 ) ( 432 384 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 384 104 ) ( 464 384 104 ) ( 464 384 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 384 104 ) ( 464 392 104 ) ( 464 392 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 107 +{ +brushDef +{ +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 384 104 ) ( 440 384 104 ) ( 440 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 384 96 ) ( 464 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 384 104 ) ( 432 384 104 ) ( 464 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 108 +{ +brushDef +{ +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 384 104 ) ( 464 384 104 ) ( 464 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 384 96 ) ( 464 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 384 104 ) ( 432 384 104 ) ( 464 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 109 +{ +brushDef +{ +( 432 380 72 ) ( 464 380 72 ) ( 464 388 72 ) ( ( -0.015625 0 9.312500 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 388 80 ) ( 464 380 80 ) ( 432 380 80 ) ( ( -0.015625 0 9.312500 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 388 128 ) ( 432 388 128 ) ( 432 388 72 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 432 388 80 ) ( 432 380 80 ) ( 432 380 24 ) ( ( 0.015625 0 16.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 432 380 80 ) ( 464 380 80 ) ( 464 380 24 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 464 380 80 ) ( 464 388 80 ) ( 464 388 24 ) ( ( 0.015625 0 -16.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 110 +{ +brushDef +{ +( 432 376 48 ) ( 440 376 48 ) ( 440 384 48 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 440 392 104 ) ( 432 392 104 ) ( 432 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 384 104 ) ( 440 384 104 ) ( 440 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 380 72 ) ( 424 380 72 ) ( 456 388 72 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 111 +{ +brushDef +{ +( 440 392 104 ) ( 432 392 104 ) ( 432 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 384 104 ) ( 440 384 104 ) ( 440 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 384 96 ) ( 432 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +( 456 380 80 ) ( 456 388 80 ) ( 424 380 80 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 112 +{ +brushDef +{ +( 440 392 104 ) ( 432 392 104 ) ( 432 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 388 80 ) ( 456 380 80 ) ( 424 380 80 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +( 424 388 128 ) ( 456 388 128 ) ( 424 388 72 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 113 +{ +brushDef +{ +( 432 384 80 ) ( 432 376 80 ) ( 432 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 384 104 ) ( 440 384 104 ) ( 440 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 440 376 80 ) ( 440 384 80 ) ( 440 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 424 380 72 ) ( 456 380 72 ) ( 456 388 72 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 456 380 80 ) ( 424 380 80 ) ( 456 380 24 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 114 +{ +brushDef +{ +( 456 376 48 ) ( 464 376 48 ) ( 464 384 48 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 392 104 ) ( 456 392 104 ) ( 456 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 384 104 ) ( 464 384 104 ) ( 464 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 380 72 ) ( 432 380 72 ) ( 464 388 72 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 115 +{ +brushDef +{ +( 464 392 104 ) ( 456 392 104 ) ( 456 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 384 104 ) ( 464 384 104 ) ( 464 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 384 96 ) ( 432 384 96 ) ( 464 392 96 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 380 80 ) ( 464 388 80 ) ( 432 380 80 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 116 +{ +brushDef +{ +( 464 392 104 ) ( 456 392 104 ) ( 456 384 48 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 388 80 ) ( 464 380 80 ) ( 432 380 80 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +( 432 388 128 ) ( 464 388 128 ) ( 432 388 72 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 117 +{ +brushDef +{ +( 456 384 80 ) ( 456 376 80 ) ( 456 376 48 ) ( ( 0.015625 0 16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 384 104 ) ( 464 384 104 ) ( 464 376 48 ) ( ( 0.015625 0 7.250000 ) ( 0 0.015625 2.280421 ) ) gothic_trim/wood2 0 0 0 +( 464 376 80 ) ( 464 384 80 ) ( 464 384 48 ) ( ( 0.015625 0 -16.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 380 72 ) ( 464 380 72 ) ( 464 388 72 ) ( ( -0.015625 0 9.375000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 464 380 80 ) ( 432 380 80 ) ( 464 380 24 ) ( ( 0.015625 0 -7.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 118 +{ +brushDef +{ +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 216 104 ) ( 432 216 104 ) ( 432 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 220 72 ) ( 432 220 72 ) ( 432 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 220 80 ) ( 464 220 80 ) ( 432 220 24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 119 +{ +brushDef +{ +( 432 208 104 ) ( 440 208 104 ) ( 440 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 212 80 ) ( 432 220 80 ) ( 464 220 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 212 128 ) ( 432 212 128 ) ( 464 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 120 +{ +brushDef +{ +( 432 208 104 ) ( 440 208 104 ) ( 440 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 216 104 ) ( 432 216 104 ) ( 432 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 216 96 ) ( 464 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 220 80 ) ( 432 212 80 ) ( 464 220 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 121 +{ +brushDef +{ +( 440 224 48 ) ( 432 224 48 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 208 104 ) ( 440 208 104 ) ( 440 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 216 104 ) ( 432 216 104 ) ( 432 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 220 72 ) ( 464 220 72 ) ( 432 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 122 +{ +brushDef +{ +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 328 104 ) ( 360 336 104 ) ( 368 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 364 304 72 ) ( 364 336 72 ) ( 356 336 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 364 336 80 ) ( 364 304 80 ) ( 364 336 24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 123 +{ +brushDef +{ +( 352 336 104 ) ( 352 328 104 ) ( 360 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 356 336 80 ) ( 364 336 80 ) ( 364 304 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 356 304 128 ) ( 356 336 128 ) ( 356 304 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 124 +{ +brushDef +{ +( 352 336 104 ) ( 352 328 104 ) ( 360 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 328 104 ) ( 360 336 104 ) ( 368 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 336 96 ) ( 360 304 96 ) ( 352 336 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 364 336 80 ) ( 356 336 80 ) ( 364 304 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 125 +{ +brushDef +{ +( 368 328 48 ) ( 368 336 48 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 336 104 ) ( 352 328 104 ) ( 360 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 328 104 ) ( 360 336 104 ) ( 368 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 364 336 72 ) ( 364 304 72 ) ( 356 336 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 126 +{ +brushDef +{ +( 392 312 40 ) ( 392 336 40 ) ( 360 336 40 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 0 0 0 +( 360 336 48 ) ( 392 336 48 ) ( 392 312 48 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 0 0 0 +( 360 336 48 ) ( 360 312 48 ) ( 360 312 40 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 304 48 ) ( 392 304 48 ) ( 392 304 40 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 392 312 48 ) ( 392 336 48 ) ( 392 336 40 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 392 336 48 ) ( 360 336 48 ) ( 360 336 40 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 127 +{ +brushDef +{ +( 360 296 8 ) ( 360 304 8 ) ( 352 304 8 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 0 0 0 +( 360 312 40 ) ( 368 312 40 ) ( 368 304 40 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 0 0 0 +( 352 296 8 ) ( 352 304 8 ) ( 360 312 40 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 -2.914160 ) ) gothic_trim/wood2 0 0 0 +( 368 296 8 ) ( 360 296 8 ) ( 360 304 40 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0.966415 ) ) gothic_trim/wood2 0 0 0 +( 360 304 8 ) ( 360 296 8 ) ( 368 304 40 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 -2.914160 ) ) gothic_trim/wood2 0 0 0 +( 360 304 8 ) ( 368 304 8 ) ( 368 312 40 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0.966415 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 128 +{ +brushDef +{ +( 352 336 8 ) ( 360 336 8 ) ( 360 344 8 ) ( ( -0.015625 0 8.375000 ) ( 0 -0.015625 -13.125000 ) ) gothic_trim/wood2 0 0 0 +( 368 336 40 ) ( 368 328 40 ) ( 360 328 40 ) ( ( -0.015625 0 8.375000 ) ( 0 -0.015625 13.125000 ) ) gothic_trim/wood2 0 0 0 +( 352 344 8 ) ( 360 344 8 ) ( 368 336 40 ) ( ( 0.015625 0 -7.875000 ) ( 0 0.015625 -3.853989 ) ) gothic_trim/wood2 0 0 0 +( 352 328 8 ) ( 352 336 8 ) ( 360 336 40 ) ( ( 0.015625 0 15.375000 ) ( 0 0.015625 -2.034964 ) ) gothic_trim/wood2 0 0 0 +( 360 336 8 ) ( 352 336 8 ) ( 360 328 40 ) ( ( 0.015625 0 7.875002 ) ( 0 0.015625 -3.853986 ) ) gothic_trim/wood2 0 0 0 +( 360 336 8 ) ( 360 328 8 ) ( 368 328 40 ) ( ( 0.015625 0 -15.375000 ) ( 0 0.015625 -2.034965 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 129 +{ +brushDef +{ +( 392 344 8 ) ( 392 336 8 ) ( 400 336 8 ) ( ( 0 -0.015625 -2 ) ( 0.015625 0 -11.750000 ) ) gothic_trim/wood2 0 0 0 +( 392 328 40 ) ( 384 328 40 ) ( 384 336 40 ) ( ( 0 0.015625 -2 ) ( -0.015625 0 11.750000 ) ) gothic_trim/wood2 0 0 0 +( 400 344 8 ) ( 400 336 8 ) ( 392 328 40 ) ( ( 0.015625 0 -11 ) ( 0 0.015625 -1.034511 ) ) gothic_trim/wood2 0 0 0 +( 384 344 8 ) ( 392 344 8 ) ( 392 336 40 ) ( ( 0.015625 0 3.750001 ) ( 0 0.015625 -2.792890 ) ) gothic_trim/wood2 0 0 0 +( 392 336 8 ) ( 392 344 8 ) ( 384 336 40 ) ( ( 0.015625 0 11 ) ( 0 0.015625 -1.034512 ) ) gothic_trim/wood2 0 0 0 +( 392 336 8 ) ( 384 336 8 ) ( 384 328 40 ) ( ( 0.015625 0 -3.750000 ) ( 0 0.015625 -2.792888 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 130 +{ +brushDef +{ +( 400 304 8 ) ( 392 304 8 ) ( 392 296 8 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 -1.375000 ) ) gothic_trim/wood2 0 0 0 +( 384 304 40 ) ( 384 312 40 ) ( 392 312 40 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 1.375000 ) ) gothic_trim/wood2 0 0 0 +( 400 296 8 ) ( 392 296 8 ) ( 384 304 40 ) ( ( 0.015625 0 1.875001 ) ( 0 0.015625 -0.276583 ) ) gothic_trim/wood2 0 0 0 +( 400 312 8 ) ( 400 304 8 ) ( 392 304 40 ) ( ( 0.015625 0 0.625000 ) ( 0 0.015625 0.329756 ) ) gothic_trim/wood2 0 0 0 +( 392 304 8 ) ( 400 304 8 ) ( 392 312 40 ) ( ( 0.015625 0 -1.875000 ) ( 0 0.015625 -0.276584 ) ) gothic_trim/wood2 0 0 0 +( 392 304 8 ) ( 392 312 8 ) ( 384 312 40 ) ( ( 0.015625 0 -0.625000 ) ( 0 0.015625 0.329758 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 131 +{ +brushDef +{ +( 360 304 96 ) ( 360 336 96 ) ( 352 336 96 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 0 0 0 +( 352 336 104 ) ( 360 336 104 ) ( 360 304 104 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 0 0 0 +( 352 336 152 ) ( 352 304 152 ) ( 352 304 96 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 304 104 ) ( 360 304 104 ) ( 360 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 304 104 ) ( 360 336 104 ) ( 360 336 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 336 104 ) ( 352 336 104 ) ( 352 336 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 132 +{ +brushDef +{ +( 360 304 80 ) ( 368 304 80 ) ( 368 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 304 104 ) ( 360 312 104 ) ( 368 312 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 0 0 0 +( 368 312 80 ) ( 360 312 80 ) ( 360 312 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 304 96 ) ( 360 336 96 ) ( 352 336 96 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 0 0 0 +( 360 336 104 ) ( 360 304 104 ) ( 360 336 48 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 133 +{ +brushDef +{ +( 360 328 80 ) ( 368 328 80 ) ( 368 328 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 328 104 ) ( 360 336 104 ) ( 368 336 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 0 0 0 +( 368 336 80 ) ( 360 336 80 ) ( 360 336 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 304 96 ) ( 360 336 96 ) ( 352 336 96 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 0 0 0 +( 360 336 104 ) ( 360 304 104 ) ( 360 336 48 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 134 +{ +brushDef +{ +( 364 304 72 ) ( 364 336 72 ) ( 356 336 72 ) ( ( 0 0.015625 9.437500 ) ( -0.015625 0 -1.500000 ) ) gothic_trim/wood2 0 0 0 +( 356 336 80 ) ( 364 336 80 ) ( 364 304 80 ) ( ( 0 -0.015625 9.437500 ) ( 0.015625 0 1.500000 ) ) gothic_trim/wood2 0 0 0 +( 356 336 128 ) ( 356 304 128 ) ( 356 304 72 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 356 304 80 ) ( 364 304 80 ) ( 364 304 24 ) ( ( 0.015625 0 11.437500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 364 304 80 ) ( 364 336 80 ) ( 364 336 24 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 364 336 80 ) ( 356 336 80 ) ( 356 336 24 ) ( ( 0.015625 0 -11.437500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 135 +{ +brushDef +{ +( 368 304 48 ) ( 368 312 48 ) ( 360 312 48 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 0 0 0 +( 352 312 104 ) ( 352 304 104 ) ( 360 304 48 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 0 0 0 +( 360 304 80 ) ( 368 304 80 ) ( 368 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 304 104 ) ( 360 312 104 ) ( 368 312 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 0 0 0 +( 368 312 80 ) ( 360 312 80 ) ( 360 312 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 364 328 72 ) ( 364 296 72 ) ( 356 328 72 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 136 +{ +brushDef +{ +( 352 312 104 ) ( 352 304 104 ) ( 360 304 48 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 0 0 0 +( 360 304 80 ) ( 368 304 80 ) ( 368 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 304 104 ) ( 360 312 104 ) ( 368 312 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 0 0 0 +( 368 312 80 ) ( 360 312 80 ) ( 360 312 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 336 96 ) ( 360 304 96 ) ( 352 336 96 ) ( ( 0 -0.015625 9.500000 ) ( 0.015625 0 1.750000 ) ) gothic_trim/wood2 0 0 0 +( 364 328 80 ) ( 356 328 80 ) ( 364 296 80 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 137 +{ +brushDef +{ +( 360 304 80 ) ( 368 304 80 ) ( 368 304 48 ) ( ( 0.015625 0 11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 360 304 104 ) ( 360 312 104 ) ( 368 312 48 ) ( ( 0.015625 0 -4.500000 ) ( 0 0.015625 1.626346 ) ) gothic_trim/wood2 0 0 0 +( 368 312 80 ) ( 360 312 80 ) ( 360 312 48 ) ( ( 0.015625 0 -11.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 364 296 72 ) ( 364 328 72 ) ( 356 328 72 ) ( ( 0 0.015625 9.500000 ) ( -0.015625 0 -1.750000 ) ) gothic_trim/wood2 0 0 0 +( 364 328 80 ) ( 364 296 80 ) ( 364 328 24 ) ( ( 0.015625 0 4.500000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 138 +{ +brushDef +{ +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 104 ) ( 456 216 104 ) ( 456 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 472 220 72 ) ( 440 220 72 ) ( 440 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 220 80 ) ( 472 220 80 ) ( 440 220 24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 139 +{ +brushDef +{ +( 456 208 104 ) ( 464 208 104 ) ( 464 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 212 80 ) ( 440 220 80 ) ( 472 220 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 472 212 128 ) ( 440 212 128 ) ( 472 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 140 +{ +brushDef +{ +( 456 208 104 ) ( 464 208 104 ) ( 464 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 104 ) ( 456 216 104 ) ( 456 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 216 96 ) ( 464 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 220 80 ) ( 440 212 80 ) ( 472 220 80 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 141 +{ +brushDef +{ +( 464 224 48 ) ( 456 224 48 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 208 104 ) ( 464 208 104 ) ( 464 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 104 ) ( 456 216 104 ) ( 456 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 220 72 ) ( 472 220 72 ) ( 440 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 142 +{ +brushDef +{ +( 464 220 72 ) ( 432 220 72 ) ( 432 212 72 ) ( ( 0.015625 0 -0.062500 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 212 80 ) ( 432 220 80 ) ( 464 220 80 ) ( ( 0.015625 0 -0.062500 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 212 128 ) ( 464 212 128 ) ( 464 212 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 464 212 80 ) ( 464 220 80 ) ( 464 220 24 ) ( ( 0.015625 0 -0.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 464 220 80 ) ( 432 220 80 ) ( 432 220 24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +( 432 220 80 ) ( 432 212 80 ) ( 432 212 24 ) ( ( 0.015625 0 0.062500 ) ( 0 0.015625 -0.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 143 +{ +brushDef +{ +( 440 216 80 ) ( 440 224 80 ) ( 440 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 216 104 ) ( 432 216 104 ) ( 432 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 224 80 ) ( 432 216 80 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 96 ) ( 432 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 216 104 ) ( 464 216 104 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 144 +{ +brushDef +{ +( 464 216 80 ) ( 464 224 80 ) ( 464 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 104 ) ( 456 216 104 ) ( 456 224 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 224 80 ) ( 456 216 80 ) ( 456 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 96 ) ( 432 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 216 104 ) ( 464 216 104 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 145 +{ +brushDef +{ +( 464 216 96 ) ( 432 216 96 ) ( 432 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 208 104 ) ( 432 216 104 ) ( 464 216 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 208 152 ) ( 464 208 152 ) ( 464 208 96 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 208 104 ) ( 464 216 104 ) ( 464 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 104 ) ( 432 216 104 ) ( 432 216 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 216 104 ) ( 432 208 104 ) ( 432 208 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 146 +{ +brushDef +{ +( 464 256 8 ) ( 464 248 8 ) ( 472 248 8 ) ( ( 0 -0.015625 -3.625000 ) ( 0.015625 0 -10.875000 ) ) gothic_trim/wood2 0 0 0 +( 464 240 40 ) ( 456 240 40 ) ( 456 248 40 ) ( ( 0 0.015625 -3.625000 ) ( -0.015625 0 10.875000 ) ) gothic_trim/wood2 0 0 0 +( 472 256 8 ) ( 472 248 8 ) ( 464 240 40 ) ( ( 0.015625 0 -9.625000 ) ( 0 0.015625 -1.367998 ) ) gothic_trim/wood2 0 0 0 +( 456 256 8 ) ( 464 256 8 ) ( 464 248 40 ) ( ( 0.015625 0 5.125000 ) ( 0 0.015625 -2.459404 ) ) gothic_trim/wood2 0 0 0 +( 464 248 8 ) ( 464 256 8 ) ( 456 248 40 ) ( ( 0.015625 0 9.625000 ) ( 0 0.015625 -1.367999 ) ) gothic_trim/wood2 0 0 0 +( 464 248 8 ) ( 456 248 8 ) ( 456 240 40 ) ( ( 0.015625 0 -5.125000 ) ( 0 0.015625 -2.459402 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 147 +{ +brushDef +{ +( 424 248 8 ) ( 432 248 8 ) ( 432 256 8 ) ( ( -0.015625 0 7.500000 ) ( 0 -0.015625 -13.500000 ) ) gothic_trim/wood2 0 0 0 +( 440 248 40 ) ( 440 240 40 ) ( 432 240 40 ) ( ( -0.015625 0 7.500000 ) ( 0 -0.015625 13.500000 ) ) gothic_trim/wood2 0 0 0 +( 424 256 8 ) ( 432 256 8 ) ( 440 248 40 ) ( ( 0.015625 0 -6.500000 ) ( 0 0.015625 -3.823671 ) ) gothic_trim/wood2 0 0 0 +( 424 240 8 ) ( 424 248 8 ) ( 432 248 40 ) ( ( 0.015625 0 15.250000 ) ( 0 0.015625 -1.701477 ) ) gothic_trim/wood2 0 0 0 +( 432 248 8 ) ( 424 248 8 ) ( 432 240 40 ) ( ( 0.015625 0 6.500000 ) ( 0 0.015625 -3.823672 ) ) gothic_trim/wood2 0 0 0 +( 432 248 8 ) ( 432 240 8 ) ( 440 240 40 ) ( ( 0.015625 0 -15.250000 ) ( 0 0.015625 -1.701478 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 148 +{ +brushDef +{ +( 432 208 8 ) ( 432 216 8 ) ( 424 216 8 ) ( ( 0 0.015625 10.125000 ) ( -0.015625 0 -3.625000 ) ) gothic_trim/wood2 0 0 0 +( 432 224 40 ) ( 440 224 40 ) ( 440 216 40 ) ( ( 0 -0.015625 10.125000 ) ( 0.015625 0 3.625000 ) ) gothic_trim/wood2 0 0 0 +( 424 208 8 ) ( 424 216 8 ) ( 432 224 40 ) ( ( 0.015625 0 3.625000 ) ( 0 0.015625 -2.762575 ) ) gothic_trim/wood2 0 0 0 +( 440 208 8 ) ( 432 208 8 ) ( 432 216 40 ) ( ( 0.015625 0 10.875000 ) ( 0 0.015625 0.754196 ) ) gothic_trim/wood2 0 0 0 +( 432 216 8 ) ( 432 208 8 ) ( 440 216 40 ) ( ( 0.015625 0 -3.625000 ) ( 0 0.015625 -2.762575 ) ) gothic_trim/wood2 0 0 0 +( 432 216 8 ) ( 440 216 8 ) ( 440 224 40 ) ( ( 0.015625 0 -10.875000 ) ( 0 0.015625 0.754195 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 149 +{ +brushDef +{ +( 472 216 8 ) ( 464 216 8 ) ( 464 208 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 216 40 ) ( 456 224 40 ) ( 464 224 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 472 208 8 ) ( 464 208 8 ) ( 456 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.125000 ) ) gothic_trim/wood2 0 0 0 +( 472 224 8 ) ( 472 216 8 ) ( 464 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.125000 ) ) gothic_trim/wood2 0 0 0 +( 464 216 8 ) ( 472 216 8 ) ( 464 224 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.125000 ) ) gothic_trim/wood2 0 0 0 +( 464 216 8 ) ( 464 224 8 ) ( 456 224 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 150 +{ +brushDef +{ +( 456 248 40 ) ( 432 248 40 ) ( 432 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 216 48 ) ( 432 248 48 ) ( 456 248 48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 216 48 ) ( 456 216 48 ) ( 456 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 464 216 48 ) ( 464 248 48 ) ( 464 248 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 248 48 ) ( 432 248 48 ) ( 432 248 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 432 248 48 ) ( 432 216 48 ) ( 432 216 40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 151 +{ +brushDef +{ +( 336 256 288 ) ( 0 256 288 ) ( 0 136 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 136 296 ) ( 0 256 296 ) ( 336 256 296 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 136 296 ) ( 336 136 296 ) ( 336 136 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 512 128 296 ) ( 512 248 296 ) ( 512 248 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 336 256 296 ) ( 0 256 296 ) ( 0 256 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 256 296 ) ( 0 136 296 ) ( 0 136 288 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 152 +{ +brushDef +{ +( 632 96 288 ) ( 512 96 288 ) ( 512 40 288 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 4.937803 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 512 8 296 ) ( 512 64 296 ) ( 632 64 296 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 -4.937810 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 544 136 296 ) ( 664 136 296 ) ( 664 136 -208 ) ( ( 0.007813 0 -4.937810 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 632 8 296 ) ( 632 64 296 ) ( 632 64 -208 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 632 448 296 ) ( 512 448 296 ) ( 512 448 -208 ) ( ( 0.007812 0 4.937197 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 512 64 296 ) ( 512 8 296 ) ( 512 8 -208 ) ( ( 0.007813 0 -2.937500 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 153 +{ +brushDef +{ +( 0 96 288 ) ( -120 96 288 ) ( -120 40 288 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -120 8 296 ) ( -120 64 296 ) ( 0 64 296 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -88 136 296 ) ( 32 136 296 ) ( 32 136 -208 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 8 296 ) ( 0 64 296 ) ( 0 64 -208 ) ( ( 0.007813 0 2.937500 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 0 448 296 ) ( -120 448 296 ) ( -120 448 -208 ) ( ( 0.007812 0 0 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -120 64 296 ) ( -120 8 296 ) ( -120 8 -208 ) ( ( 0.007813 0 -2.937500 ) ( 0 0.007813 -1.687500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 154 +{ +brushDef +{ +( 48 680 8 ) ( 32 680 8 ) ( 32 664 8 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 -1.000055 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 32 664 512 ) ( 32 680 512 ) ( 48 680 512 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 1.000055 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 24 664 112 ) ( 40 664 112 ) ( 40 664 104 ) ( ( 0.007813 0 1.000055 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 40 664 112 ) ( 40 680 112 ) ( 40 680 104 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 40 680 112 ) ( 24 680 112 ) ( 24 680 104 ) ( ( 0.007813 0 -1.000055 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 24 680 112 ) ( 24 664 112 ) ( 24 664 104 ) ( ( 0.007813 0 2.000125 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 155 +{ +brushDef +{ +( 496 680 8 ) ( 480 680 8 ) ( 480 664 8 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 2.500159 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 480 664 512 ) ( 480 680 512 ) ( 496 680 512 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 -2.500159 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 472 664 112 ) ( 488 664 112 ) ( 488 664 104 ) ( ( 0.007813 0 -2.500159 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 488 664 112 ) ( 488 680 112 ) ( 488 680 104 ) ( ( 0.007813 0 -2.000125 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 488 680 112 ) ( 472 680 112 ) ( 472 680 104 ) ( ( 0.007813 0 2.500159 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 472 680 112 ) ( 472 664 112 ) ( 472 664 104 ) ( ( 0.007813 0 2.000125 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 156 +{ +brushDef +{ +( 368 424 8 ) ( 352 424 8 ) ( 352 408 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 1.500098 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 352 408 512 ) ( 352 424 512 ) ( 368 424 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.500098 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 344 408 112 ) ( 360 408 112 ) ( 360 408 104 ) ( ( 0.007813 0 -1.500098 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 360 408 112 ) ( 360 424 112 ) ( 360 424 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 360 424 112 ) ( 344 424 112 ) ( 344 424 104 ) ( ( 0.007813 0 1.500098 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 344 424 112 ) ( 344 408 112 ) ( 344 408 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 157 +{ +brushDef +{ +( 176 424 8 ) ( 160 424 8 ) ( 160 408 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 160 408 512 ) ( 160 424 512 ) ( 176 424 512 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 152 408 112 ) ( 168 408 112 ) ( 168 408 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 168 408 112 ) ( 168 424 112 ) ( 168 424 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 168 424 112 ) ( 152 424 112 ) ( 152 424 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 152 424 112 ) ( 152 408 112 ) ( 152 408 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 158 +{ +brushDef +{ +( 640 968 0 ) ( 336 968 0 ) ( 336 960 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 336 960 512 ) ( 336 968 512 ) ( 640 968 512 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -96 960 512 ) ( 208 960 512 ) ( 208 960 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 960 512 ) ( 640 968 512 ) ( 640 968 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 968 512 ) ( 336 968 512 ) ( 336 968 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 944 512 ) ( -128 936 512 ) ( -128 936 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 159 +{ +brushDef +{ +( 640 600 8 ) ( 640 632 8 ) ( 632 632 8 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 640 512 ) ( 640 640 512 ) ( 640 608 512 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 632 640 512 ) ( 632 608 512 ) ( 632 608 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 512 512 ) ( 640 512 512 ) ( 640 512 8 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 512 512 ) ( 640 544 512 ) ( 640 544 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 512 ) ( 632 640 512 ) ( 632 640 8 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 160 +{ +brushDef +{ +( 640 192 8 ) ( 640 512 8 ) ( 632 512 8 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 136 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 640 456 16 ) ( 640 456 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 512 208 ) ( 632 512 208 ) ( 632 512 200 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 480 104 ) ( 640 376 104 ) ( 632 480 104 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 161 +{ +brushDef +{ +( 632 512 512 ) ( 640 512 512 ) ( 640 192 512 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 136 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 640 456 16 ) ( 640 456 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 512 208 ) ( 632 512 208 ) ( 632 512 200 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 480 232 ) ( 632 480 232 ) ( 640 376 232 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 162 +{ +brushDef +{ +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 192 16 ) ( 640 512 16 ) ( 640 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 512 208 ) ( 632 512 208 ) ( 632 512 200 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 376 104 ) ( 640 480 104 ) ( 632 480 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 480 232 ) ( 640 480 232 ) ( 640 376 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 632 480 128 ) ( 640 480 128 ) ( 632 480 104 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 163 +{ +brushDef +{ +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 136 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 640 456 16 ) ( 640 456 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 376 104 ) ( 640 480 104 ) ( 632 480 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 480 232 ) ( 640 480 232 ) ( 640 376 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 640 224 128 ) ( 632 224 128 ) ( 640 224 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 164 +{ +brushDef +{ +( 632 512 16 ) ( 632 192 16 ) ( 632 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 192 16 ) ( 640 512 16 ) ( 640 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 376 104 ) ( 640 480 104 ) ( 632 480 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 480 232 ) ( 640 480 232 ) ( 640 376 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 640 376 128 ) ( 632 376 128 ) ( 640 376 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 328 128 ) ( 640 328 128 ) ( 632 328 104 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 165 +{ +brushDef +{ +( 640 640 8 ) ( 640 960 8 ) ( 632 960 8 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 640 208 ) ( 640 640 208 ) ( 640 640 200 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 960 16 ) ( 632 960 16 ) ( 632 960 8 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 776 104 ) ( 648 672 104 ) ( 640 776 104 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 166 +{ +brushDef +{ +( 632 960 512 ) ( 640 960 512 ) ( 640 640 512 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 640 208 ) ( 640 640 208 ) ( 640 640 200 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 960 16 ) ( 632 960 16 ) ( 632 960 8 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 776 232 ) ( 640 776 232 ) ( 648 672 232 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 167 +{ +brushDef +{ +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 640 208 ) ( 640 640 208 ) ( 640 640 200 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 672 104 ) ( 648 776 104 ) ( 640 776 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 640 776 232 ) ( 648 776 232 ) ( 648 672 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 648 672 128 ) ( 640 672 128 ) ( 648 672 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 168 +{ +brushDef +{ +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 672 104 ) ( 648 776 104 ) ( 640 776 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 640 776 232 ) ( 648 776 232 ) ( 648 672 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 640 776 128 ) ( 648 776 128 ) ( 640 776 104 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 824 128 ) ( 640 824 128 ) ( 648 824 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 169 +{ +brushDef +{ +( 632 960 16 ) ( 632 640 16 ) ( 632 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 640 16 ) ( 640 960 16 ) ( 640 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 960 16 ) ( 632 960 16 ) ( 632 960 8 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 648 672 104 ) ( 648 776 104 ) ( 640 776 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 640 776 232 ) ( 648 776 232 ) ( 648 672 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 640 928 128 ) ( 648 928 128 ) ( 640 928 104 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 170 +{ +brushDef +{ +( 632 824 176 ) ( 640 824 176 ) ( 640 824 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 3.000001 ) ) gothic_trim/wood2 0 0 0 +( 640 928 168 ) ( 640 928 176 ) ( 632 928 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.999999 ) ) gothic_trim/wood2 0 0 0 +( 640 824 168 ) ( 632 824 168 ) ( 632 800 168 ) ( ( 0 -0.015625 -14.500000 ) ( 0.015625 0 -8.375000 ) ) gothic_trim/wood2 0 0 0 +( 632 832 168 ) ( 632 832 176 ) ( 632 808 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -12.375000 ) ) gothic_trim/wood2 0 0 0 +( 632 824 176 ) ( 640 824 176 ) ( 640 800 176 ) ( ( 0 -0.015625 14.500000 ) ( 0.015625 0 -8.375000 ) ) gothic_trim/wood2 0 0 0 +( 640 848 176 ) ( 640 848 168 ) ( 640 824 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -12.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 171 +{ +brushDef +{ +( 640 872 104 ) ( 640 880 104 ) ( 632 880 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( 632 880 128 ) ( 632 872 128 ) ( 632 872 104 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 872 136 ) ( 640 872 136 ) ( 640 872 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 872 128 ) ( 640 880 128 ) ( 640 880 104 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 880 128 ) ( 632 880 128 ) ( 632 880 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 824 168 ) ( 640 824 168 ) ( 632 800 168 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 172 +{ +brushDef +{ +( 632 880 232 ) ( 640 880 232 ) ( 640 872 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( 632 880 128 ) ( 632 872 128 ) ( 632 872 104 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 872 136 ) ( 640 872 136 ) ( 640 872 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 872 128 ) ( 640 880 128 ) ( 640 880 104 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 880 128 ) ( 632 880 128 ) ( 632 880 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 824 176 ) ( 632 824 176 ) ( 640 800 176 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 173 +{ +brushDef +{ +( 632 728 232 ) ( 640 728 232 ) ( 640 720 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -7.375000 ) ) gothic_trim/wood2 0 0 0 +( 632 728 128 ) ( 632 720 128 ) ( 632 720 104 ) ( ( 0.015625 0 6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 720 136 ) ( 640 720 136 ) ( 640 720 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 720 128 ) ( 640 728 128 ) ( 640 728 104 ) ( ( 0.015625 0 -6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 728 128 ) ( 632 728 128 ) ( 632 728 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 672 176 ) ( 632 672 176 ) ( 640 648 176 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 7.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 174 +{ +brushDef +{ +( 640 720 104 ) ( 640 728 104 ) ( 632 728 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 7.375000 ) ) gothic_trim/wood2 0 0 0 +( 632 728 128 ) ( 632 720 128 ) ( 632 720 104 ) ( ( 0.015625 0 6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 720 136 ) ( 640 720 136 ) ( 640 720 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 720 128 ) ( 640 728 128 ) ( 640 728 104 ) ( ( 0.015625 0 -6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 728 128 ) ( 632 728 128 ) ( 632 728 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 672 168 ) ( 640 672 168 ) ( 632 648 168 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -7.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 175 +{ +brushDef +{ +( 632 672 176 ) ( 640 672 176 ) ( 640 672 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 3.000001 ) ) gothic_trim/wood2 0 0 0 +( 640 776 168 ) ( 640 776 176 ) ( 632 776 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.999999 ) ) gothic_trim/wood2 0 0 0 +( 640 672 168 ) ( 632 672 168 ) ( 632 648 168 ) ( ( 0 -0.015625 -14.500000 ) ( 0.015625 0 -10.750000 ) ) gothic_trim/wood2 0 0 0 +( 632 680 168 ) ( 632 680 176 ) ( 632 656 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -10 ) ) gothic_trim/wood2 0 0 0 +( 632 672 176 ) ( 640 672 176 ) ( 640 648 176 ) ( ( 0 -0.015625 14.500000 ) ( 0.015625 0 -10.750000 ) ) gothic_trim/wood2 0 0 0 +( 640 696 176 ) ( 640 696 168 ) ( 640 672 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -10 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 176 +{ +brushDef +{ +( 632 376 176 ) ( 640 376 176 ) ( 640 376 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 3.000001 ) ) gothic_trim/wood2 0 0 0 +( 640 480 168 ) ( 640 480 176 ) ( 632 480 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.999999 ) ) gothic_trim/wood2 0 0 0 +( 640 376 168 ) ( 632 376 168 ) ( 632 352 168 ) ( ( 0 -0.015625 -14.500000 ) ( 0.015625 0 -15.375000 ) ) gothic_trim/wood2 0 0 0 +( 632 384 168 ) ( 632 384 176 ) ( 632 360 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -5.375000 ) ) gothic_trim/wood2 0 0 0 +( 632 376 176 ) ( 640 376 176 ) ( 640 352 176 ) ( ( 0 -0.015625 14.500000 ) ( 0.015625 0 -15.375000 ) ) gothic_trim/wood2 0 0 0 +( 640 400 176 ) ( 640 400 168 ) ( 640 376 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -5.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 177 +{ +brushDef +{ +( 640 424 104 ) ( 640 432 104 ) ( 632 432 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 12 ) ) gothic_trim/wood2 0 0 0 +( 632 432 128 ) ( 632 424 128 ) ( 632 424 104 ) ( ( 0.015625 0 2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 424 136 ) ( 640 424 136 ) ( 640 424 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 424 128 ) ( 640 432 128 ) ( 640 432 104 ) ( ( 0.015625 0 -2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 432 128 ) ( 632 432 128 ) ( 632 432 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 376 168 ) ( 640 376 168 ) ( 632 352 168 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -12 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 178 +{ +brushDef +{ +( 632 432 232 ) ( 640 432 232 ) ( 640 424 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -12 ) ) gothic_trim/wood2 0 0 0 +( 632 432 128 ) ( 632 424 128 ) ( 632 424 104 ) ( ( 0.015625 0 2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 424 136 ) ( 640 424 136 ) ( 640 424 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 424 128 ) ( 640 432 128 ) ( 640 432 104 ) ( ( 0.015625 0 -2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 432 128 ) ( 632 432 128 ) ( 632 432 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 376 176 ) ( 632 376 176 ) ( 640 352 176 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 12 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 179 +{ +brushDef +{ +( 632 280 232 ) ( 640 280 232 ) ( 640 272 232 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -14.375000 ) ) gothic_trim/wood2 0 0 0 +( 632 280 128 ) ( 632 272 128 ) ( 632 272 104 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 272 136 ) ( 640 272 136 ) ( 640 272 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 272 128 ) ( 640 280 128 ) ( 640 280 104 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 280 128 ) ( 632 280 128 ) ( 632 280 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 224 176 ) ( 632 224 176 ) ( 640 200 176 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 14.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 180 +{ +brushDef +{ +( 640 272 104 ) ( 640 280 104 ) ( 632 280 104 ) ( ( 0 0.015625 11.875000 ) ( -0.015625 0 14.375000 ) ) gothic_trim/wood2 0 0 0 +( 632 280 128 ) ( 632 272 128 ) ( 632 272 104 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 272 136 ) ( 640 272 136 ) ( 640 272 112 ) ( ( 0.015625 0 0.375002 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 272 128 ) ( 640 280 128 ) ( 640 280 104 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 280 128 ) ( 632 280 128 ) ( 632 280 104 ) ( ( 0.015625 0 -0.374998 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 224 168 ) ( 640 224 168 ) ( 632 200 168 ) ( ( 0 -0.015625 11.875000 ) ( 0.015625 0 -14.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 181 +{ +brushDef +{ +( 632 224 176 ) ( 640 224 176 ) ( 640 224 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 3.000001 ) ) gothic_trim/wood2 0 0 0 +( 640 328 168 ) ( 640 328 176 ) ( 632 328 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.999999 ) ) gothic_trim/wood2 0 0 0 +( 640 224 168 ) ( 632 224 168 ) ( 632 200 168 ) ( ( 0 -0.015625 -14.500000 ) ( 0.015625 0 -17.750000 ) ) gothic_trim/wood2 0 0 0 +( 632 232 168 ) ( 632 232 176 ) ( 632 208 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -3 ) ) gothic_trim/wood2 0 0 0 +( 632 224 176 ) ( 640 224 176 ) ( 640 200 176 ) ( ( 0 -0.015625 14.500000 ) ( 0.015625 0 -17.750000 ) ) gothic_trim/wood2 0 0 0 +( 640 248 176 ) ( 640 248 168 ) ( 640 224 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -3 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 182 +{ +brushDef +{ +( -120 616 8 ) ( -120 648 8 ) ( -128 648 8 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 640 512 ) ( -120 640 512 ) ( -120 608 512 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -128 640 512 ) ( -128 608 512 ) ( -128 608 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 512 512 ) ( -120 512 512 ) ( -120 512 8 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 512 512 ) ( -120 544 512 ) ( -120 544 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 512 ) ( -128 640 512 ) ( -128 640 8 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 183 +{ +brushDef +{ +( -120 192 8 ) ( -120 512 8 ) ( -128 512 8 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -120 136 16 ) ( -120 136 8 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 136 16 ) ( -120 456 16 ) ( -120 456 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 512 208 ) ( -128 512 208 ) ( -128 512 200 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 480 104 ) ( -120 376 104 ) ( -128 480 104 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 184 +{ +brushDef +{ +( -128 512 512 ) ( -120 512 512 ) ( -120 192 512 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -120 136 16 ) ( -120 136 8 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 192 16 ) ( -120 512 16 ) ( -120 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 512 208 ) ( -128 512 208 ) ( -128 512 200 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 480 232 ) ( -128 480 232 ) ( -120 376 232 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 185 +{ +brushDef +{ +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 192 16 ) ( -120 512 16 ) ( -120 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 512 208 ) ( -128 512 208 ) ( -128 512 200 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 376 104 ) ( -120 480 104 ) ( -128 480 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 480 232 ) ( -120 480 232 ) ( -120 376 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -128 480 128 ) ( -120 480 128 ) ( -128 480 104 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 186 +{ +brushDef +{ +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -120 136 16 ) ( -120 136 8 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 192 16 ) ( -120 512 16 ) ( -120 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 376 104 ) ( -120 480 104 ) ( -128 480 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 480 232 ) ( -120 480 232 ) ( -120 376 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -120 224 128 ) ( -128 224 128 ) ( -120 224 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 187 +{ +brushDef +{ +( -128 512 16 ) ( -128 192 16 ) ( -128 192 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 192 16 ) ( -120 512 16 ) ( -120 512 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 376 104 ) ( -120 480 104 ) ( -128 480 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 480 232 ) ( -120 480 232 ) ( -120 376 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -120 376 128 ) ( -128 376 128 ) ( -120 376 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 328 128 ) ( -120 328 128 ) ( -128 328 104 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 188 +{ +brushDef +{ +( -120 640 8 ) ( -120 960 8 ) ( -128 960 8 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 640 208 ) ( -120 640 208 ) ( -120 640 200 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 960 16 ) ( -128 960 16 ) ( -128 960 8 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 776 104 ) ( -112 672 104 ) ( -120 776 104 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 189 +{ +brushDef +{ +( -128 960 512 ) ( -120 960 512 ) ( -120 640 512 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 640 208 ) ( -120 640 208 ) ( -120 640 200 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 960 16 ) ( -128 960 16 ) ( -128 960 8 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 776 232 ) ( -120 776 232 ) ( -112 672 232 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 190 +{ +brushDef +{ +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 640 208 ) ( -120 640 208 ) ( -120 640 200 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 672 104 ) ( -112 776 104 ) ( -120 776 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -120 776 232 ) ( -112 776 232 ) ( -112 672 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -112 672 128 ) ( -120 672 128 ) ( -112 672 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 191 +{ +brushDef +{ +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 672 104 ) ( -112 776 104 ) ( -120 776 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -120 776 232 ) ( -112 776 232 ) ( -112 672 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -120 776 128 ) ( -112 776 128 ) ( -120 776 104 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 824 128 ) ( -120 824 128 ) ( -112 824 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 192 +{ +brushDef +{ +( -128 960 16 ) ( -128 640 16 ) ( -128 640 8 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 640 16 ) ( -120 960 16 ) ( -120 960 8 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 960 16 ) ( -128 960 16 ) ( -128 960 8 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -112 672 104 ) ( -112 776 104 ) ( -120 776 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -120 776 232 ) ( -112 776 232 ) ( -112 672 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -120 928 128 ) ( -112 928 128 ) ( -120 928 104 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 193 +{ +brushDef +{ +( -128 824 176 ) ( -120 824 176 ) ( -120 824 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 14.875021 ) ) gothic_trim/wood2 0 0 0 +( -120 928 168 ) ( -120 928 176 ) ( -128 928 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -14.874980 ) ) gothic_trim/wood2 0 0 0 +( -120 824 168 ) ( -128 824 168 ) ( -128 800 168 ) ( ( 0 -0.015625 -2.625000 ) ( 0.015625 0 -8.375000 ) ) gothic_trim/wood2 0 0 0 +( -128 832 168 ) ( -128 832 176 ) ( -128 808 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -12.375000 ) ) gothic_trim/wood2 0 0 0 +( -128 824 176 ) ( -120 824 176 ) ( -120 800 176 ) ( ( 0 -0.015625 2.625000 ) ( 0.015625 0 -8.375000 ) ) gothic_trim/wood2 0 0 0 +( -120 848 176 ) ( -120 848 168 ) ( -120 824 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -12.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 194 +{ +brushDef +{ +( -120 872 104 ) ( -120 880 104 ) ( -128 880 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +( -128 880 128 ) ( -128 872 128 ) ( -128 872 104 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 872 136 ) ( -120 872 136 ) ( -120 872 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 872 128 ) ( -120 880 128 ) ( -120 880 104 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 880 128 ) ( -128 880 128 ) ( -128 880 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 824 168 ) ( -120 824 168 ) ( -128 800 168 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 195 +{ +brushDef +{ +( -128 880 232 ) ( -120 880 232 ) ( -120 872 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -5 ) ) gothic_trim/wood2 0 0 0 +( -128 880 128 ) ( -128 872 128 ) ( -128 872 104 ) ( ( 0.015625 0 9.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 872 136 ) ( -120 872 136 ) ( -120 872 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 872 128 ) ( -120 880 128 ) ( -120 880 104 ) ( ( 0.015625 0 -9.250001 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 880 128 ) ( -128 880 128 ) ( -128 880 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 824 176 ) ( -128 824 176 ) ( -120 800 176 ) ( ( 0 0.015625 0 ) ( -0.015625 0 5 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 196 +{ +brushDef +{ +( -128 728 232 ) ( -120 728 232 ) ( -120 720 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -7.375000 ) ) gothic_trim/wood2 0 0 0 +( -128 728 128 ) ( -128 720 128 ) ( -128 720 104 ) ( ( 0.015625 0 6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 720 136 ) ( -120 720 136 ) ( -120 720 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 720 128 ) ( -120 728 128 ) ( -120 728 104 ) ( ( 0.015625 0 -6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 728 128 ) ( -128 728 128 ) ( -128 728 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 672 176 ) ( -128 672 176 ) ( -120 648 176 ) ( ( 0 0.015625 0 ) ( -0.015625 0 7.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 197 +{ +brushDef +{ +( -120 720 104 ) ( -120 728 104 ) ( -128 728 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 7.375000 ) ) gothic_trim/wood2 0 0 0 +( -128 728 128 ) ( -128 720 128 ) ( -128 720 104 ) ( ( 0.015625 0 6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 720 136 ) ( -120 720 136 ) ( -120 720 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 720 128 ) ( -120 728 128 ) ( -120 728 104 ) ( ( 0.015625 0 -6.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 728 128 ) ( -128 728 128 ) ( -128 728 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 672 168 ) ( -120 672 168 ) ( -128 648 168 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -7.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 198 +{ +brushDef +{ +( -128 672 176 ) ( -120 672 176 ) ( -120 672 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 14.875021 ) ) gothic_trim/wood2 0 0 0 +( -120 776 168 ) ( -120 776 176 ) ( -128 776 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -14.874980 ) ) gothic_trim/wood2 0 0 0 +( -120 672 168 ) ( -128 672 168 ) ( -128 648 168 ) ( ( 0 -0.015625 -2.625000 ) ( 0.015625 0 -10.750000 ) ) gothic_trim/wood2 0 0 0 +( -128 680 168 ) ( -128 680 176 ) ( -128 656 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -10 ) ) gothic_trim/wood2 0 0 0 +( -128 672 176 ) ( -120 672 176 ) ( -120 648 176 ) ( ( 0 -0.015625 2.625000 ) ( 0.015625 0 -10.750000 ) ) gothic_trim/wood2 0 0 0 +( -120 696 176 ) ( -120 696 168 ) ( -120 672 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -10 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 199 +{ +brushDef +{ +( -128 376 176 ) ( -120 376 176 ) ( -120 376 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 14.875021 ) ) gothic_trim/wood2 0 0 0 +( -120 480 168 ) ( -120 480 176 ) ( -128 480 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -14.874980 ) ) gothic_trim/wood2 0 0 0 +( -120 376 168 ) ( -128 376 168 ) ( -128 352 168 ) ( ( 0 -0.015625 -2.625000 ) ( 0.015625 0 -15.375000 ) ) gothic_trim/wood2 0 0 0 +( -128 384 168 ) ( -128 384 176 ) ( -128 360 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -5.375000 ) ) gothic_trim/wood2 0 0 0 +( -128 376 176 ) ( -120 376 176 ) ( -120 352 176 ) ( ( 0 -0.015625 2.625000 ) ( 0.015625 0 -15.375000 ) ) gothic_trim/wood2 0 0 0 +( -120 400 176 ) ( -120 400 168 ) ( -120 376 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -5.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 200 +{ +brushDef +{ +( -120 424 104 ) ( -120 432 104 ) ( -128 432 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 12 ) ) gothic_trim/wood2 0 0 0 +( -128 432 128 ) ( -128 424 128 ) ( -128 424 104 ) ( ( 0.015625 0 2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 424 136 ) ( -120 424 136 ) ( -120 424 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 424 128 ) ( -120 432 128 ) ( -120 432 104 ) ( ( 0.015625 0 -2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 432 128 ) ( -128 432 128 ) ( -128 432 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 376 168 ) ( -120 376 168 ) ( -128 352 168 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -12 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 201 +{ +brushDef +{ +( -128 432 232 ) ( -120 432 232 ) ( -120 424 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -12 ) ) gothic_trim/wood2 0 0 0 +( -128 432 128 ) ( -128 424 128 ) ( -128 424 104 ) ( ( 0.015625 0 2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 424 136 ) ( -120 424 136 ) ( -120 424 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 424 128 ) ( -120 432 128 ) ( -120 432 104 ) ( ( 0.015625 0 -2.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 432 128 ) ( -128 432 128 ) ( -128 432 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 376 176 ) ( -128 376 176 ) ( -120 352 176 ) ( ( 0 0.015625 0 ) ( -0.015625 0 12 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 202 +{ +brushDef +{ +( -128 280 232 ) ( -120 280 232 ) ( -120 272 232 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -14.375000 ) ) gothic_trim/wood2 0 0 0 +( -128 280 128 ) ( -128 272 128 ) ( -128 272 104 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 272 136 ) ( -120 272 136 ) ( -120 272 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 272 128 ) ( -120 280 128 ) ( -120 280 104 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 280 128 ) ( -128 280 128 ) ( -128 280 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 224 176 ) ( -128 224 176 ) ( -120 200 176 ) ( ( 0 0.015625 0 ) ( -0.015625 0 14.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 203 +{ +brushDef +{ +( -120 272 104 ) ( -120 280 104 ) ( -128 280 104 ) ( ( 0 0.015625 0 ) ( -0.015625 0 14.375000 ) ) gothic_trim/wood2 0 0 0 +( -128 280 128 ) ( -128 272 128 ) ( -128 272 104 ) ( ( 0.015625 0 -0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 272 136 ) ( -120 272 136 ) ( -120 272 112 ) ( ( 0.015625 0 12.250020 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 272 128 ) ( -120 280 128 ) ( -120 280 104 ) ( ( 0.015625 0 0.125000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 280 128 ) ( -128 280 128 ) ( -128 280 104 ) ( ( 0.015625 0 -12.249980 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 224 168 ) ( -120 224 168 ) ( -128 200 168 ) ( ( 0 -0.015625 0 ) ( 0.015625 0 -14.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 204 +{ +brushDef +{ +( -128 224 176 ) ( -120 224 176 ) ( -120 224 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 14.875021 ) ) gothic_trim/wood2 0 0 0 +( -120 328 168 ) ( -120 328 176 ) ( -128 328 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -14.874980 ) ) gothic_trim/wood2 0 0 0 +( -120 224 168 ) ( -128 224 168 ) ( -128 200 168 ) ( ( 0 -0.015625 -2.625000 ) ( 0.015625 0 -17.750000 ) ) gothic_trim/wood2 0 0 0 +( -128 232 168 ) ( -128 232 176 ) ( -128 208 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -3 ) ) gothic_trim/wood2 0 0 0 +( -128 224 176 ) ( -120 224 176 ) ( -120 200 176 ) ( ( 0 -0.015625 2.625000 ) ( 0.015625 0 -17.750000 ) ) gothic_trim/wood2 0 0 0 +( -120 248 176 ) ( -120 248 168 ) ( -120 224 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -3 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 205 +{ +brushDef +{ +( 384 952 176 ) ( 80 952 176 ) ( 80 920 176 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 104 920 184 ) ( 104 952 184 ) ( 408 952 184 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 104 920 184 ) ( 408 920 184 ) ( 408 920 -64 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562469 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 408 920 184 ) ( 408 952 184 ) ( 408 952 -64 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562469 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 408 952 184 ) ( 104 952 184 ) ( 104 952 -64 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562469 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 104 952 184 ) ( 104 920 184 ) ( 104 920 -64 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562469 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 206 +{ +brushDef +{ +( 384 952 112 ) ( 80 952 112 ) ( 80 920 112 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 104 920 120 ) ( 104 952 120 ) ( 408 952 120 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 104 920 120 ) ( 408 920 120 ) ( 408 920 -128 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.062500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 408 920 120 ) ( 408 952 120 ) ( 408 952 -128 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.062500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 408 952 120 ) ( 104 952 120 ) ( 104 952 -128 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.062500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 104 952 120 ) ( 104 920 120 ) ( 104 920 -128 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -1.062500 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 207 +{ +brushDef +{ +( 416 960 8 ) ( 96 960 8 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 256 ) ( 96 960 256 ) ( 416 960 256 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 104 ) ( 416 920 104 ) ( 416 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 104 ) ( 96 920 104 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 104 920 104 ) ( 104 960 104 ) ( 104 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 208 +{ +brushDef +{ +( 416 960 8 ) ( 96 960 8 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 256 ) ( 96 960 256 ) ( 416 960 256 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 920 104 ) ( 416 960 104 ) ( 416 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 104 ) ( 96 920 104 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 952 104 ) ( 416 952 104 ) ( 96 952 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 209 +{ +brushDef +{ +( 416 960 8 ) ( 96 960 8 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 256 ) ( 96 960 256 ) ( 416 960 256 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 104 ) ( 416 920 104 ) ( 416 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 920 104 ) ( 416 960 104 ) ( 416 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 408 960 104 ) ( 408 920 104 ) ( 408 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 210 +{ +brushDef +{ +( 96 920 256 ) ( 96 960 256 ) ( 416 960 256 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 104 ) ( 416 920 104 ) ( 416 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 920 104 ) ( 416 960 104 ) ( 416 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 104 ) ( 96 920 104 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 248 ) ( 96 920 248 ) ( 416 960 248 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 211 +{ +brushDef +{ +( 416 960 8 ) ( 96 960 8 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 920 104 ) ( 416 920 104 ) ( 416 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 920 104 ) ( 416 960 104 ) ( 416 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 416 960 104 ) ( 96 960 104 ) ( 96 960 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 104 ) ( 96 920 104 ) ( 96 920 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 96 960 16 ) ( 416 960 16 ) ( 96 920 16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 212 +{ +brushDef +{ +( 144 776 8 ) ( 144 792 8 ) ( -24 792 8 ) ( ( 0 0.007813 7.250462 ) ( -0.007813 0 2.000121 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 792 104 ) ( 144 792 104 ) ( 144 776 104 ) ( ( 0 -0.007813 7.250462 ) ( 0.007813 0 -2.000121 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 792 104 ) ( -24 776 104 ) ( -24 776 96 ) ( ( 0.007813 0 -3.500212 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 776 104 ) ( 144 776 104 ) ( 144 776 96 ) ( ( 0.007813 0 6.125393 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 536 768 104 ) ( 536 784 104 ) ( 536 784 96 ) ( ( 0.007813 0 3.500212 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 792 104 ) ( -24 792 104 ) ( -24 792 96 ) ( ( 0.007813 0 -6.125392 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 213 +{ +brushDef +{ +( -8 960 8 ) ( -24 960 8 ) ( -24 792 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -4.250261 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 792 104 ) ( -24 960 104 ) ( -8 960 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 4.250261 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 792 104 ) ( -8 792 104 ) ( -8 792 96 ) ( ( 0.007813 0 4.250261 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -8 792 104 ) ( -8 960 104 ) ( -8 960 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -8 960 104 ) ( -24 960 104 ) ( -24 960 96 ) ( ( 0.007813 0 -4.250261 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -24 960 104 ) ( -24 792 104 ) ( -24 792 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 214 +{ +brushDef +{ +( 536 960 8 ) ( 520 960 8 ) ( 520 792 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 520 792 104 ) ( 520 960 104 ) ( 536 960 104 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 520 792 104 ) ( 536 792 104 ) ( 536 792 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 536 792 104 ) ( 536 960 104 ) ( 536 960 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 536 960 104 ) ( 520 960 104 ) ( 520 960 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 520 960 104 ) ( 520 792 104 ) ( 520 792 96 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 215 +{ +brushDef +{ +( 272 832 104 ) ( 32 832 104 ) ( 32 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 0 0 0 +( 32 768 112 ) ( 32 832 112 ) ( 272 832 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 0 0 0 +( 32 768 112 ) ( 272 768 112 ) ( 272 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 0 0 0 +( 480 760 112 ) ( 480 824 112 ) ( 480 824 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 0 0 0 +( 272 832 112 ) ( 32 832 112 ) ( 32 832 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 0 0 0 +( 32 832 112 ) ( 32 768 112 ) ( 32 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) base_trim/pewter_spec 0 0 0 +} +} +// brush 216 +{ +brushDef +{ +( 544 960 104 ) ( 480 960 104 ) ( 480 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 5.500000 ) ) base_trim/pewter_spec 0 0 0 +( 480 768 112 ) ( 480 960 112 ) ( 544 960 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -5.500000 ) ) base_trim/pewter_spec 0 0 0 +( 480 768 112 ) ( 544 768 112 ) ( 544 768 104 ) ( ( 0.015625 0 -5.500000 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 0 0 0 +( 544 768 112 ) ( 544 960 112 ) ( 544 960 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 0 0 0 +( 544 960 112 ) ( 480 960 112 ) ( 480 960 104 ) ( ( 0.015625 0 5.500000 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 0 0 0 +( 480 960 112 ) ( 480 768 112 ) ( 480 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 0 0 0 +} +} +// brush 217 +{ +brushDef +{ +( 32 960 104 ) ( -32 960 104 ) ( -32 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2.500000 ) ) base_trim/pewter_spec 0 0 0 +( -32 768 112 ) ( -32 960 112 ) ( 32 960 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.500000 ) ) base_trim/pewter_spec 0 0 0 +( -32 768 112 ) ( 32 768 112 ) ( 32 768 104 ) ( ( 0.015625 0 2.500000 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 0 0 0 +( 32 768 112 ) ( 32 960 112 ) ( 32 960 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 0 0 0 +( 32 960 112 ) ( -32 960 112 ) ( -32 960 104 ) ( ( 0.015625 0 -2.500000 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 0 0 0 +( -32 960 112 ) ( -32 768 112 ) ( -32 768 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.625000 ) ) base_trim/pewter_spec 0 0 0 +} +} +// brush 218 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 440 512 8.000001 0 0 ) ( 440 512 36 0 0.687500 ) ( 440 512 64 0 1.375000 ) ) +( ( 440 504 8.000001 0.125000 0 ) ( 440 504 36 0.125000 0.687500 ) ( 440 504 64 0.125000 1.375000 ) ) +( ( 448 504 8.000001 0.250000 0 ) ( 448 504 36 0.250000 0.687500 ) ( 448 504 64 0.250000 1.375000 ) ) +( ( 456 504 8.000001 0.375000 0 ) ( 456 504 36 0.375000 0.687500 ) ( 456 504 64 0.375000 1.375000 ) ) +( ( 456 512 8.000001 0.500000 0 ) ( 456 512 36 0.500000 0.687500 ) ( 456 512 64 0.500000 1.375000 ) ) +( ( 456 520 8.000001 0.625000 0 ) ( 456 520 36 0.625000 0.687500 ) ( 456 520 64 0.625000 1.375000 ) ) +( ( 448 520 8.000001 0.750000 0 ) ( 448 520 36 0.750000 0.687500 ) ( 448 520 64 0.750000 1.375000 ) ) +( ( 440 520 8.000001 0.875000 0 ) ( 440 520 36 0.875000 0.687500 ) ( 440 520 64 0.875000 1.375000 ) ) +( ( 440 512 8.000001 1 0 ) ( 440 512 36 1 0.687500 ) ( 440 512 64 1 1.375000 ) ) +) + } + } +// brush 219 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 440 320 8.000001 0 0 ) ( 440 320 36 0 0.687500 ) ( 440 320 64 0 1.375000 ) ) +( ( 440 312 8.000001 0.125000 0 ) ( 440 312 36 0.125000 0.687500 ) ( 440 312 64 0.125000 1.375000 ) ) +( ( 448 312 8.000001 0.250000 0 ) ( 448 312 36 0.250000 0.687500 ) ( 448 312 64 0.250000 1.375000 ) ) +( ( 456 312 8.000001 0.375000 0 ) ( 456 312 36 0.375000 0.687500 ) ( 456 312 64 0.375000 1.375000 ) ) +( ( 456 320 8.000001 0.500000 0 ) ( 456 320 36 0.500000 0.687500 ) ( 456 320 64 0.500000 1.375000 ) ) +( ( 456 328 8.000001 0.625000 0 ) ( 456 328 36 0.625000 0.687500 ) ( 456 328 64 0.625000 1.375000 ) ) +( ( 448 328 8.000001 0.750000 0 ) ( 448 328 36 0.750000 0.687500 ) ( 448 328 64 0.750000 1.375000 ) ) +( ( 440 328 8.000001 0.875000 0 ) ( 440 328 36 0.875000 0.687500 ) ( 440 328 64 0.875000 1.375000 ) ) +( ( 440 320 8.000001 1 0 ) ( 440 320 36 1 0.687500 ) ( 440 320 64 1 1.375000 ) ) +) + } + } +// brush 220 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 56 320 8.000001 0 0 ) ( 56 320 36 0 0.687500 ) ( 56 320 64 0 1.375000 ) ) +( ( 56 312 8.000001 0.125000 0 ) ( 56 312 36 0.125000 0.687500 ) ( 56 312 64 0.125000 1.375000 ) ) +( ( 64 312 8.000001 0.250000 0 ) ( 64 312 36 0.250000 0.687500 ) ( 64 312 64 0.250000 1.375000 ) ) +( ( 72 312 8.000001 0.375000 0 ) ( 72 312 36 0.375000 0.687500 ) ( 72 312 64 0.375000 1.375000 ) ) +( ( 72 320 8.000001 0.500000 0 ) ( 72 320 36 0.500000 0.687500 ) ( 72 320 64 0.500000 1.375000 ) ) +( ( 72 328 8.000001 0.625000 0 ) ( 72 328 36 0.625000 0.687500 ) ( 72 328 64 0.625000 1.375000 ) ) +( ( 64 328 8.000001 0.750000 0 ) ( 64 328 36 0.750000 0.687500 ) ( 64 328 64 0.750000 1.375000 ) ) +( ( 56 328 8.000001 0.875000 0 ) ( 56 328 36 0.875000 0.687500 ) ( 56 328 64 0.875000 1.375000 ) ) +( ( 56 320 8.000001 1 0 ) ( 56 320 36 1 0.687500 ) ( 56 320 64 1 1.375000 ) ) +) + } + } +// brush 221 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 56 512 8.000001 0 0 ) ( 56 512 36 0 0.687500 ) ( 56 512 64 0 1.375000 ) ) +( ( 56 504 8.000001 0.125000 0 ) ( 56 504 36 0.125000 0.687500 ) ( 56 504 64 0.125000 1.375000 ) ) +( ( 64 504 8.000001 0.250000 0 ) ( 64 504 36 0.250000 0.687500 ) ( 64 504 64 0.250000 1.375000 ) ) +( ( 72 504 8.000001 0.375000 0 ) ( 72 504 36 0.375000 0.687500 ) ( 72 504 64 0.375000 1.375000 ) ) +( ( 72 512 8.000001 0.500000 0 ) ( 72 512 36 0.500000 0.687500 ) ( 72 512 64 0.500000 1.375000 ) ) +( ( 72 520 8.000001 0.625000 0 ) ( 72 520 36 0.625000 0.687500 ) ( 72 520 64 0.625000 1.375000 ) ) +( ( 64 520 8.000001 0.750000 0 ) ( 64 520 36 0.750000 0.687500 ) ( 64 520 64 0.750000 1.375000 ) ) +( ( 56 520 8.000001 0.875000 0 ) ( 56 520 36 0.875000 0.687500 ) ( 56 520 64 0.875000 1.375000 ) ) +( ( 56 512 8.000001 1 0 ) ( 56 512 36 1 0.687500 ) ( 56 512 64 1 1.375000 ) ) +) + } + } +// brush 222 +{ +brushDef +{ +( 608 128 176 ) ( 608 136 176 ) ( 608 136 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 2.625000 ) ) gothic_trim/wood2 0 0 0 +( 504 136 168 ) ( 504 136 176 ) ( 504 128 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.625000 ) ) gothic_trim/wood2 0 0 0 +( 608 136 168 ) ( 608 128 168 ) ( 632 128 168 ) ( ( -0.015625 0 -2.625000 ) ( 0 -0.015625 -12.750000 ) ) gothic_trim/wood2 0 0 0 +( 600 128 168 ) ( 600 128 176 ) ( 624 128 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 6.250000 ) ) gothic_trim/wood2 0 0 0 +( 608 128 176 ) ( 608 136 176 ) ( 632 136 176 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -12.750000 ) ) gothic_trim/wood2 0 0 0 +( 584 136 176 ) ( 584 136 168 ) ( 608 136 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 6.250000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 223 +{ +brushDef +{ +( 560 136 104 ) ( 552 136 104 ) ( 552 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.375000 ) ) gothic_trim/wood2 0 0 0 +( 552 128 128 ) ( 560 128 128 ) ( 560 128 104 ) ( ( 0.015625 0 -9.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 560 128 136 ) ( 560 136 136 ) ( 560 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 560 136 128 ) ( 552 136 128 ) ( 552 136 104 ) ( ( 0.015625 0 9.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 552 136 128 ) ( 552 128 128 ) ( 552 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 608 128 168 ) ( 608 136 168 ) ( 632 128 168 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 224 +{ +brushDef +{ +( 552 128 232 ) ( 552 136 232 ) ( 560 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.375000 ) ) gothic_trim/wood2 0 0 0 +( 552 128 128 ) ( 560 128 128 ) ( 560 128 104 ) ( ( 0.015625 0 -9.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 560 128 136 ) ( 560 136 136 ) ( 560 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 560 136 128 ) ( 552 136 128 ) ( 552 136 104 ) ( ( 0.015625 0 9.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 552 136 128 ) ( 552 128 128 ) ( 552 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 608 136 176 ) ( 608 128 176 ) ( 632 136 176 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 225 +{ +brushDef +{ +( 400 128 232 ) ( 400 136 232 ) ( 408 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7 ) ) gothic_trim/wood2 0 0 0 +( 400 128 128 ) ( 408 128 128 ) ( 408 128 104 ) ( ( 0.015625 0 -7 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 128 136 ) ( 408 136 136 ) ( 408 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 136 128 ) ( 400 136 128 ) ( 400 136 104 ) ( ( 0.015625 0 7 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 136 128 ) ( 400 128 128 ) ( 400 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 176 ) ( 456 128 176 ) ( 480 136 176 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 226 +{ +brushDef +{ +( 408 136 104 ) ( 400 136 104 ) ( 400 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7 ) ) gothic_trim/wood2 0 0 0 +( 400 128 128 ) ( 408 128 128 ) ( 408 128 104 ) ( ( 0.015625 0 -7 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 128 136 ) ( 408 136 136 ) ( 408 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 136 128 ) ( 400 136 128 ) ( 400 136 104 ) ( ( 0.015625 0 7 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 136 128 ) ( 400 128 128 ) ( 400 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 128 168 ) ( 456 136 168 ) ( 480 128 168 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 227 +{ +brushDef +{ +( 456 128 176 ) ( 456 136 176 ) ( 456 136 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 2.625000 ) ) gothic_trim/wood2 0 0 0 +( 352 136 168 ) ( 352 136 176 ) ( 352 128 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.625000 ) ) gothic_trim/wood2 0 0 0 +( 456 136 168 ) ( 456 128 168 ) ( 480 128 168 ) ( ( -0.015625 0 -2.625000 ) ( 0 -0.015625 -10.375000 ) ) gothic_trim/wood2 0 0 0 +( 448 128 168 ) ( 448 128 176 ) ( 472 128 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 3.875000 ) ) gothic_trim/wood2 0 0 0 +( 456 128 176 ) ( 456 136 176 ) ( 480 136 176 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -10.375000 ) ) gothic_trim/wood2 0 0 0 +( 432 136 176 ) ( 432 136 168 ) ( 456 136 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 3.875000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 228 +{ +brushDef +{ +( 160 128 176 ) ( 160 136 176 ) ( 160 136 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 2.625000 ) ) gothic_trim/wood2 0 0 0 +( 56 136 168 ) ( 56 136 176 ) ( 56 128 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.625000 ) ) gothic_trim/wood2 0 0 0 +( 160 136 168 ) ( 160 128 168 ) ( 184 128 168 ) ( ( -0.015625 0 -2.625000 ) ( 0 -0.015625 -5.750000 ) ) gothic_trim/wood2 0 0 0 +( 152 128 168 ) ( 152 128 176 ) ( 176 128 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -0.750000 ) ) gothic_trim/wood2 0 0 0 +( 160 128 176 ) ( 160 136 176 ) ( 184 136 176 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -5.750000 ) ) gothic_trim/wood2 0 0 0 +( 136 136 176 ) ( 136 136 168 ) ( 160 136 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -0.750000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 229 +{ +brushDef +{ +( 112 136 104 ) ( 104 136 104 ) ( 104 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.375000 ) ) gothic_trim/wood2 0 0 0 +( 104 128 128 ) ( 112 128 128 ) ( 112 128 104 ) ( ( 0.015625 0 -2.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 112 128 136 ) ( 112 136 136 ) ( 112 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 112 136 128 ) ( 104 136 128 ) ( 104 136 104 ) ( ( 0.015625 0 2.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 104 136 128 ) ( 104 128 128 ) ( 104 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 128 168 ) ( 160 136 168 ) ( 184 128 168 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 230 +{ +brushDef +{ +( 104 128 232 ) ( 104 136 232 ) ( 112 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2.375000 ) ) gothic_trim/wood2 0 0 0 +( 104 128 128 ) ( 112 128 128 ) ( 112 128 104 ) ( ( 0.015625 0 -2.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 112 128 136 ) ( 112 136 136 ) ( 112 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 112 136 128 ) ( 104 136 128 ) ( 104 136 104 ) ( ( 0.015625 0 2.375000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 104 136 128 ) ( 104 128 128 ) ( 104 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 136 176 ) ( 160 128 176 ) ( 184 136 176 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.375000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 231 +{ +brushDef +{ +( -48 128 232 ) ( -48 136 232 ) ( -40 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -48 128 128 ) ( -40 128 128 ) ( -40 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -40 128 136 ) ( -40 136 136 ) ( -40 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -40 136 128 ) ( -48 136 128 ) ( -48 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -48 136 128 ) ( -48 128 128 ) ( -48 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 8 136 176 ) ( 8 128 176 ) ( 32 136 176 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 232 +{ +brushDef +{ +( -40 136 104 ) ( -48 136 104 ) ( -48 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -48 128 128 ) ( -40 128 128 ) ( -40 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -40 128 136 ) ( -40 136 136 ) ( -40 136 112 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -40 136 128 ) ( -48 136 128 ) ( -48 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -48 136 128 ) ( -48 128 128 ) ( -48 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 8 128 168 ) ( 8 136 168 ) ( 32 128 168 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 233 +{ +brushDef +{ +( 8 128 176 ) ( 8 136 176 ) ( 8 136 168 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 2.625000 ) ) gothic_trim/wood2 0 0 0 +( -96 136 168 ) ( -96 136 176 ) ( -96 128 176 ) ( ( 0 -0.015625 -0.625000 ) ( 0.015625 0 -2.625000 ) ) gothic_trim/wood2 0 0 0 +( 8 136 168 ) ( 8 128 168 ) ( 32 128 168 ) ( ( -0.015625 0 -2.625000 ) ( 0 -0.015625 -3.375000 ) ) gothic_trim/wood2 0 0 0 +( 0 128 168 ) ( 0 128 176 ) ( 24 128 176 ) ( ( 0 0.015625 3.375000 ) ( -0.015625 0 -3.125000 ) ) gothic_trim/wood2 0 0 0 +( 8 128 176 ) ( 8 136 176 ) ( 32 136 176 ) ( ( 0.015625 0 2.625000 ) ( 0 0.015625 -3.375000 ) ) gothic_trim/wood2 0 0 0 +( -16 136 176 ) ( -16 136 168 ) ( 8 136 168 ) ( ( 0 -0.015625 -3.375000 ) ( 0.015625 0 -3.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 234 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 144 104 ) ( 56 144 104 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 136 232 ) ( 56 144 232 ) ( 160 144 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -96 136 128 ) ( -96 144 128 ) ( -96 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 235 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 144 104 ) ( 56 144 104 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 136 232 ) ( 56 144 232 ) ( 160 144 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 136 128 ) ( 56 144 128 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 8 144 128 ) ( 8 136 128 ) ( 8 144 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 236 +{ +brushDef +{ +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 144 104 ) ( 56 144 104 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 136 232 ) ( 56 144 232 ) ( 160 144 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 160 144 128 ) ( 160 136 128 ) ( 160 144 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 237 +{ +brushDef +{ +( 192 136 8 ) ( -128 136 8 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 16 ) ( 192 128 16 ) ( 192 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 128 208 ) ( 192 136 208 ) ( 192 136 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 192 136 16 ) ( -128 136 16 ) ( -128 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 136 16 ) ( -128 128 16 ) ( -128 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 56 144 104 ) ( 160 144 104 ) ( 56 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 238 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 104 ) ( 352 136 104 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 232 ) ( 352 136 232 ) ( 456 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 128 ) ( 456 128 128 ) ( 456 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 504 128 128 ) ( 504 136 128 ) ( 504 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 239 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 104 ) ( 352 136 104 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 232 ) ( 352 136 232 ) ( 456 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 608 136 128 ) ( 608 128 128 ) ( 608 136 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 240 +{ +brushDef +{ +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 456 136 104 ) ( 352 136 104 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 232 ) ( 352 136 232 ) ( 456 136 232 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 128 128 ) ( 352 136 128 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 241 +{ +brushDef +{ +( 640 136 8 ) ( 320 136 8 ) ( 320 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 128 16 ) ( 640 128 16 ) ( 640 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 16 ) ( 640 136 16 ) ( 640 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 136 16 ) ( 320 136 16 ) ( 320 136 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 136 208 ) ( 320 128 208 ) ( 320 128 200 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 352 136 104 ) ( 456 136 104 ) ( 352 128 104 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 242 +{ +brushDef +{ +( 624 -144 -40 ) ( 408 -144 -40 ) ( 408 -184 -40 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 408 -184 -16 ) ( 408 -144 -16 ) ( 624 -144 -16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 408 -184 0 ) ( 624 -184 0 ) ( 624 -184 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 624 -184 0 ) ( 624 -144 0 ) ( 624 -144 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 624 -144 0 ) ( 408 -144 0 ) ( 408 -144 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +( 408 -144 0 ) ( 408 -184 0 ) ( 408 -184 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) liquids/clear_ripple1 0 0 0 +} +} +// brush 243 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 0 ) ( 400 -136 0 ) ( 632 -136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 24 ) ( 632 -192 24 ) ( 632 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -136 24 ) ( 400 -136 24 ) ( 400 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 24 ) ( 400 -192 24 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 408 -192 24 ) ( 408 -136 24 ) ( 408 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 244 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 0 ) ( 400 -136 0 ) ( 632 -136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -192 24 ) ( 632 -136 24 ) ( 632 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -136 24 ) ( 400 -136 24 ) ( 400 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 24 ) ( 400 -192 24 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -144 24 ) ( 632 -144 24 ) ( 400 -144 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 245 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 0 ) ( 400 -136 0 ) ( 632 -136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 24 ) ( 632 -192 24 ) ( 632 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -192 24 ) ( 632 -136 24 ) ( 632 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -136 24 ) ( 400 -136 24 ) ( 400 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 624 -136 24 ) ( 624 -192 24 ) ( 624 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 246 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 0 ) ( 400 -136 0 ) ( 632 -136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 24 ) ( 632 -192 24 ) ( 632 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -192 24 ) ( 632 -136 24 ) ( 632 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 24 ) ( 400 -192 24 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -184 24 ) ( 400 -184 24 ) ( 632 -184 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 247 +{ +brushDef +{ +( 632 -136 -48 ) ( 400 -136 -48 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -192 24 ) ( 632 -192 24 ) ( 632 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -192 24 ) ( 632 -136 24 ) ( 632 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -136 24 ) ( 400 -136 24 ) ( 400 -136 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 24 ) ( 400 -192 24 ) ( 400 -192 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 400 -136 -40 ) ( 632 -136 -40 ) ( 400 -192 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 248 +{ +brushDef +{ +( 304 192 152 ) ( 304 144 152 ) ( 304 144 64 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 144 152 ) ( 312 192 152 ) ( 312 192 64 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 184 152 ) ( 304 184 152 ) ( 304 184 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 152 72 ) ( 312 176 72 ) ( 304 176 72 ) ( ( 0 0.015625 6.750000 ) ( -0.015625 0 -2 ) ) gothic_trim/wood2 0 0 0 +( 304 176 144 ) ( 312 176 144 ) ( 312 152 144 ) ( ( 0 -0.015625 6.750000 ) ( 0.015625 0 2 ) ) gothic_trim/wood2 0 0 0 +( 304 176 128 ) ( 312 176 128 ) ( 304 176 120 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 249 +{ +brushDef +{ +( 304 192 152 ) ( 304 144 152 ) ( 304 144 64 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 304 144 152 ) ( 312 144 152 ) ( 312 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 144 152 ) ( 312 192 152 ) ( 312 192 64 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 152 72 ) ( 312 176 72 ) ( 304 176 72 ) ( ( 0 0.015625 6.750000 ) ( -0.015625 0 -2 ) ) gothic_trim/wood2 0 0 0 +( 304 176 144 ) ( 312 176 144 ) ( 312 152 144 ) ( ( 0 -0.015625 6.750000 ) ( 0.015625 0 2 ) ) gothic_trim/wood2 0 0 0 +( 312 152 128 ) ( 304 152 128 ) ( 312 152 120 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 250 +{ +brushDef +{ +( 304 192 152 ) ( 312 192 152 ) ( 312 144 152 ) ( ( 0 -0.015625 6.750000 ) ( 0.015625 0 2 ) ) gothic_trim/wood2 0 0 0 +( 304 192 152 ) ( 304 144 152 ) ( 304 144 64 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 304 144 152 ) ( 312 144 152 ) ( 312 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 144 152 ) ( 312 192 152 ) ( 312 192 64 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 184 152 ) ( 304 184 152 ) ( 304 184 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 176 144 ) ( 304 176 144 ) ( 312 152 144 ) ( ( 0 0.015625 6.750000 ) ( -0.015625 0 -2 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 251 +{ +brushDef +{ +( 312 144 64 ) ( 312 192 64 ) ( 304 192 64 ) ( ( 0 0.015625 6.750000 ) ( -0.015625 0 -2 ) ) gothic_trim/wood2 0 0 0 +( 304 192 152 ) ( 304 144 152 ) ( 304 144 64 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 304 144 152 ) ( 312 144 152 ) ( 312 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 144 152 ) ( 312 192 152 ) ( 312 192 64 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 184 152 ) ( 304 184 152 ) ( 304 184 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 312 176 72 ) ( 312 152 72 ) ( 304 176 72 ) ( ( 0 -0.015625 6.750000 ) ( 0.015625 0 2 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 252 +{ +brushDef +{ +( 312 152 72 ) ( 312 176 72 ) ( 304 176 72 ) ( ( 0 0.007813 3.375216 ) ( -0.007813 0 -0.562538 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 304 176 144 ) ( 312 176 144 ) ( 312 152 144 ) ( ( 0 -0.007813 3.375216 ) ( 0.007813 0 0.562536 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 304 176 128 ) ( 304 152 128 ) ( 304 152 120 ) ( ( 0.007813 0 1.062570 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 304 152 128 ) ( 312 152 128 ) ( 312 152 120 ) ( ( 0.007813 0 3.125201 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 312 152 128 ) ( 312 176 128 ) ( 312 176 120 ) ( ( 0.007813 0 -1.062568 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 312 176 128 ) ( 304 176 128 ) ( 304 176 120 ) ( ( 0.007813 0 -3.125200 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 253 +{ +brushDef +{ +( 208 144 152 ) ( 208 192 152 ) ( 208 192 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 192 152 ) ( 200 144 152 ) ( 200 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 144 152 ) ( 208 144 152 ) ( 208 144 64 ) ( ( 0.015625 0 -1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 176 72 ) ( 200 152 72 ) ( 208 152 72 ) ( ( 0 -0.015625 -1 ) ( 0.015625 0 -6 ) ) gothic_trim/wood2 0 0 0 +( 208 152 144 ) ( 200 152 144 ) ( 200 176 144 ) ( ( 0 0.015625 -1 ) ( -0.015625 0 6 ) ) gothic_trim/wood2 0 0 0 +( 208 152 128 ) ( 200 152 128 ) ( 208 152 120 ) ( ( 0.015625 0 1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 254 +{ +brushDef +{ +( 208 144 152 ) ( 208 192 152 ) ( 208 192 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 208 184 152 ) ( 200 184 152 ) ( 200 184 64 ) ( ( 0.015625 0 1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 192 152 ) ( 200 144 152 ) ( 200 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 176 72 ) ( 200 152 72 ) ( 208 152 72 ) ( ( 0 -0.015625 -1 ) ( 0.015625 0 -6 ) ) gothic_trim/wood2 0 0 0 +( 208 152 144 ) ( 200 152 144 ) ( 200 176 144 ) ( ( 0 0.015625 -1 ) ( -0.015625 0 6 ) ) gothic_trim/wood2 0 0 0 +( 200 176 128 ) ( 208 176 128 ) ( 200 176 120 ) ( ( 0.015625 0 -1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 255 +{ +brushDef +{ +( 208 144 152 ) ( 200 144 152 ) ( 200 192 152 ) ( ( 0 0.015625 -1 ) ( -0.015625 0 6 ) ) gothic_trim/wood2 0 0 0 +( 208 144 152 ) ( 208 192 152 ) ( 208 192 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 208 184 152 ) ( 200 184 152 ) ( 200 184 64 ) ( ( 0.015625 0 1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 192 152 ) ( 200 144 152 ) ( 200 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 144 152 ) ( 208 144 152 ) ( 208 144 64 ) ( ( 0.015625 0 -1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 152 144 ) ( 208 152 144 ) ( 200 176 144 ) ( ( 0 -0.015625 -1 ) ( 0.015625 0 -6 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 256 +{ +brushDef +{ +( 200 192 64 ) ( 200 144 64 ) ( 208 144 64 ) ( ( 0 -0.015625 -1 ) ( 0.015625 0 -6 ) ) gothic_trim/wood2 0 0 0 +( 208 144 152 ) ( 208 192 152 ) ( 208 192 64 ) ( ( 0.015625 0 -6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 208 184 152 ) ( 200 184 152 ) ( 200 184 64 ) ( ( 0.015625 0 1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 192 152 ) ( 200 144 152 ) ( 200 144 64 ) ( ( 0.015625 0 6.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 144 152 ) ( 208 144 152 ) ( 208 144 64 ) ( ( 0.015625 0 -1.250000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 200 152 72 ) ( 200 176 72 ) ( 208 152 72 ) ( ( 0 0.015625 -1 ) ( -0.015625 0 6 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 257 +{ +brushDef +{ +( 200 176 72 ) ( 200 152 72 ) ( 208 152 72 ) ( ( 0 -0.007813 -0.500000 ) ( 0.007813 0 -3 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 208 152 144 ) ( 200 152 144 ) ( 200 176 144 ) ( ( 0 0.007813 -0.500000 ) ( -0.007813 0 3 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 208 152 128 ) ( 208 176 128 ) ( 208 176 120 ) ( ( 0.007813 0 -3.125000 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 208 176 128 ) ( 200 176 128 ) ( 200 176 120 ) ( ( 0.007813 0 0.625000 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 200 176 128 ) ( 200 152 128 ) ( 200 152 120 ) ( ( 0.007813 0 3.125000 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 200 152 128 ) ( 208 152 128 ) ( 208 152 120 ) ( ( 0.007813 0 -0.625000 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 258 +{ +brushDef +{ +( 136 -128 -48 ) ( 136 -152 -48 ) ( 144 -152 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 3.125198 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -152 0 ) ( 136 -152 0 ) ( 136 -128 0 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -3.125198 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -152 8 ) ( 144 -128 8 ) ( 144 -128 0 ) ( ( 0.007813 0 -0.875060 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -128 8 ) ( 136 -128 8 ) ( 136 -128 0 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -128 8 ) ( 136 -152 8 ) ( 136 -152 0 ) ( ( 0.007813 0 0.875061 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -152 8 ) ( 144 -152 8 ) ( 144 -152 0 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 259 +{ +brushDef +{ +( 136 -152 -48 ) ( 136 -176 -48 ) ( 144 -176 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.937688 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -176 -8 ) ( 136 -176 -8 ) ( 136 -152 -8 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.937688 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -176 0 ) ( 144 -152 0 ) ( 144 -152 -8 ) ( ( 0.007813 0 -0.687551 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -152 0 ) ( 136 -152 0 ) ( 136 -152 -8 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -152 0 ) ( 136 -176 0 ) ( 136 -176 -8 ) ( ( 0.007813 0 0.687551 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -176 0 ) ( 144 -176 0 ) ( 144 -176 -8 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 260 +{ +brushDef +{ +( 136 -176 -48 ) ( 136 -200 -48 ) ( 144 -200 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.750176 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -200 -16 ) ( 136 -200 -16 ) ( 136 -176 -16 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.750176 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -200 -8 ) ( 144 -176 -8 ) ( 144 -176 -16 ) ( ( 0.007813 0 -0.500039 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -176 -8 ) ( 136 -176 -8 ) ( 136 -176 -16 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -176 -8 ) ( 136 -200 -8 ) ( 136 -200 -16 ) ( ( 0.007813 0 0.500039 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -200 -8 ) ( 144 -200 -8 ) ( 144 -200 -16 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 261 +{ +brushDef +{ +( 136 -200 -48 ) ( 136 -224 -48 ) ( 144 -224 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.562655 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -224 -24 ) ( 136 -224 -24 ) ( 136 -200 -24 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.562655 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -224 -16 ) ( 144 -200 -16 ) ( 144 -200 -24 ) ( ( 0.007813 0 -0.312517 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -200 -16 ) ( 136 -200 -16 ) ( 136 -200 -24 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -200 -16 ) ( 136 -224 -16 ) ( 136 -224 -24 ) ( ( 0.007813 0 0.312517 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -224 -16 ) ( 144 -224 -16 ) ( 144 -224 -24 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 262 +{ +brushDef +{ +( 136 -224 -48 ) ( 136 -248 -48 ) ( 144 -248 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.375144 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -248 -32 ) ( 136 -248 -32 ) ( 136 -224 -32 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.375144 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -248 -24 ) ( 144 -224 -24 ) ( 144 -224 -32 ) ( ( 0.007813 0 -0.125006 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -224 -24 ) ( 136 -224 -24 ) ( 136 -224 -32 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -224 -24 ) ( 136 -248 -24 ) ( 136 -248 -32 ) ( ( 0.007813 0 0.125006 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -248 -24 ) ( 144 -248 -24 ) ( 144 -248 -32 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 263 +{ +brushDef +{ +( 136 -248 -48 ) ( 136 -272 -48 ) ( 144 -272 -48 ) ( ( 0 -0.007813 -2.000126 ) ( 0.007813 0 2.187633 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -272 -40 ) ( 136 -272 -40 ) ( 136 -248 -40 ) ( ( 0 0.007813 -2.000126 ) ( -0.007813 0 -2.187633 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -272 -32 ) ( 144 -248 -32 ) ( 144 -248 -40 ) ( ( 0.007813 0 0.062505 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 144 -248 -32 ) ( 136 -248 -32 ) ( 136 -248 -40 ) ( ( 0.007813 0 -15.875916 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -248 -32 ) ( 136 -272 -32 ) ( 136 -272 -40 ) ( ( 0.007813 0 -0.062505 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -272 -32 ) ( 144 -272 -32 ) ( 144 -272 -40 ) ( ( 0.007813 0 15.875914 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 264 +{ +brushDef +{ +( 368 -248 -48 ) ( 368 -272 -48 ) ( 376 -272 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.187633 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -272 -40 ) ( 368 -272 -40 ) ( 368 -248 -40 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.187633 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -272 -32 ) ( 376 -248 -32 ) ( 376 -248 -40 ) ( ( 0.007813 0 0.062505 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -248 -32 ) ( 368 -248 -32 ) ( 368 -248 -40 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -248 -32 ) ( 368 -272 -32 ) ( 368 -272 -40 ) ( ( 0.007813 0 -0.062505 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -272 -32 ) ( 376 -272 -32 ) ( 376 -272 -40 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 265 +{ +brushDef +{ +( 368 -224 -48 ) ( 368 -248 -48 ) ( 376 -248 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.375144 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -248 -32 ) ( 368 -248 -32 ) ( 368 -224 -32 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.375144 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -248 -24 ) ( 376 -224 -24 ) ( 376 -224 -32 ) ( ( 0.007813 0 -0.125006 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -224 -24 ) ( 368 -224 -24 ) ( 368 -224 -32 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -224 -24 ) ( 368 -248 -24 ) ( 368 -248 -32 ) ( ( 0.007813 0 0.125006 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -248 -24 ) ( 376 -248 -24 ) ( 376 -248 -32 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 266 +{ +brushDef +{ +( 368 -200 -48 ) ( 368 -224 -48 ) ( 376 -224 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.562655 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -224 -24 ) ( 368 -224 -24 ) ( 368 -200 -24 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.562655 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -224 -16 ) ( 376 -200 -16 ) ( 376 -200 -24 ) ( ( 0.007813 0 -0.312517 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -200 -16 ) ( 368 -200 -16 ) ( 368 -200 -24 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -200 -16 ) ( 368 -224 -16 ) ( 368 -224 -24 ) ( ( 0.007813 0 0.312517 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -224 -16 ) ( 376 -224 -16 ) ( 376 -224 -24 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 267 +{ +brushDef +{ +( 368 -176 -48 ) ( 368 -200 -48 ) ( 376 -200 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.750176 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -200 -16 ) ( 368 -200 -16 ) ( 368 -176 -16 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.750176 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -200 -8 ) ( 376 -176 -8 ) ( 376 -176 -16 ) ( ( 0.007813 0 -0.500039 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -176 -8 ) ( 368 -176 -8 ) ( 368 -176 -16 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -176 -8 ) ( 368 -200 -8 ) ( 368 -200 -16 ) ( ( 0.007813 0 0.500039 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -200 -8 ) ( 376 -200 -8 ) ( 376 -200 -16 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 268 +{ +brushDef +{ +( 368 -152 -48 ) ( 368 -176 -48 ) ( 376 -176 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 2.937688 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -176 -8 ) ( 368 -176 -8 ) ( 368 -152 -8 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -2.937688 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -176 0 ) ( 376 -152 0 ) ( 376 -152 -8 ) ( ( 0.007813 0 -0.687551 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -152 0 ) ( 368 -152 0 ) ( 368 -152 -8 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -152 0 ) ( 368 -176 0 ) ( 368 -176 -8 ) ( ( 0.007813 0 0.687551 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -176 0 ) ( 376 -176 0 ) ( 376 -176 -8 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 269 +{ +brushDef +{ +( 368 -128 -48 ) ( 368 -152 -48 ) ( 376 -152 -48 ) ( ( 0 -0.007813 -3.812737 ) ( 0.007813 0 3.125198 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -152 0 ) ( 368 -152 0 ) ( 368 -128 0 ) ( ( 0 0.007813 -3.812737 ) ( -0.007813 0 -3.125198 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -152 8 ) ( 376 -128 8 ) ( 376 -128 0 ) ( ( 0.007813 0 -0.875060 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 376 -128 8 ) ( 368 -128 8 ) ( 368 -128 0 ) ( ( 0.007813 0 -14.063194 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -128 8 ) ( 368 -152 8 ) ( 368 -152 0 ) ( ( 0.007813 0 0.875061 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 368 -152 8 ) ( 376 -152 8 ) ( 376 -152 0 ) ( ( 0.007813 0 14.063192 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 270 +{ +brushDef +{ +( 640 -128 -48 ) ( 664 -128 -48 ) ( 664 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.000237 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 -120 0 ) ( 664 -128 0 ) ( 640 -128 0 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.000237 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 -120 8 ) ( 640 -120 8 ) ( 640 -120 0 ) ( ( 0.007813 0 5.250314 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -120 8 ) ( 640 -128 8 ) ( 640 -128 0 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -128 8 ) ( 664 -128 8 ) ( 664 -128 0 ) ( ( 0.007813 0 -5.250313 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 -128 8 ) ( 664 -120 8 ) ( 664 -120 0 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 271 +{ +brushDef +{ +( 664 -128 -48 ) ( 688 -128 -48 ) ( 688 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.187747 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 -120 -8 ) ( 688 -128 -8 ) ( 664 -128 -8 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.187747 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 -120 0 ) ( 664 -120 0 ) ( 664 -120 -8 ) ( ( 0.007813 0 5.437823 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 -120 0 ) ( 664 -128 0 ) ( 664 -128 -8 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 -128 0 ) ( 688 -128 0 ) ( 688 -128 -8 ) ( ( 0.007813 0 -5.437823 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 -128 0 ) ( 688 -120 0 ) ( 688 -120 -8 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 272 +{ +brushDef +{ +( 688 -128 -48 ) ( 712 -128 -48 ) ( 712 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.375259 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 -120 -16 ) ( 712 -128 -16 ) ( 688 -128 -16 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.375259 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 -120 -8 ) ( 688 -120 -8 ) ( 688 -120 -16 ) ( ( 0.007813 0 5.625335 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 -120 -8 ) ( 688 -128 -8 ) ( 688 -128 -16 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 -128 -8 ) ( 712 -128 -8 ) ( 712 -128 -16 ) ( ( 0.007813 0 -5.625335 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 -128 -8 ) ( 712 -120 -8 ) ( 712 -120 -16 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 273 +{ +brushDef +{ +( 712 -128 -48 ) ( 736 -128 -48 ) ( 736 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.562780 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 -120 -24 ) ( 736 -128 -24 ) ( 712 -128 -24 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.562780 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 -120 -16 ) ( 712 -120 -16 ) ( 712 -120 -24 ) ( ( 0.007813 0 5.812857 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 -120 -16 ) ( 712 -128 -16 ) ( 712 -128 -24 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 -128 -16 ) ( 736 -128 -16 ) ( 736 -128 -24 ) ( ( 0.007813 0 -5.812857 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 -128 -16 ) ( 736 -120 -16 ) ( 736 -120 -24 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 274 +{ +brushDef +{ +( 736 -128 -48 ) ( 760 -128 -48 ) ( 760 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.750291 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 -120 -32 ) ( 760 -128 -32 ) ( 736 -128 -32 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.750291 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 -120 -24 ) ( 736 -120 -24 ) ( 736 -120 -32 ) ( ( 0.007813 0 6.000368 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 -120 -24 ) ( 736 -128 -24 ) ( 736 -128 -32 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 -128 -24 ) ( 760 -128 -24 ) ( 760 -128 -32 ) ( ( 0.007813 0 -6.000368 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 -128 -24 ) ( 760 -120 -24 ) ( 760 -120 -32 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 275 +{ +brushDef +{ +( 760 -128 -48 ) ( 784 -128 -48 ) ( 784 -120 -48 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 -4.937802 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 784 -120 -40 ) ( 784 -128 -40 ) ( 760 -128 -40 ) ( ( -0.007813 0 -1.937623 ) ( 0 -0.007813 4.937802 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 784 -120 -32 ) ( 760 -120 -32 ) ( 760 -120 -40 ) ( ( 0.007813 0 6.187879 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 -120 -32 ) ( 760 -128 -32 ) ( 760 -128 -40 ) ( ( 0.007813 0 -6.687911 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 -128 -32 ) ( 784 -128 -32 ) ( 784 -128 -40 ) ( ( 0.007813 0 -6.187879 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 784 -128 -32 ) ( 784 -120 -32 ) ( 784 -120 -40 ) ( ( 0.007813 0 6.687911 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 276 +{ +brushDef +{ +( 760 120 -48 ) ( 784 120 -48 ) ( 784 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.937802 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 784 128 -40 ) ( 784 120 -40 ) ( 760 120 -40 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.937802 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 784 128 -32 ) ( 760 128 -32 ) ( 760 128 -40 ) ( ( 0.007813 0 6.187879 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 128 -32 ) ( 760 120 -32 ) ( 760 120 -40 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 120 -32 ) ( 784 120 -32 ) ( 784 120 -40 ) ( ( 0.007813 0 -6.187878 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 784 120 -32 ) ( 784 128 -32 ) ( 784 128 -40 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 277 +{ +brushDef +{ +( 736 120 -48 ) ( 760 120 -48 ) ( 760 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.750291 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 128 -32 ) ( 760 120 -32 ) ( 736 120 -32 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.750291 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 128 -24 ) ( 736 128 -24 ) ( 736 128 -32 ) ( ( 0.007813 0 6.000368 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 128 -24 ) ( 736 120 -24 ) ( 736 120 -32 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 120 -24 ) ( 760 120 -24 ) ( 760 120 -32 ) ( ( 0.007813 0 -6.000367 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 760 120 -24 ) ( 760 128 -24 ) ( 760 128 -32 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 278 +{ +brushDef +{ +( 712 120 -48 ) ( 736 120 -48 ) ( 736 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.562780 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 128 -24 ) ( 736 120 -24 ) ( 712 120 -24 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.562780 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 128 -16 ) ( 712 128 -16 ) ( 712 128 -24 ) ( ( 0.007813 0 5.812857 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 128 -16 ) ( 712 120 -16 ) ( 712 120 -24 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 120 -16 ) ( 736 120 -16 ) ( 736 120 -24 ) ( ( 0.007813 0 -5.812856 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 736 120 -16 ) ( 736 128 -16 ) ( 736 128 -24 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 279 +{ +brushDef +{ +( 688 120 -48 ) ( 712 120 -48 ) ( 712 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.375259 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 128 -16 ) ( 712 120 -16 ) ( 688 120 -16 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.375259 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 128 -8 ) ( 688 128 -8 ) ( 688 128 -16 ) ( ( 0.007813 0 5.625335 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 128 -8 ) ( 688 120 -8 ) ( 688 120 -16 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 120 -8 ) ( 712 120 -8 ) ( 712 120 -16 ) ( ( 0.007813 0 -5.625335 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 712 120 -8 ) ( 712 128 -8 ) ( 712 128 -16 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 280 +{ +brushDef +{ +( 664 120 -48 ) ( 688 120 -48 ) ( 688 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.187747 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 128 -8 ) ( 688 120 -8 ) ( 664 120 -8 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.187747 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 128 0 ) ( 664 128 0 ) ( 664 128 -8 ) ( ( 0.007813 0 5.437823 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 128 0 ) ( 664 120 0 ) ( 664 120 -8 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 120 0 ) ( 688 120 0 ) ( 688 120 -8 ) ( ( 0.007813 0 -5.437823 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 688 120 0 ) ( 688 128 0 ) ( 688 128 -8 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 281 +{ +brushDef +{ +( 640 120 -48 ) ( 664 120 -48 ) ( 664 128 -48 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 -4.000237 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 128 0 ) ( 664 120 0 ) ( 640 120 0 ) ( ( -0.007813 0 -0.000003 ) ( 0 -0.007813 4.000237 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 128 8 ) ( 640 128 8 ) ( 640 128 0 ) ( ( 0.007813 0 5.250314 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 128 8 ) ( 640 120 8 ) ( 640 120 0 ) ( ( 0.007813 0 -4.750293 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 120 8 ) ( 664 120 8 ) ( 664 120 0 ) ( ( 0.007813 0 -5.250313 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 664 120 8 ) ( 664 128 8 ) ( 664 128 0 ) ( ( 0.007813 0 4.750293 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 282 +{ +brushDef +{ +( -128 128 -48 ) ( -152 128 -48 ) ( -152 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 120 0 ) ( -152 128 0 ) ( -128 128 0 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 120 8 ) ( -128 120 8 ) ( -128 120 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 120 8 ) ( -128 128 8 ) ( -128 128 0 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 128 8 ) ( -152 128 8 ) ( -152 128 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 128 8 ) ( -152 120 8 ) ( -152 120 0 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 283 +{ +brushDef +{ +( -152 128 -48 ) ( -176 128 -48 ) ( -176 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 120 -8 ) ( -176 128 -8 ) ( -152 128 -8 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 120 0 ) ( -152 120 0 ) ( -152 120 -8 ) ( ( 0.007813 0 0.187512 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 120 0 ) ( -152 128 0 ) ( -152 128 -8 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 128 0 ) ( -176 128 0 ) ( -176 128 -8 ) ( ( 0.007813 0 -0.187512 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 128 0 ) ( -176 120 0 ) ( -176 120 -8 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 284 +{ +brushDef +{ +( -176 128 -48 ) ( -200 128 -48 ) ( -200 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.375024 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 120 -16 ) ( -200 128 -16 ) ( -176 128 -16 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.375024 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 120 -8 ) ( -176 120 -8 ) ( -176 120 -16 ) ( ( 0.007813 0 0.375024 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 120 -8 ) ( -176 128 -8 ) ( -176 128 -16 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 128 -8 ) ( -200 128 -8 ) ( -200 128 -16 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 128 -8 ) ( -200 120 -8 ) ( -200 120 -16 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 285 +{ +brushDef +{ +( -200 128 -48 ) ( -224 128 -48 ) ( -224 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.562536 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 120 -24 ) ( -224 128 -24 ) ( -200 128 -24 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.562536 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 120 -16 ) ( -200 120 -16 ) ( -200 120 -24 ) ( ( 0.007813 0 0.562536 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 120 -16 ) ( -200 128 -16 ) ( -200 128 -24 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 128 -16 ) ( -224 128 -16 ) ( -224 128 -24 ) ( ( 0.007813 0 -0.562536 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 128 -16 ) ( -224 120 -16 ) ( -224 120 -24 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 286 +{ +brushDef +{ +( -224 128 -48 ) ( -248 128 -48 ) ( -248 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.750047 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 120 -32 ) ( -248 128 -32 ) ( -224 128 -32 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.750047 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 120 -24 ) ( -224 120 -24 ) ( -224 120 -32 ) ( ( 0.007813 0 0.750047 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 120 -24 ) ( -224 128 -24 ) ( -224 128 -32 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 128 -24 ) ( -248 128 -24 ) ( -248 128 -32 ) ( ( 0.007813 0 -0.750047 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 128 -24 ) ( -248 120 -24 ) ( -248 120 -32 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 287 +{ +brushDef +{ +( -248 128 -48 ) ( -272 128 -48 ) ( -272 120 -48 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.937558 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -272 120 -40 ) ( -272 128 -40 ) ( -248 128 -40 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 0.937558 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -272 120 -32 ) ( -248 120 -32 ) ( -248 120 -40 ) ( ( 0.007813 0 0.937558 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 120 -32 ) ( -248 128 -32 ) ( -248 128 -40 ) ( ( 0.007813 0 -1.937621 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 128 -32 ) ( -272 128 -32 ) ( -272 128 -40 ) ( ( 0.007813 0 -0.937558 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -272 128 -32 ) ( -272 120 -32 ) ( -272 120 -40 ) ( ( 0.007813 0 1.937621 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 288 +{ +brushDef +{ +( -248 -120 -48 ) ( -272 -120 -48 ) ( -272 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.937558 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -272 -128 -40 ) ( -272 -120 -40 ) ( -248 -120 -40 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.937558 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -272 -128 -32 ) ( -248 -128 -32 ) ( -248 -128 -40 ) ( ( 0.007813 0 0.937558 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 -128 -32 ) ( -248 -120 -32 ) ( -248 -120 -40 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 -120 -32 ) ( -272 -120 -32 ) ( -272 -120 -40 ) ( ( 0.007813 0 -0.937558 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -272 -120 -32 ) ( -272 -128 -32 ) ( -272 -128 -40 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.312520 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 289 +{ +brushDef +{ +( -224 -120 -48 ) ( -248 -120 -48 ) ( -248 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.750047 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 -128 -32 ) ( -248 -120 -32 ) ( -224 -120 -32 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.750047 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 -128 -24 ) ( -224 -128 -24 ) ( -224 -128 -32 ) ( ( 0.007813 0 0.750047 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 -128 -24 ) ( -224 -120 -24 ) ( -224 -120 -32 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 -120 -24 ) ( -248 -120 -24 ) ( -248 -120 -32 ) ( ( 0.007813 0 -0.750047 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -248 -120 -24 ) ( -248 -128 -24 ) ( -248 -128 -32 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.250016 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 290 +{ +brushDef +{ +( -200 -120 -48 ) ( -224 -120 -48 ) ( -224 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.562536 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 -128 -24 ) ( -224 -120 -24 ) ( -200 -120 -24 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.562536 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 -128 -16 ) ( -200 -128 -16 ) ( -200 -128 -24 ) ( ( 0.007813 0 0.562536 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 -128 -16 ) ( -200 -120 -16 ) ( -200 -120 -24 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 -120 -16 ) ( -224 -120 -16 ) ( -224 -120 -24 ) ( ( 0.007813 0 -0.562536 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -224 -120 -16 ) ( -224 -128 -16 ) ( -224 -128 -24 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 291 +{ +brushDef +{ +( -176 -120 -48 ) ( -200 -120 -48 ) ( -200 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.375024 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 -128 -16 ) ( -200 -120 -16 ) ( -176 -120 -16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.375024 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 -128 -8 ) ( -176 -128 -8 ) ( -176 -128 -16 ) ( ( 0.007813 0 0.375024 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 -128 -8 ) ( -176 -120 -8 ) ( -176 -120 -16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 -120 -8 ) ( -200 -120 -8 ) ( -200 -120 -16 ) ( ( 0.007813 0 -0.375024 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -200 -120 -8 ) ( -200 -128 -8 ) ( -200 -128 -16 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.125008 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 292 +{ +brushDef +{ +( -152 -120 -48 ) ( -176 -120 -48 ) ( -176 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 -128 -8 ) ( -176 -120 -8 ) ( -152 -120 -8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0.187512 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 -128 0 ) ( -152 -128 0 ) ( -152 -128 -8 ) ( ( 0.007813 0 0.187512 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 -128 0 ) ( -152 -120 0 ) ( -152 -120 -8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 -120 0 ) ( -176 -120 0 ) ( -176 -120 -8 ) ( ( 0.007813 0 -0.187512 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -176 -120 0 ) ( -176 -128 0 ) ( -176 -128 -8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 -0.062504 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 293 +{ +brushDef +{ +( -128 -120 -48 ) ( -152 -120 -48 ) ( -152 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 -128 0 ) ( -152 -120 0 ) ( -128 -120 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 -128 8 ) ( -128 -128 8 ) ( -128 -128 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 -128 8 ) ( -128 -120 8 ) ( -128 -120 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 -120 8 ) ( -152 -120 8 ) ( -152 -120 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -152 -120 8 ) ( -152 -128 8 ) ( -152 -128 0 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 294 +{ +brushDef +{ +( 384 -152 0 ) ( 384 -128 0 ) ( 128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -128 8 ) ( 384 -128 8 ) ( 384 -152 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 136 -128 8 ) ( 136 -152 8 ) ( 136 -152 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -152 8 ) ( 384 -152 8 ) ( 384 -152 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 376 -152 8 ) ( 376 -128 8 ) ( 376 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 384 -128 8 ) ( 128 -128 8 ) ( 128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 295 +{ +brushDef +{ +( 384 -176 -8 ) ( 384 -152 -8 ) ( 128 -152 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -152 0 ) ( 384 -152 0 ) ( 384 -176 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 136 -152 0 ) ( 136 -176 0 ) ( 136 -176 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -176 0 ) ( 384 -176 0 ) ( 384 -176 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 376 -176 0 ) ( 376 -152 0 ) ( 376 -152 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 384 -152 0 ) ( 128 -152 0 ) ( 128 -152 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 296 +{ +brushDef +{ +( 384 -200 -16 ) ( 384 -176 -16 ) ( 128 -176 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -176 -8 ) ( 384 -176 -8 ) ( 384 -200 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 136 -176 -8 ) ( 136 -200 -8 ) ( 136 -200 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -200 -8 ) ( 384 -200 -8 ) ( 384 -200 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 376 -200 -8 ) ( 376 -176 -8 ) ( 376 -176 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 384 -176 -8 ) ( 128 -176 -8 ) ( 128 -176 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 297 +{ +brushDef +{ +( 384 -224 -24 ) ( 384 -200 -24 ) ( 128 -200 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -200 -16 ) ( 384 -200 -16 ) ( 384 -224 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 136 -200 -16 ) ( 136 -224 -16 ) ( 136 -224 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -224 -16 ) ( 384 -224 -16 ) ( 384 -224 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 376 -224 -16 ) ( 376 -200 -16 ) ( 376 -200 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 384 -200 -16 ) ( 128 -200 -16 ) ( 128 -200 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 298 +{ +brushDef +{ +( 384 -248 -32 ) ( 384 -224 -32 ) ( 128 -224 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -224 -24 ) ( 384 -224 -24 ) ( 384 -248 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 136 -224 -24 ) ( 136 -248 -24 ) ( 136 -248 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -248 -24 ) ( 384 -248 -24 ) ( 384 -248 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 376 -248 -24 ) ( 376 -224 -24 ) ( 376 -224 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 384 -224 -24 ) ( 128 -224 -24 ) ( 128 -224 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 299 +{ +brushDef +{ +( 384 -272 -40 ) ( 384 -248 -40 ) ( 128 -248 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -248 -32 ) ( 384 -248 -32 ) ( 384 -272 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 136 -248 -32 ) ( 136 -272 -32 ) ( 136 -272 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -272 -32 ) ( 384 -272 -32 ) ( 384 -272 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 376 -272 -32 ) ( 376 -248 -32 ) ( 376 -248 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 384 -248 -32 ) ( 128 -248 -32 ) ( 128 -248 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 300 +{ +brushDef +{ +( 384 -296 -48 ) ( 384 -272 -48 ) ( 128 -272 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -272 -40 ) ( 384 -272 -40 ) ( 384 -296 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 136 -272 -40 ) ( 136 -296 -40 ) ( 136 -296 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -296 -40 ) ( 384 -296 -40 ) ( 384 -296 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 376 -296 -40 ) ( 376 -272 -40 ) ( 376 -272 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 384 -272 -40 ) ( 128 -272 -40 ) ( 128 -272 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 301 +{ +brushDef +{ +( 136 -120 -48 ) ( 24 -120 -48 ) ( 24 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 24 -128 8 ) ( 24 -120 8 ) ( 136 -120 8 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 24 -128 -40 ) ( 136 -128 -40 ) ( 136 -128 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -144 -40 ) ( 640 -136 -40 ) ( 640 -136 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 136 -120 -40 ) ( 24 -120 -40 ) ( 24 -120 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 -128 -40 ) ( -128 -136 -40 ) ( -128 -136 -48 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 302 +{ +brushDef +{ +( -152 -128 0 ) ( -128 -128 0 ) ( -128 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 8 ) ( -128 -128 8 ) ( -152 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 8 ) ( -152 128 8 ) ( -152 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -152 128 8 ) ( -152 -128 8 ) ( -152 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -152 -128 8 ) ( -128 -128 8 ) ( -128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 8 ) ( -128 128 8 ) ( -128 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 303 +{ +brushDef +{ +( -176 -128 -8 ) ( -152 -128 -8 ) ( -152 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -152 128 0 ) ( -152 -128 0 ) ( -176 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -152 128 0 ) ( -176 128 0 ) ( -176 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -176 128 0 ) ( -176 -128 0 ) ( -176 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -176 -128 0 ) ( -152 -128 0 ) ( -152 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -152 -128 0 ) ( -152 128 0 ) ( -152 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 304 +{ +brushDef +{ +( -200 -128 -16 ) ( -176 -128 -16 ) ( -176 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -176 128 -8 ) ( -176 -128 -8 ) ( -200 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -176 128 -8 ) ( -200 128 -8 ) ( -200 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -200 128 -8 ) ( -200 -128 -8 ) ( -200 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -200 -128 -8 ) ( -176 -128 -8 ) ( -176 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -176 -128 -8 ) ( -176 128 -8 ) ( -176 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 305 +{ +brushDef +{ +( -224 -128 -24 ) ( -200 -128 -24 ) ( -200 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -200 128 -16 ) ( -200 -128 -16 ) ( -224 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -200 128 -16 ) ( -224 128 -16 ) ( -224 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -224 128 -16 ) ( -224 -128 -16 ) ( -224 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -224 -128 -16 ) ( -200 -128 -16 ) ( -200 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -200 -128 -16 ) ( -200 128 -16 ) ( -200 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 306 +{ +brushDef +{ +( -248 -128 -32 ) ( -224 -128 -32 ) ( -224 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -224 128 -24 ) ( -224 -128 -24 ) ( -248 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -224 128 -24 ) ( -248 128 -24 ) ( -248 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -248 128 -24 ) ( -248 -128 -24 ) ( -248 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -248 -128 -24 ) ( -224 -128 -24 ) ( -224 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -224 -128 -24 ) ( -224 128 -24 ) ( -224 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 307 +{ +brushDef +{ +( -272 -128 -40 ) ( -248 -128 -40 ) ( -248 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -248 128 -32 ) ( -248 -128 -32 ) ( -272 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -248 128 -32 ) ( -272 128 -32 ) ( -272 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -272 128 -32 ) ( -272 -128 -32 ) ( -272 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -272 -128 -32 ) ( -248 -128 -32 ) ( -248 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -248 -128 -32 ) ( -248 128 -32 ) ( -248 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 308 +{ +brushDef +{ +( -296 -128 -48 ) ( -272 -128 -48 ) ( -272 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -272 128 -40 ) ( -272 -128 -40 ) ( -296 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -272 128 -40 ) ( -296 128 -40 ) ( -296 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -296 128 -40 ) ( -296 -128 -40 ) ( -296 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -296 -128 -40 ) ( -272 -128 -40 ) ( -272 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -272 -128 -40 ) ( -272 128 -40 ) ( -272 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 309 +{ +brushDef +{ +( 808 128 -48 ) ( 784 128 -48 ) ( 784 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 784 -128 -40 ) ( 784 128 -40 ) ( 808 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 784 -128 -40 ) ( 808 -128 -40 ) ( 808 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 808 -128 -40 ) ( 808 128 -40 ) ( 808 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 808 128 -40 ) ( 784 128 -40 ) ( 784 128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 784 128 -40 ) ( 784 -128 -40 ) ( 784 -128 -48 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 310 +{ +brushDef +{ +( 784 128 -40 ) ( 760 128 -40 ) ( 760 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 760 -128 -32 ) ( 760 128 -32 ) ( 784 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 760 -128 -32 ) ( 784 -128 -32 ) ( 784 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 784 -128 -32 ) ( 784 128 -32 ) ( 784 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 784 128 -32 ) ( 760 128 -32 ) ( 760 128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 760 128 -32 ) ( 760 -128 -32 ) ( 760 -128 -40 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 311 +{ +brushDef +{ +( 760 128 -32 ) ( 736 128 -32 ) ( 736 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 736 -128 -24 ) ( 736 128 -24 ) ( 760 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 736 -128 -24 ) ( 760 -128 -24 ) ( 760 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 760 -128 -24 ) ( 760 128 -24 ) ( 760 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 760 128 -24 ) ( 736 128 -24 ) ( 736 128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 736 128 -24 ) ( 736 -128 -24 ) ( 736 -128 -32 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 312 +{ +brushDef +{ +( 736 128 -24 ) ( 712 128 -24 ) ( 712 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 712 -128 -16 ) ( 712 128 -16 ) ( 736 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 712 -128 -16 ) ( 736 -128 -16 ) ( 736 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 736 -128 -16 ) ( 736 128 -16 ) ( 736 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 736 128 -16 ) ( 712 128 -16 ) ( 712 128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 712 128 -16 ) ( 712 -128 -16 ) ( 712 -128 -24 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 313 +{ +brushDef +{ +( 712 128 -16 ) ( 688 128 -16 ) ( 688 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 688 -128 -8 ) ( 688 128 -8 ) ( 712 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 688 -128 -8 ) ( 712 -128 -8 ) ( 712 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 712 -128 -8 ) ( 712 128 -8 ) ( 712 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 712 128 -8 ) ( 688 128 -8 ) ( 688 128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 688 128 -8 ) ( 688 -128 -8 ) ( 688 -128 -16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 314 +{ +brushDef +{ +( 688 128 -8 ) ( 664 128 -8 ) ( 664 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 664 -128 0 ) ( 664 128 0 ) ( 688 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 664 -128 0 ) ( 688 -128 0 ) ( 688 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 688 -128 0 ) ( 688 128 0 ) ( 688 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 688 128 0 ) ( 664 128 0 ) ( 664 128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 664 128 0 ) ( 664 -128 0 ) ( 664 -128 -8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 315 +{ +brushDef +{ +( 664 128 0 ) ( 640 128 0 ) ( 640 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 -128 8 ) ( 640 128 8 ) ( 664 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 -128 8 ) ( 664 -128 8 ) ( 664 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 664 -128 8 ) ( 664 128 8 ) ( 664 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 664 128 8 ) ( 640 128 8 ) ( 640 128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 128 8 ) ( 640 -128 8 ) ( 640 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 316 +{ +brushDef +{ +( -120 -120 72 ) ( -888 -120 72 ) ( -888 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 0 0 0 +( -888 -128 224 ) ( -888 -120 224 ) ( -120 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 0 0 0 +( -888 -128 232 ) ( -120 -128 232 ) ( -120 -128 72 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 -128 232 ) ( -120 -120 232 ) ( -120 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -120 -120 232 ) ( -888 -120 232 ) ( -888 -120 72 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -120 232 ) ( -128 -128 232 ) ( -128 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 317 +{ +brushDef +{ +( -56 -120 72 ) ( -824 -120 72 ) ( -824 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -10.875000 ) ) gothic_trim/wood2 0 0 0 +( -824 -128 224 ) ( -824 -120 224 ) ( -56 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 10.875000 ) ) gothic_trim/wood2 0 0 0 +( -824 -128 232 ) ( -56 -128 232 ) ( -56 -128 72 ) ( ( 0.015625 0 10.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -56 -128 232 ) ( -56 -120 232 ) ( -56 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -56 -120 232 ) ( -824 -120 232 ) ( -824 -120 72 ) ( ( 0.015625 0 -10.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -64 -120 232 ) ( -64 -128 232 ) ( -64 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 318 +{ +brushDef +{ +( 8 -120 72 ) ( -760 -120 72 ) ( -760 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.875000 ) ) gothic_trim/wood2 0 0 0 +( -760 -128 224 ) ( -760 -120 224 ) ( 8 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.875000 ) ) gothic_trim/wood2 0 0 0 +( -760 -128 232 ) ( 8 -128 232 ) ( 8 -128 72 ) ( ( 0.015625 0 9.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 8 -128 232 ) ( 8 -120 232 ) ( 8 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 8 -120 232 ) ( -760 -120 232 ) ( -760 -120 72 ) ( ( 0.015625 0 -9.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 0 -120 232 ) ( 0 -128 232 ) ( 0 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 319 +{ +brushDef +{ +( 72 -120 72 ) ( -696 -120 72 ) ( -696 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -8.875000 ) ) gothic_trim/wood2 0 0 0 +( -696 -128 224 ) ( -696 -120 224 ) ( 72 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 8.875000 ) ) gothic_trim/wood2 0 0 0 +( -696 -128 232 ) ( 72 -128 232 ) ( 72 -128 72 ) ( ( 0.015625 0 8.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 72 -128 232 ) ( 72 -120 232 ) ( 72 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 72 -120 232 ) ( -696 -120 232 ) ( -696 -120 72 ) ( ( 0.015625 0 -8.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 64 -120 232 ) ( 64 -128 232 ) ( 64 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 320 +{ +brushDef +{ +( 136 -120 72 ) ( -632 -120 72 ) ( -632 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7.875000 ) ) gothic_trim/wood2 0 0 0 +( -632 -128 224 ) ( -632 -120 224 ) ( 136 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7.875000 ) ) gothic_trim/wood2 0 0 0 +( -632 -128 232 ) ( 136 -128 232 ) ( 136 -128 72 ) ( ( 0.015625 0 7.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 136 -128 232 ) ( 136 -120 232 ) ( 136 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 136 -120 232 ) ( -632 -120 232 ) ( -632 -120 72 ) ( ( 0.015625 0 -7.875000 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 128 -120 232 ) ( 128 -128 232 ) ( 128 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 321 +{ +brushDef +{ +( 384 -120 72 ) ( -384 -120 72 ) ( -384 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -4 ) ) gothic_trim/wood2 0 0 0 +( -384 -128 224 ) ( -384 -120 224 ) ( 384 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 4 ) ) gothic_trim/wood2 0 0 0 +( -384 -128 232 ) ( 384 -128 232 ) ( 384 -128 72 ) ( ( 0.015625 0 4 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 384 -128 232 ) ( 384 -120 232 ) ( 384 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 384 -120 232 ) ( -384 -120 232 ) ( -384 -120 72 ) ( ( 0.015625 0 -4 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 376 -120 232 ) ( 376 -128 232 ) ( 376 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 322 +{ +brushDef +{ +( 448 -120 72 ) ( -320 -120 72 ) ( -320 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -3 ) ) gothic_trim/wood2 0 0 0 +( -320 -128 224 ) ( -320 -120 224 ) ( 448 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 3 ) ) gothic_trim/wood2 0 0 0 +( -320 -128 232 ) ( 448 -128 232 ) ( 448 -128 72 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 448 -128 232 ) ( 448 -120 232 ) ( 448 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 448 -120 232 ) ( -320 -120 232 ) ( -320 -120 72 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 440 -120 232 ) ( 440 -128 232 ) ( 440 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 323 +{ +brushDef +{ +( 512 -120 72 ) ( -256 -120 72 ) ( -256 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2 ) ) gothic_trim/wood2 0 0 0 +( -256 -128 224 ) ( -256 -120 224 ) ( 512 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2 ) ) gothic_trim/wood2 0 0 0 +( -256 -128 232 ) ( 512 -128 232 ) ( 512 -128 72 ) ( ( 0.015625 0 2 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 512 -128 232 ) ( 512 -120 232 ) ( 512 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 512 -120 232 ) ( -256 -120 232 ) ( -256 -120 72 ) ( ( 0.015625 0 -2 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 504 -120 232 ) ( 504 -128 232 ) ( 504 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 324 +{ +brushDef +{ +( 576 -120 72 ) ( -192 -120 72 ) ( -192 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -1 ) ) gothic_trim/wood2 0 0 0 +( -192 -128 224 ) ( -192 -120 224 ) ( 576 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 1 ) ) gothic_trim/wood2 0 0 0 +( -192 -128 232 ) ( 576 -128 232 ) ( 576 -128 72 ) ( ( 0.015625 0 1 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 576 -128 232 ) ( 576 -120 232 ) ( 576 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 576 -120 232 ) ( -192 -120 232 ) ( -192 -120 72 ) ( ( 0.015625 0 -1 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 568 -120 232 ) ( 568 -128 232 ) ( 568 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 325 +{ +brushDef +{ +( 640 -120 72 ) ( -128 -120 72 ) ( -128 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 224 ) ( -128 -120 224 ) ( 640 -120 224 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 232 ) ( 640 -128 232 ) ( 640 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 -128 232 ) ( 640 -120 232 ) ( 640 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 -120 232 ) ( -128 -120 232 ) ( -128 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 632 -120 232 ) ( 632 -128 232 ) ( 632 -128 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 326 +{ +brushDef +{ +( -128 -128 224 ) ( 640 -128 224 ) ( 640 128 312 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -128 232 ) ( -128 -128 232 ) ( -128 128 320 ) ( ( 0.007813 0 0 ) ( 0 0.007813 0 ) ) gothic_wall/slateroofc 0 0 0 +( -128 -128 224 ) ( -128 -128 232 ) ( 640 -128 232 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( 640 -128 320 ) ( 640 128 320 ) ( 640 128 8 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -32 128 320 ) ( -128 128 320 ) ( -128 128 8 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +( -128 -128 232 ) ( -128 -128 224 ) ( -128 128 312 ) ( ( 0 -0.007813 0 ) ( 0.007813 0 0 ) ) gothic_ceiling/woodceiling1a 0 0 0 +} +} +// brush 327 +{ +brushDef +{ +( 664 -120 64 ) ( 384 -120 64 ) ( 384 -128 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7.875000 ) ) gothic_trim/wood2 0 0 0 +( 376 -128 72 ) ( 376 -120 72 ) ( 656 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7.875000 ) ) gothic_trim/wood2 0 0 0 +( 376 -128 72 ) ( 656 -128 72 ) ( 656 -128 16 ) ( ( 0.015625 0 -7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 -128 72 ) ( 640 -120 72 ) ( 640 -120 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 656 -120 72 ) ( 376 -120 72 ) ( 376 -120 16 ) ( ( 0.015625 0 7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 376 -120 72 ) ( 376 -128 72 ) ( 376 -128 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 328 +{ +brushDef +{ +( 160 -120 64 ) ( -120 -120 64 ) ( -120 -128 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 72 ) ( -128 -120 72 ) ( 152 -120 72 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 72 ) ( 152 -128 72 ) ( 152 -128 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 136 -128 72 ) ( 136 -120 72 ) ( 136 -120 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 152 -120 72 ) ( -128 -120 72 ) ( -128 -120 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -128 -120 72 ) ( -128 -128 72 ) ( -128 -128 16 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 329 +{ +brushDef +{ +( 384 -120 8 ) ( 376 -120 8 ) ( 376 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 7.875000 ) ) gothic_trim/wood2 0 0 0 +( 376 -128 64 ) ( 376 -120 64 ) ( 384 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -7.875000 ) ) gothic_trim/wood2 0 0 0 +( 376 -128 16 ) ( 384 -128 16 ) ( 384 -128 8 ) ( ( 0.015625 0 -7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 384 -128 16 ) ( 384 -120 16 ) ( 384 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 384 -120 16 ) ( 376 -120 16 ) ( 376 -120 8 ) ( ( 0.015625 0 7.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 376 -120 16 ) ( 376 -128 16 ) ( 376 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 330 +{ +brushDef +{ +( 416 -120 8 ) ( 408 -120 8 ) ( 408 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 8.375000 ) ) gothic_trim/wood2 0 0 0 +( 408 -128 64 ) ( 408 -120 64 ) ( 416 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -8.375000 ) ) gothic_trim/wood2 0 0 0 +( 408 -128 16 ) ( 416 -128 16 ) ( 416 -128 8 ) ( ( 0.015625 0 -8.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 416 -128 16 ) ( 416 -120 16 ) ( 416 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 416 -120 16 ) ( 408 -120 16 ) ( 408 -120 8 ) ( ( 0.015625 0 8.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 408 -120 16 ) ( 408 -128 16 ) ( 408 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 331 +{ +brushDef +{ +( 448 -120 8 ) ( 440 -120 8 ) ( 440 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 8.875000 ) ) gothic_trim/wood2 0 0 0 +( 440 -128 64 ) ( 440 -120 64 ) ( 448 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -8.875000 ) ) gothic_trim/wood2 0 0 0 +( 440 -128 16 ) ( 448 -128 16 ) ( 448 -128 8 ) ( ( 0.015625 0 -8.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 448 -128 16 ) ( 448 -120 16 ) ( 448 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 448 -120 16 ) ( 440 -120 16 ) ( 440 -120 8 ) ( ( 0.015625 0 8.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 440 -120 16 ) ( 440 -128 16 ) ( 440 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 332 +{ +brushDef +{ +( 480 -120 8 ) ( 472 -120 8 ) ( 472 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.375000 ) ) gothic_trim/wood2 0 0 0 +( 472 -128 64 ) ( 472 -120 64 ) ( 480 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.375000 ) ) gothic_trim/wood2 0 0 0 +( 472 -128 16 ) ( 480 -128 16 ) ( 480 -128 8 ) ( ( 0.015625 0 -9.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 480 -128 16 ) ( 480 -120 16 ) ( 480 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 480 -120 16 ) ( 472 -120 16 ) ( 472 -120 8 ) ( ( 0.015625 0 9.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 472 -120 16 ) ( 472 -128 16 ) ( 472 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 333 +{ +brushDef +{ +( 512 -120 8 ) ( 504 -120 8 ) ( 504 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 9.875000 ) ) gothic_trim/wood2 0 0 0 +( 504 -128 64 ) ( 504 -120 64 ) ( 512 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -9.875000 ) ) gothic_trim/wood2 0 0 0 +( 504 -128 16 ) ( 512 -128 16 ) ( 512 -128 8 ) ( ( 0.015625 0 -9.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 512 -128 16 ) ( 512 -120 16 ) ( 512 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 512 -120 16 ) ( 504 -120 16 ) ( 504 -120 8 ) ( ( 0.015625 0 9.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 504 -120 16 ) ( 504 -128 16 ) ( 504 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 334 +{ +brushDef +{ +( 544 -120 8 ) ( 536 -120 8 ) ( 536 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 10.375000 ) ) gothic_trim/wood2 0 0 0 +( 536 -128 64 ) ( 536 -120 64 ) ( 544 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -10.375000 ) ) gothic_trim/wood2 0 0 0 +( 536 -128 16 ) ( 544 -128 16 ) ( 544 -128 8 ) ( ( 0.015625 0 -10.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 544 -128 16 ) ( 544 -120 16 ) ( 544 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 544 -120 16 ) ( 536 -120 16 ) ( 536 -120 8 ) ( ( 0.015625 0 10.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 536 -120 16 ) ( 536 -128 16 ) ( 536 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 335 +{ +brushDef +{ +( 576 -120 8 ) ( 568 -120 8 ) ( 568 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 10.875000 ) ) gothic_trim/wood2 0 0 0 +( 568 -128 64 ) ( 568 -120 64 ) ( 576 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -10.875000 ) ) gothic_trim/wood2 0 0 0 +( 568 -128 16 ) ( 576 -128 16 ) ( 576 -128 8 ) ( ( 0.015625 0 -10.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 576 -128 16 ) ( 576 -120 16 ) ( 576 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 576 -120 16 ) ( 568 -120 16 ) ( 568 -120 8 ) ( ( 0.015625 0 10.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 568 -120 16 ) ( 568 -128 16 ) ( 568 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 336 +{ +brushDef +{ +( 608 -120 8 ) ( 600 -120 8 ) ( 600 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 11.375000 ) ) gothic_trim/wood2 0 0 0 +( 600 -128 64 ) ( 600 -120 64 ) ( 608 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -11.375000 ) ) gothic_trim/wood2 0 0 0 +( 600 -128 16 ) ( 608 -128 16 ) ( 608 -128 8 ) ( ( 0.015625 0 -11.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 608 -128 16 ) ( 608 -120 16 ) ( 608 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 608 -120 16 ) ( 600 -120 16 ) ( 600 -120 8 ) ( ( 0.015625 0 11.375000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 600 -120 16 ) ( 600 -128 16 ) ( 600 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 337 +{ +brushDef +{ +( 640 -120 8 ) ( 632 -120 8 ) ( 632 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 -128 64 ) ( 632 -120 64 ) ( 640 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -11.875000 ) ) gothic_trim/wood2 0 0 0 +( 632 -128 16 ) ( 640 -128 16 ) ( 640 -128 8 ) ( ( 0.015625 0 -11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 -128 16 ) ( 640 -120 16 ) ( 640 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 640 -120 16 ) ( 632 -120 16 ) ( 632 -120 8 ) ( ( 0.015625 0 11.875000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 632 -120 16 ) ( 632 -128 16 ) ( 632 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 338 +{ +brushDef +{ +( -88 -120 8 ) ( -96 -120 8 ) ( -96 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.500000 ) ) gothic_trim/wood2 0 0 0 +( -96 -128 64 ) ( -96 -120 64 ) ( -88 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -0.500000 ) ) gothic_trim/wood2 0 0 0 +( -96 -128 16 ) ( -88 -128 16 ) ( -88 -128 8 ) ( ( 0.015625 0 -0.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -88 -128 16 ) ( -88 -120 16 ) ( -88 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -88 -120 16 ) ( -96 -120 16 ) ( -96 -120 8 ) ( ( 0.015625 0 0.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -96 -120 16 ) ( -96 -128 16 ) ( -96 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 339 +{ +brushDef +{ +( -24 -120 8 ) ( -32 -120 8 ) ( -32 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 1.500000 ) ) gothic_trim/wood2 0 0 0 +( -32 -128 64 ) ( -32 -120 64 ) ( -24 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -1.500000 ) ) gothic_trim/wood2 0 0 0 +( -32 -128 16 ) ( -24 -128 16 ) ( -24 -128 8 ) ( ( 0.015625 0 -1.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -24 -128 16 ) ( -24 -120 16 ) ( -24 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -24 -120 16 ) ( -32 -120 16 ) ( -32 -120 8 ) ( ( 0.015625 0 1.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -32 -120 16 ) ( -32 -128 16 ) ( -32 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 340 +{ +brushDef +{ +( 40 -120 8 ) ( 32 -120 8 ) ( 32 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2.500000 ) ) gothic_trim/wood2 0 0 0 +( 32 -128 64 ) ( 32 -120 64 ) ( 40 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2.500000 ) ) gothic_trim/wood2 0 0 0 +( 32 -128 16 ) ( 40 -128 16 ) ( 40 -128 8 ) ( ( 0.015625 0 -2.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 40 -128 16 ) ( 40 -120 16 ) ( 40 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 40 -120 16 ) ( 32 -120 16 ) ( 32 -120 8 ) ( ( 0.015625 0 2.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 32 -120 16 ) ( 32 -128 16 ) ( 32 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 341 +{ +brushDef +{ +( 104 -120 8 ) ( 96 -120 8 ) ( 96 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 3.500000 ) ) gothic_trim/wood2 0 0 0 +( 96 -128 64 ) ( 96 -120 64 ) ( 104 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -3.500000 ) ) gothic_trim/wood2 0 0 0 +( 96 -128 16 ) ( 104 -128 16 ) ( 104 -128 8 ) ( ( 0.015625 0 -3.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 104 -128 16 ) ( 104 -120 16 ) ( 104 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 104 -120 16 ) ( 96 -120 16 ) ( 96 -120 8 ) ( ( 0.015625 0 3.500000 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 96 -120 16 ) ( 96 -128 16 ) ( 96 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 342 +{ +brushDef +{ +( 136 -120 8 ) ( 128 -120 8 ) ( 128 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 4 ) ) gothic_trim/wood2 0 0 0 +( 128 -128 64 ) ( 128 -120 64 ) ( 136 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -4 ) ) gothic_trim/wood2 0 0 0 +( 128 -128 16 ) ( 136 -128 16 ) ( 136 -128 8 ) ( ( 0.015625 0 -4 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 136 -128 16 ) ( 136 -120 16 ) ( 136 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 136 -120 16 ) ( 128 -120 16 ) ( 128 -120 8 ) ( ( 0.015625 0 4 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 128 -120 16 ) ( 128 -128 16 ) ( 128 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 343 +{ +brushDef +{ +( 72 -120 8 ) ( 64 -120 8 ) ( 64 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 3 ) ) gothic_trim/wood2 0 0 0 +( 64 -128 64 ) ( 64 -120 64 ) ( 72 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -3 ) ) gothic_trim/wood2 0 0 0 +( 64 -128 16 ) ( 72 -128 16 ) ( 72 -128 8 ) ( ( 0.015625 0 -3 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 72 -128 16 ) ( 72 -120 16 ) ( 72 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 72 -120 16 ) ( 64 -120 16 ) ( 64 -120 8 ) ( ( 0.015625 0 3 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 64 -120 16 ) ( 64 -128 16 ) ( 64 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 344 +{ +brushDef +{ +( 8 -120 8 ) ( 0 -120 8 ) ( 0 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 2 ) ) gothic_trim/wood2 0 0 0 +( 0 -128 64 ) ( 0 -120 64 ) ( 8 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -2 ) ) gothic_trim/wood2 0 0 0 +( 0 -128 16 ) ( 8 -128 16 ) ( 8 -128 8 ) ( ( 0.015625 0 -2 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 8 -128 16 ) ( 8 -120 16 ) ( 8 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 8 -120 16 ) ( 0 -120 16 ) ( 0 -120 8 ) ( ( 0.015625 0 2 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( 0 -120 16 ) ( 0 -128 16 ) ( 0 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 345 +{ +brushDef +{ +( -56 -120 8 ) ( -64 -120 8 ) ( -64 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 1 ) ) gothic_trim/wood2 0 0 0 +( -64 -128 64 ) ( -64 -120 64 ) ( -56 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 -1 ) ) gothic_trim/wood2 0 0 0 +( -64 -128 16 ) ( -56 -128 16 ) ( -56 -128 8 ) ( ( 0.015625 0 -1 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -56 -128 16 ) ( -56 -120 16 ) ( -56 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -56 -120 16 ) ( -64 -120 16 ) ( -64 -120 8 ) ( ( 0.015625 0 1 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -64 -120 16 ) ( -64 -128 16 ) ( -64 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 346 +{ +brushDef +{ +( -120 -120 8 ) ( -128 -120 8 ) ( -128 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 64 ) ( -128 -120 64 ) ( -120 -120 64 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 16 ) ( -120 -128 16 ) ( -120 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 -128 16 ) ( -120 -120 16 ) ( -120 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -120 -120 16 ) ( -128 -120 16 ) ( -128 -120 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +( -128 -120 16 ) ( -128 -128 16 ) ( -128 -128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0.125000 ) ) gothic_trim/wood2 0 0 0 +} +} +// brush 347 +{ +brushDef +{ +( 256 128 0 ) ( -128 128 0 ) ( -128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 8 ) ( -128 128 8 ) ( 256 128 8 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 -128 8 ) ( 256 -128 8 ) ( 256 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 640 -120 8 ) ( 640 136 8 ) ( 640 136 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( 320 960 8 ) ( -64 960 8 ) ( -64 960 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +( -128 128 8 ) ( -128 -128 8 ) ( -128 -128 0 ) ( ( 0.015625 0 0 ) ( 0 0.015625 0 ) ) gothic_trim/wood2 0 0 0 +} +} +} +// entity 1 +{ +"origin" "248 512 336" +"light" "600" +"classname" "light" +} +// entity 2 +{ +"origin" "576 -64 32" +"classname" "info_player_start" +} +// entity 3 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 456 744 72 0 0 ) ( 456 744 76 0 0.062500 ) ( 456 744 80 0 0.125000 ) ) +( ( 456 728 72 0.250000 0 ) ( 456 728 76 0.250000 0.062500 ) ( 456 728 80 0.250000 0.125000 ) ) +( ( 472 728 72 0.500000 0 ) ( 472 728 76 0.500000 0.062500 ) ( 472 728 80 0.500000 0.125000 ) ) +( ( 488 728 72 0.750000 0 ) ( 488 728 76 0.750000 0.062500 ) ( 488 728 80 0.750000 0.125000 ) ) +( ( 488 744 72 1 0 ) ( 488 744 76 1 0.062500 ) ( 488 744 80 1 0.125000 ) ) +( ( 488 760 72 1.250000 0 ) ( 488 760 76 1.250000 0.062500 ) ( 488 760 80 1.250000 0.125000 ) ) +( ( 472 760 72 1.500000 0 ) ( 472 760 76 1.500000 0.062500 ) ( 472 760 80 1.500000 0.125000 ) ) +( ( 456 760 72 1.750000 0 ) ( 456 760 76 1.750000 0.062500 ) ( 456 760 80 1.750000 0.125000 ) ) +( ( 456 744 72 2 0 ) ( 456 744 76 2 0.062500 ) ( 456 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 472 760 72 7.375000 -11.875000 ) ( 456 760 72 7.125000 -11.875000 ) ( 456 744 72 7.125000 -11.625000 ) ) +( ( 488 760 72 7.625000 -11.875000 ) ( 472 744 72 7.375000 -11.625000 ) ( 456 728 72 7.125000 -11.375000 ) ) +( ( 488 744 72 7.625000 -11.625000 ) ( 488 728 72 7.625000 -11.375000 ) ( 472 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 456 744 80 7.125000 -11.625000 ) ( 456 760 80 7.125000 -11.875000 ) ( 472 760 80 7.375000 -11.875000 ) ) +( ( 456 728 80 7.125000 -11.375000 ) ( 472 744 80 7.375000 -11.625000 ) ( 488 760 80 7.625000 -11.875000 ) ) +( ( 472 728 80 7.375000 -11.375000 ) ( 488 728 80 7.625000 -11.375000 ) ( 488 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 4 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 400 320 64 0 0 ) ( 400 320 68 0 0.062500 ) ( 400 320 72 0 0.125000 ) ) +( ( 400 272 64 0.750000 0 ) ( 400 272 68 0.750000 0.062500 ) ( 400 272 72 0.750000 0.125000 ) ) +( ( 448 272 64 1.500000 0 ) ( 448 272 68 1.500000 0.062500 ) ( 448 272 72 1.500000 0.125000 ) ) +( ( 496 272 64 2.250000 0 ) ( 496 272 68 2.250000 0.062500 ) ( 496 272 72 2.250000 0.125000 ) ) +( ( 496 320 64 3 0 ) ( 496 320 68 3 0.062500 ) ( 496 320 72 3 0.125000 ) ) +( ( 496 368 64 3.750000 0 ) ( 496 368 68 3.750000 0.062500 ) ( 496 368 72 3.750000 0.125000 ) ) +( ( 448 368 64 4.500000 0 ) ( 448 368 68 4.500000 0.062500 ) ( 448 368 72 4.500000 0.125000 ) ) +( ( 400 368 64 5.250000 0 ) ( 400 368 68 5.250000 0.062500 ) ( 400 368 72 5.250000 0.125000 ) ) +( ( 400 320 64 6 0 ) ( 400 320 68 6 0.062500 ) ( 400 320 72 6 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 448 368 64 7 -5.750000 ) ( 400 368 64 6.250000 -5.750000 ) ( 400 320 64 6.250000 -5 ) ) +( ( 496 368 64 7.750000 -5.750000 ) ( 448 320 64 7 -5 ) ( 400 272 64 6.250000 -4.250000 ) ) +( ( 496 320 64 7.750000 -5 ) ( 496 272 64 7.750000 -4.250000 ) ( 448 272 64 7 -4.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 400 320 72 6.250000 -5 ) ( 400 368 72 6.250000 -5.750000 ) ( 448 368 72 7 -5.750000 ) ) +( ( 400 272 72 6.250000 -4.250000 ) ( 448 320 72 7 -5 ) ( 496 368 72 7.750000 -5.750000 ) ) +( ( 448 272 72 7 -4.250000 ) ( 496 272 72 7.750000 -4.250000 ) ( 496 320 72 7.750000 -5 ) ) +) + } + } +} +// entity 5 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 192 132 88 0 0 ) ( 192 132 108 0 0.312500 ) ( 192 132 128 0 0.625000 ) ) +( ( 192 128 88 0.062500 0 ) ( 192 128 108 0.062500 0.312500 ) ( 192 128 128 0.062500 0.625000 ) ) +( ( 196 128 88 0.125000 0 ) ( 196 128 108 0.125000 0.312500 ) ( 196 128 128 0.125000 0.625000 ) ) +( ( 200 128 88 0.187500 0 ) ( 200 128 108 0.187500 0.312500 ) ( 200 128 128 0.187500 0.625000 ) ) +( ( 200 132 88 0.250000 0 ) ( 200 132 108 0.250000 0.312500 ) ( 200 132 128 0.250000 0.625000 ) ) +( ( 200 136 88 0.312500 0 ) ( 200 136 108 0.312500 0.312500 ) ( 200 136 128 0.312500 0.625000 ) ) +( ( 196 136 88 0.375000 0 ) ( 196 136 108 0.375000 0.312500 ) ( 196 136 128 0.375000 0.625000 ) ) +( ( 192 136 88 0.437500 0 ) ( 192 136 108 0.437500 0.312500 ) ( 192 136 128 0.437500 0.625000 ) ) +( ( 192 132 88 0.500000 0 ) ( 192 132 108 0.500000 0.312500 ) ( 192 132 128 0.500000 0.625000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_trim/pewter_spec + ( 3 3 0 0 0 ) +( +( ( 196 136 88 3.062500 -2.125000 ) ( 192 136 88 3 -2.125000 ) ( 192 132 88 3 -2.062500 ) ) +( ( 200 136 88 3.125000 -2.125000 ) ( 196 132 88 3.062500 -2.062500 ) ( 192 128 88 3 -2 ) ) +( ( 200 132 88 3.125000 -2.062500 ) ( 200 128 88 3.125000 -2 ) ( 196 128 88 3.062500 -2 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_trim/pewter_spec + ( 3 3 0 0 0 ) +( +( ( 192 132 128 3 -2.062500 ) ( 192 136 128 3 -2.125000 ) ( 196 136 128 3.062500 -2.125000 ) ) +( ( 192 128 128 3 -2 ) ( 196 132 128 3.062500 -2.062500 ) ( 200 136 128 3.125000 -2.125000 ) ) +( ( 196 128 128 3.062500 -2 ) ( 200 128 128 3.125000 -2 ) ( 200 132 128 3.125000 -2.062500 ) ) +) + } + } +} +// entity 6 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 204 136 88 0 0 ) ( 204 136 108 0 0.312500 ) ( 204 136 128 0 0.625000 ) ) +( ( 208 136 88 0.062500 0 ) ( 208 136 108 0.062500 0.312500 ) ( 208 136 128 0.062500 0.625000 ) ) +( ( 208 140 88 0.125000 0 ) ( 208 140 108 0.125000 0.312500 ) ( 208 140 128 0.125000 0.625000 ) ) +( ( 208 144 88 0.187500 0 ) ( 208 144 108 0.187500 0.312500 ) ( 208 144 128 0.187500 0.625000 ) ) +( ( 204 144 88 0.250000 0 ) ( 204 144 108 0.250000 0.312500 ) ( 204 144 128 0.250000 0.625000 ) ) +( ( 200 144 88 0.312500 0 ) ( 200 144 108 0.312500 0.312500 ) ( 200 144 128 0.312500 0.625000 ) ) +( ( 200 140 88 0.375000 0 ) ( 200 140 108 0.375000 0.312500 ) ( 200 140 128 0.375000 0.625000 ) ) +( ( 200 136 88 0.437500 0 ) ( 200 136 108 0.437500 0.312500 ) ( 200 136 128 0.437500 0.625000 ) ) +( ( 204 136 88 0.500000 0 ) ( 204 136 108 0.500000 0.312500 ) ( 204 136 128 0.500000 0.625000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_trim/pewter_spec + ( 3 3 0 0 0 ) +( +( ( 200 140 88 3.187500 -2.125000 ) ( 200 136 88 3.125000 -2.125000 ) ( 204 136 88 3.125000 -2.062500 ) ) +( ( 200 144 88 3.250000 -2.125000 ) ( 204 140 88 3.187500 -2.062500 ) ( 208 136 88 3.125000 -2 ) ) +( ( 204 144 88 3.250000 -2.062500 ) ( 208 144 88 3.250000 -2 ) ( 208 140 88 3.187500 -2 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_trim/pewter_spec + ( 3 3 0 0 0 ) +( +( ( 204 136 128 3.125000 -2.062500 ) ( 200 136 128 3.125000 -2.125000 ) ( 200 140 128 3.187500 -2.125000 ) ) +( ( 208 136 128 3.125000 -2 ) ( 204 140 128 3.187500 -2.062500 ) ( 200 144 128 3.250000 -2.125000 ) ) +( ( 208 140 128 3.187500 -2 ) ( 208 144 128 3.250000 -2 ) ( 204 144 128 3.250000 -2.062500 ) ) +) + } + } +} +// entity 7 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 312 132 88 0 0 ) ( 312 132 108 0 0.312500 ) ( 312 132 128 0 0.625000 ) ) +( ( 312 128 88 0.062500 0 ) ( 312 128 108 0.062500 0.312500 ) ( 312 128 128 0.062500 0.625000 ) ) +( ( 316 128 88 0.125000 0 ) ( 316 128 108 0.125000 0.312500 ) ( 316 128 128 0.125000 0.625000 ) ) +( ( 320 128 88 0.187500 0 ) ( 320 128 108 0.187500 0.312500 ) ( 320 128 128 0.187500 0.625000 ) ) +( ( 320 132 88 0.250000 0 ) ( 320 132 108 0.250000 0.312500 ) ( 320 132 128 0.250000 0.625000 ) ) +( ( 320 136 88 0.312500 0 ) ( 320 136 108 0.312500 0.312500 ) ( 320 136 128 0.312500 0.625000 ) ) +( ( 316 136 88 0.375000 0 ) ( 316 136 108 0.375000 0.312500 ) ( 316 136 128 0.375000 0.625000 ) ) +( ( 312 136 88 0.437500 0 ) ( 312 136 108 0.437500 0.312500 ) ( 312 136 128 0.437500 0.625000 ) ) +( ( 312 132 88 0.500000 0 ) ( 312 132 108 0.500000 0.312500 ) ( 312 132 128 0.500000 0.625000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_trim/pewter_spec + ( 3 3 0 0 0 ) +( +( ( 316 136 88 4.937500 -2.125000 ) ( 312 136 88 4.875000 -2.125000 ) ( 312 132 88 4.875000 -2.062500 ) ) +( ( 320 136 88 5 -2.125000 ) ( 316 132 88 4.937500 -2.062500 ) ( 312 128 88 4.875000 -2 ) ) +( ( 320 132 88 5 -2.062500 ) ( 320 128 88 5 -2 ) ( 316 128 88 4.937500 -2 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_trim/pewter_spec + ( 3 3 0 0 0 ) +( +( ( 312 132 128 4.875000 -2.062500 ) ( 312 136 128 4.875000 -2.125000 ) ( 316 136 128 4.937500 -2.125000 ) ) +( ( 312 128 128 4.875000 -2 ) ( 316 132 128 4.937500 -2.062500 ) ( 320 136 128 5 -2.125000 ) ) +( ( 316 128 128 4.937500 -2 ) ( 320 128 128 5 -2 ) ( 320 132 128 5 -2.062500 ) ) +) + } + } +} +// entity 8 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + base_trim/pewter_spec + ( 9 3 0 0 0 ) +( +( ( 308 144 88 0 0 ) ( 308 144 108 0 0.312500 ) ( 308 144 128 0 0.625000 ) ) +( ( 304 144 88 0.062500 0 ) ( 304 144 108 0.062500 0.312500 ) ( 304 144 128 0.062500 0.625000 ) ) +( ( 304 140 88 0.125000 0 ) ( 304 140 108 0.125000 0.312500 ) ( 304 140 128 0.125000 0.625000 ) ) +( ( 304 136 88 0.187500 0 ) ( 304 136 108 0.187500 0.312500 ) ( 304 136 128 0.187500 0.625000 ) ) +( ( 308 136 88 0.250000 0 ) ( 308 136 108 0.250000 0.312500 ) ( 308 136 128 0.250000 0.625000 ) ) +( ( 312 136 88 0.312500 0 ) ( 312 136 108 0.312500 0.312500 ) ( 312 136 128 0.312500 0.625000 ) ) +( ( 312 140 88 0.375000 0 ) ( 312 140 108 0.375000 0.312500 ) ( 312 140 128 0.375000 0.625000 ) ) +( ( 312 144 88 0.437500 0 ) ( 312 144 108 0.437500 0.312500 ) ( 312 144 128 0.437500 0.625000 ) ) +( ( 308 144 88 0.500000 0 ) ( 308 144 108 0.500000 0.312500 ) ( 308 144 128 0.500000 0.625000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + base_trim/pewter_spec + ( 3 3 0 0 0 ) +( +( ( 312 140 88 4.812500 -2.125000 ) ( 312 144 88 4.750000 -2.125000 ) ( 308 144 88 4.750000 -2.062500 ) ) +( ( 312 136 88 4.875000 -2.125000 ) ( 308 140 88 4.812500 -2.062500 ) ( 304 144 88 4.750000 -2 ) ) +( ( 308 136 88 4.875000 -2.062500 ) ( 304 136 88 4.875000 -2 ) ( 304 140 88 4.812500 -2 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + base_trim/pewter_spec + ( 3 3 0 0 0 ) +( +( ( 308 144 128 4.750000 -2.062500 ) ( 312 144 128 4.750000 -2.125000 ) ( 312 140 128 4.812500 -2.125000 ) ) +( ( 304 144 128 4.750000 -2 ) ( 308 140 128 4.812500 -2.062500 ) ( 312 136 128 4.875000 -2.125000 ) ) +( ( 304 140 128 4.812500 -2 ) ( 304 136 128 4.875000 -2 ) ( 308 136 128 4.875000 -2.062500 ) ) +) + } + } +} +// entity 9 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 400 512 64 0 0 ) ( 400 512 68 0 0.062500 ) ( 400 512 72 0 0.125000 ) ) +( ( 400 464 64 0.750000 0 ) ( 400 464 68 0.750000 0.062500 ) ( 400 464 72 0.750000 0.125000 ) ) +( ( 448 464 64 1.500000 0 ) ( 448 464 68 1.500000 0.062500 ) ( 448 464 72 1.500000 0.125000 ) ) +( ( 496 464 64 2.250000 0 ) ( 496 464 68 2.250000 0.062500 ) ( 496 464 72 2.250000 0.125000 ) ) +( ( 496 512 64 3 0 ) ( 496 512 68 3 0.062500 ) ( 496 512 72 3 0.125000 ) ) +( ( 496 560 64 3.750000 0 ) ( 496 560 68 3.750000 0.062500 ) ( 496 560 72 3.750000 0.125000 ) ) +( ( 448 560 64 4.500000 0 ) ( 448 560 68 4.500000 0.062500 ) ( 448 560 72 4.500000 0.125000 ) ) +( ( 400 560 64 5.250000 0 ) ( 400 560 68 5.250000 0.062500 ) ( 400 560 72 5.250000 0.125000 ) ) +( ( 400 512 64 6 0 ) ( 400 512 68 6 0.062500 ) ( 400 512 72 6 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 448 560 64 7 -5.750000 ) ( 400 560 64 6.250000 -5.750000 ) ( 400 512 64 6.250000 -5 ) ) +( ( 496 560 64 7.750000 -5.750000 ) ( 448 512 64 7 -5 ) ( 400 464 64 6.250000 -4.250000 ) ) +( ( 496 512 64 7.750000 -5 ) ( 496 464 64 7.750000 -4.250000 ) ( 448 464 64 7 -4.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 400 512 72 6.250000 -5 ) ( 400 560 72 6.250000 -5.750000 ) ( 448 560 72 7 -5.750000 ) ) +( ( 400 464 72 6.250000 -4.250000 ) ( 448 512 72 7 -5 ) ( 496 560 72 7.750000 -5.750000 ) ) +( ( 448 464 72 7 -4.250000 ) ( 496 464 72 7.750000 -4.250000 ) ( 496 512 72 7.750000 -5 ) ) +) + } + } +} +// entity 10 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 16 320 64 0 0 ) ( 16 320 68 0 0.062500 ) ( 16 320 72 0 0.125000 ) ) +( ( 16 272 64 0.750000 0 ) ( 16 272 68 0.750000 0.062500 ) ( 16 272 72 0.750000 0.125000 ) ) +( ( 64 272 64 1.500000 0 ) ( 64 272 68 1.500000 0.062500 ) ( 64 272 72 1.500000 0.125000 ) ) +( ( 112 272 64 2.250000 0 ) ( 112 272 68 2.250000 0.062500 ) ( 112 272 72 2.250000 0.125000 ) ) +( ( 112 320 64 3 0 ) ( 112 320 68 3 0.062500 ) ( 112 320 72 3 0.125000 ) ) +( ( 112 368 64 3.750000 0 ) ( 112 368 68 3.750000 0.062500 ) ( 112 368 72 3.750000 0.125000 ) ) +( ( 64 368 64 4.500000 0 ) ( 64 368 68 4.500000 0.062500 ) ( 64 368 72 4.500000 0.125000 ) ) +( ( 16 368 64 5.250000 0 ) ( 16 368 68 5.250000 0.062500 ) ( 16 368 72 5.250000 0.125000 ) ) +( ( 16 320 64 6 0 ) ( 16 320 68 6 0.062500 ) ( 16 320 72 6 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 64 368 64 7 -5.750000 ) ( 16 368 64 6.250000 -5.750000 ) ( 16 320 64 6.250000 -5 ) ) +( ( 112 368 64 7.750000 -5.750000 ) ( 64 320 64 7 -5 ) ( 16 272 64 6.250000 -4.250000 ) ) +( ( 112 320 64 7.750000 -5 ) ( 112 272 64 7.750000 -4.250000 ) ( 64 272 64 7 -4.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 16 320 72 6.250000 -5 ) ( 16 368 72 6.250000 -5.750000 ) ( 64 368 72 7 -5.750000 ) ) +( ( 16 272 72 6.250000 -4.250000 ) ( 64 320 72 7 -5 ) ( 112 368 72 7.750000 -5.750000 ) ) +( ( 64 272 72 7 -4.250000 ) ( 112 272 72 7.750000 -4.250000 ) ( 112 320 72 7.750000 -5 ) ) +) + } + } +} +// entity 11 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 16 512 64 0 0 ) ( 16 512 68 0 0.062500 ) ( 16 512 72 0 0.125000 ) ) +( ( 16 464 64 0.750000 0 ) ( 16 464 68 0.750000 0.062500 ) ( 16 464 72 0.750000 0.125000 ) ) +( ( 64 464 64 1.500000 0 ) ( 64 464 68 1.500000 0.062500 ) ( 64 464 72 1.500000 0.125000 ) ) +( ( 112 464 64 2.250000 0 ) ( 112 464 68 2.250000 0.062500 ) ( 112 464 72 2.250000 0.125000 ) ) +( ( 112 512 64 3 0 ) ( 112 512 68 3 0.062500 ) ( 112 512 72 3 0.125000 ) ) +( ( 112 560 64 3.750000 0 ) ( 112 560 68 3.750000 0.062500 ) ( 112 560 72 3.750000 0.125000 ) ) +( ( 64 560 64 4.500000 0 ) ( 64 560 68 4.500000 0.062500 ) ( 64 560 72 4.500000 0.125000 ) ) +( ( 16 560 64 5.250000 0 ) ( 16 560 68 5.250000 0.062500 ) ( 16 560 72 5.250000 0.125000 ) ) +( ( 16 512 64 6 0 ) ( 16 512 68 6 0.062500 ) ( 16 512 72 6 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 64 560 64 7 -5.750000 ) ( 16 560 64 6.250000 -5.750000 ) ( 16 512 64 6.250000 -5 ) ) +( ( 112 560 64 7.750000 -5.750000 ) ( 64 512 64 7 -5 ) ( 16 464 64 6.250000 -4.250000 ) ) +( ( 112 512 64 7.750000 -5 ) ( 112 464 64 7.750000 -4.250000 ) ( 64 464 64 7 -4.250000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 16 512 72 6.250000 -5 ) ( 16 560 72 6.250000 -5.750000 ) ( 64 560 72 7 -5.750000 ) ) +( ( 16 464 72 6.250000 -4.250000 ) ( 64 512 72 7 -5 ) ( 112 560 72 7.750000 -5.750000 ) ) +( ( 64 464 72 7 -4.250000 ) ( 112 464 72 7.750000 -4.250000 ) ( 112 512 72 7.750000 -5 ) ) +) + } + } +} +// entity 12 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 368 744 72 0 0 ) ( 368 744 76 0 0.062500 ) ( 368 744 80 0 0.125000 ) ) +( ( 368 728 72 0.250000 0 ) ( 368 728 76 0.250000 0.062500 ) ( 368 728 80 0.250000 0.125000 ) ) +( ( 384 728 72 0.500000 0 ) ( 384 728 76 0.500000 0.062500 ) ( 384 728 80 0.500000 0.125000 ) ) +( ( 400 728 72 0.750000 0 ) ( 400 728 76 0.750000 0.062500 ) ( 400 728 80 0.750000 0.125000 ) ) +( ( 400 744 72 1 0 ) ( 400 744 76 1 0.062500 ) ( 400 744 80 1 0.125000 ) ) +( ( 400 760 72 1.250000 0 ) ( 400 760 76 1.250000 0.062500 ) ( 400 760 80 1.250000 0.125000 ) ) +( ( 384 760 72 1.500000 0 ) ( 384 760 76 1.500000 0.062500 ) ( 384 760 80 1.500000 0.125000 ) ) +( ( 368 760 72 1.750000 0 ) ( 368 760 76 1.750000 0.062500 ) ( 368 760 80 1.750000 0.125000 ) ) +( ( 368 744 72 2 0 ) ( 368 744 76 2 0.062500 ) ( 368 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 384 760 72 7.375000 -11.875000 ) ( 368 760 72 7.125000 -11.875000 ) ( 368 744 72 7.125000 -11.625000 ) ) +( ( 400 760 72 7.625000 -11.875000 ) ( 384 744 72 7.375000 -11.625000 ) ( 368 728 72 7.125000 -11.375000 ) ) +( ( 400 744 72 7.625000 -11.625000 ) ( 400 728 72 7.625000 -11.375000 ) ( 384 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 368 744 80 7.125000 -11.625000 ) ( 368 760 80 7.125000 -11.875000 ) ( 384 760 80 7.375000 -11.875000 ) ) +( ( 368 728 80 7.125000 -11.375000 ) ( 384 744 80 7.375000 -11.625000 ) ( 400 760 80 7.625000 -11.875000 ) ) +( ( 384 728 80 7.375000 -11.375000 ) ( 400 728 80 7.625000 -11.375000 ) ( 400 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 13 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 264 744 72 0 0 ) ( 264 744 76 0 0.062500 ) ( 264 744 80 0 0.125000 ) ) +( ( 264 728 72 0.250000 0 ) ( 264 728 76 0.250000 0.062500 ) ( 264 728 80 0.250000 0.125000 ) ) +( ( 280 728 72 0.500000 0 ) ( 280 728 76 0.500000 0.062500 ) ( 280 728 80 0.500000 0.125000 ) ) +( ( 296 728 72 0.750000 0 ) ( 296 728 76 0.750000 0.062500 ) ( 296 728 80 0.750000 0.125000 ) ) +( ( 296 744 72 1 0 ) ( 296 744 76 1 0.062500 ) ( 296 744 80 1 0.125000 ) ) +( ( 296 760 72 1.250000 0 ) ( 296 760 76 1.250000 0.062500 ) ( 296 760 80 1.250000 0.125000 ) ) +( ( 280 760 72 1.500000 0 ) ( 280 760 76 1.500000 0.062500 ) ( 280 760 80 1.500000 0.125000 ) ) +( ( 264 760 72 1.750000 0 ) ( 264 760 76 1.750000 0.062500 ) ( 264 760 80 1.750000 0.125000 ) ) +( ( 264 744 72 2 0 ) ( 264 744 76 2 0.062500 ) ( 264 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 280 760 72 7.375000 -11.875000 ) ( 264 760 72 7.125000 -11.875000 ) ( 264 744 72 7.125000 -11.625000 ) ) +( ( 296 760 72 7.625000 -11.875000 ) ( 280 744 72 7.375000 -11.625000 ) ( 264 728 72 7.125000 -11.375000 ) ) +( ( 296 744 72 7.625000 -11.625000 ) ( 296 728 72 7.625000 -11.375000 ) ( 280 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 264 744 80 7.125000 -11.625000 ) ( 264 760 80 7.125000 -11.875000 ) ( 280 760 80 7.375000 -11.875000 ) ) +( ( 264 728 80 7.125000 -11.375000 ) ( 280 744 80 7.375000 -11.625000 ) ( 296 760 80 7.625000 -11.875000 ) ) +( ( 280 728 80 7.375000 -11.375000 ) ( 296 728 80 7.625000 -11.375000 ) ( 296 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 14 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 96 744 72 0 0 ) ( 96 744 76 0 0.062500 ) ( 96 744 80 0 0.125000 ) ) +( ( 96 728 72 0.250000 0 ) ( 96 728 76 0.250000 0.062500 ) ( 96 728 80 0.250000 0.125000 ) ) +( ( 112 728 72 0.500000 0 ) ( 112 728 76 0.500000 0.062500 ) ( 112 728 80 0.500000 0.125000 ) ) +( ( 128 728 72 0.750000 0 ) ( 128 728 76 0.750000 0.062500 ) ( 128 728 80 0.750000 0.125000 ) ) +( ( 128 744 72 1 0 ) ( 128 744 76 1 0.062500 ) ( 128 744 80 1 0.125000 ) ) +( ( 128 760 72 1.250000 0 ) ( 128 760 76 1.250000 0.062500 ) ( 128 760 80 1.250000 0.125000 ) ) +( ( 112 760 72 1.500000 0 ) ( 112 760 76 1.500000 0.062500 ) ( 112 760 80 1.500000 0.125000 ) ) +( ( 96 760 72 1.750000 0 ) ( 96 760 76 1.750000 0.062500 ) ( 96 760 80 1.750000 0.125000 ) ) +( ( 96 744 72 2 0 ) ( 96 744 76 2 0.062500 ) ( 96 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 112 760 72 7.375000 -11.875000 ) ( 96 760 72 7.125000 -11.875000 ) ( 96 744 72 7.125000 -11.625000 ) ) +( ( 128 760 72 7.625000 -11.875000 ) ( 112 744 72 7.375000 -11.625000 ) ( 96 728 72 7.125000 -11.375000 ) ) +( ( 128 744 72 7.625000 -11.625000 ) ( 128 728 72 7.625000 -11.375000 ) ( 112 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 96 744 80 7.125000 -11.625000 ) ( 96 760 80 7.125000 -11.875000 ) ( 112 760 80 7.375000 -11.875000 ) ) +( ( 96 728 80 7.125000 -11.375000 ) ( 112 744 80 7.375000 -11.625000 ) ( 128 760 80 7.625000 -11.875000 ) ) +( ( 112 728 80 7.375000 -11.375000 ) ( 128 728 80 7.625000 -11.375000 ) ( 128 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 15 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 0 744 72 0 0 ) ( 0 744 76 0 0.062500 ) ( 0 744 80 0 0.125000 ) ) +( ( 0 728 72 0.250000 0 ) ( 0 728 76 0.250000 0.062500 ) ( 0 728 80 0.250000 0.125000 ) ) +( ( 16 728 72 0.500000 0 ) ( 16 728 76 0.500000 0.062500 ) ( 16 728 80 0.500000 0.125000 ) ) +( ( 32 728 72 0.750000 0 ) ( 32 728 76 0.750000 0.062500 ) ( 32 728 80 0.750000 0.125000 ) ) +( ( 32 744 72 1 0 ) ( 32 744 76 1 0.062500 ) ( 32 744 80 1 0.125000 ) ) +( ( 32 760 72 1.250000 0 ) ( 32 760 76 1.250000 0.062500 ) ( 32 760 80 1.250000 0.125000 ) ) +( ( 16 760 72 1.500000 0 ) ( 16 760 76 1.500000 0.062500 ) ( 16 760 80 1.500000 0.125000 ) ) +( ( 0 760 72 1.750000 0 ) ( 0 760 76 1.750000 0.062500 ) ( 0 760 80 1.750000 0.125000 ) ) +( ( 0 744 72 2 0 ) ( 0 744 76 2 0.062500 ) ( 0 744 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 16 760 72 7.375000 -11.875000 ) ( 0 760 72 7.125000 -11.875000 ) ( 0 744 72 7.125000 -11.625000 ) ) +( ( 32 760 72 7.625000 -11.875000 ) ( 16 744 72 7.375000 -11.625000 ) ( 0 728 72 7.125000 -11.375000 ) ) +( ( 32 744 72 7.625000 -11.625000 ) ( 32 728 72 7.625000 -11.375000 ) ( 16 728 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 0 744 80 7.125000 -11.625000 ) ( 0 760 80 7.125000 -11.875000 ) ( 16 760 80 7.375000 -11.875000 ) ) +( ( 0 728 80 7.125000 -11.375000 ) ( 16 744 80 7.375000 -11.625000 ) ( 32 760 80 7.625000 -11.875000 ) ) +( ( 16 728 80 7.375000 -11.375000 ) ( 32 728 80 7.625000 -11.375000 ) ( 32 744 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 16 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( -72 928 72 0 0 ) ( -72 928 76 0 0.062500 ) ( -72 928 80 0 0.125000 ) ) +( ( -72 912 72 0.250000 0 ) ( -72 912 76 0.250000 0.062500 ) ( -72 912 80 0.250000 0.125000 ) ) +( ( -56 912 72 0.500000 0 ) ( -56 912 76 0.500000 0.062500 ) ( -56 912 80 0.500000 0.125000 ) ) +( ( -40 912 72 0.750000 0 ) ( -40 912 76 0.750000 0.062500 ) ( -40 912 80 0.750000 0.125000 ) ) +( ( -40 928 72 1 0 ) ( -40 928 76 1 0.062500 ) ( -40 928 80 1 0.125000 ) ) +( ( -40 944 72 1.250000 0 ) ( -40 944 76 1.250000 0.062500 ) ( -40 944 80 1.250000 0.125000 ) ) +( ( -56 944 72 1.500000 0 ) ( -56 944 76 1.500000 0.062500 ) ( -56 944 80 1.500000 0.125000 ) ) +( ( -72 944 72 1.750000 0 ) ( -72 944 76 1.750000 0.062500 ) ( -72 944 80 1.750000 0.125000 ) ) +( ( -72 928 72 2 0 ) ( -72 928 76 2 0.062500 ) ( -72 928 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( -56 944 72 7.375000 -11.875000 ) ( -72 944 72 7.125000 -11.875000 ) ( -72 928 72 7.125000 -11.625000 ) ) +( ( -40 944 72 7.625000 -11.875000 ) ( -56 928 72 7.375000 -11.625000 ) ( -72 912 72 7.125000 -11.375000 ) ) +( ( -40 928 72 7.625000 -11.625000 ) ( -40 912 72 7.625000 -11.375000 ) ( -56 912 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( -72 928 80 7.125000 -11.625000 ) ( -72 944 80 7.125000 -11.875000 ) ( -56 944 80 7.375000 -11.875000 ) ) +( ( -72 912 80 7.125000 -11.375000 ) ( -56 928 80 7.375000 -11.625000 ) ( -40 944 80 7.625000 -11.875000 ) ) +( ( -56 912 80 7.375000 -11.375000 ) ( -40 912 80 7.625000 -11.375000 ) ( -40 928 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 17 +{ +"type" "patchCapped" +"classname" "func_group" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( -72 824 72 0 0 ) ( -72 824 76 0 0.062500 ) ( -72 824 80 0 0.125000 ) ) +( ( -72 808 72 0.250000 0 ) ( -72 808 76 0.250000 0.062500 ) ( -72 808 80 0.250000 0.125000 ) ) +( ( -56 808 72 0.500000 0 ) ( -56 808 76 0.500000 0.062500 ) ( -56 808 80 0.500000 0.125000 ) ) +( ( -40 808 72 0.750000 0 ) ( -40 808 76 0.750000 0.062500 ) ( -40 808 80 0.750000 0.125000 ) ) +( ( -40 824 72 1 0 ) ( -40 824 76 1 0.062500 ) ( -40 824 80 1 0.125000 ) ) +( ( -40 840 72 1.250000 0 ) ( -40 840 76 1.250000 0.062500 ) ( -40 840 80 1.250000 0.125000 ) ) +( ( -56 840 72 1.500000 0 ) ( -56 840 76 1.500000 0.062500 ) ( -56 840 80 1.500000 0.125000 ) ) +( ( -72 840 72 1.750000 0 ) ( -72 840 76 1.750000 0.062500 ) ( -72 840 80 1.750000 0.125000 ) ) +( ( -72 824 72 2 0 ) ( -72 824 76 2 0.062500 ) ( -72 824 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( -56 840 72 7.375000 -11.875000 ) ( -72 840 72 7.125000 -11.875000 ) ( -72 824 72 7.125000 -11.625000 ) ) +( ( -40 840 72 7.625000 -11.875000 ) ( -56 824 72 7.375000 -11.625000 ) ( -72 808 72 7.125000 -11.375000 ) ) +( ( -40 824 72 7.625000 -11.625000 ) ( -40 808 72 7.625000 -11.375000 ) ( -56 808 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( -72 824 80 7.125000 -11.625000 ) ( -72 840 80 7.125000 -11.875000 ) ( -56 840 80 7.375000 -11.875000 ) ) +( ( -72 808 80 7.125000 -11.375000 ) ( -56 824 80 7.375000 -11.625000 ) ( -40 840 80 7.625000 -11.875000 ) ) +( ( -56 808 80 7.375000 -11.375000 ) ( -40 808 80 7.625000 -11.375000 ) ( -40 824 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 18 +{ +"classname" "func_group" +"type" "patchCapped" +// brush 0 + { + patchDef2 + { + gothic_trim/wood2 + ( 9 3 0 0 0 ) +( +( ( 552 824 72 0 0 ) ( 552 824 76 0 0.062500 ) ( 552 824 80 0 0.125000 ) ) +( ( 552 808 72 0.250000 0 ) ( 552 808 76 0.250000 0.062500 ) ( 552 808 80 0.250000 0.125000 ) ) +( ( 568 808 72 0.500000 0 ) ( 568 808 76 0.500000 0.062500 ) ( 568 808 80 0.500000 0.125000 ) ) +( ( 584 808 72 0.750000 0 ) ( 584 808 76 0.750000 0.062500 ) ( 584 808 80 0.750000 0.125000 ) ) +( ( 584 824 72 1 0 ) ( 584 824 76 1 0.062500 ) ( 584 824 80 1 0.125000 ) ) +( ( 584 840 72 1.250000 0 ) ( 584 840 76 1.250000 0.062500 ) ( 584 840 80 1.250000 0.125000 ) ) +( ( 568 840 72 1.500000 0 ) ( 568 840 76 1.500000 0.062500 ) ( 568 840 80 1.500000 0.125000 ) ) +( ( 552 840 72 1.750000 0 ) ( 552 840 76 1.750000 0.062500 ) ( 552 840 80 1.750000 0.125000 ) ) +( ( 552 824 72 2 0 ) ( 552 824 76 2 0.062500 ) ( 552 824 80 2 0.125000 ) ) +) + } + } +// brush 1 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 568 840 72 7.375000 -11.875000 ) ( 552 840 72 7.125000 -11.875000 ) ( 552 824 72 7.125000 -11.625000 ) ) +( ( 584 840 72 7.625000 -11.875000 ) ( 568 824 72 7.375000 -11.625000 ) ( 552 808 72 7.125000 -11.375000 ) ) +( ( 584 824 72 7.625000 -11.625000 ) ( 584 808 72 7.625000 -11.375000 ) ( 568 808 72 7.375000 -11.375000 ) ) +) + } + } +// brush 2 + { + patchDef2 + { + gothic_trim/wood2 + ( 3 3 0 0 0 ) +( +( ( 552 824 80 7.125000 -11.625000 ) ( 552 840 80 7.125000 -11.875000 ) ( 568 840 80 7.375000 -11.875000 ) ) +( ( 552 808 80 7.125000 -11.375000 ) ( 568 824 80 7.375000 -11.625000 ) ( 584 840 80 7.625000 -11.875000 ) ) +( ( 568 808 80 7.375000 -11.375000 ) ( 584 808 80 7.625000 -11.375000 ) ( 584 824 80 7.625000 -11.625000 ) ) +) + } + } +} +// entity 19 +{ +"classname" "info_player_start" +"origin" "576 72 352" +} +// entity 20 +{ +"classname" "light" +"light" "600" +"origin" "256 -448 336" +} diff --git a/docs/developer/UML/modules.zargo b/docs/developer/UML/modules.zargo new file mode 100644 index 00000000..5f46c24a Binary files /dev/null and b/docs/developer/UML/modules.zargo differ diff --git a/docs/developer/WIN32BETA b/docs/developer/WIN32BETA new file mode 100644 index 00000000..2e71c8f1 --- /dev/null +++ b/docs/developer/WIN32BETA @@ -0,0 +1,247 @@ +THIS FILE IS OFFICIALLY OUTDATED CLOSED NO LONGER USED + +All the stuff that needs to be settled for win32 beta of GtkRadiant: + +- need to add more code checking BSP process execution (Q_Exec or engine spawning) +(TTimo: Assigned to self) + +- the BSP commands are switching in order randomly + +- Need more error checking when executing q3map (in any mode) + (Q_Exec goes out of resources sometimes) + +- Region compiling is broken + +- GL font on win32 uses the default system font .. which can be .. yiddish or cyrilic etc. + force to courier? + NOTE: actually I'm not sure this really is the problem .. some people are getting weird bitmap fonts + +- view n2 needs to wake on whatever widget you raise first +Fixed. + +- entity information box on entity inspector displays with nasty characters + maybe the same problem as above? + +- map snapshot has a bug (allocation and stuff around Str class) +OK (don't use CString stuff = other_stuff; do CString stuff; stuff = other_stuff;) + +- sleep mode on view 2&3 crashing +Fixed for the floating windows mode. + +- sleep mode: need to bring back the bitmap fonts +Fixed + +- sleep mode: need to rebuild the data on models and patches! (call Map_BuildBrushData) +Calling Map_BuildBrushData in Mainframe::OnSleep. +OK (added some crap to reload) ... Maybe more to do + +- sleep mode: need to trigger out sleep mode when raising again! +Done. + +- console: we want output while it's processing .. otherwise it's just useless .. +OK! + +- win32 help format distribution of the manual? + +- update the links page, add stuff from the forum + (TTimo .. will do) + +- check maximized state is working(?) + +<<<<<<< WIN32BETA +- view n.3 crashes on exit in MainFrame::OnDestroy.. + (trying to save prefs) + +Fixed. +======= +- remove high color textures from prefs .. remnant from Q2 .. always on .. off is broken anyway +Done. + +- test sleep mode! + +- check my project template bug checking code is ok + NOTE: it's fuxored. Need a central function to shrink and standardize file paths: + lowercase + short dos8.2 names + unix style forward slashes / + -> then perform the comparisons + +- surface and patch inspector: +[23:37] WHen you make adjustments in surface window, it should show results immediately. Pressing Apply after each change to see how it looks is a pain. +[23:41] true +[23:42] is it the behaviour of the MFC version or not? +[23:42] on the MFC version when you make adjustements it updates on the fly right? +[23:43] Yeah. +[23:44] ANd the fit and axial buittons do not seem to do anything, even if you press Apply afterwords. +[23:44] HDidn't check patches at all, don't know about them. +Fixed + +- check the engine path changes I made didn't break on linux + +- user INI path in prefs: need to look into it .. but my guess is .. it's broken/useless + +- view n.2: doesn't remember the window positions +Fixed + +- view n.2: the Z window doesn't shrink below the default size +Fixed + +- do some performance comparisons with 202 + (specially BrushBuild step) + +- a quickstart.txt file with some explanations about the transition 202 -> GtkRadiant? + like: + what are the actual new features + (new way to deal with project settings, sleep mode, net connect for BSP process) + what are we testing in the alpha + where to report bugs, who is doing what + how to contribute as a coder + some of this stuff goes into the changelog! +>>>>>>> 1.15 + +- is there a way to have something actually drawing when moving the splitters? + +- view n.4: the Z window gets pushed when you resize with the leftmost vertical splitter + +- disable the groups view (it's not functional) +Fixed + +- floating windows mode (n.2 in prefs): + if a message gets printed, the console will raise up. But if something else was active + (like Entities) .. the widgets are still active .. start moving the mouse on top of + the entity window and stuff will start to appear + +- floating windows mode (n.2 in prefs): + when moving in the 2D window the console outputs lots of error messages: + ERROR: glXMakeCurrent failed.. Error:0 + Please restart Q3Radiant if the Map view is not working + but everything seems to work fine, no graphic glitches + +- floating windows mode (n.2 in prefs): + the Z window doesn't resize + +- more window position storage, store maximized state and position on the desktop +Note: maximized state doesn't exist under X, it depends on the WM. + +- keyboard shortcuts break if click in the console window, it keeps the focus.. +Fixed (using GtkText again). + +<<<<<<< WIN32BETA +- upgrade to latest Gtk distribution (there's been a new release) and make sure we are ok + +- enable undo/redo + +Fixed. + +- make sure the BSP monitoring stuff is stored in registry + +- remove the "Buggy GL driver" thing, we'll use another strategy for hardware-specific issues + +- remove the QE4 update model, force always on + +- assertion failed when raising the prefs box for the first time? + +======= +>>>>>>> 1.15 +- use the other view modes to check nothing's wrong with them + +- win32 console doesn't release the focus if you click into it + it also has resize issues .. doesn't seem to want to shrink down +Fixed the focus problem (using GtkText again). + +- some problems with file permissions under linux? + seems it used to create the log and pid file with no write permissions for the user + ends up that when you try to open the console file for output it fails or the .pid remains when you try to erase it + (NOTE: I need someone with an old install to check that) + on win32 more or less same problem. It's created with an archive flag that + fordibs removal as well. +<<<<<<< WIN32BETA + +Fixed: missing fclose in main.cpp that could be causing this problem. +======= +leo: there was a missing fclose in main.cpp that could be causing this problem. +>>>>>>> 1.15 + +- engine path / project loading + when we load a template project file we are using the engine path to build it + if user has several installs and old prefs that rely on another engine path, project + template construction fails. (i.e. is still based on old engine path) + I don't know how to solve: + -check the engine path when we do the template thing? + -check engine path at each project load + actually we can check everytime and ask the user, it seems this happens in weird cases + .. anyway it's not supposed to be a "stable" situation anytime + +- make sure the BSP monitoring stuff is stored in registry +OK (added) + +- the Radiant logo is screwed in the about dialog box? +OK (Leo:) The logo.bmp file in the CVS server is screwed, fixed. + +- remove the "Buggy GL driver" thing, we'll use another strategy for hardware-specific issues +OK (Leo fixed) + +- engine path dialog is broken (need split to get the actual path) +OK (splitting the path, can't edit it must go through the dialog) + +- assertion failed when raising the prefs box for the first time? +WORKSFORM (can't reprodcue this one) +leo: Used to happen sometimes for me (not anymore ?) + +- view n.3 crashes on exit in MainFrame::OnDestroy.. + (trying to save prefs) +Fixed + +- remove the QE4 update model, force always on +Done. + +- custom keyboard shortcuts is buggy .. works halfway +OK all fixed + +- upgrade to latest Gtk distribution (there's been a new release) and make sure we are ok +OK (tested and stuff .. I'm using the latest in the setup) + +- enable undo/redo +leo: it's already enabled +(ok fixed, had to enable back the menus) +OK + +- project settings. GtkRadiant uses a new version of project settings. +Default name is quakev2.qe4 +Must be able to read old project settings as well .. BSP monitoring disabled +if using old project settings +When searching for project settings, will look for quakev2.qe4 first, then quake.qe4 +No more overwriting the loaded project settings. We detect "template" project settings +(ie. the ones we distribute) with a "user_project" "1" keyval +When a template is loaded, save as userxx.qe4 where xx = 1 2 3 4 5 6 etc. +It will trash scripts/ a bit but it doesn't matter .. + +I did some cleanup to the project code, tested on both linux and win32, will need more +testing and stuff while in alpha/beta I guess. But it should be stabilized now. + +OK + +-unify the project file syntax on both platforms! (and yes, the problem is + radiant on linux is in quake3/ instead of quake3/tools) + the expansion rules are not the same between version 1 and v2 project files! + we change the string names so we don't have to adapt.. + NOTE: later we'll remove support for old v1 syntax? + NOTE: we may need to add a g_strHomePath for ~/.q3a/ on linux + +see above, the v2 project file is in data/quakev2.qe4 + +OK + +- preferences dialog for BSP monitoring: do / don't do, launch engine after + compilation. + Right now all the params are in prefs, just need the interface + +OK, need more testing, and the sleep mode code +.. may also want to add more configurable stuff later .. though I'd rather have it done +by a plugin + +- in QE_LoadProject, check the template reading works ok, specially with the new +globals Leo added some time ago + +OK, tested on both win32 and linux + diff --git a/docs/developer/WIN32SETUP b/docs/developer/WIN32SETUP new file mode 100644 index 00000000..2fdd2f3b --- /dev/null +++ b/docs/developer/WIN32SETUP @@ -0,0 +1,36 @@ +Summary of TODO and BUGS for GtkRadiant setup files on win32: + +(most of the times the stuff has to be checked in both versions of the setup) + +- installer back button is broken +OK (it just bails out if you try to back instead) + +- need proper setup splash screen + is there someone skilled with gimp at loki :) ? +OK (Maj did) + +- don't have several files for license and readme .. use a central version + (scripts or proper settings in InstallShield) + in private/GtkRadiant/data <- where we put all the install specific stuff? + NOTE: we could put the gtk.dll libs there as well +OK + +- remove curry from the alpha (it's still MFC) + remove GenSurf as well .. try to get some info from David Hyde +OK + +- have a changelog for the end user (not the DevDocs/CHANGES kind of thing) + something that focuses on features and bug fixes more than on the internals +OK .. need to fill it up a bit + +- use quakev2.qe4 instead of quake.qe4 (both in nomedia and full) + added it in the advanced files section + (need to prompt the user about overwriting it) + for now the nomedia installation needs to run on top of 202 +OK + +- fix bug with shaders names (skies and liquids) +OK + +- add Wolfen to the credits! +OK \ No newline at end of file diff --git a/docs/developer/XML.txt b/docs/developer/XML.txt new file mode 100644 index 00000000..2e2ef596 --- /dev/null +++ b/docs/developer/XML.txt @@ -0,0 +1,27 @@ +printf mess in q3map +(and in the libs) + +q3map: several breeds .. qprintf _printf printf +should all resolve to use a single Sys_Printf thing +and put #define printf .. + +for the static libs? need to use function pointers.. + +q3map uses common/cmdlib.c +Radiant links against cmdlib.lib based on libs/cmdlib/cmdlib.cpp + +but eventually we'll want to use the same Sys_Printf scheme in q3map AND Radiant? +qprintf and _printf are defined in common/cmdlib.c +BUT: modifying cmdlib would probably break bspc and other stuff that relies on it? + +moving q3map to use a custom version of cmdlib.c in q3map/cmdlib.c +removing the qprintf and _printf stuff, moving to a seperate printout.c file + +compiling libxml on win32: need to turn off a bunch of stuff. +problem: we got two xmlversion.h files?? +we can't get rid of using libxml/xmlversion.h, so the solution is to get rid of xmlversion.h +(add ../libxml to the paths) + +fuck! +we also compile some .c files from common/ ! +-> create a common2/ dir .. diff --git a/docs/developer/XMLPush/ReadMe.txt b/docs/developer/XMLPush/ReadMe.txt new file mode 100644 index 00000000..f2c6ab49 --- /dev/null +++ b/docs/developer/XMLPush/ReadMe.txt @@ -0,0 +1,34 @@ +======================================================================== + CONSOLE APPLICATION : XMLPush +======================================================================== + + +AppWizard has created this XMLPush application for you. + +This file contains a summary of what you will find in each of the files that +make up your XMLPush application. + +XMLPush.dsp + This file (the project file) contains information at the project level and + is used to build a single project or subproject. Other users can share the + project (.dsp) file, but they should export the makefiles locally. + +XMLPush.cpp + This is the main application source file. + + +///////////////////////////////////////////////////////////////////////////// +Other standard files: + +StdAfx.h, StdAfx.cpp + These files are used to build a precompiled header (PCH) file + named XMLPush.pch and a precompiled types file named StdAfx.obj. + + +///////////////////////////////////////////////////////////////////////////// +Other notes: + +AppWizard uses "TODO:" to indicate parts of the source code you +should add to or customize. + +///////////////////////////////////////////////////////////////////////////// diff --git a/docs/developer/XMLPush/StdAfx.cpp b/docs/developer/XMLPush/StdAfx.cpp new file mode 100644 index 00000000..e8b9d80f --- /dev/null +++ b/docs/developer/XMLPush/StdAfx.cpp @@ -0,0 +1,8 @@ +// stdafx.cpp : source file that includes just the standard includes +// XMLPush.pch will be the pre-compiled header +// stdafx.obj will contain the pre-compiled type information + +#include "stdafx.h" + +// TODO: reference any additional headers you need in STDAFX.H +// and not in this file diff --git a/docs/developer/XMLPush/StdAfx.h b/docs/developer/XMLPush/StdAfx.h new file mode 100644 index 00000000..fbb8d5e2 --- /dev/null +++ b/docs/developer/XMLPush/StdAfx.h @@ -0,0 +1,22 @@ +// stdafx.h : include file for standard system include files, +// or project specific include files that are used frequently, but +// are changed infrequently +// + +#if !defined(AFX_STDAFX_H__323F1140_CFC1_11D4_A457_0004AC96D4C3__INCLUDED_) +#define AFX_STDAFX_H__323F1140_CFC1_11D4_A457_0004AC96D4C3__INCLUDED_ + +#if _MSC_VER > 1000 +#pragma once +#endif // _MSC_VER > 1000 + + +// TODO: reference additional headers your program requires here + +//{{AFX_INSERT_LOCATION}} +// Microsoft Visual C++ will insert additional declarations immediately before the previous line. + +#endif // !defined(AFX_STDAFX_H__323F1140_CFC1_11D4_A457_0004AC96D4C3__INCLUDED_) + +#include "libxml/parser.h" +#include "libxml/tree.h" diff --git a/docs/developer/XMLPush/XMLDump.xml b/docs/developer/XMLPush/XMLDump.xml new file mode 100644 index 00000000..fcbaaaee --- /dev/null +++ b/docs/developer/XMLPush/XMLDump.xml @@ -0,0 +1,8 @@ + + +Q3Map - built for GtkRadiant v1.1b - based on v1.0q (c) 1999 Id Software Inc. + +************ ERROR ************ +usage: q3map [general options] [options] mapfile + + diff --git a/docs/developer/XMLPush/XMLPush.cpp b/docs/developer/XMLPush/XMLPush.cpp new file mode 100644 index 00000000..9edc3c63 --- /dev/null +++ b/docs/developer/XMLPush/XMLPush.cpp @@ -0,0 +1,30 @@ +// XMLPush.cpp : Defines the entry point for the console application. +// + +#include "stdafx.h" + +int main(int argc, char* argv[]) +{ + FILE *f; + xmlDocPtr doc; + + f = fopen("XMLDump.xml", "r"); + if (f != NULL) { + int res, size = 1024; + char chars[1024]; + xmlParserCtxtPtr ctxt; + + res = fread(chars, 1, 4, f); + if (res > 0) { + ctxt = xmlCreatePushParserCtxt(NULL, NULL, + chars, res, "foooo (filename)?"); + while ((res = fread(chars, 1, size, f)) > 0) { + xmlParseChunk(ctxt, chars, res, 0); + } + xmlParseChunk(ctxt, chars, 0, 1); + doc = ctxt->myDoc; + xmlFreeParserCtxt(ctxt); + } + } + return 0; +} diff --git a/docs/developer/XMLmap.txt b/docs/developer/XMLmap.txt new file mode 100644 index 00000000..a88dd7f9 --- /dev/null +++ b/docs/developer/XMLmap.txt @@ -0,0 +1,27 @@ +XMLmap branch: + +need to move the map loading / saving code out in a module +what are the main dependencies? + +main functions to move out: +Map_LoadFile +Map_SaveFile +(and all their direct dependencies/call graph) +ex Entity_Parse Brush_Parse Entity_Write Brush_Write + +but? even changing to XML format we would need those functions too? +is it worth having the .map and .xmlmap through a same interface? + +what dependencies? +-> active_brushes +-> GetToken etc. +-> LoadFile (load into a buffer) .. that's VFS right? + +first step: move some code out in map module and try to compile it.. +Map_LoadFile for example +or the whole map.cpp? + +first problem: entity_t is declared in entity.h, currently not available to +the plugin API. Clean way would be to create a wrapper, but speed says we +should move entity_t to qertypes.h.. + diff --git a/docs/developer/changes.201.202 b/docs/developer/changes.201.202 new file mode 100644 index 00000000..449356f7 --- /dev/null +++ b/docs/developer/changes.201.202 @@ -0,0 +1,455 @@ +diff -rup ../Q3Radiant201/PrefsDlg.cpp Q3Radiant/PrefsDlg.cpp +--- ../Q3Radiant201/PrefsDlg.cpp Mon Jun 26 12:31:00 2000 ++++ Q3Radiant/PrefsDlg.cpp Thu Aug 3 17:19:16 2000 +@@ -224,6 +232,8 @@ void CPrefsDlg::DoDataExchange(CDataExch + DDX_Text(pDX, IDC_EDIT_UNDOLEVELS, m_nUndoLevels); + DDV_MinMaxInt(pDX, m_nUndoLevels, 1, 64); + DDX_Check(pDX, IDC_CHECK_VERTEXMODE, m_bVertexSplit); ++ DDX_Check(pDX, IDC_CHECK_LOG, m_bLogConsole); ++ DDX_Check(pDX, IDC_NOALPHA, m_bDisableAlphaChannel); + //}}AFX_DATA_MAP + } + +@@ -236,6 +246,7 @@ BEGIN_MESSAGE_MAP(CPrefsDlg, CDialog) + ON_BN_CLICKED(IDC_BTN_BROWSEUSERINI, OnBtnBrowseuserini) + ON_CBN_SELCHANGE(IDC_COMBO_WHATGAME, OnSelchangeComboWhatgame) + ON_BN_CLICKED(IDC_BUTTON_CLEAN, OnButtonClean) ++ ON_BN_CLICKED(IDC_NOALPHA, OnNoalpha) + //}}AFX_MSG_MAP + END_MESSAGE_MAP() + +@@ -332,7 +344,7 @@ bool SetQdirFromPath( const char *path ) + len = strlen(BASEDIRNAME); + for (c=path+strlen(path)-1 ; c != path ; c--) + { +- int i; ++ unsigned int i; + + if (strnicmp (c, BASEDIRNAME, len) == 0) + { +@@ -448,7 +460,12 @@ void CPrefsDlg::LoadPrefs() + + m_strQuake2 = AfxGetApp()->GetProfileString(PREF_SECTION, Q2_KEY); + // if the path to the engine is empty, we set this flag to call InitEnginePath later +- if (m_strQuake2.GetLength() == 0) ++ // if the path to the engine is empty or points to a file that doesn't exist we call InitEnginePath ++ struct _finddata_t fileinfo; ++ int handle; ++ handle = _findfirst (m_strQuake2.GetBuffer(0), &fileinfo); ++ _findclose( handle ); ++ if (handle == -1 || m_strQuake2.GetLength() == 0) + InitEnginePath(); + + m_iLastLightIntensity = AfxGetApp()->GetProfileInt(PREF_SECTION, "LastLightIntensity", 300); +@@ -697,4 +731,10 @@ void CPrefsDlg::OnButtonClean() + theApp.ResetRegistry(); + g_pParentWnd->OnFileExit(); + } ++} ++ ++void CPrefsDlg::OnNoalpha() ++{ ++ if (static_cast(GetDlgItem(IDC_NOALPHA))->GetState() & 0x0003) ++ MessageBox( "If alpha channel support is disabled, Curry plugin might not work as expected.", "Alpha channel support", MB_OK ); + } +diff -rup ../Q3Radiant201/Radiant.rc Q3Radiant/Radiant.rc +--- ../Q3Radiant201/Radiant.rc Mon Jun 26 12:31:00 2000 ++++ Q3Radiant/Radiant.rc Thu Aug 3 17:19:22 2000 +@@ -1518,7 +1520,7 @@ BEGIN + LTEXT "Height",IDC_STATIC,131,136,22,8 + END + +-IDD_DLG_PREFS DIALOG DISCARDABLE 0, 0, 386, 351 ++IDD_DLG_PREFS DIALOG DISCARDABLE 0, 0, 386, 380 + STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU + CAPTION "Q3Radiant Preferences" + FONT 8, "MS Sans Serif" +@@ -1561,103 +1563,108 @@ BEGIN + CONTROL "Texture subset",IDC_CHECK_TEXTUREWINDOW,"Button", + BS_AUTOCHECKBOX | WS_TABSTOP,308,94,63,10 + CONTROL "Right click to drop entities",IDC_CHECK_RIGHTCLICK, +- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,137,95,10 ++ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,150,95,10 + CONTROL "Face selection",IDC_CHECK_FACE,"Button",BS_AUTOCHECKBOX | +- WS_TABSTOP,13,149,62,10 +- EDITTEXT IDC_EDIT_ROTATION,58,161,24,12,ES_AUTOHSCROLL ++ WS_TABSTOP,13,162,62,10 ++ EDITTEXT IDC_EDIT_ROTATION,58,174,24,12,ES_AUTOHSCROLL + CONTROL "ALT + multi-drag",IDC_CHECK_ALTDRAG,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,114,137,68,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,114,150,68,10 + CONTROL "Snap T to Grid",IDC_CHECK_SNAPT,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,114,149,62,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,114,162,62,10 + CONTROL "Mouse chaser",IDC_CHECK_MOUSECHASE,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,114,160,68,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,114,173,68,10 + CONTROL "Patch Toolbar",IDC_CHECK_WIDETOOLBAR,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,193,137,61,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,193,150,61,10 + CONTROL "Light drawing",IDC_CHECK_LIGHTDRAW,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,193,149,58,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,193,162,58,10 + CONTROL "Paint sizing info",IDC_CHECK_SIZEPAINT,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,193,160,65,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,193,173,65,10 + CONTROL "Hi Color Textures",IDC_CHECK_HICOLOR,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,281,137,70,10 +- LTEXT "Startup Shaders:",IDC_STATIC,281,150,54,8 +- COMBOBOX IDC_COMBO_SHADERS,281,160,82,54,CBS_DROPDOWNLIST | ++ BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | ++ WS_TABSTOP,281,150,70,10 ++ LTEXT "Startup Shaders:",IDC_STATIC,281,163,54,8 ++ COMBOBOX IDC_COMBO_SHADERS,281,173,82,54,CBS_DROPDOWNLIST | + WS_VSCROLL | WS_TABSTOP +- EDITTEXT IDC_EDIT_QUAKE2,13,215,229,12,ES_AUTOHSCROLL +- PUSHBUTTON "...",IDC_BTN_BROWSE,248,216,16,11 ++ EDITTEXT IDC_EDIT_QUAKE2,13,228,229,12,ES_AUTOHSCROLL ++ PUSHBUTTON "...",IDC_BTN_BROWSE,248,230,16,11 + CONTROL "Use internal (DLL) QBSP....",IDC_CHECK_INTERNALBSP, +- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,234,102,10 ++ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,247,102,10 + CONTROL "Don't clamp plane points",IDC_CHECK_NOCLAMP,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,13,246,93,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,13,260,93,10 + CONTROL "Snapshots",IDC_CHECK_SNAPSHOTS,"Button",BS_AUTOCHECKBOX | +- WS_TABSTOP,13,258,49,10 ++ WS_TABSTOP,13,271,49,10 + CONTROL "Use +setgame for run",IDC_CHECK_SETGAME,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,13,270,83,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,13,284,83,10 + CONTROL "Run game after QBSP3...",IDC_CHECK_RUNQUAKE,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,121,234,96,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,121,247,96,10 + CONTROL "Load last project on open",IDC_CHECK_LOADLAST,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,121,246,96,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,121,260,96,10 + CONTROL "Load last map on open",IDC_CHECK_LOADLASTMAP,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,121,258,88,10 ++ BS_AUTOCHECKBOX | WS_TABSTOP,121,271,88,10 + CONTROL "Auto save every ",IDC_CHECK_AUTOSAVE,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,121,270,66,10 +- EDITTEXT IDC_EDIT_AUTOSAVE,188,270,27,12,ES_AUTOHSCROLL | ++ BS_AUTOCHECKBOX | WS_TABSTOP,121,284,66,10 ++ EDITTEXT IDC_EDIT_AUTOSAVE,188,284,27,12,ES_AUTOHSCROLL | + ES_NUMBER + CONTROL "Spin1",IDC_SPIN_AUTOSAVE,"msctls_updown32",UDS_WRAP | + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | +- UDS_ARROWKEYS,212,268,11,14 +- LTEXT "Status point size:",IDC_STATIC,258,235,54,8 +- EDITTEXT IDC_EDIT_STATUSPOINTSIZE,315,233,29,12,ES_AUTOHSCROLL ++ UDS_ARROWKEYS,212,282,11,14 ++ LTEXT "Status point size:",IDC_STATIC,258,249,54,8 ++ EDITTEXT IDC_EDIT_STATUSPOINTSIZE,315,247,29,12,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN_POINTSIZE,"msctls_updown32",UDS_WRAP | + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | +- UDS_ARROWKEYS,344,232,11,14 +- LTEXT "Undo Levels:",IDC_STATIC,258,248,43,8 +- EDITTEXT IDC_EDIT_UNDOLEVELS,315,246,29,12,ES_AUTOHSCROLL ++ UDS_ARROWKEYS,344,246,11,14 ++ LTEXT "Undo Levels:",IDC_STATIC,258,262,43,8 ++ EDITTEXT IDC_EDIT_UNDOLEVELS,315,260,29,12,ES_AUTOHSCROLL + CONTROL "Spin1",IDC_SPIN_UNDO,"msctls_updown32",UDS_WRAP | + UDS_SETBUDDYINT | UDS_ALIGNRIGHT | UDS_AUTOBUDDY | +- UDS_ARROWKEYS,344,246,11,14 ++ UDS_ARROWKEYS,344,260,11,14 + CONTROL "Use PAK/PK3 file(s):",IDC_CHECK_PAK,"Button", +- BS_AUTOCHECKBOX | WS_TABSTOP,13,289,81,10 +- EDITTEXT IDC_EDIT_PAKFILE,95,288,227,12,ES_AUTOHSCROLL +- PUSHBUTTON "...",IDC_BTN_BROWSEPAK,328,289,16,11 +- EDITTEXT IDC_EDIT_PREFABPATH,95,305,227,12,ES_AUTOHSCROLL +- PUSHBUTTON "...",IDC_BTN_BROWSEPREFAB,328,306,16,11 +- EDITTEXT IDC_EDIT_USERPATH,95,322,227,12,ES_AUTOHSCROLL +- PUSHBUTTON "...",IDC_BTN_BROWSEUSERINI,328,323,16,11 ++ BS_AUTOCHECKBOX | WS_TABSTOP,13,303,81,10 ++ EDITTEXT IDC_EDIT_PAKFILE,95,302,227,12,ES_AUTOHSCROLL ++ PUSHBUTTON "...",IDC_BTN_BROWSEPAK,328,303,16,11 ++ EDITTEXT IDC_EDIT_PREFABPATH,95,319,227,12,ES_AUTOHSCROLL ++ PUSHBUTTON "...",IDC_BTN_BROWSEPREFAB,328,319,16,11 ++ EDITTEXT IDC_EDIT_USERPATH,95,335,227,12,ES_AUTOHSCROLL ++ PUSHBUTTON "...",IDC_BTN_BROWSEUSERINI,328,337,16,11 + DEFPUSHBUTTON "OK",IDOK,341,7,38,14 + PUSHBUTTON "Cancel",IDCANCEL,341,24,38,14 + CONTROL "Entities are DLL based",IDC_CHECK_DLLENTITIES,"Button", + BS_AUTOCHECKBOX | BS_TOP | BS_MULTILINE | NOT WS_VISIBLE | +- WS_DISABLED | WS_TABSTOP,273,178,88,12 ++ WS_DISABLED | WS_TABSTOP,273,191,88,12 + CONTROL "Write face color info",IDC_CHECK_FACECOLOR,"Button", + BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | +- WS_TABSTOP,189,178,79,10 +- LTEXT "minutes",IDC_STATIC,216,271,25,8 ++ WS_TABSTOP,189,191,79,10 ++ LTEXT "minutes",IDC_STATIC,216,284,25,8 + GROUPBOX "Mouse",IDC_STATIC,179,7,103,28 +- GROUPBOX "Views / Rendering",IDC_STATIC,7,38,372,86 ++ GROUPBOX "Views / Rendering",IDC_STATIC,7,38,372,98 + GROUPBOX "Game path / Tool settings / Stuff that wouldn't fit anywhere else", +- IDC_STATIC,7,205,372,139 ++ IDC_STATIC,7,216,372,157 + CONTROL 147,IDB_VIEWDEFAULT,"Static",SS_BITMAP,13,48,21,19 + CONTROL 148,IDB_VIEWDEFAULT2,"Static",SS_BITMAP,40,48,21,19 + CONTROL 149,IDB_VIEWDEFAULT3,"Static",SS_BITMAP,67,48,21,19 +- GROUPBOX "New functionality:",IDC_STATIC,7,126,372,74 ++ GROUPBOX "New functionality:",IDC_STATIC,7,139,372,74 + CONTROL 150,IDB_VIEWDEFAULT_Z,"Static",SS_BITMAP,93,48,21,19 + LTEXT "slow",IDC_STATIC,131,69,15,8 + LTEXT "fast",IDC_STATIC,204,69,12,8 +- GROUPBOX "Camera ",IDC_STATIC,126,47,100,72 +- LTEXT "Prefab path:",IDC_STATIC,54,306,40,8 ++ GROUPBOX "Camera ",IDC_STATIC,126,47,100,84 ++ LTEXT "Prefab path:",IDC_STATIC,54,319,40,8 + GROUPBOX "Optimize interface for",IDC_STATIC,7,7,170,28 +- LTEXT "User INI path:",IDC_STATIC,49,324,45,8 +- LTEXT "Rotation inc:",IDC_STATIC,15,163,41,8 ++ LTEXT "User INI path:",IDC_STATIC,49,338,45,8 ++ LTEXT "Rotation inc:",IDC_STATIC,15,176,41,8 + CONTROL "Use Shaders",IDC_CHECK_USESHADERS,"Button", + BS_AUTOCHECKBOX | NOT WS_VISIBLE | WS_DISABLED | +- WS_TABSTOP,129,178,57,10 +- GROUPBOX "Texturing",IDC_STATIC,231,47,141,72 ++ WS_TABSTOP,129,191,57,10 ++ GROUPBOX "Texturing",IDC_STATIC,231,47,141,84 + LTEXT "Quality",IDC_STATIC,237,57,22,8 + LTEXT "Low",IDC_STATIC,239,81,14,8 + LTEXT "High",IDC_STATIC,347,82,16,8 + CONTROL "Vertex editing splits faces",IDC_CHECK_VERTEXMODE, +- "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,179,94,10 ++ "Button",BS_AUTOCHECKBOX | WS_TABSTOP,13,192,94,10 + PUSHBUTTON "Reset Registry",IDC_BUTTON_CLEAN,287,24,50,14 ++ CONTROL "Log console to Radiant.log",IDC_CHECK_LOG,"Button", ++ BS_AUTOCHECKBOX | WS_TABSTOP,13,356,97,11 ++ CONTROL "Ignore alpha channel",IDC_NOALPHA,"Button", ++ BS_AUTOCHECKBOX | WS_TABSTOP,236,117,127,10 + END + + IDD_DLG_MAPINFO DIALOG DISCARDABLE 0, 0, 181, 183 +diff -rup ../Q3Radiant201/TexWnd.cpp Q3Radiant/TexWnd.cpp +--- ../Q3Radiant201/TexWnd.cpp Mon Jun 26 12:31:00 2000 ++++ Q3Radiant/TexWnd.cpp Thu Aug 3 17:19:23 2000 +@@ -1439,31 +1550,46 @@ void Delay(float fSeconds) + void ViewShader(const char *pFile, const char *pName) + { + // we load the .shader file to find where it actually is +- CString str; ++ CString fullName = ValueForKey( g_qeglobals.d_project_entity, "basepath" ); ++ fullName += '/'; ++ fullName += pFile; + char* pBuff = NULL; +- int nSize = LoadFile(pFile, reinterpret_cast(&pBuff)); ++ int nSize = LoadFile(fullName.GetBuffer(0), reinterpret_cast(&pBuff)); + if (nSize == -1) + { +- nSize = PakLoadAnyFile(pFile, reinterpret_cast(&pBuff)); +- } +- +- if (nSize > 0) +- { +- str = pBuff; ++ Sys_Printf("Failed to load shader file %s ... check your project settings!\n", pFile ); ++ return; + } +- int nStart = 0; +- if (str.GetLength() > 0) ++ // look for the shader declaration ++ int nStart; ++ CString strFind = pName; ++ CString strLook = pBuff; ++ strLook.MakeLower(); ++ strFind.MakeLower(); ++ // offset used when jumping over commented out definitions ++ int nOffset = 0; ++ while (true) + { +- CString strFind = pName; +- CString strLook = str; +- strLook.MakeLower(); +- strFind.MakeLower(); +- int n = strLook.Find(strFind); +- if (n >= 0) +- { +- nStart = n; ++ nStart = strLook.Find(strFind, nOffset); ++ if (nStart == -1) ++ break; ++ // we have found something, maybe it's a commented out shader name? ++ char *strCheck = new char[strLook.GetLength()+1]; ++ strcpy( strCheck, strLook.GetBuffer(0) ); ++ strCheck[nStart] = 0; ++ char *pCheck = strrchr( strCheck, '\n' ); ++ // if there's a commentary sign in-between we'll continue ++ if (pCheck && strstr( pCheck, "//" )) ++ { ++ delete[] strCheck; ++ nOffset = nStart + 1; ++ continue; + } ++ delete[] strCheck; ++ break; + } ++ // now close the file ++ free(pBuff); + + CString s= "editpad "; + // build the full shader name +@@ -1472,7 +1598,9 @@ void ViewShader(const char *pFile, const + s += pFile; + WinExec(s, SW_SHOWNORMAL); + +- Delay(1.5); ++ // TTimo: we used to call Delay here, to continue processing messages. But it seems to induce a lot of instabilities. ++ // so now the user will simply have to wait. ++ Sleep( 1500 ); + + // now grab the edit window and scroll to the shader we want to edit + HWND hwndEdit = FindEditWindow(); +@@ -1485,8 +1613,6 @@ void ViewShader(const char *pFile, const + { + Sys_Printf("Unable to load shader editor.\n"); + } +- +- + } + + /* +@@ -2319,10 +2459,21 @@ void CTexWnd::OnVScroll(UINT nSBCode, UI + + void LoadShaders() + { ++ CStringList lst; ++ BuildShaderList( lst ); ++ if (lst.GetCount() == 0) ++ return; ++ POSITION pos = lst.GetHeadPosition(); ++ while (pos != NULL) ++ { ++ QERApp_LoadShaderFile( lst.GetAt(pos).GetBuffer(0) ); ++ lst.GetNext(pos); ++ } ++ ++ //++timo clean ++#if 0 + char dirstring[1024]; + char *path; +- //struct _finddata_t fileinfo; +- //int handle; + path = ValueForKey (g_qeglobals.d_project_entity, "basepath"); + sprintf (dirstring, "%s/scripts/shaderlist.txt", path); + char *pBuff = NULL; +@@ -2354,9 +2505,9 @@ void LoadShaders() + } + else + { +- Sys_Printf("Unable to load shaderlist.txt, shaders not loaded!"); ++ Sys_Printf("Unable to load %s, shaders not loaded!\n", dirstring); + } +- ++#endif + } + + // TTimo: modified to expect the reletive path to the skin as input +diff -rup ../Q3Radiant201/WIN_QE3.CPP Q3Radiant/WIN_QE3.CPP +--- ../Q3Radiant201/WIN_QE3.CPP Mon Jun 26 12:31:00 2000 ++++ Q3Radiant/WIN_QE3.CPP Thu Aug 3 17:19:24 2000 +@@ -3,6 +3,11 @@ + #include "mru.h" + #include "PrefsDlg.h" + ++// for the logging part ++#include ++#include ++#include ++ + //////////////////////////////////////////////////////////////////////////// + // BSP frontend plugin + // global flag for BSP frontend plugin is g_qeglobals.bBSPFrontendPlugin +@@ -42,10 +47,18 @@ void Sys_SetTitle (char *text) + } + + HCURSOR waitcursor; ++#define TIMING_STATS ++#ifdef TIMING_STATS ++double start,end; ++#endif + + void Sys_BeginWait (void) + { + waitcursor = SetCursor (LoadCursor (NULL, IDC_WAIT)); ++#ifdef TIMING_STATS ++ Sys_Printf("Sys_BeginWait\n"); ++ start = Sys_DoubleTime(); ++#endif + } + + void Sys_EndWait (void) +@@ -55,9 +68,12 @@ void Sys_EndWait (void) + SetCursor (waitcursor); + waitcursor = NULL; + } ++#ifdef TIMING_STATS ++ end = Sys_DoubleTime(); ++ Sys_Printf ("Sys_EndWait: %i ms\n", (int)(1000*(end-start))); ++#endif + } + +- + void Sys_GetCursorPos (int *x, int *y) + { + POINT lpPoint; +diff -rup ../Q3Radiant201/Win_main.cpp Q3Radiant/Win_main.cpp +--- ../Q3Radiant201/Win_main.cpp Mon Jun 26 12:31:01 2000 ++++ Q3Radiant/Win_main.cpp Thu Aug 3 17:19:24 2000 +@@ -341,54 +341,6 @@ void RunBsp (char *command) + Sleep (100); // give the new process a chance to open it's window + + BringWindowToTop( g_qeglobals.d_hwndMain ); // pop us back on top +-#if 0 +- // +- // write qe3bsp.bat +- // +- sprintf (batpath, "%sqe3bsp.bat", temppath); +- hFile = fopen(batpath, "w"); +- if (!hFile) +- Error ("Can't write to %s", batpath); +- fprintf (hFile, sys); +- fclose (hFile); +- +- // +- // write qe3bsp2.bat +- // +- sprintf (batpath, "%sqe3bsp2.bat", temppath); +- hFile = fopen(batpath, "w"); +- if (!hFile) +- Error ("Can't write to %s", batpath); +- fprintf (hFile, "%sqe3bsp.bat > %s", temppath, outputpath); +- fclose (hFile); +- +- Pointfile_Delete (); +- +- GetStartupInfo (&startupinfo); +- +- ret = CreateProcess( +- batpath, // pointer to name of executable module +- NULL, // pointer to command line string +- NULL, // pointer to process security attributes +- NULL, // pointer to thread security attributes +- FALSE, // handle inheritance flag +- 0 /*DETACHED_PROCESS*/, // creation flags +- NULL, // pointer to new environment block +- NULL, // pointer to current directory name +- &startupinfo, // pointer to STARTUPINFO +- &ProcessInformation // pointer to PROCESS_INFORMATION +- ); +- +- if (!ret) +- Error ("CreateProcess failed"); +- +- bsp_process = ProcessInformation.hProcess; +- +- Sleep (100); // give the new process a chance to open it's window +- +- //BringWindowToTop( g_qeglobals.d_hwndMain ); // pop us back on top +- //SetFocus (g_qeglobals.d_hwndCamera); +-#endif + } + } + diff --git a/docs/developer/d2u b/docs/developer/d2u new file mode 100644 index 00000000..16d4e197 --- /dev/null +++ b/docs/developer/d2u @@ -0,0 +1,17 @@ +#!/bin/sh + +for filename in $*; do + if [ -f $filename ]; then + echo -n $filename + tr -d '\r' < $filename > ___$filename_d2u___ + mv ___$filename_d2u___ $filename + echo " converted." + else + echo "$filename is not a file." + fi +done + +echo +echo done. + +# end of d2u ... diff --git a/docs/developer/data-driven-design.txt b/docs/developer/data-driven-design.txt new file mode 100644 index 00000000..698fa1b5 --- /dev/null +++ b/docs/developer/data-driven-design.txt @@ -0,0 +1,76 @@ +Listing of required modules and interfaces as an XML file +========================================================= + +Purpose: +-------- + +Make the editor more data driven. Be able to specify during +startup the full running configuration of the editor: +- what modules to load +- general execution paths (i.e. what's in the project settings) +- configuration for the loaded modules +- user preferences + +Feature Requirements: +--------------------- + +This is primarily intended for multiple games support. A restart +of the editor may be required when going from one game to the +other, but otherwise it should read the XML file and initialize +the right modules and APIs from there. + +Don't have a clear view of what multiple games support is gonna +be like. Can list a few things: + +- some interfaces are required for startup in a given game mode. +That's primarily what the XML config file is there for. +For instance in Q3 you will require Q3 map format module +and Q1 will require Q1 map format module + +- some modules are to be ignored? that's primary intended to +avoid loading unneeded modules. + +- some plugins are loaded for all games? +- some plugins are only relevant for some games? +(those two suggest various installation paths for modules +and directory-based scan?) + +- a plugin might require some other APIs to complete it's loading +process (i.e. sending it's own XML description of required +interfaces). + +Constaints: +----------- + +We have a nasty collision between preferences / project settings +and XML requirements. All three things need to be unified in some way. +The long term target being to have a central installation location +for the editor, and independant packages for each game. + +What kind of difference is there between project settings and prefs? +Prefs would be user settings that survive throughout all games, +whereas project settings are per-game / per-mod configuration. Turns +out it's all a matter of loading the right configuration chunks at the +right time. + +Proposed implementation: +------------------------ + +Use key/values (== property bags) based on XML format for everything. +Use them on project settings, and user prefs. The only difference +between what would be project settings and what would be user pref +is in which game configuration they are loaded, and how they are used. + +Project templates: We have a particular syntax to build settings from +a 'template' version. Instead of loading a project template, we should +be selecting a template from a list. + +Default startup: If we are configured to load last project on startup, +load it .. otherwise display a list of games and templates? + +Module library: +--------------- + +The dynamic loading / interfaces sharing / pure virtual classes needs +to be implemented in a generic module. It should be the basis of the +editor startup process. diff --git a/docs/developer/frp b/docs/developer/frp new file mode 100644 index 00000000..6267f4f9 --- /dev/null +++ b/docs/developer/frp @@ -0,0 +1,6 @@ +#!/bin/sh +for i in *.h; do + sed -e "s/BasePath/EnginePath/" $i > $i.tmp + mv -f $i.tmp $i + done + diff --git a/docs/developer/q3mapfeedback.txt b/docs/developer/q3mapfeedback.txt new file mode 100644 index 00000000..4831eb13 --- /dev/null +++ b/docs/developer/q3mapfeedback.txt @@ -0,0 +1,33 @@ +** currently supported debug messages: + +* map leaked / pointfile information ++ tested + +* duplicate plane ++ tested + +* degenerate plane, mirrored plane ++ testing may not be necessary, exact same code as duplicate plane + +* mixed CONTENTS_DETAIL and CONTENTS_STRUCTURAL +- not tested! + +* fog brush has multiple visible sides ++ tested + +* WindingFromDrawSurf failed: MAX_POINTS_ON_WINDING exceeded ++ tested, only outputs a single point, would need much improvement + (TstMaps/western.map) + +* MAX_BUILD_SIDES +uses xml_Select as other warnings, switched xml_Select to error or warn ++ tested + +** to-be-added list (and associated test map file if any) + +* Node without a volume +* leaf with too many portals +-> both in Desktop_p_leaf.map, contributed by y_lavanant@vistech.ie + +Mesh lightmap miscount +(no test map) \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image002.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image002.png new file mode 100644 index 00000000..faf0c04d Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image002.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image003.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image003.png new file mode 100644 index 00000000..e47ad7d6 Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image003.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image004.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image004.png new file mode 100644 index 00000000..71383952 Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image004.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image006.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image006.png new file mode 100644 index 00000000..f69042e3 Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image006.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image008.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image008.png new file mode 100644 index 00000000..b0b7fd32 Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image008.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image010.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image010.png new file mode 100644 index 00000000..2c2f6749 Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image010.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image012.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image012.png new file mode 100644 index 00000000..84015aee Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image012.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image014.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image014.png new file mode 100644 index 00000000..fd5292fa Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image014.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image016.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image016.png new file mode 100644 index 00000000..28110bfa Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image016.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image018.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image018.png new file mode 100644 index 00000000..8761cf55 Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image018.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image020.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image020.png new file mode 100644 index 00000000..d0e53bf1 Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image020.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image022.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image022.png new file mode 100644 index 00000000..4b70c81a Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image022.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image024.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image024.png new file mode 100644 index 00000000..d4a10aca Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image024.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image026.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image026.png new file mode 100644 index 00000000..8542c9e2 Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image026.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image028.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image028.png new file mode 100644 index 00000000..db8801f1 Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image028.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image030.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image030.png new file mode 100644 index 00000000..90681bb4 Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image030.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image032.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image032.png new file mode 100644 index 00000000..303e9663 Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image032.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image034.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image034.png new file mode 100644 index 00000000..816422e7 Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image034.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image035.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image035.png new file mode 100644 index 00000000..fa01de36 Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image035.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image038.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image038.png new file mode 100644 index 00000000..60f4bc1d Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image038.png differ diff --git a/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image040.png b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image040.png new file mode 100644 index 00000000..16d81ad2 Binary files /dev/null and b/docs/manual/Q3Rad_Manual/Q3Rad_Manual_files/image040.png differ diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_a.htm b/docs/manual/Q3Rad_Manual/appndx/appn_a.htm new file mode 100644 index 00000000..af9a048f --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_a.htm @@ -0,0 +1,56 @@ + + +Q3Radiant Editor Manual: Appendix A + + + +

Q3Radiant Editor Manual

+
+

Appendix A: Glossary of Terms

+ +Alpha Channel: This is a fourth 8-bit grayscale channel that is used by the shaders to further manipulate the art. It is often used to create transparency and translucency. +
Arena: A confined space in which Quake III Arena game play occurs. This is also called a "map" or a "level". +
B_Model: An entity, such as a lift, train, door, or rotating object, made of geometry brushes. These models can also contain curve patches and md3 models as components. +
Brush: A single piece of map geometry defined by four or more vertices that define a solid, convex volume. +
Bot: A computer-controlled player. To the server, a bot is treated as if it were a player. Some entities can make a distinction between interaction with, or use by "live" players and/or bots. +
Bsp: An abbreviation for Binary Space Partitioning. This is used as a name for the compiling process. +
BSPC: The utility, which creates a bot navigation .aas file for a map. Currently, it is run from outside the editor. +
Compile: A number crunching process that turns editor code into game code. This is also referred to as "bsp". +
CTF: (g_gametype 4) Abbreviation for the team game type "Capture the Flag." +
Delay:  A keyword for the amount of time, expressed in seconds (value), between the moment when activation occurs and the moment when the event it triggers occurs. +
DM: Abbreviation for "Death Match." +
Editor: Usually refers to the tool, in this case, Q3Radiant, used to make game maps. +
Entity: One of several classes of objects that are placed into game maps. Entities include miscellaneous models, ammo, weapons, point lights, doors, moving objects and so on. +
Event: Something that happens during game play. Activating a trigger is an event. +
FFA: (g_gametype 0) Abbreviation for "Free for All" a style of play in which every player is pitted against all other players. +
FPS: This is Frames per Second, sometimes call frame rate. This number shows approximately how many times the screen is being redrawn each second. This number depends on many factors, including the complexity of the map, the number of players in the map (bots are worse than humans), the processing power of the computer and the processing power of the video accelerator card in that computer. It is not the best measure for determining the playability of a map. +
FOV: Field of View how much of the game world can be see at one time, either in the game or the camera window of the editor. +
Game Unit: The basic unit of measure in a game map. Eight game units are approximately equal to one foot (30.48 cm) in the "real" world. This measure is also referred to as simply a "unit." +
Grid: In the Map Windows, this is a measuring tool, much like graph paper. +
Key: A key is a property possessed by an entity in the game. Light entities have a default value of 300. See the Entity description appendix for details Entering in the key "light" with a "value" of 150 reduces that by half. +
Map: Also called an arena or a game level. It is a self-contained game play area created by an editing tool like +Q3Radiant. It can refer to both the map file and the final playable product. +
Map Component: This is anything placed in the editor to create the map. It includes geometry brushes, curve patches, lights, entities, and models. +
Md3: Shorthand for a mesh model created and textured outside of Q3Radiant. The acronym refers to the custom file format used for the models in Quake III Arena. +
Patch: Any map component built from bezier curves. This includes bevels, caps, patches, and cylinders. +
Pathname: The sequence of file folders/directories from a starting point to a game asset or executable. +
Pixel: The smallest definable graphic component. This literally means, "Picture element". A game unit typically consists of a square cluster of 4 pixels (two pixels by two pixels). +
POV: Point of View. This is essentially, where the eye sits in relation to the game world. +
Project: A text file that contains the path designations for the various editor functions of Q3Radiant. +
PVS: Potential Viewable Set. Refers to those world triangles that might be seen from a position in the game world. +
R_Speeds: This is a set of numbers used to debug maps for visual complexity They show the number of triangles that are being drawn in a given point of view. Lower numbers are better. +
Region: A subset of the map. Selecting one or more map components and using a menu command to set them off temporarily from the rest of the map create regions. +
Script: A text file that contains instructions for the game. Examples: arena.txt, base_floor.shader, debug.cfg. +
Shader: A short script of program commands that define the way the graphic engine processes a texture. +
Team DM: (g_gametype 3) A team of players takes on another team to get the most frags. +
Texture: A graphic file designed to suggest a physical surface or a component for a graphic special effect. +
T-Junction Cracks: A visual artifact resulting from patch vertices that are not properly matched to world geometry. This is characterized by 'sparkles' running along the edge of the patch. +
Tournament: (g_gametype 1) This is a mode of game play characterized by a one on one match with other players watching as spectators while waiting their turns. The winner of the match plays the next opponent. +
Trigger: A map component that activates events in the game world under the right conditions. +
Unit: (See "Game Unit") +
Value: A setting for a key possessed by an entity. Depending on the key, values can be numbers, pathnames, word +strings, or word commands. See individual Entity descriptions for details. +
Z-fighting: A visual artifact caused when two z-buffered surfaces share the same plane, resulting in the engine trying to draw both simultaneously. +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_b_1.htm b/docs/manual/Q3Rad_Manual/appndx/appn_b_1.htm new file mode 100644 index 00000000..c9fb166b --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_b_1.htm @@ -0,0 +1,228 @@ + + +Q3Radiant Editor Manual: Appendix B1 + + + +

Q3Radiant Editor Manual

+
+

Appendix B: Entity Descriptions

+This Section owes much of the background and testing research to three dedicated Quake Engine editing supporters, Suicide20, inolen, and EuteTic. It is based on version 1.1 (12/22/99) of a document that they created and gave us permission to include with the official id editor documents. + +

"Keys" are keywords that represent the in-game properties of an +entity. Some are flags that determine whether an entity will +appear in a particular game play mode. Others define extents or +rates for entity movement. Others establish how much of some game +effect will occur (example: damage) or how long to wait until an +event occurs or can reoccur. + + + +

With the exception of properties that can be set by checkboxes, +the map maker will need to type in keys (names for game function +properties) and their values (numbers or strings) into fields +within the entities window. + + + +

Keys that are set by checkboxes in the editor are called +"Spawnflags" and will be shown in All Caps. The rest are shown in +lowercase, as they should be typed into the editor field. + + + +

Basic Key information

+Angle: This is the direction of facing or direction of +movement for an entity. Set this value with the Angle buttons on +the entity window. The angle value can be typed in as any positive +value between 1 and 360. + + + +

Color: This key only affects md3 models that are built +into func_entities. The color is the color of light used to +illuminate the model. It is expressed as a normalized three +digit RGB formula. + + + +

Entity Dimensions: The minimum and maximum coordinate +dimensions of the entity box. + + + +

Light: This key only affects md3 models that are built +into func_entities. + + + +

Map Entity Color: This is the color of the generic entity +box used to represent the entity in the map editor. + + + +

Ammo_* Entities

+The properties for ammo entities are all very similar. + +

Map Entity Color: Blue +
Entity Dimensions: (-16 -16 -16) (16 16 16) + +

These are ammunition boxes for weapons in the game. They can be +represented by either a blue entity box, or the ammo box model +itself. With the exception of the type and amount of ammo given to +the player upon pick up, all ammo entities have the same +properties. + +

ammo_bfg
+Game Function: BFG ammo. Gives the player 15 shots by +default. + + + +

Custom Keys + +
count: sets the amount of ammo given to the player when +picked up (default 15). + +

ammo_bullets
+ +Game Function: Machine Gun ammo. Gives the player 50 +shots by default. + +

Custom Keys + +
count: sets the amount of ammo given to the player when +picked up (default 50). + +

ammo_cells
+ +Game Functions: Plasma Gun ammo. Gives the player 30 +shots by default. + + + +

Custom Keys + +
count: sets the amount of ammo given to the player when +picked up (default 30). + +

ammo_grenades
+ +Game Function: Grenade Launcher ammo. Gives the player 5 +shots by default. + + + +

Custom Keys + +
count: sets the amount of ammo given to the player when +picked up (default 5). + +

ammo_lightning
+ +Game Function: Lightning Gun ammo. Gives the player 60 +shots by default. + +

Custom Keys + +
count: sets the amount of ammo given to the player when +picked up (default 60). + +

ammo_rockets
+Game Function: Rocket Launcher ammo. Gives the player 5 +shots by default. + + + +

Custom Keys +
count: sets the amount of ammo given to the player when +picked up (default 5). + +

ammo_shells
+ +Game Function: Shotgun ammo. Gives the player 10 shots by +default. + + + +

Custom Keys +
count: sets the amount of ammo given to the player when +picked up (default 10). + +

ammo_slugs
+Game Function: Railgun ammo. Gives the player 10 shots by +default. + + + +

Custom Keys +
count: sets the amount of ammo given to the player when +picked up (default 10). + + + +

Common Keys +
wait: time in seconds before the item respawns after +being picked up (default 40, -1 = never respawn). + +
random: random time variance in seconds added or +subtracted from "wait" delay (default 0 - see Notes). + +
team: set this to team items. Teamed items will respawn +randomly after team master is picked up (see Notes). + +
target: picking up the item will trigger the entity this +points to. + +
targetname: a target_give entity can point to this for +respawn freebies. + +
notbot: when set to 1, a bot will never seek out this +item + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags +
SUSPENDED: item will spawn where it was placed in map and won't +drop to the floor. Set by Checkbox. Bots will only be attracted to +suspended entities if they are reachable by way of a jump pad or +launch pad (trigger_push). + + + +

Notes + +
The amount of time it takes for an item in the team to respawn +is determined by the "wait" value of the item that was picked up +previously. So if one of the items in the team has it's "wait" key +set to -1 (never respawn), the random respawning cycle of the +teamed items will stop after that item is picked up. + + + +

When the random key is set, its value is used to calculate a +minimum and a maximum delay. The final time delay will be a random +value anywhere between the minimum and maximum values: (min delay = +wait - random) (max delay = wait + random). + + + +

Design Notes + +
An ammo item can be given a negative "count" value. Taking away +ammo in combat would be a bad idea but in combination with a +target_give entity, it can be used to set up games mods like Rocket +Arena by removing the machinegun ammunition from a player when he +spawns into the map.
+

Back | Home | Next + + diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_b_2.htm b/docs/manual/Q3Rad_Manual/appndx/appn_b_2.htm new file mode 100644 index 00000000..dd9a5104 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_b_2.htm @@ -0,0 +1,651 @@ + + +Q3Radiant Editor Manual: Appendix B2 + + + +

Q3Radiant Editor Manual

+
+

Appendix B: Entity Descriptions

+

Func_* Entities

+Func_Entities include a wider variety of game purposes than +other entity classes. They are sometimes represented by simple +function boxes. But many are built out of brushes, patches and +models. These constructions are sometimes called "b_models", though +for many of them the word "mover" works as well, since they are +made to be moving objects in the game world. + +

func_bobbing
+ +Map Entity Color: N/A + +
Dimensions: size of map components used + +
Game Function: Solid entity that oscillates back and +forth in a linear motion. By default, it will have an amount of +displacement in either direction equal to the dimension of the +brush in the axis in which it's bobbing. Entity bobs on the Z axis +(up-down) by default. It can also emit sound if the "noise" key is +set. Will crush the player when blocked. + + + +

Keys + +
speed: amount of time in seconds for one complete +oscillation cycle (default 4). + +
height: sets the amount of travel of the oscillation +movement (default 32). + +
phase: sets the start offset of the oscillation cycle. +Values must be 0 < phase < 1. Any integer phase value is the +same as no offset (default 0). + +
noise: path/name of .wav file to play. Use looping sounds +only (eg. sound/world/drone6.wav - See Notes). + +
model2: path/name of model to include (eg: +models/mapobjects/jets/jets01.md3). + +
origin: alternate method of setting XYZ origin of sound +and .md3 model included with entity (See Notes). + +
light: constantLight radius of .md3 model included with +entity. Has no effect on the entity's brushes (default 0). + +
color: constantLight color of .md3 model included with +entity. Has no effect on the entity's brushes (default 1 1 1). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags +
X_AXIS : entity will bob along the X axis. +
Y_AXIS : entity will bob along the Y axis. + + + +

Notes +
In order for the sound to be emitted from the location of the +entity, it is recommended to include a brush with an origin shader +at its center, otherwise the sound will not follow the entity as it +moves. Setting the origin key is simply an alternate method to +using an origin brush. When using the model2 key, the origin point +of the model will correspond to the origin point defined by either +the origin brush or the origin coordinate value. The movement of +the func_bobbing follows a sinoid wave pattern. + + + +

func_button
+Map Entity Color: N/A + +
Dimensions: size of map components used + +
Game Function: When a button is touched by a player, it +moves in the direction set by the "angle" key, triggers all its +targets, stays pressed by an amount of time set by the "wait" key, +then returns to its original position where it can be operated +again. + + + +

Keys +
angle: determines the direction in which the button will +move (up = -1, down = -2). + +
target: all entities with a matching targetname will be +triggered. + +
speed: speed of button's displacement (default 40). Speed +is in game units per second. + +
wait: number of seconds button stays pressed (default 1, +-1 = return immediately). + +
lip: lip remaining at end of move (default 4 units). + +
health: if set to a non-zero value, the button must be +damaged by "health" amount of points to operate. + +
light: constantLight radius of .md3 model included with +entity. Has no effect on the entity's brushes (default 0). + +
color: constantLight color of .md3 model included with +entity. Has no effect on the entity's brushes (default 1 1 1). + +
model2: path/name of model to include (eg: +models/mapobjects/pipe/pipe02.md3). + +
origin: alternate method of setting XYZ origin of .md3 +model included with entity (See Notes). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes +
Setting the origin key is simply an alternate method to using an +origin brush. When using the model2 key, the origin point of the +model will correspond to the origin point defined by either the +origin brush or the origin coordinate value. + + + +

func_door
+ +Map Entity Color: N/A + +
Dimensions: size of map components used + +
Game Function: Normal sliding door entity. By default, +the door will activate when player walks close to it or when damage +is inflicted on it. Doors move a distance equal to their dimension +along the selected angle of  travel, minus the "lip" key +value. + + + +

Keys + +
angle: determines the opening direction of door  (up += -1, down = -2). + +
speed: determines how fast the door moves (default 100). +Speed is in game units per second. + +
wait: number of seconds before door returns (default 2, +-1 = return immediately - see Notes). + +
lip: lip remaining at end of move (default 8). + +
targetname: if set, a func_button or trigger is required +to activate the door. + +
health: if set to a non-zero value, the door must be +damaged by "health" amount of points to activate (default 0). + +
dmg: damage to inflict on player when he blocks operation +of door (default 4). Door will reverse direction when blocked +unless CRUSHER spawnflag is set. + +
team: assign the same team name to multiple doors that +should operate together (see Notes). + +
light: constantLight radius of .md3 model included with entity. +Has no effect on the entity's brushes (default 0). + +
color: constantLight color of .md3 model included with +entity. Has no effect on the entity's brushes. (default 1 1 1). + +
model2: path/name of model to include (eg: +models/mapobjects/pipe/pipe02.md3). + +
origin: alternate method of setting XYZ origin of .md3 +model included with entity (See Notes). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
START_OPEN: the door will spawn in the open state and +operate in reverse. + +
CRUSHER: door will not reverse direction when blocked and +will keep damaging player until he dies or gets out of the way. + + + +

Notes + +
Unlike in Quake 2, doors that touch are NOT automatically +teamed. If you want doors to operate together, you have to team +them manually by assigning the same team name to all of them. +Setting wait =-1 for normal touch doors makes them work +erratically. Use this only for damage-only ("health" key set to +non-zero value) or targeted doors. Setting the origin key is simply +an alternate method to using an origin brush. When using the model2 +key, the origin point of the model will correspond to the origin +point defined by either the origin brush or the origin coordinate +value. + + + +

func_group
+ +Map Entity Color:  Light blue + +
Dimensions: Determined by dimensions of map +components. + +
Game Function: This is not an entity. It is strictly an +editor utility to group world brushes and patches together for +convenience (selecting, moving, copying, etc). You cannot group +entities with this. + + + +

Notes + +
The TAB key can be used to flip through the component pieces of +a selected func_group entity, isolating individual components. + + + +

func_pendulum
+ +Map Entity Color: Light blue + +
Dimensions: Determined by dimensions of map +components. + +
Game Function: Solid entity that describes a pendulum +back and forth rotation movement. Rotates on the X axis by default. +Pendulum frequency is a physical constant based on the length of +the beam and gravity. Contact with the pendulum instantly kills a +player. + + + +

Keys + +
angle: angle offset of axis of rotation from default X +axis (default 0/360). + +
speed: angle of swing arc in either direction from +initial vertical position (default 30). + +
phase: sets the start offset of the swinging cycle. +Values must be 0 < phase < 1. Any integer phase value is the +same as no offset (default 0). + +
noise: path/name of .wav file to play. Use looping sounds +only (eg. sound/world/drone6.wav). + +
model2: path/name of model to include (eg: +models/mapobjects/jets/jets01.md3). + +
origin: alternate method of setting XYZ origin of +entity's rotation axis and .md3 model included with entity (default +"0 0 0" - See Notes). + +
light: constantLight radius of .md3 model included with +entity. Has no effect on the entity's brushes (default 0). + +
color: constantLight color of .md3 model included with +entity. Has no effect on the entity's brushes (default 1 1 1). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +
You need to have an origin brush as part of this entity. The +center of that brush will be the point through which the rotation +axis passes. Setting the origin key is simply an alternate method +to using an origin brush. Pendulum will rotate along the X axis by +default. Pendulum cannot rotate along Z axis. The speed of swing +(frequency) is not adjustable, and the "dmg" key (although set in +the Q3A maps) has no effect whatsoever. When using the model2 key, +the origin point of the model will correspond to the origin point +defined by either the origin brush or the origin coordinate +value. + +

func_plat
+ +Map Entity Color: Light blue + +
Dimensions: Determined by dimensions of map +components. + +
Game Function: This is a rising platform that a player +can ride to reach higher places. Plats must always be drawn in the +raised position, so they will operate and be lighted correctly but +they spawn in the lowered position. The plat will stay in the +raised position until the player steps off. There are no proper +sounds for this entity, only beep noises, so sound call paths must +be adjusted (see Notes). + + + +

Keys + +
speed: determines how fast the plat moves (default 150) +in game units per second. + +
lip: lip remaining at end of move (default 16). Has no +effect if "height" is set. + +
height: if set, this will determine the total amount of +vertical travel of the plat (see Design Notes). + +
dmg: damage to inflict on a player when he blocks +operation of plat (default 4). Plat will reverse direction when +blocked. + +
targetname: if set, the trigger that points to this will +raise the plat each time it fires. The plat raises and comes back +down a second later if no player is on it. + +
light: constantLight radius of .md3 model included with +entity. Has no effect on the entity's brushes (default 0). + +
color: constantLight color of .md3 model included with +entity. Has no effect on the entity's brushes (default 1 1 1). + +
model2: path/name of model to include (eg: +models/mapobjects/pipe/pipe02.md3). + +
origin: alternate method of setting XYZ origin of .md3 +model included with entity (See Notes). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +
By default, the total amount of vertical travel of a platform is +implicitly determined by the overall vertical size of the brushes +of which it's made minus the lip value. But if the "height" key is +used, then the total amount of vertical travel of the plat will be +exactly that value regardless of the shape and size of the plat and +regardless of the value of the "lip" key. Using the "height" key is +the best method for any kind of platforms and the only possible one +for thin plats which need to travel vertical distances many times +their own thickness. Setting the origin key is simply an alternate +method to using an origin brush. When using the model2 key, the +origin point of the model will correspond to the origin point +defined by either the origin brush or the origin coordinate +value. + + + +

Design Notes: + +
     Clip brushes can be used to create the +additional size for "thin" plats. Func_plats were pulled from all +maps in the final build of Quake 3 Arena due to some problems in +their operation, particularly as it related to bot function.  +The id designers recommend using plats with care and that plats be +built as "solid" pillar-like lifts (more like those in Doom). + +
     There is a way to make plats play +proper sounds. Just create a sound\movers\plats folder under baseq3 +and put 2 sounds named pt1_start.wav and pt1_end.wav in it. Those +can be the renamed sounds from the Q2 plats or renamed copies of +the sound\movers\doors sounds you can extract from your pak0.pk3 +file or new custom sounds if you're up to it. Thanks to Fragzilla +for the tip.
+ + + +

func_rotating
+ +Map Entity Color: Light blue + +
Dimensions: Determined by dimensions of map +components. + +
Game Function: Solid entity that rotates continuously. +Rotates on the Z axis by default and requires an origin brush. It +will always start on in the game and is not targetable. + + + +

Keys + +
speed: determines how fast entity rotates (default +100). + +
noise: path/name of .wav file to play. Use looping sounds +only (eg. sound/world/drone6.wav). + +
model2: path/name of model to include (eg: +models/mapobjects/bitch/fembotbig.md3). + +
origin: alternate method of setting XYZ origin of +entity's rotation axis and .md3 model included with entity (default +"0 0 0" - See Notes). + +
light: constantLight radius of .md3 model included with +entity. Has no effect on the entity's brushes (default 0). + +
color: constantLight color of .md3 model included with +entity. Has no effect on the entity's brushes (default 1 1 1). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
X_AXIS: entity will rotate along the X axis. + +
Y_AXIS: entity will rotate along the Y axis. + + + +

Notes + +
You need to have an origin brush as part of this entity. The +center of that brush will be the point through which the rotation +axis passes. Setting the origin key is simply an alternate method +to using an origin brush. It will rotate along the Z axis by +default. You can check either the X_AXIS or Y_AXIS box to change +that + + + +

func_static
+ +Map Entity Color: N/A + +
Dimensions: Determined by components + +
Game Function: Static solid bspmodel. Can be used for +conditional walls and models for different game types. + + + +

Keys + +
model2: path/name of model to include (eg: +models/mapobjects/bitch/fembotbig.md3). + +
light: constantLight radius of .md3 model included with +entity. Has no effect on the entity's brushes (default 0). + +
color: constantLight color of .md3 model included with +entity. Has no effect on the entity's brushes (default 1 1 1). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +
When using the model2 key, the origin point of the model will +correspond to the origin point defined by either the origin brush +or the origin coordinate value. Because the map has only a single +bot navigation file, Func_Statics cannot be used to make +significant changes in game play flow between differing game +types. + + + +

func_timer
+ +Map Entity Color: Dark blue (0.3 0.1 0.6) + +
Dimensions: (-8 -8 -8) (8 8 +8) + +
Game Function: Time delay trigger that will continuously +fire its targets after a preset time delay. The time delay can also +be randomized. When triggered, the timer will toggle on/off. + + + +

Keys + +
wait: delay in seconds between each triggering of its +targets (default 1). + +
random: random time variance in seconds added or +subtracted from "wait" delay (default 0 - see Notes). + +
target: this points to the entities to trigger. + +
targetname: a func_button or trigger that points to this +will toggle the timer on/off when activated. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
START_ON: timer will start on in the game and +continuously fire its targets. + + + +

Notes + +
When the random key is set, its value is used to calculate a +minimum and a maximum delay. The final time delay will be a random +value anywhere between the minimum and maximum values: (min delay = +wait - random) (max delay = wait + random). + + + +

func_train
+ +Map Entity Color: (0 .5 .8) + +
Dimensions: Determined by +components + +
Game Function: Trains are moving solids that follow a +string of path_corner entities. Trains in Q3A are very basic, they +also require an origin brush (see Notes). + + + +

Keys + +
speed: speed of displacement of train (default 100 or +overridden by speed value of path). + +
target: this points to the first path_corner of the path +which is also the spawn location of the train's origin. + +
model2: path/name of model to include (eg: +models/mapobjects/pipe/pipe02.md3). + +
origin: alternate method of setting XYZ origin of the +train's brush(es) and .md3 model included with entity (See +Notes). + +
light: constantLight radius of .md3 model included with +entity. Has no effect on the entity's brushes (default 0). + +
color: constantLight color of .md3 model included with +entity. Has no effect on the entity's brushes (default 1 1 1). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +
1. Trains always start on in the game. + +
2. Trains do not damage the player when blocked. + +
3. Trains cannot emit sound. + +
4. Trains are not triggerable or toggle-able. + +
5. Trains cannot be block-stopped just by getting in their way, +the player must be wedged between the train and another obstacle to +block it. + + + +

Setting the origin key is simply an alternate method to using an +origin brush. When using the model2 key, the origin point of the +model will correspond to the origin point defined by either the +origin brush or the origin coordinate value. +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_b_3.htm b/docs/manual/Q3Rad_Manual/appndx/appn_b_3.htm new file mode 100644 index 00000000..b9ff8fff --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_b_3.htm @@ -0,0 +1,150 @@ + + +Q3Radiant Editor Manual: Appendix B3 + + + +

Q3Radiant Editor Manual

+
+

Appendix B: Entity Descriptions

+

Holdable_* Entities

+ +

holdable_medkit
+ +Map Entity Color: blue (.7 0 1) + +
Dimensions:  (-16 -16 -16) (16 16 16) + +
Game Function:  This is a Medkit that can be picked +up and used (once) later. Brings the player's health back to 100 +when used. Player can only carry one holdable item at a time. + + + +

Keys + +
wait: time in seconds before item respawns after being +picked up (default 60, -1 = never respawn). + +
random: random time variance in seconds added or +subtracted from "wait" delay (default 0 - see Notes). + +
team: set this to team items. Teamed items will respawn +randomly after team master is picked up (see Notes). + +
target: picking up the item will trigger the entity this +points to. + +
targetname: a target_give entity can point to this for +respawn freebies. + +
notbot: when set to 1, a bot will never seek out this +item + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
SUSPENDED: item will spawn where it was placed in map and +won't drop to the floor.  Bots will only be attracted to +suspended entities if they are reachable by way of a jump pad or +launch pad (trigger_push). + + + +

Notes + +
The amount of time it takes for an item in the team to respawn +is determined by the "wait" value of the item that was picked up +previously. So if one of the items in the team has it's "wait" key +set to -1 (never respawn), the random respawning cycle of the +teamed items will stop after that item is picked up. + + + +

When the random key is set, its value is used to calculate a +minimum and a maximum delay. The final time delay will be a random +value anywhere between the minimum and maximum values: (min delay = +wait - random) (max delay = wait + random).*/ + + + +

holdable_teleporter
+ +Map Entity Color: blue (.7 0 1) + +
  Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Teleporter item that can be picked up and +used (once) later. Teleports the player to a random player spawn +point when used. Player can only carry one holdable item at a +time. + + + +

Keys + +
wait: time in seconds before item respawns after being +picked up (default 60, -1 = never respawn). + +
random: random time variance in seconds added or +subtracted from "wait" delay (default 0 - see Notes). + +
team: set this to team items. Teamed items will respawn +randomly after team master is picked up (see Notes). + +
target: picking up the item will trigger the entity this +points to. + +
targetname: a target_give entity can point to this for +respawn freebies. + +
notbot: when set to 1, a bot will never seek out this +item + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
SUSPENDED: item will spawn where it was placed in map and won't +drop to the floor. Bots will only be attracted to suspended +entities if they are reachable by way of a jump pad or launch pad +(trigger_push). + + + +

Notes + +
The amount of time it takes for an item in the team to respawn +is determined by the "wait" value of the item that was picked up +previously. So if one of the items in the team has its "wait" key +set to -1 (never respawn), the random respawning cycle of the +teamed items will stop after that item is picked up. + + + +

When the random key is set, its value is used to calculate a +minimum and a maximum delay. The final time delay will be a random +value anywhere between the minimum and maximum values: (min delay = +wait - random) (max delay = wait + random). +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_b_4.htm b/docs/manual/Q3Rad_Manual/appndx/appn_b_4.htm new file mode 100644 index 00000000..7d60e126 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_b_4.htm @@ -0,0 +1,209 @@ + + +Q3Radiant Editor Manual: Appendix B4 + + + +

Q3Radiant Editor Manual

+
+

Appendix B: Entity Descriptions

+

Info_* Entities

+ +

info_camp
+ +Map Entity Color: Dark green (0 0.5 0) + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: This atttracts bots which have a camping +preference in their A.I. characteristics. It should be placed at +least 32 units away from any brush surface. + + + +

Keys +
range: number of units that the bot can move away from +camp entity while camping on it. + +
weight: number that is compared against the weight +assigned to all the other camp spots in the map to determine if a +bot chooses to camp there. The value is normalized against all +other weight values. + + + +

Notes + +
Examples of Q3A bots which have a high camping preference are: +Razor, Tank Jr., Grunt, Patriot and Doom. Examples of Q3A bots +which have a low camping preference are: Klesk, Mynx, Sarge, Keel +and Xaero. Info_Camp entities should be reachable by "normal" +means, including relatively non-complex rocket jumps. + +

info_notnull
+ +Map Entity Color: Dark green (0 0.5 0) + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Used as a positional target for entities +that can use directional pointing. A target_position can be used +instead of this but was kept in Q3A for legacy purposes. + + + +

Keys + +
targetname: must match the target key of entity that uses +this for pointing. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

info_null
+ +Map Entity Color: Dark green (0 0.5 0) + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Used as a positional target for light +entities to create a spotlight effect. A target_position can be +used instead of this but was kept in Q3A for legacy purposes. + + + +

Keys + +
targetname: must match the target key of entity that uses +this for pointing. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode).*/ + + + +

info_player_deathmatch
+ +Map Entity Color: Pink (1 0 0) + +
Dimensions: (-16 -16 -24) (16 16 32) + +
Game Function: Normal player spawning location for Q3A +levels. + + + +

Keys + +
angle: direction in which player will look when spawning +in the game. Does not apply to bots. + +
target: this can point at a target_give entity for +respawn freebies. + +
nobots: when set to 1, bots will never use this spawn +point to respawn in the game. + +
nohumans: when set to 1, human players will never use +this spawn point to respawn in the game. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
INITIAL: makes the spawnpoint the initial place for the player +to spawn at the beginning of the game. This is also where the +player spawns as a spectator. + + + +

Design Tip: If you include an +info_player_deathmatch entity in a CTF map, players from both teams +can respawn at that location. Great for placing respawn spots in +contested central battleground areas.
+ +

info_player_intermission
+ +Map Entity Color: Pink (1 0 1) + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Camera for intermission screen between +matches. This also automatically generates the podium for bot arena +matches (see Notes). Can be aimed by setting the "angles" key or +targeting an pointing to an aiming entity. Use only one per +level. + + + +

Keys + +
angles: alternate "pitch, yaw, roll" angles method of +aiming intermission camera (default 0 0 0). + +
target: point this to an info_notnull or target_position +entity to set the camera's pointing angles. + + + +

Notes + +
In Single Player bot arena matches, the podium for the 1st, 2nd +and 3rd place players at the end of the match is generated by this +entity. The podium's origin will automatically be located 128 units +in the direction of the camera's view and 84 units down from the y +height of the view line at that point. It will also always be +generated on a level plane regardless of the pointing angle of the +camera so if that angle is too steep, part of the podium model +might not be visible. If the origin point of the podium model is +inside brush geometry, the podium will not draw. Make sure you +leave at least 106 units of free space in front of where the camera +points to otherwise the podium model won't be visible at all. + + + +

info_player_start
+ +Map Entity Color: Red (1 0 0) + +
Dimensions: (-16 -16 -24) (16 16 32) + +
Game Function: Player spawn location. It works in Quake +III Arena, but is not used in the id maps. Use +info_player_deathmatch instead. + + + +

Keys + +
angle: direction in which player will look when spawning +in the game. + +
target: this can point at a target_give entity for +respawn freebies. +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_b_5.htm b/docs/manual/Q3Rad_Manual/appndx/appn_b_5.htm new file mode 100644 index 00000000..29bd4fb6 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_b_5.htm @@ -0,0 +1,487 @@ + + +Q3Radiant Editor Manual: Appendix B5 + + + +

Q3Radiant Editor Manual

+
+

Appendix B: Entity Descriptions

+

Item_* Entities

+ +Most of the properties for item entities are the same and are +listed immediately below. Properties that are unique to specific +entities follow those entries. + + + +

Shared Keys (for all item entities) + +
All the entities in this grouping can have the following +keys. + +

team: set this to team items. Teamed items will respawn +randomly after team master is picked up (see Notes). + +
target: picking up the item will trigger the entity this +points to. + +
targetname: a target_give entity can point to this for +respawn freebies. + +
notbot: when set to 1, a bot will never seek out this +item. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Two other keys, wait and count, do not apply to all entities and +are described as they apply to individual entity types. + + + +

Check Boxes/Spawnflags + +
SUSPENDED: item will spawn where it was placed in map and won't +drop to the floor. Bots will only be attracted to suspended +entities if they are reachable by way of a jump pad or launch pad +(trigger_push). + + + +

Notes + +
Team: Just as you would set doors to work together with +the "team" key, you can do the same for item, weapon and ammo +entities. Give each entity in the team the same key value (example: +"team" "powerups"). The game randomly selects which team member +respawns next. You can set your own wait times. You can skew the +weighting towards a particular item by including multiple copies of +it. Example: 1 quad and 2 hastes in a team mean a greater chance +that a haste entity will appear next. + +

The amount of time it takes for an item in the team to respawn +is determined by the "wait" value of the item that was picked up +previously. So if one of the items in the team has it's "wait" key +set to -1 (never respawn), the random respawning cycle of the +teamed items will stop after that item is picked up. + + + +

When the random key is set, its value is used to calculate a +minimum and a maximum delay. The final time delay will be a random +value anywhere between the minimum and maximum values: (min delay = +wait - random) (max delay = wait + random). + + + +

item_armor_body
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Red Armor - 100 points of protection. All +armor can be cumulated up to a maximum of 200 points and slowly +decays back to 100 points. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 25, -1 = never respawn). + + + +

item_armor_combat
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Yellow Armor - 50 points of protectiong. +All armor can be cumulated up to a maximum of 200 points and slowly +decays back to 100 points. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 25, -1 = never respawn). + +

item_armor_shard
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Green Armor Shard - 5 points of +protection. All armor can be cumulated up to a maximum of 200 +points and slowly decays back to 100 points. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 25, -1 = never respawn). + + + +

Item_botroam
+ +Map Entity Color: orange + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: An invisible entity that attracts a bot to +it. Used to move bots to parts of a map that might otherwise not be +used. + + + +

Custom Keys + +
Weight: non-zero floating point value, most often in the +range 0 to 400. Very low values are unlikely to attract a bot to +that area, since most bots have "desires" that attract them to +other game entities. (Higher values are allowed but keep in mind +that the bot should also be attracted to normal items. Don't +make the weight value too high. + + + +

Notes + +
The item_botroam entity can be used when a bot does not roam the +whole level or prefers to go to only specific areas. But don't +confuse these items with "way points". They are more like magnets. +This (invisible) item can be placed in a map just like regular +items. Nobody can actually pick up the item it's only used to +attract bots to certain places of the map. The value is the weight +of the roam_item is relative to the weight assigned other items in +the map (each bot has its own weights). The bot character specific +item weights are stored with the bot characters in the +botfiles/bots/ sub-folder in the .pk3 file. + +

When a bot should never go for a specific item the key "notbot" +with value "1" can be used for that item. This key with value can +be used for every available item in Quake III Arena. + +

Design Tip: Wait to place these items until you've done a +significant amount of live play testing on the final map against +bots. Observe a bot-only match. See which parts of the map they +DON'T use frequently. Use bot_roam entities to encourage the +bots to follow more paths through the map. Example: In one of id's +CTF maps, it was eventually observed that bots were most likely to +use only one entrance when assaulting the base. Placement of +item_botroam entities along the other entrance paths might have +solved this.
+ + + +

item_enviro
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Battle Suit power-up. Lasts 30 seconds. +Battle suit provides full protection against explosion radius +damage, slime, and lava damage. It gives partial protection against +falling, and direct rocket hits. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 120, -1 = never respawn). + +
count: time in seconds that power-up will last when +picked up (default 30). + + + +

item_flight
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Flight power-up. Lasts 60 seconds. Will +not appear in single player games. Bots do not understand its +use. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 120, -1 = never respawn). + +
count: time in seconds power-up will last when picked up +(default 60). + + + +

item_haste
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Speed power-up. Makes player run at double +speed for 30 seconds. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 120, -1 = never respawn). + +
count: time in seconds power-up will last when picked up +(default 30). + + + +

item_health
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Yellow cross bubble - 25 Health. Cannot be +picked up over 100 health. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 35, -1 = never respawn). + +
count: sets the amount of health points given to the +player when item is picked up (default 25). + + + +

item_health_large
+Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Gold cross bubble - 50 Health. Cannot be +picked up over 100 health. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 35, -1 = never respawn). + +
count: sets the amount of health points given to the +player when item is picked up (default 50). + + + +

item_health_mega
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Blue M bubble - 100 Health. Adds 100 +health points to current health up to a maximum of 200. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 40, -1 = never respawn). + +
count: sets the amount of health points given to the +player when item is picked up (default 100). + + + +

item_health_small
+ +
Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Green cross bubble - 5 Health. Can be +picked up to give over 100 health but slowly decays back to +100. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 35, -1 = never respawn). + +
count: sets the amount of health points given to the +player when item is picked up (default 5). + +

item_invis
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Invisibility power-up. Lasts 30 +seconds. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 120, -1 = never respawn). + +
count: time in seconds power-up will last when picked up +(default 30). + +
team : set this to team items. Teamed items will respawn +randomly after team master is picked up (see Notes). + + + +

item_quad
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Quad Damage power-up (3 times damage). +Lasts 30 seconds. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 120, -1 = never respawn). + +
count: time in seconds power-up will last when picked up +(default 30). + + + +

item_regen
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Health Regeneration power-up. This will +boost your current health by 5 points every second up to a maximum +of 200. The boost continues for a period of 30 seconds. Aftewards, +any health points over 100 slowly decay back to 100. + + + +

Custom Keys + +
wait: time in seconds before item respawns after being +picked up (default 120, -1 = never respawn). + +
count: time in seconds power-up will last when picked up +(default 30). + +

Light Entity

+ +

light
+ +Map Entity Color: bright green  (see Notes) + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Non-displayed light entity. The default +condition emits white light in all directions at a value of 300. +The apparent brightness of the light is modeled on "real world" +physics, so the falloff in brightness willl be an inverse square of +distance from the source. It can be colored. It can be targeted on +an info_null entity to make a spotlight. + + + +

Keys + +
light: value of light intensity (default 300). + +
_color: weighted RGB value of light color (default white +- 1 1 1). + +
target: point this to an target_position, info_null or +info_notnull to create a spotlight effect. + +
radius: sets radius of light cone for spotlights (default +64) in game units. Radius measurement is made at the targeted +entity. Light must target an info_null entity (info_nulls are only +used by the compiler and need not be "remembered" by the game +engine during play). + + + +

Check Boxes/Spawnflags + +
LINEAR: light falloff will be linear instead of inverse square +of distance from source. + + + +

Notes + +

  • Linear fall off will not make much difference on low value +lights. Useful on high value lights where the light travels long +distances. + +
  • If the "Light drawing" preference is selected (under +Preferences), the editor shows the light entities as diamond shaped +pieces the color of the light they cast. If not, they are light +yellow green cubes.
+ + +

Coloring Lights + +
To quickly change the color of a light entity, use on of the +following methods. + +

  1. CTRL + k:  With the entity +window open, select a light entity in either the map or camera +window. Press CTRL + k. This brings up the windows color selector. +Select a color and choose "OK".  The editor automatically +normalizes the light colors. + +
  2. Sample Texture: Select the light +entity. Select a texture in either the texture window or the camera +window.  Hit SHIFT + middle mouse button. + +
  3. Manual Entry: Type in the value +for the key _color as a 3 numbers between 0 and 1 (inclusive). + +
  4. Copy Existing: Select another +light entity whose color value the user would like to duplicate. In +the editor window, lef click on the key "_color". Now select the +light entity to be colored. Hit ENTER.
+ + +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_b_6.htm b/docs/manual/Q3Rad_Manual/appndx/appn_b_6.htm new file mode 100644 index 00000000..e1dfcb06 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_b_6.htm @@ -0,0 +1,332 @@ + + +Q3Radiant Editor Manual: Appendix B6 + + + +

Q3Radiant Editor Manual

+
+

Appendix B: Entity Descriptions

+

Misc_* Entities

+
misc_model
+ +Map Entity Color: red + +
Dimensions: (-16 -16 -16) (16 16 16) + +
Game Function: Generic, one-size-fits-all placeholder for +inserting .md3 models in game. Requires compilation of map geometry +to be added to level. + +

Keys + +
angle: direction in which model will be oriented. + +
model : path/name of model to use (eg: +models/mapobjects/teleporter/teleporter.md3).*/ + + + +

Notes + +
This is a premade mesh model, created in a program like +Kinetix's 3d Studio Max. It is a static (non-animating) +model.  Shaders can give it the appearance of motion, but no +animation.  The models should be stored in a directory with +the pathname: models/mapobjects. The process by which models are +made is not a part of this document. Currently, models only have +rotation on the Z axis. + +

Models do not "clip" against players or weapon +hits. They are entirely non-solid. If clipping is important, The +user will need to build clip brushes that are roughly the size and +shape of the models. + +

Do not use the flip or rotate tools on models. Only use the +entity facing buttons or manually change the angle value. The +purple "3d crosshair" is the origin point of the model. + +

Make it: Right mouse press on a map window to bring up +the floating entity selector.  Select misc_model. A selection +dialogue box will open giving access to available .md3 files.  +Select the one you want and it will load into the map.  Now, +hit "n" to open the entity window. Click on the "model" key in the +key list box. Now edit the value field to remove part of the +line. + +

Example: "c://program files/quake III +arena/baseq3/models/mapobjects/storch.md3" + +

… should be edited to read: + +

"models/mapobjects/storch.md3" + + + +

misc_portal_camera
+ +Map Entity Color: light orange + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Portal camera. This camera is used to +project its view onto a portal surface in the level through the +intermediary of a misc_portal_surface entity. Use the "angles" key +or target a target_position or info_notnull entity to set the +camera's pointing direction. + + + +

Keys + +
angles: this sets the pitch and yaw aiming angles of the +portal camera (default 0 0). Use "roll" key to set roll angle. + +
target: point this to a target_position entity to set the +camera's pointing direction. + +
targetname: a misc_portal_surface portal surface +indicator must point to this. + +
roll: roll angle of camera. A value of 0 is upside down +and 180 is the same as the player's view. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
SLOWROTATE : makes the portal camera rotate slowly along the +axis of camera to target or (selected direction). + +
FASTROTATE : makes the portal camera rotate faster along the +axis of camera to target or (selected direction).. + + + +

Notes +

  • Both the setting "angles" key or "targeting a target_position" +methods can be used to aim the camera. However, the target_position +method is simpler. In both cases, the "roll" key must be used to +set the roll angle. Generally, this is adjusted after compiling the +map at least once. + +
  • If either the SLOWROTATE or FASTROTATE spawnflag is set, then +the "roll" value is irrelevant.
+ + + +

misc_portal_surface
+ +Map Entity Color: light orange + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Portal surface indicator. This will "lock +on" the brush face closest to it and identify as a portal. The view +displayed on the portal surface is the view of the +misc_portal_camera that this entity targets. Also used for mirrors +(see Notes). + + + +

Keys + +
target: point this to a misc_portal_camera that "sees" +the view you want to display on the portal. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +

  • The entity must be no farther than 64 units away from the portal +surface to lock onto it. + +
  • To make a mirror, apply the common/mirror shader to the surface, +place this entity near it but don't target a +misc_portal_camera. + +
  • When used as a mirror, the mirror surface will display what the +entity can "see."
+ + + +

misc_teleporter_dest
+ +Map Entity Color: red + +
Dimensions: (-32 -32 -24) (32 32 -16) + +
Game Function: Teleport destination location point for +trigger_teleporter entities. A "target_position" can also be used +for this. + + + +

Keys + +
angle: direction in which player will look when +teleported. + +
targetname: make the trigger_teleporter point to +this. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +
In most cases, this is replaced by the "target_position" +entity. + +

Path_* Entities

+ +

path_corner
+ +Map Entity Color: brown + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Path corner entity that define the routes +that func_trains can be made to follow. + + + +

Keys + +
target: point to next path_corner in the path. + +
targetname: the train following the path or the previous +path_corner in the path points to this. + +
speed: speed of func_train (in game units per second) +while moving to the next path corner. This will override the speed +value of the train. + +
wait: number of seconds func_train will pause on path +corner before moving to next path corner (default 0 - see +Notes). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +

  • Setting the wait key to -1 will not make the train stop on the +path corner, it will simply default to 0. + +
  • The center of the origin brush in the func_train follows the +path.
+ + + +

Shooter_* Entities

+ +
shooter_grenade
+ +Map Entity Color: red-violet + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: This will shoot a grenade each time it's +triggered. Aiming is done by setting the "angles" key or by +targeting an info_notnull or target_position entity. + + + +

shooter_plasma
+ +Map Entity Color: red-violet + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: This will shoot a plasma ball each time +it's triggered. Aiming is done by setting the "angles" key or by +targeting an info_notnull or target_position entity. + + + +

shooter_rocket
+ +Map Entity Color: red-violet + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: This will shoot a rocket each time it's +triggered. Aiming is done by setting the "angles" key or by +targeting an info_notnull or target_position entity. + + + +

Keys + +
angles: this sets the pitch and yaw aiming angles of +shooter (default 0 0). The roll angle does not apply. + +
targetname: activating trigger points to this. + +
target: this points to a target_position entity for +aiming the grenades. + +
random: random aiming variance in degrees from the +straight line to the targeted entity (default 0 - see Notes). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in "Teamplay" and +"CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single Player +mode (bot play mode). + + + +

Notes + +

  • When the random key is set, its value is used to calculate a +maximum angle deviation from the normal trajectory formed by a +straight line between the shooter and the aiming entity it targets. +The final trajectory will be a random value anywhere between no +deviation at all (0) to maximum deviation (value of the random +key). + +
  • Both the setting "angles" key or "targeting a target_position" +methods can be used to aim the shooter. However, the +target_position method is simpler.*/
+

Back | Home | Next + + diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_b_7.htm b/docs/manual/Q3Rad_Manual/appndx/appn_b_7.htm new file mode 100644 index 00000000..55d28b31 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_b_7.htm @@ -0,0 +1,637 @@ + + +Q3Radiant Editor Manual: Appendix B7 + + + +

Q3Radiant Editor Manual

+
+

Appendix B: Entity Descriptions

+

Target_* Entities

+ + + +
target_delay
+ +Map Entity Color: aqua + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: The target_delay trigger is an +intermediary time delay trigger. Like a target_relay (see below), +this can only be fired by other triggers which will, in turn, cause +it to fire its own targets + + + +

Keys + +
targetname: activating trigger points to this. + +
target: this points to entities to activate when this +entity is triggered. + +
wait: delay in seconds from when this gets triggered to +when it fires its own targets (default approx. 1). + +
random: random time variance in seconds added or +subtracted from "wait" delay (default 0 - see Notes). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +
When the random key is set, its value is used to calculate a +minimum and a maximum delay. The final time delay will be a random +value anywhere between the minimum and maximum values: (min delay = +wait - random) (max delay = wait + random). + + + +

target_give
+ +Map Entity Color: red + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: This is used to give ammo, weapons, health +or items to the player who activates it. + + + +

Keys + +
target: this points to the item(s) to give when +activated. + +
targetname: activating trigger or spawn entity points to +this. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +

  • There are 2 ways to use this entity. + +
    1. To automatically give items to players when they spawn +in the game: make a spawn location entity like +info_player_deathmatch or CTF respawn points target this entity, +then make it target the item(s) to give to the player upon +respawn. + +
    2. To give items to players during the game: make a +trigger_multiple target this entity, then make it target the +item(s) to give to the player when the trigger is touched. This is +how the column of health and armor in Q3DM10 works.
    + +
  • Items targeted to be given are not seen in the map.
+ + + +

target_kill
+ +Map Entity Color: gray + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: This will kill the player who activates +the trigger that fires this target. + + + +

Keys + +
targetname: the activating trigger points to this. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode).*/ + + + +

target_laser
+ +
Map Entity Color: red + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Generates a red laser beam. I think this +can somehow spawn in the game, I saw it once but it's too +inconsistent to be usable. Commented out. + + + +

Keys + +
angles: alternate "pitch, yaw, roll" angles method of +aiming laser (default 0 0 0). + +
target: point this to a target_position entity to set the +laser's aiming direction. + +
targetname: the activating trigger points to this. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
START_ON: when set, the laser will start on in the game. + + + +

Notes + +
Since none of the game maps in Quake III Arena used this +function, it is not likely to be a functioning entity. + + + +

target_location
+ +Map Entity Color: Dark Green + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Location marker used by bots and players +for team orders and team chat in the course of Teamplay games. The +closest target_location in sight is used for the location. If none +is in sight, the closest in distance is used. + + + +

Keys + +
Message: name of the location (text string). +Displayed in parentheses in front of all team chat and order +messages. Shorter is better. + +
count: color of the location text displayed in +parentheses during team chat. Set to 0-7 for color. + +

    0 : white (default) + +
    1 : red + +
    2 : green + +
    3 : yellow + +
    4 : blue + +
    5 : cyan + +
    6 : magenta + +
    7 : white
+ +notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Design Tips: The target locations are "line-of-sight." If +a player can "see" it, and that target is the closest to the +player, then that location message is displayed. Be +conservative in placing location markers. Because of the way the +location code is implemented, it causes a large amount of data to +be transmitted regularly. It has been explained that the game +serrver has to constantly keep track of, and update to the clients, +a data table equal to all the location markers multiplied by all +the players. Not only that, but it must calculate line of sight +from players to location markers and calculate the distance from +the location marker. + +
   Place the target locations in such a way that the entity can be +"seen" from most, if not all, the positions that a player can stand +in when it is inside that area. Fewer are better, even if it +means that occasionally, a team mate is in an unknown location.
+ +

target_position
+ +Map Entity Color: Dark Green + +
Dimensions: (-4 -4 -4) (4 4 4) + +
Game Function: This is an aiming target for entities like +light, misc_portal_camera, and trigger_push (jump pads and launch +pads) in particular. + + + +

Keys + +
Targetname: the entity that requires an aiming direction +points to this. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +
Use this as the target for any entity that must be actively +targeted during the game (do not use it as a target for +spotlights). + +
See Tips, Tricks and Tutorials for the method used to make jump +pads. + + + +

target_print
+ +
Map Entity Color: dark green + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: This will print a message on the center of +the screen when triggered. By default, all the clients will see the +message. + + + +

Keys + +
message: text string to print on screen. + +
targetname: the activating trigger points to this. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
REDTEAM : only the red team players will see the message. + +
BLUETEAM : only the blue team players will see the message. + +
PRIVATE : only the player that activates the target will see the +message. + + + +

target_push
+ +Map Entity Color: gray + +
Dimensions: (-8 -8 -8) (8 8 8) + + + + + +
Game Function: This is not recommended for creating jump +pads and launch ramps. The direction of push can be set by the +"angles" key or pointing to a target_position or info_notnull +entity. Unlike trigger_push, this is NOT client side predicted and +must be activated by a trigger. + + + +

Keys + +
angles: this sets the pitch and yaw aiming angles of push +entity (default 0 0). The roll angle does not apply. + +
speed: speed of push (default 1000 game units per +second). Has no effect if entity targets an aiming entity. + +
targetname: the activating trigger points to this. Push +originates from the location of the trigger. + +
target: this points to the aiming entity to which the +player will jump. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
BOUNCEPAD : if set, trigger will play bounce noise instead of +beep noise when activated (see notes). + + + +

Notes + +

  • The player will first move from the trigger to the target_push +and then on towards the target_position. + +
  • To make a jump pad or launch ramp, create a trigger_multiple +where the jump must originate. Place the target_push directly above +the trigger_multiple and place the target_position entity at the +highest point of the jump. Target the trigger_multiple to the +target_push and target the target_push to the +target_position/info_notnull (or set the target_push's "angles" +key). + +
  • Note that the "angle" key also +works. + +
  • A target_push can be used to make a wind tunnel push effect (as +opposed to the jump pad effect of a trigger_push). It pushes the +activator in the direction of the angle value or towards its apex, +a targeted target_position entity. + +
  • The default speed is 1000. + +
  • If bouncepad is checked, it will play the bouncepad sound +instead of windfly.
+ + +

Design Tip: + +
There is a way to make the target push play proper sounds. Just +create a sound\movers\plats folder under baseq3 and put a sounds +windfly.wav in it. It can be the sound from the Q2 or your own +custom looping if you're up to it.
+ +

target_relay
+ +Map Entity Color: aqua + +
Map Entity Color: (-8 -8 -8) (8 8 8) + +
Game Function: This can only be activated by other +triggers, which will, in turn, cause it to activate its own +targets. + + + +

Keys + +
targetname: activating trigger points to this. + +
target: this points to entities to activate when this +entity is triggered. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
RED_ONLY : only red team players can activate trigger. + +
BLUE_ONLY : only red team players can activate trigger. + +
RANDOM: one of the targeted entities will be triggered at +random. + + + +

Notes + +
Use this when you need to split off targeting functions along +separate paths. + + + +

target_remove_powerups
+ +
Map Entity Color: blue + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: This takes away all item_* type powerups +from player except health and armor (holdable_* items are not taken +away either). This must be activated by a button or +trigger_multiple entity. The player that activates the trigger will +lose any powerup(s) currently in his possession. + + + +

Keys + +
targetname: activating trigger points to this. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode).*/ + + + +

target_score
+ +Map Entity Color: bright green + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: This is used to automatically give frag +points to the player who activates this. A spawn location entity +like info_player_* or CTF respawn points can target this entity to +give points to the player when he spawns in the game. Or a trigger +can also be used to activate this. The activator of the trigger +will get the points. + + + +

Keys + +
targetname: activating entity points to this. + +
count: number of frag points to give to player (default +1). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode).*/ + + + +

target_speaker
+ +
Map Entity Color: bright green + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Sound generating entity that plays .wav +files. Normal non-looping sounds play each time the target_speaker +is triggered. Looping sounds can be set to play by themselves (no +activating trigger) or be toggled on/off by a trigger. + + + +

Keys + +
noise: path/name of .wav file to play (eg. +sound/world/growl1.wav - see Notes). + +
wait: delay in seconds between each time the sound is +played ("random" key must be set - see Notes). + +
Random: random time variance in seconds added or +subtracted from "wait" delay ("wait" key must be set - see +Notes). + +
targetname: the activating button or trigger points to +this. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
LOOPED_ON: sound will loop and initially start on in level (will +toggle on/off when triggered). + +
LOOPED_OFF: sound will loop and initially start off in level +(will toggle on/off when triggered). + +
GLOBAL: sound will play full volume throughout the level. + +
ACTIVATOR: sound will play only for the player that activated +the target. + + + +

Notes + +

  • The path portion value of the "noise" key can be replaced by the +implicit folder character "*" for triggered sounds that belong to a +particular player model. For example, if you want to create a +"bottomless pit" in which the player screams and dies when he falls +into, you would place a trigger_multiple over the floor of the pit +and target a target_speaker with it. Then, you would set the +"noise" key to "*falling1.wav". The * character means the current +player model's sound folder. So if your current player model is +Visor, * = sound/player/visor, if your current player model is +Sarge, * = sound/player/sarge, etc. This cool feature provides an +excellent way to create "player-specific" triggered sounds in your +levels. + +
  • The combination of the "wait" and "random" keys can be used to +play non-looping sounds without requiring an activating trigger but +both keys must be used together. The value of the "random" key is +used to calculate a minimum and a maximum delay. The final time +delay will be a random value anywhere between the minimum and +maximum values: (min delay = wait - random) (max delay = wait + +random).
+ + + +

target_teleporter
+ +Map Entity Color: red + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Activating this will teleport players to +the location of the targeted misc_teleporter_dest entity +(target_position can also be used). Unlike trigger_teleport, this +entity must be activated by a trigger and does NOT allow client +prediction of events. + + + +

Keys + +
targetname: activating trigger points to this. + +
target: this must point to a misc_teleporter_dest +entity. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +
When you give multiple targets the same target name, the +teleporter will randomly select from one each time it is used. +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_b_8.htm b/docs/manual/Q3Rad_Manual/appndx/appn_b_8.htm new file mode 100644 index 00000000..ec4d957a --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_b_8.htm @@ -0,0 +1,352 @@ + + +Q3Radiant Editor Manual: Appendix B8 + + + +

Q3Radiant Editor Manual

+
+

Appendix B: Entity Descriptions

+

Team_* Entities

+ +These entities only function when a team style game is being +played. Most are for Capture the Flag. They do not need to be +marked with notfree, since that is part of their nature. + + + +

team_CTF_blueflag
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -24) (16 16 32) + +
Game Function: Blue team flag for CTF games. + + + +

Notes + +
This cannot be suspended (or the bots won't find it). It must be +reachable by players of both teams, since it is where a player must +return an opponent's flag. + + + +

team_CTF_blueplayer
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -24) (16 16 32) + +
Game Function: Initial Blue team spawning position for +CTF games. This is where players spawn when they join the Blue team +(at the start of a game or upon entering a game in progress). + + + +

Keys + +
target: this can point at a target_give entity for +respawn freebies. + + + +

team_CTF_bluespawn
+ +Map Entity Color: blue + +
Dimensions: (-16 -16 -24) (16 16 32) + +
Game Function: Blue team respawning position for CTF +games. This is where Blue team players respawn after they get +fragged. + + + +

Keys + +
target: this can point at a target_give entity for +respawn freebies. + + + +

team_CTF_redflag
+ +Map Entity Color: red + +
Dimensions: (-16 -16 -24) (16 16 32) + +
Game Function: Blue team flag for CTF games. + + + +

Notes + +
This cannot be suspended (or the bots won't find it). It must be +reachable by players of both teams, since it is where a player must +return an opponent's flag. + + + +

team_CTF_redplayer
+ +Map Entity Color: red + +
Dimensions: (-16 -16 -24) (16 16 32) + +
Game Function: Initial Red team spawning position for CTF +games. This is where players spawn when they join the red team (at +the start of a game or upon entering a game in progress). + + + +

Keys + +
target: this can point at a target_give entity for +respawn freebies. + + + +

team_CTF_redspawn
+ +Map Entity Color: red + +
Dimensions: (-16 -16 -24) (16 16 32) + +
Game Function: Red team respawning position for CTF +games. This is where red team players respawn after they get +fragged. + + + +

Keys + +
target: this can point at a target_give entity for +respawn freebies. + + + +

Trigger_* Entities

+ +
trigger_always
+ +Map Entity Color: gray + +
Dimensions: (-8 -8 -8) (8 8 8) + +
Game Function: Automatic trigger. It will fire the +entities it targets as soon as it spawns in the game. + + + +

Keys + +
target: this points to the entity to activate. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +
For reliable internet play, make any trigger which can be passed +through at least 32 game units deep. + + + +

trigger_hurt
+ +Map Entity Color: gray + +
Dimensions: size of brush used + +
Game Function: Any player that touches this will be hurt +by "dmg" points of damage once per server frame (very fast). A +sizzling sound is also played while the player is being hurt. + + + +

Keys + +
dmg: number of points of damage inflicted to player per +server frame (default 5 - integer values only). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + +

Check Boxes/Spawnflags + +
START_OFF: if set, the trigger will initially start off in the +game. + +
SILENT: supresses the sizzling sound while player is being +hurt. + +
NO_PROTECTION: player will be hurt regardless of protection (see +Notes). + +
SLOW: changes the damage rate to once per second. + + + +

Notes + +

  • The invulnerability power-up (item_enviro) does not protect the +player from damage caused by this entity regardless of whether the +NO_PROTECTION spawnflag is set or not. + +
  • A trigger_hurt always starts on in the game. + +
  • For reliable Internet play, make any trigger which can be passed +through at least 32 game units deep. +
+ + +

trigger_multiple
+ +Map Entity Color: gray + +
Dimensions: size of brush used + +
Game Function: Variable size repeatable trigger. It will +fire the entities it targets when touched by player. Can be made to +operate like a trigger_once entity by setting the "wait" key to -1. +It can also be activated by another trigger that targets it. + + + +

Keys + +
target: this points to the entity to activate. + +
targetname: activating trigger points to this. + +
wait: time in seconds until trigger becomes +re-triggerable after it's been touched (default 0.2, -1 = trigger +once). + +
random: random time variance in seconds added or subtracted from +"wait" delay (default 0 - see Notes). + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +

  • When the random key is set, its value is used to calculate a +minimum and a maximum delay. The final time delay will be a random +value anywhere between the minimum and maximum values: (min delay = +wait - random) (max delay = wait + random). + +
  • For reliable Internet play, make any trigger which can be passed +through at least 32 game units deep. +
+ + +

trigger_push
+ +Map Entity Color: gray + +
Dimensions: size of brush used + +
Game Function: This is used to create jump pads and +launch ramps. It MUST point to a target_position or info_notnull +entity to work. Unlike target_push, this is client side +predicted. + + + +

Keys + +
target: this points to the target_position to which the +player will jump. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +

  • To make a jump pad or launch ramp, place the +target_position/info_notnull entity at the highest point of the +jump and target it with this entity. + +
  • This trigger automatically makes the bouncepad sound. + +
  • Speed of travel is determined by the distance needed to reach +the target entity. Longer = faster. + +
  • For reliable Internet play, make any trigger which can be passed +through at least 32 game units deep. +
+ + +

trigger_teleport
+ +Map Entity Color: gray + +
Dimensions: size of brush used + +
Game Function: Touching this will teleport players to the +location of the targeted misc_teleporter_dest or target_position +entities. This entity allows client prediction of events. It is the +preferred method. + + + +

Keys + +
target: this must point to a misc_teleporter_dest entity +or a target_position entity. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Notes + +

  • For reliable Internet play, make any trigger which can be passed +through at least 32 game units deep. + +
  • When you give multiple targets the same target name, the +teleporter will randomly select from one each time it is used. +
+

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_b_9.htm b/docs/manual/Q3Rad_Manual/appndx/appn_b_9.htm new file mode 100644 index 00000000..5a723bfd --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_b_9.htm @@ -0,0 +1,224 @@ + + +Q3Radiant Editor Manual: Appendix B9 + + + +

Q3Radiant Editor Manual

+
+

Appendix B: Entity Descriptions

+

Weapon Entities

+ +

weapon_bfg
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Big Freaking Gun. Default ammo load +is 20. + + + +

weapon_gauntlet
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Melee weapon. No ammo. There is no +reason to place this entity in a map. + + + +

weapon_ grapplinghook
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Grappling Hook. Spawns in the game and +works but is unskinned. Does not use ammo. + + + +

weapon_grenadelauncher
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Lobs bouncing grenades. Comes with 10 +grenades. + + + +

weapon_lightning
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Also called the "shaft" by some. Comes +with 100 "shocks" + + + +

weapon_machinegun
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Player automatically starts with this. +Comes with a default load of 100 "shots." + +

Design Tip: For a "Rocket Arena" type game, the designer +may wish to use the target_give entity to "give" the player an +ammo_bullets entity with a count of -100 to remove the +machinegun from play.
+ + + +

weapon_plasmagun
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Comes with 50 shots. + + + +

weapon_railgun
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Comes with 10 slugs. + + + +

weapon_rocketlauncher
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Comes with 10 rockets. + + + +

weapon_shotgun
+ +Map Entity Color: blue + +
Dimensions: 32x32 + +
Game Function: Also called the "shaft" by some. Comes +with 10 rockets. + + + +

Keys + +
wait: time in seconds before item respawns after being +picked up (default 5, -1 = never respawn). + +
random: random time variance in seconds added or +subtracted from "wait" delay (default 0 - see Notes). + +
count: sets the amount of ammo given to the player when +weapon is picked up. + +
team: set this to team items. Teamed items will respawn +randomly after team master is picked up (see Notes). + +
target: picking up the item will trigger the entity this +points to. + +
targetname: a target_give entity can point to this for +respawn freebies. + +
notfree: when set to 1, entity will not spawn in "Free +for all" and "Tournament" modes. + +
notteam: when set to 1, entity will not spawn in +"Teamplay" and "CTF" modes. + +
notsingle: when set to 1, entity will not spawn in Single +Player mode (bot play mode). + + + +

Check Boxes/Spawnflags + +
SUSPENDED : item will spawn where it was placed in map and won't +drop to the floor. Bots will only be attracted to suspended +entities if they are reachable by way of a jump pad or launch pad +(trigger_push). + + + +

Notes + +
The amount of time it takes for an item in the team to respawn +is determined by the "wait" value of the item that was picked up +previously. So if one of the items in the team has it's "wait" key +set to -1 (never respawn), the random respawning cycle of the +teamed items will stop after that item is picked up. + + + +

When the random key is set, its value is used to calculate a +minimum and a maximum delay. The final time delay will be a random +value anywhere between the minimum and maximum values: (min delay = +wait - random) (max delay = wait + random). + + + + + +

Worldspawn Entity

+ +
Worldspawn
+ +Only used for the world. You access the worldspawn entity by +selecting any non-entity brush in your map. + + + +

Keys + +
message: text to print at user logon. Used for name of +level. + +
music: path/name of looping .wav file used for level's +music (eg. music/sonic5.wav). This is for a piece of music +with only one part. To make a song play with both an intro and a +looping portion, the following is the correct form for the music +value: + + + +

    music/intro.wav music/loop.wav
+ + + +

ambient: Adds a constant value to overall lighting. Use +not recommended. Ambient light will have a tendency to flatten out +variations in light and shade. + +
_color: This is the normalized formula for RGB +values for ambient light. A value is considered normalized +when it fits in a range between 0 and 1. If you are using a +tool like the Windows color picker, divide the value for each +component of the RGB values by 255. The result will be a +normalized value. + +
gravity: gravity of level (default is normal gravity: +800). +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_c.htm b/docs/manual/Q3Rad_Manual/appndx/appn_c.htm new file mode 100644 index 00000000..eb881f59 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_c.htm @@ -0,0 +1,654 @@ + + +Q3Radiant Editor Manual: Appendix C + + + +

Q3Radiant Editor Manual

+
+

Appendix C: Bot Navigation Files

+ +(Original Document Title: BSP Converter) +
+ + + + + + + + + + + + +
Version:= 1.8
Date:= 2000-01-11
Author:= Mr. Elusive
+ +

Introduction

+ +This appendix is based on documentation that has been released +and updated by Mr. Elusive. It deals with the Navigation file that +must be created in order for the Quake III Arena bots to be +able to navigate and play in game maps. It is not a manual for the +creation of bots. + +

Description

+ +The BSPC tool is used to create AAS files from BSP files. An AAS +file is a file with areas used by the Quake III Arena bot in order +to navigate and understand a map. + +

Installation

+ +Place the BSPC program in your Quake III Arena folder. + +

Usage

+ +Unless you are using a front-end utility, which gives you +check-button access to compiler functions, you will need to run +this program from the command line of your DOS Command Prompt +program. If the command line is not already pointing the Quake +III Arena directory, change directories (cd\quake III +arena). + +

The command line should be formatted as follows: + +

    bspc [-<switch> [-<switch> ...]]
+ +

Example 1: bspc -bsp2aas d:\quake3\baseq3\maps\mymap?.bsp + +
Example 2: bspc -bsp2aas +d:\quake3\baseq3\pak0.pk3\maps/q3dm*.bsp + +

In the first example a "?" is used as a metacharacter variable +to indicate any single keyboard character. This allows you to +compile the latest version of a map ("mymap1" or "mymapb"). + +

In the second example a "*" is used as a metacharacter variable +to indicate any string of keyboard characters. This allows you to +compile the latest version of a map ("mymap1" or "mymapb"). + +

The bot navigation compile process can be further modified by +the use of "switches" that change some of the parmeters used in +compilation. Some of these can be used to compile only +certain features, such as reachability. Others allow the compiler +to use more than a single processor, as is the case with +"threads." + +

Switches: +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
bsp2aas <[pakfilter/]filter.bsp>= convert BSP to AAS
reach <filter.bsp>= compute reachability & clusters
cluster <filter.aas>= compute clusters
aasopt <filter.aas> = optimize aas file
output <output path> = set output path
threads <X> = set number of threads to X
cfg <filename> = use this cfg file
optimize = enable optimization
noverbose = disable verbose output
breathfirst = breath first bsp building
nobrushmerge = don't merge brushes
freetree = free the bsp tree
nocsg = disables brush chopping
forcesidesvisible = force all sides to be visible
grapplereach = calculate grapple reachabilities
+ +

Several metacharacters may be used in the filter and +pakfilter. + +

+ + + + + + + + + + + + +
*Match any string of zero or more characters
?Match any single character
[abc...]Match any of the enclosed characters; a hyphen can be used to specify a range (e.g. a-z, A-Z, 0-9)
+ +

.pk3 files are accessed as if they are normal folders (whether +they are compressed or not). + +

For instance, use "d:\quake3\baseq3\pak0.pk3\maps/q3dm1.bsp" to +access the map q3dm1.bsp from the pak0.pk3 file. + +

Multiple files may be listed after the switches bsp2map, +bsp2aas, reach, cluster and aasopt. + +

If a BSP file is being converted to an AAS file and no output +path is entered on the command line then the AAS file will +automatically be stored in the same folder as the BSP file. However +if the BSP file was stored in a .pk3 file then the AAS file will be +stored in a folder with the name 'maps' outside the .pk3 file. + +

Updating the Entity Lump

+ +If an AAS file is already available for a BSP file and you ONLY +change the entities inside this BSP file then you only have to +recalculate the reachabilities. This way you can move items, +platforms etc. around without the need to recalculate the whole AAS +file -- which can save quite some compile time. You can recalculate +the reachabilities as follows: + +
    bspc -reach mymap.bsp
+ +

Where mymap.bsp is the BSP file. The mymap.aas file has to be in +the same folder as mymap.bsp or should be in the output folder +specified with the -output option. + +

Keep in mind that as soon as ANY geometry in the map changes +(including b_models and trigger brushes) the whole AAS file HAS to +be recalculated in order to play with bots. + +

Leaks

+ +Just like there can be vis "leaks" in a map there can also be +clipping leaks. Two things can be wrong when the BSPC tool outputs +that a map leaks. + +
  1. + +There are no entities in the map at all, or all entities that are +actually in the map are placed in solid locations (see Test Solid +below). In this case the BSPC tool outputs: "WARNING: no entities +inside." The map must contain at least one player start entity to +load in the game. + +
  2. + +There is a spot in the map where players can go outside the map +into the void. This is bad, players should never be able to fall +out of a level. In this case the BSPC tool outputs: "WARNING: +entity reached from outside." The BSPC tool also writes a mymap.lin +file that can be loaded in the Q3Radiant editor to show lines that +go through the actual leak.
+ +

Make sure the .lin file is stored in the same folder as where +q3radiant stores the .bsp file. Load the map in q3radiant and use +the menu > File > Pointfile... to load the .lin file. +A thick red line will be shown in the map. Follow this line to find +the leak. + +

Useful Map Information

+ +The following information is given as a reference for bot +capabilities. The area file information is used by bots. It tells +them when and where they can make jumps. Human players don't have +this information readily available to them, so you may want to be +more forgiving when designing tricky jumps. + +

Map Boundaries
+ +Currently all the contained area of a Quake III Arena map +should fall within the bounds (8192, 8192, 8192) - (-8192, -8192, +-8192) for the bspc tool to compile. These are the same bounds as +the Q3Map compilers. + +

Game Physics
+ +Player Dimensions + +
Model size: The player model's actual size is a bounding +box 30 units by 30 units square with a height of 56 units. In the +game world, eight units roughly equal one foot (30.5 cm). From +this, we deduce that the characters are a heroic 7 feet tall (2.13 +meters). + +

Step Heights + +
For scale purposes, "normal" steps should be no higher than 8 +units. However, the maximum value that a player may step up is 18 +units (just keep steps 16 units or lower). + +

Normal Jumps + +
The maximum height for barriers the bots will jump on is 32 +units. + +

Water Jump Heights (or "Everyone, out of the pool!") + +
The maximum distance that a bot may jump to exit water is 18 +units. This is the height difference between the water surface and +the adjacent floor that the bot is jumping onto. If the water jump +height is made higher, human players will have a hard time getting +out of the water. + +

Rocket Jumps + +
With normal gravity and without the quad, the maximum rocket +jump height is around 280 units (you can sometimes jump a few units +higher but this is a safe value for reference). In practice, except +for especially tricky jumps, this value should be substantially +lower. Test rocket jumps repeatedly before settling on a +final height. + +

Math for Map Makers + +
Here's some math to calculate some other values of interest: + +

Gravity = 800; + +
Jump velocity = 270; + +
Max vertical rocketjump velocity = 670; + +
Max run velocity = 320; + +
Max step height = 18; + +
Max jump height = 0.5 * gravity * +(jumpvelocity/gravity)*(jumpvelocity/gravity); + +
Max normal jump height = 45 units + +
NOTE: even +though this is the mathematical maximum jump height always keep the +the 32 units maximum barrier height for bots in mind when building +maps. + +
Maximum horizontal jump distance over a gap from one spot +to another when both are at the same height: + +

    t = sqrt((maxjumpheight + maxstep) / (0.5 * gravity)); + +
    t = 0.3986 seconds; + +
    dist = maxrunvelocity * (t + jumpvelocity / gravity); + +
    dist = 235 units;
+ +

Because players use a bounding box we can jump a full bounding +box width further in the ideal case. (15 units at the jump starting +position and 15 at the landing place). + +

    235 + 15 + 15 = 265 units.
+ +

Again, remember that this is the mathematical maximum which +players can only reach under ideal circumstances. + +

Optimizing a Map for bspc Compiling

+ +The area file is the tool that the bots use to understand the +map. If it is overly complex, it can cause navigation problems. +With careful attention to detail, many of these problems can be +eliminated, or avoided altogether. + +

First, understand that hint brushes, which are of great use to +the bsp compiler, have no effect on the bspc tool that creates area +files. Only solid, clip and liquid brushes and curve patches are +used by the bspc tool. Using these mapcomponents, the bspc tool +outputs how many "areas" will be created for a map. Having fewer +areas in a map is better than having more. + +

Quite often, map trim and detail create many of these small +areas. For the most part, these small areas are too small to enter +and are thus useless to the bots. Brushes that project out into the +map's floor cut it up and create additional areas. Often the number +of areas can be greatly reduced by adding additional clip brushes. +Take a look at Q3DM7 in the map editor, and you will see the walls +are literally covered with clip brushes. This not only +smooths out passage for human players, but also has the added +benefit of eliminating unnecesary navigation areas. This is +also why, as many "camping style" players have found, many areas +above door and window trim have also been clipped off. + +

Another way to reduce complexity is to use clip brushes to +simplify the collision area around complex objects. For exmple, the +map maker can add clip brushes with simple shapes (axial or +"square" brushes are prefered) around (small) detail brushes. +Simple shaped clip brushes can also be added around curves to +reduce the collision complexity (for instance, place an axial clip +brush around a small cylinder). It is better to place the clip +brushes around the whole curve (not just part of the curve). The +map maker should also use shader scripts to make the textures on +brushes or curve patches non-solid (surfaceparm nonsolid) when they +are enclosed by (full) clip brushes. This will also speed up bspc +calculations. + +

Always try to align your geometry to the grids. Always use the +largest grid possible for alignment of your geometry. Also try to +align the backsides of brushes which may not be visible. The more +brush sides are aligned the better. This will also speed up bspc +calculations. + +

Align adjacent brushes as much as possible. Make sure that badly +aligned brushes create no tiny faces. + +

Quite often there are also places in a map that are visible to +players but where players can never go (even determined, +rocket-jumping players). If a player could reach that area, they +would be able to walk around upon it. If the mapmaker decides not +to allow that, he or she should use large clip brushes to enclose +the entire unreachable space. This will also speed up bspc +calculations and reduce the number of areas created by the bspc +tool. + +

Note: the number of areas relative to the map size tells +something about the navigation complexity for players in general +(also human players). Reducing the collision complexity for bots +also makes the map easier to navigate for human players + +

Entities & the Navigation File

+ +There are specific rules and guidelines for using a number of +entities and entity-like textures with the bspc tool. + +

Func_plat and Func_bobbing
+ +When func_plat or func_bobbing entities are placed in a map, the +bots will use them if possible. The bots assume they can stand on +top of the bounding box (xy extents of all components used to +create the entity) of the model used for the func_plat or +func_bobbing entity. As a result, creating complex-shaped func_plat +or func_bobbing models is mostly a bad idea. You have to make sure +the bots (and players) can actually stand everywhere on top of the +bounding box of the model. The basic rule: If a bot is going to use +a func_plat or a func_bobbing, make sure the top surface is a +solid, rectilinear rectangle or square. + +

Cluster Portals
+ +Cluster portals are one of the several "texture entities" used +by the game engine. These are textures, which as used by the game +engine, function like entities. The bspc tool divides the map into +many, much smaller areas, which are essentially the surfaces a bot +can move upon during play. Several of these areas can be grouped +together to create a cluster. The clusters are seperated by cluster +portals, which are also areas themselves. One of the things the bot +uses these clusters for is to create a multi-level routing +algorithm. When a map is efficiently divided up into clusters bot +calculations (in run time) will be faster. + +

Guidelines to Consider When Placing Cluster Portals: + +

  • The BSPC tool creates cluster portals automatically, but placing +"clusterportal" brushes can create additional cluster portals. + +
  • Placing "clusterportal" brushes inside the map manually creates +cluster portals. + +
  • The "clusterportal" brushes should not be used outside the world +hull. + +
  • The cluster portals do not have any effect on map vis. + +
  • If a door is already sealed with an areaportal brush, a +clusterportal is not necessary there. (areaportals are used by the +bspc tool as if they were cluster portals). + +
  • Just like the areaportals, the cluster portals must seal a space +off entirely from other areas. + +
  • The cluster portal areas should seal off a cluster in a way that +the only path towards another cluster is through a cluster portal +area. + +
  • Only create cluster portals where people can walk or swim +through. + +
  • Don't create cluster portals in gaps in the floor. (people would +fall through) + +
  • Cluster portals must separate no more and no less than two (2) +clusters. + +
  • Try to create clusters with all the same number of +"reachability" areas. For instance if the map has 5,400 areas try +to create 10 clusters with 540 areas each, or 12 clusters with 450 +areas each, etc. The BSPC tool lists the number of reachability +areas in each cluster. + +
  • Avoid creating clusters with only a few (less than 10) +areas. + +
  • When adding "cluster portal" brushes, try to place them in +places with minimal geometric complexity. For instance place them +inside convex door openings or small hallways (not in front of door +openings). Ideally, the shape of the face through which a player +walks or swims into the cluster portal is the same as the shape of +the face through which a player leaves the cluster portal. Also +ideally, the open space inside the cluster portal brush is +convex. + +
  • Make cluster portals about 16 or 32 units thick.
+ +

"Do Not Enter" Areas
+The Do Not Enter texture is another one of the "texture +entities" that the game engine uses as if they were entities. In +some regards, it is like a clip brush, intended to prevent a bot +from moving into or through it. However, this works more as a +"strong suggestion" and is, in reality, not a physical barrier to +the bot. A simple example of how a bot may enter a "Do Not Enter" +area is knockback. If an explosion tosses a bot about, it may end +up inside a prohibited area. Bots may pass out of such areas, but +they will not actively try to enter them. + +

When bot navigation problems show up or you want to make sure a +bot never tries to go to a certain place use a "do not enter" +brush. + +

Guidelines to consider when placing "Do Not Enter" +brushes: + +

  • The "do not enter" brushes should not be used outside the world +hull. + +
  • The "do not enter" brush is Not a clip brush for the bot. + +
  • The "do not enter" brush is a tool of last resort. Do not use it +unless there are serious navigation problems. + +
  • The number of "do not enter" brushes should be minimized because +these brushes create additional areas for the bots. + +
  • The "do not enter" brush will create a new area that the bot +will try to avoid. However if the bot somehow ends up inside a "do +not enter" area or there is a valid goal (game entity or +item_botroam entity) inside the "do not enter" area then the bot is +allowed to go into and out of that area. So if the bot somehow gets +in a "do not enter" area the bot will be able to get out.
+ +

Bot Control Entities
+ +These entities encourage a bot to move about and use more parts +of the map. + +

Item_botroam +
The item_botroam entity can be used when a bot does not roam the +whole level or prefers to go to only specific areas. This +(invisible) item can be placed in a map just like regular items. +Nobody can actually pick up the item. It's only used to attract +bots to certain places of the map. + +

The item_botroam has a key "origin" that is set by Q3Radiant +automatically. + +

The item_botroam also has a key "weight." The value is the +weight of the roam item and is relative to the weight of other +items in the map, which are individual to each bot. The bot +character-specific item weights are stored with the bot characters +in the botfiles/bots/ sub-folder in the .pk3 file. The value of the +weight is a non-zero floating-point value, most often in the range +0 to 400. Higher values are allowed but keep in mind that the bot +should also still go for normal items, so don't make the +item_botroam weight too high. + +

"Notbot" Means "Don't Touch" + +
When a bot should never go for a specific item, the key +"notbot" with a value of "1" can be used for that item. This +notbot key and its value can be used for every available item in +Quake III Arena. + +

Info_Camp + +
This entity suggests locations where the bot can wait for +enemies to come into view. + + +

Suspended + +
The suspended checkbox flag can be used on all items +(item_botroam included). However keep in mind that when a suspended +item is not anywhere near the ground the bot will ONLY try to go +for this suspended item using jump pads. + +

Testing .AAS files

+ +
Solid Areas
+ +A solid area in the map is an area that looks empty to the human +player, but is solid, like a wall, to a bot player. One of the +easiest ways to test the AAS file for solid areas is to load the +map in Quake III Arena in teamplay mode (type /set +g_gametype 3 on the console before loading the map). Enter a team +and add a bot to your team. Use the team order menu (by default +bound to the F3 key) to command the bot to follow you. Walk around +the map and see if the bot is able to follow you everywhere. If a +bot stops at any point, it may have encountered an area of the map +that appears to be unblocked to you, but to the bot, it is like it +has encountered a solid wall. + +

Test Solid + +
In most cases, solid areas are the result of careless design. +But, if you insist on making maps that are not axial in layout +(say, your average cave), they can result from brushes meeting at +non-axial angles. These "map bugs" can sometimes cause certain +places in the map to show up solid in the AAS file. To test for +these solid places set the cvar bot_testsolid to "1" on the +console. (type /set bot_testsolid 1) + +

As you walk through the map, either "empty area" or "SOLID area" +will be printed on the screen while traveling through a map. + +

The Culprits: What May Cause Map Bugs + +
Several map bugs can cause these solid places in the AAS +file. + +

  • Sometimes microscopic brushes are created by CSG subtraction on +one or more brushes. Search for such brushes in the problem area +and delete them. + +
  • Tiny brush faces (not curves) can also cause problems. Due to +vertex snapping in the q3map tool, those tiny brush faces can be +snapped out of existence. Such faces will not show up in Quake +III Arena and you'll see tiny peek holes or slits where you can +view through the geometry (often into other rooms). Align vertexes +of adjacent brushes to remove and avoid such tiny faces. Placing a +clip brush in front of the face that is snapped out of existence +will also remove the "solid area" but of course it's preferred to +remove the peek hole or slit. Another cause could be a brush with a +collapsed side. Check how many sides a brush has and how many sides +actually have a surface. Rebuild brushes with collapsed sides. + +
  • Lava creates a solid area. All faces contained within liquid +brushes using a shader without "surfaceparm trans" set will be +removed (this includes some lava textures). Those contained +surfaces will not be visible and can cause the liquid to appear +"solid" in the aas file.
+ +

Hacking Away the Problem + +
If you insist creating an .AAS file for a map with bugs, then +the BSPC compile option -forcesidesvisible can be used. This +should fix all the problems with areas showing up solid in the .AAS +file. However creating an .AAS file with this option takes a lot +longer (often more than twice the normal compile time). This is not +recommended as a default option for compiling. + +

Testing Jump and Launch Pads + +
Jumppads can also be tested. Type the following on the Quake +III Arena console, before loading your map: + +

/set bot_maxdebugpolys 1024 + +
/set bot_visualizejumppads 1 + +
/set bot_forcereachability 1 + +

Now load the map. A counter will be shown and goes from 0% to +100%. When the counter has reached 100% type /set r_debugSurface 2 +on the console. For every jumppad the default arc of travel +(without using air control) will be visualized. + +

Version Changes

+ +1.8 (2000-01-08) + +
- increased max points on winding + +
- made "HashVec: point x y z outside valid range" non-fatal + +
- fixed rocket jump reachabilities + +
- added force sides visible option + +
- increased simulated stack size for area traces + +

1.7 (1999-12-22) + +
- fixed ducked bounding box size + +
- fixed sv_maxsteepness being zero in aas configuration + +
- AAS files are now automatically stored in BSP file folder + +
- fixed crash bug caused by overflow of a simulated stack + +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_d.htm b/docs/manual/Q3Rad_Manual/appndx/appn_d.htm new file mode 100644 index 00000000..a4650ca3 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_d.htm @@ -0,0 +1,243 @@ + + +Q3Radiant Editor Manual: Appendix D + + + +

Q3Radiant Editor Manual

+
+

Appendix D: Tricks, Tips, and Tutorials

+ +

Making the death fall sound…

+ +The death yell that occurs when a player or bot falls into the +void or fog of death is triggered by the falling character passing +through a trigger multiple (should be no less than 32 units thick) +that is targeted on a target_speaker. If you look at q3DM17 +and find a target speaker, you will see that it plays the falling +to death sound of the player who activates the trigger. Put +that sound in your own target_speaker. + +

Making a Mirror …

+ +Apply a mirror texture to brush (it will only work on brushes, +not curve patches). Next, place a misc_portal_surface entity within +64 units of the mirror and at roughly eye level for the character. +Because a mirror shows all that it can "see" the mapmaker needs to +take special care that his mirror doesn't see so much of the map +that it affects game performance. + +
    Rules: A mirror should not be able to see another +mirror or portal surface. This means no mirror mazes or +mirror facing each other to produce infinite reflections.
+ +

Making a Jump Pad

+ +
  1. Make the brush that contains your pulsing pad texture. It can be +set in the floor or raised up on separate brush. + +
  2. Make a trigger_push brush entity that is smaller than the pad +(the id triggers are usually octagonal). + +
  3. Create a target_position entity and move it to the height and +location you want. The target position is both the aiming point for +the trigger_push and the highest point (apex) of the assisted +jump. + +
  4. Hi-light the trigger first, then the target_position (order is +important). + +
  5. Press CTRL + k to connect the two entities (pointing the first +at the second). + +
  6. Compile and test it. The first compile needs to be a full or +fast vis. If you need to make adjustments to the target_position, +you only need to use an entities compile.
+ +

Lining Up the Pad Texture
+ +The combination of shader keys that make the jump pad pulsing +texture work can be tricky to line up. Try the following methods if +your own attempts bring no joy. + +
  1. Make the brush that will be your pad (128x128 units). + +
  2. Apply the pad texture. If it doesn't line up, turn off the lock +texture feature and move the pad until it lines up perfectly. + +
  3. Lock the texture and move the brush into position.
+ +

If that doesn't work: + +

  1. Build your brush in place. + +
  2. Apply the pad texture so that several corners of the pad circle +are visible. + +
  3. Compile a regioned area with the jump pad in it. + +
  4. At least one of the pad circles should have a pulsing circle in +it. + +
  5. Back in the editor, slide the pad circle with the active pulse +so it fills the pad. + +
  6. Recompile. It should work now.
+ +

Making a Launch Pad

+ +Target the trigger_push that you put above the pad at a +target_position. The player will accelerate until he reaches the +target. Physics does the rest. + +

Note: The center point of the target must be +higher than the center point of the trigger_push. + +

Making a "Rocket Arena" style map

+ +
  1. Create all the entities you want the player to spawn with when +he enters the arena, and make sure they are somewhere within the +enclosed space of the map. + +
  2. Add a "target_give" entity somewhere in the world. + +
  3. Create all the spawn spots you want to be in your map. + +
  4. Select the "target_give" entity. + +
  5. Select one of the "give on spawn in" entities. + +
  6. Hit Ctrl-K in the editor to link the two items together. + +
  7. Repeat steps 4 through 6 until the target_give is linked to +all +the entities you wish the player to spawn into the world with. + +
  8. Select a spawn spot + +
  9. Select the target_give entity + +
  10. Hit Ctrl-K in the editor to link the two entities together. + +
  11. Repeat steps 8 through 10 until all the spawn spots are linked +to +the target_give entity. + +
  12. Compile the map + +
  13. Set g_gametype to tournament mode and set fraglimit of 1. + +
  14. Get a bunch of your friends to connect into your server and +have +fun playing a "Rocket Arena" style game =)
+ +

An alternate use of target_give is how I used it in q3dm10 to +create the +"power tube" that gives you health and armour. The tube has a +trigger_multiple with a wait of 0.5, linked to a target_give which +is linked +to a small health and an armour shard. + +

Making an Environment Box …

+ +This is the shader script taken from the sky.shader that I used +to make a test sky box months and months ago. + + + +

In baseq3, make an 'env' folder. + +

Put your skybox art in here and use this naming +convention: + +

[skyname]_lf.tga + +
[skyname]_rt.tga + +
[skyname]_ft.tga + +
[skyname]_bk.tga + +
[skyname]_up.tga + +
[skyname]_dn.tga + +

  • Make a directory in your quake3 folder with the following path: + +
      quake3/baseq3/textures/[mymapname]
    + +
  • Make a directory in your quake3 folder with the following path: + +
      quake3/baseq3/scripts
    + +
  • Make a script document called [mymapname].shader + +
  • Make a script document called shaderlist.txt
+ +

In shaderlist.txt put [mymapname] on the first line and close +the document. + + + +

+//*******************************************************
+//*	    Sample environment box shader
+//*******************************************************
+
+textures/[mymapname]/[skyname]01
+
+{
+	qer_editorimage textures/[mymapname]/[skyname]
+
+	surfaceparm noimpact
+	surfaceparm nolightmap
+	surfaceparm sky
+	q3map_sun 0.933333 0.541176 03.13725 60 160 11
+	q3map_surfacelight 100 //lots of diffuse light
+	skyparms - 512 -
+	sky env/[skyname]
+
+// the following stuff lays clouds over the skybox map which you may not want with a city skyline
+	//{
+	// map textures/skies/dimclouds.tga
+	//
+	// tcMod turb 0 0.001 0.5 0.001
+	// tcMod scale 3 3
+	// tcMod scroll 0.01 0.01
+	// blendFunc GL_ONE GL_ONE_MINUS_SRC_COLOR
+	// depthWrite
+	//}
+	//{
+	// map textures/skies/pjbasesky.tga
+	// blendfunc GL_ONE GL_ONE
+	// tcMod scroll -0.01 -0.01
+	// tcMod scale 5 5
+	//}
+//}
+ +

Making a Shooter

+The shooters; shooter_rocket, shooter_grenade, and +shooter_plasma all fire a single projectile when they are triggered +by an event. + +
  • Make a shooter entity (rocket, grenade or plasma) + +
  • Give it a facing (1 to 360 degrees), or, + +
  • Target it at a target_position. + +
  • Give it a random value (potential degrees off target) + +
  • Create an Activator. Make a trigger multiple or target an entity +at the shooter. When the trigger is entered or the entity is taken, +the, shooter is activated. + +
  • If you want a shooter to fire multiple times, target the +activator on two or more target_delays. Set the delay time to a +different value for each (if using a trigger multiple, the WAIT +value on the trigger should be greater than the longest delay on +the target_delay). Target each target_delay on the shooter.
+ +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_e.htm b/docs/manual/Q3Rad_Manual/appndx/appn_e.htm new file mode 100644 index 00000000..d243d327 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_e.htm @@ -0,0 +1,225 @@ + + +Q3Radiant Editor Manual: Appendix D + + + +

Q3Radiant Editor Manual

+
+

Appendix E: Online Resources

+ +The Internet is an excellent source for information about Quake +engine editing.  The sites listed here provide a variety of +useful editing resources. + +

Disclaimer: Most of these sites are established, heavily +trafficked web pages with a history of stability. But, because +these sites are not maintained by id Software, we make no claims +that they will be there when you go looking for them or that they +will still have the information of the type you are seeking.
+ +

News about the Editor

+ +
QERadiant.com
+ +Qeradiant.com is the official site for the id editing tool that +was the predecessor of Q3Radiant. + +
http://www.qeradiant.com/ + +

MapCenter
+ +A great online forum based resource for models, skinning, textures, and mapping in many different games. + +
http://www.map-center.com + + +

Quake3World.com
+ +Looking for a heavily trafficked message board where questions +often get answered by the id designers? Look no further than the +community section of Mplayer's Quake3World.com. + + +http://www.quake3world.com/ + +

Editing Tutorials

+ +These tutorials are located at several sites that have been +around for a while, and may continue to be around. + +

Tram Design
+ http://www.planetwolfenstein.com/tramdesign/index.html + +
Tutorials and files for Return To Castle Wolfenstein editing. + +

Claudec's Lair of Shaders
+ + +http://www.claudec.com/lair_of_shaders/ + +
Numerous tutorials on editing subjects. + +

RiceBug.Com
+ + +http://ricebug.qeradiant.com/ + +
Some good tutorials on Q3Radiant (the Quake 3 editor) and QERadiant (the Quake 2 +editor). + +

RUST - Game Design.net
+ + +http://www.gamedesign.net/ + +
RUST has been a prime source for Quake engine editing for some +time. + +

Editing Tools

+ +

GenSurf
+ + +http://tarot.telefragged.com/gensurf/index.shtml + +
GenSurf is a "natural" terrain creation tool that converts a +grayscale bitmap into a web of triangular brushes or curve patches. +Used with care, it can make some very interesting irregular +surfaces. + +

Milkshape 3D
+ + +http://www.swissquake.ch/chumbalum-soft/home.html + +
This is a shareware editor for 3D models. Support for Quake +III Arena's native md3 format is forthcoming. + +

Quake 3 Arena Shader Editor
+ + +http://www.larian.com/rat/q3ase.html + +
This is a tool for editing shaders. It allows you to construct +the shader in realtime, seeing what works you build it. + +

Prefab Sources

+ +
Gamedesign.net Prefabs
+ +http://prefabs.gamedesign.net/game.php3?game_id=13&num=0 + +
This Rust's source for prefabricated map plug-ins. These here +are in the form of .map files instead of Quake III Arena's +native .pfb format. + +

Quake Prefab Park 2
+ + +http://www.planetquake.com/qpp/qpp2/ + +
These are prefabs designed for use with Quake and +Quake 2, which means the ones with movement or action gimmicks +most likely will not work. And of course, you'll need to +retexture anything you find here if it's not a Quake III +Arena prefab. + +

Texture Sources

+ +The following sites include shader documents, downloadable +textures, tutorials or links to tutorials on making your own. + +

Shaderlab - Robot Life
+http://www.shaderlab.com + +
This site has a nice selection of textures and shaders to go with them. + +

[h f x]
+http://www.planetquake.com/hfx/ + +
This is a fantastic source for textures and shaders as well. + +

Mean Arena
+ + +http://www.planetquake.com/meanarena/Q3_textures.html + +
This site has a few texture sets to choose from. + +

Quake III Arena Shader Manual
+ + +http://www.planetquake.com/polycount/resources/quake3/tutorials.shtml + +
+http://www.quake3world.com/files/Q3Ashader_manual.doc + +
This is the official id documentation of Quake III Arena +shaders. The second source is a download. + +

Texture Forest
+ + +http://www.planetunreal.com/forest/main1.html + +
It is possible to learn some tricks from artists who work for +that "other" game engine. + +

Map Object Model Sources

+ +
F.P.S.
+http://fps.brainerd.net/ +
Tons of Quake 3 stuff. The best part though is the map models section. A whole lot of them at this site. + +

Polycount
+ + +http://www.planetquake.com/polycount/resources/quake3/index.shtml + +
This link takes you to the resource page for Quake III Arena +modeling. + +

Frequently Asked Questions (FAQ)

+ +
Developer's FAQ (Quake3mods)
+ + +http://www.q3seek.com/edit.php3 + +
This site answers a lot of questions about map making, model +making, texturing and skinning. Mod makers appear to have +submitted much of the information. + +

Official Quake III Arena FAQ (Quake3world.com)
+ + +http://www.quake3arena.com/faq/ + +
This is the official FAQ, created and maintained by id Software. +Most of the information pertains to general problems players +encounter with Quake III Arena, and doesn't have a lot to do with +map making. + +

RUST - Game Design.net
+ + +http://www.gamedesign.net/quake3/faq/ + +
This development-oriented site has a Quake III Arena FAQ though at the moment it's not particularly helpful. + +

Map Reviews, General Information

+ +
LVL - Q3A Edition
+ + +http://www.planetquake.com/lvl/ + +
A great level review site. It also has a great beta section for people to beta test your maps before you release and get you some feedback to make it one of the best levels out there. + +

Back | Home | Next + + diff --git a/docs/manual/Q3Rad_Manual/appndx/appn_f.htm b/docs/manual/Q3Rad_Manual/appndx/appn_f.htm new file mode 100644 index 00000000..0458dd6b --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/appn_f.htm @@ -0,0 +1,144 @@ + + +Q3Radiant Editor Manual: Appendix F + + + +

Q3Radiant Editor Manual

+
+

Appendix F: Default Key Shortcuts

+ +On the odd chance that you (like the author of this manual) might seriously mess up your default key bindings when making an .ini file, here are the default assignments to correct your mistake. Copy these below the [commands] line of your .ini file. + +

HideSelected			H
+ShowHidden			Shift + H
+BendMode			B
+FitFace				Control + B
+FitBrush			Shift + B
+FreezePatchVertices		F
+UnFreezePatchVertices		Control + F
+UnFreezeAllPatchVertices	Shift + Control + F
+ViewTextures			T
+ThickenPatch			Control + T
+MakeOverlayPatch		Y
+ClearPatchOverlays		Control + Y
+SurfaceInspector		S
+PatchInspector			Shift + S
+ToggleShowPatches		Shift + Control + P
+ToggleShowPatches		Control + P
+RedisperseRows			Control + E
+RedisperseCols			Shift + Control + E
+InvertCurveTextureX		Shift + Control + I
+InvertCurveTextureY		Shift + I
+InvertCurve			Control + I
+IncPatchColumn			Shift + Control + PLUS
+IncPatchRow			Control + PLUS
+DecPatchColumn			Shift + Control + SUBTRACT
+DecPatchRow			Control + SUBTRACT
+Patch TAB			TAB
+Patch TAB			Shift + TAB
+SelectNudgeDown			Alt + DOWN
+EntityColor			K
+CameraForward			UP
+CameraBack			DOWN
+CameraLeft			LEFT
+CameraRight			RIGHT
+CameraUp			D
+CameraDown			C
+CameraAngleUp			A
+CameraAngleDown			Z
+CameraStrafeRight		PERIOD
+CameraStrafeLeft		COMMA
+ToggleGrid			0
+SetGrid1			1
+SetGrid2			2
+SetGrid4			3
+SetGrid8			4
+SetGrid16			5
+SetGrid32			6
+SetGrid64			7
+DragEdges			E
+DragVertices			V
+ViewEntityInfo			N
+ViewConsole			O
+CloneSelection			SPACE
+DeleteSelection			BACKSPACE
+UnSelectSelection		ESCAPE
+CenterView			END
+ZoomOut				INSERT
+ZoomIn				DELETE
+UpFloor				PAGEUP
+DownFloor			PAGEDOWN
+ToggleClipper			X
+ToggleCrosshairs		Shift + X
+TogTexLock			Shift + T
+TogTexRotLock			Shift + R
+ToggleRealtime			Control + R
+EntityList			L
+Preferences			P
+ToggleCamera			Shift + Control + C
+ToggleConsole			O
+ToggleView			Shift + Control + V
+ToggleZ				Shift + Control + Z
+ConnectSelection		Control + K
+Brush3Sided			Control + 3
+Brush4Sided			Control + 4
+Brush5Sided			Control + 5
+Brush6Sided			Control + 6
+Brush7Sided			Control + 7
+Brush8Sided			Control + 8
+Brush9Sided			Control + 9
+ShowDetail			Control + D
+MakeDetail			Shift + Control + M
+MakeDetail			Control + M
+MapInfo				M
+NextLeakSpot			Shift + Control + K
+PrevLeakSpot			Shift + Control + L
+FileOpen			Control + O
+FileSave			Control + S
+Exit				Control + X
+NextView			Control + TAB
+ClipSelected			RETURN
+SplitSelected			Shift + RETURN
+FlipClip			Control + RETURN
+MouseRotate			R
+Copy				Control + C
+Paste				Control + V
+Undo				Control + Z
+ZZoomOut			Control + INSERT
+ZZoomIn				Control + DELETE
+TexDecrement			Shift + SUBTRACT
+TexIncrement			Shift + PLUS
+TextureFit			Shift + 5
+TexRotateClock			Shift + PAGEDOWN
+TexRotateCounter		Shift + PAGEUP
+TexScaleUp			Control + UP
+TexScaleDown			Control + DOWN
+TexShiftLeft			Shift + LEFT
+TexShiftRight			Shift + RIGHT
+TexShiftUp			Shift + UP
+TexShiftDown			Shift + DOWN
+GridDown			[
+GridUp				]
+TexScaleLeft			Control + LEFT
+TexScaleRight			Control + RIGHT
+CubicClipZoomOut		Control + [
+CubicClipZoomIn			Control + ]
+ToggleCubicClip			Control + \
+MoveSelectionDOWN		SUBTRACT
+MoveSelectionUP			PLUS
+DumpSelectedBrush		Shift + D
+ToggleSizePaint			Q
+SelectNudgeLeft			Alt + LEFT
+SelectNudgeRight		Alt + RIGHT
+SelectNudgeUp			Alt + UP
+CycleCapTexturePatch		Shift + Control + N
+NaturalizePatch			Control + N
+SnapPatchToGrid			Control + G
+ShowAllTextures			Control + A
+SelectAllOfType			Shift + A
+CapCurrentCurve			Shift + C
+
+

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/appndx/sskey_dl.htm b/docs/manual/Q3Rad_Manual/appndx/sskey_dl.htm new file mode 100644 index 00000000..22e31c02 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/appndx/sskey_dl.htm @@ -0,0 +1,977 @@ + + + Shortcut keys and Mouse functions in QeRadiant & Q3Radiant + + + + +

Q3Radiant Editor Manual

+
+

Appendix G: Shortcut keys and Mouse functions
in QeRadiant/Q3Radiant

+ +

By Eutectic

+ + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +

1. Introduction

+

This is a list of all the command shortcut keys and key-mouse functions in QeRadiant and Q3Radiant. Please note that there are some commands that work in QeRadiant and not in Q3Radiant and vice versa. This is mainly because those are actually 2 different map editors for 2 very different game engines (Quake II and Quake III Arena) even though they share a common interface. But unless otherwise specified, the commands in this list work for both editors. Also note that in QeRadiant, there are some functions that work when selected from the menus but for which the shortcut key doesn't work. Whenever this is the case, this is clearly indicated with a color coded table cell.

+This revised version of this list reflects all the changes and additions in Q3Radiant Build 189.

+ +

2. Shortcut key list

+

The commands are sorted by category and color coding was implemented in the table boxes: + +

    +
  • Red background:

    +This denotes shortcut keys which are listed in the Help command list but don't work.


  • +
  • Green background:

    +This denotes shortcut keys or mouse functions which apply only to QeRadiant.


  • +
  • Orange background:

    +This denotes shortcut keys or mouse functions which apply only to Q3Radiant.


  • +
  • Purple background:

    +This denotes shortcut keys which are assigned to different features in QeRadiant and Q3Radiant.
  • +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ActionDescriptionShortcut Key
2D view and Z view navigation & control keys
Toggle ViewOnly used in free window mode. Toggles the 2D view on/off.CTRL+SHIFT+V
Next ViewCycles the 2D view through all 3 views (top, front, side). Not used in 4 view mode.CTRL+TAB
Zoom InZooms 2D view in.DELETE
Zoom OutZooms 2D view out.INSERT
Center On CameraCenters the 2D view on the camera's current location.G
Toggle ZOnly used in free window mode. Toggles the Z view on/off.CTRL+SHIFT+Z
Z Zoom InZooms Z checker window in.CTRL+DELETE
Z Zoom OutZooms Z checker window out.CTRL+INSERT
3D view navigation & control keys
Camera BackMakes the POV in the 3D view move backwards.DOWN ARROW
Camera ForwardMakes the POV in the 3D view move forward.UP ARROW
Camera LeftMakes the POV in the 3D view look left.LEFT ARROW
Camera RightMakes the POV in the 3D view look right.RIGHT ARROW
Camera Strafe LeftMakes the POV in the 3D view move left.COMMA ( , )
Camera Strafe RightMakes the POV in the 3D view move right.PERIOD ( . )
Camera DownMakes the POV in the 3D view move down.C
Camera UpMakes the POV in the 3D view move up.D
Camera Angle DownMakes the POV in the 3D view look down.Z
Camera Angle UpMakes the POV in the 3D view look up.A
Center ViewCenters the POV in the 3D view.END
Down FloorMoves the POV in the 3D view down by one floor.PAGE DOWN
Up FloorMoves the POV in the 3D view up by one floor.PAGE UP
Toggle CameraOnly used in free window mode. Toggles the 3D view on/off.CTRL+SHIFT+C
Toggle Cubic ClipToggles 3D view clipping on/off. This feature works in both editors but shortcut key only works in Q3Radiant.CTRL+\
Cubic Clip Zoom InMakes the cubic clipping plane come in closer. Best used for speed optimizations.CTRL+ ]
Cubic Clip Zoom OutMakes the cubic clipping plane move further out. CTRL+ [
Toggle RealtimeToggles on/off real time 3D view camera updates.
+Feature doesn't work.
CTRL+R
Grid + control keys
Toggle GridTurns grid view on/off.0
Set Grid 1Sets the grid to 1 unit.1
Set Grid 2Sets the grid to 2 units.2
Set Grid 4Sets the grid to 4 units.3
Set Grid 8Sets the grid to 8 units.4
Set Grid 16Sets the grid to 16 units.5
Set Grid 32Sets the grid to 32 units.6
Set Grid 64Sets the grid to 64 units.7
Grid DownDecreases the size of the grid.[
Grid UpIncreases the size of the grid.]
Brush & entity creation and manipulation keys
Brush (3 sided)Creates a 3 sided brush.CTRL+3
Brush (4 sided)Creates a 4 sided brush.CTRL+4
Brush (5 sided)Creates a 5 sided brush.CTRL+5
Brush (6 sided)Creates a 6 sided brush.CTRL+6
Brush (7 sided)Creates a 7 sided brushCTRL+7
Brush (8 sided)Creates a 8 sided brush.CTRL+8
Brush (9 sided)Creates a 9 sided brush.CTRL+9
Unselect SelectionDeselects all currently selected objects.ESC
Delete SelectionDeletes all currently selected objects.BACKSPACE
Clone SelectionCreates a duplicate of the currently selected objects.SPACEBAR
Drag Edges ModeToggles edge manipulation mode on/off. Edges are represented by blue dots on the brush.E
Drag Vertex ModeToggles vertex manipulation mode on/off. Vertices are represented by green dots on the brush.V
Brush Clip modeToggles brush clipping mode on/off.X
Flip ClipSwitches which part of the brush is going to be clipped away on the set clip plane points while in clipping mode.CTRL+ENTER
Clip SelectedClips the selected brush/brushs on the set clip plane points while in clipping mode.ENTER
Split SelectedSplits the selected brush/brushs on the set clip plane points while in clipping mode.SHIFT+ENTER
Move Selection DownMoves the selected object down in Z axis by units equal to the grid size (independent of current 2D view).KEYPAD MINUS
Move Selection UpMoves the selected object up in Z axis by units equal to the grid size (independent of current 2D view).KEYPAD PLUS
Select Nudge DownMoves the selected object down in current 2D view by units equal to the grid size.ALT+DOWN ARROW
Select Nudge UpMoves the selected object up in current 2D view by units equal to the grid size.ALT+UP ARROW
Select Nudge LeftMoves the selected object left in current 2D view by units equal to the grid size.ALT+LEFT ARROW
Select Nudge RightMoves the selected object right in current 2D view by units equal to the grid size.ALT+RIGHT ARROW
Snap Selection To GridSnaps the vertices of the currently selected brush or patch mesh to the grid.CTRL+G
Make DetailTurns selected structural brush into a detail brush.CTRL+M
Make StructuralTurns selected detail brush into a structural brush.CTRL+SHIFT+S
Dump Selected BrushDumps a list of the plane point coordinates of all the faces of the currently selected brush to the console view.SHIFT+D
View Entity InfoBrings up the entity dialog window.N
Select Whole EntitiesQeRadiant only: Toggles feature on/off. When feature is on, selecting any single brush of a multiple brush entity automatically selects all the brushes that belong to that entity (This shortcut key does a Redisperse Rows in Q3Radiant).CTRL+E
Cycle Group SelectionCycle selects each individual brush of currently selected bsp-model entity (Select Whole Entities must not be on in QeRadiant). This command was renamed Patch Tab in Q3Radiant but it's function is unchanged.TAB
Connect SelectionConnect entities target to targetname.CTRL+K
Entity ColorUse this to set the "_color" key of a entity by bringing up the standard Windows RGB color selector. Used for choosing the color of lights for example.K
Texture manipulation keys
View TexturesOnly used in 4 view and free window modes. Brings up the texture selection window (toggle in 4 view mode).T
Surface InspectorBrings up the surface properties dialog (only used to align textures in Q3Radiant).S
Texture Shift DownMoves texture on currently selected brush face(s) downwards. Also works for patches but might sometimes give unexpected results.SHIFT+DOWN ARROW
Texture Shift UpMoves texture on currently selected brush face(s) upwards. Also works for patches but might sometimes give unexpected results.SHIFT+UP ARROW
Texture Shift LeftMoves texture on currently selected brush face(s) to the left. Also works for patches but might sometimes give unexpected results.SHIFT+LEFT ARROW
Texture Shift RightMoves texture on currently selected brush face(s) to the right. Also works for patches but might sometimes give unexpected results.SHIFT+RIGHT ARROW
Texture Rotate ClockwiseRotates texture clockwise on currently selected brush face(s). Also works for patches but might sometimes give unexpected results.SHIFT+PAGE DOWN
Texture Rotate Counter-ClockwiseRotates texture counter-clockwise on currently selected brush face(s). Also works for patches but might sometimes give unexpected results.SHIFT+PAGE UP
Texture Scale DownDecreases vertical scale of texture on currently selected brush
face(s). Also works for patches but might sometimes give unexpected results.
CTRL+DOWN ARROW
Texture Scale UpIncreases vertical scale of texture on currently selected brush face(s). Also works for patches but might sometimes give unexpected results.CTRL+UP ARROW
Texture Scale LeftDecreases horizontal scale of texture on currently selected brush face(s). Also works for patches but might sometimes give unexpected results.CTRL+LEFT ARROW
Texture Scale RightIncreases horizontal scale of texture on currently selected brush
face(s). Also works for patches but might sometimes give unexpected results.
CTRL+RIGHT ARROW
Texture FitAutomatically fits the texture to the size of the currently selected brush face by scaling it vertically and horizontally. This shortcut only works in QeRadiant.SHIFT+5
Texture Fit To FaceSame as Texture Fit. This shortcut only works in QeRadiant.CTRL+F
Toggle Texture LockToggles brush move texture alignment locking on/off. This feature works in both editors but shortcut key only works in Q3Radiant.SHIFT+T
Toggle Texture Rotate LockToggles brush rotation texture alignment locking on/off. This feature works in both editors but shortcut key only works in Q3Radiant.SHIFT+R
Dialogs and special features keys
View ConsoleOnly used in 4 view and free window modes. Brings up the console (this is a toggle function in 4 view mode).O
PreferencesBrings up the user preferences dialog.P
Entity ListBrings up the entity list "tree view" window. This feature works in both editors but shortcut key only works in Q3Radiant.L
Map InfoBrings up the map info status window. This feature works in both editors but shortcut key only works in Q3Radiant.M
Filter SettingsBrings up the filters dialog window. This feature only works in QeRadiant.F
Show DetailToggles display of detail brushes on/off.CTRL+D
Animate Selected EntitiesToggles animation of selected mover entities (doors, buttons, etc.) on/off. This feature only works in QeRadiant.CTRL+A
Previous Leak SpotTakes POV in the 3D view to the previous leak spot (pointfile must be loaded).CTRL+SHIFT+L
Next Leak SpotTakes POV in the 3D view to the next leak spot (pointfile must be loaded). This feature works in both editors but shortcut key only works in Q3Radiant.CTRL+SHIFT+K
Misc utility keys
File OpenOpens a file.CTRL+O
File SaveSaves a file.CTRL+S
ExitCloses the editor.CTRL+X
CopyCopies whatever is currently selected.CTRL+C
PastePastes what ever is in the clip board. Only works with text and Radiant's stuff.CTRL+V
UndoUndo. Doesn't work in all cases.CTRL+Z
RedoRedo. Doesn't work in all cases.CTRL+Y
Q3Radiant miscellaneous features keys
View GroupsBrings up the groups dialog window.G
Toggle Size PaintMomentarily displays the position + dimensions of currently selected brush(es) in the 2D view.Q
Mouse RotateToggles mouse free rotation mode on/off for currently selected objects.R
Select Type AllSelects all "identical" based on type of "currently selected". If type is a surface, all solids with the same texture are selected. If type is an entity, all the other entities of its classname are selected.SHIFT+A
CSG MergeWill merge all currently selected brushes into a single brush. If the shape and size of any one of the selected brushes would cause the merge to produce a concave solid, the merge operation is not performed.SHIFT+M
Toggle CrosshairsToggles between the regular mouse pointer and a large crosshair style pointer in the 2D view.CTRL+SHIFT+X
Fit TextureThis will automatically scale the texture on the currently selected faces so one texture tile will fit exactly on the faces by default. It also brings up Surface Inspector so the texture can be fit to the faces by a different number of texture tiles than 1.SHIFT+B
Hide SelectedHides all currently selected objects from the 2D/3D views.H
Show HiddenUn-hides all objects currently hidden from the 2D/3D views.SHIFT+H
Show All TexturesShows all the textures currently loaded in Q3radiant's texture window. Use this to un-set Show In Use in the textures menu.CTRL+A
Patch TabCycle selects each individual brush or patch of currently selected bsp-model entity. This command was called Cycle Group Selection in QeRadiant but it's function is unchanged.TAB or SHIFT+TAB
Q3Radiant patch manipulation keys
Bend ModeToggles bend mode on/off. This is used to bend patch meshes. Follow the instructions that come up in the dialog box when you use this. Best used for making arches and such.B
Cap Current CurveAutomatically creates cap patches for the currently selected patch if it's a cylinder. For bevels and endcaps, it will bring up the cap dialog instead. The patch and its caps will then automatically be grouped in a func_group.SHIFT+C
Cycle Cap Texture PatchThis cycles the cap texturing type on the currently selected patch.CTRL+SHIFT+N
Cycle Cap Texture AxisThis cycles the cap texturing axis on the currently selected patch.CTRL+SHIFT+P
Naturalize PatchMakes the texture natural on the patch mesh (sometimes the textures are stretched to fit the patch, this will make the texture fit normal instead of streching it).CTRL+N
Increase Patch RowAdds 3 rows to currently selected patch.CTRL+KEYPAD PLUS
Decrease Patch Row Removes 3 rows from currently selected patch (assuming patch currently has more than 3 rows).CTRL+KEYPAD MINUS
Increase Patch ColumnAdds 3 columns to currently selected patch.CTRL+SHIFT+KEYPAD PLUS
Decrease Patch ColumnRemoves 3 columns from currently selected patch (assuming patch currently has more than 3 columns).CTRL+SHIFT+KEYPAD MINUS
Redisperse ColumnsEvenly re-disperses all the columns of the currently selected patch. Useful after adding new columns.CTRL+SHIFT+E
Redisperse RowsEvenly re-disperses all the rows of the currently selected patch. Useful after adding new rows (this shortcut key does a Select Whole Entities in QeRadiant).CTRL+E
Invert CurveThis inverts the patch mesh's matrix. IOW, it changes which side of the patch the texture is applied to.CTRL+I
Invert Curve Texture XInverts the X value of the texture on the matrix. Use this to mirror the texture vertically on a patch.SHIFT+I
Invert Curve Texture YInverts the Y value of the texture on the matrix. Use this to mirror the texture horizontally on a patch.CTRL+SHIFT+I
Matrix TransposeSwaps the rows and columns on a patch. There is no physical change on the patch as such: rows become columns and vice versa. Use this to change the natural texture orientation axis on patches.CTRL+SHIFT+M
Make Overlay PatchTurns on display of the currently selected patches control points. The display of the patches control points will remain on until turned off by Clear Patch Overlays.Y
Clear Patch OverlaysTurns off display of the currently displayed patches control points previously turned on by Make Overlay Patch.CTRL+L
Patch InspectorBrings up the patch inspector dialog.SHIFT+S
Thicken PatchCreates a copy of current patch and spaces it by X amount of units (as per value entered in dialog box) then caps off the mesh.CTRL+T
Toggle Show PatchesToggles display of patch meshes from 2D/3D views on/off.CTRL+P
+


+

3. Mouse Function list

+

This is the list of all the Mouse Functions in QeRadiant and Q3Radiant. Note that these are not shortcuts. The tasks accomplished by the mouse cannot be found in the menus. They provide much of the essential functionality in QeRadiant/Q3Radiant when designing maps.

+ +

Radiant's user interface includes many productivity features and is a very powerful tool. It's no wonder that it's the editor of choice for professional and amateur map designers alike. But it's true power is unleashed when you use a 3-Button mouse. Several extremely useful power features, especially when it comes to texturing, are only accessible if you use a 3-Button mouse. Many people own one nowadays and if you use QeRadiant regularly, I strongly recommend you get one.

+ +

The commands were sorted by category and abbreviations were used to make it easier for me to fit the shortcut names in the table boxes: + +

    +
  • LEFT-SIDE BUTTON or LEFT-CLICK = LEFTBUT


  • +
  • MIDDLE BUTTON or MIDDLE-CLICK = MIDBUT


  • +
  • RIGHT-SIDE BUTTON or RIGHT-CLICK = RIGHTBUT

    The action of these 3 abbreviations mean: click once



  • +
  • LEFT-CLICK & DRAG = LEFTBUT+DRAG


  • +
  • MIDDLE-CLICK & DRAG = MIDBUT+DRAG


  • +
  • RIGHT-CLICK & DRAG = RIGHTBUT+DRAG

    +The action of these last 3 abbreviations mean: click once, hold down button and drag mouse.


  • +
+ +

Also, as with most applications, the action of the mouse is context-sensitive meaning that the same Mouse shortcut might do a different thing depending in what view you click. This is why the categories below are sorted more by context than type.

+


+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
ActionDescriptionMouse Function
2D view mouse functions
Scroll ViewScroll or pan the 2D view. Also works in the Z view.RIGHTBUT+DRAG
Move Z CheckerMoves the location of the Z Checker box icon in the 2D view to where you click. Dragging the mouse makes it follow around.SHIFT+MIDBUT
SHIFT+MIDBUT+DRAG
Move CameraMoves the location of the Camera eye icon in the 2D view to where you click. Dragging the mouse makes it follow around. Also works in the Z view.CTRL+MIDBUT
CTRL+MIDBUT+DRAG
Point CameraPoints the Camera eye icon in the 2D view to where you click. Dragging the mouse makes it follow around.MIDBUT
MIDBUT+DRAG
Create/Modify BrushThis will create a new brush if no object is currently selected. If one or more brushes are selected, this will:

+1. Resize the brush when click-dragging outside.

+2. Move the brush when click-dragging inside.

+If one or more point entities are currently selected, this will just move them. Also works in the Z view but for brushes, only move and vertical resize are possible. In the 3D view, only move and resize work.
LEFTBUT+DRAG
Select ObjectSelects/Deselects brush or entity under cursor. Entities have priority over brushes. This also works in the Z and 3D views.SHIFT+LEFTBUT
Cycle Select ObjectCycle selects all brushes or entities under cursor in order of depth. This only works in the 2D view in QeRadiant but works in all views in Q3Radiant.SHIFT+ALT+LEFTBUT
Drag Brush FaceDrags the face of the currently selected brush. The face nearest to the cursor is dragged. Brushes can also be sheared by using this. This also works in the 3D view.CTRL+LEFTBUT+DRAG
Entity MenuBrings up the entity pop-up menu. You can then select the entity to create. For solid entities (doors, buttons, triggers, etc.), at least one brush must be selected beforehand.RIGHTBUT
3D view mouse navigation functions
Drive CameraMakes the POV in the 3D view move forward/backwards and turn left/right when mouse is dragged.RIGHTBUT+DRAG
Strafe CameraMakes the POV in the 3D view strafe up/down and sideways when mouse is dragged.CTRL+RIGHTBUT+DRAG
3D view mouse texturing functions
Select Brush FaceSelects brush face under cursor. Only one face at a time can be selected. Will automatically deselect any currently selected objects. Also grabs the face's current texture + alignment + flags into Surf Inspector.CTRL+SHIFT+LEFTBUT
Select Multiple Brush FacesSelects brush faces under cursor. Any number of faces at a time can be selected. Will automatically deselect any currently selected objects. Also grabs the face's current texture + alignment + flags into Surf Inspector. This feature only works in Q3Radiant.CTRL+SHIFT+ALT
+LEFTBUT
Grab TextureGrabs the texture + alignment + flags of the brush face under the cursor into Surf Inspector. Any currently selected face or brushes will automatically be assigned the grabbed values.MIDBUT
Apply Texture To BrushApplies the current texture + alignment + flags in Surf Inspector to the whole brush under the cursor.CTRL+MIDBUT
Apply Texture To FaceApplies the current texture + alignment + flags in Surf Inspector to the single brush face under the cursor. +CTRL+SHIFT+MIDBUT
Apply Texture Only To FaceApplies the current texture in Surf Inspector to the single brush face under the cursor but face retains its current alignment + flags.SHIFT+MIDBUT
Shift TextureShifts the texture's vertical and horizontal alignment on the currently selected face or brushes. This feature only works in QeRadiant.ALT+RIGHTBUT+DRAG
Scale TextureStretches up/down the texture's vertical and horizontal scale on the currently selected face or brushes. This feature only works in QeRadiant.SHIFT+ALT+RIGHTBUT
+DRAG
Rotate TextureRotates the texture on the currently selected face or brushes. This feature only works in QeRadiant.CTRL+ALT+RIGHTBUT
+DRAG
Set Light To Average Texture ColorGrabs the average color of the current texture in Surf Inspector and sets the "_color" key of the light entity under the cursor to that RGB color value. This feature only works in Q3Radiant.SHIFT+MIDBUT
Texture window mouse functions
Select TextureSelects the texture under the cursor and pastes the texture + default flags into Surf Inspector. All currently selected brushes or face will automatically be assigned the selected texture.LEFTBUT
Select Texture + Surf InspectorSame as above but also automatically brings up the Surf Inspector window. This feature only works in QeRadiant but shortcut key does a Apply Texture Angled in Q3Radiant.CTRL+LEFTBUT
Scroll Texture WindowScrolls up/down through the texture window (same as scrollbar or mouse wheel).RIGHTBUT+DRAG
Scroll Texture Window FastSame as above but will scroll much faster. Useful for browsing through very large texture folders.SHIFT+RIGHTBUT+DRAG
Edit ShaderShader window function. Shift-click on a shader opens the proper shader file in EditPad and automatically places the cursor at the beginning of the shader. This feature only works in Q3Radiant.SHIFT+LEFTBUT
Apply Texture AngledAutomatically applies and scales the texture under the cursor on currently selected angled faces so it will fit on those faces by exactly one texture tile. This feature only works in Q3Radiant but shortcut key does a Select Texture + Surf Inspector in QeRadiant.CTRL+LEFTBUT
Entity dialog mouse functions
Create EntityDouble-clicking on an entity name in the dialog's list will create an entity at the location of the currently selected brush (mandatory).

+1. If a point entity is chosen from the list, it will automatically replace the selected brush(es).

+2. If a solid entity is chosen from the list, the selected brush(es) will belong to the entity.

+3. If an entity or nothing is selected beforehand, you will get an error dialog: "Failed to create entity".
DOUBLE-LEFTBUT
+
+
+

Back | Home | Next + + diff --git a/docs/manual/Q3Rad_Manual/ch01/pg1_1.htm b/docs/manual/Q3Rad_Manual/ch01/pg1_1.htm new file mode 100644 index 00000000..0a452022 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch01/pg1_1.htm @@ -0,0 +1,179 @@ + + +Q3Radiant Editor Manual: Page 1.1 + + + +

Q3Radiant Editor Manual

+
+

Preface

+ +The authors would like to thank the many supporters of Quake Engine +editing who made this work possible. Several sections in the manual +are based on material written by dedicated fans. Others were +"corrected" by fans who found undiscovered bugs in both the editor +and game code. Where possible, we have noted the contributors in +the sections they helped produce. + +

Paul Jaquays
+Robert A. Duffy + +

GtkRadiant note: This version of the manual is meant to be distributed with +GtkRadiant. Being for Q3Radiant 192, some parts are very outdated, specially all +the ones dealing with configuration. But the core features (curves and brush +manipulation, texturing) are still very relevant. If you are willing to help +maintaining this version more up to date get in touch with us (http://www.qeradiant.com) +

Note: Chapter 1 has been updated to follow the GTKRadiant 1.2.1. Mainly the preferences menu and some information on this page and appendix E (links and resources). + +

Introduction

+ +Part of the fun of games like Quake III Arena is the ability to add +to your own ideas to a favorite game and then have others play and +enjoy them. While the technical skills needed to create a 3D +graphic engine is beyond many game fans, the skills and equipment +necessary to make modifications to the game are not. It has become +the custom of many game developers to share their development tools +with the public. This allows fans make their own game content. The +Q3Radiant editor is the software used by the designers at id to +create the arenas in Quake III Arena. In fact, it's an +improvement on that editor, since it contains features that have +been added since the game was completed. If you are familiar with +Q3Radiant's immediate ancestor, the QeRadiant editor for +Quake 2, then a good share of what's in this manual will be +old hat to you. Whether you are a veteran mapmaker or new to the +art of making game arenas, we think you will find some +indispensible information in this manual. + +

Now comes the caveat. + +

This manual will tell you how to use the tools, but not +necessarily, how to make what you have in mind. Many fine on-line +tutorial and resource sites will be listed at the end of the +document. + +

Minimum System Requirements

+ +The designers at id used Q3Radiant on some heavy-duty computing +equipment to make their game maps. Despite the fact that Quake III +Arena runs under several different operating systems, not every +computer that can run Quake III Arena will be able to run the +Q3Radiant editor. Q3Radiant only runs under MS Windows 95, MS +Windows 98, MS Windows NT, or MS Windows 2000 operating systems. +There are currently no plans for Mac or Linux versions. The editor +requires an Open GL compliant 3D graphics acceleration card (it is +expected that all cards capable of running Quake III Arena will be +able to handle editor functions … although some may handle +it better). A 3-button mouse gives the best performance. + +

Minimum System

+ +The minimum system requirements generally require that preferences +such as texture quality and screen resolution be set to absolute +minimums. The editor will run on the systems described, but speed +of operation and visual quality will probably be less than +satisfactory. It should also be noted that you would be limited to +working on relatively small maps with limited texture and model +usage. + +

+ + + + + + + + + + + + + + + + + + + + + + + + +
Processor:P233mmx
RAM:64 meg
Video Card:4 Meg, software Open GL-compliant
Screen Resolution:1024 x 768
Pointing Device:Two-button mouse*
+ +

Recommended System

+ +The more powerful the machine, the better and usually faster the +development experience. This will become especially true when you +get to the point of compiling your maps (turning them from editor +code into game code). It should come as no surprise that, more +powerful machines will crunch the numbers faster when compiling a +map. + +

+ + + + + + + + + + + + + + + + + + + + + + + + +
Processor:P2450 (or better)
RAM:128 meg**
Video Card:Open GL accelerated video card
Screen Resolution:1280 x 1024
Pointing Device:Two-button mouse*
+ +

* This will work, but not well. A three-button mouse, even on a +minimal system is highly preferred.
+** id designers often found it convenient to work with several maps +open at once. The recommended 128 Meg of RAM may not be enough to +accommodate this. + +

What Doesn't Work (well) - and How to +fix it

+ +The key to a satisfactory editing experience is whether your video +card supports the demands of the editor. The original id editor was +designed for a workstation card called the Realizm, which ran on +Intergraph workstations in a WinNT environment. Robert Duffy +expanded this to include the Win9x operating systems and a number +of other video cards. But not all video cards support the editor +equally well. + +
    +
  • The G200 and G400 require updated drivers from Matrox
  • + +
  • The 3fx Voodoo 3000 chipset requires a driver upgrade in order +for the map grids to show.
  • + +
  • If the map grids don't appear when using some ATI chip +sets, try turning the settings on you desktop up to 32 bit (true +color).
  • + +
  • Nvidia TNT and GeFORCE have slowdown issues when the user +selects curve patches. While this is a driver issue, it can be +addressed by checking the "Solid selection boxes" +feature under preferences.
  • +
+ +

Back | Home | Next + + + diff --git a/docs/manual/Q3Rad_Manual/ch01/pg1_2.htm b/docs/manual/Q3Rad_Manual/ch01/pg1_2.htm new file mode 100644 index 00000000..95c7bb9a --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch01/pg1_2.htm @@ -0,0 +1,391 @@ + + +Q3Radiant Editor Manual: Page 1.2 + + + +

Q3Radiant Editor Manual

+
+

Installation & Set Up

+Instalation of the editor has changed in the latest build. It is much more simple then before. + +

Installing the editor

+Run the setup file you downloaded of the latest GTKradiant program. You know longer have to install GTKRadiant to the Quake3 directory. It can reside in any directory you would like to have it. + +

Setting up Paths

+During installation you will be asked where your Quake3 game is located. Browse to the folder and select Ok. Then you will be prompted for a directory name for the Quake3 game pak. Setup will create this directory in the Quake3 game directory. +

+You will then be prompted for your Return To Castle Wolfenstein folder. Repeat the same process as you did for Quake3, only this time pointing to your RTCW directory. + +

Improving Performance

+If you find that the editor is sluggish on your system, try some or all of the following tweaks: + +
    +
  • On the View menu, check Cubic Clipping to be ON. This reduces the number of game components in view, by shortening the distance that the editor can "see." Use CTRL + to set the distance to 13 (a good number in this case). +
  • On the Textures menu, open the Render Quality option and select an option higher on the list than your current setting. We recommend not going below Nearest MipMap first. This reduces the amount of blending and filtering in the textures as they are seen in the Camera window, but still lets you see what the textures look like in a relatively undistorted manner. The Nearest setting will further improve performance, but textures may be distorted when seen in perspective. +
  • On View Menu, open the Entities as… option and select an option higher on the list than your current setting. +
  • Select Preferences … from the Edit Menu. Under “Display / 3D View”, deselect (uncheck) “Update XY views during mouse drags.” This will stop the 2D-map window(s) from being repeatedly redrawn during Camera window mouse drags. +
  • Select Preferences … from the Edit Menu. Under “Display / Texturing Settings”, move the slider bar under "Texture Quality" one or more settings to the left, reducing overall texture quality. +
  • Select Preferences - from the Edit Menu. Under “Interface / Editing”, lower the number of “Patch Subdivisions” to a lower number. +
  • Further performance can be gained by turning off curves (CTRL + p) or reducing curve displays to wireframe only. +
+ +

Setting up Preferences

+To set up your editing preferences, open the Edit menu and select Preferences. Use preferences to set a variety of options and editor behavior based on your personal preferences. + + +

Globals +
+Game Settings / Select The Game +
+
+GTKRadiant now stores preferences on a per game basis. For instance: Any settings you set up for Quake3 are stored for that game mode only. Switching to Return To Castle Wolfenstein mode, will use the preferences you setup when that Game mode was set up. + +

Display +
+2D Display +

    +
  • OpenGl Display Lists - Uncheck this option if you encounter any graphic errors. This can some times cuase problems with bad opengl drivers. +
  • OpenGL Antialliased Points and Lines - This will render all points and lines in the 2D view using antialiasing. This can slow down the 2d view if your video card can not handle antialiasing very well. +
  • Solid Selection Boxes - This will make anything selected draw with solid lines rather then the old style of dashed boxes. This can slow down the 2D view as well. +
  • Display Size Info - If this is checked on, it will display the size information of any object selected. +
  • Alternate Vertex Edge Handles - This changes the shape (a little bit) of the vertex and edge points when in either vertex or edge manipulation mode. +
+ +

3D View +
Thanks to some new code. Radiants 3D View is Ultra fast. +

    +
  • Movement Velocity - This will increase or decrease the movement of forward, back, and strafing speed in the 3d view. +
  • Rotational Velocity - This will increase or decrease the turning speed in the 3D View. +
  • Freelook in Camera View - With this checked, you will be able to use free look in the 3D View. Just Right Click in the 3d view to turn on free look, and Shift + Right Click again to turn it off. +
  • Invert Mouse In Freelook - This will reverse the mouse controls in freelook mode. +
  • Discrete Movement - If checked, this cuases the view in the 3d view to move one step at a time. If unchecked the movement is smoother. +
  • Update XY Views On Camera Move - When interacting with the camera (which you will do a lot), turning this off will NOT update the camera icon location in the Map windows automatically. This can help with speed but prevents you from seeing exactly where the camera icon is positioned. +
+ +

Texture Settings +

    +
  • Texture Quality - This will increase or decrease the texture quality displayed in the texture window and 3D View. +
  • Texture Subsets - This provides a texture edit window within the texture window. It is still buggy as of build 188. It puts a text field at the top of the Texture window. Type in the first few letters of a texture name and the window will only display the textures beginning with that letter or letters. +
  • Texture Scrollbar - If checked, this will add a scroll bar to the texture window. +
  • Tex Increment Matches Grid - If checked, this will cuase Radiant to use the grid spacing when moving and aligning textures with the shift + arrow keys. +
  • Default Scale - The default scaling of textures on load up of the editor. +
  • Startup Shaders - You can choose to have certain shaders load upong startup of the editor or to not have any load on startup. +
+ +

Interface +
+Layout +

    +
  • Layout - Choose 1 of 4 layouts. +
      +
    • Split Window View - This is the QeRadiant default view. The Camera, XY Map, Z-axis Scale, Texture, and Console windows are constantly displayed. While the arrangement of the windows cannot be changed, their size is adjustable by pulling the window border splitters. The Entity and Group windows share a common pop-up window. This arrangement is one that may work particularly well for mappers using smaller monitors and slower computers.

      +
    • Floating Window View - This is the view used by id designers. The position, arrangement, and size of the windows are all adjustable. The windows initially come up on top of one another (a known bug), but once positioned, this view offers the greatest flexibility. The Camera, XY Map, Z-axis Scale, and a shared Entity/Texture/Console/Group window are all displayed simultaneously. Changing the size of one window does not automatically affect the others (it can lay atop the others). Additional map layout views can be cycled from menu commands or bound keys. This view only works well if you have a 20+-inch monitor. +

      Make it Big! In floating windows mode (ONLY), you can double-click on any window’s Title Bar to enlarge the contents of the window to fill the screen. Double clicking on it again reduces it back to normal size.

      +

    • Quad View - The display window is split into four equal-sized windows: Camera, XY Map, YZ Map, and XZ Map. This is similar to other editors and offers four-way viewing. You see the map components in three views simultaneously. The size of the windows (relative to each other) can be adjusted, by pulling the splitters. The combined Entity/Texture/Console/Group window is brought into view as a single, floating window that lays over the others. The Z-axis window is not used in this view. This is a popular editing configuration, but it has significant performance issues. The editor is drawing all the 2D map components three times (plus maintaining a camera view). Some mappers have notice significant performance slow-downs when working with curves. Using the Quad view is only recommended for mappers with more powerful computers.

      +
    • Reverse Split Window View - Essentially the same as the Split Window view, except that the windows are all flopped left to right.

      +
    +
  • Floating Z Window - This will make the Z-Window float in the Floating Window View mode. +
  • Patch Toolbar - Seems to have been disabled. +
  • Use Win32 File Load Dialog - If checked, this will use the common windows style file browser. Unchecked it will have the unique GTK / Linux X-Windows file browser. +
+ +Mouse +
    +
  • 2 Button / 3 Button - Use 2 button mode or 3 button mode. Each mode is different in some ways. The hot keys and key combinations are generally different for each mode. +
  • Right Click To Drop Entities - If checked, this will create a menu where ever you click in the 2D View with a list of the entities you can select and place. +
  • Mouse Chaser - Turning this on causes the view to chase the mouse if you drag something off the edge. +
  • Alt + Multi-Drag - If this option is checked, you must hold down the ALT key to drag multiple brush edges. This lets you resize more than one brush at a time. +
  • Wheel Mouse Inc - This number will adjust the amount the texture window scrolls in the texture window when using the mouse wheel. The higher the number, the faster it scroll basically. +
+ +Editing +
    +
  • Vertex Editing Splits Face - This will cuase face splits in brushes when in moving vertex points around and the brush becomes a concave shape. +
  • Fix Target/Targetname Collisions - This prevents duplicate target/targetnames from happening if you load a map into your current map. For instance: if you load q3dm7 into q3dm7, it adds _1 to duplicate target/targetname pairs. +
  • Cliiper Tool Uses Caulk - When using the clipper tool, the faces that are created from the clip will add a cualk texture to the brush. +
  • Dont Clamp Plane Points - This turns off clamping of plane points. This allows for very precise brush/vertex manipulation but can make it difficult to get things properly aligned and can also cause the bsp process to take a LOT longer. In general, this should be unchecked. +
  • Select Patches by Bounding Boxes - If checked, you will be able to select patches by there bounding boxes. Note: Bounding boxes for patches must be turned on. +
  • Rotation Increment - This allows you to choose the increments in pixels a texture is rotated when rotating a texture with the shift + pgup or pgdn keys. +
  • Undo Levels - Set how many undos you can do. This does require memmory so do not set it to high if you do not have alot of memmory. +
  • Patch Subdivisions - Select how many subdivisions are drawn on the patches in all views. If set to high it can slow down the editor. If set very low it will look blocky. Essentially it works like the games r_subdivisions option. +
+ +

Other +
+Startup/Autosave +

    +
  • Snapshots - If checked, this will create snapshots every 5 minutes of your level. They are saved into your maps directory and have a numbered order (eg. .001 .002) for the file extension. +
  • Load Last Project On Open - If checked, GTKRadiant will automatically load the project settings you last used. +
  • Load Last Map On Open - If checked, GTKRadiant will load the last map you had open during your last session. +
  • Auto-Save Every - Here you can choose to use auto saving, and how many minutes between each auto-save. +
+ +Paths +
    +
  • Prefab Path - Here you can choose the directory of where you will have your prefabs ( .pfb ) stored. +
  • Game Path - This is now controlled by GTKRadiant. It displays the path of your game executable for which game mode you are in. +
  • User Ini Path - This will allow you to choose a user .ini file and its path. +
+ +Misc +
    +
  • Light Drawing - This draws lights as shaded triangle things (octahedrons) instead of standard square entities. When enabled, the light entities also show their emitted light color. +
  • Log The Console To radiant.log - This will cuase GTKRadiant to create a log file of all output from the GTKRadiant console. This can cuase the editor to slow down, and is normally used for debugging purposes. +
  • Use Pak/PK3 Files - This will force GTKRadiant to read from .pak or .pk3 files before searching in the game directories like baseq3. +
+ +BSP Monitoring +
    +
  • Enable BSP Process Monitoring - This will have a ms-dos window open when you compile a map from the BSP menu. +
  • Stop Compilation On Leak - This will cuase the bsp compile process to halt when a leak is found in a map during the BSP process. +
  • Run Engine After Compile - This will cuase the game to launch after the compile process is complete. +
  • Activate Sleep Mode When Running The Engine - This is automatic now. GTKRadiant will go into sleep mode when you load the engine after a compile.

    Warning. With some video drivers, it is a bad idea to run Quake 2 or Quake III Arena and the Q3Radiant editor. The drivers just will not sustain two demanding OpenGL applications simultaneously. This feature is best left turned off. + +

+ + + +

The Project File

+The project file contains the paths for the various GTKRadiant file-processing functions. Using the installer to set up the editor should write these for you. + +

New Project +

+
This creates a new folder (which you must name) in your Quake III Arena or RTCW directory. +
This is a good function for mods. You can use a different directory other then baseq3 if you plan to have alot of new resources and dont want to clutter it into the baseq3 folder. + +

Load Project +

+
This opens up a browse directory pointed at the scripts directory. It is looking for a text file with a .qe4 file extension. + +

Changing the Project File +

+
You can edit the project file by changing the pathnames to various functions in field of the dialogue window that pops up. HOWEVER, before doing this, you should make a backup copy of your Quake project file and give it a new name. Make your changes to this new file. If you mess things up, you can always reload the original. This is a good thing to do if you are making maps for a mod that uses a separate set of definitions for entities or directories for textures and want to easily change between types of projects. + +

Project Settings +

    Basepath: This traces a path, beginning in your root directory to the baseq3 where the editor expects to find resources. +

    Mapspath: This traces a path, beginning in your root directory, to the location where maps are saved and from which they are loaded. The default is the maps directory. + + + +

    Rshcmd: This means "remote shell command." Use it only if you are directing a remote processing device (not your editing computer) to compile maps. The syntax for the field is: "rsh [processor name]" + + + +

    Remotebasepath: If you are running your compile from your editing computer, this should be the same as your basepath. If you are working off a remote compling device, this should trace the full path to the to the baseq3 folder where the compiler will find the resources it requires. + + + +

    Entitypath: This traces a path to the definition file for your game entities. This can either be a .c file which contains the game code, or a .def file which contains more instructive information about the entities. +

    Note: As of GTKRadiant 1.2.1 the default path for this is "Radiant", also known as the new game packs style it uses which allows for the remote installation of GTKRadiant anywhere on your computer. + + +

    Texturepath: This traces a path, beginning in your root directory, to the location from which textures are loaded. The default is the textures directory. +

+ + +

Menu commands +
These commands are your map compile commands. You can CHANGE these commands or ADD your own. Each new command must start with “bsp_” The following is the compile command string for “bsp_Fullvis” taken off one of our project files. + +

    ! q3map $ && ! q3map -vis -threads 8 $ && ! q3map -light -threads 8 $
+ +

Command parameters: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + +
!The exclamation mark is replaced by the contents of the rshcmd field. It is the path to the processor.
$The dollar sign is replaced by the Mapspath.
&&The double ampersand is the command terminator (end of command)
q3mapThis is the process command. Without a switch after it, it performs the .bsp compile phase.
-visThis is a switch to select the vis compile phase.
-lightThis is a switch to select the lighting compile phase.
-threadsThis is a switch to break the compile up into a number of different processor threads. The number of processors follows the switch parameter.
+ + +

Other parameters +

+ + + + + + + + + + + + + + + + + + + + +
-onlyentsProcess only the entities in the map.
-fastA quicker process. However, it treats the map as if it were all one vis area.
-extraAs in -light -extra. This is a second lighting pass that more finely subdivides the map into areas of light and shadow.
-nowaterCompiled without liquids in the map. Used in the first compile phase only.
-nocurvesCompiles without curves in the map. Used in the first compile phase only.
+ + +

Misc settings +
Use brush primitives in MAP files. +
Once this is set for a map, the program converts the texture mapping to this format. Once chosen, there is no going back to the old format. Brush primitives are described in detail under the Working with Textures section. + +

Setting up the Windows

+There are six configurable windows in Q3Radiant. + +

The Camera Window (CAM) +
The Camera window initially shows a gray field. This is where the 3D in-progress view of your map appears. You can SHIFT + click mouse button 1 to select objects in this window. If the images in this window appear overly dark, you can adjust the gamma value. Open the Misc menu and select Gamma. Enter a value between 0 and 1 for the light value. Close the program. Reopen the program. Check the darkness. Repeat this until you have a value you like. + +

Entity/Texture/Console/Group Window +
Depending on the Windows layout view that you’ve chosen, one or more of the following sub-windows share this window. They are selectable by the tab at the bottom of the window, or by shortcut keys. + +

Entity Window +

+The Entity window is one of four windows that share the same window space: Console, Entity and Texture and Group. The entity window is used to create and modify the properties of game entities. The uppermost box in this window contains the entity names. Use the scroll bar to find the one you want or for speed, type in the first letter of the class of entity you desire (“w” for weapon, “I” for item and so on). Refer to the Working with Entities section for more details on this. + +

Texture Window +

+The Texture window displays textures that have been loaded from the texture directories for easy use. The texture subset tool (set in preferences) allows you to quickly jump to a texture if you know the first few letters of its name. The scrollbar tool adds normal Windows functionality to the window. The most common method of navigating the window is to right-mouse click and drag through the window contents. SHIFT + right-mouse click and drag speeds up the rate of movement through the window’s contents. A thin green outline around a texture indicates a non-shadered texture in use in the map. A thin white outline indicates a shadered texture. A bold red outline indicates a selected texture. + +

Console Window +

+The console tracks the editor’s processes, like loading, saving, and compiling. When you compile (selecting an option from the bsp menu), the contents of the console are dumped into the junk.txt file in your Temp file folder on your root drive. In the Split Window view layout, the Console window is always in view. + +

Groups Window +

+This window will deal with the future grouping functions that will soon be a part of the editor. At this time, it is only a non-functioning window. + +

Z-axis Scale Window +
This window is used by three of the four views to show the Z-axis position (height) of the Point of View and any selected map components. + +

Map Window(s) +

The Grid +
Think of the Map window as a piece of graph paper, neatly divided into squares. However, unlike graph paper, you can change the size of the grid to fit your needs of the moment. You can change grid size from the Grid menu, but it’s faster to learn the key shortcuts listed below. + +

Setting Grid Size + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Grid sizeKey
1 unit grid(1)
2 unit grid(2)
4 unit grid(3)
8 unit grid(4)
16 unit grid(5)
32 unit grid(6)
64 unit grid(7)
Grid DownDecreases the size of the grid. [ key
Grid UpIncreases the size of the grid. ] key
+ + +

Grid and Window Layouts +
There are four distinct ways of laying out the work windows for Q3Radiant. + +

Design Notes: +
Try not to build architecture with a grid smaller than 8 units. +
Use a smaller grid if you need to build small details. +
Use a large grid (32 or 64) for roughing in a level. +
Use a large grid for moving large chunks of architecture around.
+ +

Snap to Grid +
When this is checked, the edges and vertices of brushes and patches will “snap” to grid coordinates. Unless you are attempting some very fussy maneuvering of a map component, Snap to Grid makes life much easier. In fact, if you are building objects out of curve patches, it is crucial that you be able to line up patch control points with the vertices of surrounding solid geometry brushes. + +

Colors +
Q3Radiant allows you to select the colors of your grids and tools. Because the manual refers to the colors of some features, you may wish to wait until you are more comfortable using the editor before changing too many things. You can always revert to the Q3Radiant defaults, should you choose change too much. + +

To change Map window and Texture window colors, select the “Misc” menu and choose colors. The pop-up lists a number of options. + +

Themes +
Brings up three options: + +

    QE4 Original: The settings for id’s original Quake 2 editor +
    Q3Radiant Original: The default setting. +
    Black & Green: a black background with a green grid major. +
+ +

Each of the following options opens the Windows color selector. + +

Grid Background… +
The background color for the map window. + +

Texture Background… +
The background color behind the textures in the texture window. This is probably best left a neutral color. + +

Grid Major… +
These bolder grid lines mark 64 unit increments in the map window. These never change. + +

Grid Minor… +
The finer grid lines in the map window. + +

Grid Text… +
The color of the scale numbers along the left and top of the map window. + +

Grid Blocks… +
These lines mark the 1024 x 1024 unit grids on the map. + +

Default Brush… +
This is the color of unselected brushes in the map. + +

Selected Brush… +
The color of selected brushes in the map. + +

Active View Name… +
This is the text that says “XY Top” or “YZ Side” or “XZ Front” in the map view window(s). + + + +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch02/pg2_1.htm b/docs/manual/Q3Rad_Manual/ch02/pg2_1.htm new file mode 100644 index 00000000..758469fd --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch02/pg2_1.htm @@ -0,0 +1,213 @@ + + +Q3Radiant Editor Manual: Page 2.1 + + + +

Q3Radiant Editor Manual

+
+

Entities and Assets

+

What are Entities?

+Quake III Arena divides map components into two classes: World Geometry and Entities. World Geometry represents the brushes (the Q3A term for the blocks of geometry used to build the physical game world) and patches (anything built with calculated curves). Entities are a broad category that not only includes simplistic editor representations of game play objects like weapons and ammo, but also includes diverse things like player start spots, and lights. Typically, they are displayed as brightly colored cubes (for those entities not constructed of brushes). The following are the general category of entity types. The actual entities and the rules and tips for their use are listed in Appendix B. + +

Brush entities. The “brush” is the basic building block of Quake engine games (including Quake, Quake 2, Quake III Arena, and a host of games using the engine licenses). In its most basic form, it’s a block, a solid rectangular volume defined by the coordinates of its corner vertices. A single brush or a linked grouping of brushes can be turned into a brush entity. Brush entities include the movers (see below), triggers, and func_statics. + +

Movers. Most moving objects or "Movers" are built from brushes. These include doors, lifts or “plats”, rotating objects, buttons, pendulums and trains (objects following pre-defined paths), and bobbers (platforms that are constantly in motion, up and down or side to side). + +

Triggers. Triggers are brush entities that cause an event to occur when a player’s bounding box moves inside the volume of the trigger. Triggers can be targeted on many other entities, including most movers and targets. Some triggers also have more specialized functions. There are triggers that cause injury, activate other entities, and push or teleport the players. + +

Targets. Targets are the entities that are activated to cause events to happen in Q3A, or to redirect activations, insert time delays, mark locations for team play, or act as destination points for teleportation or pushing. + +

Lights. These are point lights, disembodied (read as no visible source) sources of illumination. They ca n be targeted at info_nulls to create spotlights. They can be turned into colored lights. Usually, they are used to create unfocused fill light in a large area or placed near glowing surface textures to create an effect. + +

Info. This category includes non-team player spawn spots, targets for lights, and camera locators for intermission shots. + +

Items. With the exception of ammo and weapons, these are things in the map that the players grab to use during play. Included are armor, power ups like the quad, and one-use items like the personal teleporter. + +

Ammo. Locations for ammo boxes. Each weapon type in Q3A has its own unique ammo entity. + +

Weapons. Each of the weapons that can be picked up has an entity that can be placed. + +

Miscellaneous. This is another catchall category. It includes things like the misc_model which links into the models directory when placed, func_timers which are automated repeating triggers, shooters which fire one of three different weapon fire types, camera and portal surfaces, and path corners. + +

What are Assets?

+Assets are the textures, sounds, and models that are used to flesh out the appearance and ambience of a game map. The editor is designed to use the assets stored in the pak0.pk3 file in your quake3 directory. Using Q3Radiant, the mapmaker can work with the assets in the Quake III Arena pak0.pk3 file or create new ones. + +

What are Textures? +
The art appearing on the walls of maps are generally referred to as “textures.” Textures are created and stored as true color targa (.tga) or jpeg (.jpg) graphic files. The textures do not use a pre-defined color palette (as was the case with both Quake and Quake 2). Shader scripts can further combine textures and/or modify them in numerous ways. This document will briefly touch on shaders. For an in-depth treatment of shaders, refer to the accompanying Shader Manual. + +

What are Sounds? +
Quake III Arena world sounds are played by target_speaker entities in the maps. They are stored as 22 khz, 16-bit, mono format .wav files. + +

What are Models? +
The statues and lights in Q3A are models, just like the player characters. They are placed with the misc_model entity. + +

Creating New Assets

+If you are familiar with the required tools, creating new assets for use in Quake III Arena is not particularly difficult. As a rule, you should create new directories for each map with names different from the names used by id. If you are making a map that will be called “H4x0r_D00M”, every directory containing new assets for that map should be titled H4x0r_D00M. This is to try and avoid asset directories overwriting each other as the editor and the game load in assets. + +

Creating Textures +
Any combination of graphic programs and plug-ins that can output a 24 bit MS windows compatible Targa (.tga) or JPEG (.jpg) graphic file. If you plan to make textures that will have an alpha channel component (see glossary for definition), you must have a program that can create 32-bit art with that fourth channel. + +

Adobe PhotoShop has the ability to easily create alpha channels. Paint Shop Pro from JASC (v5.0+) can also make an alpha channel by creating a mask and naming it “alpha”. + +

Generally speaking, regardless of the program used, we found it best to do most of the art manipulation of the alpha channel in a separate layer or file and then paste it into the alpha channel before saving. + +

Setting up Files +
The editor and the game program look for assets to be located along the paths set up in your project file. Start by creating a directory for you new textures by creating file folders to make a directory path as follows: quake3\baseq3\textures\[mymapname] + +

The installation of Q3Radiant will create a text document called “shaderlist.txt” in the following path: + +

    Quake3\baseq3\scripts\shaderlist.txt
+ +

Q3Radiant will use the contents of this script to grab your new textures for inclusion in the game. The contents of shaderlist.txt document will contain a listing of all the shader documents that were used by id Software to create Quake III Arena. + +

Since you will obviously want to create your own shaders, you need to put them in separate folders and create a new shader script for them. + +

If you plan to work on several maps at once and want to distinguish between textures used in each map, simply add additional map names here. For map and mod makers, we STRONGLY recommend that any new shader scripts created use the name of the map or mod in the shader file name. We know we can’t avoid every incident of files overwriting each other, but we certainly can advise you how to try. + +

Now, create another text file within the scripts directory and call it: + +

    [mymapname].shader
+ + + +

This file will contain the shader scripts you write to modify a particular texture. + + + +

Rules +
Follow these rules when creating textures for the Quake III Arena engine: +

    +
  • Save your textures into your new [map name] directories. +
  • Don’t use the same names that id used for textures. It will cause problems. +
  • For best quality, save textures without an alpha channel as 24 bit TARGA files. Using JPEG files can save memory space, but at the risk of losing detail and depth in the texture. JPEG files cannot be used for textures requiring an alpha channel. +
  • Textures containing an alpha channel must be saved as 32 bit TARGA files. +
  • If a new texture requires no further manipulation, it does not need a shader script. +
  • Size textures in powers of 2. Example: 8x8, 16x16, 32x32, 64x64 pixels and so on. +
  • Textures don’t need to be square. A 32x256-pixel texture is perfectly acceptable. +
+ +

Guidelines +
The following are some things the id designers learned about textures. +

    +
  • Create textures in “suites” built around one or two large textures with a number of much smaller supporting detail or accent textures. +
  • Very large textures are possible, but some video cards compress textures larger than 256x256 pixels. +
  • Textures are grouped alphabetically by name in the texture display window, so you may want to give suites of textures similar names. +
  • Use the shader function qe3_editorimage to conserve memory when making multiple versions of a single texture (as in the case of a glowing texture with several light values). +
  • Unless you are creating special effects or textures designed to draw the player’s eye to a specific spot, muted, middle value colors work best with the game engine. +
  • Extremely busy (a lot of fussy detail) textures can break up or form visually unpleasant patterns when seen at distances. +
+ +

Creating Sounds +
Tools needed: Any sound editing program that can create and save out sound files as 22 khz, 16-bit, mono format .wav files. + +

Set up: The editor and the game program look for assets to be located along the paths set up in your project file. Start by creating a directory for you new textures by creating file folders to make a directory path as follows: quake3\baseq3\sounds\world\[map name] + +

Place your completed .wav files in the [map name] folder. You can access (and play) this file from within the editor (see instructions for Target_Speaker). + +

Creating Models +
Map models need to be converted from their native file format into Quake III Arena’s native md3 file format. The modeling program, Milkshape 3D supports the file format needed to create map models for Quake III Arena (a link for this program is in the On-line Resources appendix). The compiling process merges the models into the bsp file. If you want other mappers to be able to use your models, you will need to include the md3 and supporting texture files within your pk3. + +

Making the .pk3 File

+When you go to distribute your creation to the gaming world, you need to put your newly created map, textures, bot area files, and shader documents into an archive format called a “pk3” file. You do not need to include the shaderlist.txt file, since only the Q3Radiant editor uses that. Start by creating folders/directories in your root drive (C: for most of us). The game assumes that these folders are placed in the baseq3 directory, so you need to write your path names accordingly. You will need to keep the paths to the various assets the same as they are for the rest of the assets in the game. So your paths should be something like this: + +
    Textures: textures/[mymapnamefolder] + +
    New Models: models/mapobjects/[mymodelnamefolder] + +
    Map, bsp & aas: maps/mymapname.bsp , mymapname.aas + +
    Shader scripts: scripts/mymapname.shader + +
    Server scripts: scripts/mymapname.arena +
+ + +

Move or copy all your new game assets in their folders. + + + +

We used an archiving program call Winzip to make the pk3 file. Get Winzip from WinZip.com + +

NOTE: Do not include or redistribute any game assets that are not your own (at least without permission). This specifically refers to id-copyrighted material that came with the original game or subsequent id released patches. + +

Make a zip archive called “map-mymapname.zip” + + + +

If you plan on distributing other resources separately, we strongly recommend the following naming conventions: + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
md3-xxx.pk3User Model with original associated skin files and sound files
bot-xxx.pk3User bot files. May contain additional model or skin and texture files
skin-xxx.pk3User skin with associated skin and texture files
map-xxx.pk3User created map(s) and supporting files (arena, texture, sound, music)
tex-xxx.pk3User texture and shader files
snd-xxx.pk3Sounds only
mus-xxx.pk3Music only
pfb-xxx.pk3Map prefabs
+ + +

(special thanks to Rogue13 of http://www.polycount.com for this naming convention) + + + +

When you go to add a resource to the archive, click on options to “Recurse Folders” and “Save Extra Folder Info” + + + +

Zip all the required assets into a zip archive file (Quake III Arena DOES support compressed pk3 files). + + + +

Rename the zip archive to mymapname.pk3 + + + +

Put it where the Quake III Arena community can find it. + + + +

My .pk3 File is Huge! No One is downloading it! +
Large pak files are daunting as downloads. And as specified by the Quake III Arena End User License Agreement, that is the only way those new game assets may be distributed. Be kind and remember that not everyone has access to DSL, ADSL, ISDN, Satellite, Cable Modem or other high speed internet connections. Before packing up your resources, you may want to look into some dieting tricks to make it smaller. + + + +

    +
  • First, resave all your new non-alpha channel textures in JPG format. That will give you some significant art size savings. +
  • Streamline your map’s art package. Id designers had to go on a rip ‘n strip rampage through their levels to cut down on unique texture usage. Do you really need all that additional art? Can you substitute more of the original Q3A art, or get more duty out of some of your new work? +
  • Recompile your area files with the optomize switch. That will reduce their size. That's why it's in there as a command. This is also one of the biggest savings that you can make. +
  • Turn up the level of compression when archiving into the pk3 file. +
  • Compress again when zipping up the files. +
  • Take a SERIOUS look at any new sound resources you've created. Sounds, especially long sounds can be HUGE! Can short sounds be cleverly used to replace longer sounds in your map? The id designers did a bunch of that for Q3A. Very short sounds, played off sync against each other were made to sound like longer, more expensive sound files. +
+ +

Back | Home | Next + + diff --git a/docs/manual/Q3Rad_Manual/ch03/pg3_1.htm b/docs/manual/Q3Rad_Manual/ch03/pg3_1.htm new file mode 100644 index 00000000..91bbb4c5 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch03/pg3_1.htm @@ -0,0 +1,265 @@ + + +Q3Radiant Editor Manual: Page 3.1 + + + +

Q3Radiant Editor Manual

+
+

Map Building Basics

+Once you have the editor installed and the preferences set, open the map and let’s get started. + +

Moving Around

+There are a number of ways to move your point of view around in the map and camera windows. Some are easy to master. Others are a bit trickier. Find one that works for you and master it. + + +

Moving in All Directions +
All movement directions are given relative to directions in the XY map. When other map views are shown, movement is still calculated in terms of the XY view. Key press movement occurs in discrete increments. + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Forward (in facing direction)(Up Arrow Key) or (Keypad 8)
Turn left(Left Arrow Key) or (Keypad 4)
Turn right(Right Arrow Key) or (Keypad 6)
Backward(Down Arrow Key) or (Keypad 2)
Move up(D)
Move down(C)
Look up(A)
Look down(Z)
Level View(END)
+ +

Flying … through the Map (and other 3D commands) +
Some mappers prefer using mouse-fly to move around their map. Mousefly works by clicking and pressing with the Mouse button 2 (Right mouse button) on the Camera window. This takes a lot of practice to master. Clicking farther away from the window center increases the speed of movement. + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Forward (in facing direction)(Right Mouse click above of window center)
Turn left(Right Mouse click left of window center)
Turn right(Right Mouse click right window center)
Backward(Right Mouse click below window center)
Move up(D)
Move down(C)
Look up(A)
Look down(Z)
Level View(END)
+ +

Zoom with a View +
The zoom keys increase or decrease the visual scale of the map, letting you move in close to work with small details or move away to see the entire map at once. Currently, there are 24 steps of zoom, from most distant to closest. If Quad view is used (XY, YZ, and XZ views simultaneously), all three windows may zoomed at different scales. The Z-axis scale window is also zoomed separately + + + +

Zoom in +
(DELETE) + + + +

Zoom out +
(INSERT) + + + +

Z-axis Zoom in +
(CTRL + DELETE) + + + +

Z-axis Zoom out +
(CTRL + INSERT) + + + +

Jump to Location +
(CTRL + Middle Mouse Button) + +
Click on a 2D map or the Z-axis window and your point of view immediately moves to that location. In the 2D map windows, neither the facing, nor the “height” of the point of view changes. + + + +

Moving the Maps Around +
A right-mouse-button click and drag on a 2D Map window will cause the map to be dragged, allowing you to easily reposition what is being viewed. + + + +

Basic Construction Tutorial

+ + +This is a simple, step-by-step guide to making your first room. Before attempting it, you may want to familiarize yourself with some of the Brush selecting and handling tools. A Quake III Arena aficionado who goes by the handle “The Dog!” posted this simple tutorial on a Quake III Arena on-line message board. It appears here with his permission. It will walk you through creating a new map file, making your first “brush,” adding a start spot and a light and then compiling the map. + +

The Dog!’s Ten Quick-n-Dirty steps to a SIMPLE room: + + +

  1. Create new map: + + +
    1. Click file, new map
    + + + +

  2. Create a small hollow room (make a box and hollow it out): + + +
    1. Make a box. In the XY Top window, click/hold your left mouse button at coordinates 256,-256 (upper left) - then drag your mouse to the -256,256 (lower right) [you should see a red square appear in grid]. + + + +

    2. Make the box taller. In the Z Window (this is also called the height bar): This brush appears as a red box. Click/hold your left mouse button above the upper edge of the box and drag that bar up to about 256. [you have just raised the height of the box] + + + +

    3. Make it hollow. On your Toolbar below the Menu bar, locate the 'Make Hollow' Button (should be a red box with a dotted box inside of it )located under the M in Misc). Press that button. This breaks the box up into six pieces: four walls, a ceiling and a floor. [you should now see a hollow room in the texture view window] +
    + + +

  3. Press Escape to deselect the box (you are finished with room/box for now). + + + +

  4. Add a player starting point: + + + +
    1. Bring up the Easy Entity Menu. With your pointer over the room in the XY Top window, right mouse click INSIDE the newly created room box to open up the easy entity menu. + + + +

    2. Place a Start Spot. Select info, then select info_player_deathmatch. [you should see a small pink box appear - this is where you will start in this map anytime its loaded] + + + +

    3. Is it in there? Make sure that your new starting point is 'really inside' the room that you have created. + + + +
      1. Click the xyz button on your toolbar so that you can toggle through each 'view' of that coordinate (XY top, XZ front, or YZ side). + + + +

      2. Watch the red box (info_player_deathmatch) as you toggle through each view to make sure the red box is inside room + + + +

      3. If there is a view it is not located inside - simply stop and drag it inside the box. (You can learn how to put it in optimal places later), until it is totally inside the room. +
      +
    + +

  5. Press Escape to deselect the info_player_deathmatch item. + +
    The box now turns into a solid pink, box outline. + + + +

  6. Now add some textures: + + + +
    1. Load up Textures. Click on the texture menu and drag down to select the gothic_wall texture directory. + +
    2. Open Texture window. Press “T” to open the texture window. It should be full of wall textures. + +
    3. That wall will do just fine. Then decide what wall surface you want to apply the texture to. Hold the left-CTRL and the left-SHIFT key down and then left click on a wall. The wall will turn red. + +
    4. Pick a Texture, any Texture. in the 'texture view' window, left mouse click on any wall texture. A red border will now surround this texture. And presto, the wall becomes that texture too. + +
    5. Repeat this step for all the walls that you want to apply textures to. +
    + + + +

  7. Save your map. +
    The editor doesn’t like to work with “unnamed” map files. From the menu, select File > Save. Name the map “test1”. Always use lower case for your map names. + + + +

  8. Add a light. + +
    1. Bring up the Easy Entity Menu Again. With your pointer over the room in the XY Top window, right-mouse-click INSIDE the newly created room box to open up the easy entity menu. + + + +
    2. Place a Light. Select info, and then select light. [You should see a small red box appear (smaller than the player start).] + +
    3. Move it into place. Do the same procedure you did for the player start spot, making sure that this light is inside the room. + +
    4. Deselect the light. It will become a green box. +
    + + + +

  9. Compile it. +
    In the BSP menu, select “bsp_fastvis”. Wait patiently for the program to finish three phases of compile: bsp, vis, light. + + + +

  10. Start ‘er up. +
    Start your Quake III Arena game. When the menu appears, hit the tilda key (~). On most American keyboards, this is in the upper left corner of the keyboard, below ESC. + +
      +
    1. Set your game to run the map. In the console, type "/sv_pure 0" +
    2. Enter the Devmap. In the console, type “\devmap test1” and then ENTER. +
    3. Play it for all it’s worth. The map should start and you will be standing in the center of your first room. +
    +
+ + + +

Now go make something more complicated on your own! + +

Back | Home | Next + + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch04/pg4_1.htm b/docs/manual/Q3Rad_Manual/ch04/pg4_1.htm new file mode 100644 index 00000000..94575ba3 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch04/pg4_1.htm @@ -0,0 +1,174 @@ + + +Q3Radiant Editor Manual: Page 4.1 + + + +

Q3Radiant Editor Manual

+
+

Tools 1: Selecting and deselecting

+The most basic interaction with the editor is selecting and deselecting the map components. Everything else builds off from these commands. + + + +

The Component Handling Tools

+
Escape (ESC)
+This is the all-purpose deselect key. Use it to back out of operations you don’t want to complete or to stop working on a map component or group of components. + + + +

Select single component
+ + +In the XY Window (or XZ or YZ), this selects a single map component that is “closest” to the top of all components beneath the pointer. The following is an exception: If an entity is directly beneath the pointer, it will be chosen in preference to a non-entity, even if the non-entity is “between” it and the pointer. + + + +

Select single face on brush
+ + +This selects a single face on one brush, not the brush itself. + + + +

Select multiple faces on one or more brushes
+ +Use this to select several brush faces on one or more brushes. + +

Cycle through stacked components
+ +Beginning with the component that has the greatest Z value, the user can cycle through vertically stacked components that are directly beneath the mouse pointer. + + + +

Deselect single component
+ +In the XY Window (or XZ or YZ), SHIFT clicking on a selected component deselects it. The following is an exception: If a selected entity is directly beneath the pointer, it will be chosen and deselected in preference to a non-entity, even if the non-entity is “between” it and the pointer. + + +

Deselect all selected components
+ + +All selected components are deselected. + + + +

Group Component Selections

+There are four commands for selecting large groups of components. These involve creating a brush that encloses or touches numerous other components. In most cases, the brush used to create the grouping is deleted by the operation. These operations can be selected by menu commands or by buttons on the toolbar. The toolbar buttons are in the third grouping (as counted from the left). The command buttons on the toolbar are given as they relate to the Selection sub-grouping on the toolbar. + + + +

Design Note: These grouping commands are particularly useful when you want to region off a small area of the map.
+ +

Select Complete Tall
+ +All brushes from the top to the bottom of the map that are totally enclosed within the XY dimensions of the grouping brush will be selected. The grouping brush is discarded. + + + +

WARNING: Undo will restore selected components but will delete the selection brush. + + + +

Select Touching
+ +All brushes that are in contact with the grouping brush will be selected. The grouping brush is NOT discarded. + + + +

Design Tip: Need to work an area around a particular brush? Use this tool to select the brush and then use the selected brushes to create a regioned area.
+ + + +

Select Partial Tall
+ +All brushes from the top to the bottom of the map that are touched by the XY dimensions of the grouping brush will be selected. The grouping brush is discarded. + + + +

Select Inside
+ +All brushes from the top to the bottom of the map that are totally enclosed by the XY and Z dimensions of the grouping brush will be selected. The grouping brush is discarded. + +

Copying, Pasting, Cloning, Deleting and Prefabs

+
Save Selected
+(Menu: File) +
The selected brushes are saved as a map file. Not a true prefab, but a way to duplicate pieces of a map for later insertion. + +

Copy brush
+(Menu: Edit) +
(CTRL+C) +
This function copies all hi-lighted brushes, patches, and entities onto clipboard. Contents of clipboard may be pasted into the current open map file or into another open map file. + +

Paste brush
+(Menu: Edit) +
(CTRL+V) +
The map information previously copied into the clipboard is pasted at the same XYZ coordinates as the original. UNDO will delete the paste + +

Clone
+(Menu: Selection > Clone) +
(Shortcut: SPACE) +
Selected map components are immediately duplicated. The clone appears +1x and -1y units (current map grid) away from the original (down and to the right). The clone remains hi-lighted until deselected. + +

Save Selection as Prefab
+(Menu: EditèSave Selection as Prefab) +
(Shortcut: none) +
The user is prompted to save the selected map components as a prefab file (*.pfb) in the directory set by Preferences. + + +

Load Prefab
+(Menu: EditèLoad Prefab) +
(Shortcut: none) +
Opens a file selection window into the directory set in Preferences. Select from that directory or browse for another. The selected prefab is pasted into the map at the same XYZ coordinates as the original. + +

Delete
+(Menu: Selection > Delete) +
(Shortcut: BACKSPACE) +
All selected map components are removed from the map. + +

Undo
+(Menu: Edit > Undo) +
(Shortcut: none) +
Undo will undo recent command actions affecting brush geometry, curve patches, and in-map comands that affect entities (move, rotate, delete, etc.). Undo has no effect on texture operations. + +

The number of levels or layers of Undo can be set in Preferences. The maximum number is 64. Unless your computer memory is extremely low, there is no real reason to use less than all 64 levels of Undo. + +

Working with Regions

+Regions are an important tool to learn and use early on. Whether you isolate off a single brush, or half a map, you’ll wonder how you ever got along without this tool in other editing programs. The selections on the Region Menu allow the mapper to isolate, and work on, a subset of the map. There are innumerable benefits to working in a “regioned” area of the map. However, the following are the most important: +
    +
  • It allows you to work with a few map components at a time, without the distraction of the rest of the map pieces. +
  • When you want to perform CSG operations, regioning lets you isolate the pieces from the rest of the map, reducing risk of making unwanted cuts or splits. +
  • Map regions can be compiled without having to compile the rest of the map. This can be an incredible timesaver. Instead of spending hours to compile an entire map just to check for leaks in new construction, or check the appearance of a room, or test a lighting effect, minutes can be spent processing just the room itself. +
+ +

There are several ways to select a region, by a group selection, by XY map window dimensions (or the corresponding view in YZ and XZ), or by a few selected map components. + +

The commands for selecting regioned areas are found under the Region Menu heading. + +

Region Menu
+Off + +This returns you back to the full map. Brushes that were selected while in the regioned mode remain selected until ESC is pressed to unselect them. + +

Set XY +

+Any map components that are inside, or that are touched by the bounds of the XY Map window are converted into a region. The size or shape of the window does not matter. Nor does the degree of Zoom matter. This is an excellent way to select are larger subset of your map, such as a complex room or group of rooms. Any brushes selected before regioning the map remain selected. + +

Set Tall Brush +

+This functions in a similar manner to the group selection command, Select Partial Tall. Any map components contained within the XY bounds, or touching the XY bounds of the brush will be regioned off. The selecting brush itself is discarded. + +

Set Brush +

+This functions in a similar manner to the group selection command, Select Touching. Any map components contained within the XYZ bounds of the brush, or touching the XYZ bounds of the brush will be regioned off. The selecting brush itself is discarded. + +

Set Selected Brushes +

+If you need to work with just a few brushes, this is the option to choose. Hi-light the brushes to be worked upon then select this option. Only those brushes are moved to the region. The selected brushes are unselected when the region is created. + +

Compiling Notes: Sometimes, when compiling a regioned area, md3 map object models near the edge of the region can cause a “false leak” situation to occur. This can usually be corrected by adjusting the region size to include more of the map near the md3 map object model. + +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch05/pg5_1.htm b/docs/manual/Q3Rad_Manual/ch05/pg5_1.htm new file mode 100644 index 00000000..ec02e30a --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch05/pg5_1.htm @@ -0,0 +1,784 @@ + + +Q3Radiant Editor Manual: Page 5.1 + + + +

Q3Radiant Editor Manual

+
+

Tools 2: Working with Brushes

+ +

The geometry brushes are the basic building block of the Quake +III Arena engine. These are the tools to make them work for +you. + +

Geometry Brush Handling Tools

+
Escape (ESC)
+This is the all-purpose deselect key. Use it to back out of +operations you don't want to complete or to stop working on a brush +or group of brushes. + +

Create New Brush
+ + + +While mouse1 clicking over the main map window (or any open map +window) drag the mouse pointer across the grid. A brush will be +created that has the height of the current map grid size. If you +have the "snap to grid" function set in your preferences, the brush +will start and stop on gridlines. The texture will be either the +default texture (if none has been selected) or the most recently +used texture. For all these functions, you will first need to +select a brush in either the Map or Camera windows. + +

Move Geometry Brush
+ + + +The Undo command will return the brush to its original size (if +the brush is still selected). If the brush has been deselected, the +resized version will remain and another brush will be created at +full size. + +
    In the Map Window. In the map window, select the +brush. Click on the selected brush. With the mouse 1 button +depressed move the brush around the map to the position you +desire. + +
    In the Z (height) Window. In the map window, select the +brush. Next, click on the selected brush in the Z window. With the +mouse 1 button depressed move the brush around the map to the +position you desire. + +
    In the Camera Window. Select a brush in the camera +window (see select single component above). +Mouse button 1 click on the brush and drag it in the desired +direction. You may need to adjust your camera view to make dragging +easier.
+ +

Stretching the Brush
+ + + +Think of this as stretching the brush. The Undo command will +return the brush to its original size (if the brush is still +selected). If the brush has been deselected, the resized version +will remain and another brush will be created at full size. + +
    In the Map Window. In the map window, click next to the +selected brush on the side you want to pull. With the mouse 1 +button depressed pull in a direction away from the nearest edge. +The brush will grow larger in that direction. + +
    In the Z (height) Window. Use this to make the +brush taller. In the Map or Camera window, select the brush. +Next, click above or below the selected brush in the Z window. With +the mouse 1 button depressed pull away from the select brush. The +brush will grow in that direction. + +
    In the Camera Window. Select a brush in the camera +window (see select single component above). +Mouse1 click near the edge of the selected brush. With the mouse 1 +button depressed pull in a direction away from the nearest edge. +The brush will grow larger in that direction. You may need to +adjust your camera view to make dragging easier.
+ +

Shrinking the Brush
+ +Think of this as crunching the brush smaller. + +
    In the Map Window: In the map window, select the +brush. Click next to the selected brush on the side you want +to pull. With the mouse 1 button depressed pull in a direction +toward the nearest edge. The brush will shrink in that +direction. + +
    In the Z (height) Window: Use this to make the brush +shorter. In the Map or Camera window, select the brush. Next, +click above or below the selected brush in the Z window. With the +mouse button 1 depressed, push towards the select brush. The brush +will shrink in that direction. + +
    In the Camera Window: Select a brush in the camera window +(see select single component above). Mouse1 +click near the edge of the selected brush. With the mouse 1 button +depressed push in a direction towards the nearest edge. The brush +will grow larger in that direction. You may need to adjust your +camera view to make dragging easier.
+ +

Flip Brush
+ + + +There are three separate actions here. They flip a brush +along either X, Y, or Z-axes. A menu command and toolbar button +controls each. The six flip and rotate toolbar commands are the +second grouping (from the left) on the toolbar. The rotate +command for the same axis is always next to the flip command. +Flipping will not change the facing on non-model entities. + +
    Flip X (Menu: Selection) (Toolbar: Leftmost button) + +
    + +Flips brush along x-axis. + +
    + +Flip Y (Menu: Selection) (Toolbar: left of center +button) + +
    + +Flips brush along y-axis. + +
    Flip Z (Menu: Selection) (Toolbar: second button from the +right) + +
    + +Flips brush along z-axis.
+ +

Rotate Brush
+ + +There are three separate actions here. They rotate a brush +in 90 degree increments around a brush's X, Y, or Z axes. Both a +menu command and toolbar button controls each action. The six flip +and rotate toolbar commands are the second grouping (from the left) +on the toolbar. The flip command for the same axis is always next +to the rotate command for the same axis. The rotation will not +change the facing on non-model entities. + +
    + +Rotate X + + +Rotates brush around the x-axis. + +
    + +Rotate Y + + + +Rotates brush around the y-axis. + +
    Rotate Z + + +Rotates brush around the Z-axis.
+ +

Arbitrary Rotation
+ +The Rotate commands accessed from the toolbar all rotate +affected map components 90 degrees; no more, no less. Arbitrary +Rotation allows the user to set angles individually for the X, Y, +and/or Z-axes. Enter a number value for each axis you want to +rotate. Value can be positive or negative. After the values are +entered, select OK. This rotates the object and closes the pop-up +window. If you don't like the rotation, you can use Undo, so long +as the brush is still selected, and the brush will return to its +un-manipulated facing. + +

Free Rotate in Map Window
+ +Press the "R" key. The selected map component(s) turns lavender. +The purple square at the center is the center of the selection and +the axis around which it will rotate. Left Mouse clicking on or +near the selected component (in the map or camera window) and +dragging will cause it to rotate. If the user does a SHIFT + middle +mouse button click on the 2D map window, the axis square will +relocate to the coordinates of the click. Deselecting and +reselecting the component returns the axis to its original +center. + +

Drag
+ +There are two "drag" functions that involve control points or +"handles" on the brush. + +
    Drag Edges + + + +This highlights the edges of a geometry brush, marking those +edges with a blue "handle" box at the center of each side. Press +again and the feature will toggle off. Pull on a handle to resize +part of a brush. If Snap-to-Grid is active (Menu: Grid), the +handle will snap to the nearest grid coordinate as it is pulled. +Undo functions with this effect. + +
    Drag Vertices + + + +This highlights the corner vertices of a geometry brush, marking +those corners with a green "handle" box where the sides of each +brush face connect. Press again and the feature will toggle off. +Pull on a handle to resize part of a brush. If Snap-to-Grid +is active (Menu: Grid), the handle will usually snap to the nearest +grid coordinate as it is pulled. Undo does NOT function with this +effect.
+ +

Design Note: Drag Vertices is a balky tool at best. It +works well if the user is manipulating a triangular brush face, +raising or lowering corners of the triangle. Work with care, it is +quite easy to pull a brush out of useable (or recoverable) +shape.
+ +

Scale
+ + + +With Scale you can enlarge or reduce a brush, patch, or group of +brushes and patches. You choose the axes to scale (X, Y, or Z) and +the factor of the scale. The scaling factor can be different for +each axis. Selecting this option brings up a tool window. The size +of the brush or group of brushes is multiplied by the numbers in +the boxes adjacent to the X, Y, or Z axes. Leave the value as 1 and +no change occurs. If the value is a decimal less than one, the size +of that axis shrinks. If the value is greater than 1, it grows. Hit +OK to activate the scaling function with you chosen values. Undo +functions with this effect. + +

CSG Operations
+ +CSG stands for "Constructive Solid Geometry". The two +functions here, CSG Subtract and Make +Hollow, calculate the removing of sections from that +geometry and breaking solid brushes (not curve patches) into +smaller pieces. Although they are convenient to use for some +operations, they often do things that the user may not care for. +These "side effects" can include breaking brushes into inconvenient +parts, cutting up adjacent brushes, and creating hard to find and +remove micro brushes. + +

Subtract +

+When you select this, the selected brush or brushes subtract its +volume from all the geometry that contacts it. The cutting brush is +not removed. Undo does not fix this action. + +

Design Note: Region off together the brushes that will be +cut and the brushes which will be used for cutting. This keeps +other brushes in the map from being affected by the action. It's +also a good idea to save just before doing the action, so the user +can "back up" to an earlier version.
+ +

Hollow + +

+ +When the user selects this, the sides of the highlighted brush +are turned into separate brushes. The thickness of these brushes is +equal to the grid size. Undo functions with this action. + +

Design Note: This works best with rectangular +brushes. The edges of the created brushes overlap each +other.
+ +

Merge +

+When the user selects this, the highlighted brushes are turned +into a single, convex brush. If the result of the merge would not +create a convex brush, the following message appears in the editor +console: " Cannot add a set of brushes with a concave hull." + +

Examples: Example "A" shows two brushes can be +merged together. Example "B" shows two brushes that cannot +merge. + +

image028.png + +

Clipper
+ + + +If you think of this tool as being near the same as the miter +box that a carpenter uses to cut wood or moldings, then you are not +far from the truth. + +

Placing Clip Points + +
Clip points are placed in the map views by two methods: + +

+ +

The figure below shows a square brush that has been "clipped" +from the lower left (point 1) to the upper right (point 2). The +editor creates a line between the first point and the second point. +The piece to be kept when the brush is cut is always created in a +clockwise direction from the line (assuming that the first point is +the center of the "clock") + +

In a two-point clip (shown here), the cut occurs perpendicular +(at a 90 degree angle) from the plane of the map view. Adding a +third point, and adjusting its position in a different map view can +change the angle of the cutting plane. This will take practice to +master. + +

    Toggle Clipper + + + +This toggles the Clipper function on and off. After completing a +cut, the tool remains active and must be toggled off before another +brush is selected. + +
    Clip Selection + + + +If the "clip selection" action is completed the red portion of +the brush will be discarded and only the yellow will remain. The +brush is unselected. Undo currently returns the original brush and +keeps the clipped off piece. + +
    Split Selection + + + +If the "split selection" action is completed the red and yellow +portions of the brush will remain, split into two triangular +brushes. The brush is unselected. + +
    Flip Clip Orientation + + +The yellow and red hi-lights toggle so what was red is now +yellow and what was yellow is now red.
+ +

Make Detail
+ + + +In Quake 2, this was a surface flag. In Quake III +Arena, it is used on the brush itself. Detail makes a brush +non-structural. This means that it cannot be used to seal the hull +of the map world. Don't use it for wall, floors, or ceilings. If it +is used as a hull, the map will "leak" when compiled. But it can be +used on things that jut out away from the walls (as long as there +is a structural brush behind it). + +

Detail has two beneficial effects: + +

1. Detail brushes are less likely to cause additional cuts to +occur in non-detail brushes that they touch ... thus reducing +triangle counts. This can help reduce frame rate. + +

2. When the compiler does Vis, it breaks the world up into many +small volumes. Any break in the surface of the box that forms a +room creates additional volumes that must be. Detail brushes don't +create these breaks. Therefore, using them speeds up compiling. + +

Make Structural
+ + + +Structural is the Default State for brushes. Textures that are +not manipulated by shader scripts to be transparent or non-solid) +do not change this. Essentially, this is a change-it-back +command for Make Detail. It removes the detail flag from the brush. +This surface WILL block Vis when the map is compiled (so long as +there isn't shader content that says otherwise). + +

Func_Group
+ + + +Technically, this is a b_model (brush model) entity. However, +it's a great way to manage and handle related groups of map +components for ease of selection. To use, select the brushes +and patches you want to group and then open the Entity window +(press "N"). Click on the entity list sub-window and type in "F" to +move to the top of the "funcs". Double-click on Func_Group and all +the brushes and patches selected are bound together into a group. +Select one and you select them all. + +

Thumb through Components + +
(Shortcut: TAB) + +When you have a Func_Group b_model entity selected, press the +TAB key to "thumb" through the component pieces, hi-lighting them +individually, one at a time. This allows you to work on part of a +multi-piece group without having to work on all pieces + +

Find Brush
+ + + +Find brush allows you to locate a brush in the map by its +identifying number. As the map is built, the editor assigns +identification numbers to each map component. For brushes (and +patches) these include an Entity number and a brush number. For any +brush that is not part of a brush model (b_model), the entity +number is zero (0). Each b_model will have it's own number. + +

When the compiler outputs error messages in the console and +junk.text file, an identification number will call out brushes with +problems. Be prepared for them. Even when you do things right, you +will get error messages. + +

Selecting Find brush pops up a dialogue window with two fields. +The first field is the entity number. For most brushes, this will +be zero. The second number is the brush's individual number. +Selecting "OK," jumps the 2D map window(s) to the selected +component and hi-lights it. + +

Brush scripts…
+ + + +The command allows you to perform multiple step operations that +manipulate a single brush. Currently, only two of the list scripts +function. + +

+ + + + + + + + +
BuildSpiralThis walks you through the steps of building a spiral staircase. +Select a brush, then click on the map to locate the spiral origin. +Click again to bring up a dialogue window that prompts you to enter +the number of steps, the angle of rotation, and the height of each +step.
+ BuildStepThis clones the selected brush and moves it +X 16 units and +Z 8 +units.
+ +

Brush Menu Commands

+ +The Brush menu lets the mapmaker convert a selected brush into a +brush of a different shape. Most of the commands change the number +of sides that the brush possesses. It will also change the brush to +a single color. There are individual commands for three through +nine sides. The brush will be given the number of sides indicated +by the command (Plus top and bottom). The "top" facing is always +relative to the view in which it is created. The sides are always +at right angles to the view facing. + +

Poly-Sided Brushes
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +

Arbitrary sided…
+ + + +This command opens a dialogue window. You can enter a number of +sides in the field from 3 to 64. Select OK to execute the +command. + +

Primitives
+ + + +Primitives are pre-made shapes other than squares or the +polygonal multisided boxes made by the "number" sided brush +commands. + +

Cone… + +

+ +This opens a pop-up dialogue window that lets you enter an +arbitrary number of sides. The height of the cone is equal to the Z +height of the brush. The cone is always made with its axis along +the Z-axis. At first, the radius of the base of the cone appears to +be unrelated, or at least unevenly related to the XY dimensions of +the brush from which it is transformed. However, if you make a four +sided brush, the point to point "diameter" of the resulting pyramid +is equal to the longest XY dimension of the brush. Starting the +same size brush as you used for the four-side cone, an eight-sided +cone fits neatly within the volume of the four-sided cone, four of +its sides congruent with the side planes of the four-sided cone. Do +the same for a 16 sided cone, and the same again for both a 32 +sided cone. However, the number of sides seems to max out at +56. + +

Sphere… + +

+ +This opens a pop-up dialogue window that lets you enter an +arbitrary number of sides. The maximum number of sides, which the +editor seems willing to handle is 32.The diameter of the sphere, is +roughly equal to the length of the longest XY side of the brush +from which it is transformed. Attempts to create spheres with more +faces than 32 may result in the brush disappearing and becoming +infinitely tall. Use Undo to back up from this or hit backspace to +discard the brush. + +

Torus… + +
Non functioniong command. No donuts for you! + +

Moving +Selected Brushes

+ +
Moving the Brush
+ +These keys move the brush around the map in discrete map grid +increments. + +
    Move Selection Down + + +Each press moves the selected map component down along the +Z-axis by one grid position (at current grid setting). Not affected +by current 2D-map view. + +

    Move Selection Up + +

    +Each press moves the selected map component up along the Z-axis +by one grid position (at current grid setting). Not affected by +current 2D-map view.
+ +

Nudging the Brush
+ +These keys move the brush around the map in discrete map grid +increments. The movement is in terms of the selected window, not in +terms of XYZ coordinates. + +
    Nudge Down + + + +Each press moves the selected map component "down" the map view +by one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates. + + + +

    Nudge Up + +

    + +Each press moves the selected map component "up" the map view by +one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates. + +

    Nudge Left + +

    + +Each press moves the selected map component "left" the map view +by one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates. + +

    Nudge Right + +

    + +Each press moves the selected map component "right" the map view +by one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates.
+ +

Snap Selection To Grid
+ + + +If you are using the map grid to keep brushes in alignment, this +is a great tool. Rotated brushes and brushes that have had their +vertices tweaked can have vertices that no longer lie on map grid +intersections. This snaps the vertices to align with the +grid. Be warned that snapping to large grids may be hazardous +to the health of your brush (Snap and it's gone! But that's what +UNDO is for). + +

Efficient Brush Building +Techniques

+ +

Developed from a Quake 3 World online posting by +Astrocreep + +

Compiling a map is a necessary evil. It takes time, it ties up +your processor, and in the early phases of map construction, comes +up with construction errors as often as not. Nothing you can do +about that … except the time thing. It is possible, +through more careful construction (or perhaps reconstruction) to +significantly reduce both map and bot compile times, and reduce map +and .bsp file sizes (the latter being important for downloads). The +following is based on reports written by Astrocreep that documents +his extensive work to streamline the compile on one of the id +sample maps. + +

Brush Construction
+ +It cannot be overstressed. If you want shorter compile times and +small file sizes, efficient brush construction is "critical" in +building your map. There is one rule that stands above all: + +

+DO NOT OVERLAP BRUSHES AT ANYTIME. + +

No matter what you have to do to build your map, do not overlap +brushes. Overlapping means that all or parts of two or more +brushes share the same physical space. If brushes overlap, you can +expect to add time to your compiling, and add size to your .map, +.bsp and, .aas file sizes. + +

Efficient map construction means that all brushes butt up +against each other, but never intersect. + +

Brush Counts
+ +The sample map to be reworked on had 1,100 brushes in it. +Without changing the layout or appearance of the map, Astrocreep +was able to remove 110, or 10% of the total brush count. + +

Learn how to do more with a single brush than with multiple +brushes. Evaluate your map after you complete initial construction +phases on all or part of it. Pick a part of the map, look at +the layout and ask yourself if you could do that with fewer +brushes. In all likelihood, nine times out of 10, the answer will +be yes. + +

If you make a structure out of three brushes (or whatever) and +have the same floor height and ceiling height (in some cases +heights can be different), look at it in the "top view". Can you +draw a line from each vertex and not cross out side of those three +brushes? If you can, then that grouping of three can become one +brush instead of three. + +

Example: here's how the engine might look at this. + +

Using 3 square brushes, you have 18 faces (with a texture mapped +on each side) to be calculated. This doesn't take into +consideration the number of in-game triangle faces that those +brushes may generate. Even if two-thirds of those faces are not +being drawn, they are still being calculated by both the compile +process and the bot navigation compile process. + +

As compared to: + +

Using one brush (filling the same area), you have only 6 faces +to be calculated. Here, you are compiling only a third of the total +geometry. It should go faster. + + +

Efficient map construction means using fewer brushes to build +the world. + +

+Caulking
+ +It is possible to even further reduce the number of brush faces +being calculated by applying a special non-drawing, but "solid" +texture called "caulk" (common/caulk) to surfaces that cannot be +seen in the game. When seen in the editor, this texture is a bright +garish pink. In the game, it does not draw at all. Apply caulk to +any brush face that either doesn't form the "shell" of the world or +can't be seen by a player during play. Doing this may not improve +your map's frame rate, but since your are telling the compiler that +as many as five of the six faces on a square brush don't have to be +calculated, it should have some significant effects on compile +times. As long as you do not have any brushes that "share" the same +space, caulking brushes should help reduce compile times. However, +if you use caulk on a brush that "shares" the space of another, +your compile time and all file sizes will actually increase. + + +

Astrocreep compiled the test level nearly 200 times, many of +those times were when he moved just a single brush, just to see +what would change. Caulking seems to help the -light phase +of compiling the most. + +

+Efficient map construction means caulking all unseen brush +faces. + +

Miscellaneous Tips
+ +Lights: You can further improve compile times by careful +use of lights. Entity lights, especially LOTS of entity lights can +reduce compile time. If you need to reduce compiling time even more +look to this. + +

Clip brushes: Clip brushes that have more than two sides +not touching another brush appear to increase compile times. + +

Hint brushes: Use these only if you need to resolve a vis +problem. Using them can significantly add to compile times. +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch06/pg6_1.htm b/docs/manual/Q3Rad_Manual/ch06/pg6_1.htm new file mode 100644 index 00000000..e9133e04 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch06/pg6_1.htm @@ -0,0 +1,624 @@ + + +Q3Radiant Editor Manual: Page 5.1 + + + +

Q3Radiant Editor Manual

+
+

Tools 3: Working with Curve Patches

+ +
Escape (ESC)
+ +This is the all-purpose deselect key. Use it to back out of +operations you don't want to complete or to stop working on a patch +or group of patches. + +

Curve Menu Commands

+ +The next set of commands comes from the Curve Menu. Some are +duplicated on the Patch Tool Bar. + +

Cylinder
+ + +This creates the simplest cylinder. Cylinders are always drawn +with their open ends facing up and down. It does not matter which +map view is open when the cylinder is created. + +

More Cylinders: + +

+ +
    Dense Cylinder + +
    This is a cylinder with a set of extra rows. It allows a +180-degree bend into a half donut (half torus). + +

    Very Dense Cylinder + +
    This is a cylinder with two extra sets of rows. This allows a +bend into a full donut (torus). + +

    Square Cylinder + +
    This is a cylinder whose columns have been adjusted so that a +square, with flat sides, is formed. +

+ +

End Cap
+ + +This is a half cylinder. + +

Bevel
+ + +This is a quarter cylinder + +

More End caps, Bevels: + +

+ +

Square Endcap + +
This is an endcap without the backside removed. + +

Square Bevel + +
This is a bevel with squared off back faces + +

Cone
+ + + +A cone is a cylinder with control points drawn together and +welded at one end to form a point. + +

Sphere
+ + + +
Design Note: A curve patch sphere can be constructed from +a cone. Start with a cubic brush. Convert into a cone. Go into edit +vertexes mode and grab the control point at the peak of the +cone. Pull it downward to half the height of the cone. Clone +the resulting piece and flip it upside down.
+ +

Simple Patch Mesh…
+ + + +The patch mesh is the basic building block use to create all +curves. All the curve primitives are deformations of this +item. For this to work, you must first create a brush of the +dimension desired for the patch. Selecting this opens a Patch +dialogue window. This lets you select the vertical (rows) and +horizontal (columns) complexity of the patch. The more complexity +means being able to perform more deformations on the patch. It also +means adding a greater number of triangles that must be +rendered. + +

Insert
+ + +Adding control points increases the complexity of a mesh. This +action does not increase the physical size of a mesh. Additions are +usually done before manipulating the patch mesh. + +
    Insert (2) Columns +
    This adds two columns of control points to the left edge of a +patch. + +
    Add (2) Columns + +
    This adds two columns of control points to the right edge of a +patch. + +
    Insert (2) Rows + +
    This adds two rows of control points to the lower edge of a +patch. + +
    Add (2) Rows +
    This adds two rows of control points to the upper edge of a +patch. +
+ +

Delete
+ + + +Deleting control points reduces the complexity of a patch mesh. +Be warned that the features created by the removed points are also +removed. It does not make the mesh a less complex version of the +former design. Deletions also change the dimensions of the mesh, +removing the area created by the deleted control points. A mesh +cannot be reduced smaller than a 3 column by 3 row complexity. + +
    First (2) Columns + +
    This removes two columns of control points from the left edge of +a patch. + +
    Last (2) Columns + +
    This removes two columns of control points from the right edge +of a patch. + +
    First (2) Rows + +
    This removes two rows of control points from the lower edge of a +patch. + +
    Last (2) Rows + +
    This removes two rows of control points from the upper edge of a +patch. +
+ +

Matrix
+ + + +This has nothing to do with Neo and Trinity. It's the patch mesh +taken as a whole. + +

Invert + +

+ +This command inverts the normals of the patch mesh. The normals +control the direction of facing for the texture skin and the +clipping surfaces. + +

Re-disperse + +

+This is used on a selected patch. When rows or columns are +inserted or added to a patch, the dimensions of the patch are not +changed. The distances between the new additions and the old points +are not the same. This command averages out the distance between +the points. It does not change the size of the patch. +WARNING! Only apply this BEFORE adjusting the patch. Otherwise, +you may lose your work on it. With some patches, selecting this +command will destroy the patch itself. + + +
    Cols + + + +The distance between columns is averaged and evened out. + +

    Rows + +

    +The distance between rows is averaged and evened out.
+ +

Transpose + +

+ +(Function undetermined) + +

Cap
+ + + +This command adds "cap" patches to the ends of the patch. The +original brush and the caps are linked together as a func_group +entity. A Patch Tool Bar button duplicates this command. The type +of cap depends on the selected patch: + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +CylinderThe ends of the cylinder are sealed with circular patches.
Square +CylinderThe ends of the cylinder are sealed with square patches.
+ConeBoth ends are capped (open and point). You will want to discard the +cap on the point end.
+BevelIf you select to cap a bevel, a dialogue window pops up. +A normal bevel cap covers the space between the curve and the +center.
Inverted +BevelAn inverted bevel covers the space between the curve and the outer +corner.
+EndcapIf you select to cap an endcap, the same dialogue window pops +up.
Patch +MeshThe bevel/endcap window will pop up. Results will vary depending on +the manipulations done to the mesh.
Square +BevelCapped in the same manner as a cylinder
Square End CapCapped +in the same manner as a cylinder
+ +

Cycle Cap Texture + +

+ +Press this repeatedly until the texture on the cap patch looks +correct. + +

Overlay
+ + + +Overlay turns the grid of control points on for the selected +patches and leaves them on until the Clear command is selected. By +having the control points on a curve patch be visible, it is easier +for the designer to align the vertices of adjacent solid geometry +brushes. + +
    Set + + + +This is the command to turn on the control points in a selected +patch. + +

    Clear + +

    + +This is the command to turn off all control points in all +patches.
+ +

Thicken
+ + + +If you think about it conceptually, Thicken transforms a curve +patch into a three-dimensional object. It does this by duplicating +the selected curve and moving it a distance away from the copied +curve, and, if the "seams" checkbox is checked, it will cover the +space between the original and the copy with patches. The distance +between original and copy is selected in a pop-up dialogue window. +The direction is determined by the facing of the curve's normals +(the textured side). The duplicated curve appears on the opposite +side of the textured face. The resulting object depends on the +nature of the curve primitive being thickened. The following +are some examples: + +

+ + + + + + + + + + + + + + + + +
+CylinderA pipe is created. Checking "seams" caps the ends.
BevelA matching bevel is created. Checking "seams" creates a bent square +tube.
EndcapA matching endcap is created. Checking "seams" creates an +arch.*
Patch +MeshA mesh that echoes the shape of the selected patch is created, but +with XY dimensions smaller or larger by the measure of the +thickness (smaller if the normals are on the concave side; larger +if on the convex side).
+ +

* Thickening an Endcap is not the best way to create this shape. +Bending a square cylinder will produce better results. + + + +

Patch Tool Bar

+ +
The patch tool part is turned on in the Preferences. Each +of these buttons enables or disables a curve editing feature, or +initiates a process on a selected curve patch. + +

Don't Select Curved Brushes
+ +This button toggles the ability to select or not select curve +patches in the map. If turned on (depressed), the user will not be +able to individually select curve patches. Group selections +will still include any curve patches within their boundaries. + + + +

Show Patch Bounding Box
+ +This button toggles the display of the bounding box that defines +the limits of the patch. On (button depressed) shows the bounding +box. + + + +

Show Patches as Wireframe
+ +This button toggles the display of patches between a fully +textured mesh (off) and a wireframe-only mode (on). The wireframe +mode makes it easier to see the deformations of the mesh and allows +the user to see some control points that may be hidden by the +texture when it is mapped on the mesh. It can also be a +performance-enhancer for the editor (by setting the view to +wireframe until you need to see the brush textured). + + + +

Design Tip: When manipulating the control points on a +patch mesh, using wire frame allows you to best see both the +control points and the deformations.
+ + + +

Patch Bend Mode
+ +If a curve patch is selected, this button initiates a multi-step +bending procedure. There are tutorials available on several +sites that address the fine points of bending a patch, whether it +is a cylinder or a simple flat mesh. The ESC key will exit the +procedure at any point. The following are just the steps: + + + +
  • Select the patch (and only the patch). + +
  • Press the Patch Bend Mode button. This brings up an instruction +window that says: +
+ + + + + + +

This highlights (turns pink) a row or column of patch control +points. One of these control points will likely be the axis for +your bend. Pressing ENTER locks in your choice and advances to the +next step. + + + +

  • A second instruction window message appears:
+ + + + + + + +

This highlights the specific control point around which the +patch will bend. Pressing ENTER locks in your choice and advances +to the next step. You can also choose the control point by +SHIFT + middle mouse button clicking on the map window. The +click need not be within the bounds of the patch. + + + +

  • A third instruction window message appears:
+ + + + + + + +

This highlights the side or end of the patch (relative to the +bend point) around which the patch will bend. Pressing ENTER +locks in your choice and advances to the next step. + + + +

  • A fourth instruction window message appears:
+ + + + + + + +

Clicking and holding the Left mouse button on the map window and +dragging it around will cause the patch to bend. Pressing ENTER or +ESC at this point will accept any changes that you have made. + + + +

Redisperse Patch Points
+ +This is used on a selected patch. When rows or columns are +inserted or added to a patch, the dimensions of the whole patch are +not automatically adjusted. The distances between the new additions +and the old points are not the same. This command averages out the +distance between the points. + + + +

WARNING: Only apply this BEFORE making adjustments to the +patch, otherwise you may lose your work on it. With some +patches, the patch itself will be destroyed. + + + +

CAP (put caps on the current patch)
+This is used on a selected patch. + + + +

Design Notes: + +
    Endcaps: Don't cap endcaps with this tool. Make a +pair of opposing bevel caps that match the arch of the endcap + +
    Messed Up Texturing: If an inverted bevel endcap covers +something other than an arc of a perfect circle, it is likely that +the texture won't appear right when you apply the CAP function to +the texture. Press SHIFT + CTRL + P a few times until it looks +right.
+
+ +

Weld Equal Patch Points (welds equal patch points during +moves) + +
(Patch Control Bar only) This feature, when selected (button +pressed in) causes control points to weld together if they are +moved to the same coordinates. Undo will undo the move and the +weld. + + + +

Drill Down (selects drill down rows and columns) + +
When this is toggled on (depressed), clicking on a control point +in a 2D Map view selects all the control points in the row or +column beneath it. + + + + + +

Moving Patches

+ +
Moving Selected Curve Patch
+ +These keys move the curve patch around the map in discrete map +grid increments. + +
    Move Selection Down + + + +Each press moves the selected map component down along the +Z-axis by one grid position (at current grid setting). Not affected +by current 2D-map view. + +

    Move Selection Up + +

    + +Each press moves the selected map component up along the Z-axis +by one grid position (at current grid setting). Not affected by +current 2D-map view.
+ +

Nudging the Curve Patch
+ +These keys move the curve patch around the map in discrete map +grid increments. The movement is in terms of the selected window, +not in terms of XYZ coordinates. + +
    Nudge Down + + +Each press moves the selected map component "down" the map view +by one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates. + + + +

    Nudge Up + +

    + +Each press moves the selected map component "up" the map view by +one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates. + +

    Nudge Left + +

    + +Each press moves the selected map component "left" the map view +by one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates. + +

    Nudge Right + +

    + +Each press moves the selected map component "right" the map view +by one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates.
+ +

Snap Selection To Grid
+ + + +If you are using the map grid to keep curve patches in +alignment, this is a great tool. Rotated curve patches and curve +patches that have had their vertices tweaked can have vertices that +no longer lie on map grid intersections. This snaps the vertices to +align with the grid. Be warned that snapping to large grids +may be hazardous to the health of your curve patch (Snap and it's +gone! But that's what UNDO is for). +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch07/pg7_1.htm b/docs/manual/Q3Rad_Manual/ch07/pg7_1.htm new file mode 100644 index 00000000..ec331a7d --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch07/pg7_1.htm @@ -0,0 +1,945 @@ + + +Q3Radiant Editor Manual: Page 7.1 + + + +

Q3Radiant Editor Manual

+
+

Tools 4: Working with Textures

+ +There are three skill and knowledge components to working with +textures as they regard Quake III Arena. They are Texture +creation, Texture Manipulation, and Texture Application. Only the +third, Texture Application, is absolutely necessary for making +maps. You need not master all three. + +

Brush Primitives: A New Format

+ +With the release of version 192, the Q3Radiant editor takes a +new direction in the way textures are mapped to the surfaces of +brushes. The texturing format will roughly be the same as the way +textures are handled on curve patches. While there are no changes +to the user interface within the editor, you should see a change in +the way textures behave on brushes during transformation operations +like move and rotate. Because textures are mapped to the S +and T coordinates of a brush (as they are with curve patches), +locked textures will now maintain their positions on brushes when +they are moved or located. Even complex rotations should now be +possible without the textures going askew. + +

Checking the Brush Primitives checkbox turns on this feature. +(Menu: Project Settings… > Use brush primitives in map +files). Once you change a map to Brush Primitives, you cannot go +back to the earlier method of texture mapping with that map. The +prudent mapper makes backups before making major changes to +projects. + +

Texture Creation: Making new Assets

+ +This is covered earlier in the manual. + +

Texture Manipulation: Shader Overview

+ +Technically, each texture already has a default shader that +passes it through the pipeline to appear much as it does in the +graphic program that made it. A shader is a short script, +separate from the texture file, that the game engine uses to make +further adjustments to the texture's appearance or function. The +shader is to Q3A what the surface properties flags were to +Q2, only ever so much more powerful. If you plan on creating +your own textures, you should get to know and understand how +shaders work. The Q3A Shader Manual contains the information you +need. + +

Shaders and Multi-Pass Texture Effects
+ +(Drawn from an original essay by Small Pile of Gibs) + +

Shaders give the mapper control over special graphics effects +that require multiple redrawing passes before they are finally +displayed on the game screen. Every shader that changes the visual +component of a texture uses these "Multitexture" effects. +Multitexture is ON by default in Quake III Arena. It is +turned off with the cvar, "set r_ext_multitexture 0 (entered in the +console or bound to a key) - see the Debugging section in this +document for more details. + +

To understand how multitexture works, you need to understand how +the Quake III Arena graphic engine renders a scene. All the +faces you see in Quake III Arena are made up of triangles - +you can see this by using the cvar command "r_showtris 1." +Initially, each triangle adds one to the "tris" number in r_speeds +(the numbers that are used to estimate whether a scene is too +complex). With every frame that Q3A "paints", it draws +triangles onto the scene in layers, starting at the back of the +scene and drawing every triangle visible until it reaches the +front. It takes time to draw each triangle. If a triangle is +painted with a texture that is "see through" in some way (either +transluscent, transparent, or containing cut-outs), any triangles +seen through that triangle must be redrawn one additional time for +each stage in the the shader. If a single transparent triangle +takes up the whole screen, for example, a glass window - The whole +area of the screen has to be redrawn. Each triangle of glass takes +an entire screen worth of "overdraw" and each extra stage on the +glass adds another screenful, which is why glass can be such a big +framerate hit. + +

The simplest form of multitexture is a Lightmap. In most cases, +the Q3A engine first draws the lightmap (precalculated light and +shadow information). Then, on top of that, it adds in the +information from the texture art specified for that triangle using +a special effect (blendfunc filter) - which blends the lightmap +with the texture to make areas of the texture look light or dark. +Using the cvar command "r_vertexlight 1" (Vertex Lighting +instead of Lightmaps) stops Q3 from drawing the lightmap triangles +(which is why many gamers use vertex lighting to gain additional +playing speed). + +

Every extra stage in a shader is an extra triangle drawn over +and blended with the first triangle in a special way. Like the +lightmap example above, each additional stage requires an extra +triangle to be drawn for each frame. On certain 3D accelerator +cards (like the TNT - TwiN Texture), the multitexture effect +cancels out the real cost of the first pass of blending. The +blending for the first additional stage is done before the triangle +is drawn. However, if the shader takes 3 stages (like all the shiny +metal effects) it costs an extra triangle for every triangle it is +used on. Every extra triangle used adds a triangle to the r_speeds +triangle count. Because there are cards that don't automatically +handle this first blending pass, the map maker needs to +occasionally check his r_speeds with the multitexture turned +off. + +

Texture Application: Texture Handling +Tools

+ +These tools manipulate textures within the editor. They do not +create textures or shader scripts. + +

Escape (ESC)
+ +This is the all-purpose deselect key. Use it to back out of +operations you don't want to complete or to stop working on a brush +face, a brush, a patch, or a group of brushes or patches. + +

View Textures
+ + + +This is only used in the four-view and floating windows modes +(as set in Preferences). It brings up the Texture selection window +(also accessible from a folder tab). If the Entity window is open, +you may need to click on a map view window first for the "T" +command shortcut to work. + +

Show in Use
+ + + +This command affects the content of the Textures window. It +filters the contents so that only those textures currently in use +in the map are displayed in the window. + +

Show All
+ + + +This command affects the content of the Textures window. It +"un"-filters the contents so that all the texture directories +previously loaded during the mapping session are re-displayed. + +

Surface Inspector
+ + + +

+ +

This brings up a pop-up dialogue box. This is one of the more +complicated interfaces used during map development and may take +some getting used to. + +

Texture + +
This is the path/name (beginning in Textures directory) for the +texture. You can copy from this field or paste into it. If you know +the pathname of a texture, you can enter it here. It will load +without having to first load the entire directory that contains +it. + +

The next five commands work on both patches and brushes. +However, the results of applying a Horizontal Shift to a brush and +to a patch may be substantially different. When working with +patches, the numbers in the fields do not change … although +the texture on the map component may be changing. + +

Design Note: When a curve patch butts flush up against a +piece of solid geometry, as if it were an extension of that +geometry, it may be difficult to align the textures exactly. In +fact is often extremely difficult to align a texture on a +patch with the texture on an adjacent geometry brush. It works best +when the dimensions of the patch are an exact multiple of the +dimensions of the texture being used. Otherwise, you may want to +consider designing your architecture in such a way that it is +logical for a new texture to begin at that point. Use your +judgement.
+ +

Horizontal Shift + +
This allows you to change the Horizontal texture offset +(position of texture on a surface). You can type an offset value +into field or use the scroll buttons on the right to shift the +texture. If "Snap T to Grid" is set in Preferences, the scroll +increments will move a number of pixels equal to the grid size. + +

Vertical Shift + +This allows you to change the Vertical texture offset (position +of texture on a surface). You can type an offset value into field +or use the scroll buttons on the right to shift the texture. If +"Snap T to Grid" is set in Preferences, the scroll increments will +move a number of pixels equal to the grid size. + +

Horizontal Stretch + +This allows you to change the dimensions of textures as they are +mapped into the world. You can type a size value into field or use +the scroll buttons on the right to enlarge or reduce the texture. +The default value is 0.5. This gives a presentation in the game +world of two pixels for each game unit. A Horizontal Stretch value +of 1.0 would double the amount of area covered by a single repeat +of the texture. Of course, doing that also reduces the apparent +resolution of the texture by half (can you say blurry?)! Making the +stretch value a negative number horizontally flops the texture's +normals (i.e.; flops the texture left to right). + +

Design note: Textures are "projected" onto brush +surfaces. This means that if a surface is angled, the texture +stretches to fit the space upon which it is projected. To make the +texture look "unstretched" you need to change the dimension so that +it looks correct when stretched. Example: If you want to map a +texture on a 45-degree angle, it should be scaled to 0.35 along the +direction perpendicular to the axis of the angle.
+ +

Vertical Stretch + +This is the same as for the Horizontal Stretch, but along the +vertical axis. Making the stretch value a negative number +vertically flops the texture's normals (i.e.; flops the texture up +and down). + +

Rotate + +This rotates the texture around the center point of the brush +(or patch). If the texture is not centered on the map component, +the rotation will not necessarily look correct. The increment of +rotation is set by the value given for the Rotation Inc field on +the Preferences window. The default value is 45 (degrees), roughly +1/8 rotation around the axis. + +

Value + +(This Quake 2 function is not used by Quake III +Arena) + +

Texturing + +

This next grouping of commands in the lower left corner of the +window provides two separate sets of buttons. The top set deal with +texturing geometry brushes. The lower set is for texturing curve +patches. + +

    Axial (Brush) + +
    Realigns texture to the X and Y axes (removing the effects of +rotation) + +

    Fit (Brush) + +
    The texture is stretched to fit the dimensions of the brush. The +width and height fields to the right are the number of repetitions +to be used in the S and T dimensions (S corresponds to X on +the actual texture and T corresponds to Y on the actual texture). +The default value for the height and width fields is 1. You can +type a size value into field or use the scroll buttons on the right +to enlarge or reduce the texture. Only integer values can be +entered (meaning that you can't enlarge a texture 1.5 times). + +

    CAP (Patch) + +
    This function is most often applied to patches used to fill in +the gaps between curves and solid geometry. It can also be applied +to flat patches so that the texture doesn't appear to follow the +arc of the patch. You may need to use the SHIFT + CTRL + N command +to normalize the texture on the patch. + +

    Set… (Patch) + +
    This command functions almost like the "Fit" command above for +brushes. The texture will be fit across the patch based on the X +and Y values given. However, there is a notable difference. The X +and Y fields will accept non-integer values (e.g. 6.4 x 3.8). It +may take some experimentation to determine which dimension of your +patch is considered to be "X" and which is thought to be "Y". If a +value of 1x1 is given, the texture will be "fit" to the +patch. + +

    Natural (Patch) + +
    The engine does its best to map the texture onto the patch in a +"natural" appearing manner. This means that the texture will curve +and flow with the curves and bends in the patch. Unless you are +texturing a cap, this should be your first choice when applying a +texture. + +

    Fit + +
    The texture's coordinates are mapped to fit the patch +(with no repeats). +

+

Find / Replace
+ + + +This feature allows the user to replace a texture within a +single brush, a set of selected brushes or globally throughout the +entire map. Selecting the command from the menu opens up a dialogue +window. The top line is for the texture path and name of the +texture to be replaced. The second line is for the texture to be +used for replacement. Several checkboxes allow fine control over +what, exactly, is to be changed. This command does not respond to +UNDO. If you accidentally mistype a texture name in the replace +line, you will need to enter it again (as mistyped) on the find +line and then enter the correct texture on the replace line. + +

Texture replacement is global (throughout the map) unless the +selected checkboxes state otherwise. + +

    Replace within selected brushes only. Only the hi-lighted +brushes that contain the texture to be replaced will be +affected. + +

    Force replacement (ignore current texture name). +All textures in the map will be replaced. Best if used with +Replace within selected brushes only. Be very careful +with this one. + +

    Live Updates from Texture/Camera windows. Using +Live Update the user can find and replace textures with a fully +point and click interface. + +

    Texture Replacement using Live Updates + +
    Click on the Find box, then click on any texture in either the +Camera window or the Texture window. The texture path/name for that +texture appears in the box. Next click on the Replace box and click +on the replacement texture. That texture's path/name appear in the +Replace box. Select "OK" and the replacement will occur.

+ +

Step-by-step for replacing a texture on a brush face +(if live update is not used). + +

  • In the Camera window, hi-light (CTRL+SHIFT+mouse1) the texture +to be replaced. + +
  • Open Surface Inspector. If the name of the texture is not +hi-lighted, then hi-light it. + +
  • Press CTRL+C to copy the texture name. + +
  • Open the Find/Replace window. + +
  • Paste (CTRL+V) the name into the find window. + +
  • Hit ESC to deselect the texture in the CAM winow. + +
  • Open the Textures Window. Find the texture you want to replace +with and select it. + +
  • Open Surface Inspector again. + +
  • Copy the texture name there. + +
  • Open Find/Replace again and paste the new texture into the +Replace box. + +
  • Select OK. Replacement occurs and the dialogue window +closes.
+ +

Texture Lock
+ + + +Opens Pop-up window with two options for "locking" texture +shifting during brush or patch movement. NOTE: If you have +selected the BRUSH PRIMITIVES option under Project Settings… +then Texture lock will always be on. + +
    Moves + + +When this option is checked, textures stay locked in position on +the brush as brushes are moved around the map. If unchecked, the +texture appears to shift across the brush, because they are fixed +to the world, not the individual brush. On small brushes and small +textures (such as the small square lights), some "creepage" may +occur, with textures shifting 1 or 2 units off their locked +position. + +

    Rotation + +

    + +When this option is checked, textures stay locked in position on +the brush or brushes as they are rotated around the map. If +unchecked, the texture appears to shift across the brush, because +they are fixed to the world, not the individual brush. On small +brushes and small textures (such as the small square lights), some +"creepage" may occur, with textures shifting 1 or 2 units off their +locked position.
+ +

Load from List…
+ + + +Opens a dialogue box listing all texture directories currently +recognized by the editor. Hi-light a directory title then +click on the "Load" button. The textures in the selected +directory will be loaded into the Textures window. + +

Shaders
+ + + +This command pops up a Pop-up window with two shader-related +commands. + +
    Load All (Reload) + + + +This command loads or reloads all the .shader scripts recognized +by your shaderlist.txt file. When you change and save a shader +script, execute this command, then reload the affected texture +directory to see any changes. + +

    Show + +

    + +When checked, this command surrounds all shader-manipulated +textures in the Texture window with a thin white border.
+ +

Flush
+ + + +The flush command frees up texture memory and should improve +editor performance. Exactly how much is flushed depends on your +choice of commands. + +
    Flush All + + + +This command flushes all the texture memory, restarts OpenGL and +reloads the map from the last saved copy. + +

    Flush Unused + +

    + +This command flushes all UNUSED textures from memory.
+ +

Texture Window Scale-
+ + + +This affects the size of the texture images displayed in the +Textures window. Clicking on the menu entry opens up a pop-up +window with the following size selections: 200%, 100%, 50%, 25%, +and 10%. Adjust it to suit your liking. If seeing the detail in the +textures is important to you, set the size to 100% or larger. If +you know your way around the textures without having to see each +pixel, set it for smaller. + +

Texture Directories
+ + + +This is not a command. The entries on the Textures Menu below +"Texture Window Scale" are the names of the available texture +directories (all whose filenames are listed in the shaderlist.txt +script). Clicking on one loads the contents of the directory into +the Texture window. + +

Texture Shift Key Shortcuts
+ +A brush, brush surface, or curve patch must already be selected +before using these shortcuts. This feature closely copies the +function of the Texture Shift fields and scroll bars on Surface +Inspector pop-up window. If Snap to T is selected in preferences, +then the texture shifts in pixel increments equal to the current +grid setting. Shifting textures on curve patches may produce +unexpected results. + +

+ + + + + + + + + + + + + + + + + + +

Texture Rotate Key Shortcuts
+ +A brush, brush surface, or curve patch must already be selected +before using these shortcuts. This feature closely copies the +function of the Texture Rotate field and scroll bar on Surface +Inspector pop-up window. The texture rotates in degree increments +set in Preferences. Rotating textures on curve patches may produce +unexpected results. + +

+ + + + + + + + + + +

Texture Scaling Shortcuts
+ +A brush, brush surface, or curve patch must already be selected +before using these shortcuts. This feature changes the scale of the +texture (the amount of area that a single instance of the texture +covers). The texture scale seems inconsistent, except that opposite +directions appear to cancel each other out. The amount of increase +delivered by the first use appears to be about a ratio of 1:15. + +

+ + + + + + + + + + + + + + + + + + +

Using Interactive Textures

+ +Interactive textures are the shader-manipulated textures that +have an effect on game play, not just the appearance of the map. +There are two classes of Interactive Textures: Special Content +Textures and Texture Entities. For more detail and +instructions regarding shader manipulation of textures, refer to +the Q3A Shader Manual. + +

Special Content Textures + +Special content textures are textures where the "surface" +parameters of the texture actually change the physical nature of +the geometry brush and in so doing, affects the play of the +game. + +

Water + +
Water is a content parameter that allows a player to "swim" +inside a geometry brush, causes a pulsing visual distortion of the +underwater geometry, and prompts the game engine to draw bubbles as +projectiles pass through it. A player can only remain under water +for a short time (without a battlesuit) and then begins to +drown. + +

Water usage rules: + +

    +
  • A water texture is defined by the presence of surfaceparm water +in the shader that creates it. + +
  • Because water is typically a "transparent" surface, the shader +passes used to create surface effects on water are added to the +shader passes of textures seen through the water surface. This can +significantly increase the number of redraw passes necessary to +draw the game world and may negatively affect performance. + +
  • If you place water brushes side by side, the touching sides must +be marked with the common/nodraw texture. + +
  • Both the top and the bottom surfaces of a water brush must be +water texture. + +
  • Water brushes cannot be stacked so they touch another water +brush vertically, only set side by side. + +
  • If you want to be able to exit water easily, keep the +distance from the top of the water brush to the adjacent "shore" or +pool edge at no more than 16 game units. Somewhat less is actually +better. + +
  • If fog is to be used as a part of a water volume, the water +surface should not deform.
+ +

Fog + +Fog content is used to block or diminish player vision and +provide "atmosphere" for a level. Like water, fog can affect game +performance, especially if one can see additional shader effects +within it. The following information is taken from the Q3A +Shader Manual regarding fog creation and usage. + +

fogparms <red value> <green value> <blue +value> <distance to Opaque> + +
This surface parameter (or "surfaceparm") defines the contents +of the fog. + +
Note: you must also specify "surfaceparm fog" to cause +q3map to identify the surfaces inside the volume. Fogparms +only describes how to render the fog on the surfaces. + +

<red value> <green value> <blue value> +These are normalized values (number range from 0 to 1). A good +computer art program should give you the RGB values for a color. To +obtain the values that define fog color for Quake III Arena, +divide the desired color's Red, Green and Blue values by 255 to +obtain three normalized numbers within the 0.0 to 1.0 +range. + +

<distance to opaque> This is the distance, in +game units, until the fog becomes totally opaque, as measured from +the point of view of the observer. By making the height of the fog +brush shorter than the distance to opaque, the apparent density of +the fog can be reduced (because it never reaches the depth at which +full opacity occurs). + +

Fog usage rules: + +

    +
  • If a room (or rooms) is to be filled completely with a fog +volume, it can only be entered through one surface (and still have +the fog function correctly). + +
  • The fog volume can only have one surface visible (from outside +the fog). + +
  • Fog must be made of one brush. It cannot be made of adjacent +brushes. + +
  • Fog brushes must be axial. This means that only square or +rectangular brushes may contain fog, and those must have their +edges drawn along the axes of the map grid (all 90 degree +angles). + +
  • If a water texture contains a fog parameter, it must be treated +as if it were a fog texture when in use. + +
  • Additional shader passes may be placed on a fog brush, as with +other brushes. + +
  • If a light-emitting fog brush is placed beneath normal brush +geometry, the light may cause light artifacting on the solid brush +surface. Use with care. + +
  • Brush models (trains, doors, rotating objects, etc.) within, or +partially within fog volumes will have drawing priority problems +against the fog. It is best not to place these entities in +fog volumes. + +
  • There are unconfirmed reports of moving entities being made with +fog shaders.
+ +

Lava + +
Lava content, for most practical purposes, is a variation of +water content. The damage that it does to players in contact with +it is defined by game code and cannot be directly affected by the +map designer. + +

Slime + +
Slime content, for most practical purposes, is a variation of +water content. The damage that it does to players in contact with +it is defined by game code and cannot be directly affected by the +map designer. + +

Texture Entities
+ +There are a number of shader-manipulated textures that are used +in an entity-like fashion. The shader files that manipulate the +textures are what give them their game properties. These are +the ones that id used and their relevant properties. + +

Areaportal + +
Color: Opaque Red Orange + +
Location: (textures/common/areaportal) + +
The bsp tool uses areaportals to create hard, visual breaks +between areas in the map. Until triggered, the areaportal blocks +geometry behind it from being drawn or seen. The area portal brush +should be a thin (2 to 4 units thick) brush. It should touch all +the brushes that form the hull of the opening being portalled. It +must be placed inside a door. The opening of the door triggers the +portal function. The closing of the door returns it to its former +state. The areaportal texture must completely seal off a volume +from another volume (although this can be in conjunction with other +areaportals). If a door is being used to block off an area from +view, consider placing an areaportal brush inside the door. Example +in Quake III Arena: All the doors out of the central courtyard in +Q3DM12, The Dredwerkz, are areaportalled. + +

Caulk + +
Location: (common/caulk) + +
Color: Opaque Pink + +
Game Function: Caulk, the miracle texture. It blocks vis. +It seals the world off from the void. It doesn't draw (so it +doesn't add to triangle counts). It keeps curves from competing +with textures behind them. It looks like hell if you see it in your +world. From the View menu (View > Show > Caulk), you can +toggle on and off the display of caulk brush sides. + +

Design Tips: When you build a brush entity (a.k.a. +b_model), mark all the brush sides that you will never see with +caulk. Otherwise, the game draws every one of them. Even if you're +only making a one-piece door, mark all the non-viewed sides with +caulk. The same holds true for detail brushes. If you can't +(or won't ever) see a brush face on a brush that's been marked as +detail, paint it with caulk. Next, whenever you build a curve, try +to build the brush geometry immediately behind it out of caulk. +Finally, look around your map for brush faces that you suspect are +being drawn, but are never seen: door pockets, bars, underneath +bridges or very low railings and so on. It may sound like work, but +attention to detail like this buys you both the appearance of +greater geometric detail in the map AND faster game running +speed. + +

More Design Tips: Finally, and this should be used with +great care, a caulk brush can be used to create an invisible +support for entities. If you place a very thin caulk brush floating +above a surface that would otherwise not support an entity +(example: a grate made of clip brush), the brush will not draw in +the world, but will support the entity. The reason for this is that +SUSPENDED entities are not "seen" by bots unless they can be +reached by a jump pad.

+ +

Clip + +
Location: (textures/common/clip) + +
Color: Transparent Red + +
Game Function: If you look at a professionally made map, +quite often you'll see that nearly every bit of wall surface is +covered in a transparent red texture called "common/clip." Clip is +a nondrawing texture that blocks player movement. Clip does not +block weapon fire. Entities, such as ammo or weapons, are not +supported by clip brushes. If placed or dropped on a clip brush, +they will pass through them. + +

Design Tips: Place clip brushes to smooth the passage of +players through the world. This could mean creating a slope that +allows the player to slip past a piece of architectural trim, or +filling a window to keep players from getting into it. It can be +used to create an artificial ceiling that prevents players from +flying or jumping too high.
+ +

Cluster Portal + +
Location: (textures/common/clip) + +
Color: Translucent lavender + +
Game Function: Works like an area portal, but for the bot +navigation file only. Cluster portal is used by the bspc utility to +subdivide the map into smaller areas for calculating bot +navigation. Appendix C: Bot Navigation Files contains the specific +details for using cluster portal texture entities. + +

Cushion + +
Location: (textures/common/clusterportal) + +
Color: Translucent pale aqua + +
Game Function: A player falling on this does not take +damage. They also don't make a "landing" sound, so use with +caution. + +

Do Not Enter + +
Location: (textures/common/donotenter) + +
Color: Transparent Pale Orange + +
Game Function: It is a tool used to solve bot navigation +problems. Use it like a clip brush, but sparingly. When you observe +bots doing stupid things in your map, try to block off the area +with this texture. The Bot Navigation Files appendix contains the +specific details for using the Do Not Enter texture entity. + +

Hint + +
Location: (textures/common/clusterportal) + +
Color: Transparent Yellow Green + +
Game Function: Helps determine the vis portals. It is +used as a suggestion to the compiler during the vis phase, when the +world is subdivided. Generally speaking, they are used to correct +vis problems, whose chief symptom is the "hall of mirrors" effect +seen during game play. These can often be corrected by careful +placement of a hint brush. If you fill the volume where the +error is seen or the volume adjacent to it, the problem may be +corrected in the next compile. This is really more art than +science. + +

Invisible + +
Location: (textures/common/noimpact) + +
Color: + +
Game Function: This was used to create a surface that +would be marked by weapon fire, but would not be drawn in the +world. This was created specifically to resolve a problem where +func_static brushes were being used to replace floor textures that +marked the location of weapons in Q3DM8. Because the rocket +launcher was located in different places between the team and the +deathmatch games, the designer wanted to make floor markers that +would not only change between game types, but would be marked like +adjacent floor pieces. + +

Nodrawnonsolid + +
Location: (textures/common/trigger) + +
Color: Opaque light yellow + +
Game Function: This is the same as nodraw. + +

Noimpact + +
Location: (textures/common/noimpact) + +
Color: black + +
Game Function: Used to create a surface which does not +block weapon fire. + +
Weapon fire will pass through this. This usually used as a +shader key on other textures. + +

Origin + +
Location: (textures/common/origin) + +
Color: Opaque Orange + +
Game Function: Used to create origin point in moving +b_models, such as trains, plats, and rotating objects. This +texture, applied to a square or rectangular brush, is used to +create the point of origin for moving b_models, such as trains, +plats, and rotating objects. It is used by func_trains as the point +that passes through path entities and the source for sound +attachment + +

Skip + +
Location: (textures/common/skip) + +
Color: Transparent yellow + +
Game Function: Do not use in Q3A. This texture was used +in Quake 2 maps to discard sides of hint brushes. It is +nonfunctional in Q3A. + +

Slick + +
Location: (textures/common/trigger) + +
Color: Translucent Pale Blue + +
Game Function: Not stick coating for map surfaces. +Reduces friction. Use like a very thin clip brush over surfaces you +want to be low friction. + +

Trigger + +
Location: (textures/common/trigger) + +
Color: Transparent Dark Yellow + +
Game Function: Used to make trigger brushes. + +

Weapon Clip + +
Location: (textures/common/weap_clip) + +
Color: Transparent Red + +
Game Function: This version of the clip brush only stops +weapon projectiles from passing through it. No marks are left on +the surface. + +
Design Tip: Use to create clip surfaces for map object +models. +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch08/pg8_1.htm b/docs/manual/Q3Rad_Manual/ch08/pg8_1.htm new file mode 100644 index 00000000..328e35d8 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch08/pg8_1.htm @@ -0,0 +1,347 @@ + + +Q3Radiant Editor Manual: Page 8.1 + + + +

Q3Radiant Editor Manual

+
+

Tools 5: Working with Entities

+ +The entities in Quake III Arena are limited to those +defined by the game code. The editor can draws entity information +from the game code, or from special definition (.def) files. +Version 192 of the editor comes with a .def file developed from an +original supplied by EutecTic. Mods made to Quake III Arena +can add to and/or subtract from the entities used by a game. If you +plan to work on mods, you should create multiple project files +(copy and rename your project file) with the changes required for +the mod. + +

The Entity Window

+ +You make game design decisions about entities and modify their +features within the Entity Window. The definition file that you +select on the Project Settings… window determines what +entities will be shown in the Entity List and what, if any, +property descriptions appear in the Key Descriptions and Check box +Spawn Flags. + + + +

Entity List
+ +The Entity List is the field on the Entity Window. It +contains the "classnames" of all the entities defined by the +definition file in alphabetical order. + + + +

You can use the scroll bar to scroll through the entities or, +after clicking on the field, type in the first letter of the class +you want to use (e.g.; type in "T" to select "target", or "A" for +ammo, "W" for weapon). + + + +

Double-click on the classname to select it and enter it on the +first line of the Active Properties field. + + + +

The Entities appendices of this document contain a complete listing of all the entities used in Quake III Arena. + + + +

Key Descriptions
+ +The entries in the Key Description field are the "rules of use" +for the hi-lighted classname in the Entity List field. You can use +the scroll bar to scroll up and down through the lines, but +the entries are not interactive. If you are using the .def file +accompanying release version 192 of the editor (or Eutectic's +original), all the key commands are described and their acceptable +values (or value ranges) are listed. If you are using the +descriptions in the .c game code file, they may be substantially +less descriptive. + + + +

Check box Spawn Flags
+ +Spawn flags are properties assigned to entities by use of check +boxes. Check the box to set the feature for the selected entity. +Many entities have only a single spawn flag property, while others +have numerous ones. Note that the check boxes to the right are only +relevant for Quake 2 single player games and will not work for Quake III Arena. + +

Active Properties
+ +This field shows all the properties currently assigned to the +selected (or newly-created) entity. Each property has two parts: +key and value. Once created or assigned, they appear on the same +line together. Only properties that are valid for an entity (that +is, ones that appear in the Key Descriptions field) will function +in game. Adding others may create error messages. You cannot +directly affect the properties in this field. + + + +

Clicking on an active property hi-lights it and fills in the key +and value fields below. You can edit both the key and the +value in those fields, or use the Del Key/Pair button to delete it +altogether. + + + +

Key & Value Fields
+ +Keys (and their values) are assigned to entities by typing them +into the fields. There is no spell check or auto-correction, so +make sure that your typing is accurate. Start by typing in +the name of the key. Then hit TAB or ENTER to change to the value +field. This also clears the contents of the value field. Now type +in the value for the key (the Key Descriptions list the acceptable +value ranges for the keys). If you hit ENTER, the key and value +appear in the Active Properties field. If you hit TAB, the +cursor moves up to the key field. You can also click directly on a +field to edit it. The cursor will appear after the last character +in the field. Use arrow keys to position the cursor within the +field. + + + +

Angle Buttons
+ +The Angle Buttons (below the value field) are used to assign a +facing direction (as is the case with player start spots or +misc_models) or movement direction to entities (such as doors and +buttons). Click on a button to create an Angle key with that +button's value in the Active Properties field. Clicking on +another key changes the angle value. + + + +

There are two clusters of angle buttons. The first cluster +represents rotation around the Z-axis for entities like player +start or spawn spots or misc_models. The entity will face in the +selected direction. The buttons represent angle directions in +45 degree increments. There is a direct correspondance between the +angle that the entity will face (or move) and the position of the +button in the cluster. If you select the 90-degree button at the +top center of the cluster, the entity will face "up" on the XY 2D +Map. If you select the 180-degree button on the left side of +the cluster, the entity will face left on the XY 2D Map. + + + +

For entities like doors or buttons, it represents the direction +that entity will move when activated. + + + +

The second angle button cluster assigns an up (-1) or down +(-2) direction to the entity. Note that an entity can only have one +facing direction. It cannot face up and 45 degrees. It can only +affect one or the other. + + + +

It is also possible to directly edit the angle value in the +value field. This allows for a much more precise angle +selection. + + + +

The Other Buttons
+ +

A third cluster of buttons sits to the right of the Angle +buttons. Each has a unique function. + + + +

Reset + +
Clicking on this button will reset all properties from the entity to the default values. + + +

Del Key/Pair + +
If you have selected an active property, clicking on this button +will delete the property. + + + +

Sound… + +
This opens a Windows directory browser in the directory that +contains the map sounds. Double clicking on a sound file name +in the browser window creates an active property with the +appropriate key and the value as the path/name for that sound. + + + +

Model… +
This opens a Windows directory browser in the models/mapobjects +directory. Double clicking on an .md3 file name in the +browser window creates classname misc_model active property with +the value as the path/name for that model. + + + +

Entity Handling Tools

+ +These tools manipulate the in game entities. The map component +handling tools that are described in the Working with Brushes +section also work with entities. + +

Escape (ESC)
+ +This is the all-purpose deselect key. Use it to back out of +operations you don't want to complete or to stop working on an +entity. + +

Connect Entities
+ + + +This targets one entity, typically an activating trigger, at +another entity, usually a target of some kind. Some entities +may be linked in multi-part chains, where each entity has some +effect on the one(s) that follow it. To use, do the following: + +
    +
  1. Hi-light the acting entity (usually a trigger, or a button). + +
  2. Hi-light the targeted entity (examples: target_position, +target_relay, a door). + +
  3. Select Connect Entities (or press CTRL + k). + +
  4. A path is drawn between the two entities. The first entity +selected always targets on the second.
+ +Troubleshooting: If the connection is not made check the +following: + +
  • Are both objects already entities? Sometimes it's easy to forget +to make a trigger brush into a trigger. + +
  • Did you select ONLY two objects? If you accidentally click +on something you don't intend to link, you have to start the +linkage over. + +
  • Did you select the objects in the correct order? + +
  • Is the second object something that can be triggered +remotely?
+ +

Ungroup Entity
+ +
(Menu: Selection > Ungroup Entity) + +
(Shortcut: none)
+ +This unbinds an entity made of brushes, and/or patches, and md2 +models back into separate map components. Once ungrouped, the +entity is no longer an entity and loses any and all key value +properties it may have had. + +

Design Note: If you intend to rebuild an entity after +ungrouping it, write down its key properties and values first.
+ +

Moving Selected Entity
+ +These keys move the Entity around the map in discrete map grid +increments. + +
    Move Selection Down + + + +Each press moves the selected map component down along the +Z-axis by one grid position (at current grid setting). Not affected +by current 2D-map view. + +

    Move Selection Up + +

    + +Each press moves the selected map component up along the Z-axis +by one grid position (at current grid setting). Not affected by +current 2D-map view.
+ +

Nudging the Entity
+ +These keys move the Entity around the map in discrete map grid +increments. The movement is in terms of the selected window, not in +terms of XYZ coordinates. + +
    Nudge Down + + + +Each press moves the selected map component "down" the map view +by one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates. + + + +

    Nudge Up + +

    + +Each press moves the selected map component "up" the map view by +one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates. + +

    Nudge Left + +

    + +Each press moves the selected map component "left" the map view +by one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates. + +

    Nudge Right + +

    + +Each press moves the selected map component "right" the map view +by one grid position (at the current grid setting). The movement is +relative to the selected map view, not XYZ coordinates.
+ +

Rotating Entities = BAD!
+ +All the commands that rotate brushes and patches will work on +entities. Unfortunately, what they do to some entities is BAD! +Don't use free rotate or menu rotation commands to rotate +Misc_models or any entity model represented by a wireframe model in +your map. The movement will separate the model wireframe from its +bounding box and will not actually change the facing of the +entity. + +

Changing Facing = GOOD!
+ +To change the direction that a misc_model or entity with a +facing (such as a player start or spawn spot) faces, use Angle keys +and values. You should "rotate" (change facing) entities with +either the Angle buttons on the Entity Window or by entering an +Angle key and giving it a rotation value between 1 and 360 +(inclusive). + +

Mass Rotations
+ +If you are building a Capture the Flag map, or other map where +you only build one portion and rotate it to make the others, +consider doing the following. Change the display of all +non-misc_model entities to bounding boxes only. Select the +entities to be moved and clone them. Then rotate them using the +menu rotating commands. Position them in the new map +section. Next, move misc_models individually. Change +their facing and set them in place. +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch09/pg9_1.htm b/docs/manual/Q3Rad_Manual/ch09/pg9_1.htm new file mode 100644 index 00000000..f79b44bc --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch09/pg9_1.htm @@ -0,0 +1,87 @@ + + +Q3Radiant Editor Manual: Page 9.1 + + + +

Q3Radiant Editor Manual

+
+

Tools 6: Lights & Lighting

+ +Lighting a map is both an art and a science. For Quake III +Arena, the id designers worked to create instances of dramatic +lighting, while attempting to maintain a relatively consistent +intensity of light throughout the maps. Other designers worked to +create dark realms, full of shadows in which lurking assassins +could hide. + +

Whatever style of lighting you strive for, remember one key +rule: The bots don't use light information. In a pitch-black room, +they would still see an opponent. Keep that in mind when designing +your maps. + +

Entity Lights
+ +There are several ways to create light emitting objects.  +The simplest is to place a light entity into your map.  If you +do nothing, it has a default value of 300 and emits white light. If +you think of the light value as the wattage for an incandescent +light bulb, you are not far off target. The section on the Light +entity in the Entities Description Appendix contains specific +information on using light entities. + +

Texture Lights
+ +Textures can be made to emit light. The amount of light that +they give off is determined by two factors: the size of the texture +and the value given for its q3map_surfacelight parameter. + +

If you only plan on using id textures in your maps, simply use +the textures surrounded by a white box in the texture window. Many +of them have their light values as part of their names: Example: +ceil22a_5k.  This would be a small, square light with a light +value of 5000.  There is not a direct correspondence between +the light value of a texture light and an entity light. + +

If you want to make your own lights, either with new, custom +textures, or changing the light and/or color values of the emitted +light in existing id textures, plan on learning your way around the +shader files.  The Shader Manual explains the light commands. +Place the new lights in unique directories. Example: +Mymapname_light\skull_light_2k.  Use the q3map_editorimage key +to make multiple light intensity versions of your new lights. + +

Generally speaking, very small lights need to have very large +values to look right (a 32x32 pixel light could easily have a +surfacelight value of 10,000 or more).  As the surface area of +the light becomes larger, the amount of light needs to be +substantially reduced for it to look right in the world.  A +word of warning, though. Very large glowing surfaces (other than +skies) can look odd in the game world, especially if they are made +from a repeating texture.  The light source will appear to be +generated from the center of the brush with the glowing +texture. + +

"Sky" Lights
+ +Quake III Arena was designed so that sky textures could +appear to emit light in a natural way. The q3map_sun parameter +creates a single light source in the sky. The mapper can control +the brightness, color, and position in the sky of this light +source.  Furthermore, the designer can add a +q3map_surfacelight value to the sky, giving it an overall lighting +value. + +

Ambient Light
+ +Ambient light is a property of the map's worldspawn entity. By +assigning a number value to the ambient key, the overall lighting +level of the map is raised. This has the tendency to flatten the +difference between light and shadow. The color of the light can +also be modified. This technique is considered a "hack." It does +not come recommended. You will find instructions that are more +complete later in this manual under the worldspawn entity heading +in the Entities Appendix. +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch10/pg10_1.htm b/docs/manual/Q3Rad_Manual/ch10/pg10_1.htm new file mode 100644 index 00000000..07bdc11b --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch10/pg10_1.htm @@ -0,0 +1,858 @@ + + +Q3Radiant Editor Manual: Page 10.1 + + + +

Q3Radiant Editor Manual

+
+

Tools 7: Miscellaneous Commands

+ +

Feedback & Read-outs

+ +The bottom border of the map window holds four clusters of +feedback information. + +

Z-Axis Layers
+ + + +If you are using any window layout that includes the Z-axis +scale, you can see the vertical relationships between components +with this function. + +

Cursor Coordinates
+ +These three coordinates, found to the left of center, report the +xyz position of the cursor in the 2D map window. + +
+ +

Brush & Entity Counter
+ +This readout is located at roughly center position. It reports +the number of brushes (including brushes forming brush entities) +and the number of non-brush entities (items, spawn spots, lights, +etc.) + +
+ +

Pushing the Limits + +This is a good place (as any) to talk about limits. +Quake III Arena has an upper limit of 2048 entities (including +entity lights!!) and while it's not an upper limit, staying under +8000 brushes is a pretty good idea. + +

Selection
+ +This readout temporarily replaces the Brush & Entity counter +when a map component is selected. The numbers represent the +dimensions of the selection. + +
+ +

Origin
+ +This readout temporarily replaces the Brush & Entity counter +when a select map component is moved. The numbers represent the +origin point of the selection (and track it as it moves). + +
+ +

Cursor Travel Distance
+ +These three coordinates, found to the right of the brush and +entity counter, report the distance that cursor has traveled from +the point where the user has clicked on the 2D map window. + +
+ +

Control Settings
+ +In the lower right corner of the editor window, you will see a +string of letters and numbers that might look something like +this: + +
+ +Each of these letter/number combinations represents the setting +for one of the commonly used tools. + +

+ + + + + + + + + + + + + + + + + + + + +
GGrid. Here, it's set to 8 units.
TTexture Tweak. This the increment in pixels that a texture will +shift. Here, it's set to 16 pixels.
RRotation. This is the amount of increment, in degrees that a +texture or brush will rotate.
CCubic Clip depth of field. When cubic clip is set, this is how far, +in terms of 64 unit blocks that you can see into the map. Here, the +setting of 10 would allow you to see 640 units into the map.
LTexture Lock. If M is showing, then it is locked for moves. +If R is showing, then it is locked for rotations.
+ +

Viewing, Seeing, Not seeing, and Hiding

+ +This group of commands all relates to what you see in the map and how you see it. Some are designed to reduce map clutter. Others are designed to improve editor performance. + +

Toggle…
+ +
    Camera View + +Toggles (hides or shows) the Camera View (CAM) window. + +

    Console View + +

    +Toggles (hides or shows) the Console window. + +

    + +Entity View + +

    + +Toggles (hides or shows) the Entity window. + +

    + +XY (Top) + +

    + +Toggles (hides or shows) the XY map window. + +

    + +YZ (Side) + +

    + +Toggles (hides or shows) the YZ map window. + +

    + +XZ (Front) + +

    + +Toggles (hides or shows) the XZ map window. + +

    + +Z View + +

    + +Toggles (hides or shows) the Z (height) window.
+ +

Center
+ + + +Centers the pitch (up and down) angle of the user view. + +

Up Floor
+ + + +This is a shortcut for moving up between "floors" in map. It +changes the user's Z height in the camera and map views. The view +moves to a point where it appears that the user is "standing" on a +"floor" (a brush with "air" space directly above it) directly above +the user's current position in the map. + +

Down Floor
+ + + +This is a shortcut for moving down between "floors" in map. It +changes the user's Z height in the camera and map views. The view +changes to a point where it appears the user is "standing" on a +"floor" (a brush with "air" space directly above it) directly below +the user's current position in the map. + +

Next (XY, YZ, XZ)
+ + + +Cycles the content of the XY map window with the other views +(side and front). + +

Layout
+ + + +
    + +XY (Top) + + + +This returns the main map view to XY Top view. + +

    + +YZ + +

    + +Changes main (XY) map view to YZ Side view + +

    + +XZ + +

    + +Changes main (XY) map view to XZ Side view
+ +

Zoom
+ + + +If the XY Top window is changed to display either +XZ front or YZ side the XY commands +below function the same way relative to the window, zooming in and +out as commanded. + +
    + +XY 100% + + + +Changes zoom on main map view to full size. + +

    + +XY Zoom In + +

    + +Zooms closer to main map. Working in smaller grid scale becomes +easier. + +

    + +XY Zoom Out + +

    + +Zooms out away from the main map. Working in larger grid scale +becomes easier. + +

    Z 100% + +

    + +Changes zoom on the z (height) scale to full size. + +

    Z Zoom In + +

    + +Zooms in closer on the z (height) scale. + +

    + +Z Zoom Out + +

    + +Zooms out and away from the z (height) scale. + +

    Cubic Clip Zoom In + +

    + +This requires that the Cubic Clipping function be toggled on. It +decreases the Depth of Field (distance in which map components are +seen) in the Camera window. Less map components are seen at one +time. Decreasing the distance seen in the Camera window can +significantly improve editor performance when viewing large numbers +of map components. See Cubic Clipping. + +

    Cubic Clip Zoom Out + +

    + +This requires that the Cubic Clipping function be toggled on. It +Increases the Depth of Field (distance in which map components are +seen) in the Camera Window. Increasing the distance seen in the +Camera window can significantly slow down speed at which your point +of view moves in the camera window. Increase the zoom to maximum +distance only if you have a relatively powerful editing system. See +Cubic Clipping.
+ +

Show
+ + + +This is a pop-up menu with checked toggle functions for each of +the features on the list. If a feature is checked, all map +components of that type will show in both the Camera window and the +Map windows. If the feature is not checked, all map components of +that type will be hidden. + +
    Names + + + +Shows names of entities. + +

    Blocks + +

    + +Shows an additional grid over the Map window with subdivisions +every 1024 units. + +

    Coordinates + +

    + +Shows the Map window coordinates along the left and top edges of +the Map window. + +

    Entities + +

    + +Shows entities, including brush entities, lights, and +models. + +

    Paths + +

    + +Shows the linkage connections between entities. This includes +triggers targeted at entities and path lines. + +

    Lights + +

    + +Shows Light entities. + +

    Water + +

    + +Currently non-functional. Look for future fix. Shows brushes +with water, lava, or slime content. + + + +

    Clip Brush + +

    + +This shows brushes with the common/clip content, including +common/clip and common/weapon_clip. The entire brush is +affected, not just clip brush texture sides. + +

    Hint Brush + +

    + +Shows brushes made with the hint texture. + +

    World + +

    + +Shows all non-entity brushes. + +

    Detail + +

    + +Shows all brushes marked with a Detail setting. + +

    Curves + +

    + +Shows all curve patches. + +

    Caulk + +

    + +Shows brush sides containing the common/caulk texture (does not +affect entire brush). + +

    Design Tip: When you optimize detail brushes by caulking +unseen brush faces, isolate the detail brushes in a region then +turn off Caulk. Brush faces that need caulking will show up clearly +as you move around the brushes.
    + +

    Angles + +

    + +Shows facing angle of player start spots by way of a white +arrow.
+ +

Hide/Show
+ + + +This is an immensely powerful and useful tool. It lets the user +temporarily hide map components that may be in the way of working +on other brushes. Hidden components are not affected by CSG +actions. + +
    + +Hide Selected + + +Selected map components are hidden from view (and CSG cutting +operations) until the Show Hidden command is executed. + +

    Show Hidden + +

    + +Previously hidden map components are returned to view.
+ +

Entities as…
+ + + +The editor can show model entities (referring at this point only +to Misc_Model entities) in several formats. Note: More +detail in a model shown in the Camera and map views will affect the +ability of the editor to display the map. If the editor responds +sluggishly, try reducing the level and/or type of detail shown for +models. + +
    Bounding Box + + +This is the simplest form of display. A box defines the outer +dimensions of the model. This is the least costly manner of +display. + +

    Wireframe + +

    + +Non-functioning. + +

    Selected Wireframe + +

    + +The Model is displayed as a bounding box until selected, at +which point the wireframe mesh for the model appears. + + + +

    Selected Skinned + +

    +The Model is displayed as a bounding box until selected, at +which point the skinned mesh for the model appears. + +

    Skinned + +

    +Only the skinned mesh for the model appears in the map and +Camera views. + +

    Skinned and boxed + +

    +The skinned mesh for the model appears inside a wire frame of +the bounding box in both the map and Camera views.
+ +

+ + + +This command toggles on (checked) or off when selected. Cubic +Clipping may be the most effective way to improve editor +performance. When turned on, only those map components near +the player are displayed in the Camera window. Any map components +beyond a certain depth of field will not be displayed in the camera +window (it has no effect on map windows). As the user moves +through the map in camera view, map components will pop into being +as the point-of-view (POV) draws closer and disappear as the POV +moves farther away. The shorter the distance "seen" in the +camera view, the better will be the editor performance when moving +through the map. Use the Cubic Clip Zoom commands +(see above) to modify the depth of field seen in the camera +view. + +

Open GL Lighting
+ + + +This feature is not fully implemented yet. It toggles on +(checked) or off when selected. When it is finished, all planes +facing a particular direction will shade the same way (curves will +shade like brushes) and the overall quality of the camera view will +be better. It will be slower however. + +
    + +Tip: As it currently is implemented, this lighting can be +useful when working with irregular surfaces all covered with the +same texture.
+ +

Show Brush/Patch Dimensions
+ + + +When you select a brush, the hi-lighted image in the map window +shows its dimensions, in game units. If multiple patches or brushes +are selected, the size will be the dimensions of the grouping. If +any kind of non-brush model entity is included in the grouping, the +dimensions are not shown. + +

File Management Commands

+ +
New Map
+ + + +This creates a new map file. If the current map file contains +any unsaved changes, the editor will offer the option to +cancel. + +

Open…
+ + + +This opens up the Maps folder as defined in the preferences. It +will show all valid map files in that directory. User may browse to +other directories from here. Double clicking on a map file +icon or hi-lighting that map and selecting Open will open +the map. The user may also type in a map file name. Be sure to add +the ".map" or ".reg" extensions or the editor will not find the +file. + +

Save…
+ + + +Saves a new map file to the default Maps directory. A reopened +map file will be saved to its source directory. Note, that it is +usually a good idea to save the map into the directory used by the +compiler as the source of its map data. Remember to give the file a +name. The compiler doesn't like to work with files called Unnamed +Map. + +

Save As…
+ + + +Opens the default directory for maps and prompts the user to +give the map a filename. + +

Save Selected…
+ + + +The selected brushes are saved as a map file. This is not the +way to make prefabs, though. + +

Save Region
+ + + +If the user has "regioned off" a subset of the map, this command +will save it as a separate file. It is grayed out unless the user +has created a regioned area. The editor prompts the user to enter a +file name before saving. + + + +

Reopening Maps
+ + + +(ALT+1 to 6 when File menu is held open) + +
OK, There isn't actually a command called this. When you open +the File Menu, you will see (after you've done some work on maps), +the path/file names for the last six maps that you worked on. They +are listed here for easy opening access). + +

Projects and Preferences

+ +

New project…
+ + + +Make a new project file. This allows you to set up different +preferences. + +

Load project…
+ + + +Make a new project file. This allows you to set up different +preferences. + +

Project Settings…
+ + + +Change pathnames and add, remove or modify commands. + +

Miscellaneous Commands

+ +
Map info…
+ + + +This gives a readout of brushes (including curve patches) and +entities in the map, including the total number of brushes that are +not part of entities. There is also a breakdown, by type, showing +the number of entities in the map. + + + +

Entity info…
+ + + +This gives a read-out of the entities in a map by their +type. It allows you to select an entity, which +hi-lights it in the XY Map. Good for locating lost entities. + +

Preferences
+ + + +This opens the window for setting or modifying the parameters, +paths and features of the editor. Preferences are discussed in the +Installation & Set Up section earlier in this document. + +

Opening Menus from the Keyboard

+ +These are the keyboard shortcuts that open up the menus. If you +continue to hold down the ALT key, many of the commands in that +menu may be activated with an ALT+ keystroke command. + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
File(ALT + F)
Edit(ALT + E)
View(ALT + V)
Selection(ALT + S)
Bsp(ALT + B)Note: Toggles between BSP & Brush. Hit enter to open selected.
Grid(ALT + G)
Textures(ALT + T)
Misc(ALT + M)
Region(ALT + R)
Brush(ALT + B)
Curve(ALT + C)
Plugins(ALT + P)
Help(ALT + H)
+

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch11/pg11_1.htm b/docs/manual/Q3Rad_Manual/ch11/pg11_1.htm new file mode 100644 index 00000000..e495ca6c --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch11/pg11_1.htm @@ -0,0 +1,116 @@ + + +Q3Radiant Editor Manual: Page 11.1 + + + +

Q3Radiant Editor Manual

+
+

Tools 8: Compiling Maps

+ +To turn a map file from editor code into game code, it must be +processed or "compiled". In Quake engine gaming, this is often +referred to by the name "BSP", as in "I need to BSP my map before +you can play it." The word "BSP" is actually an abbreviation +for "binary space partition", the type of data organization +procedure John Carmack used when creating the graphic engine for +"DOOM". + +

The primary BSP process builds the game spaces, +establishes the position of entities, and builds a lighting map of +the arena. Altogether, there are four distinct processes that +can be run together or separately. The first, the bsp process +establishes the data organization of the map. The second phase, the +vis process, builds the walls and internal spaces. The third +process lights the map, calculating brightness and shadow and the +color of the light that falls on every map surface. The fourth and +final process is the Bot bsp, which creates the area (.aas) file +that the bots use to navigate the map. + +

The size and complexity of a map and the computer's raw +processing speed determine how long it will take a map to compile. +Tiny one-room maps that lack detail or numerous lights will compile +rapidly. As maps become larger, are broken up into more +spaces and have more complex lighting, the speed of compile +drops. + +

Generally speaking, if you have an older, slower processor, you +may want to make very small maps. + +

The BSP Menu
+ +The bsp menu contains a number of compile options. The process +you choose will depend on what you are doing with the map at the +time you choose to compile. + +

novis - Only the bsp function is performed. Checks +for map leaks. No light information is created, so the map is seen +at "fullbright". Because there are no shadows to get in the +way, this mode is also good for looking for overlapping brushes, +and texture misalignment. + + + +
fastvis - Performs a bsp and a quick version of the vis +process. The entire world is made into a single bsp partition. It's +fast, but when you look in a particular direction, you see every +single detail in that direction. Nothing is blocked. A light map is +created. This mode was used for space maps. + + + +
fullvis - the world is subdivided and broken up +into smaller chunks so you can see only what is logically in your +view. A light map is created. This is what is used to check +polygon-in-view counts. Combined with light extra, it is the final +compile for all maps. + + + +
entities only - When you add or subtract non-brush model +entities from a map, use this compiler. It's very quick. If you +change the brush components of a brush model entity (like a trigger +or a door), you must do a compile that includes a vis stage (fast +or full). If you are only changing the properties, an entities-only +will do. However,, if a brush model entity also has a md3 model +component, the map must be at least fastvis'd for that entity to +appear in the map. + + + +
relight - Use only if no geometry (or light emitting +textures) have been changed. It will rebuild the light map with the +new information. + + + +
(nocurves) - This function is always a modifier to +another bsp command. It does (or doesn't do) what it says. The map +is compiled without curves. + + + +
(nowater) - This function is always a modifier to another +bsp command. The map is compiled without water, lava, or slime. + + + +
(no light) - This function is always a modifier to +another bsp command. No light map is generated. A fast way to check +polycounts. Most often used in conjunction with the novis bsp +command. + + + +
(-light extra) - This function is always a modifier to +another bsp command. A finer degree of subdivision is used to +create a more detailed light map. This is generally only done when +the lighting is going through a final fine-tuning because it takes +a long time. Instead of being calculated in 16 unit increments, the +light is calculated in 8 unit increments. This has no effect on +final map size, only on the time needed to compile. + +

Back | Home | Next + + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/ch12/pg12_1.htm b/docs/manual/Q3Rad_Manual/ch12/pg12_1.htm new file mode 100644 index 00000000..2b79b319 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/ch12/pg12_1.htm @@ -0,0 +1,285 @@ + + +Q3Radiant Editor Manual: Page 12.1 + + + +

Q3Radiant Editor Manual

+
+

Tools 9: Debugging Maps

+ +Regardless of your skills, you can almost guarantee that you are going to make mistakes building your maps. You need tools to help you find and correct those mistakes. There are two classes of map debugging tools usable with Quake III Arena. The first are those that the editor gives you. The second are commands usable in the game. + +

The Editor's Debug Tools

+ +The Q3Radiant editor has some built in debugging tools + +

The Pointfile
+ +One of the most useful tools in the box, this is the "red flag" that warns you about problems with the "hull" or "shell" of the map. When you compile a map, the bsp process checks the integrity of the map hull. If a map has a hole in it's hull or if an entity's origin point is placed outside the map hull, the map will "leak". Quake III Arena maps must be totally contained volumes. They cannot have "leaks" in them. Leaks are openings in the hull between the contained space (or "breathable" as one mapper has described it) and the outer void where nothing can abide. + +

The pointfile appears as a series of points, connected by red line segments, that traces a connecting path between an entity inside the hull and a point in the outside world.. Follow the pointfile through the map and note where it passes out of the enclosed space and into the void. In the case of an entity outside the world, it may just draw a line near the entity. You may need to turn off the display of clip and hint brushes, and curves to find the leaks. Adjust your solid map geometry to close up the leaks. + +

When you save the map (or an auto-save occurs), the pointfile disappears. You can bring the pointfile back by toggling this command. + +

Note: If you use a front-end program for compiling, such as Q3Build, you will need to reload the map file and select the "pointfile" command under the File menu. + +

Next leak spot
+ + +If you have a pointfile displayed in your map, use this command to move from point to point along the file. It's an easy way to move along the path to the point where the red line passes out of the contained space of the map. + +

Previous leak spot
+ +A feature just like "Next leak spot", except that you move backwards along the pointfile. + +

Junk.txt
+The Q3MAP compiler outputs this log file. It logs what the compiler is doing during the process; displays error messages and +gives final compile times for each phase. Because the compiler works in three discrete phases, you can also use this +output to gauge how far along the compile has gone. Edit the project file to change the path to the destination for this +output. + +

Error Messages
+When you compile a map, you are likely to get error messages. Most of these are not serious and the game engine either corrects them or ignores them. This is a sampling of common messages and what you should do about them. + +

Mixed faces: One or more faces on a brush has a surface parameter that conflicts with the other surface parameters. This is not a problem. Putting nodraw or clip on a brush that has a face that draws will cause this. That includes most all "flame" brushes, many water brushes, and just about every instance where alpha-channel textures are used to create see-through brush faces. + +

Bad point to polygon form factor: A curve patch is larger than 512 units in at least one dimension. This is not fatal, but may result in some unusual light artifacts on the curve. + +

Unknown surfaceparm: "nomipmaps" Some shaders contain old or incorrectly spelled parameters. This is not a problem. + +

Too many portals. Your map is broken into too many separate hulls by areaportal brushes. Try to keep the number of +discrete portalled areas under 16. + +

Duplicate plane. During the course of manipulating brushes, you may have moved edges in such a manner that two +adjacent sides of a brush now form a single brush side. Use Find brush to locate the problem brush. Use the old brush as a template or pattern, but build the new one with a single side in the place of the duplicate plane sides. One way to solve the problem is to use the Clipper tool cut off a corner instead of collapsing two faces into one. While this is not a serious problem for multiplayer play, it can create "solid" areas in the bot navigation (.aas) file. This makes the bots think there are walls in places where there appear to be none. You can check for solid areas with the "bot_testsolid 1" inside the game (after creating an .aas file). See the Bot Navigation appendix for more details. + +

******* Leaked *******. There is a hole between the contained space of your map and the outer void. Use the pointfile to locate the problem. + +

Couldn't load baseq3/pics/colormap.pcx trying tools/colormap.pcx...failed! This is not a compile error, +but a loading error. Correct it by checking the hi-color textures setting in Preferences. + +

Loading base_light/light_flare...failed, using default shader. Just ignore this. + +

match token ("{") failed at line [line number]. You broke a shader while editing it. Go closely look at the shader you most recently edited. Chances are you'll find a bracket error in the syntax. + +

In-game Debug tools

+One of the best places to look for errors in your map is within the Quake III Arena game itself. After the map has compiled, +execute your Debug Config and load your map. The commands here will help you discover the errors in your map. + +

General Cheats
+The following are the general Quake III Arena cheat codes (they're actually developer's tools). You can enter them from the console, or bind them to whatever keys you prefer using the syntax bind [key] [command]. If the command is a string with spaces, then the string should be enclosed with quotation marks. + +

give [weapon/item/ammo/health] [amount] // Give selected weapon/item/ammo/health + +

give all // Gives all weapons, ammo, armor, and items + +

god // Godmode + +

noclip // Pass through anything. Use in conjunction with r_fastsky 1 or r_clear 1, or you will have hall of mirror problems when you pass out of the bounds of the map. + +

notarget // Bots think you're a pal viewpos // Outputs player coordinate position and facing angle. + +

General Toggle Binds
+(Thanks to original authors GrandMaMa and Eutectic) +
The following are some binds that you might like handy. Note that some of these will alter saved settings, so make sure that your preferred settings are loaded on startup, like in your autoexec.cfg file. + +

bind "your key" toggle r_speeds // polycount report +
bind "your key" toggle r_showtris // tris triangles +
bind "your key" toggle cg_drawfps // framerate counter +
bind "your key" toggle com_speeds // shows all stats +
bind "your key" toggle r_drawentities // ents won't be drawn +
+ +

Debug Mode: Logfile Creation
+One method that can be used for troubleshooting maps where curious errors occur (usually when simply too much is going on at +once) is to resort to poring over the developer output. The console buffer is limited, and error-producing maps may crash, so printing the output to a logfile is desired. This script allows the toggling of these functions. + +

bind "your key" vstr dbg set dbg vstr debug_1 + +

set developer 0 set logfile 0 set debug_1 "set dbg vstr debug_0;echo DEBUGMODE ON;developer 1;logfile 2" set debug_0 "set +dbg vstr debug_1;echo DEBUGMODE OFF;developer 0;logfile 0"

+ +

GL_Showtris/R_Speeds/FrameCounter Toggle
+(Based in part on an article by orginal author MD) +

The "gl_showtris" and "r_speeds" commands allow you to see the number and location of polygons (surface triangles) in your view. The " + +

Show me the Triangles +Showtris draws a white line around each triangle used to create the world when it is a part of a map's potential viewable set (PVS). This is especially effective tool, since it shows the triangle outlines of map areas that are being "seen" by the engine, which are not always just the ones that the player sees. + +

Depending on your video card, this may work well, or it may not. For some (like the Matrox cards, it comes with a huge performance hit). + +

The Need for (R_) Speeds +This output is one of the more valuable reports you can get on a map. The numbers show you the numbers that can tell you what kind of real visual costs you are encounter. Combined with other commands that turn features like entities, curves, and multi-pass texturing on and off, you can get a realistic idea of where you're having problems. + +

Here's what those cryptic numbers mean. +When r_speeds = 1, the numbers read as follows (where the # sign equals a number) + +

# / # shaders/surfs is the number of shaders in view, followec by the number of surfaces in view. + +

# leafs is how many leaf nodes are potentially visible. + +

# verts is how many vertexes are in view + +

# / # tris is the number of trangles drawn by the renderer in a single pass single pass followed by the number of +triangles drawn by the renderer with all passes. These are the numbers that are most often implied when someone talks about +"r_speeds." If the r_ext_multitexture variable is off, the numbers will reflect a more accurate accounting of the real triangle count (see multi-pass texturing section below). + +

# .## mtex #.## dc [definition under construction] + +

Frame Rate +There is a tendency for rate of frame display to become a sort of god (or at least a "greatest good") for some players. Their quality of play, whether real or psychological, revolves around how fast their computer is flipping through screen updates. Everything else, to them, is throw away. While the design and complexity of a map can affect this, so can many features that are outside of the designer's control. For that reason, frame rate is not a particularly good way to judge the quality of your map. + +

The "cg_drawfps 1" command gives you instantaneous frame rate readout. + +

Use this command string to toggle the three at once. Include the following lines in your Debug Config script: + +

set r_showtris 0 +
set r_speeds 0 +
set cg_drawfps 0

+
bind "your key" "toggle r_showtris;toggle r_speeds;toggle cg_drawfps"
+ +

Lock the PVS Table
+(Author: MD) +
"PVS" means "potential viewable set." The PVS includes all the polygons that can be seen from a particular location in the map (i.e., where you are standing now). The game engine updates what is visible and what is not as you move through the map. You can stop this updating process, and see just how far the engine can see by moving until you find an area of the world that's not being drawn. Use this to debug views where the frame rate drops below an acceptable level. Go to a place where you get a bad "fps" reading. Execute this command. When the PVS Table is locked, you can walk through the map and see exactly how far your view extends. Surfaces in view will be drawn as normal. Non-seen surfaces will show up as the Hall of Mirrors effect (unless the fast sky or r_clear options are also set). Use the information as a guide for changing what can be seen in a view. + +

This command string script toggles the use of the PVS table to let you do this. It also toggles on the r_clear option, so +instead of Hall of Mirrors the void beyond the world is seen in fashion doll pink. + +

set r_lockpvs 0 set r_clear 0 +
bind "your key" vstr lockview set lockview vstr lockview1 +
set lockview1 "set lockview vstr lockview0;echo PVS Locked;r_lockpvs 1;r_clear 1" +
set lockview0 "set lockview vstr lockview1;echo PVS Unlocked;r_lockpvs 0;r_clear 0"
+ +

MultiPass Texturing Toggle
+(Based on an article by original author: MD<) +
The number of triangles that must be drawn before a frame can be displayed affects the speed at which the game is played. More triangles means lower speed. When a texture on a triangle requires additional drawing passes, it is the same as drawing an additional triangle again for each pass of redraw. The ideal video card for the Quake III Arena game is one that has a multi-pass texturing feature. What this means is that the second rendering pass on a texture is essentially free. Its triangle cost is not calculated into the r-speeds. Unfortunately, the map designer cannot plan on every user having such a card and must instead design for worst case scenarios. If you are working on machine that has a multi-pass texturing feature, you will need to find out how the other half plays. You need to toggle the feature off for this. + +

This feature toggles between multi-pass texturing and single-pass texturing. When multi-pass texturing is enabled, the +additional triangles are masked. They won't appear in the r_speeds report. + +

For this feature to work, the video must be restarted. That command is included in the binding. For best results, refrain from pressing the bound key again until the video has re-initialized and the map has re-loaded. Your normal setting for r_ext_multitexture should appear also. In the key binding below, it's been set to a value of 1, which is the most common. This way it will be properly set on startup, since this toggle can hose that setting. + +

set r_ext_multitexture 1 +
bind "your key" "toggle r_ext_multitexture;vid_restart"
+ +

Turning Off Curves and Entities
+How much of the r_speed cost in your map can be attributed to entities. How much to curves? These two commands turn off the +drawing of those entities. The set commands start by setting the features to their "on" condition. + +

bind "your key" toggle r_drawentities // entities won't be drawn +
bind "your key" toggle r_nocurves // curves won't be drawn
+ +

Curves, Caulk, T-Junctions and Cracks

+(From an article on the same by Martin Ka'ai Cluney) + +

During the course of Quake III Arena development, a number of solutions were created to deal with the idiosyncrasies of the compiling process. None of these problems is a game killer, but the presence of these little flaws tends to reduce the professional appearance of game maps. + +

An Explanation of "Z-Fighting"
+"Z-fighting" is caused when the engine tries to simultaneously draw two surfaces that share the same plane. "Z-fighting" +commonly occurs when two brushes with different textures are in the same place (see fig. X-1,) but it can also occur on some video cards when a patch is placed over a textured brush (see fig. X-2.) + +

An Explanation of T-Junction Cracks
+"T-junction cracks" are a little more complicated than 'Z-fighting', and can be more difficult to track down and fix. They +are caused when the vertices (control points) of a curve patch don't match up with surrounding world geometry. They can be caused when a patch extends into the world on one or more sides (see fig. X-3,) or when there is a split in the faces that make up one or more edges of a patch (fig. X-4.) + +

Avoiding T-Junction Cracks and Z-fighting
+The best way to keep maps free of "T-junction cracks" and "Z-fighting" is to keep these problems in mind while adding patches and supporting geometry. There are a few simple methods for adding patches. Initially, they may seem like more work that they're worth, but they will save hours of hunting down and fixing problems that can arise through careless construction. + +
  1. Avoid spanning more than one brush with one edge of a patch. For example, if an inverted bevel is 128 units tall, back it with 128 unit tall caulk brushes. Likewise, if the wall is made up of two vertically stacked brushes; use two +vertically stacked patches of matching heights. + +
  2. Avoid patches that extend into world brushes, unless all of the edges extend into world brushes. When +adding patches, if one edge of the patch extends into the world, while the other edges line up with other brushes, there will most likely be cracking. Sometimes, particularly in the case of 'flesh' elements, it is necessary to extend parts of a patch into the world. In these cases, extend all edges into the world, or into surrounding patches. + +
  3. Be Careful with vertices. Use Snap to Grid. Without it, your curves will create far more problems than they will otherwise might. Sometimes, especially after resizing patches, vertices can get "knocked off" the grid. Always make sure vertices are where they're supposed to be. If needed, patch vertices can always be snapped back to the grid using CTRL+ G. It's always a good idea to be completely aware of where things are in relation to the grid. + +
  4. Caulk, caulk and more caulk. Get into the habit early of building the space behind curve patches with caulk brushes. You will eliminate Z-fighting, seal up the area behind the curves, and unless you are building a map in fashion doll pink, edges that aren't aligned with the curves have a better chance of showing up.
+ +

Here are a few examples of common elements from the maps in Quake III Arena, and how they should (and should not) be built to avoid Cracks and "Z-Fighting": + +

Jump Pads +
Jump pads are probably the most common occurrence of T-junction cracks in Quake III Arena Maps. They usually extend upwards +through at least two 'levels' (layers) of textures, so they're a perfect illustration of proper caulking. They are also a +perfect illustration of 'binding' curves within structural brushes. + +

Flat arches +
Flat Arches are another good example of 'binding' curves with structural brushes. This is a handy technique when incorporating a curve into a complex map element seamlessly. + +

Rounded Wall Edges (endcapped) +
This is a simple example of terminating a wall in a rounded edge. The most important thing to keep in mind here is where +the vertices are placed. If the patch is extended into the ceiling or floor, there will almost certainly be cracks. + +

Inverted Wall Bevels +
Filleting a wall seems like it would be a simple thing, but there are many cases that could cause cracks. It's important +to make sure heights are consistent, especially in the case of layered texturing, as is the case in this example. + +

Finding and Fixing T-Junction Cracks and Z-Fighting
+There will usually be cases where, despite careful building, cracks appear. When looking for cracks that may have been missed, there are three console commands that will be a great help: + +

\r_clear 1: This will clear the frame buffer on each frame, eliminating the Hall of Mirrors effect. + +

\r_fastsky 1: This will draw the sky as a single, solid color, making it easier to see the void behind curves. This makes cracks stand out. Be aware that fastsky also disables the function of portal screens and mirrors. + +

\r_showtris 1: This will draw white lines around all of the triangles in the world, showing exactly how the geometry in the map is affecting the patches. + +

NOTE: Another good way to use these commands is to set them to toggle on a key. The Debug Config below contains these commands as toggles. + +

Turn on r_clear, and r_fastsky, and run through the map, looking at the patches from all possible angles. If there is a crack, turn on r_showtris, and make sure that the patch does not extend into the world, unless it was intended to. Next, look at the surrounding brushes. Make sure that no splits meet the edge of the patch. If neither case is true (it happens these case… 'mystery cracks'), then try a different approach to building the area; perhaps splitting one patch into two, or rearranging the brushes surrounding the patch. When none of the above seems to work, experiment with as many different ways as possible. If something works, keep it in mind for the next time. + +

A Debug Config

+The following script should be copied and pasted into a text file. Save the text file as "debug.cfg". When you want to use +these commands while playing a map, you need to load the map using the console. First type in "/devmap [mymapname] to load the map. Next type in "/debug.cfg". This executes your development configuration. Note that this changes the key assignments of some keys (you define which one is used for each assignment of "yourkey". These debugging tools are considered "cheats." They will not function during normal game play. + +

//+++++++++++++++++++++ +
//toggle on/off frames per second, polygon wireframes, and polygon in view counts with one keypress +
set r_showtris 0 //sets triangle display to off +
set r_speeds 0 //sets triangle counter display to off +
set cg_drawfps 0 //sets frame display counter to off +
bind "your key" "toggle r_showtris;toggle r_speeds;toggle cg_drawfps" + +

//The following are some individual binds for a few debug tools +
set r_drawentities 1 +
set toggle r_nocurves 0 +
bind "your key" "toggle r_speeds" // polycount report +
bind "your key" "toggle r_showtris" // Shows the actual triangles that form the world +
bind "your key" "toggle cg_drawfps" // framerate counter +
bind "your key" "toggle com_speeds" // shows all stats +
bind "your key" "toggle r_fastsky" //turns off detailed sky and turns void to sky color +
bind "your key" "toggle r_clear 1" // This will clear the frame buffer on each frame. + +

//Show coordinates that can be related to map coordinates. +
bind "your key" "viewpos" // Outputs player coordinate position and facing angle. + +

//Turn off Entities and Curves +
bind "your key" "toggle r_drawentities" // entities won't be drawn +
bind "your key" "toggle r_nocurves" // curves won't be drawn + +

//Toggle off the multi-pass texturing feature +
set r_ext_multitexture 1 +
bind "your key" "toggle r_ext_multitexture;vid_restart" + +

//Output console messages to a log file +
bind "your key" vstr dbg set dbg vstr debug_1 +
set developer 0 set logfile 0 set debug_1 "set dbg vstr debug_0;echo DEBUGMODE ON;developer 1;logfile 2" set debug_0 "set dbg vstr debug_1;echo DEBUGMODE OFF;developer 0;logfile 0" + +

//Lock the PVS Table +
set r_lockpvs 0 //turns off any existing PVS lock +
set r_clear 0 //turns "void" bright pink +
bind "your key" vstr lockview set lockview vstr lockview1 //binds three vstr scripts to a key +
set lockview 1 "set lockview vstr lockview 0;echo PVS Locked;r_lockpvs 1;r_clear 1" +
set lockview 0 "set lockview vstr lockview 1;echo PVS Unlocked;r_lockpvs 0;r_clear 0" + +

//Game Cheats (for debugging purposes) +
bind "your key" "give all" // Gives all weapons, ammo, armor, and items +
bind "your key" "god" //toggles god mode //makes player invulnerable to everything but kill triggers +
bind "your key" "toggle noclip; toggle r_clear 1"//toggles ability to pass through walls and clear function +
bind "your key" "notarget" // Bots think you're a pal (until you shoot them) +

+

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/Q3Rad_Manual/gtkrad/pg1_1.htm b/docs/manual/Q3Rad_Manual/gtkrad/pg1_1.htm new file mode 100644 index 00000000..182f2f2a --- /dev/null +++ b/docs/manual/Q3Rad_Manual/gtkrad/pg1_1.htm @@ -0,0 +1,69 @@ + + +Q3Radiant Editor Manual: New functionality in GtkRadiant + + + + + +Better movement in camera window + +

Q3Radiant Editor Manual

+
+

Better movement in camera window

+ +

+By enabling "Freelook in 3D window" in the preferences screen you can use a +noclip style of movement in the camera window. Rightclick in your camera window +(or shift+rightclick if you are in 2 mouse button mode) to start freelook mode. +The mouse can be used to look around, up arrow is forward, down arrow is +backwards, left and right are strafing. You can control the sensitivity of the +camera controls in the preferences screen, directional velocity is for movement +(forward/back/strafe) and angular velocity is mouse sensitivity. Also you can +enable inversed mouse mode here. +

+ +

+Another way of moving backward and forward in the camera window is by using +your mousewheel, scroll up is forward, scroll down is backwards. This works in +all camera modes, classic as well as freelook. +

+ +

Mod support

+ +

+1.1-TA was the first version to add builting support for mod directories, +bringing easy editing capabilities for Quake III: Team Arena. This has been +extended to support any mod developement. Simply open the project settings +dialog to set the mod directory (among several builtins, +Quake III Arena, Quake III: Team Arena and custom mods). +

+ +

Misc functionalities

+ +

+The mousewheel has gotten another new option for the 2D windows. Scroll up is +zoom in, scroll down is zoom out. +

+ +

+It is possible to texture faces simply by selecting a texture in the +texturewindow and dragging it into the 3D (Cam) window onto the face you want +to texture with it. +

+ +

+More GtkRadiant tips and tricks have been gathered on the +qeradiant.com FAQ. +

+ +

Known issues

+ +

+Current known issues for GtkRadiant releases are listed in the +qeradiant.com FAQ. +

+ +

Back | Home | Next + + diff --git a/docs/manual/Q3Rad_Manual/index.htm b/docs/manual/Q3Rad_Manual/index.htm new file mode 100644 index 00000000..45e06e96 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/index.htm @@ -0,0 +1,180 @@ + + +Q3Radiant Editor Manual: Contents + + + + +

+

Q3Radiant Editor Manual

+ +
Based on Version 192 - partly updated to GtkRadiant
+ +

By Paul Jaquays + +

With additional contributions by Astrocreep, Christian Antkow, +
EutecTic, Inolen, Mr. Elusive, Maddog, Martin Ka’ai Cluney, +
Robert A. Duffy, Small Pile of Gibs, Suicide20, and The Dog! + +

Special thanks go out to the members of the Quake3world Editing forum. + +

Your questions prompted many of the sections in this manual. + +

QERadiant.com thanks John Hutton for re-formating this manual into a more +web friendly version. +

+ +

Table of Contents

+Preface +
Introduction +
Minimum System Requirements + + +Installation & set-up + + +Entities and assets + + +New Functionalities in GtkRadiant + + +Map-building basics + + +Tools 1: Selecting and deselecting + + +Tools 2: Working with brushes + + +Tools 3: Working with curve patches + + +Tools 4: Working with textures + + +Tools 5: Working with entities + + +Tools 6: Lights & lighting + +
Tools 7: Miscellaneous commands + + +Tools 8: Compilings maps +
Tools 9: Debugging maps + + +Appendix A: Glossary of Terms +
Appendix B: Entity descriptions + + +Appendix C: Bot navigation files + + +Appendix D: Tips, tricks, and tutorials + + +Appendix E: Online resources + + +Appendix F: Default key shortcuts +
Appendix G: Shortcut keys and mouse functions + + + diff --git a/docs/manual/Q3Rad_Manual/styles/q3rad.css b/docs/manual/Q3Rad_Manual/styles/q3rad.css new file mode 100644 index 00000000..b4daab91 --- /dev/null +++ b/docs/manual/Q3Rad_Manual/styles/q3rad.css @@ -0,0 +1,23 @@ +body { font: 12pt "Times New Roman"; + margin-left: 5mm; + margin-right: 5mm; + text-align: justify; + background: #ffffff; + color: #000000 } +h1 { font: bold 24pt Arial, Helvetica } +h2 { font: bold italic 18pt Arial, Helvetica } +.subheading { font: bold 16pt Arial, Helvetica } +:link {color: blue; + text-decoration: none; } +:visited {color: purple; + text-decoration: none; } +h6 { font: 10pt "Times New Roman" } +.MsoToc2 { font: bold small-caps 12pt "Times New Roman" } +.MsoTitle { text-align:center; + font: bold 24pt "BankGothic Md BT"; + letter-spacing:2.5pt } +.heading { font: italic 10pt "Times New Roman" } +.subcontents { font: 10pt "Times New Roman" } +.tip { font: 10pt "Comic Sans MS" } +.type { font: 10pt "Courier New" } +.menu { font: 10pt Arial, Helvetica } \ No newline at end of file diff --git a/docs/manual/quake3/Compile_Manual/bspc.txt b/docs/manual/quake3/Compile_Manual/bspc.txt new file mode 100644 index 00000000..90fd96d4 --- /dev/null +++ b/docs/manual/quake3/Compile_Manual/bspc.txt @@ -0,0 +1,565 @@ + + +Title: BSP Converter +Version: 2.1h +Date: 2001-03-28 +Author: Mr. Elusive + + +Description +----------- + +The BSPC tool is used to create AAS files from BSP files. +An AAS file is a file with areas used by the Quake III Arena bot in order +to navigate and understand a map. The Quake III Arena maps are stored in +BSP files. + + +Usage +----- + +bspc [- [- ...]] + +Example 1: bspc -bsp2aas d:\quake3\baseq3\maps\mymap?.bsp +Example 2: bspc -bsp2aas d:\quake3\baseq3\pak0.pk3\maps/q3dm*.bsp + +Switches: + bsp2aas <[pakfilter/]filter.bsp> = convert BSP to AAS + reach = compute reachability & clusters + cluster = compute clusters + aasopt = optimize aas file + output = set output path + threads = set number of threads to X + cfg = use this cfg file + optimize = enable optimization + noverbose = disable verbose output + breadthfirst = breadth first bsp building + nobrushmerge = don't merge brushes + freetree = free the bsp tree + nocsg = disables brush chopping + forcesidesvisible = force all sides to be visible + grapplereach = calculate grapple reachabilities + + +Several metacharacter may be used in the filter and pakfilter. + +* match any string of zero or more characters +? match any single character +[abc...] match any of the enclosed characters; a hyphen can + be used to specify a range (e.g. a-z, A-Z, 0-9) + +.pk3 files are accessed as if they are normal folders. For instance +use "d:\quake3\baseq3\pak0.pk3\maps/q3dm1.bsp" to access the +map q3dm1.bsp from the pak0.pk3 file. + +Multiple files may be listed after the switches bsp2map, bsp2aas, reach, +cluster and aasopt. + +If a BSP file is being converted to an AAS file and no output path +is entered on the command-line then the AAS file will automatically +be stored in the same folder as the BSP file. However if the BSP file +was stored in a .pk3 file then the AAS file will be stored in a folder +with the name 'maps' outside the .pk3 file. + + +Updating entity lump +-------------------- + +If an AAS file is already available for a BSP file and you ONLY change +the entities inside this BSP file then you only have to recalculate the +reachabilities. This way you can move items, platforms etc. around +without the need to recalculate the whole AAS file which can save quite +some compile time. You can recalculate the reachabilities as follows: + +bspc -reach mymap.bsp + +Where mymap.bsp is the BSP file. The mymap.aas file has to be in the +same folder as mymap.bsp or should be in the output folder specified +with the -output option. + +Keep in mind that as soon as ANY geometry in the map changes the whole +AAS file HAS to be recalculated in order to play with bots. + +NOTE: -reach does not work on optimized .AAS files! +NOTE: don't use -reach when moving the position of doors. + + +Leaks +----- + +Just like there can be vis leaks in a map there can also be clipping +leaks. Two things can be wrong when the BSPC tool outputs that a map +leaks. + +1. There are no entities in the map at all, or all entities that are +actually in the map are placed in solid. In this case the BSPC tool +outputs "WARNING: no entities inside". (At least a player start entity +is needed to load a map.) + +2. There is a spot in the map where players can go outside the map +into the void. This is bad, players should never be able to fall out +of a level. In this case the BSPC tool outputs "WARNING: entity +reached from outside". The BSPC tool also writes a mymap.lin file +that can be loaded in the Q3Radiant editor to show lines that go +through the actual leak. + +Make sure the .lin file is stored in the same folder as where q3radiant +stores the .bsp file. Load the map in q3radiant and use the +menu -> File -> Pointfile... to load the .lin file. A thick red line +will be shown in the map. Follow this line to find the leak. + + +Map bounds +---------- + +Currently a map should be within the bounds (-65536, -65536, -65536) - +(65536, 65536, 65536) for the bspc tool to compile. These are the same +limits the q3map tool has. + + +Physics +------- + +The player bounding box is a 30 units by 30 units square with a height +of 56 units. If we assume 1.75 meters being the average height of a human +and a player in Quake III Arena being 56 units high we get 32 units = 1 meter. + +Maximum step height of a player is 18 units (just keep steps 16 units or +lower). + +The maximum water jump height for bots has been set to 18 units. (height +difference between water surface and the floor jumping onto). If the +waterjump height is made higher human players will have a hard time getting +out of the water. + +With normal gravity and without the quad the maximum rocket jump height is +around 280 units (you can sometimes jump a few units higher but this is a +safe value for reference). + +The maximum height for barriers the bots will jump on is 32 units. + +Some math to calculate some other values of interest: + +gravity = 800; +jump velocity = 270; +max vertical rocketjump velocity = 670; +max run velocity = 320; +max step height = 18; + +max jump height = 0.5 * gravity * (jumpvelocity/gravity)*(jumpvelocity/gravity); +max jump height = 45 units; +NOTE: even though this is the mathematical maximum jump height always keep +the the 32 units maximum barrier height for bots in mind when building maps. + +maximum horizontal jump distance over a gap from one spot to another both +at the same height: + +t = sqrt((maxjumpheight + maxstep) / (0.5 * gravity)); +t = 0.3986 seconds; +dist = maxrunvelocity * (t + jumpvelocity / gravity); +dist = 235 units; +Because players use a bounding box we can jump a full bounding box width +furter in the ideal case. (15 units at the jump start and 15 at the +landing place). +235 + 15 + 15 = 265 units. +Again this is the mathematical maximum which players can only reach under +ideal circumstances. + + +Optimizing a map for bspc +------------------------- + +Hint brushes have no effect on the bspc tool. Only solid, clip, liquid, +cluster portal and do not enter brushes are used by the bspc tool. + +The bspc tool outputs how many areas are created for a map. Less areas +is better. Often the number of areas can be reduced by adding additional +clip brushes. By adding these additional clip brushes the complexity +of the geometry used for collision can be reduced. Do not add clip +brushes in front of the complex geometry but get the complex shaped +geometry contained within these clip brushes. Things that should be +contained within clip brushes are small or complex shaped (often detail) +brushes and complex and twisted curves, but also more regular curves +can be placed within a clip brush. When containing a curve within a +clip brush it's preferred to place the whole curve within the clip +brush (not just part of the curve). +Note: you can make brushes or curves non-solid when they are contained +within *full* clip or *weap* clip brushes to speed up bspc calculations. + +Always try to align your geometry to the grids. Always use the largest +grid possible for alignment of your geometry. Also try to align the +back sides of brushes which may not be visible. The more brush sides +are aligned the better. This will also speed up bspc calculations. + +Align adjacent brushes as much as possible. Make sure no tiny faces are +created due to badly aligned brushes. + +Quite often there are places in a map that are visible to players +but that players can never get to. Players would be able to walk around there +but since players can never reach such places they will never actually +move around there. If players are never able to get to such places +it's better to put a large clip brush which encloses that whole space. +This will also speed up bspc calculations and reduce the number of areas +created by the bspc tool. + +Note: the number of areas relative to the map size tells something about +the navigation complexity for players in general (also human players). +Reducing the collision complexity for bots also makes the map easier to +navigate for human players + + +func_plat and func_bobbing +-------------------------- + +When func_plat or func_bobbing entities are placed in a map the bots will +use them if possible. The bots assume they can stand on top of the bounding +box of the model used for the func_plat or func_bobbing entity. As a result +creating complex shaped func_plat or func_bobbing models is mostly a bad +idea. You have to make sure the bots (and players) can actually stand +everywhere ontop of the bounding box of the model. + + +Cluster Portals +--------------- + +A map is divided into areas. Several of these areas can be grouped together +to create a cluster. The clusters are seperated by cluster portals which are +areas themselves. One of the things the bot uses these clusters for is a +multi-level routing algorithm. When a map is efficiently divided up into +clusters bot calculations will be faster. + +several things to take into account: + +- The BSPC tool tries to create cluster portals automatically but additional + cluster portals can be created by placing "clusterportal" brushes. +- Cluster portals are manually created by placing "clusterportal" brushes + inside the map. +- Cluster portal brushes are a tool to optimize a map for CPU usage by the + bots. They are not needed for the bots to operate correctly. +- The "clusterportal" brushes should not be used outside the world hull. +- The cluster portals do not have any effect on vis. +- If a door is already sealed with an areaportal brush, a clusterportal is + not necessary there. (area portals are also used as cluster portals). +- Just like the area portals, the cluster portals must seal a space off + entirely from other areas. +- The cluster portal areas should seal off a cluster in a way that the only + path towards another cluster is through a cluster portal area. +- Only create cluster portals where people can walk or swim through. +- Don't create cluster portals in gaps in the floor. (people would fall through) +- If you have two sealed off clusters and you add a teleporter between them + then the two clusters will be merged again because of the teleporter. +- Cluster portals must seperate no more and no less than two (2) clusters. +- Try to create clusters with all the same number of 'reachability' areas. + for instance if the map has 5400 areas try to create 10 clusters with 540 + areas each, or 12 clusters with 450 areas each, etc. The BSPC tool lists + the number of reachability areas in each cluster. + With Q3A version 1.25 and up you can use /set bot_testclusters 1 on the + console and the area number and cluster number you're in will be printed + on the screen. These cluster number correspond to the cluster numbers + the BSPC tool prints. +- Minimize the number of clusters with only a few (less than 10) areas. +- When adding "cluster portal" brushes try to place them in places with + minimal geometric complexity. For instance place them inside convex door + openings or small hallways (not infront of door openings). Ideally the shape + of the face through which a player walks or swims into the cluster portal + is the same as the shape of the face through which a player leaves the + cluster portal. Also ideally the open space inside the cluster portal + brush is convex. +- Make cluster portals about 16 or 32 units thick or align them with + adjacent geometry. Don't make them too thick though. +- Minimize the total number of cluster portal areas at all times. The more + cluster portal areas you have the more CPU the bots need. +- Items have no effect at all on the creation of areas or clusters. + The same goes for item_botroam. + + +Do Not Enter areas +------------------ + +When bot navigation problems show up or you want to make sure a bot never tries +to go to a certain place "do not enter" brushes can be used. + +several things to take into account: + +- The "do not enter" brushes should not be used outside the world hull. +- The "do not enter" brush is Not a clip brush for the bot. +- The "do not enter" brush is a tool of last resort. Do not use it unless + there are serious navigation problems. +- The number of "do not enter" brushes should be minimized because these + brushes create additional areas for the bots. +- The "do not enter" brush will create a New area that the bot will try to + avoid. However if the bot somehow ends up in a "do not enter" area or there + is a valid goal inside the "do not enter" area then the bot is allowed to + go into and out of that area. So if the bot somehow gets in a "do not enter" + area the bot will be able to get out. + + +Bot roaming +----------- + +The item_botroam entity can be used when a bot does not roam the whole level +or prefers to go to only specific areas. This (invisible) item can be placed +in a map just like regular items. Nobody can actually pick up the item it's +only used to attract bots to certain places of the map. The item_botroam has +a key "origin". The value is set by Q3Radiant automatically. The item_botroam +also has a key "weight". The value is the weight of the roam item and is +relative to the weight of other items in the map. The bot character specific +item weights are stored with the bot characters in the botfiles/bots/ sub-folder +in the .pk3 file. The value of the weight is a non-zero floating point value, +most often in the range 0 to 400. (Higher values are allowed but keep in mind +that the bot should also still go for normal items, so don't make the +item_botroam weight to high.) + +When a bot should never go for a specific item the key "notbot" with value "1" +can be used for that item. This key with value can be used for every available +item in Quake III Arena. + +The suspended flag can be used on all items (item_botroam included). +However keep in mind that when a suspended item is not anywhere near the +ground the bot will ONLY try to go for this suspended item using jump pads. + + +Team based entities +------------------- + +You can use the "bot_notteam" entity key with value "1" or "2" on teleporters +(trigger_teleport or trigger_multiple pointing at a target_teleporter), +elevators (func_plat), cyclic movers (func_bobbing), jumppads (trigger_push) +and areas that hurt the player (trigger_hurt). +When "notteam" is set to "1" only bots using the travel flag TFL_NOTTEAM1 will +use the entity or move through the area. When "bot_notteam" is set to "2" only +bots using the travel flag TFL_NOTTEAM2 will use the entity or move through the +area. These travel flags can be used in the game source code. Using this entity +key also only has effect if the mod the map is being made for supports team based +navigation for bots. + + +Testing AAS files +----------------- + +One of the easiest ways to test the AAS file is to load the map in +Quake3 in teamplay mode (type /set g_gametype 3 on the console before +loading the map). Enter a team and add a bot to your team. Use the +team order menu (by default bound to the key F3) to command the bot +to follow you. Walk around the map and see if the bot is able to +follow you everywhere. + +Map bugs can sometimes cause certain places in the map to show up +'solid' in the AAS file. The bots cannot travel through these 'solid' +areas. To test for these 'solid' places set the cvar bot_testsolid +to 1 on the console. (type /set bot_testsolid 1) The map has to be +started with devmap instead of map before the cvar bot_testsolid can +be set. When the cvar is set to 1 then either "empty area" or +"SOLID area" will be printed on the screen while traveling through a map. +Several map bugs can cause these 'solid' places in the AAS file. +- Sometimes microscopic brushes are left over after a brush CSG. Search + for such brushes in the problem area and delete them. +- Tiny brush faces (not curves) can also cause problems. Due to vertex + snapping in the q3map tool those tiny brush faces can be snapped out + of existence. Such faces will not show up in Quake3 and you'll see + tiny peek holes or slits where you can view through the geometry. + Allign vertexes of and edges of adjacent brushes to remove and avoid + such tiny faces. Placing a clip brush in front of the face that is + snapped out of existence will also remove the 'solid' area but ofcourse + it's much better to remove the peek holes and slits. +- Another cause could be a brush with a collapsed side. Check how many + sides a brush has and how many sides actually have a surface. Rebuild + brushes with collapsed sides. +- All faces contained within liquid brushes using a shader without + "surfaceparm trans" set will be removed. Those contained surfaces will + not be visible and can cause the liquid to appear "solid" in the AAS file. + +If you insist creating an AAS file for a map with bugs then the option +-forcesidesvisible can be used. This should fix all the problems with areas +showing up solid in the AAS file. However creating an AAS file with this +option takes a lot longer (often more than twice the normal compile time). + +Clusters can be tested with the cvar bot_testclusters. +(type "/set bot_testclusters 1" on the console) + +Jumppads can also be tested. Type the following on the Quake3 console +before loading your map: + +/set bot_maxdebugpolys 1024 +/set bot_visualizejumppads 1 +/set bot_forcereachability 1 + +Now load the map. A counter will be shown and goes from 0% to 100%. +When the counter has reached 100% type /set bot_debug 1 and +/set r_debugSurface 2 on the console. For every jumppad the +default arch of travel (without using air control) will be visualized. +This only works if your .aas file is not optimized. + + +Error messages +-------------- + +Level designers should not worry too much about the following messages and/or warnings. The things reported are non fatal and won't cause any major problems. Some of the messages are just debug left overs. + +"AAS_CheckArea: area %d face %d is flipped\n" +"AAS_CheckArea: area %d center is %f %f %f\n" +"AAS_CheckFaceWindingPlane: face %d winding plane unequal to face plane\r\n" +"AAS_CheckFaceWindingPlane: face %d winding reversed\r\n" +"area %d face %d flipped: front area %d, back area %d\n" +"area %d face %d is tiny\r\n" +"face %d and %d, same front and back area but flipped planes\r\n" +"AAS_SplitFace: tiny back face\r\n" +"AAS_SplitFace: tiny back face\r\n" +"AAS_SplitArea: front area without faces\n" +"AAS_SplitArea: back area without faces\n" +"gsubdiv: area %d has a tiny winding\r\n" +"AAS_TestSplitPlane: tried face plane as splitter\n" +"found %d epsilon faces trying to split area %d\r\n" +"AAS_SplitArea: front area without faces\n" +"AAS_GetFace: face %d had degenerate edge %d-%d\r\n" +"AAS_GetFace: face %d was tiny\r\n" +"WARNING: huge winding\n" +"bogus brush after clip" +"split removed brush" +"split not on both sides" +"two tiny brushes\r\n" +"possible portal: %d\r\n" +"portal %d: area %d\r\n" +"WARNING: CM_GridPlane unresolvable\n" +"WARNING: CM_AddFacetBevels... invalid bevel\n" +"WARNING: CM_SetBorderInward: mixed plane sides\n" +"WARNING: bevel plane already used\n" +"trigger_multiple model = \"%s\"\n" +"trigger_teleport model = \"%s\"\n" +"found a trigger_push with velocity %f %f %f\n" +"AAS_TraceBoundingBox: stack overflow\n" +"AAS_TraceAreas: stack overflow\n" +"AAS_LinkEntity: stack overflow\n" +"MergeWindings: degenerate edge on winding %f %f %f\n" +"Warning: MergeWindings: front to back found twice\n" +"FindPlaneSeperatingWindings: winding1 non-convex\r\n" +"FindPlaneSeperatingWindings: winding2 non-convex\r\n" + + +When one of the following messages, errors or warnings is found then there is often something to be fixed. + +"WARNING! HashVec: point %f %f %f outside valid range\n" +"This should never happen!\n" + While storing the AAS file some vertex was found outside the valid map bounds. When this happens some part of the map is likely to have badly aligned brushes or weird shaped curves. Clipping off or rebuilding complex shapes often helps. +"trigger_push start solid\n" + The trigger_push start point is in solid. Try making the trigger_push brush a bit larger or move it around a bit. +"trigger_push without target entity %s\n" + Could not find the target entity of the trigger_push with the target field %s. +"trigger_push without time\n" + trigger_push entity found without "time" field. +"trigger_multiple not in any jump pad area\n" +"trigger_push not in any jump pad area\n" + A trigger_push entity was found not to be in any valid jumppad area. (the message states trigger_multiple but it should have been trigger_push) Try making the trigger_push brush a bit larger or move it around a bit. +"trigger_multiple at %1.0f %1.0f %1.0f without target\n" + A trigger multiple was found at the given coordinates without a "target" field. +"target_teleporter without target\n" + A target_teleporter entity was found without target field. +"trigger_teleport at %1.0f %1.0f %1.0f without target\n" + A trigger_teleport entity was found at the given coordinates without "target" field. +"teleporter without misc_teleporter_dest (%s)\n" + The destination of a teleporter with target field %s could not be found. +"teleporter destination (%s) without origin\n" + A teleporter destination with the target name %s was found without origin field. +"teleporter destination (%s) in solid\n" + A teleporter destination with the targetname %s was found to be in solid. +"teleported into slime or lava at dest %s\n" + A player would be pushed into slime or lave at the teleporter destination with the targetname %s. +"trigger_multiple not in any area\n" + A teleporter trigger was found not to be in any valid area. Try moving the trigger around a bit. +"func_plat without model\n" + A func_plat entity was found without model field. +"func_plat with invalid model number\n" + A func_plat entity was found with the model field set to some invalid number. +"func_bobbing without model\n" + A func_bobbing entity was found without model field. +"func_bobbing with invalid model number\n" + A func_bobbing entity was found with the model field set to some invalid number. +"%s in solid at (%1.1f %1.1f %1.1f)\n" + An item with classname %s was found to be in solid at the given coordinates. +"empty aas link heap\n" + Some part of the map has some rather complex clipping. Reduce the geometric complexity or use clip brushes to reduce the clipping complexity. +"too many entities in BSP file\n" + There are too many entities in the bsp file. +"error opening %s\n" + Could not create a new AAS file. Hard disk might be full. +"error writing lump %s\n" + Could not write an AAS lump to file. Hard disk might be full. + + + +Version Changes +--------------- + +2.1h (2001-03-28) + +- fixed crash bug + +2.1g (2001-02-18) + +- added bot_notteam support on trigger_hurt entities + + +2.1f (2001-02-06) + +- added some AAS statistics +- don't flood through faces when creating clusters + + +2.1e (2001-01-10) + +- fix map size limitation + + +2.1d (2000-12-17) + +- renamed "notteam" to "bot_notteam" + + +2.1c (2000-11-02) + +- added fs_maxfallheight +- compiled with larger map size bounds + + +2.1b (2000-09-15) + +- fixed cfg file loading + + +2.1 (2000-06-28) + +- added model numbers for AREACONTENTS_MOVER +- added team based func_plat, func_bobbing, trigger_teleport and trigger_push reachabilities + + +2.0 (2000-06-21) + +- fixed swim reachabilities +- fixed some reachabilities through cluster portals +- fixed jump reachabilities +- changed some start travel times +- added travel time settings to cfg + + +1.9 (2000-03-27) + +- fixed func_bobbing entities with origin brush + + +1.8 (2000-01-14) + +- fixed trigger_teleport bug. +- increased max map bounds to (-8192, -8192, -8192)-(8192, 8192, 8192) +- increased max points on winding +- made "HashVec: point x y z outside valid range" non-fatal +- fixed rocket jump reachabilities +- added force sides visible option +- increased simulated stack size for area traces + + +1.7 (1999-12-22) + +- fixed ducked bounding box size +- fixed sv_maxsteepness being zero in aas configuration +- AAS files are now automatically stored in BSP file folder +- fixed crash bug caused by overflow of a simulated stack diff --git a/docs/manual/quake3/Compile_Manual/cfgq3.c b/docs/manual/quake3/Compile_Manual/cfgq3.c new file mode 100644 index 00000000..b3694bef --- /dev/null +++ b/docs/manual/quake3/Compile_Manual/cfgq3.c @@ -0,0 +1,78 @@ +//=========================================================================== +// BSPC configuration file +// Quake3 +//=========================================================================== + +#define PRESENCE_NONE 1 +#define PRESENCE_NORMAL 2 +#define PRESENCE_CROUCH 4 + +// more bounding boxes can be added if required +// always minimize the number of bounding boxes listed here to reduce AAS file size +// for instance if players cannot crouch then it's good to remove the bbox definition for it + +//bounding box when running/walking +bbox //30x30x56 +{ + presencetype PRESENCE_NORMAL + flags 0x0000 + mins {-15, -15, -24} + maxs {15, 15, 32} +} + +// bounding box when crouched +bbox //30x30x40 +{ + presencetype PRESENCE_CROUCH + flags 0x0001 + mins {-15, -15, -24} + maxs {15, 15, 16} +} + +// do not forget settings as they might not be defaulted correctly when this cfg is used +settings +{ + // physics settings + phys_gravitydirection {0, 0, -1} // direction of gravity + phys_friction 6 // friction + phys_stopspeed 100 // stop speed + phys_gravity 800 // gravity + phys_waterfriction 1 // friction in water + phys_watergravity 400 // gravity in water + phys_maxvelocity 320 // maximum run speed + phys_maxwalkvelocity 320 // maximum walk speed (set for running) + phys_maxcrouchvelocity 100 // maximum crouch speed + phys_maxswimvelocity 150 // maximum swim speed + phys_walkaccelerate 100 // acceleration for walking + phys_airaccelerate 0 // acceleration flying through the air + phys_swimaccelerate 0 // acceleration for swimming + phys_maxstep 18 // maximum step height + phys_maxsteepness 0.7 // maximum floor steepness a player can walk on + phys_maxwaterjump 19 // maximum height for an out of water jump + phys_maxbarrier 33 // maximum barrier a player can jump onto + phys_jumpvel 270 // jump velocity + phys_falldelta5 40 // falling delta for 5 damage ( see PM_CrashLand in game/bg_pmove.c ) + phys_falldelta10 60 // falling delta for 5 damage ( see PM_CrashLand in game/bg_pmove.c ) + // reachability settings + // the following are all additional travel times added + // for certain reachabilities in 1/100th of a second + rs_waterjump 400 + rs_teleport 50 + rs_barrierjump 100 + rs_startcrouch 300 + rs_startgrapple 500 + rs_startwalkoffledge 70 + rs_startjump 300 + rs_rocketjump 500 + rs_bfgjump 500 + rs_jumppad 250 + rs_aircontrolledjumppad 300 + rs_funcbob 300 + rs_startelevator 50 + rs_falldamage5 300 // avoid getting 5 damage + rs_falldamage10 500 // avoid getting 10 damage + // if != 0 then this is the maximum fall height a reachability can be created for + rs_maxfallheight 0 + // maximum height a bot may fall down when jumping to some location + rs_maxjumpfallheight 450 +} diff --git a/docs/manual/quake3/Compile_Manual/headskins.txt b/docs/manual/quake3/Compile_Manual/headskins.txt new file mode 100644 index 00000000..2418fd6b --- /dev/null +++ b/docs/manual/quake3/Compile_Manual/headskins.txt @@ -0,0 +1,75 @@ +search orders with different settings + + +===================== +NON-TEAMPLAY +===================== + +------------------------------------------------- +headmodel = *callisto/lily + +models/players/heads/callisto/lily/head_default.skin +models/players/heads/callisto/head_lily.skin + + +------------------------------------------------- +headmodel = callisto/lily + +models/players/callisto/lily/head_default.skin +models/players/callisto/head_lily.skin +models/players/heads/callisto/lily/head_default.skin +models/players/heads/callisto/head_lily.skin + + + +===================== +Q3 TEAMPLAY +===================== + +------------------------------------------------- +team_headmodel = *callisto/lily +team = red + +models/players/heads/callisto/lily/head_red.skin +models/players/heads/callisto/head_red.skin + + +------------------------------------------------- +team_headmodel = callisto/lily +team = red + +models/players/callisto/lily/head_red.skin +models/players/callisto/head_red.skin +models/players/heads/callisto/lily/head_red.skin +models/players/heads/callisto/head_red.skin + + + +===================== +TA TEAMPLAY +===================== + +------------------------------------------------- +team_headmodel = *callisto/lily +team = red +teamName = Stroggs + +models/players/heads/callisto/lily/Stroggs/head_red.skin +models/players/heads/callisto/Stroggs/head_red.skin +models/players/heads/callisto/lily/head_red.skin +models/players/heads/callisto/head_red.skin + + +------------------------------------------------- +team_headmodel = callisto/lily +team = red +teamName = Stroggs + +models/players/callisto/lily/Stroggs/head_red.skin +models/players/callisto/Stroggs/head_red.skin +models/players/callisto/lily/head_red.skin +models/players/callisto/head_red.skin +models/players/heads/callisto/lily/Stroggs/head_red.skin +models/players/heads/callisto/Stroggs/head_red.skin +models/players/heads/callisto/lily/head_red.skin +models/players/heads/callisto/head_red.skin diff --git a/docs/manual/quake3/Compile_Manual/index.html b/docs/manual/quake3/Compile_Manual/index.html new file mode 100644 index 00000000..aabf7b16 --- /dev/null +++ b/docs/manual/quake3/Compile_Manual/index.html @@ -0,0 +1,65 @@ + + + + + Compiling Manual + + + + + + + +
+
+
+ + +
+

Compiling Manual, q3map & bspc help

+
+
+ +

+ Table of Contents +

    + · + Q3Map Documentation + +
    · + BSPC Documentation + +
    . + BSPC Configuration file + +
    . + modelskins: Q3 and TA search order for model skins + +
    . + headskins: Q3 and TA search order for head skins + +
+

+ +
+ + +
+ Last updated: Jan 21, 2002   +
+
+ +
+
+ + + diff --git a/docs/manual/quake3/Compile_Manual/modelskins.txt b/docs/manual/quake3/Compile_Manual/modelskins.txt new file mode 100644 index 00000000..6c253559 --- /dev/null +++ b/docs/manual/quake3/Compile_Manual/modelskins.txt @@ -0,0 +1,73 @@ +search orders with different settings + + +===================== +NON-TEAMPLAY +===================== + +------------------------------------------------- +model = hunter/harpy + + +legs: + models/players/hunter/lower_harpy_default.skin + models/players/hunter/lower_harpy.skin + models/players/characters/james/lower_harpy_default.skin + models/players/characters/james/lower_harpy.skin +torso: + models/players/hunter/upper_harpy_default.skin + models/players/hunter/upper_harpy.skin + models/players/characters/hunter/upper_harpy_default.skin + models/players/characters/hunter/upper_harpy.skin + + +===================== +Q3 TEAMPLAY +===================== + +------------------------------------------------- +team_model = hunter/harpy +team = red + +legs: + models/players/hunter/lower_harpy_red.skin + models/players/hunter/lower_red.skin + models/players/characters/hunter/lower_harpy_red.skin + models/players/characters/hunter/lower_red.skin +torso: + models/players/hunter/upper_harpy_red.skin + models/players/hunter/upper_red.skin + models/players/characters/hunter/upper_harpy_red.skin + models/players/characters/hunter/upper_red.skin + + +===================== +TA TEAMPLAY +===================== + +------------------------------------------------- +team_model = james/badass +team = red +teamName = Stroggs + +legs: + models/players/james/Stroggs/lower_badass_red.skin + models/players/james/Stroggs/lower_red.skin + models/players/james/lower_badass_red.skin + models/players/james/lower_red.skin + models/players/characters/james/Stroggs/lower_badass_red.skin + models/players/characters/james/Stroggs/lower_red.skin + models/players/characters/james/lower_badass_red.skin + models/players/characters/james/lower_red.skin +torso: + models/players/james/Stroggs/upper_badass_red.skin + models/players/james/Stroggs/upper_red.skin + models/players/james/upper_badass_red.skin + models/players/james/upper_red.skin + models/players/characters/james/Stroggs/upper_badass_red.skin + models/players/characters/james/Stroggs/upper_red.skin + models/players/characters/james/upper_badass_red.skin + models/players/characters/james/upper_red.skin + + + diff --git a/docs/manual/quake3/Compile_Manual/q3map.html b/docs/manual/quake3/Compile_Manual/q3map.html new file mode 100644 index 00000000..b1aaba23 --- /dev/null +++ b/docs/manual/quake3/Compile_Manual/q3map.html @@ -0,0 +1,410 @@ + + + + + Q3Map Manual + + + + + +

Q3map Manual

+ +
+ + + + +
+

q3map command line switches:

+
+q3map
+-----
+
+-threads <number>
+	Number of threads used to compile the map. For the fastest compile
+	times the number of threads is set to the number of system processors.
+-glview
+	Write a .gl file of the bsp tree for debugging.
+-v
+	Output verbose information.
+-draw
+	Enable realtime debug drawing output.
+-nowater
+	Water, slime and lava brushes are not compiled and won't show up when running the map in Quake.
+-noopt
+	unused.
+-nofill
+	unused.
+-nodetail
+	Detail brushes are not compiled and won't show up when running the map in Quake.
+-fulldetail
+	Detail brushes will be treated as normal brushes.
+-onlyents
+	Only change the entities in a .bsp using a .ent file.
+-onlytextures
+	Only change the textures in a .bsp file.
+-micro
+	unused.
+-nofog
+	Visible surfaces that cross fog boundaries will not be split along the bound.
+	This can cause visually incorrect fog in the map.
+-nosubdivide
+	Visible surfaces are not subdivided as required by shader tesselation.
+	The shader parameter "tesssize" sets the tesselation of a surface.
+-leaktest
+	Only test the map for leaks. If a leak is found the compilation is stopped.
+-verboseentities
+	Output verbose information about entity sub-models.
+-nocurves
+	Curves are not compiled and won't show up when running the map in Quake.
+-notjunc
+	T-junctions are not fixed. This can cause tiny slits where a surface meets halfway another surface.
+-expand
+	Expands all the brush planes and saves a new map out to allow visual inspection of the clipping bevels
+-tmpout
+	Output files to a folder called "tmp".
+-fakemap
+	Write out a fakemap.map This map will contain a worldspawn entity with all the world brushes.
+-samplesize <N>
+	Set the lightmap pixel size to NxN units. Default 16x16.
+-custinfoparms
+	Will enable custom surface flags (see below)
+
+q3map -vis
+----------
+
+-threads <number>
+	Number of threads used to compile the map. For the fastest compile
+	times the number of threads is set to the number of system processors.
+-fast
+	Only calculate a very loose visiblity list. It doesn't take much time to
+	calculate but a lot more polygons will be drawn by the Q3 engine than necesary.
+-merge
+	Merge bsp leaves before calculating the visibility list. This will speed up
+	the vis calculations but mostly more polygons will be drawn by the Q3 engine
+	than necesary.
+-nopassage
+	Disable the passage visibility algorithm. The passage vis is faster and a bit more
+	tight than the old algorithm.
+-level
+	unused.
+-v
+	Output verbose information.
+-nosort
+	Don't sort the portals on complexity. Sorting mostly speeds up visibility calculations
+	because more complex portals can use information from less complex portals.
+-saveprt
+	Don't delete the .prt file after creating the visibility list.
+-tmpin <path>
+	Input files will be read from a folder called "tmp".
+-tmpout <path>
+	Output files will be written to a folder called "tmp".
+
+
+q3map -light
+------------
+
+-threads <number>
+	Number of threads used to compile the map. For the fastest compile
+	times the number of threads is set to the number of system processors.
+-bounce <N> [NEW]
+	Enable radiosity calculation. Rediffuses the light emitted onto surfaces N
+	times. Will write out the BSP after every pass, so it can be cancelled.
+	Light reflected is the lightmap/vertex * texture color, subsampled to a certain
+	granularity across every lit surface. Use q3map_lightimage in a shader
+	to override the reflected color.
+-bouncegrid [NEW]
+	Radiosity affects lightgrid (entity lighting).
+-fast [NEW]
+	Enables light envelopes for area lights, speeding light up by 50x or more on
+	some maps. Has the side effect of dimmer maps with large numbers of dim surface
+	lights.
+-fastgrid [NEW]
+	Same as fast, but only for lightgrid calculation.
+-fastbounce [NEW]
+	Enables fast for radiosity passes only.
+-cheap [NEW]
+	Stop calculating light at a sample when it exceeds (255, 255, 255). This may
+	produce odd artifacts on maps with lots of saturated colored lighting. Also,
+	do not use -cheap with radiosity if you wish to preserve all light emitted.
+-cheapgrid [NEW]
+	Same as cheap, but only for lightgrid calculation.
+-area <scale>
+	This scales the light intensity of area lights.
+-point <scale>
+	This scales the light intensity of point lights.
+-notrace
+	No light tracing is performed. As a result no shadows will be casted.
+-patchshadows
+	Enable patches casting shadows.
+-novertex
+	Don't calculate vertex lighting.
+-nogrid
+	Don't calculate light grid for dynamic model lighting.
+-smooth [NEW]
+	Smart version of -extra. Only subsamples lightmap pixels that are shadowed.
+	Produces results comparable to -extra in roughly 1/3 the time. Can also be
+	used with -extra or -extrawide for 16- or 48-tap sampling respectively
+	(smoother shadows).
+-extra
+	Take four samples per lightmap pixel and store the average light value of these
+	four samples for the actual lightmap pixel.
+	This super sampling is used for anti-aliasing.
+-extrawide
+	Just like -extra four samples per lightmap pixel are calculated. However the
+	average of 12 samples is stored per lightmap pixel.
+-samplesize <N>
+	Set the lightmap pixel size to NxN units. Default 16x16.
+-border
+	Create a debugging border around the lightmap.
+-v
+	Output verbose information.
+-nosurf
+	Disables surface tracing (detail brushes and patches) for shadow calculation.
+-dump
+	Dumps prefab files when used with radiosity for each bounce.
+
+
+q3map -vlight
+-------------
+
+-threads <number>
+	Number of threads used to compile the map. For the fastest compile
+	times the number of threads is set to the number of system processors.
+-area <scale>
+	This scales the light intensity of area lights.
+-point <scale>
+	This scales the light intensity of point lights.
+-novertex
+	Don't calculate vertex lighting.
+-nogrid
+	Don't calculate light grid for dynamic model lighting.
+-nostitching
+	No polygon stitching before lighting.
+-noalphashading
+	Don't use alpha shading at all.
+-nocolorshading
+	Don't use colored alpha shading. The alpha channel will be used as if it were binary.
+	The light goes through or not and does not change color.
+-tracelight
+	Use the "-light" light algorithm for all surface unless a surface
+	uses a shader with the shader option "q3map_vlight".
+-samplesize <N>
+	Set the lightmap pixel size to NxN units. Default 16x16.
+-v
+	Output verbose information.
+
+ + + +

The q3map options are a subset of the shader instructions that require +recompiling of the map.

+ +

q3map_bounce <fraction>

+

      [NEW] +Specify a number between 0 and 1.0 (or higher) to scale the amount of light reflected in radiosity passes. +Default: 1.0

+ +

q3map_nofast

+

      [NEW] +Surfaces that emit light with this shader parameter will disable -fast optimisation. Useful for +large areas of dim sky where you want all the dim light to reach all surfaces.

+ +

q3map_tracelight

+

      [NEW] Surfaces using a shader with this option will always be lit with the +original "-light" light algorithm. Patches will not cast shadows on +this surface unless the shader option q3map_patchshadows is used.

+

q3map_patchshadows

+

      [NEW] When this option is used in conjunction with the original (-light) +lighting algorithm, surfaces with textures modified by this option will will +show shadows cast by curve patches (under normal circumstances, curve patches do +not cast shadows).

+

q3map_vertexshadows

+

      [NEW] By default, no shadows are cast on vertex-only lit surfaces (see +surfaceparm pointlight). Also when running Quake III Arena in vertex  lighting +mode, no shadows are cast upon any surfaces (shadows are part of the light map). +When using this shader option shadows *will* be cast on the surface when vertex +lit. However sharp shadow edges won't be seen on the surface because light +values are only calculated at the vertexes.

+

q3map_novertexshadows

+

      [NEW] Shaders used for misc_models and terrain can now use +q3map_novertexshadows to disable shadows to be cast at the vertex lit surfaces. +Shadows being cast at small misc_model objects often makes sense. However +shadows on large vertex lit terrain surfaces often look bad. By default no +shadows are cast at forced vertex list surfaces ( shaders with "pointlight" +).

+

q3map_forcesunlight

+

      [NEW] No sunlight is cast at vertex lit md3 models and terrain by default. +Using this option sunlight (overbright bits created by q3map_sun option) will be +cast on these surfaces.

+

q3map_vertexscale <scale>

+

      [NEW] The light value at the vertexes of a surface using a shader with this +option is multiplied by the scale value. This is a way to lighten or darken a +vertex light only surface in comparison to other, light-map lit surfaces around +it.

+

q3map_notjunc

+

      [NEW] Surfaces modified by a shader with this option are not used for +tjunction fixing.

+

q3map_vlight

+

      [NEW] Surfaces modified by a shader with this option will always be lit with +the "-vlight" algorithm when q3map is used with the options "-vlight +-tracelight".

+

q3map_lightmapsamplesize <S>

+

      [NEW] Surfaces using a shader with this shader option will use lightmaps with +pixel size SxS. This option can be used to produce high resolution shadows on +certain surfaces or can be used to reduce the size of lightmap data where high +resolution shadows are not required.

+

q3map_lightimage <image>

+

      Image to use for the light color of a surface light instead of the image(s) +used by the shader. Color is averaged from the texture. Texture must be the same +size as the base image map.

+

q3map_surfacelight <value>

+

Sets the amount of light this surface emits.

+

q3map_lightsubdivide <value>

+

      A surface light is subdivided into a bunch of point lights for the actual +lighting of the world. This parameter controls the space between those point +lights. Default value is 120.

+

q3map_backsplash <percent> <distance>

+

      A surface light is also lit by itself using back splash point lights with a +lower intensity. The <percent> parameter specifies the intensity +percentage they use from the q3map_surfacelight <value> parameter. The +<distance> parameter controls the distance of these back splash lights +from the surface. You can set the <percent> to zero or a negative value to +disable the back splash lights.

+

      q3map_globaltexture

+

When this option is set the texture is not aligned to the world.

+

      q3map_backshader <shader>

+

<shader> is the path/name of the shader or texture to be used at the +back side of the surface.

+

      q3map_flare <shader>

+

Creates a flare using the specified <shader> at the center of the +surface using a shader with this option.

+

      light <value>

+

Old style flare specification always using the shader "flareshader". +The <value> parameter is unused.

+

      q3map_sun <red> <green> <blue> <intensity> +<degrees> <elevation>

+

Color will be normalized, so it doesn't matter what range you use. The +intensity falls off with angle but not distance. A value of 100 is a fairly +bright sun.

+

      degree of 0 = from the east, 90 = north, etc.

+

      elevation of 0 = sunrise/set, 90 = noon

+

      surfaceparm pointlight

+

Surfaces using a shader with this parameter will always be vertex lit

+

This option can be used to reduce the lightmap data. Often used on surfaces

+

that don't need any shadows.

+ + +

Surfaceparm dust

+

If a player lands (jumps onto) on a surfaces using a shader with this +parameter, a put of dust will appear at the player’s feet. Note that the +worldspawn entity of that map must have an enableDust key set to a value of 1. +Note: This surfaceflag has been replaced by "surfaceparm woodsteps" in +Return to Castle Wolfenstien.

+ + +

Custom surfaceparms

+
+

With the new q3map tool you can add custom surface parameters for mods +without the need to recompile the q3map tool. These custom surfaceparms are +stored in a file called ‘custinfoparms.txt’ in the folder scripts/. An +example of this file with the new surfaceparm treacle and surfaceparm grass is +shown below.

+

// Custom Infoparms File
+// Custom Contentsflags
+{
+treacle 0x4000
+}
+// Custom Surfaceflags
+{
+grass 0x80000
+}

+

 

+ +

NOTE: For linux users, when using the -custinfoparms parameter q3map +first looks in your homedir, and only if it doesn't find a custinfoparms.txt +there, it uses the one stored in the

+

quake3 install dir (usually /usr/local/games).

+

 

+
+

Content Flags

+
+

Contents flags are flags similar to CONTENTS_FOG in the original Q3A. These +flags define the contents of volumes inside the game (for instance lava, fog, +water, etc.).

+

If you look in the source file game/surfaceflags.h, it has defines for all +contents flags. The define is split into a name and a hexadecimal value, for +instance CONTENTS_PLAYERCLIP 0x10000. These hexadecimal values are powers of 2 +and can be ored together (binary) to form a bit mask. Up to 32 contents flags +can be ored together this way.

+ +

Example: creating a volume with treacle.

+

The following outlines how a custom contents flag can be added and used in a +mod. First open the ‘custinfoparms.txt’ file and add ‘treacle 0x4000’ +to the Custom Contentsflags section as shown in the example file above (0x4000 +is one of the unused values available for custom use). Next write a shader +script which uses ‘surfaceparm treacle’. Apply this new shader to all sides +of a brush in a test map. When you compile the map, add the -custinfoparms +parameter to the command line following q3map.

+

Next, add CONTENTS_TREACLE 0x4000 to the source file game/surfaceflags.h in +your mod. Now you can call the point contents function. If the point is inside +the brush with the shader using the ‘surfaceparm treacle’ then the point +contents call will return a bit mask with CONTENTS_TREACLE set. This can for +instance be used to slow down player movement when a player is inside such a +brush.

+

 

+
+

Surface Flags

+
+

The surface flags are texture properties that often affect entities in +contact with surfaces using such flags. The ‘surfaceparm metalsteps’ +parameter from Q3A is a good example.

+

If you look in the source file game/surfaceflags.h, it has defines for all +surface flags. The define is split into a name and a hexadecimal value, for +instance SURF_NODAMAGE 0x1. These hexadecimal values are powers of 2 and can be +ored together (binary) to form a bit mask. Up to 32 surface flags can be ored +together this way.

+ +

Example: Making ‘footsteps on grass’ sounds

+

The following outlines how a custom surface flag can be added and used in a +mod. First open up the ‘custinfoparms.txt’ file and add 'grass 0x80000' to +the Custom Surfaceflags section as shown in the example file above (0x80000 is +the first available unused value in surfaceflags.h for surface flags). Next +write a shader script which uses a grass image and has 'surfaceparm grass’. +Create a test map with the grass shader covering the ground surface. When you +compile the map, add the -custinfoparms parameter to the command line following +q3map.

+

Next, add SURF_GRASS 0x80000 to the source file game/surfaceflags.h in your +mod. Now you'll be able to execute a trace and the trace information will be +returned in the trace_t structure. If the trace hits a surface with the grass +surfaceparm then the SURF_GRASS flag will be set in trace_t->surfaceFlags. +Such a trace can be used to trigger playing a sound of a person stepping on +grass. For a reference example, see the existing metal steps in the game code.

+

 

+
+

 

+ +
+ + + +

 

+
+ +

 

+

 

+

-27-

+ + + + diff --git a/docs/manual/quake3/Model_Manual/model_manual.htm b/docs/manual/quake3/Model_Manual/model_manual.htm new file mode 100644 index 00000000..3af5ebd5 --- /dev/null +++ b/docs/manual/quake3/Model_Manual/model_manual.htm @@ -0,0 +1,217 @@ + + + +Q3A Player Characters: Putting them in the Game + + + +
+

Putting New Models in Quake III Arena

+ +Based on original notes by Paul Steed + +

Edited by Paul Jaquays
+

Edited 12/22/99 by ps
+

QERadiant.com thanks John Hutton for re-formating this manual into a more web friendly version
+

+
+The purpose of this document is to explain how to set up a model for Quake 3 Arena, create the necessary animation and conversion files, and then export it into the MD3 format required by the game. It is intended to be informative only and not a tutorial on building or animating models. + +

The player models for Quake III Arena were built using the commercial modeling software, 3D Studio Max R2.5 (3ds Max) by +Kinetix. These models were then animated using Physique and Biped, components of a plugin for 3dsMax called Character Studio +(also by Kinetix). The following instructions assume that you will model and animate with 3dsMax and Character Studio. + +

1. Setting up the Files

+Begin in your Quake3 directory. If you don't have one already, create a baseq3 directory. Inside the baseq3 directory, create a models directory. Inside the models directory, create a players directory. Inside the players directory, create a directory with the name of your model (we will use [character] in this document to represent information requiring the name of the model). It is generally a good idea to create a 'work' directory under [character] so that the [character] directory itself remains uncluttered. Place all versions of your model and temp textures here, saving the [character] directory purely for the finished model files. + +

2. Building and Naming the Mesh

+The mesh should be built keeping in mind the game engine needs three distinct body part grouping: the head, the upper body, and the lower body. These groupings can consist of different parts or sub-objects, but keep in mind too many sub-objects does impact performance and game play speed. A good rule of thumb is to consolidate your objects (i.e. attach them to each other) as long as they remain a part of a major group. For example, you decide to create a character that has its arms as separate objects for easier animation. Unless the arms or torso has different textures assigned to them go ahead and attach the arms to the torso. It may be more difficult to assign the vertices to the biped skeleton later on, but the efficiency of the model is much better. However, if you must keep the limbs detached for unique shader assignment then keep the following naming conventions in mind: + +

2.1 Head Geometry

+All head geometry needs to begin with lower case 'H_' (h_head, h_glasses, h_hat, etc...). Keep in mind that the head has no +animations itself other than to respond to player mouse-look input. + +

2.2 Upper Body Geometry

+All upper body geometry needs to begin with lower case 'U_' (u_torso, u_arms, u_abdomen, etc.) This is your model's torso and arms. The individual animations for the upper body are listed below. + +

2.3 Lower Body Geometry

+All lower body geometry begins with lower case 'L_' (l_hips, l_legs, l_lfoot, l_rfoot, etc...). This is your model's buttocks, legs and feet. The individual animations for the upper body are listed below. + +

2.4 Tags

+Tags are connection points for other model parts and represent the limited hierarchical system of the game. They include links between the three character body parts and the weapons. Keep in mind that these tags are representations of geometry so they can be animated to represent that geometry. For example, tag_head represents the head, tag_torso represents the torso and tag_weapon represents the weapon. This is important to understand since for example, any time the character is performing a locomotive animation, the upper body can and will animate independently of the lower body, using the relative position of the tag as a base or 'home' position. The tags for the body parts and weapons are named tag_weapon, tag_torso and tag_head. + +

3. Texturing

+Once you finish building your character go ahead and attach it to your biped and do some basic test animations to make certain the mesh doesn't deform in weird ways. Turn edges, ad faces, whatever you need to do to make sure that while animating, the character retains its mesh integrity. Handing the mesh over to another artist to assign UVW's or assigning and texturing yourself without testing the animation integrity of the mesh is very risky. Major modifications after UV assignment can cost you valuable time resulting in re-assigning not just the UV's, but re-attaching the mesh to your biped as well. Once your model is ready, go ahead and apply the texture to it. Typically the textures used in Q3A consist of one 256 x 256 texture for the body and one 128 x 128 texture for the head. Keep in mind that it's best to consolidate your texture on a single page rather than break it up into smaller pages. Also some video cards cannot process a texture size larger than 256, so making a high-rez 1024 x 512 texture just won't be seen since the card will knock it down to +256 x 128 to digest it. + +

4. Set Up for Animation

+Once the character is textured or skinned, bring the mesh back into 3dsMax (2.5) and attach it to an adjusted Biped using the Character Studio plug-in. As a rule of thumb, it's always better to just assign the mesh to the biped using the default +settings and then manually assign vertices to appropriate skeletal 'limbs'. + +

5. Animation

+When animating the character, keep all animations in one file. It's crucial that the animations adhere to a specific order that pertains to the separate body parts as this supports our current tag system. + +

Basically the order of animations goes: full body (animations that combine both upper and lower), upper body, and lower body. Each character file has the following animations in them and for now that's all the modeler is allowed. The division is basically death (all body parts), extraneous upper body, and dedicated locomotive animations. That way all the upper body animations can be performed at any time, separate from whatever it is that that lower body animations may be doing. There is a set number of animation types which are (in order): + +

  • death1 (approx. 30 frames) +
  • death2 (approx. 30 frames) +
  • death3 (approx. 30 frames) + +

  • taunt (approx. 45 frames) +
  • weapon attack (exactly 6 frames) +
  • melee attack (exactly 6 frames) +
  • change weapon (exactly 9 frames) +
  • weapon idle (exactly 1 frame) +
  • melee idle (exactly 1 frame) + +

  • crouched walk (approx. 10 frames) +
  • walk (approx. 15 frames) +
  • run (approx. 12 frames) +
  • backpedal (approx. 10 frames) +
  • swim (approx. 10 frames) +
  • jump forward (approx. 10 frames) +
  • jump forward-land (approx. 6 frames) +
  • jump backward (approx. 10 frames) +
  • jump backward-land (approx. 6 frames) +
  • standing idle (approx. 10 frames) +
  • crouched idle (approx. 10 frames) +
  • turn in place (approx. 8 frames)
+ +

A good rule of thumb is to create an idle pose at the frame right after the final death frame. Keep this pose for the +entire lower body and center of mass of the biped up through melee idle frame since any animation by the lower body during these frames will not register during the grab process. Similarly, once the animations for the lower body start, copy the pose for the upper body at the weapon idle frame to the first frame of the crouched walk animation and don't animate the upper body at all after that frame. This allows you to more closely approximate what happens during the game where the upper body is basically just along for the ride as the lower body carries it along via the tag_torso. + +

Keep in mind that an animation.cfg has to be generated for each character that is a direct reflection of your animation file above. + +

6. Setting up Tags

+After the modeler is satisfied with the animations for the character, it's time to bring in the tags that up until now, have +kept in a separate file. This is milestone mark that lets the modeler know that the character is nearly complete. 'Merge' +the tags into your scene. Turn off 'inherit scale' for the tags under the hierarchy/link command panel in Max. Then, +assign a Physique modifier (Character Studio), linking them to specific areas in the biped: + +

tag_torso is linked to the Biped 'pelvis' +
tag_head is linked to the Biped 'head'. +
tag_weapon is linked to the right 'hand'. + +

6.1 Animate Body Tags

+Now, go in and actually animate the tag_torso so that it matches the default position (established previously at +approximately the standing idle frame- from the top view it looks like a perfect 90 degree triangle with the base half as wide as the length, pointing forward) when appropriate. "Appropriate" means that as the character goes through the lower body animations, if the triangle is pointing anywhere else but forward, the upper body will point that way as well since to the code the upper body IS the tag. This works out to the modeler's advantage, though because even if the upper body LOOKS crazy in the animation you simply rely on the tag representation to compensate for it. + +

6.2 Handling Weapon Tags

+Tag_weapon is a bit different. Basically there is no difference between view model weapons (the weapon as seen by the player when it is in use by his or another player) and the world model weapons (weapons as they are found rotating in the maps) in Quake III Arena. However, for visually clarity and identification, they are doubled in scale when they become seen as world models. They are the same object. This reduces the number of models needed the game and creates an overall more efficient system. Unfortunately a drawback to the system is that there can be only one firing animation for the character. Thusly all weapons need to fit within the grip of the character regardless of size or geometry. This also makes it impossible to see hands on your weapons or otherwise perform vertex animation on the weapons other than barrel rotations vis the tag system (tag_barrel). +

Since the placement is always the same for the character's hands on the weapons , create the animations to the point where it begins the weapon attack sequence. Then merge one of the weapon models into the character file as a guide. The weapons have a nested triangle of same dimensions as the tag_head and tag_torso triangles (each weapon in the game has this triangle saved with it. Move the weapon into a horizontal firing position (using the side view) to about where the character would be holding the weapon correctly. Then move the character's hands into the appropriate position and link the weapon to the character's right hand. + +

When you get to the point where you bring in the tags, make a snapshot of the weapon, hide the original and simply delete all the vertices and faces of the copy of the weapon object except for the nested triangle. Rename it tag_weapon, turn off the 'inherit scale' attributes (very important), and assign Physique to it (linking it to the 'right hand' of the biped) and voila. Ready to export. + +

Level of Detail

+Each of the Quake III Arena player characters have a base model and two lower polygon versions of the model (to help with speed issues). For use in the game, the three levels of detail are file formatted as follows: + +

+ + + + + + + + + + + + +
[character].[file extension]This is the highest detail model for close up viewing
[character]_1.[file extension]This is a slightly lower polygon model for mid distance viewing
[character]_2.[file extension]This is the lowest polygon model for long distance viewing.
+ +

Level of detail means you need to make three versions of your model to get the best performance during gameplay. Each +version needs to have the same textures assigned and same animations assigned to them in order to work in the game. The +numbers you need to shoot for are 800 faces for the highest level, 500 faces for next level and 300 for the lowest level. This works out roughly to be a 60% drop in each LOD, but your numbers will vary in order to maintain mesh integrity. Most LOD's created in Q3A were done with the plugin called MRM (multiple resolution mesh) by Intel. The stock Optimize modifier or manual optimization techniques can be applied. + +

8. Exporting

+Once the tags are in place (also with the Physique modifier attached to them) the model is ready to export to an ase(ascii) +file. To make the models available for use in Quake III Arena, the model was exported to a native 3dsMax ASCII format +file called an '.ase' file. This export option in Max has several check boxes to tweak and then just exports the character +with its animation data (via Character Studio) to a huge ase/ascii file. Under 'Output Options' make sure the 'Mesh Definition', 'Materials', 'Transform Animation Keys', and 'Animated Mesh' boxes are checked. Under 'Mesh Options' and 'Object Types' make sure 'Mapping Coordinates' and 'Geometric' are the only boxes checked, respectively and let it run. Your 'Time Configuration' must reflect a '0' starting point up through the last frame of your animation. The native Max exporter will rely on the time configuration as a guide on which frames to actually grab during the conversion process. Of course there will be better exporters available in the future…this is just how it was done for the characters in Q3A. + +

9. Animation Config File

+The character's animations are controlled by an 'animation.cfg' file where the model maker specifies reference frames and frame rates. The animation.cfg file is a text file (originally created with MS Excel) which contains the frame and animation sequence data. Place this in the model's directory. Note, when the modeler is testing the model in Quake III Arena, changes to the animation.cfg can be made without having to re-grab the model…just do a 'vid_restart' at the cvar command line +prompt. + +

Edit an animation.cfg file which matches the frame/animation sequences and place it in the character's directory. Each animation can have different frame rates that the modeler can tweak, save out in the animation.cfg, hit 'vid_restart' to see the change right away in the game (no need to re-grab the model). The file for visor is shown here below in it's entirety. You may clip this portion of the file out and use it as the basis for your own animation files. + +

+////////////////////////////////////////////////////////////////////////////////
+
+// animation config file
+
+sex		m
+
+headoffset	0 0 0
+footsteps	normal
+
+// first frame, num frames, looping frames, frames per second
+
+0	30	0	25	// BOTH_DEATH1
+29	1	0	25	// BOTH_DEAD1
+30	30	0	25	// BOTH_DEATH2
+59	1	0	25	// BOTH_DEAD2
+60	30	0	25	// BOTH_DEATH3
+89	1	0	25	// BOTH_DEAD3
+90	40	0	20	// TORSO_GESTURE
+130	6	0	15	// TORSO_ATTACK (MUST NOT CHANGE -- hand animation is synced to this)
+136	6	0	15	// TORSO_ATTACK2 (MUST NOT CHANGE -- hand animation is synced to this)
+142	5	0	20	// TORSO_DROP (MUST NOT CHANGE -- hand animation is synced to this)
+147	4	0	20	// TORSO_RAISE (MUST NOT CHANGE -- hand animation is synced to this)
+151	1	0	15	// TORSO_STAND
+152	1	0	15	// TORSO_STAND2
+153	8	8	20	// LEGS_WALKCR
+161	12	12	20	// LEGS_WALK
+173	9	9	18	// LEGS_RUN
+182	10	10	20	// LEGS_BACK
+192	10	10	15	// LEGS_SWIM
+202	8	0	15	// LEGS_JUMP
+210	1	0	15	// LEGS_LAND
+211	8	0	15	// LEGS_JUMPB
+219	1	0	15	// LEGS_LANDB
+220	10	10	15	// LEGS_IDLE
+230	10	10	15	// LEGS_IDLECR
+240	7	7	15	// LEGS_TURN
+
+//////////////////////////////////////////////////////////////////
+ +

10. The Conversion Process

+ +The models need to be run through id's custom md3 conversion/'grabber' program. The program uses the information in the Quake Data text file ([filename].qdt) to grab and convert the 3dsMax files. + +

10.1 The Conversion File

+ +Create a "Quake Data" text file for the model with the extension ".qdt". The contents for our [character].qdt file would read something like: + +

$asecanimconvert models/players/[character]/[character].ase -playerparms 92 155 +
$asecanimconvert models/players/[character]/[character]_1.ase -lod 1 -playerparms 92 155 +
$asecanimconvert models/players/[character]/[character]_2.ase -lod 2 -playerparms 92 155 + +

+This is the grabber program executable. + +

+ +This is the path to the model's .ase file. The program looks for files starting in your Quake3\baseq3 directory. + +

+This tells the converter that this is the first level of reduced detail for the model. The value "-lod 2" is for the second, +or lowest level of detail for the model. + +

+This tells the converter which frame the upper body anims only start (first value) and which frame the lower body only anims start (second value). The numbers here are only used as examples + +

10.2 Run the Conversion

+When the qdt file is set up correctly, run the grabber by opening MSDOS command prompt, going to the quake3 directory +containing the model files and typing in 'q3data [character].qdt' + +

11. Review the Model

+Load up Quake 3 Arena. Go to map Q3DM0 (or any map containing a mirror). Bring down the console and type "\model +[character name]". Hit your Show Score key (default is TAB). You should see your new model here. Tweak the frame rates in +your animation.cfg file and save them. Type in "\vid_restart" on the console and hit enter to see the changes. + + + + + diff --git a/docs/manual/quake3/Model_Manual/styles/q3rad.css b/docs/manual/quake3/Model_Manual/styles/q3rad.css new file mode 100644 index 00000000..b4daab91 --- /dev/null +++ b/docs/manual/quake3/Model_Manual/styles/q3rad.css @@ -0,0 +1,23 @@ +body { font: 12pt "Times New Roman"; + margin-left: 5mm; + margin-right: 5mm; + text-align: justify; + background: #ffffff; + color: #000000 } +h1 { font: bold 24pt Arial, Helvetica } +h2 { font: bold italic 18pt Arial, Helvetica } +.subheading { font: bold 16pt Arial, Helvetica } +:link {color: blue; + text-decoration: none; } +:visited {color: purple; + text-decoration: none; } +h6 { font: 10pt "Times New Roman" } +.MsoToc2 { font: bold small-caps 12pt "Times New Roman" } +.MsoTitle { text-align:center; + font: bold 24pt "BankGothic Md BT"; + letter-spacing:2.5pt } +.heading { font: italic 10pt "Times New Roman" } +.subcontents { font: 10pt "Times New Roman" } +.tip { font: 10pt "Comic Sans MS" } +.type { font: 10pt "Courier New" } +.menu { font: 10pt Arial, Helvetica } \ No newline at end of file diff --git a/docs/manual/quake3/New_Teams_For_Q3TA/index.html b/docs/manual/quake3/New_Teams_For_Q3TA/index.html new file mode 100644 index 00000000..75046c9c --- /dev/null +++ b/docs/manual/quake3/New_Teams_For_Q3TA/index.html @@ -0,0 +1,2258 @@ + + + + + + + + +New Teams For Q3TA + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
+

 

+
+

New + Teams for Team Arena (and other stories)
+ By Paul Jaquays Script files by various id design team members Bot Search Material by Jan Paul “MrElusive” + van Waveren

+
+

 

+
+

 

+
+

Table + of Contents
+ Introduction
+ The Team Pak
+ Scripts
+ User Interface Assets
+ In Game Team Logo Icons
+ New Models for Team Skins
+ Appendix A: The .Bot File
+ Appendix B: The .Team File
+ Appendix C: The Voice List
+ Appendix D: Model Sound List
+ Appendix E: .VC File Sample
+ Appendix F: Sample Team Arena Animation.Cfg + File and New Animation Commands
+ Appendix G: Teamname.shader
+ Appendix H: Search Order for Model and Head model Assets
+ Appendix I: Expanded Team Skin Functionality for Q3A
+ Appendix J: Contents of the tm_kreechurs.pk3
+ Appendix K: A Minimal Team
+ Appendix L: Contents of the TAhead_lily.pk3

+
+

 

+
+

 

+
+

Introduction
+ The original intent for Teams in Quake III: Team Arena was to allow the use + and creation of new Teams. However, it was not until community modelers attempted + to build new teams that we discovered that the hooks that we put in place for + team creation did not work as intended. This point release contains the fixes + and additions necessary to make new teams work.

+

This document presupposes + that the person wanting to create a new team already knows the basics of + creating, animating, and skinning new character models for Quake III Arena. + There are numerous good tutorials on-line covering both the basics and the + more in-depth skills needed to make models that work inside the game.

+

Special Thanks
+ The content used to test and debug the team creation code is based on a test + model provided and made “Team Arena compatible” by Bill and Mike Jukes, + a.k.a. “The Brothers Grimm” and a re-skinning of the original Team Arena Callisto head model provided by artist Camilla “milla” Bennett. Also thanks to milla + for providing the .html version of this document. Names of some of the files + used in examples have been changed. Furthermore, thanks go to Graeme Devine, + Robert Duffy, and MrElusive for putting up with + semi-constant harassment to get the team content working for the point + release.

+

Notices: QUAKE III ARENA and QUAKE III: Team + Arena are trademarks of id Software, Inc. This + document is copyright 2000, 2001 by id Software, Inc. Id Software grants + permission to redistribute and or redisplay this document in electronic form + only. It may not be included as a part of any permanent media without first + obtaining permission from id Software, inc. Permission is granted to use the + contents of the scripts embedded in this document as a base for creating + additional teams for Team Arena.
+

+

TOP

+

The Team Pak File
+ It takes a surprisingly large amount of new content to create an entirely new + team. Our test file contained 186 separate files (model included only one + head). An additional head added another 16 files (we tested with only one + extra head model). The content required covers every discipline of game + creation … skin painting, scripting, modeling, and sound production. In fact, + if the new team is to have new voice taunt sounds, it can easily exceed 10 + megabytes in compressed form inside the pak file. + Each of the files necessary to create a team is listed below in outline and + will be discussed later in detail. The paths for these files begin in the missionpack directory. Appendix J + contains the file list for the test team, Appendix K + shows a team with the bare minimum of files needed to create a new team with + a male and female uniform, and Appendix L contains the + file list for the Callisto/Lily test head.

+

Naming Conventions
+ When naming a pak file that contains the assets for + a new team, preface the team name with the letters + “tm_”. This usage is for organizational purposes only. It is done to identify + the pak as a team file. Example: tm_kreechurs.pk

+

Including What id Didn’t Make
+ You don’t need to include any of the game content + that id put in the original pak0.pk3 that shipped with Team Arena. The game + should have no problem finding those assets if they are called for by the new + team. Any new assets created for the team need to be in the pak file. Any assets created by other artists or authors + for use with Team Arena need to be in the pak file. + The team creator cannot assume that players will have those assets in their + possession. When including assets created by others, including modified id + game content, be sure to give notice of original + authorship in the readme that accompanies the pakfile.

+

Teamname_readme.txt
+ This text file tells all about the contents of your new team, including who + made it, how they can reach the author, who else contributed to the project, + what tools were used, how long it took, when it was released (copyright data + goes here), where the ideas came from, and so on. Essentially, it should + contain whatever the team creator wants to reveal about himself + or herself and the process of making the team. Any resources that were + created by others should be acknowledged here. If the team creator agrees to + let others use the original contents of the pak + file in other projects, it should be noted here also, along with any special + terms or contact information.

+

NOTE: The scripts used to create the + various aspects of the new team are included throughout this document. Team + creators have permission to copy the scripts in this document and paste them + into new scripts for use in original teams. Details such as team name, + character names, and bot names should be changed to + fit the new team.

+

TOP

+

Scripts
+ Priority: Unless otherwise noted, all of the scripts listed below are + required to be in the team pak file (see Appendix K: A Minimal Team, for a detailed list of the + contents required for a basic team using existing models).

+

These are the various + scripts used to define the team and model characteristics.

+

Teamname.team (in root directory) : A text file that defines the components of the team. This file + corresponds to the original team.txt file in pak0.pk3. It is required for all + new teams. See Appendix B for details.

+

Teamname.bot (scripts\) : This file defines the resources + used by the five bots that are used by the team in single player (model, head_model, and bot a.i.). It is required for all new teams. See Appendix A for details.

+

Teamname.shader (scripts\) : Shader + scripts for all shaders used to create the new_model and the five new_headmodels. + This is required for the team icons to work properly in game. Other shader-modified textures may be included. See Appendix G for the sample version of this shader.

+

Animation.cfg (models\players\newmodel\) : The animation configuration file. + Team Arena models have a few a few more animation sequences than their Q3A + counterparts, but the basics are the same. The contents of a sample Q3:TA animation.cfg are included + at the end of this document. It’s a script, but not + one that’s resident in the scripts file. This is + only required if a new model is included in the pak. +

+

New_model.voice (scripts\) : This is the script that assigns + individual voice wav files to specific message or status commands. See + Appendix C for a sample script and discussion of its use. Voice files are + optional and only required if an entirely new set of voice wav files is to be + included in the pak. Sound files are large and can + add significantly to the size of the pakfile. If + creating a human-based team, consider using the 8 voices that came with Team + Arena to save file space.

+

New_headmodel_1.vc + (scripts\) : This file selects which .voice file is linked to a head + file. Each head model in the pak needs one of + these. A separate version of this file is required for each new headmodel included with the team. The name of the file is + the same as the name of the bot that uses the headmodel. A sample .vc file is + included in Appendix E.

+

TOP

+

User Interface + Assets
+
Priority: The tga files are required. The roq + file is optional. The User Interface menus use these files to show the team + logo icons and movies of the characters in actions.

+

Teamname, of course, refers to the name of + the new team.

+

Teamname_name_alt.tga (ui\assets\) : This is a 256 x 128 pixel, 32 bit .tga file + (with alpha channel) depicting the name of the team as a black and white + (grayscale) art file. Teamname is the name of the + new team, the rest of the filename is part of its format. The alpha channel should + be the same as the image (not reversed).

+

Teamname_name.tga (ui\assets\) : This is a 256 x 128 pixel, 32 bit .tga file + (with alpha channel) depicting the name of the team with a glow around it. It + is a black and white art file (grayscale). The alpha channel should be the + same as the image (not reversed).

+

Teamname.tga (ui\assets\) : This is a 128 x 128 pixel, 32 bit .tga file + (with alpha channel) that depicts a black and white version of the team logo + or symbol. The alpha channel should be the same as the image (not reversed).

+

Teamname_metal.tga (ui\assets\) : This is a 128 x 128 pixel, 32 bit .tga file + (with alpha channel). If the team creator wants to keep the same style as the + original game, this version of the team’s logo is + rendered to look like brushed metal, perhaps with a bluish cast. But in + reality, it can be anything, any color. The alpha channel should be the same + as the alpha channel in the Teamlogo.tga art.

+

Teamname.roq (ui\assets\) : The .roq movie displays in the center area + of the player set up screen when the player selects one of the teams. Movie + file sizes can be large, so the team creator may wish to take the overall + size of the team pakfile into consideration before + including a movie. Uncompressed, the team movies in Team Arena were over a + megabyte each … and being compressed format files already; they don’t get much smaller in the pakfile. + The good news is that if no movie file is present, the game displays the teamname_metal.tga in the center area instead. It must be + noted that team movie files will not be offered for viewing in the Cinematics menu option unless the teamname.roq + file is also present in the video\ directory.

+

TOP

+

In Game Team Logo + Icons
+ Priority: Required

+

The team style game maps + for Team Arena are usually set up to display the icons of the competing + teams. The game uses a separate set of art files located in the team_icon directory off the root missionpack + directory for the team icons displayed in game. For Team Arena, these art + files were a single color, red or blue. But that need not be the case. If a + game clan wanted to use a full color version of their clan symbol, it would + work in game - though the team creator may want to consider tinting the art + either bluish or reddish to better suit the color used in play (most team + maps are likely to use the blue/red color theme as was done in the original + game).

+

Also, take into + consideration that the art will be transparent, with background textures + (floors, walls, colored banners) showing through behind it. Simple, graphic + treatments of logos will probably work the best in all cases.

+

Art files can be larger or + smaller than those shown here. However, while having smaller files will save + memory, image quality will suffer. If using larger art files, image quality + may improve substantially but the memory usage will be substantial also. + Whether increasing or reducing file size, remember to keep the file dimension + proportional to the original.

+

The Teamname.shader + references this art. Make sure that the file names in the shader + match those of the artwork.

+

Teamname.tga (team_icon\): + This is a 128 x + 128 pixel art file, the exact same file as used in ui\assets\teamname.tga. + It is a black and white 32 bit version of the team logo with the same art in + the alpha channel.

+

Teamname_blue.tga (team_icon\): + For Team Arena, we + created solid color logos, but that need not be the case. This 32 bit 128 x + 128 pixel art file can be full color. The alpha channel should be the same as + the teamname.tga file. If you choose to make it + solid blue, consider using the same color value as the original TA logos. The + RGB formula for that blue is: 0 148 255.

+

Teamname_red.tga (team_icon\): + Even though id + chose to make our logo’s single, solid colors, this + 32 bit 128 x 128 pixel art file can be whatever color the team creator + wishes. The alpha channel should be the same as the teamname.tga + file. If you choose to make it solid red, consider using the same color value + as the original TA logos. The RGB formula for that red is: 255 0 0.

+

TOP

+

New Models and Skins + for Teams
+ The process by which body models are created is outside the scope of this + document. While body model has a few more animations than the corresponding + Quake III Arena model, the process of creation is quite similar … except for + one very key element. The Team Arena model has no head. Head models for Team + Arena teams are created and stored separately from the body. Where the + pathname to a body model might be models\players\BoB, + the path to the head models is different:

+

Example: models\players\heads\Kreecha.

+

New Team Arena Models + based on Q3A models +
+ For the Team Arena test model, the Brothers Grimm converted a character model + that they had previously made for Quake III Arena. In order to keep the game + from confusing two models with the same file name, the search code for models + and skins was changed to allow extended search paths for models. In this + case, we placed the Team Arena model in a “characters” directory nested + within the “players” directory. The path to the new model read: + models\players\characters\BoB\. The model directory + contains the torso and legs models only, which are Upper.md3 and Lower.md3 + respectively. There are no head models in that directory. Furthermore, + include any art and skin files used for the default version of the model + along with the animation.cfg.

+

NOTE: When creating your models for + export as .ASE files for use with the Q3data.exe, you must have a head on the + model (e.g.; an h_head in the max file) for the + converter to work. The converter looks for and expects to see an h_head for of the model. If the converter does not find + the head during the conversion, the process will halt. After the conversion + is complete just use the Upper and lower Md3 files for that character’s directory. Place the head model in its own + separate directory.

+

Icons for new models
+ The Loading Screen for Team Arena uses the icons associated with a team member’s body model, not the member’s + head model. Be certain to include an icon_default.tga + file in new model’s directory. This icon will be + used on the map loading screen. It represents the Body model in use by a + player … not the Head model.

+

New Team Skins
+ When creating a team, make a red and a blue version + of the skin. Name the skins as noted below. Do not use the team or character + name in the skin. That information is taken from the name of the directory in + which it resides.

+

The team skins (red and + blue) for a Team Arena model reside in a directory within the model directory + (which contains the model md3 pieces).

+

Example: models\players\characters\BoB\Kreechurs\.

+

The teamname + directory (Kreechurs in this case) would contain + the art files for the skin, and the .skin files that link art to model.

+

In simple form, the skin + assets required to be in the teamname file are as + follows:

+

TGA file names
+ Blue.tga //the body skin for the blue team version
+ Red.tga //the body skin for the red team version

+

Skin File Names
+ Lower_blue.skin //blue version of legs skin file
+ Upper_blue.skin //blue version of torso skin file
+ Lower_red.skin //red version of legs skin file
+ Upper_red.skin //red version of torso skin file
+ Lower_default.skin //default legs skin file (used + by U.I.). Usually, this is the red skin.
+ Upper_default.skin //default torso skin file (used + by U.I.). Usually, this is the red skin.

+

New Heads
+ Each new player on a new team should either have a new head model or have a + new skin for an existing Team Arena model. Each new head model and all its + assets go into a directory named for it. In the case of new skins for + pre-existing models, the new skin assets reside in a directory nested within + the model’s directory.

+

Example: models\players\heads\callisto\lily is a new skin for the Callisto + head.

+

Note that other assets, + such as the .vc file for this head will also need + to be nested in directories a layer deeper in their normal files.

+

Example: scripts\callisto\lily.vc. +

+

New head models need to + have all the assets specific to the model (md3 files, skin files and art + files) in the directory named for the model head.

+

No MD3 Models Required + for New Skins on id Models
+ New skins created for existing head models (id created or community created) + do not require that the md3 models be in their directories. The assets + specific to the new skin (skin art, skin file, icons) are placed in a + directory. You do not need to redistribute md3 models for the heads that are + a part of the original id game.

+

Using the Work of + Others
+ If you are reskinning or simply using a head model + previously created and distributed by a member of the community, make sure + that the original creator has authorized such use (and remember to give + credit where credit is due). When using community-created models, the team + creator must plan to include that model and all its assets in the pakfile.

+

TOP

+

Appendix A: The .Bot File
+ Five Heads, Five Bots, Five Team Members

+ Priority: Required for each new team

+

A Team Arena team consists + of five players. In the original game, the five players were drawn from a mix + of 11 new player heads sitting atop two body models. New teams should also + have five players each. However, five players on the new team should each have + a unique head/skin combination. These can either be new models or new skins + using the original Q3:TA models.

+

The .bot + file (whose file name is the same as the name of the new team, e.g.; Kreechurs.bot or Scumsukkers.bot) + is a text script whose “.txt” file extension has been renamed to “.bot.” This file corresponds to the bots.txt file used in + the original Team Arena game. Appendix A shows a + sample bot file.

+

Name = the name of the bot as it appears on the Start Server Menu.

+

Model = the body model used by this bot. A team can use more than one body model. However, + adding multiple body models can and will add significantly to the size of the + team pak file and to memory usage in game. Limiting + the number of body models used by a team is a good design practice. No more + than two models per team should be the limit.

+

Headmodel = *modelname. + The headmodel is what makes the bot + unique. It has links to the voice files and is used when creating name + aliases for the bots to use in the single player game. The asterisk is a + necessary part of the file name here.

+

The headmodel + called Callisto/Lily is a new skin on the Callisto model mesh. The pathname is required for the + model to work.

+

Aifile = the bot + ai used by the team member. The computer-controlled + opponents in Team Arena used three individual ai + files that define their general role in the game: defense (tad_c.c), offense (tao_c.c) and + all-arounder (taa_c.c). + New bots can use these same a.i. files or, if + desired the team creator can make new ai files + based on the Team Arena ai files.

+

Filename: Teamname.bot

+
//bot file begins here
{
name           Kreecha
model          BoB
headmodel      *Kreecha
aifile  bots/taa_c.c
}
 
{
name           Callisto/Lily
model          BoB
headmodel      *Callisto/Lily
aifile  bots/tad_c.c
}
 
{
name           Infinite
model          BoB
headmodel      *Infinite
aifile  bots/tad_c.c
}
 
{
name           Prime
model          BoB
headmodel      *Prime
aifile  bots/tao_c.c
}
 
{
name           Vlad
model          BoB
headmodel      *Vlad
aifile  bots/tao_c.c
}
//bot file ends here
+

TOP

+

Appendix B: The + .TEAM File
+ Priority: Required for each new team.

+

The team file is a text + file that has had the file extension renamed from .txt to .team.

+

Kreechurs is a test Team Arena team created + to test the team and head model code for point release v1.28. It uses the + hypothetical “BoB” model to create a new team.

+

The team definition + appears on a single line in the file:

+

“Team name” “asset + path/name” “bot 1” “bot + 2” “bot 3” “bot 4” “bot 5”

+

//Teams define the assets + used by the team: team name, path to U.I. assets, player names
+ // Character definitions act as a link between head models used by a team and + models that have the proper team skin assets. The Player Set Up User + Interface primarily uses the character definitions. The first entry is the + head model as defined in the .bot file. The second + entry is body model used by that character. For everything to work out for + the best, each character should have a unique model/skin combination that + defines it.

+

Filename: Teamname.team

+
// .team file begins here
teams {
  { "Kreechurs" "ui/assets/kreechurs"  "BoB" "Lily" "Vlad" "Infinite" "Prime"}
}
 
characters {
{ "Callisto/Lily" " BoB " }
{ "Kreecha"  " BoB " }
{ "Infinite"  " BoB " }
{ "Prime"  " BoB " }
{ "Vlad" " BoB " }
}
 
// Aliases are the link between character name, headmodel, and bot A.I.
 
aliases {
        { "Kreecha"           "BoB"              "a"  }
        { "Lily"        "Callisto/Lily" "d"   }
            { "Vlad"           "Vlad"              "o"       }
            { "Infinite"       "Infinite"           "d"      }
            { "Prime"          "Prime"             "o"       }              
}
 
//.team file ends here
+

TOP

+

Appendix C: The + Voice List
+ Priority: Optional.

+

The voice file is a text + file that has had the file extension renamed from .txt to .voice. Each unique + set of voice recordings requires its own voice file. This file contains the + code script that defines the voice and corresponding text messages used by + the player models in game. Like the text chat messages that appeared in + original Q3A, these messages are triggered by game conditions and statuses.

+

The file directory name + for the voice does not have to be the same as a head or body model, though + giving it a unique name that identifies it with the team is always a good + idea. The specific file names for each voice message ARE VERY IMPORTANT, as + the voice script that corresponds to the file directory for the voice calls + them. Example: If the new voice is called “monster”, then the directory would + be called “monster” and the voice file would be called monster.voice. +

+

If you create a new set of + recorded voices for your team or for a new model, be certain to include at + least one voice message for each category (defined by a name like “getflag” and follow by opening and closing brackets) on + this list. It is not necessary to provide as many different messages as shown + below. Example: Your character may not need more than one way to say “yes” or + have as many kill insults. You can also rewrite the scripts. Your team need + not say the same thing as the id teams said or use the same style of + speaking. Just remember that the text portion of the message will display on + screen, so having it match the audio is always a good thing. And remember + that in game, shorter speeches are better and cheaper.

+

The file path is as + follows: sound\voices\newmodel\soundname.wav

+

You may include additional + voices but these are the ones currently the phrases accessed by the game.

+

As with any script, these + are lines of game code. Take care to maintain the proper syntax, otherwise, + you are likely to either disable the file or even crash the game.

+

To create new voice + recordings use a sound editing program that can produce a .wav format file + that conforms to the following: Mono 22k 16bit

+

(This is taken from the + male5 voice file. Substitute the name of your model for male5 in the file + pathnames).

+

Filename: Voicename.voice

+
//voice file starts here
 
getflag
{
        sound/voices/male5/or_01.wav   "Get the flag"
        sound/voices/male5/or_02.wav   "Secure the flag"
}
 
offense
{
        sound/voices/male5/or_03.wav   "You're on offense"
}
 
defend
{
        sound/voices/male5/or_04.wav   "Stay Home"
        sound/voices/male5/or_05.wav   "Guard the base"
        sound/voices/male5/or_07.wav   "You're on defense"
}
 
defendflag
{
        sound/voices/male5/or_06.wav   "Guard our flag"
}
 
patrol
{
        sound/voices/male5/or_08.wav   "Patrol"
        sound/voices/male5/or_09.wav   "Take point"
        sound/voices/male5/or_10.wav   "Go on patrol"
}
 
followme
{
        sound/voices/male5/or_11.wav   "Follow me"
        sound/voices/male5/or_12.wav   "Cover me"
        sound/voices/male5/or_13.wav   "Watch my back"
}
 
yes
{
        sound/voices/male5/re_01.wav   "Yessir"
        sound/voices/male5/re_02.wav   "Yes ma'am"
        sound/voices/male5/re_03.wav   "Aye, aye, sir"
        sound/voices/male5/re_04.wav   "Aye, aye, ma'am"
        sound/voices/male5/re_05.wav   "Affirmative"
        sound/voices/male5/re_06.wav   "Copy"
        sound/voices/male5/re_07.wav   "Roger"
}
 
no
{
        sound/voices/male5/re_08.wav   "No sir"
        sound/voices/male5/re_09.wav   "No ma'am"
        sound/voices/male5/re_10.wav   "Negative"
        sound/voices/male5/re_11.wav   "I'm busy"
}
 
ihaveflag
{
        sound/voices/male5/gs_01.wav   "I'm coming in hot!"
        sound/voices/male5/gs_02.wav   "I've secured the flag!"
        sound/voices/male5/gs_03.wav   "I've got the flag!"
        sound/voices/male5/gs_04.wav   "Bringing home the bacon!"
}
 
baseattack
{
        sound/voices/male5/gs_05.wav   "We're taking enemy fire!"
        sound/voices/male5/gs_06.wav   "Security breach!"
        sound/voices/male5/gs_07.wav   "Our base is under attack."
}
 
enemyhasflag
{
        sound/voices/male5/gs_08.wav   "Our flag is gone!"
        sound/voices/male5/gs_09.wav   "They've got our flag!"
        sound/voices/male5/gs_10.wav   "Enemy has secured our flag!"
}
 
ongetflag
{
        sound/voices/male5/ps_03.wav   "Getting the flag..."
}
 
onoffense
{
        sound/voices/male5/ps_01.wav   "I'm taking offense"
        sound/voices/male5/ps_02.wav   "I'm going in..."
}
 
ondefense
{
        sound/voices/male5/ps_04.wav   "I'll stay home"
        sound/voices/male5/ps_05.wav   "Securing base"
        sound/voices/male5/ps_06.wav   "Guarding the base now"
}
 
onpatrol
{
        sound/voices/male5/ps_07.wav   "On patrol..."
        sound/voices/male5/ps_08.wav   "Patroling..."
        sound/voices/male5/ps_09.wav   "I'll take point"
}
 
startleader
{
        sound/voices/male5/ps_10.wav   "I'm the leader"
        sound/voices/male5/ps_11.wav   "I'm in charge"
}
 
stopleader
{
        sound/voices/male5/ps_12.wav   "I don't want to lead"
        sound/voices/male5/ps_13.wav   "Someone else lead"
        sound/voices/male5/ps_14.wav   "I resign"
}
 
kill_insult
{
        sound/voices/male5/tt_06.wav   "Next time don't get up"
        sound/voices/male5/tt_05.wav   "You're just a waste of space"
        sound/voices/male2/tt_07.wav   "Are you blind?"
        sound/voices/male5/tt_13.wav   "Duck next time"
        sound/voices/male5/tt_19.wav   "Suh-weeet!"
        sound/voices/male5/tt_20.wav   "Woo-Hoo!"
        sound/voices/male5/tt_22.wav   "You just got schooled!"
//      sound/voices/male5/tt_16.wav   "You talkin' ta ME?"
}
 
taunt {
        sound/voices/male5/tt_18.wav   "How about some competition here?"
        sound/voices/male5/tt_01.wav   "FRAGbait!"    
        sound/voices/male5/tt_11.wav   "My momma shoots better!"
        sound/voices/male5/tt_14.wav   "Try hitting that barn over there!"
        sound/voices/male5/tt_17.wav   "Wanna BUY a shot?"
//      sound/voices/male5/tt_03.wav   "Get a clue moron!"
//      sound/voices/male5/tt_09.wav   "MORON!"
//      sound/voices/male5/tt_02.wav   "You're such a Loser!"
//      sound/voices/male5/tt_08.wav   "LOSER!"
//      sound/voices/male5/tt_10.wav   "No-skill idiot!"
//      sound/voices/male5/tt_12.wav   "Watched that all the way..."
}
 
death_insult {
        sound/voices/male5/tt_15.wav   "Thank you sir.. may I have another!"
        sound/voices/male5/tt_23.wav   "Bite me!"
        sound/voices/male5/tt_25.wav   "Cheap shot!"
        sound/voices/male5/tt_26.wav   "DOH"
        sound/voices/male5/tt_28.wav   "Lucky shot!"
        sound/voices/male5/tt_29.wav   "That's it!"
        sound/voices/male5/tt_30.wav   "Ooh! That's it!"
//      sound/voices/male5/tt_35.wav   "Hey, dumbass"
//      sound/voices/male5/tt_04.wav   "What an ass!"
//      sound/voices/male5/tt_24.wav   "Screw you!"
}
 
kill_gauntlet {
        sound/voices/male5/tt_21.wav   "Eat gauntlet baby!"
}
 
praise {
        sound/voices/male5/tt_27.wav   "Nice!"
}
 
camp                   // command someone to camp
{
        sound/voices/male5/voc_01.wav  "Camp this position."
        sound/voices/male5/voc_02.wav  "Camp here."
 
}
 
returnflag                     // return our flag  (CTF only)
{
        sound/voices/male5/voc_03.wav  "Get our flag!"
        sound/voices/male5/voc_04.wav  "Return our flag!"
        sound/voices/male5/voc_05.wav  "Recover our flag!"
}
 
whoisleader                    // who is the team leader
{
        sound/voices/male5/voc_06.wav  "Who's our leader?"
        sound/voices/male5/voc_07.wav  "Who's in charge?"
        sound/voices/male5/voc_08.wav  "Who leads this team?"
}
 
followflagcarrier              // follow the flag/skull carrier (CTF, Oneflag, Harvester)
{
        sound/voices/male5/voc_09.wav  "Follow our carrier."
        sound/voices/male5/voc_10.wav  "Stay with the carrier."
        sound/voices/male5/voc_11.wav  "Protect the carrier."
        sound/voices/male5/voc_12.wav  "Cover the carrier."
}
 
inposition                     // I'm in position
{
        sound/voices/male5/voc_13.wav  "I'm in place."
        sound/voices/male5/voc_14.wav  "I'm at my post."
        sound/voices/male5/voc_15.wav  "I am in position."
        sound/voices/male5/voc_15a.wav "I am in position"
}
 
wantondefense          // I want to be on defense
{
        sound/voices/male5/voc_16.wav  "Let me defend."
        sound/voices/male5/voc_17.wav  "I'd rather defend."
}
 
wantonoffense          // I want to be on offense
{
        sound/voices/male5/voc_18.wav  "Let me go on offense."
        sound/voices/male5/voc_19.wav  "I'd rather go on offense."
}
 
wantonpatrol           // I want to go on patrol
{
        sound/voices/male5/voc_20.wav  "Let me patrol."
        sound/voices/male5/voc_21.wav  "I'd rather patrol."
}
 
oncamp  //I'm Camping (status)
{
        sound/voices/male5/voc_22.wav  "I'm camping here."
}
 
onfollow
{
        sound/voices/male5/voc_23.wav  "I'm following."
        sound/voices/male5/voc_24.wav  "Following!"
}
 
onfollowcarrier
{
        sound/voices/male5/voc_27.wav  "Guarding the carrier."
}
 
onreturnflag
{
        sound/voices/male5/voc_28.wav  "Getting our flag."
}
 
harvest //harvester game type only
{
        sound/voices/male5/voc_25.wav  "Go collect skulls."
        sound/voices/male5/voc_26.wav  "Harvest some skulls."
}
// voice file ends here
+

TOP
+
+
Appendix D: + Model Sound List
+ Priority: Only required if a new body model is included in the team pak file.

+

The following game sounds + are associated with the team model. Each of the sounds listed below is a + separate file. They need to be located in a directory having the same name as + the body model and be nested within the sounds directory.

+

Example: sounds/newmodel/Death1.wav.

+

If new sound files are to + be created, make sure that they conform to the following wav file format: + Mono 22k 16bit.

+

Death1.wav
+ Death2.wav
+ Death3.wav
+ Drown.wav
+ Fall1.wav
+ Falling1.wav
+ Gasp.wav
+ Jump1.wav
+ Pain100_1.wav
+ Pain25_1.wav
+ Pain50_1.wav
+ Pain75_1.wav
+ Taunt.wav

+

TOP

+

Appendix E: .VC + File Sample
+ Priority: Required for each head model

+

The vc + file is a text file script that has had the file extension renamed from .txt + to .vc. The script is linked to a bot name. Bot names are defined + in the .bot file included in the pak file. Each bot needs to + have a .vc file. It’s + best, if at all possible, to have the model name (or model/skin combination) + and the bot name be the same. The very brief + contents are simply a path to a voice file. The selected voice file can be + either one of the original Team Arena voices or an original voice included + with the team. When creating the voice file for a re-skinned head model, be + sure to include the head name in the path to the voice script. That script + must also be nested a layer deeper in the directory, such as: scripts/callisto/lily.vc.

+

The contents of a sample .vc file are shown below.

+
        //VC script begins here
scripts/newcharacter.voice
           //VC script ends here
+

TOP

+

Appendix F: Sample + Team Arena Animation.Cfg File and New Animation + Commands
+ Priority: Required only if a new model is included.

+

The animation.cfg + file is a text file that has had the file extension renamed from .txt to .cfg. This file goes in the directory with the body model + components (model\players \new_model\ -- or -- + model\players\characters\new_model\). The specifics + of using or modifying the contents of this file are a part of the model + making process and are mostly outside the focus of this document.

+

It is included in this + document because the Team Arena animation configuration is different from the + Quake 3 Arena Configuration. Furthermore it contains the “sex” key that + determines the gender/sex of a character (as does the Q3A animation.cfg). + This key/value pair determines which pronouns (masculine, feminine, or + neuter) are used when the game generates messages about the player.

+

Additionally, two new + animation commands (for both Q3A and Q3:TA) are + shown here. These were done at the request of modelers doing non-traditional + biped models. When put in the animation.cfg file, + they literally stop the model from responding to the programmatic animations + for those body parts. If you freeze the legs, the hips don't tilt during + running animation. If the model’s legs were too + much outside of bipedal norms (as is the case for quadrupeds), the front or + back legs would disappear into the ground as the leg models programmatically + tilted around the model’s pelvis. If you freeze the + torso, you don't get waist twists or bends. Depending on what you are making, + you may want to use one, but not the other.

+

Fixedlegs : put in the animation .cfg this command freezes programmatic rotation of the + legs

+

Fixedtorso : when put in the animation .cfg this command freezes programmatic rotation of the + torso

+

These commands are + commented out in the sample below.

+
// animation.config file begins here
sex     m      // THIS VALUE  (m, f, n) DETERMINES GENDER OF MODEL
//fixedlegs  // PREVENTS PROGRAMMATIC ROTATION OF LEGS
//fixedtorso // PREVENTS PROGRAMMATIC ROTATION OF TORSO
headoffset -3 0 0
footsteps boot
 
 
 
// first frame, num frames, looping frames, frames per second
0       30      0       20             // BOTH_DEATH1
29      1       0       20             // BOTH_DEAD1
30      30      0       20             // BOTH_DEATH2
59      1       0       20             // BOTH_DEAD2
60      30      0       20             // BOTH_DEATH3
89      1       0       20             // BOTH_DEAD3
 
90      26      0       20             // TORSO_GESTURE
 
116     6       0       15             // TORSO_ATTACK        (MUST NOT CHANGE -- hand animation is synced to this)
122     6       0       15             // TORSO_ATTACK2       (MUST NOT CHANGE -- hand animation is synced to this)
 
128     5       0       20             // TORSO_DROP          (MUST NOT CHANGE -- hand animation is synced to this)
133     4       0       20             // TORSO_RAISE         (MUST NOT CHANGE -- hand animation is synced to this)
 
137     1       0       15             // TORSO_STAND
138     1       0       15             // TORSO_STAND2
 
199     8       8       20             // LEGS_WALKCR
207     12      12      20             // LEGS_WALK
219     10      10      20             // LEGS_RUN
229     10      10      20             // LEGS_BACK
239     10      10      15             // LEGS_SWIM
 
249     7       0       15             // LEGS_JUMP
256     9       0       15             // LEGS_LAND
265     9       0       15             // LEGS_JUMPB
274     6       0       15             // LEGS_LANDB
280     15      15      15             // LEGS_IDLE
295     11      11      15             // LEGS_IDLECR
307     9       9       15             // LEGS_TURN
 
139     10      0       15             // TORSO_GETFLAG    //TA Gesture
149     10      0       15             // TORSO_GUARDBASE   //TA Gesture
159     10      0       15             // TORSO_PATROL   //TA Gesture
169     10      0       15             // TORSO_FOLLOWME   //TA Gesture
179     10      0       15             // TORSO_AFFIRMATIVE   //TA Gesture
189     10      0       15             // TORSO_NEGATIVE   //TA Gesture
 
// animation.config file ends here
+

TOP

+

Appendix G: Teamname.shader
+ Priority: Required for team icons to work in the game

+

This is a text file script + with the file extension renamed from .txt to ..shader.

+
//Teamname.shader begins here
team_icon/Kreechurs_red
{              
        cull none
        surfaceparm nolightmap
        surfaceparm trans
        surfaceparm nomarks
        {
               map team_icon/Kreechurs_red.tga
               blendFunc Add
               rgbgen wave triangle 0.2 0.5 0 0.2           
        }
}
 
team_icon/Kreechurs_blue
{              
        cull none
        surfaceparm nolightmap
        surfaceparm trans
        surfaceparm nomarks
        {
               map team_icon/Kreechurs_blue.tga
               blendFunc Add
               rgbgen wave triangle 0.2 0.5 0 0.2       
        }
}
//Teamname.shader ends here
+

TOP

+

Appendix H: Search + Order for Model and Head model Assets

+

The means by which headmodels are used and selected was unified as much as + possible between Q3A and Q3:TA code. The byproduct + of this change allows players some more choices when selecting head models. + The following documents the new procedures.

+

Searching for Head + skins
+ The game uses the following paths and order of search when looking for headmodel assets. The asterisk (*) is only used for head + models. When the asterisk is used, the game will try to load the head model + from the models/players/heads folder first. After that, it looks deeper into + the directories.

+

More Variety of Head + Skins
+ If the team creator so chooses, different skins can be created for each team + (note that id chose to use the same head skins for each team … but that doesn’t have to be the case).

+
===================================
Q3A/TA NON-TEAMPLAY SEARCH ORDER
===================================
 
-------------------------------------------------
headmodel = *callisto/lily
 
models/players/heads/callisto/lily/head_default.skin
models/players/heads/callisto/head_lily.skin
 
-------------------------------------------------
headmodel = callisto/lily
 
models/players/callisto/lily/head_default.skin
models/players/callisto/head_lily.skin
models/players/heads/callisto/lily/head_default.skin
models/players/heads/callisto/head_lily.skin
 
============================
Q3A TEAMPLAY SEARCH ORDER
============================
-------------------------------------------------
Example:
team_headmodel = *callisto/lily
team = red
models/players/heads/callisto/lily/head_red.skin
models/players/heads/callisto/head_red.skin
 
-------------------------------------------------
Example:
team_headmodel = callisto/lily
team = red
 
models/players/callisto/lily/head_red.skin
models/players/callisto/head_red.skin
models/players/heads/callisto/lily/head_red.skin
models/players/heads/callisto/head_red.skin
 
===========================
TA TEAMPLAY SEARCH ORDER
===========================
Example:
team_headmodel = *callisto/lily
team = red
teamName = Stroggs
 
models/players/heads/callisto/lily/Stroggs/head_red.skin
models/players/heads/callisto/Stroggs/head_red.skin
models/players/heads/callisto/lily/head_red.skin
models/players/heads/callisto/head_red.skin
 
Example:
team_headmodel = callisto/lily
team = red
teamName = Stroggs
 
models/players/callisto/lily/Stroggs/head_red.skin
models/players/callisto/Stroggs/head_red.skin
models/players/callisto/lily/head_red.skin
models/players/callisto/head_red.skin
models/players/heads/callisto/lily/Stroggs/head_red.skin
models/players/heads/callisto/Stroggs/head_red.skin
models/players/heads/callisto/lily/head_red.skin
models/players/heads/callisto/head_red.skin
+

Searching for Model + Skins
+ The following list shows the order in which the game searches for model + skins. When creating new skins for Team Arena or Quake 3 Arena (or related mods of either), use the following directory arrangement. +

+
===================================
Q3A/TA NON-TEAMPLAY SEARCH ORDER
===================================
-------------------------------------------------
Example:
model = hunter/harpy
 
 
legs:
        models/players/hunter/lower_harpy_default.skin
        models/players/hunter/lower_harpy.skin
        models/players/characters/james/lower_harpy_default.skin
        models/players/characters/james/lower_harpy.skin
torso:
        models/players/hunter/upper_harpy_default.skin
        models/players/hunter/upper_harpy.skin
        models/players/characters/hunter/upper_harpy_default.skin
        models/players/characters/hunter/upper_harpy.skin
 
============================
Q3A TEAMPLAY SEARCH ORDER
============================
 
-------------------------------------------------
Example:
team_model = hunter/harpy
team = red
 
legs:
        models/players/hunter/lower_harpy_red.skin
        models/players/hunter/lower_red.skin
        models/players/characters/hunter/lower_harpy_red.skin
        models/players/characters/hunter/lower_red.skin
torso:
        models/players/hunter/upper_harpy_red.skin
        models/players/hunter/upper_red.skin
        models/players/characters/hunter/upper_harpy_red.skin
        models/players/characters/hunter/upper_red.skin
 
 
===========================
TA TEAMPLAY SEARCH ORDER
===========================
 
-------------------------------------------------
Example:
team_model = james/badass
team = red
teamName = Stroggs
 
legs:
        models/players/james/Stroggs/lower_badass_red.skin
        models/players/james/Stroggs/lower_red.skin
        models/players/james/lower_badass_red.skin
        models/players/james/lower_red.skin
        models/players/characters/james/Stroggs/lower_badass_red.skin
        models/players/characters/james/Stroggs/lower_red.skin
        models/players/characters/james/lower_badass_red.skin
        models/players/characters/james/lower_red.skin
torso:
        models/players/james/Stroggs/upper_badass_red.skin
        models/players/james/Stroggs/upper_red.skin
        models/players/james/upper_badass_red.skin
        models/players/james/upper_red.skin
        models/players/characters/james/Stroggs/upper_badass_red.skin
        models/players/characters/james/Stroggs/upper_red.skin
        models/players/characters/james/upper_badass_red.skin
        models/players/characters/james/upper_red.skin
+

TOP

+

Appendix I: + Expanded Team Skin Functionality for Q3A

+

Technically speaking, the + following information has nothing to do with Team Arena teams, but this + document is just as good a place for this information to reside as any.

+

At the request of several + modelers who worked with the modeling and skin making forums and archives at Polycount, + we changed the way that Quake III Arena (not just Team Arena) handles skin + replacement in team games. Originally, if a skinner made a new skin for a Q3A + model AND made team color versions of that skin, the game would not + automatically use the team version. Instead, it would display the id default + red or blue skin. To see a new team skin in the game, the skinner literally + had to remove the default skins and replace them with the new versions.

+

With version 1.28 of the + game code, we’ve been able to get that changed. The + file format that we used is the one requested by the skinners themselves. + However, because of the way searches for head skins now work, pre-existing + Q3A files are not going to work correctly. They need to have one, renamed + skin file added for the proper head skins to appear in the game.

+

When a properly set-up + user-created skin for a model is accompanied by matching team color skins, + the game will now use them instead of the default team skin for that model.

+

The example below shows + the assets that must be in the pakfile for the Blue + version of a skin named Hellion that uses the id-created Crash model.

+
 Hellion_blue.tga                          models\players\crash\
 Hellion_blue_f.tga                       models\players\crash\
 Hellion_blue_t.tga                       models\players\crash\
 Head_Hellion_blue.skin              models\players\crash\
 Icon_Hellion_blue.tga                 models\players\crash\
 Lower_Hellion_blue.skin            models\players\crash\
 Upper_Hellion_blue.skin            models\players\crash\
 Head_blue.skin                            models\players\crash\Hellion\
+

The last file is the key + to making it work … a skin file with the same contents as Head_Hellion_blue.skin, + only renamed Head_blue.skin and placed one layer + deeper in the Hellion directory. Note that BOTH head_hellion_blue.skin + in the crash directory and head_blue.skin in the + crash/Hellion directory are necessary for the model to work properly.

+

To see a working example + of a properly set up Q3A skin, look for Hades Orphan, the revised version + (h20.pk3), by Camilla “milla” Bennett for the Crash + model.

+

TOP

+

Appendix J: + Contents of the tm_kreechurs.pk3

+

The following list is + taken directly from the contents of the pak file contain + the BoB model and the Kreechurs + team information. Use this as a reference when creating your own team pak files.

+
tm_kreechurs.pk3
Name    Modified       Size    Ratio   Packed  Path
kreechurs.team  5/9/2001 12:01 PM      1,968   61%     770
kreechurs_readme.txt   5/9/2001       3,162   59%     1,286   
animation.cfg  5/161/2001 4:32 PM     1,173   59%     478         models\players\characters\BoB\
default_flame1.jpg     513/2000 7:19 PM       5,972   10%     5,385        models\players\characters\BoB\
default_flame2.jpg     51312000 7:19 PM       5,984   10%     5,359        models\players\characters\BoB\
default_flame3.jpg     5/3/2000 7:20 PM       5,623   11%     5,014        models\players\characters\BoB\
default_flame4.jpg     51312000 7:20 PM       5,284   12%     4,658        models\players\characters\BoB\
default_flame5.jpg     513/2000 7:21 PM       5,231   10%     4,691         models\players\characters\BoB\
default_flame6.jpg     5/3/2000 7:21 PM       5,318   11%     4,735         models\players\characters\BoB\
qefault_flame7.jpg     5/3/2000 7:21 PM       5,807   11%     5,197         models\players\characters\BoB\
default_flame8.jpg     5/3/2000 7:22 PM       6,114   10%     5,510         models\players\characters\BoB\
default_flameball.jpg  5/3/2000 7:22 PM       3,010   26%     2,216         models\players\characters\BoB\
defaultjets.tga        611412000 2:55 AM      49,196  37%     31,075         models\players\characters\BoB\
icon_blue.tga  6/13/2000 8:15 PM      16,402  58%     6,845         models\players\characters\BoB\
icon_red.tga   6/13/2000 8:15 PM      16,402  61%     6,327         models\players\characters\BoB\
lower.md3      3/3/2001 12:11 PM      593,972        33%     398,956         models\players\characters\BoB\
lower_1.md3    3/3/2001 12:11 PM      593,972 33%     398,956         models\players\characters\BoB\
lower_2.md3    3/3/2001 12.11 PM      593,972        33%     398,956         models\players\characters\BoB\
upper.md3      3/3/2001 12:11 PM      721,388        33%     483,599         models\players\characters\BoB\
upper_1.md3    3/3/2001 12:11 PM      721,388        33%     483,599         models\players\characters\BoB\
upper_2.md3    3/3/2001 12:11 PM      721,388        33%     483,599         models\players\characters\BoB\
icon_default.tga       6/13/2000 8:15 PM      16,402  61%     6,328         models\players\ characters\BoB\
blue.tga       10/23/2000 7: 17 PM    196,626        41%     115,756         models\players\characters\BoB\kreechurs\
lower_blue.skin        4/6/2001 11 :20 AM     203     52%     98         models\players\characters\BoB\kreechurs\
lower_default.skin     4/6/200 111:25AM       204     50%     102         models\players\characters\BoB\kreechurs\
lower_red.skin  4/6/2001 11:20AM       204     50%     102         models\players\characters\BoB\kreechurs\
red.tga        10/23/2000 7:17 PM     196,626        43%     111,607         models\players\characters\BoB\kreechurs\
upper_blue.skin        41612001 11:20AM       281     58%     118         models\players\characters\BoB\kreechurs\
upper_default.skin     416/2001 11:25AM       282     58%     119         models\players\characters\BoB\kreechurs\
upper_red.skin  4/6/2001 11 :20 AM     282     58%     119         models\players\characters\BoB\kreechurs\
blue_h.tga     6/14/2000 10:26 AM     196,652        56%     86,873         models\players\heads\Kreecha\
default_fc.tga  5/29/2000 10:07 AM     3,090   90%     323         models\players\heads\Kreecha\
default_visor.tga      10/23/2000 7:57 PM     196,626        96%     7,656         models\players\heads\Kreecha\
Kreecha.md3    3/3/2001 12:12 PM      5,868   46%     3,171         models\players\heads\Kreecha\
Kreecha_1.md3  3/3/2001 12:12 PM      5,868   46%     3,171         models\players\heads\Kreecha\
Kreecha_2.md3  3/3/2001 12:12 PM      5,868   46%     3,171         models\players\heads\Kreecha\
head_blue.skin  3/12/2001 4:58 PM      56      7%      52         models\players\heads\Kreecha\
head_default.skin      3/1212001 4:57 PM      53      8%      49         models\players\heads\Kreecha\
head_red.skin  3/12/2001 4:58 PM      55      7%      51         models\players\heads\Kreecha\
icon_blue.tga  6/13/2000 8:15 PM      16,402  58%     6,846        models\players\heads\Kreecha\
icon_default.tga       6/13/2000 8:15 PM      16,402  61%     6,328         models\players\heads\Kreecha\
icon_red.tga   6/1312000 8.15 PM      16,402  61%     6,328         models\players\heads\Kreecha\
red_h.tga      3112/2001 6:06 PM      196,626        66%     66,666         models\players\heads\Kreecha\
BoB.shader     3/12/2001 5:49 PM      2,912   89%     308     scripts\
kreechurs.bot  5/9/2001 11 :43 AM     405     70%     123     scripts\
kreechurs.shader       4/6/2001 3:05 PM       500     67%     163     scripts\
Kreecha.vc     5/2/2001 5:53 PM       21      0%      21      scripts\
Infinite.vc    4/9/2001 11: 18 AM     24      0%      24      scripts\
Prime.vc       4/9/2001 11: 18 AM     24      0%      24      scripts\
Vader.vc       4/9/2001 11: 18 AM     24      0%      24      scripts\
death1.wav     2/23/2000 9:20 AM      16,720  47%     8,900   sound\player\BoB\
death2.wav     5/7/2000 5:46 PM       18,496  17%     15,356  sound\player\BoB\
death3.wav     5/7/2000 5:46 PM       18,496  17%     15,356  sound\player\BoB\
fall1.wav      5/9/2000 6:40 AM       13,944  62%     5,327   sound\player\BoB\
falling1.wav   5/7/2000 5:22 PM       40,722  26%     30,585  sound\player\BoB\
gasp.wav       5/7/2000 5:15 PM       55,230  4%      53,293  sound\player\BoB\
jump1.wav      5/7/20009:26 PM 47,778   8%     44,070  sound\player\BoB\
pain100_1.wav  5/7/20005:33PM 6,894    29%    4,880   sound\player\BoB\
pain25_1.wav   5/7/20005:34 PM 9,832    26%    7,248   sound\player\BoB\
pain50_1.wav   5/7/20005:33 PM 6,444    22%    5,007   sound\player\BoB\
pain75_1.wav   5/7/20005:33 PM 9,512    26%    6,997   sound\player\BoB\
taunt.wav      3/3/2001 12:17 PM      163,874  11%    146,434 sound\player\BoB\
gs_01.wav      10/20/20005:05 PM      51,304   10%    46,296  sound\voices\BoB\
gs_02.wav      10/20/20005:05 PM      69,704   10%    62,811  sound\voices\BoB\
gs_03.wav      10/20/20005:05 PM      53,394   8%     49,195  sound\voices\BoB\
gs_04.wav      10/20/20005:05 PM      48,802   3%     47,157  sound\voices\BoB\
gs_05.wav      10/20/20005:05 PM      62,170   4%     59,614  sound\voices\BoB\
gs_06.wav      10/20/2000 5:05 PM     53,622   5%     51,075  sound\voices\BoB\
gs_07 .wav     10/20/2000 5:05 PM     67,756   10%    60,889  sound\voices\BoB\
gs_08.wav      10/20/2000 5:05 PM     61,458   4%     59,265  sound\voices\BoB\
gs_09.wav      10/20/2000 5:05 PM     60,042   6%     56,640  sound\voices\BoB\
gs_10.wav      10/20/2000 5:05 PM     82,526   4%     79,337  sound\voices\BoB\
or_01.wav      10/20/2000 5.05 PM     46,892   8%     42,990  sound\voices\BoB\
or_02.wav      10/20/2000 5:05 PM     63,152   10%    56,946  sound\voices\BoB\
or_03.wav      10/20/2000 5:05 PM     54,714   6%     51,246  sound\voices\BoB\
or_04.wav      10/20/2000 5:05 PM     43,640   4%     41,815  sound\voices\BoB\
or_05.wav      10/20/2000 5:05 PM     56,694   6%     53,172  sound\voices\BoB\
or_06.wav      10/20/2000 5:05 PM     44,248   6%     41,468  sound\voices\BoB\
or_07.wav      10/20/2000 5:05 PM     57,616   4%     55,043  sound\voices\BoB\
or_08.wav      10/20/2000 5:05 PM     22,626   5%     21,538  sound\voices\BoB\
or_09.wav      10/20/2000 5:05 PM     36,260   30%    25,528  sound\voices\BoB\
or_10.wav      10/20/2000 5:05 PM     43,396   7%     40,432  sound\voices\BoB\
or_11.wav      10/20/2000 5:05 PM     37,070   4%     35,592  sound\voices\BoB\
or_12.wav      10/20/2000 5:05 PM     25,714   4%     24,796  sound\voices\BoB\
ps_01.wav      10/20/2000 5:05 PM     58,040   4%     55,538  sound\voices\BoB\
ps_02.wav      10/20/2000 5:05 PM     40,686   4%     39,161  sound\voices\BoB\
ps_03.wav      10/20/2000 5:05 PM     44,870   5%     42,695  sound\voices\BoB\
ps_04.wav      10/20/2000 5:05 PM     50,550   4%     48,465  sound\voices\BoB\
ps_05.wav      10/20/2000 5:05 PM     64,256   9%     58,718  sound\voices\BoB\
ps_06.wav      10/20/2000 5:05 PM     60,770   4%     58,385  sound\voices\BoB\
ps_07.wav      10/20/2000 5:05 PM     41,604   3%     40,372  sound\voices\BoB\
ps_08.wav      10/20/2000 5:05 PM     33,102   4%     31,860  sound\voices\BoB\
ps_09.wav      10/20/2000 5:05 PM     43,578   14%    37,279  sound\voices\BoB\
ps_1 0.wav     10/20/2000 5:05 PM     48,126   3%     46,467  sound\voices\BoB\
ps_11.wav      10/20/2000 5:05 PM     52,114   7%     48,442  sound\voices\BoB\
ps_12.wav      10/20/2000 5:05 PM     46,054   3%     44,632  sound\voices\BoB\
ps_13.wav      10/20/2000 5:05 PM     52,026   4%     49,921  sound\voices\BoB\
ps_14.wav      10/20/2000 5:05 PM     38,428   3%     37,165  sound\voices\BoB\
re_01.wav      10/20/2000 5:05 PM     42,970   5%     40,707  sound\voices\BoB\
re_02.wav      10/20/2000 5:05 PM     42,010   16%    35,118  sound\voices\BoB\
re_03.wav      10/20/2000 5:05 PM     44,994   4%     43,387  sound\voices\BoB\
re_04.wav      10/20/2000 5:05 PM     26,620   3%     25,824  sound\voices\BoB\
re_05.wav      10/20/2000 5:05 PM     31,732   4%     30,549  sound\voices\BoB\
re_06.wav      10/20/2000 5:05 PM     20,342   5%     19,287  sound\voices\BoB\
re_07.wav      10/20/2000 5:05 PM     23,544   4%     22,526  sound\voices\BoB\
re_08.wav      10/20/2000 5:05 PM     38,070   3%     36,822  sound\voices\BoB\
re_09.wav      10/20/2000 5:05 PM     33,436   4%     32,041  sound\voices\BoB\
re_10.wav      10/20/2000 5:05 PM     29,016   7%     26,898  sound\voices\BoB\
re_11.wav      10/20/2000 5:05 PM     31,998   3%     30,885  sound\voices\BoB\
tt_01.wav      10/20/2000 5:05 PM     56,240   7%     52,038  sound\voices\BoB\
tt_02.wav      10/20/2000 5:05 PM     57,144   5%     54,206  sound\voices\BoB\
tt_03.wav      10/20/2000 5:05 PM     68,484   9%     62,426  sound\voices\BoB\
tt_04.wav      10/20/2000 5:05 PM     55,838   5%     52,785  sound\voices\BoB\
tt_05.wav      10/20/2000 5:05 PM     75,106   6%     70,367  sound\voices\BoB\
tt_06.wav      10/20/2000 5:05 PM     81,630   10%    73,342  sound\voices\BoB\
tt_07.wav      10/20/2000 5:05 PM     60,354   5%     57,333  sound\voices\BoB\
tt_08.wav      10/20/2000 5:05 PM     56,642   5%     53,981  sound\voices\BoB\
tt_09.wav      10/20/2000 5:05 PM     49,216   3%     47,675  sound\voices\BoB\
tt_10.wav      10/20/2000 5:05 PM     60,656   5%     57,563  sound\voices\BoB\
tt_11.wav      10/20/2000 5:05 PM     75,106   5%     71,690  sound\voices\BoB\
tt_12.wav      10/20/2000 5:05 PM     90,760   6%     84,879  sound\voices\BoB\
tt_13.wav      10/20/2000 5:05 PM     52,628   8%     48,347  sound\voices\BoB\
tt_14.wav      10/20/2000 5:05 PM     72,848   4%     70,004  sound\voices\BoB\
tt_15.wav      10/20/2000 5:05 PM     109 184  12%    96,020  sound\voices\BoB\
tt_16.wav      10/20/2000 5:05 PM     48,812   3%     47,245  sound\voices\BoB\
tt_17.wav      10/20/2000 5:05 PM     64,506   10%    57,951  sound\voices\BoB\
tt_18.wav      10/20/2000 5:05 PM     85,018   6%     79,532  sound\voices\BoB\
tt_19.wav      10/20/2000 5:05 PM     72,978   17%    60,260  sound\voices\BoB\
tt_20.wav      10/20/2000 5:05 PM     73,328   6%     68,967  sound\voices\BoB\
tt_21.wav      10/20/2000 5:05 PM     79,434   7%     74, 101 sound\voices\BoB\
tt_22.wav      10/20/2000 5:05 PM     74,636   4%     71,397  sound\voices\BoB\
tt_23.wav      10/20/2000 5:05 PM     37,034   18%    30,448  sound\voices\BoB\
tt_24.wav      10/20/2000 5:05 PM     43,316   5%     41,087  sound\voices\BoB\
tt_25.wav      10/20/2000 5:05 PM     48,376   13%    42,005  sound\voices\BoB\
tt_26.wav      10/20/2000 5:05 PM     35,464   8%     32,716  sound\voices\BoB\
tt_27.wav      10/20/2000 5:05 PM     38,430   6%     35,995  sound\voices\BoB\
tt_28.wav      10/20/2000 5:05 PM     40,698   13%    35,580  sound\voices\BoB\
tt_29.wav      10/20/2000 5:05 PM     36,074   17%    29,767  sound\voices\BoB\
tt_30.wav      10/20/2000 5:05 PM     83,012   5%     79,167  sound\voices\BoB\
tt_31.wav      10/20/2000 5:05PM      55,530   14%    47,706  sound\voices\BoB\
tt_32.wav      10/20/2000 5:05 PM     52,040   15%    44,369  sound\vojces\BoB\
tt_33.wav      10/20/2000 5:05 PM     96,360   10%    86,316  sound\voices\BoB\
tt_34.wav      10/20/2000 5:05 PM     100,896  5%     96,263  sound\voices\BoB\
tt_35.wav      10/20/2000 5:05 PM     104,038  10%    93,172  sound\voices\BoB\
tt_36.wav      10/20/2000 5:05 PM     34,940   4%     33,701  sound\voices\BoB\
tt_37.wav      10/20/2000 5:05 PM     81,704   12%    71,904  sound\voices\BoB\
tt_38.wav      10/20/2000 5:05 PM     58,670   19%    47,593  sound\voices\BoB\
tt_39.wav      10/20/2000 5:05 PM     57,012   4%     54,683  sound\voices\BoB\
tt_40.wav      10/20/2000 5:05 PM     94,790   5%     90,171  sound\voices\BoB\
tt_41.wav      10/20/2000 5:05 PM     89,030   7%     82,981  sound\voices\BoB\
tt_42.wav      10/20/2000 5:05 PM     76,556   14%    65,952  sound\voices\BoB\
tt_43.wav      10/20/2000 5:05 PM     67,744   10%    60,694  sound\voices\BoB\
tt_44.wav      10/20/2000 5:05 PM     44,188   20%    35,183  sound\voices\BoB\
voc_01.wav     10/20/2000 5:05 PM     51,640   12%    45,423  sound\voices\BoB\
voc_02.wav     10/20/2000 5:05 PM     37,916   12%    33,258  sound\voices\BoB\
voc_03.wav     10/20/2000 5:05 PM     40,364   9%     36,548  sound\voices\BoB\
voc_04.wav     10/20/2000 5:05 PM     60,412   4%     57,815  sound\voices\BoB\
voc_05.wav     10/20/2000 5:05 PM     56,172   6%     52,986  sound\voices\BoB\
voc_06.wav     10/20/2000 5:05 PM     41,284   3%     39,918  sound\voices\BoB\
voc_07.wav     10/20/2000 5:05 PM     49,442   9%     45,003  sound\voices\BoB\
voc_08.wav     10/20/2000 5:05 PM     61,656   5%     58,449  sound\voices\BoB\
voc_09.wav     10/20/2000 5:05 PM     44,306   7%     41,295  sound\voices\BoB\
voc_10.wav     10/20/2000 5:05 PM     58,298   9%     52,997  sound\voices\BoB\
voc_11.wav     10/20/2000 5:05 PM     55,050   18%    45,254  sound\voices\BoB\
voc_12.wav     10/20/2000 5:05 PM     40,614   9%     37,135  sound\voices\BoB\
voc_13.wav     10/20/2000 5:05 PM     43,068   4%     41,307  sound\voices\BoB\
voc_14.wav     10/20/2000 5:05 PM     45,512   9%     41,619  sound\voices\BoB\
voc_15.wav     10/20/2000 5:05 PM     47,532   3%     45,886  sound\voices\BoB\
voc_16.wav     10/20/2000 5:05 PM     40,756   3%     39,412  sound\voices\BoB\
yoc_17.wav     10/20/2000 5:05 PM     52,070   7%     48,546  sound\voices\BoB\
voc_18.wav     10/20/2000 5:05 PM     55,394   6%     51,854  sound\voices\BoB\
voc_19.wav     10/20/2000 5:05 PM     74,718   8%     68,688  sound\voices\BoB\
voc_20.wav     10/20/2000 5:05 PM     47,504   10%    42,821  sound\voices\BoB\
voc_21.wav     10/20/2000 5:05 PM     52,034   7%     48,188  sound\voices\BoB\
voc_22.wav     10/20/2000 5:05 PM     36,558   10%    32,925  sound\voices\BoB\
voc_23.wav     10/20/2000 5:05 PM     35,880   4%     34,606  sound\voices\BoB\
voc_24.wav     10/20/2000 5:05 PM     28,234   4%     27,227  sound\voices\BoB\
voc_25.wav     10/20/2000 5:05 PM     50,004   14%    42,898  sound\voices\BoB\
voc_26.wav     10/20/2000 5:05 PM     62,516   10%    56,117  sound\voices\BoB\
voc_27.wav     10/23/2000 3:01 PM     49,444   5%     46,934  sound\voices\BoB\
voc_28.wav     10/23/2000 3:05 PM     54,600   6%     51,556  sound\voices\BoB\
Kreechurs.tga  4/6/2001 1 :08 PM      65,580   99%    873     team_icon\
Kreechurs_blue.tga     4/6/2001 1 :09 PM      65,580   98%    1,030   team_icon\
Kreechurs_red.tga      4/6/2001 1 :09 PM      65,580   98%    1,016   team_icon\
Kreechurs.roq  5/09/2001 5:45 PM      1,078,120      9%      976,146 ui\assets\
Kreechurs.tga  3/2/2001 11 :57 AM     65,580   99%    873     ui\assets\
Kreechurs_metal.tga    3/2/2001 10:58 AM      65,580   74%    16,883  ui\assets\
Kreechurs_name.tga     3/2/200111:16AM 131,116  91%    11,640  ui\assets\
Kreechurs_name_alt.tga         3/2/200111:05AM 131,116  97%    3,870   ui\assets\
 
188 file(s)            12,590,550      25%    9,496,872
+

TOP

+

Appendix K: A + Minimal Team

+

The following list is the + minimum number of files needed to make a new team and assumes that the team + creator is using both the Janet and James models (the models shipped with Quake + III: Team Arena) and the pre-existing heads that work with those models. Note + that no sound or voice files are necessary. No head files are necessary. When + adding new heads, refer to the Kreecha head in + Appendix J. When reskinning previously created heads, + refer to the Callisto/Lily head in Appendix J. Use + this list as a reference when creating your own team pak + files.

+
tm_kreechurs.pk3
Name    Modified       Size    Ratio   Packed  Path
kreechurs.team  5/9/2001 12:01 PM      1,968   61%     770
kreechurs_readme.txt   5/9/2001       3,162   59%     1,286   
blue.tga       10/23/2000 7: 17 PM    196,626        41%     115,756         models\players\James\kreechurs\
lower_blue.skin        4/6/2001 11 :20 AM     203     52%     98         models\players\James\kreechurs\
lower_default.skin     4/6/200 111:25AM       204     50%     102         models\players\James\kreechurs\
lower_red.skin  4/6/2001 11:20AM       204     50%     102         models\players\James\kreechurs\
red.tga        10/23/2000 7:17 PM     196,626        43%     111,607         models\players\James\kreechurs\
upper_blue.skin        41612001 11:20AM       281     58%     118         models\players\James\kreechurs\
upper_default.skin     416/2001 11:25AM       282     58%     119         models\players\James\kreechurs\
upper_red.skin  4/6/2001 11 :20 AM     282     58%     119         models\players\James\kreechurs\
blue.tga       10/23/2000 7: 17 PM    196,626        41%     115,756         models\players\Janet\kreechurs\
lower_blue.skin        4/6/2001 11 :20 AM     203     52%     98         models\players\Janet\kreechurs\
lower_default.skin     4/6/200 111:25AM       204     50%     102         models\players\Janet\kreechurs\
lower_red.skin  4/6/2001 11:20AM       204     50%     102         models\players\Janet\kreechurs\
red.tga        10/23/2000 7:17 PM     196,626        43%     111,607         models\players\Janet\kreechurs\
upper_blue.skin        41612001 11:20AM       281     58%     118         models\players\Janet\kreechurs\
upper_default.skin     416/2001 11:25AM       282     58%     119         models\players\Janet\kreechurs\
upper_red.skin  4/6/2001 11 :20 AM     282     58%     119         models\players\Janet\kreechurs\
kreechurs.bot  5/9/2001 11 :43 AM     405     70%     123     scripts\
kreechurs.shader       4/6/2001 3:05 PM       500     67%     163     scripts\
kreechurs.tga  4/6/2001 1 :08 PM      65,580   99%    873     team_icon\
kreechurs_blue.tga     4/6/2001 1 :09 PM      65,580   98%    1,030   team_icon\
kreechurs_red.tga      4/6/2001 1 :09 PM      65,580   98%    1,016   team_icon\
kreechurs.tga  3/2/2001 11 :57 AM     65,580   99%    873     ui\assets\
kreechurs_metal.tga    3/2/2001 10:58 AM      65,580   74%    16,883  ui\assets\
kreechurs_name.tga     3/2/200111:16AM 131,116  91%    11,640  ui\assets\
kreechurs_name_alt.tga         3/2/200111:05AM 131,116  97%    3,870   ui\assets\
 
27 file(s)             1,354,162              271,112 
+

TOP

+

Appendix L: + Contents of the TAhead_lily.pk3

+

The following list is + taken directly from the contents of the pak file + that contains the Lily head model that is a part of the Kreechurs + team. Lily is based on the Callisto head model from + the original TA game (blinking female head with red or blue hair cut in a + pageboy style). Use this as a reference when creating your own pak files for new character heads.

+
TAhead_lily.pk3
 
Name    Modified       Size    Ratio   Packed  Path
Lily.vc        5/112001 6:56 PM       23      0%      23      scripts\Callisto\
red_Iily.shader        4/9/20011:18 PM        557     79%     117     scripts\
lily .shader   4/9/2001 1: 19 PM      528     78%     114      scripts\
blue_lily.shader       5/1/20015:50 PM        566     79%     119     scripts\
Lily_redface2.tga      4/3/200111:41 PM       16,428  32%     11,092         models\players\heads\Callisto\Lily\
Lily_redface.tga       4/3/2001 11 :40 PM     16,428  33%     11,062         models\players\heads\Callisto\Lily\
Lily_red.tga   4/2/2001 2:14 PM       65,580  79%     13,873         models\players\heads\Callisto\Lily\
Lily_blueface2.tga     4/3/2001 11 :42 PM     16,428  32%     11, 182         models\players\heads\Callisto\Lily\
Lily_blueface.tga      4/3/200111:41 PM       16,428  32%     11,174         models\players\heads\Callisto\Lily\
LJily_blu.tga  4/10/2001 12:55 AM     65,580  33%     43,929         models\players\heads\Callisto\Lily\
icon_red.tga   3/27/20016:15 AM       12,306  30%     8,581         models\players\heads\Callisto\Lily\
icon_default.tga       3/27/20016:15 AM       12,306  30%     8,595         models\players\heads\Callisto\Lily\
icon_blue.tga  3/29/2001 10:20 PM     16,428  41%     9,707         models\players\heads\Callisto\Lily\
head_red.skin  4/17/20014:35 PM       125     44%     70         models\players\heads\Callisto\Lily\
head_default.skin      4/17/20014:35 PM       126     41%     74         models\players\heads\Callisto\Lily\
head_blue.skin  4/17/20014:33 PM       126     44%     71         models\players\heads\Callisto\Lily\
 
16 file(s)             239,963        46%     129,783
 
+

TOP

+
+

 

+
+ +

 

+ +
+ + + + diff --git a/docs/manual/quake3/Q3AShader_Manual/appendix/appA.html b/docs/manual/quake3/Q3AShader_Manual/appendix/appA.html new file mode 100644 index 00000000..907f7f38 --- /dev/null +++ b/docs/manual/quake3/Q3AShader_Manual/appendix/appA.html @@ -0,0 +1,60 @@ + + +Quake III Arena Shader Manual: Appendix A + + + +

Q3Radiant Shader Manual

+ +TTimo
+2001.31.08
+
+
+

Appendix A: usage of targetShaderName and targetShaderNewName

+ +

+The targetShaderName and targetShaderNewName keys can be used with any entity +that supports the target key (the entity instance does not actually have to use +the target key for these new keys to work). If both are defined, then when the +entity decides to activate its targets, all shaders/textures in the map that +were originally the same name as the targetShaderName value, will be changed to +the targetShaderNewName value. +

+ +

+For example this would make it look like the red light shader is "turning on": +

+ +

+"targetShaderName" "textures/proto2/redlight_off"
+"targetShaderNewName" "textures/proto2/redlight_on" +

+ +

+And this would turn it back off: +

+ +

+"targetShaderName" "textures/proto2/redlight_off"
+"targetShaderNewName" "textures/proto2/redlight_off" +

+ +

+Note that the ORIGINAL shader name is used in both instances, not whatever it +happens to be currently. Also, of course, this will happen globally. If the +mapper wanted to affect only a certain set of red lights, he/she would need to +make a unique shader name to be used with that set. +

+ +

+The code that supports these keys is in G_UseTargets in g_utils.c. +

+ +

+For more information, see this thread:
+ +http://www.quake3world.com/ubb/Forum6/HTML/014812.html#9 + +

+ + diff --git a/docs/manual/quake3/Q3AShader_Manual/ch01/pg1_1.htm b/docs/manual/quake3/Q3AShader_Manual/ch01/pg1_1.htm new file mode 100644 index 00000000..4edf8735 --- /dev/null +++ b/docs/manual/quake3/Q3AShader_Manual/ch01/pg1_1.htm @@ -0,0 +1,126 @@ + + +Quake III Arena Shader Manual: Introduction + + + +

Q3Radiant Shader Manual

+
+

1 Preface: Making Your Own Shaders

+ +The Manual for the Q3Radiant editor program contains a section called Creating New Assets that has the necessary information for setting up the files to create your own custom Quake III Arena shaders. It is recommended that you study the scripts in this document and in the individual shader scripts. Pay careful attention to syntax and punctuation. This is where you are most likely to make mistakes. + +

2 Introduction

+ +The graphic engine for QuakeIII Arena has taken a step forward by putting much more direct control over the surface +qualities of textures into the hands of designers and artists. In writing this manual, we have tried to define the +concepts and tools that are used to modify textures in a way that, it is hoped, will be graspable by users who already have basic knowledge ofcomputer graphics but are not necessarily computer programmers. It is not a tutorial, nor was it intended to be one. + +

2.1 What is a Shader?

+ +Shaders are short text scripts that define the properties of a surface as it appears and functions in a game world (or compatible editing tool). By convention, the documents that contain these scripts usually has the same name as the texture set which contains the textures being modified (e.g; base, hell, castle, etc,). Several specific script documents have also been created to handle special cases, like liquids, sky and special effects. + +

For Quake III Arena,Shader scripts are located in quake3/baseq3/scripts. + +

A Quake III Arena shader file consists of a series of surface attribute and rendering instructions formatted +within braces ("{" and "}"). Below you can see a simple example of syntaxand format for a single process, including the +Q3MAP keywords or "SurfaceParameters", which follow the first bracket and a single bracketed "stage": + +

textures/liquids/lava
+	{
+	deformVertexes wave sin 0 3 0 0.1
+	tessSize 64
+	{
+	map textures/common/lava.tga
+	}
+}
+
+ +

2.2 Shader Name & File Conventions

+The first line is the shader name. Shader names can be up to 63 characters long. The names are often a mirror of +a pathname to a .tga file without the extension or base dir (/quake3/baseq3 in ourcase), but they do not need to be. + +

Shaders that are only going to be referenced by the gamecode, not modeling tools, often are just a single world, +like"projectionShadow" or "viewBlood". + +

Shaders that are used on characters or other polygon models need to mirror a .tga file, which allows the modelers to build with normal textures, then have the special effects show up when the model is loaded into the game. + +

Shaders that are placed on surfaces in the map editor commonly mirror a .tga file, but the "qer_editorimage" shader parameter canforce the editor to use an arbitrary image for display. + +

Shader pathnames have a case sensitivity issue - on windows, they aren't case sensitive, but on unix they are. Try to always use lowercase for filenames, and always use forward slashes "/" for directory separators. + +

2.3 Shader Types

+The keywords that affect shaders are divided into two classes. The first class of keywords are global parameters. Some global parameters ("surfaceparms." And all "q3map_" keywords) are processed by Q3MAP, and change physical attributes of the surface that uses the shader. These attributes can affect the player. To see changes in these +parameters one must re-bsp the map. + +

The remaining global keywords, and all Stage Specific Keywords are processed by the renderer. They are appearance changes +only and have no effect on game play or game mechanics. Changes to any of these attributes will take effect as soon as the game goes to another level or vid_restarts (type command vid_restart in the game console). + +

Shader keywords are notcase sensitive. + +

IMPORTANT NOTE: some of the shader commands may be order dependent, so it's good practice to place all global shader commands (keywords defined in this section) at the very beginning of the shader and to place shader stages at the end (see various examples). + +

2.4 Key Concepts

+ +Ideally, a designer or artist who is manipulating textures with shader files has a basic understanding of wave forms and knows about mixing colored light (high school physics sort of stuff). If not, there are some concepts you need to have a +grasp on to make shaders work for you. + +

2.4.1 Surface Effects vs. Content Effects vs. Deformation Effects
+Shaders not only modify the visible aspect of textures on a geometry brush, curve, patch or mesh model, but they can also have an effect on both the content, "shape," and apparent movement of those things. A surface effect does nothing to modify +the shape or content of the brush. Surface effects include glows, transparencies and rgb (red, green, blue) value +changes. Content shaders affect the way the brush operates in the game world. Examples include water, fog, nonsolid, and +structural. Deformation effects change the actual shape of the affected brush or curve, and may make it appear to move. + +

2.4.2 Power Has a Price
+The shader script gives the designer, artist and programmer a great deal of easily accessible power over the appearance of +and potential special effects that may be applied to surfaces in the gameworld. But it is power that comes with a price tag +attached, and the cost is measured in performance speed. Each shader phase that affects the appearance of a texture causes the Q3:Aengine to make another processing pass and redraw the world. Think of it as if you were adding all +the shader-affected triangles to the total r_speed count for each stage in the shader script. A shader-manipulated texture that is seen through another shader-manipulated texture (e.g. a light in fog) has the effect of adding the total number of passes together for the affected triangles. A light that required two passes seen through a fog that requires one pass will be treated as having to redraw that part of the world three times. + +

2.4.3 RGB Color
+ +RGB means "Red, Green, Blue."Mixing red, green and blue light in differing intensities creates the colors in computers and television monitors. This is called additive color (as opposed to the mixing of pigments in paint or colored ink in the printing process, which is subtractive color). In Quake III Arena and most higher-end computer art programs (and the color selector in Windows), the intensities ofthe individual Red, Green and Blue components are expressed as number values. When mixed together on a screen, number values of equal intensity in each component color create a completely neutral (gray) color. The lower the number value (towards 0), the darker the shade. The higher the value, the lighter the shade or the more saturated the color until it reaches a maximum value of 255 (in the art programs). All colors possible on the computer can be expressed as a formula of three numbers. The value for complete black is 0 0 0. The value for complete white is 255 255 255. However, the QuakeIII Arena graphics engine requires that the color range be "normalized" into a range between 0.0 and 1.0. + +

2.4.4 Normalization: a Scale of 0 to 1
+The mathematics in Quake III Arena use a scale of 0.0 to 1.0 instead of 0 to 255. Most computer art programs that can express RGB values as numbers use the 0 to 255 scale. To convert numbers, divide each of the artprogram's values for the component colors by 255. The resulting three values are your Quake III Arena formula for that color component. The same holds true for texture coordinates. + +

2.4.5 Texture Sizes
+TGA texture files are measured in pixels (picture elements). Textures are measured in powers of 2, with 16 x16 pixels being the smallest (typically) texture in use. Most will be larger. Textures need not be square, so long as both dimensions are powers of 2. Examples include: 32x256, 16x32, 128x16. + +

2.4.6 Color Math
+ +In Quake III Arena , colors are changed by mathematical equations worked on the textures by way ofthe scripts or +"programlets" in the shader file. An equation that adds to or multiplies the number values in atexture causes it to become +darker. Equations that subtract from or modulate number values in a texture cause it to become lighter. Either equation can change the hue and saturation of a color. + +

2.4.7 Measurements
+ +The measurements used in the shaders are in either game units, color units, or texture units. + +

· Game unit: A game unit is used by deformations to specify sizes relative to the world. Game units are the same scale we have had since way back in the Wolfensteindays - 8 units equals one foot. The default texture scale used by the Q3Radiant map editor results in two texels for each game unit, but that can be freely changed. + +

· Color units: Colors scale the values generated by the texture units to produce lighting effects. A value of 0.0 will be completely black, and a value of 1.0 will leave the texture unchanged. Colors are sometimes specified with a single value to be used across all red, green,and blue channels, or sometimes as separate values for each channel. + +

· Texture units: This is the normalized (see above) dimensions of the original texture image (or a previously modified texture at a given stage in the shader pipeline). A full texture, regardless of its original size in texels, has a normalized measurement of 1.0 x 1.0. For normal repeating textures, it is possible to have value greater than 1.0 or less than 0.0, resulting in repeating of the texture. The coordinates are usually assigned by the level editor or +modeling tools, but you still need to be aware of this for scrolling or turbulent movement of the texture at runtime. + +

2.4.8 Waveform Functions
+Many of the shader functions use waveforms to modulate measurements over time. Where appropriate, additional information is provided with wave modulated keyword functions to describe the effect of a particular waveform on that process. Currently there are five waveforms in use in Q3A shaders: + +

Sin: Sin standsfor sine wave, a regular smoothly flowing wave ranging from -1 to 1. +
Triangle: Triangle is a wave with a sharp ascent and a sharp decay, ranging from 0 to 1.It will make a choppy looking wave forms. +
Square: A squarewave simply switches from -1 to 1 with no in-between. +
Sawtooth: In the sawtooth wave, the ascent is like a triangle wave from 0 to 1, but the decay cuts off sharply back to 0. +
Inversesawtooth: This is the reverse of the sawtooth… instant ascent to the peak value (1), then a triangle wave descent to the valley value (0). The phase on this goes from 1.0 to 0.0 instead of 0.0 to 1.0. This wave is particularly usefulfor additive cross-fades. + +

Waveforms all have thefollowing properties: +
<base> Where the wave form begins. Amplitude is measured from this base value. +
<amplitude> This is the height of the wave created, measured from the base. You will probably need to test and tweak this value to get it correct for each new shader stage. The greater the amplitude, the higher the wave peaks and the deeper the valleys. +
<phase> This is a normalized value between 0.0 and 1.0. Changing phase to a non-zero value affects the point on the wave at which the wave form initially begins to be plotted. Example: In Sin or Triangle wave, a phase of 0.25 means it begins one fourth (25%) of the way along the curve, or more simply put, it begins at the peak of the wave. A phaseof 0.5 would begin at the point the wave re-crosses the base line. A phase of 0.75 would be at the lowest point of the valley. If only one wave form is being used in a shader, a phase shift will probably not be noticed and phase should have a value of zero (0). However, including two or more stages of the same process in a single shader, but with the phases shifted can be used to create interesting visual effects. Example: using rgbGen in two stages with different colors and a 0.5 difference in phase would cause the manipulated texture to modulate between two distinct colors. Phase changes can also be used when you have two uses of the same effect near each other, and you don't want them to be synchronized. You would write a separate shader for each, changing only the phase value. +
<freq>Frequency. This value is expressed as repetitions or cycles of the wave per second. A value of 1 +would cycle once per second. A value of 10 would cycle 10 times per second. A value of 0.1 would cycle once every 10 +seconds. +

Back | Home | Next + + + \ No newline at end of file diff --git a/docs/manual/quake3/Q3AShader_Manual/ch02/pg2_1.htm b/docs/manual/quake3/Q3AShader_Manual/ch02/pg2_1.htm new file mode 100644 index 00000000..9bdf0c35 --- /dev/null +++ b/docs/manual/quake3/Q3AShader_Manual/ch02/pg2_1.htm @@ -0,0 +1,222 @@ + + +Quake III Arena Shader Manual: General Shader Keywords + + + +

Q3Radiant Shader Manual

+
+

3 General Shader Keywords

+IMPORTANT NOTE: Once again, be aware that some of the shader commands may be order dependent, so it's good practice to place all global shader commands (keywords defined inthis section) at the very beginning of the shader and to place shader stages at the end (see various examples). + +

These Keywords are global to a shader and affect all stages. They are also ignored by Q3MAP. + +

3.1 skyParms <farbox> <cloudheight> <nearbox>

+ +Specifies how to use the surface as a sky, including an optional far box (stars, moon, etc), optional cloud layers with any shader attributes, and an optional near box (mountains in front of the clouds, etc). + +

<farbox> Specifies a set of files to use as an environment box behind all cloudlayers. Specify "-" for no +farbox, or a file base name. A base name of "env/test" would look for files "env/test_rt.tga", "env/test_lf.tga", +"env/test_ft.tga", "env/test_bk.tga", "env/test_up.tga", "env/test_dn.tga" to use as the right / left / front / back / up / +down sides. + +
<cloudheight> controls apparent curvature of the cloud layers - lower numbers mean more curvature (and thus more distortion at the horizons). Higher height values create "flatter" skies with less horizon distortion. Think of height +as the radius of a sphere on which the clouds are mapped. Good ranges are 64 to 256. The default value is 128. + +
<nearbox> Specified as farbox, to be alpha blended ontop of the clouds. This has not be tested in a long time, so it probably doesn't actually work. Set to "-" to ignore. + +

Design Notes: + +
  • If you are making a map where the sky is seen by looking up most of the time, use a lower cloudheight value. Under those circumstances the tighter curve looks more dynamic. If you are making a map where the sky is seen by looking out windows most of the time or has a map area that is open to the sky on one or more sides, use a higher height to make the clouds seem more natural. + +
  • It is possible to create a sky with up to 8 cloudlayers, but that also means 8 processing passes and a potentially large processing hit. + +
  • Be aware that the skybox does not wrap around the entire world. The "floor" or bottom face of the skybox is not drawn by the game. If a player in the game can see that face, they will see the "hall of mirrors" effect.
+ +

Example: Sky script + +

textures/skies/xtoxicsky_dm9
+{
+	qer_editorimage textures/skies/toxicsky.tga
+	surfaceparm noimpact
+	surfaceparm nolightmap
+q3map_globaltexture
+q3map_lightsubdivide 256
+	q3map_surfacelight 400
+	surfaceparm sky
+	q3map_sun 1 1 0.5 150 30 60
+	skyparms full 512 -
+	{
+		map textures/skies/inteldimclouds.tga
+		tcMod scroll 0.1 0.1
+		tcMod scale 3 2
+	}
+	{
+		map textures/skies/intelredclouds.tga
+		blendFunc add
+		tcMod scroll 0.05 0.05
+		tcMod scale 3 3
+	}
+}
+
+ +

3.2 cull <side>

+Every surface of a polygon has two sides, a front and a back. Typically, we only see the front or "out" side. For +example, a solid block you only show the front side. In many applications we see both. For example, in water, you can see both front and a back. The same is true for things like grates and screens. + +

To "cull" means to remove. The value parameter determines the type of face culling to apply. The default value is cull front if this keyword is not specified. However for items that should be inverted then the value back should be used. To disable culling, the value disable ornone should be used. Only one cull instruction can be set +for the shader. + +

3.2.1 cull front
+ +The front or "outside" of the polygon is not drawn in the world. This is the default value. It is used if the keyword "cull " appears in the content instructions without a <side>value or if the keyword cull does not appear at all in the shader. + +

3.2.2 cull back
+ +Cull back removes the back or "inside" of a polygon from being drawn in the world. + +

3.2.3 cull disable, cull none
+Neither side of the polygon is removed. Both sides are drawn in the game. Very useful for making panels or barriers that +have no depth, such as grates, screens, metal wire fences and so on and for liquid volumes that the player can see from within. Also used for energy fields, sprites, and weapon effects (e.g. plasma). + +

Design Notes: For things like grates and screens, put the texture with the cull none property on one face only. On the other faces, use a non-drawing texture.
+ +

3.3 deformVertexes

+ +This function performs a general deformation on the surface's vertexes, changing the actual shape of the surface before drawing the shader passes. You can stack multiple deformVertexes commands to modify positions in more complex ways, making an object move in two dimensions, for instance. + +

3.3.1 +deformVertexes wave <div> <func> +<base><amplitude> <phase> <freq>
+ +Designed for water surfaces, modifying the values differently at each point. It accepts the standard wave functions of the type sin,triangle, square, sawtooth orinversesawtooth . The "div" parameter is used to +control the wave "spread" - a value equal to the tessSizeof the surface is a good default value (tessSize is subdivision size, in game units, used for the shader when seen in the game world). + +

3.3.2 +deformVertexes normal <div> <func> +<base><amplitude ~0.1-~0.5> <frequency +~1.0-~4.0>
+ +This deformation affects the normals of a vertex without actually moving it, which will effect later shader options like +lighting and especially environment mapping. If the shader stages don't use normals in any of their calculations, there will +be novisible effect. + +

Design Notes: Putting values of 0.1 to 0.5 in Amplitude and 1.0 to 4.0 in the Frequency can produce some satisfying results. Some things that have been done with it: A small fluttering bat, falling leaves, rain, flags.
+ +

3.3.3 +deformVertexes bulge <bulgeWidth> +<bulgeHeight><bulgeSpeed>
+ +This forces a bulge to move along the given s and t directions. Designed for use on curved pipes. + +

Specific parameter definitions for deform keywords: + +
<div> This is roughly defined as the size of the waves that occur. It is measured in game units. Smaller +values create agreater density of smaller wave forms occurring in a given area. Larger values create a lesser density of waves, or otherwise put, the appearance of larger waves. To look correct this value should closely correspond to the value (in pixels) set for tessSize (tessellation size) of the texture. A value of 100.0 is a good default value (which means your tessSize should be close to that for things tolook "wavelike"). + +
<func> This is the type of wave form being created. Sin stands for sine wave, a regular smoothly flowing +wave. Triangle is a wave with a sharp ascent and a sharp decay. It will make a choppy looking wave forms. A square +wave is simply on or off for the period of the frequency with no in between. The sawtooth wave has the ascent of a triangle wave, but has the decay cut off sharply like a square wave. An inversesawtooth wave reverses this. + +
<base> This is the distance, in game units that the apparent surface of the texture is displaced from the +actual surface of the brush as placed in the editor. Apositive value appears above the brush surface. A negative value appears below the brush surface. An example of thisis the Quad effect, which essentially is a shell with a positive base value to stand it away from the model surface and a 0 (zero) value for amplitude. + +
<amplitude> The distance that the deformation moves away from the base value. See Wave Forms in the introduction for a description of amplitude. + +
<phase> SeeWave Forms in the introduction for a description of phase) +
<frequency> See Wave Forms in the introduction for a description of frequency) + +

Design Note: The div and amplitude parameters, when used in conjunction with liquid volumes like water should take into consideration how much the water will be moving. A large ocean area would have have massive swells (big div values) that rose and fell dramatically (big amplitude values). While a small, quiet pool may move very little.
+ +

3.3.4 +deformVertexes move<x> <y> <z> <func> +<base> <amplitude> <phase> <freq>
+ +This keyword is used to make a brush, curve patch or md3model appear to move together as a unit. The <x> <y> +and <z> values are the distance and direction in game units the object appears to move relative to it's point of origin in the map. + +

The <func> <base> <amplitude><phase> and <freq> values are the same as found in other wave +form manipulations. + +

The product of the function modifies the values x, y, and z.Therefore, if you have an amplitude of 5 and an x value of 2, the object will travel 10 units from its point of origin along the x axis. This results in a total of 20 units of motion along the x axis, since the amplitude is the variation both above and below the base. + +

It must be noted that an object made with this shader does not actually change position, it only appears to. + +

Design Note: If an object is made up of surfaces with different shaders, all must have matching deformVertexes move values or the object will appear to tear itself apart.
+ +

3.3.5 +DeformVertexes autosprite
+ +This function can be used to make any given triangle quad (pair of triangles that form a square rectangle) automatically behave like a sprite without having to make it a separate entity. This means that the "sprite" on which the texture is placed will rotate to always appear at right angles to the player's view as a sprite would. Any four-sided brush side, flat patch, or pair of triangles in an .md3 model can have the autosprite effect on it. The brush face containing a texture with this shader keyword must besquare. + +

Design Note :This is best used on objects that would appear the same regardless of viewing angle. An example might be a glowing light flare.
+ +

3.3.6 +DeformVertexes autosprite2
+ +Is a slightly modified "sprite" that only rotates around the middle of its longest axis. This allows you to make a +pillar of fire that you can walk around, or an energy beam stretched across the room. + +

3.4 fogparms <red +value> <green value> <bluevalue> <distance to +Opaque>

+ +

Note: you must also specify "surfaceparm fog" to cause q3map to identify the surfaces inside the volume. Fogparms only +describes how to render the fog on the surfaces. + +

<red value> <green value> <blue value> These are normalized values. A good computer art program should give you the RGB values for a color. To obtain the values that define fog color for Quake III Arena, divide the desired color's Red, Green and Blue values by 255 to obtain three normalized numbers within the 0.0 to 1.0 range. + +
<distance toopaque> This is the distance, in game units, until the fog becomes totally opaque, as measured from the point of view of the observer. By making the height of the fog brush shorter than the distance to opaque, the apparent density of the fog can be reduced (because it never reaches the depth at which full opacity occurs). + +

  • The fog volume can only have one surface visible (from outside the fog). +
  • Fog must be made of one brush. It cannot be made of adjacent brushes. +
  • Fog brushes must be axial. This means that only square or rectangular brushes may contain fog, and those must have their edges drawn along the axes of the map grid (all 90 degree angles). +
+ +

Design Notes: + +
  • If a water texture contains a fog parameter, it must be treated as if it were a fog texture when in use. +
  • If a room is to be filled completely with a fog volume,it can only be entered through one surface (and still have the fog function correctly). +
  • Additional shader passes may be placed on a fog brush, as with other brushes.
+ +

3.5 nopicmip

+This causes the texture to ignore user-set values for the r_picmip cvar command. The image will always be high +resolution. Example: Used to keep images and text in the heads up display from blurring when user optimizes the game graphics. + +

3.6 nomipmaps

+This implies nopicmip, but also prevents the generation of any lower resolution mipmaps for use by the 3d card. This will +cause the texture to alias when it gets smaller, but there are some cases where you would rather have this than a blurry image. Sometimes thin slivers of triangles force things to very low mipmap levels, which leave a few constant pixels on otherwise scrolling special effects. + +

3.7 polygonOffset

+Surfaces rendered with the polygonOffset keyword are rendered slightly off the polygon's surface. This is typically +used for wall markings and "decals." The distance between the offset and the polygon is fixed. It is not a variable in QuakeIII Arena. + +

3.8 portal

+Specifies that this texture is the surface for a portal or mirror. In the game map, a portal entity must be placed directly in front of the texture (within 64 game units). All this does is set "sortportal", so it isn't needed if you specify +that explicitly. + +

3.9 sort <value>

+Use this keyword to fine-tune the depth sorting of shaders as they are compared against other shaders in the game world. The +basic concept is that if there is a question or a problem with shaders drawing in the wrong order against each other, this allows the designer to create a hierarchy ofwhich shader draws in what order. + +

The default behavior is to put all blended shaders in sort "additive" and all other shaders in sort "opaque", so you only +need to specify this when you are trying to work around a sorting problem with multiple transparent surfaces in a scene. + +

The value here can be either a numerical value or one of the keywords in the following list (listed in order of ascending priority): + +

    portal (1): This surface is a portal, it draws over every other shader seen inside the portal, but before anything in the main view. + +
    Sky (2): Typically, the sky is the farthest surface in the game world. Drawing this after other opaque surfaces can be an optimization on some cards. This currently has the wrong value for this purpose, so it doesn't do much of anything. + +
    Opaque (3):This surface is opaque (rarely needed since this is the default with noblendfunc) + +
    Banner (6) :Transparent, but very close to walls. + +
    Underwater (8): Draw behind normal transparent surfaces. + +
    Additive (9): normal transparent surface (default for shaders with blendfuncs) +
    nearest (16):this shader should always sort closest to the viewer, e.g. muzzle flashes and blend blobs
+

Back | Home | Next + + + \ No newline at end of file diff --git a/docs/manual/quake3/Q3AShader_Manual/ch03/pg3_1.htm b/docs/manual/quake3/Q3AShader_Manual/ch03/pg3_1.htm new file mode 100644 index 00000000..00a4ed66 --- /dev/null +++ b/docs/manual/quake3/Q3AShader_Manual/ch03/pg3_1.htm @@ -0,0 +1,197 @@ + + +Quake III Arena Shader Manual: Specific Shader Keywords + + + +

Q3Radiant Shader Manual

+
+

4 Q3MAP Specific Shader Keywords

+These keywords change the physical nature of the textures and the brushes that are marked with them. Changing any of these values will require the map to be re-compiled. These are global and affect the entire shader. + +

4.1 tessSize <amount>

+For consistency's sake, this really should have been called q3map_tessSize. But it wasn't. The tessSize shader controls +the tessellation size (how finely a surface is chopped up in to triangles), in game units, of the surface. This is only +applicable to solid brushes, not curves, and is generally only used on surfaces that are flagged with the deformVertexes keyword. Abuse of this can create a huge number of triangles. This happens during q3map processing, so maps must be reprocessed for changes to take effect. + +

Design Note: It can also be used on tesselating surfaces to make sure that tesselations arelarge, and thus, less costly in terms of triangles created.
+ +

4.2 q3map_backshader <shadername>

+This allows a brush to use a different shader when you are inside it looking out. By way of example, this would allow a water brush (or other) surfaces to have a different sort order (see sort above) or appearance when seen from the inside. + +

4.3 q3map_globaltexture

+Use this shader in the global keyword commands whenever the tcMod scale function is used in one of the later render stages. Many problems with getting shader effects to work across multiple adjacent brushes are a result of the way q3map optimizes texture precision. This option resolves that, but at the expense of some precision of the textures when they are far away from the origin of the map. + +

4.4 q3map_sun <red> <green> <blue> <intensity> <degrees> <elevation>

+This keyword in a sky shader will create the illusion of light cast into a map by a single, infinitely distance light source (sun, moon, hellish fire, etc.). This is only processed during the lighting phase of q3map. + +

<red><green> <blue> Color is described by three normalized rgbvalues. Color will be normalized to a 0.0 to 1.0 range, so it doesn't matter what range you use. + +
<intensity> is the brightness of the generated light. A value of 100 is a fairly bright sun. The +intensity of the light falls off with angle but not distance. + +
<degrees> is the angle relative to the directions on the map file. A setting of 0 degrees equals east. 90 +isnorth, 180 is west and 270 is south. + +
<elevation> is the distance, measured in degrees from the horizon (z value of zero in the map file). An +elevation of 0 is sunrise/sunset. An elevation of 90 is noon. + +

DESIGN NOTE: Sky shaders should probably still have aq3map_surfacelight value. The "sun" gives a strong directional light, but doesn't necessarily give the fill light needed to soften and illuminate shadows. Skies with clouds should probably have a weaker q3map_sunvalue and a higher q3map_surfacelight value. Heavy clouds diffuse light and weaken shadows. The opposite is true of a cloudless or nearly cloudless sky. Insuch cases, the "sun" or "moon" will cast stronger, shadows that have a greater degree of contrast. + +

Design Trick: Not certain what color formula you want to use for the sun's light? Try this. Create a light entity. Use the Q3Radiant editor's color selection tools to pick a color. The light's _color key's value will be the normalized RGB formula. Copy it from the value line in the editor (CTRL+c) and paste it into your shader.

+ +

4.5 q3map_surfaceLight <light value>

+ +The texture gives off light equal to the <light value> set for it. The relative surface area of the texture in the world affects the actual amount of light that appears to be radiated. To give off what appears to be the same amount +of light, a smaller texture must be significantly brighter than a larger texture. Unless the qer_lightimage keyword is used to select a different source for the texture's light color information, the color of the light will be the averaged color of the texture. + +

4.6 q3map_lightimage <texturepath/texturename>

+The keyword q3map_lightimage generates lighting from the average color of the TGA image specified by the +q3map_lightimage. + +

The keyword sequence for generating light on a q3map_surfacelight should be ordered as follows: + +

  1. q3map_lightimage ; (the texture providing the light and the color of the light) +
  2. qer_editorimage ; (the editor-only image used to select the source map for the texture) +
  3. the average color of the light emitted from the shader is calculated from the lightimage.)
+ +

The reason q3map_lightimageis specified for the light in the example below, is because the blend map is predominantly yellow, and the designer wanted more yellow light to be emitted from the light. + +

Example: Taking light from another source texture + +

+textures/eerie/ironcrosslt2_10000
+{
+q3map_lightimagetextures/gothic_light/ironcrosslt2.blend.tga
+// this TGA is the source for the color of the blended light
+
+qer_editorimagetextures/gothic_light/ironcrosslt2.tga
+//base TGA (used because the shader is used with several
+// different light values
+
+q3map_surfacelight 10000
+//emitted light value of10,000
+
+{
+map $lightmap
+//source texture is affected by the lightmap
+rgbGen identity
+// this command handles the overbright bits created by "sunlight"
+// in the game
+}
+{
+maptextures/gothic_light/ironcrosslt2.tga
+blendFunc filter
+rgbGen identity
+}
+{
+maptextures/gothic_light/ironcrosslt2.blend.tga
+blendFunc add
+}
+}
+
+ +

4.7 q3map_lightsubdivide <value>

+This allows the user to define how large, or small to make the subdivisions (triangles) in a textured surface, particularly aimed at light-emitting textures like skies. It defaults to 120 game units, but can be made larger (256 or 512) for sky boxes or smaller for light surfaces at the bottoms of cracks. This can be a dominant factor in processing time for q3map lighting. + +

4.8 surfaceparm <parm>

+ +

All surfaceparm keywords are preceded by the word surfaceparm as follows: surfaceparm fogor surfaceparm noimpact. + +

4.8.1 alphashadow
+This keyword applied to a texture on a brush, patch or model will cause the lighting phase of the q3map process to use the texture's alpha channel as a mask for casting static shadows in the game world. + +

Design Note: Alphashadow does not work well with fine line detail on a texture. Fine lines may not cast acceptable shadows. It appears to work best with well-defined silhouettes and wider lines within the texture. Most of our tattered banners use this to cast tattered shadows.
+ +

4.8.2 areaportal
+A brush marked with this keyword functions as an area portal, a break in the Q3MAP tree. It is typically placed on a very thin brush placed inside a door entity (but is not a part of that entity). The intent is to block the game from processing +surface triangles located behind it when the door is closed. It is also used by the BSPC (bot area file creation compiler) in the same manner as a clusterportal. The brush must touch all the structural brushes surrounding the +areaportal. + +

4.8.3 clusterportal
+A brush marked with this keyword function creates a subdivision of the area file (.aas) used by the bots for navigation. It +is typically placed in locations that are natural breaks in a map, such a sentrances to halls, doors, tunnels, etc. The intent is keep the bot from having to process the entire map at once. As with the the areaportal parameter, the affected brush must touch all the structural brushes surrounding the areaportal. + +

4.8.4 donotenter
+Read as "do not enter." Like clusterportal, this is a bot-only property. A brush marked with donotenter will not affect +non-bot players, but bots will not enter it. It should be used only when bots appear to have difficulty navigating around some map features. + +

4.8.5 flesh
+This will cue different sounds (in a similar manner to metalsteps) and cause blood to appear instead of bullet impact flashes. + +

4.8.6 fog
+Fog defines the brush as being a "fog" brush. This is a Q3MAP function that chops and identifies all geometry inside the +brush. The General shader keyword fogparms must also be specified to tell how to draw the fog. + +

4.8.7 lava
+ +

Assigns to the texture the game properties set for lava. This affects both the surface and the content of a brush. + +

4.8.8 metalsteps
+The player sounds as if he is walking on clanging metal steps or gratings. Other than specifiying flesh, metalsteps, nosteps, or default (i.e. specify nothing) it is currently not possible for a designer to create or assign a specific sound routine to a texture. Note: If no sound is set for a texture, then the default footsteps sound routines are heard. + +

4.8.9 nodamage
+The player takes no damage if he falls onto a texture with this surfaceparm + +

4.8.10 nodlight
+Read as "No DeeLight". A texture containing this parameter will not be affected or lit by dynamic lights, such as +weapon effects. And example in Quake III Arena would be solid lava. + +

4.8.11 nodraw
+A texture marked with nodraw will not visually appear in the game world. Most often used for triggers, clip brushes, origin +brushes, and so on. + +

4.8.12 nodrop
+When a player dies inside a volume (brush) marked nodrop, no weapon is dropped. The intend use isfor "Pits of Death." Have a kill trigger inside a nodrop volume, and when the players die here, they won't drop their weapons. The intent is to prevent unnecessary polygon pileups on the floors of pits. + +

4.8.13 noimpact
+World entities will not impact on this texture. No explosions occur when projectiles strike this surface and no marks +will be left on it. Sky textures are usually marked with this texture so those projectiles will not hit the sky and leave +marks. + +

4.8.14 nomarks
+Projectiles will explode upon contact with this surface, but will not leave marks. Blood will also not mark this surface. +This is useful to keep lights from being temporarily obscured by battle damage. + +

Design Note: Use this on any surface with a deformVertexes keyword. Otherwise, the marks will appear on the unmodified surface location of the texture with the surface wriggles and squirms through the marks.
+ +

4.8.15 nolightmap
+This texture does not have a lightmap phase. It is not affected by the ambient lighting of the world around it. It does not +require the addition of an rgbGen identity keyword in that stage. + +

4.8.16 nosteps
+The player makes no sound when walking on this texture. + +

4.8.17 nonsolid
+This attribute indicates a brush, which does not block the movement of entities in the game world. It applied to +triggers, hint brushes and similar brushes. This affects the content of a brush. + +

4.8.18 origin
+Used on the "origin" texture. Rotating entities need to contain an origin brush in their construction. The brush must be +rectangular (or square). The origin point is the exact center of the origin brush. + +

4.8.19 playerclip
+Blocks player movement through a nonsolid texture. Other game world entities can pass through a brush marked +playerclip. The intended use for this is to block the player but not block projectiles like rockets. + +

4.8.20 slick
+This surfaceparm included in a texture should give it significantly reduced friction. + +

4.8.21 slime
+Assigns to the texture the game properties for slime. This affects both the surface and the content of a brush. + +

4.8.22 structural
+This surface attribute causes a brush to be seen by the Q3MAP process as a possible break-point in a BSP tree. It is used +as a part of the shader for the "hint" texture. Generally speaking, any opaque texture not marked as "detail" is, by +default, structural, so you shouldn't need to specify this. + +

4.8.23 trans
+Tells q3map that pre-computed visibility should not be blocked by this surface. Generally, any shaders that have blendfuncs +should be marked as surfaceparm trans. + +

4.8.24 water
+Assigns to the texture the game properties for water. +

Back | Home | Next + + + \ No newline at end of file diff --git a/docs/manual/quake3/Q3AShader_Manual/ch04/pg4_1.htm b/docs/manual/quake3/Q3AShader_Manual/ch04/pg4_1.htm new file mode 100644 index 00000000..d014d2e1 --- /dev/null +++ b/docs/manual/quake3/Q3AShader_Manual/ch04/pg4_1.htm @@ -0,0 +1,64 @@ + + +Quake III Arena Shader Manual: Editor Specific Shader Instructions + + + +

Q3Radiant Shader Manual

+
+

5 Editor specific shader instructions

+These instructions only affect the texture when it is seen in the Q3Radiant editor. They should be grouped with the surface +parameters but ahead of them in sequence. + +

5.1 qer_editorimage <texture path/texturename>

+This keyword creates a shader name in memory, but in the editor, it displays the TGA art image specified in qer_editorimage (in the example below this is textures/eerie/lavahell.tga). + +

The editor maps a texture using the size attributes of the TGA file used for the editor image. When that editor image represents a shader, any texture used in any of the shader stages will be scaled up or down to the dimensions of the editor image. If a 128x128 pixel image is used to represent the shader in the editor, then a 256x256 image used in a later stage will be shrunk to fit. A 64x64 image would be stretched to fit. Be sure to check this on bouncy, acceleration, and power-uppads placed on surfaces other than 256 x 256. Use tcMod scale to change the size of the stretched +texture. Rememberthat tcMod scale 0.5 0.5 will double your image, while tcMod scale 2 2will halve it. + +

Design Notes: The base_light and gothic_light shaders contain numerous uses of this. It can be very useful for making different light styles (mostly to change the light brightnesses) without having to create a new piece of TGA art for each new shader.
+ + +

textures/liquids/lavahell2//path and name of new texture
+{
+qer_editorimagetextures/eerie/lavahell.tga
+//based on this
+qer_nocarve
+//cannot be cut by CSG subtract
+surfaceparm noimpact
+//projectiles do not hitit
+surfaceparm lava
+//has the game properties of lava
+surfaceparm nolightmap
+//environment lighting does not affect
+q3map_surfacelight 3000
+//light is emitted
+tessSize 256
+//relatively large triangles
+cull disable
+//no sides are removed
+deformVertexes wave 100sin 5 5 .5 0.02
+fogparms 0.85191420.309723 0.0 128 128
+{
+maptextures/eerie/lavahell.tga
+//base texture artwork
+tcMod turb .25 0.2 1 0.02
+//texture is subjected to turbulence
+tcMod scroll 0.1 0.1
+//the turbulence is scrolled
+}
+}
+
+ +

5.2 qer_nocarve

+A brush marked with this instruction will not be affected by CSG subtract functions. It is especially useful for water and fog textures. + +

5.3 qer_trans <value>

+This parameter defines the percentage of transparency that a brush will have when seen in the editor (no effect on game +rendering a tall). It can have a positive value between 0 and 1. The higher the value, the less transparent the texture. +Example: qer_trans 0.2 means the brush is 20% opaque and nearly invisible. + +

Back | Home | Next + + + \ No newline at end of file diff --git a/docs/manual/quake3/Q3AShader_Manual/ch05/pg5_1.htm b/docs/manual/quake3/Q3AShader_Manual/ch05/pg5_1.htm new file mode 100644 index 00000000..d3506d69 --- /dev/null +++ b/docs/manual/quake3/Q3AShader_Manual/ch05/pg5_1.htm @@ -0,0 +1,483 @@ + + +Quake III Arena Shader Manual: Stage Specific Keywords + + + +

Q3Radiant Shader Manual

+
+

6 Stage Specific Keywords

+Stage specifications only affect rendering. Changing any keywords or values within a stage will usually take effect as soon +as a vid_restart is executed. Q3MAP ignores stage specific keywords entirely. + +

A stage can specify a texture map, a color function, an alpha function, a texture coordinate function, a blend function, and a few other rasterization options. + +

6.1 Texture map specification

+
6.1.1 map <texturepath/texturename>
+Specifies the source texture map (a 24 or 32-bit TGA file) used for this stage. The texture may or may not contain alpha +channel information. The special keywords $lightmap and $whiteimage may be substituted in lieu of an actual +texture map name. In those cases, the texture named in the first line of the shader becomes the texture that supplies the light mapping data for the process. + +

$lightmap
+This is the overall lightmap for the game world. It is calculated during the Q3MAP process. It is the initial color +data found in the framebuffer. Note: due to the use of overbright bits in light calculation, the keyword rgbGen +identity must accompany all $lightmap instructions. + +

$whiteimage
+This is used for specular lighting on MD3 models. This is a white image generated internally by the game. This image can +be used in lieu of $lightmap or an actual texture map if, for example, you wish for the vertex colors to come +through unaltered. + +

6.1.2 Clampmap <texturepath>
+Dictates that this stage should clamp texture coordinates instead of wrapping them. During a stretch function, the area, +which the texture must cover during a wave cycle, enlarges and decreases. Instead of repeating a texture multiple times +during enlargement (or seeing only a portion of the texture during shrinking) the texture dimensions increase or contract accordingly. This is only relevant when using something like deformTexCoordParms to stretch/compress texture coordinates for a specific special effect. Remember that the Quake III Arena engine normalizes all texture coordinates (regardless of actual texture size) into a scale of 0.0 to1.0. + +

Proper Alignment: When using clampTexCoords make sure the texture is properly aligned on the brush. The +clampTexCoords function keeps the image from tiling. However, the editor doesn't represent this properly and shows a tiled image. Therefore, what appears to be the correct position may be offset. This is very apparent onanything with a tcMod rotate and clampTexCoords function. + +

AvoidingDistortion: When seen at a given distance (which can vary, depending onhardware and the size of the texture), the compression phase of a stretchfunction will cause a "cross"-like visual artifact to form on the modified texture due to the way that textures are reduced. This occurs because the texture undergoing modification lacks sufficient "empty space" around the displayed (non-black) part of the texture (see figure 2a). To compensate for this, make the non-zero portion of the texture substantially smaller (50% of maximum stretched size -- see figure 2b)than the dimensions of the texture. Then, write a scaling function (tcScale) into the appropriate shader phase, to enlarge the image to the desired proportion. + +

The shaders for the bouncy pads (in the sfx.shader file) show the stretch function in use, including the scaling of the +stretched texture: + +

Example: UsingclampTexCoords to control a stretching texture + +

+textures/sfx/metalbridge06_bounce
+{
+	//q3map_surfacelight 2000
+	surfaceparm nodamage
+	q3map_lightimage textures/sfx/jumppadsmall.tga
+	q3map_surfacelight 400
+	{
+		map textures/sfx/metalbridge06_bounce.tga
+		rgbGen identity
+	}
+	{
+		map $lightmap
+		rgbGen identity
+		blendfunc gl_dst_color gl_zero
+	}
+	{
+		map textures/sfx/bouncepad01b_layer1.tga
+		blendfunc gl_one gl_one
+		rgbGen wave sin .5 .5 0 1.5
+	}
+	{
+		clampmap textures/sfx/jumppadsmall.tga
+		blendfunc gl_one gl_one
+		tcMod stretch sin 1.2 .8 0 1.5
+		rgbGen wave square .5 .5 .25 1.5
+	}
+	// END
+}
+
+ +

+ +

6.1.3 AnimMap <frequency> <texture1> … <texture8>
+The surfaces in the game can be animated by displaying asequence of 1 to 8 frames (separate texture maps). These animations +are affected by other keyword effects in the same and later shader stages. + +

<Frequency>: the number of times that the animation cycle will repeat within a one second time period. The +larger the value, the more repeats within a second. Animations that should last for more than a second need to be expressed as decimal values. + +
<texture1> …<texture8>: the texture path/texture name for each animation frame must be +explicitly listed. Up to eight frames (eight separate .tga files) can be used to make an animated sequence. Each frame is +displayed for an equal subdivision of the frequency value. + +

Example: AnimMap 0.25 animMap 10textures/sfx/b_flame1.tga textures/sfx/b_flame2.tga textures/sfx/b_flame3.tgatextures/sfx/b_flame4.tga would be a 4 frame animated sequence, calling each frame in sequence over a cycle length of 4 seconds. Each frame would be displayed for 1 second before the next one is displayed. The cycle repeats after the last frame in sequence is shown. + +

Design Notes: To make a texture image appear for an unequal (longer) amount of time (compared to other frames), repeat that frame more than once in the sequence.
+ +

textures/sfx/flameanim_blue
+{
+
+	//	*************************************************
+	//	*	Blue Flame				*
+	//	*	July 20, 1999 Surface Light 1800 	*
+	//	*	Please Comment Changes			*
+	//	*************************************************
+	qer_editorimage textures/sfx/b_flame7.tga
+	q3map_lightimage textures/sfx/b_flame7.tga
+	surfaceparm trans
+	surfaceparm nomarks
+	surfaceparm nolightmap
+	cull none
+	q3map_surfacelight 1800
+	// texture changed to blue flame.... PAJ
+	{
+		animMap 10 textures/sfx/b_flame1.tgatextures/sfx/b_flame2.tga
+textures/sfx/b_flame3.tga textures/sfx/b_flame4.tgatextures/sfx/b_flame5.tga
+textures/sfx/b_flame6.tga textures/sfx/b_flame7.tgatextures/sfx/b_flame8.tga
+		blendFunc GL_ONE GL_ONE
+		rgbGen wave inverseSawtooth 0 1 0 10
+
+	}
+	{
+		animMap 10 textures/sfx/b_flame2.tgatextures/sfx/b_flame3.tga
+textures/sfx/b_flame4.tga textures/sfx/b_flame5.tgatextures/sfx/b_flame6.tga
+textures/sfx/b_flame7.tga textures/sfx/b_flame8.tgatextures/sfx/b_flame1.tga
+		blendFunc GL_ONE GL_ONE
+		rgbGen wave sawtooth 0 1 0 10
+	}
+	{
+		map textures/sfx/b_flameball.tga
+		blendFunc GL_ONE GL_ONE
+		rgbGen wave sin .6 .2 0 .6
+	}
+}
+
+ +

6.2 Blend Functions

+Blend functions are the keyword commands that tell the Quake III Arena graphic engine's renderer how graphic layers are to be mixed together. + +

6.2.1 Simplified blend functions:
+The most common blend functions are set up here as simple commands, and should be used unless you really know what you are +doing. + +

6.2.1.1 blendfunc add +
This is a shorthand command for blendfunc gl_one gl_one. Effects like fire and energy are additive. + +

6.2.1.2 blendfunc filter +
This is a shorthand command that can be substituted for either blendfunc gl_dst_color gl_zero or blendfunc gl_zero gl_src_color. A filter will always result in darker pixels than what is behind it, but it can also remove color selectively. Lightmaps are filters. + +

6.2.1.3 blendfunc blend +
Shorthand for blendfunc gl_src_alphagl_one_minus_src_alpha. This is conventional transparency, where part of the background is mixed with part of the texture. + +

6.2.2 Explicit blend functions:
+Getting a handle on this concept is absolutely key to understanding all shader manipulation of graphics. + +

BlendFunc or "Blend Function" is the equation at the core of processing shader graphics. The formula reads as follows: + +

[Source *<srcBlend>] + [Destination * +<dstBlend>] + +

Source is usually the RGB color data in a texture TGA file (remember it's all numbers) modified by any rgbgen and alphagen. In the shader, the source is generally identified by command MAP, followed by the name of the image. + +

Destination is the color data currently existing in the frame buffer. + +

Rather than think of the entire texture as a whole, it maybe easier to think of the number values that correspond to a single pixel, because that is essentially what the computer is processing … one pixel of the bit map at a time. + +

The process for calculating the final look of a texture in place in the game world begins with the precalculated lightmap for the area where the texture will be located. This data is in the frame buffer. That is to say, it is the initial data in the Destination. In an unmanipulated texture (i.e. one without a special shader script), color information from the texture is combined with the lightmap. In a shader-modified texture, the $lightmap stage must be present for the lightmap to be included in the calculation of the final texture appearance. + +

Each pass or "stage" of blending is combined (in a cumulative manner) with the color data passed onto it by the +previous stage. How that data combines together depends on the values chosen for the Source Blends and Destination Blends at each stage. Remember it's numbers that are being mathematically combined together that are ultimately interpreted as colors. + +

A general rule is that any Source Blend other than GL_ONE (or GL_SRC_ALPHA where the alpha channel is entirely white) will cause the Source to become darker. + +

6.2.3 Source Blend <srcBlend>
+The following values are valid for the Source Blend part of the equation. + +

GL_ONE This is the value 1. When multiplied by the Source, the value stays the same the value of the color information does not change. + +
GL_ZERO This is the value 0. When multiplied by the Source, all RGB data in the Source becomes Zero (essentially black). + +
GL_DST_COLOR This is the value of color data currently in the Destination (frame buffer). The value of that information depends on the information supplied by previous stages. + +
GL_ONE_MINUS_DST_COLOR This is nearly the same as GL_DST_COLOR except that the value for each component color +is inverted by subtracting it from one. (,i.e. R = 1.0 - DST.R, G = 1.0 - DST.G, B = 1.0 - DST.B, etc.) + +
GL_SRC_ALPHA The TGA file being used for the Source data must have an alpha channel in addition to its RGB channels (for a total of four channels). The alpha channel is an 8-bit black and white only channel. An entirely white alpha channel will not darken the Source. + +
GL_ONE_MINUS_SRC_ALPHA This is the same as GL_SRC_ALPHA except that the value in the alpha channel is inverted by subtracting it from one.(i.e. A=1.0 - SRC.A) + +

6.2.4 Destination Blend <dstBlend>
+The following values are valid for the Destination Blend part of the equation. + +

GL_ONE This is the value 1. When multiplied by the Destination, the value stays the same the value of the color information does not change. + +
GL_ZERO This is the value 0. When multiplied by the Destination,all RGB data in the Destinationbecomes Zero (essentially black). + +
GL_SRC_COLOR This is the value of color data currently in the Source (which is the texture being manipulated here). + +
GL_ONE_MINUS_SRC_COLOR This is the value of color data currently in Source, but subtracted from one(i.e. +inverted). + +
GL_SRC_ALPHA The TGA file being used for the Source data must have an alpha channel in addition to its RGB channels (four a total of four channels). The alpha channel is an 8-bit black and white only channel. An entirely white alpha channel will not darken the Source. + +
GL_ONE_MINUS_SRC_ALPHA This is the same as GL_SRC_ALPHA except that the value in the alpha channel is inverted by subtracting it from one. (i.e. A=1.0 - SRC.A). + +

Doing the Math: The Final Result + +
The product of the Source side of the equation is added to the product of the Destination side of the equation. The sum is then placed into the frame buffer to become the Destination information for the next stage. Ultimately, the equation creates a modified color value that is used by other functions to define what happens in the texture when it is displayed in the game world. + +

6.2.5 Default Blend Function
+If no blendFunc is specified then no blending will take place. A warning is generated if any stage after the first stage does not have a blendFunc specified. + +

6.2.6 Technical Information/Limitations Regarding Blend Modes:
+The Riva 128 graphics card supports ONLY the following blendmodes: + +

GL_ONE, GL_ONE +
GL_DST_COLOR, GL_ZERO + +
GL_ZERO, GL_SRC_COLOR + +
GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA + +
GL_ONE_MINUS_SRC_ALPHA, GL_SRC_ALPHA + +

Cards running in 16 bit color cannot use any GL_DST_ALPHA blends. + +

6.3 rgbGen <func>

+There are two color sources for any given shader, the texture file and the vertex colors. Output at any given time will be equal to TEXTURE multiplied by VERTEXCOLOR. Most of the time VERTEXCOLORwill default to white (which is a normalized value of 1.0), so output will be TEXTURE (this usually lands in the Sourceside of the shader equation). Sometimes you do the opposite and use TEXTURE = WHITE, but this is only commonly used when doing specular lighting on entities (i.e. shaders that level designers will probably never create + +

The most common reason to use rgbGen is to pulsate something. This means that the VERTEXCOLOR will oscillate between two +values, and that value will be multiplied (darkening) the texture. + +

If no rgbGen is specified, either "identityLighting" or"identity" will be selected, depending on which blend modes are +used. + +

Valid <func> parameters are wave, identity, identityLighting, entity, oneMinusEntity, fromVertex, and +lightingDiffuse. + +

6.3.1 RgbGen identityLighting
+Colors will be (1.0,1.0,1.0) if running without overbright bits (NT, linux, windowed modes), or (0.5, 0.5, 0.5) if running +with overbright. Overbright allows a greater color range at the expense of a loss of precision. Additive and blended stages +will get this by default. + +

6.3.2 rgbGen identity
+Colors are assumed to be all white (1.0,1.0,1.0). All filters stages (lightmaps, etc) will get this by default. + +

6.3.3 rgbGen wave <func> <base> <amp><phase> <freq>
+Colors are generated using the specified waveform. An affected texture with become darker and lighter, but will not change +hue. Hue stays constant. Note that the rgb values for color will not go below 0 (black) orabove 1 (white). Valid waveforms are sin, triangle, square, sawtooth and inversesawtooth. + +

<func> Waveforms and their effects: + +
Sin: color flows smoothly through changes. + +
Triangle: color changes at a constant rate and spends noappreciable time at peaks and valleys. + +
Square: color alternates instantly between its peak and valley values. + +
Sawtooth: With a positive frequency value, the color changes at aconstant rate to the peak then instantly drops to its valley value. + +
Inversesawtooth: An inverse sawtooth wave will reverse this, making the ascent immediate (like a square wave) and the decay fall off like a triangle wave. + +
<base> Baseline value. The initial RGB formula of a color (normalilzed). + +
<amp> Amplitude. This is the degree of change from the baseline value. In some cases you will want +values outside the 0.0 to 1.0 range, but it will induce clamping (holding at the maximum or minimum value for a time period) +instead of continuous change. + +
<phase> See the explanation for phase under the waveforms heading of Key Concepts. + +
<freq> Frequency. This is a value (NOT normalized) that indicates peaks per second. + +

6.3.4 RgbGen entity
+Colors are grabbed from the entity's modulate field. This isused for things like explosions. + +

Design Note: This keyword would probably not be used by a level designer.
+ +

6.3.5 rgbGen oneMinusEntity
+Colors are grabbed from 1.0 minus the entity's modulate field. + +

Design Note: This keyword would probably not be used by a level designer.
+ +

6.3.6 rgbGen Vertex
+Colors are filled in directly by the data from the map or model files. + +

Design Note: rgbGen vertex should be used when you want the RGB values to be computed for a static model (i.e. mapobject) in the world using precomputed static lighting from Q3BSP. This would be used on things like +the gargoyles, the portal frame, skulls, and other decorative MD3s put into the Quake III Arena world.
+ +

6.3.7 rgbGen oneMinusVertex
+As rgbGen vertex, but inverted. + +

Design Note: This keyword would probably not be used by a level designer
+ +

6.3.8 rgbGen lightingDiffuse
+Colors are computed using a standard diffuse lighting equation. It uses the vertex normals to illuminate the object correctly. + +

Design Note: -rgbGen lightingDiffuse is used when you want the RGB values to be computed for a dynamic model (i.e. non-map object) in the world using regular in-game lighting. For example, you would specify on shaders for items, characters, weapons, etc.
+ +

6.4 AlphaGen <func>

+The alpha channel can be specified like the rgbchannels. If not specified, it defaults to 1.0. + +

6.4.1 AlphaGen portal
+This rendering stage keyword is used in conjunction with the surface parameter keyword portal. The function +accomplishes the "fade" that causes the scene in the portal to fade from view. Specifically, it means "Generate alpha values +based on the distance from the viewer to the portal." Use alphaGen portal on the last rendering pass. + +

6.5 tcGen <coordinate source>

+Specifies how texture coordinates are generated and where they come from. Valid functions are base,lightmap and environment. + +

<base> = base texture coordinates from the original art. +
<lightmap> = lightmap texture coordinates +
<environment> = Make this object environment mapped. + +

6.5.1 tcGen vector (<sx> <sy> <sz>) +(<tx><ty> <tz>)
+New texcoord generation by world projection. This allows you to project a texture onto a surface in a fixed way, regardless of its orientation. + +

S coordinates correspond to the "x" coordinates on the texture itself. + +
T coordinates correspond to the "y" coordinates on the texture itself. + +

The measurements are in game units. + +

+ +

Example: tcGen vector (0.01 0 0) (0 0.01 0) +
This would project a texture with a repeat every 100 units across the X/Y plane. + +

6.6 tcMod <func> <…>

+Specifies how texture coordinates are modified after they are generated. The valid functions for tcMod are rotate, +scale,scroll, stretch and transform. Transform is a function generally reserved for use by programmers who suggest that designers leave it alone. When using multiple tcMod functions during a stage, place the scroll command last in order, because it performs a mod operation to save precision, and that can disturb other operations. Texture coordinates are modified in the order in which tcMods are specified. In otherwords, if you see: + +

tcMod scale 0.5 0.5 +
tcMod scroll 1 1 + +

Then the texture coordinates will be scaled then scrolled. + +

6.6.1 tcMod rotate <degrees per per second>
+This keyword causes the texture coordinates to rotate. The value is expressed in degrees rotated each second. A positive value means clockwise rotation. A negative value means counterclockwise rotation. For example "tcMod rotate 5" would +rotate texture coordinates 5 degrees each second in a clockwise direction. The texture rotates around the center +point of the texture map, so you are rotating a texture with a single repetition, be careful to center it on the brush (unless off-center rotation is desired). + +

6.6.2 tcMod scale <sScale> <tScale>
+Resizes (enlarges or shrinks) the texture coordinates bymultiplying them against the given factors of <sScale> +and <tScale). The values "s" and "t"conform to the "x" and "y" values (respectively) as they are found in the original texture TGA. The values for sScale and tScale are NOT normalized. This means that a value greater than 1.0 will increase the size of thetexture. A positive value less than one will reduce the texture to a fraction of its size and cause it to repeat within the same area as the original texture (Note: see clampTexCoords for ways to control this).; + +

Example: tcMod scale 0.5 2 would cause the texture to repeat twice along its width, but expand to twice its height (in which case half of the texture would be seen in the same area as the original) + +

6.6.3 tcMod scroll <sSpeed> <tSpeed>
+Scrolls the texture coordinates with the given speeds. The values "s" and "t" conform to the "x" and "y" values +(respectively) as they are found in the original textureTGA. The scroll speed is measured in "textures" per second. A "texture" is the dimension of the texture being modified and includes any previous shader modifications to the original TGA). A negative s value would scroll the texture to the left. A negative t value would scroll the texture down. + +

Example: tcMod scroll 0.5 -0.5 moves the texture down and right (relative to the TGA files original coordinates) at the rate of a half texture each second of travel. + +

This should be the LAST tcMod in a stage. Otherwise there maybe popping or snapping visual effects in some shaders. + +

6.6.4 tcMod stretch <func> <base> +<amplitude><phase> <frequency>
+ +Stretches the texture coordinates with the given function. Stretching is defined as stretching the texture coordinate away from the center of the polygon and then compressing it towards the center of the polygon. + +

<base>: A base value of one is the original dimension of the texture when it reaches the stretch stage. +Inserting other values positive or negative in this variable will produce unknown effects. + +
<amplitude>: This is the measurement of distance the texture will stretch from the base size. It is +measured, like scroll, in textures. A value of 1 here will double the size of the texture at its peak. + +
<phase>: See the explanation for phase under the deform vertexes keyword. + +
<frequency>: this is wave peaks per second. + +
Wave Functions <func> + +
Sin wave: the texture expands smoothly to its peak dimension and then shrinks smoothly to its valley dimension in a flowing manner. + +
Triangle wave: The textures stretch at a constant rate and spend no appreciable time at the peak or valley points. + +
Square wave: The texture is shown at its peak for the duration of the frequency and then at its valley for the +duration of the frequency. + +
Sawtooth: the texture stretches like a triangle wave until it reaches a peak, then instantly drops to the valley, as in a square wave. + +
Inversesawtooth: this is the reverse of the sawtooth wave. + +

6.6.5 tcMod <transform> <m00> <m01> <m10><m11> <t0> <t1>
+Transforms each texture coordinate as follows: + +

S' = s * m00 + t * m10 + t0 + +
T' = s * m01 + t * m11 + t1 + +

This is for use by programmers. + +

6.6.6 tcMod turb <base> <amplitude> +<phase><freq>
+ +

Applies turbulence to the texture coordinate. Turbulence is a back and forth churning and swirling effect on the texture. + +

The parameters for this shader are defined as follows: + + +

<base> Currently undefined. + +
<amplitude> This is essentially the intensity of the disturbance or twisting and squiggling of the texture. + +
<phase> See the explanation for phase under the deformvertexes keyword. + +
<freq> Frequency. This value is expressed as repetitions or cycles of the wave per second. A value of one +would cycle once per second. A value of 10 would cycle 10 times per second. A value of 0.1 would cycle once every 10 +seconds. + +

6.7 depthFunc <func>

+This controls the depth comparison function used while rendering. The default is "lequal" (Less than or equal to) +where any surface that is at the same depth or closer of an existing surface is drawn. This is used for textures with +transparency or translucency. Under some circumstances you may wish to use "equal", e.g. for light-mapped grates that are alpha tested (it is also used for mirrors). + +

6.8 depthWrite

+By default, writes to the depth buffer when depthFunc passes will happen for opaque surfaces and not for translucent surfaces. Blended surfaces can have the depth writes forced with this function. + +

6.9 Detail

+This feature was not used in Quake III Arena maps, but should still function. +Designates this stage as a detail texture stage, which means that if the c_var, r_detailtextures, is set to 0 then this stage will be ignored (detail will not be displayed). This keyword, by itself, does not affect rendering at all. If you do put in a detail texture, it has to conform to very specific rules. Specifically, the blendFunc: + +

blendFuncGL_DST_COLOR GL_SRC_COLOR + +

This is also the simple blend function: blendfuncfilter + +

And the average intensity of the detail texture itself must be around 127. + +

Detail is used to blend fine pixel detail back into a base texture whose scale has been increased significantly. When detail iswritten into a set of stage instructions, it allows the stage to be disabled by the c_var console command setting "r_detailtextures 0". + +

A texture whose scale has been increased beyond a 1:1 ratio tends not to have very high frequency content. In other words, one texel can cover a lot of real estate. Frequency is also known as "detail." Lack of detail can appear acceptable if the player never has the opportunity to see the texture at close range. But seen close up, such textures look glaringly wrong within the sharp detail of the Quake III Arena environment. A detail texture solves this problem by taking a noisy "detail" pattern (a tiling texture that appears to have a great deal of surface roughness) and applying it to the base texture at a very densely packed scale (that is, reduced from its normal size). This is done programmatically in the +shader, and does not require modification of the base texture. Note that if the detail texture is the same size and scale as the base texture that you may as well just add the detail directly to the base texture. The theory is that the detail texture's scale will be so high compared to the base texture (e.g.; 9 detail texels fitting into 1 base texel) that it is literally impossible to fit that detail into the base texture directly. + +

For this to work, the rules are as follows: + +

    + +
  1. the lightmap must be rendered first. This is because the subsequent detail texture will be modifying the lightmap in the framebuffer directly; +
  2. the detail texture must be rendered next since it modifies the lightmap in the framebuffer; +
  3. the base texture must be rendered last; +
  4. the detail texture MUST have a mean intensity around 127-129. If it does not then it will modify the displayed texture's perceived brightness in the world; +
  5. the detail shader stage MUSThave the "detail" keyword or it will not be disabled if the user uses the "r_detailtextures 0" setting; +
  6. the detail stage MUST use "blendFunc GL_DST_COLOR GL_SRC_COLOR". Any other BlendFunc will cause mismatches in brightness between detail and non-detail views.; +
  7. the detail stage should scale its textures by some amount (usually between 3 and 12) using "tcMod" to control density. This roughly corresponds to coarseness. A very large number, such as 12, will give very fine detail, however that detail will disappear VERY quickly as the viewer moves away fromthe wall since it will be MIP mapped away. A very small number, e.g. 3, gives diminishing returns since not enough is brought in when the user gets very close. I'm currently using values between 6 and 9.5. You should use non-integral numbers as much as possible to avoid seeing repeating patterns. +
  8. detail textures add one pass of overdraw, so there is a definite performance hit . +
  9. detail textures can be shared, so designers may wish to define only a very small handful of detail textures for common surfaces such as rocks, etc.
+ +

An example (non-existent) detailshader is as follows: +

Example: Texture with Detail + +

+textures/bwhtest/foo
+{
+// draw the lightmap first
+{
+map $lightmap
+rgbGen identity
+}
+// modify the lightmap in the framebuffer by
+// a highly compressed detail texture
+{
+map textures/details/detail01.tga
+blendFunc GL_DST_COLOR GL_SRC_COLOR
+// YOU MUST USE THIS!!
+detail
+// for the detail to be disabled, this must be present
+tcMod scale 9.1 9.2
+}
+// now slap on the base texture
+{
+map textures/castle/blocks11b.tga
+blendFunc filter
+}
+}
+
+ +

6.10 alphaFunc <func>

+Determines the alpha test function used when rendering this map. Valid values are GT0, LT128, and GE128. These +correspond to "GREATER THAN 0", "LESS THAN 128", and "GREATER THAN OR EQUAL TO 128". This function is used when determining if a pixel should be written to the framebuffer. For example, if GT0 is specified, the only the portions of the texture map with corresponding alpha values greater than zero will be written to the framebuffer. By default alpha testing is disabled. + +

Both alpha testing and normal alpha blending can be used to get textures that have see-through parts. The difference is that alphaFunc is an all-or-nothing test, while blending smoothly blends between opaque and translucent at pixel edges. Alpha test can also be used with depthwrite, allowing other effects to be conditionally layered on top of just the opaque pixels by setting depthFunc to equal. + +

Back | Home | Next + + + diff --git a/docs/manual/quake3/Q3AShader_Manual/ch06/pg6_1.htm b/docs/manual/quake3/Q3AShader_Manual/ch06/pg6_1.htm new file mode 100644 index 00000000..c5a6b87d --- /dev/null +++ b/docs/manual/quake3/Q3AShader_Manual/ch06/pg6_1.htm @@ -0,0 +1,145 @@ + + +Quake III Arena Shader Manual: Notes on Alpha Channels + + + +

Q3Radiant Shader Manual

+
+

7 Notes on Alpha Channels

+To use some blend modes of alphaFunc, you must add an alpha channel to your texture files. Photoshop can do this. +Paintshop Pro has the ability to make an alpha channel but cannot work directly in to it. In Photoshop you want to set the type to Mask. Black has a value of 255. White has a value of 0. The darkness of a pixel's alpha value determines the +transparency of the corresponding RGB value in the game world. Darker = more transparent. + +

Care must be taken when reworking textures with alpha channels. Textures without alpha channels are saved as 24 bit images while textures with alpha channels are saved as 32 bit. If you save them out as 24 bit, the alpha channel is erased. Note: Adobe Photoshop will prompt you to save as 32, 24 or 16 bit. Choose wisely. If you save a texture as 32 bit and you don't actually have anything in the alpha channel, Quake III Arena may still be forced to use a lower quality texture format (when in 16 bit rendering) than if you had saved it as 24 bit. + +

To create a texture that has "open" areas, make those areas black in the alpha channel and make white the areas that are to be opaque. Using gray shades can create varying degrees of opacity/transparency. + +

Example: An opaque texture with see-through holes knocked in it. + +

+textures/base_floor/pjgrate1
+{
+	surfaceparm metalsteps
+	cull none
+
+	// A GRATE OR GRILL THAT CAN BE SEEN FROM BOTH SIDES
+	{
+		map textures/base_floor/pjgrate1.tga
+		blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+		alphaFunc GT0
+		depthWrite
+		rgbGen identity
+	}
+	{
+		map $lightmap
+		rgbGen identity
+		blendFunc GL_DST_COLOR GL_ZERO
+		depthFunc equal
+	}
+	}
+
+ +

The alpha channel can also be used to merge a texture (including one that contains black) into another image so that the merged art appears to be and opaque decal on a solid surface (unaffected by the surface it appears to sit on), without actually using an alpha function. The following is a very simple example: + +

+ +
Figure 1 + +

Start with a TGA file image. In this case, a pentagram on a plain white field (figure 1A). The color of the field surrrounding the image to be merged is not relevant to this process (although having a hard-edged break between the image to be isolated and the field makes the mask making process easier). Make an alpha channel. The area of the image to be merged with another image is masked off in white. The area to be masked out (notused) is pure black (figure 1B). The image to be merged into is greenfloor.tga (figure 1C). + +

Make a qer_editorimage of greenfloor.tga. This is placed inthe frame buffer as the map image for the texture. By +using GL_SRC_ALPHA as the source part of the blend equation, the shader adds in only the non-black parts of the pentagram. +Using GL_MINUS_ONE_SRC_ALPHA, the shader inverts the pentagram's alpha channel and adds in only the non-black parts of the green floor. + +

In a like manner, the alpha channel can be used to blend the textures more evenly. A simple experiment involves using a +linear gradiant in the alpha channel (white to black) and merging two textures so they appear to cross fade into each other. + +

A more complicated experiment would be to take the pentagram in the first example and give it an aliased edge so that the pentagram appeared to fade or blend into the floor. + +

8 Troubleshooting Shaders

+If a shader is not working, look first for syntax errors. +
  • Are the brackets correctly set? +
  • Do you have too many parameter values on a line? +
  • Are you using a word in a parameter that wants a numerical value? +
  • Are you using a numerical value in a parameter that wants a word? +
  • Are the path names to your textures correct? +
  • Are your texture names correct? There is a chance that the texture name is too long or too complex. Try renaming a +texture with a shorter, simpler name.
+ +

9 Creating New Textures

+If you are familiar with the required tools, creating new assets for use in Quake III Arena is not particularly difficult. As a general rule, you should create new directories for each map with names different from the names used by id. If you are making a map that will be called "H4x0r_D00M", every directory containing new assets for that map should be titled H4x0r_D00M. This is to try and avoid asset directories overwriting each other as the editor and the gameload in assets. + +

9.1 Tools Needed

+Any combination of graphic programs and plug-ins that canout put a 24 bit MS windows compatible Targa (.tga) or JPEG (.jpg) graphic file.If you plan to make textures that will have an alpha channel component (a 4th 8-bit greyscale channel that is used by the shaders to further manipulate the art), you must have a program that can create 32-bit art with that fourth channel. + +

Adobe Photoshop has the ability to easily create alpha channels. PaintShop Pro from JASC (v5.0+) can also make an +alpha channel by creating a mask and naming it "alpha". + +

Generally speaking, regardless of the program used, we found it best to do most of the art manipulation of the alpha channel in a separate layer or file and then paste it into the alpha channel before saving. + +

9.2 Setting up Files

+The editor and the game program look for assets to be located along the paths set up in your project file. Start by creating +a directory for you new textures by creating file folders to make a directory path as follows: + +

quake3\baseq3\textures\[mymapname]
+ +

The installation of Q3Radiant will create a text document called "shaderlist.txt" in the following path: + +

quake3\baseq3\scripts\shaderlist.txt
+ +

Q3Radiant will use the contents of this script to grab your new textures for inclusion in the game. The contents of shaderlist.txt document will contain a listing of all the shader documents that were used by id Software to create Quake III Arena. + +

Since you will obviously want to create your own shaders, you need to put them in separate folders and create a new shader script for them. + +

If you plan to work on several maps at once and want to distinguish between textures used in each map, simply add additional map names here. For map and mod makers, we STRONGLY recommend that any new shader scripts created use the name of the map or mod in the shader file name. We know we can't avoid every incident of files overwriting each other, but we certainly can advise you how to try. + +

Now, in the scripts directory that you just created, create another text file and call it: + +

[mymapname].shader
+ +

This file will contain the shader scripts you write to modify a particular texture. + +

9.3 Rules and Guidelines

+
9.3.1 Rules
+Follow these rules when creating textures for the Quake III Arena engine: + +
  • Save your textures into your new [map name] directories. +
  • Don't use the same names that id used for textures. It will cause problems. +
  • For best quality, save textures without an alpha channel as 24 bit TARGA files. Using JPEG files can save memory space, but at the risk of losing detail and depth in the texture. JPEG files cannot be used for textures requiring an alpha channel. +
  • Textures containing an alpha channel must be saved as32 bit TARGA files. +
  • If a new texture requires no further manipulation, it does not need a shader script. +
  • Size textures in powers of 2. Example: 8x8, 16x16,32x32, 64x64 pixels and so on. +
  • Textures don't need to be square. A 32x256 pixel texture is perfectly acceptable.
+ +

9.3.2 Guidelines
+The following are some things the id designers learned about textures. + +
  • Create textures in "suites" built around one or two large textures with a number of much smaller supporting detail or accent textures. +
  • Very large textures are possible, but some video cards compress textures larger than 256x256 pixels. +
  • Textures are grouped alphabetically by name in the texture display window, so you may want to give suites of textures +similar names. +
  • Use the shader function qe3_editorimage to conserve memory when making multiple versions of a single texture (as in the case of a glowing texture with several light values). +
  • Unless you are creating special effects or textures designed to draw the player's eye to a specific spot, muted, middle value colors work best with the game engine. +
  • Extremely busy (a lot of fussy detail) textures can break up or form visually unpleasant patterns when seen at distances.
+ +

9.4 Making the .pk3 File>

+When you go to distribute your creation to the gaming world, you need to put your newly created map, textures, bot area files, and shader documents into an archive format called a "pk3" file. You do not need to include the shaderlist.txt file, since that is only used by the editor. You will need to keep the paths to the various assets the same. So your paths should be something like this: + +

Textures: baseq3/textures/[mymapnamefolder] +
Bsp & aas: baseq3/maps/mymapname.bsp, mymapname.aas +
Shader scripts: baseq3/scripts/mymapname.shader + +

You need to use an archiving program call Winzip to make the pk3 file. Get Winzip from http://www.winzip.com/winzip/winzip.htm + +
Make a zip archive called mymapname.zip + +
Zip all the required assets into a zip archive file (Quake III Arena DOES support compressed pk3 files). + +
Rename the zip archive to mymapname.pk3 + +
Put it where the Quake III Arena community can find it. +

Back | Home | Next + + \ No newline at end of file diff --git a/docs/manual/quake3/Q3AShader_Manual/index.htm b/docs/manual/quake3/Q3AShader_Manual/index.htm new file mode 100644 index 00000000..5e80b29a --- /dev/null +++ b/docs/manual/quake3/Q3AShader_Manual/index.htm @@ -0,0 +1,76 @@ + + +Quake III Arena Shader Manual: Table of Contents + + + +

+

Q3Radiant Shader Manual

+ +

Revision #12

+ +

By Paul Jaquays and Brian Hook + +

(with additional material by John Carmack, Christian Antkow, Kevin Cloud, & Adrian Carmack) +

QERadiant.com thanks John Hutton for re-formating this manual into a more web friendly version

+
+

Table of Contents

+1 Preface: Making Your Own Shaders +
2 Introduction + + +3 General Shader Keywords + + +4 Q3MAP Specific Shader Keywords + + +5 Editor specific shader instructions + + +6 Stage Specific Keywords + + +7 Notes on Alpha Channels +
8 Troubleshooting Shaders +
9 Creating New Textures + +
Appendix A: targetShaderName and targetNewShaderName + + diff --git a/docs/manual/quake3/Q3AShader_Manual/q3ashader_manual_files/image002.jpg b/docs/manual/quake3/Q3AShader_Manual/q3ashader_manual_files/image002.jpg new file mode 100644 index 00000000..9cc0ffc7 Binary files /dev/null and b/docs/manual/quake3/Q3AShader_Manual/q3ashader_manual_files/image002.jpg differ diff --git a/docs/manual/quake3/Q3AShader_Manual/styles/q3rad.css b/docs/manual/quake3/Q3AShader_Manual/styles/q3rad.css new file mode 100644 index 00000000..b4daab91 --- /dev/null +++ b/docs/manual/quake3/Q3AShader_Manual/styles/q3rad.css @@ -0,0 +1,23 @@ +body { font: 12pt "Times New Roman"; + margin-left: 5mm; + margin-right: 5mm; + text-align: justify; + background: #ffffff; + color: #000000 } +h1 { font: bold 24pt Arial, Helvetica } +h2 { font: bold italic 18pt Arial, Helvetica } +.subheading { font: bold 16pt Arial, Helvetica } +:link {color: blue; + text-decoration: none; } +:visited {color: purple; + text-decoration: none; } +h6 { font: 10pt "Times New Roman" } +.MsoToc2 { font: bold small-caps 12pt "Times New Roman" } +.MsoTitle { text-align:center; + font: bold 24pt "BankGothic Md BT"; + letter-spacing:2.5pt } +.heading { font: italic 10pt "Times New Roman" } +.subcontents { font: 10pt "Times New Roman" } +.tip { font: 10pt "Comic Sans MS" } +.type { font: 10pt "Courier New" } +.menu { font: 10pt Arial, Helvetica } \ No newline at end of file diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/design_tips.html b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/design_tips.html new file mode 100644 index 00000000..0d72ce1f --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/design_tips.html @@ -0,0 +1,113 @@ + + + + + + +Design Tips and Suggestions + + + + + +

Design Tips and Suggestions

+
+
+ + + + +
  +
+
+

· The skull + generator in Harvester tosses skulls about it to a maximum distance + of 96 units. The id map designers usually allowed for a drop radius + of 104 to 128 units as a minimum. As a rule, the generator should + drop skulls only in a places accessible to the players. Skulls + should not drop out into death fog or the void.

+

· Where you place + the persistent team power-ups is really more a matter of personal + style than a fixed requirement. Generally speaking, we found having + all or most of them in easy view of the initial start positions was + a good thing. In some cases, we found that placing the scout in a + contested area made for interesting game challenges.

+

· It is not + necessary to put every team power-up on every map. If a team + power-up would be overpowering on a map, leave it out. If you study + the id team maps, you’ll note that not every map has every power + up. In a small map, the scout can be unreasonable. In a map where + the base is easily attacked and overwhelmed, the guard can unbalance + things. In a map where the base is easily defended by snipers, the + doubler is powerful.

+

· For One Flag CTF, + the flag should be placed in an area that is roughly equidistant + from both bases and can be easily reached by players from either + team.

+

· The same (as + above) is true for Harvester.

+

· You don’t have + to place the white flag and the Harvester skull generator in the + same place in the map.

+

· Don’t feel + obligated to put the CTF flag bases, the skull receptacles, and the + Overload skull obelisk in the exact same location in the bases. Just + remember to mark gametypes correctly.

+

· Don’t include a + kamikaze in a map where players are unlikely to ever see the full + effect of the explosion.

+

· The personal + teleporter entity takes the player to a deathmatch spawn. That’s + how we restricted where the player teleported to in some maps.

+

· When converting + Q3A CTF maps with small base areas around their flags will probably + need to have their bases enlarged to accommodate the Overload skull + obelisk.

+

· OVERLOAD: When + designing the base for the placement of the skull obelisk, don’t + make it easy for attackers to shoot the obelisk from protected + locations.

+

· FLOOR ARROWS: The + graphic arrows were added to map floors to help the players find + their ways through potentially confusing arenas and to give the + player a sense of how close to the flag room he or she might be. The + rule of thumb was that the greater the distance to the flag, the + more stripes or bars would follow the arrow. Exact style of arrow + use varied from mapper to mapper. Study the individual maps to + determine which works best for your own map. The floor arrows act + like decals (if you ever built plastic model kits, these are the + little graphic things that you soaked in water and then stuck on the + surfaces of the model). The images will appear to be a part of the + surface upon which they rest. For the arrows, you will want to build + them as nodraw brushes of the proper dimension with a surface raised + about 2 units above the floor or wall. For the arrow, use + missionpack/proto2/bluea_dcl for the blue arrows and missionpack/proto2/reda_dcl + for the red. You may have to scale and rotate the texture to get + what you want. For more than three trailing bars, add additional + decals and arrange to suit.

+
+
+
+
+
+
+ + + + +
+

Back
+
+ + Table of Contents
+
+ + Map Converter's Checklist
+
+ -9-

+
+
+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/map_converters_checklist.html b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/map_converters_checklist.html new file mode 100644 index 00000000..03ed5879 --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/map_converters_checklist.html @@ -0,0 +1,101 @@ + + + + + + +Design Tips and Suggestions + + + + + +

Map Converter’s Checklist

+
+
+ + + + +
  +

The following is a list of things to look for, do, or + be aware of when converting a pre-existing CTF map to Q3:TA game types.

+
+
+

· New file name. Don’t + overwrite your old CTF map.

+

· If you want to + convert an existing Q3A CTF map to the team arena game types, it + would be good to make a clean break from Q3A. Give it a new file + name and even a new map name. We did the same for our original CTF + maps.

+

· If you don’t + already have one, build a central “neutral” area in keeping with + the style of the rest of the map. This is an important play area, + perhaps even more so than the bases. Make the opportunities for + gameplay here just as exciting as the flag bases.

+

· Fix-up Time. This is + your opportunity to fix all those things that players have been + telling you are wrong with your map (sticky spots, bad hallway + connections, misaligned textures, poor item placement). The id guys + did it, so can you. It’s also a good time to read or re-read the + Q3Radiant section on optimizing maps for bots (you may want to look + for the recent updates that accompany the bspc tool). Pay particular + attention to placement of clip brushes and cluster portals. If + players can’t reach an area of the map (such as sky above ceiling + grills, or beyond window bars, fill the unreachable space with clip + brush - just walling it off is often worse than doing nothing.

+

· Add Team Power-ups + in or near bases.

+

· Place .md3 powerup + pad bases beneath Power-ups

+

· Remove “ow” + marks from floors that were used as weapon locators. Replace them + with the base floor for that texture. You may also be able to + simplify the geometry.

+

· Place Weapon pad + markers (use the pfbs) beneath weapon spawns.

+

· Consider adding new + weapon types or replacing existing ones with the new weapons. Don’t + just do it because they are new, though. Make sure the weapon is + appropriate to the map. If you don’t like a weapon or it’s + effect on play, don’t add it to your map.

+

· Replace old Q3A CTF + banners with new Q3: TA banners. Use the banner prefabs (pfbs) for + ease of placement.

+

· Consider adding team + logos as decals (see FLOOR ARROWS above) to other parts of the map, + like walls and floors.

+

· Make sure that the + team logos on banners and floors; walls, etc. have the proper + facing. You should be able to properly read the word “red” or + “blue” on the placeholder logo.

+

· Add in the flag + bases and obelisks. Follow directions noted above (page 9) to mark them for + gameplay types.

+
+
+
+
+
+
+ + + + +
+

Back
+
+ + Table of Contents
+
+ + Related Links
+
+ -10-

+
+
+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/preface.html b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/preface.html new file mode 100644 index 00000000..cae26324 --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/preface.html @@ -0,0 +1,40 @@ + + + + + + +If you are already familiar with the tools and processes for making your +own + + + + +

 

+

 

+

If you are already familiar with the tools +and processes for making your own

+

Quake III Arena game maps, then this +document and the other files in this directory

+

are what you need to create Quake III: Team +Arena maps. If you have previously

+

created team play style maps (for Capture +the Flag or other game “mods”),

+

it will not be difficult to add the new game +entities and models.

+

If you think you might be interested in +making game maps, consider

+

stopping by the Level Editing forum at Quake3World

+

registering as a forum user and asking what +you need to do to

+

get started. From the Quake3World home page, +click

+

on the “Community” button, and then

+

select the “Level Editing” button.

+

 

+

Back - Table of Contents

+

-2-

+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/related_links.html b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/related_links.html new file mode 100644 index 00000000..44c6ec1e --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/related_links.html @@ -0,0 +1,51 @@ + + + + + + +Related Links + + + + + +

Related Links

+
+ +
+
+ + + + +
+

Back
+
+ + Table of Contents
+
+ -11-

+
+
+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/ta_game_types.html b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/ta_game_types.html new file mode 100644 index 00000000..89a7d629 --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/ta_game_types.html @@ -0,0 +1,199 @@ + + + + + + +Design for all Team Arena Game Types + + + + + +

Design for All Team Arena Game Types

+
+
+ + + + +
      We + encourage designers to make their maps compatible with all “team” + style games. Team DM and Tournament are the exceptions here. Experience + shows that balanced CTF style maps do not make great (or even good) Team + DM maps. To do this, you will need to mark some of the team game + entities for multiple game types. An example is the obelisk used in + Overload. The entity is also used to mark the location of the + skull-receiving base in Harvester. If your Overload obelisk and your + Harvester base are to be in the same location give the entity a + key/value of “gametype/obelisk, harvester”. If you choose to place + the entities in different locations in each game type, you will need to + place separate entities and mark them appropriately. +

 

+
+

Placing Common Entities for all Game types

+
+

     Typically, the player + start, respawn, power-ups, ammo and weapon placement are the same for + each game type. It helps players if they don’t have to remember a lot + of placement locations from game to game. But this doesn’t have to be + the case. Use the gametype key to control placement if you want them + different between game types.

+

      Place + team_CTF_blueplayer entities in the locations where you want blue team + members to join the game and team_CTF_redplayer entities in the + locations where you want red team members to join the game. You should + place enough of these to accommodate the maximum number of players that + will be on a side (though usually no more than 8 to a side in a “normal” + map and as many as 32 in an extremely large terrain map). If you place + too few, teammates are likely to telefrag each other as they join the + game.

+

      Place + team_CTF_bluespawn entities in the locations where you want blue team + members to respawn when they die in the game. Place team_CTF_redspawn + entities in the locations where you want red team members to respawn + when they die in the game. You should place enough of these to + accommodate the maximum number of players that will be on a side (though + usually no more than 8 to a side).

+

      Place the four + persistent power-ups (guard, doubler, scout, and ammo_regen) in or near + the bases of each team. On the blue side, check the BLUETEAM spawn flag + box for each entity. On the red side, check the REDTEAM spawn flag box + for each entity. Place (and center) the appropriate spawn spot model + beneath each power-up (spawn.md3 on the blue side, spawn_red.md3 on the + red side).

+ +

 

+
+

Placing Game-type Specific Entities

+
+

      Each of the four + team-style game types has a set of associated entities that go with it, + whether it’s the flags and bases in Capture the Flag, or the obelisk + in Overload.

+ +

Capture the Flag (required entities)

+
+

      This corresponds + to the cvar: “/g_gametype 4” when entered in the console.

+

      Entities in this game + must have a value/key setting of “gametype/ctf”

+

      Place a + team_CTF_blueflag in the blue base.

+

      Place a + team_CTF_redflag in the red base.

+

      Place a + team_blueobelisk in the blue base where the goal should be. Give it a + facing angle. This forms the flag base. Do not mark any gametype.

+

      Place a team_redobelisk + in the red base where the goal should be. Give it a facing angle. This + forms the flag base. Do not mark any gametype.

+ +

 

+ +

One Flag CTF (required entities)

+
+

      This corresponds + to the cvar: “/g_gametype 5” when entered in the console.

+

      Entities in this game + must have a value/key setting of “gametype/oneflag”

+

      Place a + team_CTF_blueflag in the blue base.

+

      Place a + team_CTF_redflag in the red base.

+

      Place a + team_blueobelisk in the blue base where the goal should be. Give it a + facing angle. This forms the flag base. Do not mark any gametype.

+

      Place a team_redobelisk + in the red base where the goal should be. Give it a facing angle. This + forms the flag base. Do not mark any gametype.

+

      Place a + team_neutralflag some place in the neutral area of the map, preferably + equidistant from both bases.

+ +

 

+ +

Overload (required entities)

+
+

     This corresponds to + the cvar: “/g_gametype 6” when entered in the console.

+

      Entities in this game + must have a value/key setting of “gametype/obelisk”

+

      Place a + team_blueobelisk in the blue base where the goal should be. Give it a + facing angle. Do not mark any gametype.

+

      Place a team_redobelisk + in the red base where the goal should be. Give it a facing angle. Do not + mark any gametype.

+ +

 

+ +

Harvester (required entities)

+
+

      This corresponds + to the cvar: “/g_gametype 7” when entered in the console.

+

      Entities in this game + must have a value/key setting of “gametype/harvester”

+

      Place a + team_blueobelisk in the blue base. Do not mark any gametype.

+

      Place a team_redobelisk + in the red base. Do not mark any gametype.

+

      Place a + team_neutralobelisk some place in the neutral area of the map, + preferably equidistant from both bases.

+ +

 

+ +

Using Entities for All Gametypes

+
+

      This assumes + that the designer will use the same entities, in the same locations for + all gametypes. Mark the gametypes on each entity as noted:

+

      Place a + team_CTF_blueflag in the blue base.

+

      Gametype: ctf, oneflag

+

      Place a + team_CTF_redflag in the red base.

+

      Gametype: ctf, oneflag

+

      Place a + team_blueobelisk in the blue base where the goal should be. Give it a + facing angle. This forms the flag base.

+

      Gametype: Do not mark + any gametype.

+

      Place a team_redobelisk + in the red base where the goal should be. Give it a facing angle. This + forms the flag base.

+

      Gametype: Do not mark + any gametype.

+

      Place a + team_neutralobelisk some place in the neutral area of the map, + preferably equidistant from both bases.

+

      Gametype: harvester

+

      Place a + team_neutralflag some place in the neutral area of the map, preferably + equidistant from both bases.

+

      Gametype: oneflag

+

 

+
+
+
+ + + + +
+

Back
+
+ + Table of Contents
+
+ + Design Tips
+
+ -8-

+
+
+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/table_of_contents.htm b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/table_of_contents.htm new file mode 100644 index 00000000..536bfc7a --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/table_of_contents.htm @@ -0,0 +1,77 @@ + + + + + + + +Table of Contents + + + + +

Table of Contents
+
(HTML Conversion by AstroCreep)

+
+ + + + + +
+

Title..........................1
+
+ +Preface..........................2
+
+ +Table of Contents..........................3
+
+ +Team Arena Entity Definitions..........................4
+
+ +Team Arena Prefabs..........................5
+
+ +Team Power-Up Bases..........................6
+
+ +Using the New Game Entities..........................7
+
+ +Design for All Team Arena Game Types...........................8
+
+ +Design Tips and Suggestions...........................9
+
+ +Map Converter’s Checklist.........................10
+
+Related Links.........................11
+

+
+
+
+
+ + + + +
+

Back
+
+ + Table of Contents
+
+ + T A Entity Definitions
+
+ -3-

+
+
+

 

+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_arena_entity_definitions.html b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_arena_entity_definitions.html new file mode 100644 index 00000000..23682fa3 --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_arena_entity_definitions.html @@ -0,0 +1,66 @@ + + + + + + +Team Arena Entity Definitions + + + + + +

Team Arena Entity +Definitions

+
+ + + + +
The enclosed tadef_ptch.def + file a bare bones list of entity descriptions for use in the Q3Radiant + editor. You can paste it onto the end of your current def file (or better + yet, into a copy of that file). +

This is the Quake III: Team Arena entities definition + file patch (note that it is not the entire definition file). The Q3Radiant + editing tool uses this data to place game entities (ammo, weapons, + power-ups, etc.) in the game map and the game. It contains the definitions + for all the power-ups, game-specific items (like the Obelisks from + Harvester and Overload). To use these definitions, open the text file and + copy it. Now open the definitions file that you are currently using + (probably in Baseq3/Scripts) and paste the contents of your clipboard at + the end of the file. Now save this modified document as “teamarena.def” + in a folder in your Quake III Arena folder called Missionpack/scripts. + Open the Q3Radiant editor. Click on the File menu, and then select the “Project + Settings” entry. This brings up the Project Settings pop-up window. + Change the entitypath field so the pathname leads to the new definitions + file.

+

Example: If the field currently reads c:/quake3 or + g:/quake3/missionpack/scripts/*.def, change it to + c:/quake3/baseq3/scripts/teamarena.def

+ +

 

+
+
+
+ + + + +
+

Back
+
+ + Table of Contents
+
+ +  Team Arena Prefabs
+
+ -4-

+
+
+

 

+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_arena_prefabs.html b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_arena_prefabs.html new file mode 100644 index 00000000..8aa53d50 --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_arena_prefabs.html @@ -0,0 +1,96 @@ + + + + + + +Team Arena Entity Definitions + + + + + +

Team Arena Prefabs

+
+ + + + +
There are eight prefabricated brush groups + in this folder. They are pre-built game components (using brushes and/or + curve patches) for some of the objects frequently used in Quake III: + Team Arena. The shader scripts and textures for these prefabs are + already a part of the Team Arena Mission Pack pak file and need not be + added separately. +

      The pads act like + decals (if you ever built plastic model kits, these are the little + graphic things that you soaked in water and then stuck on the surfaces + of the model). The images will appear to be a part of the surface upon + which they rest. For the pads, you will want to place them in such a way + that they are centered under the entity boxes above them. The surface of + the pad should be one to two units above the surface beneath them.

+

When positioning the banners, the banner brush should + not touch the surface behind it.

+ +

     armorpad_blue.pfb + Place this prefab beneath yellow and/or red armor on the blue team’s + side.

+ +

     armorpad_red.pfb Place + this prefab beneath yellow and/or red armor on the red team’s side

+ +

     armorpad_neutral.pfb + Place this prefab beneath yellow and/or red armor in neutral areas.

+ +

     weaponpad_blue.pfb + Place this prefab beneath weapons and (non persistent) power-ups on the + blue team’s side.

+ +

     weaponpad_red.pfb + Place this prefab beneath weapons and (non-persistent) power-ups on the + red team’s side.

+ +

     weaponpad_neutral.pfb + Place this prefab beneath weapons and (non-persistent) power-ups in the + map’s neutral areas (in between bases).

+ +

TA_banner_blue.pfb This + prefab is a smallish blue team flag with the placeholder blue team logo + placed over the flag surface as a decal. During game play, this logo + will change to show the logo selected by the blue team. Designers may + wish to scale the size or proportions of this banner to suit their + needs. Always make sure that the word “blue” on the logo reads + correctly. Otherwise, non-symmetrical team logos will appear backwards + on the banner.

+ +

TA_banner_red.pfb This + prefab is a red team flag with the placeholder red team logo placed over + the flag surface as a decal. During game play, this logo will change to + show the logo selected by the red team. Designers may wish to scale the + size or proportions of this banner to suit their needs. Always make sure + that the word “red” on the logo reads correctly. Otherwise, + non-symmetrical team logos will appear backwards on the banner.

+

 

+
+
+
+
+ + + + +
+

Back
+
+ + Table of Contents
+
+  Team Power-up Bases +

-5-

+
+
+

 

+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_powerup_bases.html b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_powerup_bases.html new file mode 100644 index 00000000..349ad089 --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/team_powerup_bases.html @@ -0,0 +1,62 @@ + + + + + + +Team Arena Entity Definitions + + + + + +

Team Power-up Bases

+
+
+ + + + +
In Quake III: Team Arena, a base model + marks the location of each of the four persistent Team Power-Ups (Ammo + Regen, Guard, Doubler, and Scout). These models are not generated + programmatically (as is the case with the obelisks and flag bases) and + must be placed in the game maps by the mapmaker. Position the model such + that the center of its origin sits on top of the floor and so that it is + centered beneath the Team Power-Up. There are separate models for the + blue and red team sides. If you choose to place a powerup in neutral + territory (as in MPTERRA3), place a weaponpad_neutral.pfb under the + powerup. +

Copy the spawn folder into the models/mapobjects + directory in your missionpack directory (if necessary, create all three + directories now). Do not create a new directory for them. Shader scripts + and textures for these models are already a part of the Mission Pack pak + file and need not be added separately.

+

spawn.md3  This model is the location marker for the + blue side.

+

spawn_red.md3  This model is the location marker for + the red side.

+ +

 

+
+
+
+ + + + +
+

Back
+
+ + Table of Contents
+
+  New Game Entities +

-6-

+
+
+

 

+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pages/using_new_game_entities.html b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/using_new_game_entities.html new file mode 100644 index 00000000..6d4ae40d --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/pages/using_new_game_entities.html @@ -0,0 +1,115 @@ + + + + + + +Team Arena Entity Definitions + + + + + +

Using New Game Entities

+
+
+ + + + + +
The best way to get a feeling for how the + new game entities should be used is to play Team Arena for a while. Here + are the id team’s rules and suggestions for using the new entities. +

 

+
+

Game Types

+
+

There are eight game types (including those from + original Quake III Arena). Unless marked with a gametype key, entities + will appear in every game type. The game types are:

+ +

Gametype Type of play corresponds to cvar …

+
+

FFA (multiplayer Free for All deathmatch) corresponds + to g_gametype 0

+

Tournament (1 on 1 deathmatch) corresponds to + g_gametype 1

+

Single (Single Player Free for All) corresponds to + g_gametype 2

+

Team (Team deathmatch) corresponds to g_gametype 3

+

CTF (Capture the Flag … traditional rules) + corresponds to g_gametype 4

+

Oneflag (single flag CTF) corresponds to g_gametype 5

+

Overload (destroy the opponent’s obelisk) + corresponds to g_gametype 6

+

Harvester (collect skulls, take to opponent’s base) + corresponds to g_gametype 7

+ +

 

+
+

The “notfree”, “notteam”, and “notsingle” + Keys

+
+

These are still checked by the game engine. They are + checked AFTER the gametype keys are checked. Because they complicate the + design (simple is usually best), we recommend not using them in Quake 3 + Team Arena maps.

+ +

 

+
+

Enable/Disabled entities for TA / Vanilla Q3

+
+

+ Entities can now have one of the following epairs: +

+ +

+ "notta" "1" +

+ +

+ for when the entity is not supposed to show up in Team Arena, and: +

+ +

+ "notq3a" "1" +

+ +

+ for when the entity is not supposed to show up in Quake III Arena. +

+ +

+ An entity may have both epairs, meaning it will only show up in mods. +

+ +

+ The epairs only work on "gameplay" type entities such as weapons, + powerups, items, ammo, etc. They will not affect entities that are + compiled into maps, such as models. +

+ +

 

+
+
+
+ + + + +
+

Back
+
+ + Table of Contents
+
+ T.A. Game Types +

-7-

+
+
+

 

+ + + + diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pics/CRUSADER.gif b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/CRUSADER.gif new file mode 100644 index 00000000..002d850c Binary files /dev/null and b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/CRUSADER.gif differ diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pics/INTRUDER.gif b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/INTRUDER.gif new file mode 100644 index 00000000..34a52f0e Binary files /dev/null and b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/INTRUDER.gif differ diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pics/MAINPOP.gif b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/MAINPOP.gif new file mode 100644 index 00000000..cdd9c029 Binary files /dev/null and b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/MAINPOP.gif differ diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pics/MENUBACKgif.gif b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/MENUBACKgif.gif new file mode 100644 index 00000000..ec299c78 Binary files /dev/null and b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/MENUBACKgif.gif differ diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pics/PAGANs.gif b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/PAGANs.gif new file mode 100644 index 00000000..9eb6c4e5 Binary files /dev/null and b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/PAGANs.gif differ diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pics/STROGGS.gif b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/STROGGS.gif new file mode 100644 index 00000000..d0b595e4 Binary files /dev/null and b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/STROGGS.gif differ diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pics/THEFALLEN.gif b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/THEFALLEN.gif new file mode 100644 index 00000000..a360a0be Binary files /dev/null and b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/THEFALLEN.gif differ diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/pics/logo.gif b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/logo.gif new file mode 100644 index 00000000..3dfbdca5 Binary files /dev/null and b/docs/manual/quake3/Team_Arena_Mapping_Help/pics/logo.gif differ diff --git a/docs/manual/quake3/Team_Arena_Mapping_Help/start.html b/docs/manual/quake3/Team_Arena_Mapping_Help/start.html new file mode 100644 index 00000000..412d5057 --- /dev/null +++ b/docs/manual/quake3/Team_Arena_Mapping_Help/start.html @@ -0,0 +1,30 @@ + + + + + + + +MAPPING HELP + + + + +

 

+

+

MAPPING +HELP

+

by +Paul Jaquays
+
Copyright © 2000 id software, inc.

+

      +    +    +    +

+

 

+

START

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/Image3.gif b/docs/manual/quake3/Terrain_Manual/pages/Image3.gif new file mode 100644 index 00000000..fdb98d27 Binary files /dev/null and b/docs/manual/quake3/Terrain_Manual/pages/Image3.gif differ diff --git a/docs/manual/quake3/Terrain_Manual/pages/Image4.gif b/docs/manual/quake3/Terrain_Manual/pages/Image4.gif new file mode 100644 index 00000000..46d39abd Binary files /dev/null and b/docs/manual/quake3/Terrain_Manual/pages/Image4.gif differ diff --git a/docs/manual/quake3/Terrain_Manual/pages/Image5.gif b/docs/manual/quake3/Terrain_Manual/pages/Image5.gif new file mode 100644 index 00000000..f240add8 Binary files /dev/null and b/docs/manual/quake3/Terrain_Manual/pages/Image5.gif differ diff --git a/docs/manual/quake3/Terrain_Manual/pages/Image6.gif b/docs/manual/quake3/Terrain_Manual/pages/Image6.gif new file mode 100644 index 00000000..fdb98d27 Binary files /dev/null and b/docs/manual/quake3/Terrain_Manual/pages/Image6.gif differ diff --git a/docs/manual/quake3/Terrain_Manual/pages/adding_bots.html b/docs/manual/quake3/Terrain_Manual/pages/adding_bots.html new file mode 100644 index 00000000..c6e951f2 --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/adding_bots.html @@ -0,0 +1,40 @@ + + + + + + +Adding Bots + + + + + +

Adding Bots

+
+ + + + +
+

      Despite their massive size, terrain maps can support enjoyable bot play. The +key is careful placement of cluster portals, which is true of any map. Study the +bspc documentation for details. The documents accompanying the tools are more up +to date than those in the Q3Radiant manual. Your goal should be to keep the +number of areas in each cluster roughly equal and reasonably low (hundreds, not +thousands).

+
+ +

Back - Table +of Contents - Glossary

+ +
+
+
+

 

+

 

+

-25-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/adding_buildings_to_terrain.html b/docs/manual/quake3/Terrain_Manual/pages/adding_buildings_to_terrain.html new file mode 100644 index 00000000..9e40b467 --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/adding_buildings_to_terrain.html @@ -0,0 +1,85 @@ + + + + + + +Adding Buildings to Terrain + + + + + +

Adding Buildings to Terrain

+
+ + + + +
+

This is really best addressed as a number of semi-related building tips:

+ +

      Plan Ahead. If you know you want buildings +in your map, plan their locations from the first. Very complicated buildings +(lots of geometry and surface detail) should be isolated away from long views. +One reason for this is to control in view polygon counts. The second (and really +obscure one) is to reduce the amount of z-compression that will affect the +structures.

+ +

      Build to Support Game play. Each of the +structures in the Q3:TA terrain maps was built to support a game play need. +Quite often, less is better than more.

+ +

      Build Simply. Simple, uncomplicated +architecture may be best. The more complicated you make your buildings, the less +complicated the terrain around them can be. Depends on what you want to play up. +The busy look of many Q3A maps doesn’t translate well to large terrain. +Details are lost at great distances and only add to the triangle complexity of +maps containing them.

+ +

      Detail Content. With few exceptions ALL +the geometry inside the terrain map is detail content, not just the terrain +entity. The walls forming the corridor in mpterra2 may be the only non-detail +structures in that map. Making geometry into detail makes a map far easier and +faster to compile. If you want to block vis inside your structures, create +simple caulk structures … much the same way as described for vis blocking the +terrain.

+ +

      Z-Compression Problems. Review the the map +in 16 bit mode during development. This brings out z-fighting issues that occur +at long distances. This z-fighting is created by detail brushes being compressed +into each other (The Q3A engine does a significant amount of “z compression” +as geometry becomes farther away from the viewer). This z-compression is far +less apparent in 32 bit modes, but we have to remember that many people turn +down graphic features in order to simply play Q3A on their systems (not just to +get ridiculously high frame rates).

+ +

      Fit Structures to the Terrain. Don’t +just set structures on terrain and expect them to look right. Make your +buildings look like they belong where you put them. Accommodate the rise and +fall of terrain in your floor plans … or “dig” into the terrain brushes to +create basements, tunnels and whatever you need. You can also adjust the height +map to better arrange the geometry around structures, or manually tweak the +triangles once the structures are in place. History is full of examples of +really interesting buildings that have been built to accommodate difficult +terrain like hills, cliffs and mountains.

+

 

+
+
+ +
+
+ +

Back - Table +of Contents - Adding Bots

+ +

 

+
+
+

 

+

 

+

-24-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/art_tools.html b/docs/manual/quake3/Terrain_Manual/pages/art_tools.html new file mode 100644 index 00000000..ce54961d --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/art_tools.html @@ -0,0 +1,39 @@ + + + + + + +Art Tools Required + + + + + +

Art Tools Required

+
+ + + + +
+

      The creation of terrain maps requires that the mapmaker have, or have access +to a computer art program. Both JASC’s Paint Shop Pro and + Adobe’s Photoshop +were tested and will do the job. Any art program that can output an 8-bit BMP +format file with indexed color should work also.

+
+

Back - Table + of Contents- The Terrain Entity

+ +
+
+
+

 

+

 

+

 

+

-5-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/blocking_vis.html b/docs/manual/quake3/Terrain_Manual/pages/blocking_vis.html new file mode 100644 index 00000000..369cf083 --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/blocking_vis.html @@ -0,0 +1,101 @@ + + + + + + +Blocking Vis + + + + + +

Blocking Vis

+
+ + + + +
+

      Terrain maps still have to follow the rules that apply to all Q3A engine +maps. There’s only so much that you can allow to be seen at one time, or the +game starts slowing down. The good news is that the engine will only draw the +terrain triangles that are in the player’s PVS (potential visible set). It +doesn’t have to draw all the triangles in the terrain entity just because part +of the entity is in view.

+

      At first, most of the usual bag of tricks that mappers use to create vis +blocking structures in architectural maps don’t seem to apply to terrain. But +that is not the case. If anything, you NEED to think of terrain in much the same +way as you think of buildings. You are still dealing with open spaces that could +be considered corridors and large rooms … even though they look like large +valleys.

+

      In fact, it would be best to plan out the layout of your terrain + BEFORE +creating your height map. If you know you want to block vis, you can design your +terrain to work with vis blocking techniques and avoid the agony of having to go +all the way back to the start when you discover that your killer terrain map +lets you see too much at once.

+

      If you want the player, even in spectator mode, to be able to fly everywhere +and see the whole world laid out below him … an unrestricted vista, so to +speak, you’re going to be much more limited. Every single triangle in the map +will essentially be viewable at any moment in time. However, if you’re willing +to place restrictions on your players - limit how high they can fly or climb, +you suddenly have more options for blocking player visibility.

+

      First, the terrain entity is entirely detail content, so it doesn’t block +vis. That’s a key part of how this whole process works. Otherwise, vis time +would be measured in eras (not minutes or hours) and visdata size would be very, +very large.

+

      To block vis in the terrain, start by creating simple +vis-blocking structures +out of caulk texture inside the forms of the terrain (they are not part of the +terrain entity). You can try to match the silhouette of the terrain, but in the +end, you may only end up complicating the visdata without gaining any real +benefit.

+

      Next, and this is going to sound strange, build thin walls of caulk that +follow the divide line (where the terrain falls away on both sides) of the +highest mountains, buttes or hills. Only do this where you know that you will +not allow the player to move over or see over that +part of the terrain (we’ll talk about clipping real soon).

+

 

+
+

Other Tips:

+
+
+ +

· Sky Texture in Place of Caulk: +You sometimes want to apply the sky texture to some of the surfaces of the thin +walls used as vis blockers. This can remove some HOM effects. The caulk brushes +that block the vis around the bases in mpterra2 have sky texture painted on the +surfaces facing the base.

+ +

· Hint Brushes: +Use these extremely sparingly and only after trying to solve the problem in +other ways. Hint brushes can add hours to vis compile times. Even so, they can +make a difference. One trick you can try is to put a horizontal hint brush at a +point about midway up the slopes of your terrain. It can add some additional vis +break points.

+ +

· Adjusting Terrain: +Vis times totally depend on the placement of your vis blockers. Vis times are +not affected by modifying the terrain surfaces (terrain entities are detail +content, remember?). With that being said, you may want to modify the terrain to +allow you to more effectively position the vis-blockers. + + +

+
+
+ +

Back - Table +of Contents - Clipping the Terrain

+ +

 

+
+
+

 

+

 

+

-18-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/boxing_in_the_world.html b/docs/manual/quake3/Terrain_Manual/pages/boxing_in_the_world.html new file mode 100644 index 00000000..d04314a3 --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/boxing_in_the_world.html @@ -0,0 +1,48 @@ + + + + + + +Boxing in the World + + + + + +

Boxing in the World

+
+ + + + +
+

      It may not need mentioning here, but … the terrain entity needs to be +contained inside a sealed world. For the terrain maps in Q3:TA, we built huge +boxes. Any portion of the box that could be seen while playing the game, or +flying around in spectator mode was covered in sky texture. Any portion of the +box that could not be seen was made out of common/caulk. If mountains or canyon +walls surround your map, plan to bring the caulk portion of the wall up as high +as you can. This can reduce the number of triangles seen in the map. Generally +speaking, you will see ALL the sky triangles inside the map at all times.

+

      Finally, and this is a part of vis blocking, but it should also be noted +here. Don’t forget to place large caulk structures that rise up from the +bottom of the world box to near the ground surfaces of terrain entity. If the +ground level rises and falls substantially, these can be a part of the vis +blocking process. Otherwise they serve to reduce the size of the map’s total +volume (generally speaking … a good thing).

+
+ +

Back - Table +of Contents - Entity Keys and Values

+ +

 

+
+
+

 

+

 

+

-14-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/clipping_the_terrain.html b/docs/manual/quake3/Terrain_Manual/pages/clipping_the_terrain.html new file mode 100644 index 00000000..bb35889d --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/clipping_the_terrain.html @@ -0,0 +1,58 @@ + + + + + + +Clipping the Terrain + + + + + +

Clipping the Terrain

+
+ + + + +
+

      The terrain entity uses its triangle surfaces as clipping planes. No +additional clipping is required to allow characters to run on the terrain’s +surface. As the initial terrain maps developed in house, we discovered that to +control and guide play flow, we needed to clip many of our mountain and canyon +slopes with vertical walls. Done right (as the slopes start becoming too steep +to climb), players don’t notice (as much).

+

      Next, decide how far up in the sky you are willing to let your player’s +fly. If the map is entirely open you might want to keep it that way. If you’ve +placed caulk barriers as described above, then the low point on the ridgeline +(or lower) will likely be your ceiling height.

+ +

Clipping Tips

+
+
+ +

· Make sure your “ceiling” clip +brushes extend all the way up the sky brush.

+ +

· Keep your clip brushes simple.

+ +

· Right angles are rarely found in +nature. Use the clipper tool to take the corners off your vertical clips.

+
+
+ + +

Back - Table +of Contents - Mapping the Textures

+ +

 

+
+
+

 

+

 

+

-19-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/creating_the_alphamap.html b/docs/manual/quake3/Terrain_Manual/pages/creating_the_alphamap.html new file mode 100644 index 00000000..0ccad7d7 --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/creating_the_alphamap.html @@ -0,0 +1,194 @@ + + + + + + +Creating the Alphamap + + + + + +

Creating the Alphamap

+
+ + + + +
+

      The alphamap referenced by the alphamap key/value pair is an art file created +specifically for the map. For non-digital artists, it may be one of the more +technically and conceptually challenging things that need to be created to make +the terrain map work.

+

      Simply put, the alpha map is the template that the compiler uses to assign +textures to the terrain surface.

+

      To make the alphamap, you must have, or have access to, an art program that +can save a file as an 8-bit BMP file with indexed color. I’ll discuss other +file types later on, but the BMP file is probably the simplest solution, both +technically and conceptually.

+

 

+
+

Terms

+
+

      First, you need to understand a couple vocabulary words … jargon, if you +will:

+ +

Indexed Color: In essence, each color used in a piece of art is +remembered by its location on the color table or palette (see below). There are +256 colors available, numbered from 0 to 255. Each position on the palette has +its own number. This number has nothing to do with the RGB values of a color in +that position. If you change the actual color located at a particular location +on the palette (say from red to blue), all the pixels that were formerly that +shade of red (if painted using a color with that index number), will change to +the new color of blue.

+ +

Color Table: This is what Photoshop calls the indexed color layout of 256 +colors. In Paint Shop Pro it’s a palette. This is a pop-up window that shows +the colors in the palette and their arrangement. For making an alphamap for a +terrain map, the colors you choose are not important, but their position on the +palette is.

+ +

Palette: This is what Paint Shop Pro calls a Color Table.

+

 

+
+

Making the Palette

+
+

      The best way to start is to make a set of colors to use when painting +alphamaps. If you want, you can do this once and save it out. In PSP edit the +palette (in Photoshop, open the Color Table). Make sure the colors are sorted by +index number (there may be a pull down menu that allows this). In PSP, the +colors are indexed from the upper left (color 0 in the upper leftmost position +and increasing in value to the right). In Photoshop, the positions are reversed. +The color with value 0 is in the lower rightmost position and the index numbers +increase to the right.

+

      Because there is a direct one-to-one relationship between colors in the +palette and individual shaders that make of the metashader, you should select +clearly distinct colors to represent each shader. You should have one color for +each layer you intend to include in the map (see keys above), which means one +color to represent each root shader. You may find it convenient to create more, +so they are available for later use (if you save the palette).

+

      This method worked for me to make a 16-color palette in Paint Shop Pro. +First, I reduced my palette size to 16 colors. I clicked on each palette +position and created a color for it (don’t use black). Then, I increased my +palette size back up to 256 colors, filling the rest with black. In Photoshop, +it’s easier to select all the colors you don’t intend to use and make them +black. Then, I save the palette out as a file for later use.

+

      Another thing you might try is to make a grayscale palette, then use only the +first few positions for your color and leave the rest for grayscale (this allows +you to import bmp height maps and use them as guidelines).

+

 

+
+

Alphamap File Data

+
+

File type: The alphamap is a BMP format file or a TGA file (see other +file formats below). With BMP format, each color in your palette corresponds +directly to a root shader used to create the smooth texture blends on the +terrain.

+ +

File size: The size of the alphamap should be one-to-one with the number +of vertexes in the map. If you have 64 divisions x 32 divisions in your terrain +mesh (65x33 vertexes), you should use a 65 by 33 alphamap. You can use an +alphamap with a size that is not a one-to-one map with the number of map +vertexes, but you can then expect a less precise interpretation of your texture +assignments.

+ +

Colors linked to Shaders: If an 8-bit texture is used (BMP), q3map links +a color’s position on the palette to an identifying number in the name of a +shader. The color in position 0 would reference a root shader named <metashadername>_0. +The color in position 1 would reference a root shader named <metashadername>_1. +<metashadername> refers to the value of the Shader key (see Key: Shader +below). In theory, you could probably have 256 different root shaders assigned +to the terrain entity. In practice, you’d probably want to bite your arm off +at the elbow before doing something as complicated as that.

+
+

Other File Formats

+
+

      It is possible to use a TGA file (a RGB color format) for an +alphamap. TGA +files are handled differently than indexed color files like BMP. Instead of +looking for a position on the palette, q3map interprets the RGB value of actual +color. With a 32-bit TGA file, only the color values in the red channel are +used. The program assumes that a gray scale of equal values is being used. The +program divides the colors by the number of levels into equal-sized ranges. When +assigning textures, q3map looks at what range the color falls in and chooses the +appropriate shader to place or blend.

+
+

Controlling Texture Blends

+
+

      Each triangle on the mesh can only have two root shaders blending across it. +Another way to say this is that there should be only two different colors on the +three vertexes that form any given triangle in the mesh. Any more, and a sharp, +unblended edge appears on the terrain surface. This can take some trial and +error to correct. A bsp -switch command called -showseams can help the mapmaker +find these errors. Create a new bsp command in your project file that includes +this option. We recommend doing it with a novis only operation.

+
+

              +

+
+

Figure 3

+

      In figure 3, the blue and white image on the left is a scaled up (4X) version +of the alphamap used on Distant Screams. It shows three different root shaders +in use. Compare that to the gray scale height map on the right and you can see +how the artist chose to assign textures to the various heights and depths of the +map. As long as the guidelines for texture placement are followed, a mapmaker +should be able to work with more different root shaders than shown here.

+
+

Alphamap Creation Tips:

+
+
+ +

· The alphamaps for the team arena maps +are included with this document, both as reference and as files that you can +modify to work with your own maps. You may want to compare the alphamaps against +the heightmaps for the same maps, just to see how id resolved mapping issues.

+ +

· You can create a quick (though not +necessarily good) alphamap by saving your height map as a new file. Then use the +“posterize” filter that can be found in some art tools. Reduce the number of +colors in the art to equal the layers (number of unique root shaders) in the +terrain.

+ +

· If you are creating a new alphamap +from scratch, use colors that are easily distinguished from each other.

+ +

· If you are making an alphamap for a +team style map where both sides of the map are identical (mirrored or rotated), +you only need to design the map for one side. Copy and position it as described +above for the heightmap.

+ +

· The id maps used simple color schemes +that were homogenous throughout the maps. That is not the only way of doing +things. It would be quite reasonable to use many more terrain textures +(particularly if you weren’t going to build complicated, multi-texture +architecture on top of them). Consider a map where one part of the terrain used +red-themed textures and the other side blue themed textures. Have them blend +into a few simple neutral colors near the map center.

+ +

· Try doing terrain style texture +mapping on non-terrain geometry. Results will definitely vary, but some could be +interesting.

+
+
+ +

Samples: The last height map and the alphamap used to create each of the +terrain maps in Team Arena is included in the Mapping Support folder. Note that +the designers made vertex manipulations to the final terrain meshes that are not +reflected in these height maps. Also, the alphamaps are in PCX format, not BMP +format.

+
+ +

Back - Table +of Contents - The Terrain Texture

+ +

 

+
+
+

 

+

 

+

-16-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/creating_the_terrain.html b/docs/manual/quake3/Terrain_Manual/pages/creating_the_terrain.html new file mode 100644 index 00000000..7cc5b281 --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/creating_the_terrain.html @@ -0,0 +1,63 @@ + + + + + + +Creating the Terrain + + + + +

Creating the Terrain “Mesh”

+ + +
+ + + + +
+

      Although it’s not necessarily the only way to develop a piece of terrain, +thinking of it and creating it as “mesh” of triangular brushes may be the +easiest way to work initially. The terrain sections for Quake III: Team Arena +were built in this manner, though each designer went about it in slightly +different ways.

+

      Our primary tool was a plugin for Q3Radiant , created by David Hyde, called +GenSurf. The tool was originally created for Quake 2 (and may have been around +longer) and has been adapted for use with many of the game engines using Quake, +Quake2 and Quake3 technology. The basic concept behind GenSurf is that it can +create and export a group of brushes (or curve patches) to Q3Radiant that have +the look of “natural” terrain about them. Within the plug-in, the mapmaker +has control over the horizontal dimensions of the terrain entity, the steepness +of the slopes it creates, and the number of columns and rows of triangles that +it subdivides into.

+

      The terrain can be generated from within the tool by using simple waveforms, +more complex mathematical expressions, fractal calculations, or height maps. The +last item, height maps, is in our opinion, the route to take for creating +complex, visually interesting terrain layouts. A height map is a piece of art +(we rendered them in grayscale) that GenSurf uses as a template for establishing +the height of vertexes (the points where the corners of the terrain triangles +meet). GenSurf interprets the color of the pixel (or more correctly the +numerical color value of the pixel) that corresponds to the location of the +vertex. Generally, the darker the gray value, the lower in height the vertex +(256 unique height values corresponding to 256 pixel colors). GenSurf then uses +the vertexes to define the extents of triangles and suddenly, one has a terrain +surface. Of course, there are a few details of construction between start and +finish …

+
+ +

Back - Table +of Contents - Height Maps

+ +

 

+
+
+ +

 

+

 

+

-7-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/entity_keys_and_values.html b/docs/manual/quake3/Terrain_Manual/pages/entity_keys_and_values.html new file mode 100644 index 00000000..1548da49 --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/entity_keys_and_values.html @@ -0,0 +1,102 @@ + + + + + + +Entity Keys and Values + + + + + +

Entity Keys and Values

+
+ + + + +
+

      Once you’ve created the func_group that will become the terrain entity, you +need to add the various keys and key values that make it a terrain entity.

+ +

      +A word to the wise: WRITE YOUR KEYS AND VALUES ON SOMETHING YOU CAN +EASILY REFER TO DURING DEVELOPMENT!! During the creation, testing and tweaking +of the heightmap, you will have to reenter these key/value pairs for the terrain +entity every time you recreate it. One thing that can make things easier is +before replacing the terrain entity with a new mesh, open the entity window and +click on the most complicated of the key/value pairs (usually the alphamap). +When the new terrain func_group is in place, click on the value line and hit +return. That’s one less thing to retype.

+
+

Key: Alphamap

+
+

      Value: The value should be the +pathname to the art file use to assign textures to the terrain. Example: +maps/alpha/pj_terra1.bmp. The pathname begins in the game (baseq3 or missionpack) +directory, which includes the name of the art file.

+

      The q3map compiler applies and blends the textures +(shaders) on the terrain +entity using a “metashader” (see Texturing the Terrain below) that +references the art file named by the alphamap value. See the Creating the +Alphamap section below for details.

+
+

Key: Layers

+
+

      Value: A positive integer, equal to +the number of unique or root textures to be blended on the map. Each color on +the alphamap’s palette corresponds to a “layer.” If you plan to blend 4 +textures, you need a layer value of 4.

+ +

Key: Shader

+
+

      Value: A pathname, beginning in the + missionpack/scripts directory, which includes the name of the filename and the +name of the metashader. Example: The shader value for mpterra2 is “terrain/mpterra2”. +“terrain” is the name of the script and mpterra2 is the name of the +metashader used to apply texture to this terrain.

+ +

Key: Terrain

+
+

      Value: Set this to 1 to indicate that +the func_group is a terrain entity. It’s essentially a yes/no flag.

+ +

Key: Min

+
+

      Value: Map coordinates of the minimum +XY extents (lowest left extent) of a component piece of a multi-part terrain +entity. This is optional, only used if you are texturing a subset of the total +terrain area.

+

The Min and Max extents (both must be in the entity) establish where a +subsection of terrain fits into the overall terrain map. It lets q3map assign a +subset of the alphamap to the entity, instead of referencing the entire alphamap. +It could also be used on a separate terrain entity to use the same alphamap, but +reference a different shader.

+
+

Key: Max

+
+

      Value: Map coordinates of the maximum +XY extents (uppermost right extent) of a component piece of a multi-part terrain +entity. This is optional, only used if you are texturing a subset of the total +terrain area.

+

      The Min and Max extents (both must be in the entity) establish where a +subsection of terrain fits into the overall terrain map. It lets q3map assign a +subset of the alphamap to the entity, instead of referencing the entire alphamap. +It could also be used on a separate terrain entity to use the same alphamap, but +reference a different shader.

+
+ +

Back - Table +of Contents - Creating the Alphamap

+ +

 

+
+
+

 

+

 

+

-15-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/glossary.html b/docs/manual/quake3/Terrain_Manual/pages/glossary.html new file mode 100644 index 00000000..b2311675 --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/glossary.html @@ -0,0 +1,52 @@ + + + + + + +Glossary + + + + + +

Glossary

+
+ + + + +
+ + +

Root Shader: a shader that is part of +a family of related shaders used to texture a terrain entity. It represents a +terrain texture in its unblended state. The naming convention for a root shader +is <metashadername>_#.

+ +

Blend Shader: a shader that is part of a family of related shaders used +to texture a terrain entity. It represents a terrain texture in its blended +state, two textures that crossfade across each other. The naming convention for +a blend shader is <metashadername>_#to#.

+ +

Metashader: the identifying name of a group of related shaders used to +texture a terrain entity. By way of example, the metashader name used to texture +mpterra2 was … mpterra2. Its root shaders had names like mpterra2_0, +mpterra2_1, and mpterra2_2. Its blend shaders were named mpterra2_0to1, +mpterra2_1to2, and mpterra2_0to2.

+
+ +

Back - Table +of Contents - Q3Map Shader +Commands

+ +

 

+
+
+

 

+

 

+

-26-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/height_map_into_terrain_mesh.html b/docs/manual/quake3/Terrain_Manual/pages/height_map_into_terrain_mesh.html new file mode 100644 index 00000000..78875d5c --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/height_map_into_terrain_mesh.html @@ -0,0 +1,41 @@ + + + + + + +Height Map into Terrain Mesh + + + + + +

Height Map into Terrain Mesh

+
+ + + + +
+

      This is not intended to be a tutorial on using GenSurf, but it will include +some pointers on getting the most out of the tool. You can download the +standalone tool and find tutorials for GenSurf at this site

+

      This page, in particular, contains tips for using GenSurf, most of which to +apply to Q3A terrain creation. 

+

      When starting the GenSurf plug-in: You will probably want to “Select Ground +Surface” as the option for making your terrain surface.

+
+ +

Back - Table +of Contents - Gensurf Settings

+ +

 

+
+
+

 

+

 

+

-10-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/height_maps.html b/docs/manual/quake3/Terrain_Manual/pages/height_maps.html new file mode 100644 index 00000000..878f04d7 --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/height_maps.html @@ -0,0 +1,174 @@ + + + + + + +Height Maps + + + + + +

Height Maps

+
+ + + + +
+

      The terrain maps in Quake III: Team Arena began as grayscale bitmap art files +imported into David Hyde’s “GenSurf” tool, a Q3Radiant plug-in. As +mentioned before, the height map is a template that the utility uses to define +the vertex heights of the triangles forming the terrain surface. We used Adobe +Photoshop and JASC’s Paint Shop Pro to create and adjust our height maps … +but any art program that can output a .bmp format file can be used to create the +height map.

+
+

+
+

figure 1.

+

      By way of example, the piece of artwork in figure 1 is a greatly scaled up +(4X) version of the height map used to create the initial terrain geometry for +mpterra2. The very dark, horizontal area near the center is the big “lake” +near the center of the map. The dark curves to the upper right and lower left +are the “fjord” water areas. The dark areas in the upper left and lower +right are the locations of the bases. The white and very light gray areas +represent the peaks of hills and mountains.

+

      The key to understanding how the height map works is that the shades of gray +in the art (call them “color values”) represent the height of mesh vertexes +(triangle corners) and not the triangle quads (squares created by two +triangles). When you work on a piece of art where each individual pixel +corresponds to a vertex, it is easy to imagine the pixels (usually large square +blocks) as squares of terrain. But that’s not how it works.

+

      Start by giving some thought to the eventual size and proportions of the +final terrain area in your map. How many rows and columns of triangles do you +want in the map? The finer you subdivide the map (making more rows and columns), +the more triangles will appear in any given view, but the terrain can be made +less blocky by including more.

+

      GenSurf can generate a terrain mesh of up to 64 triangles on a side (of the X +and Y dimensions of the entire mesh). If you don’t decimate the GenSurf output +(an option that optimizes and reduces the number of triangles used to create the +mesh … and we really recommend that you don’t), it generates a mesh of +triangles in arranged in quads in neat rows and columns. By way of reference, +mpterra2 (the largest Team Arena map) is “only” 48x64 columns and rows of +triangles. Since Q3Radiant and q3map tend to like things that end up in neat +powers of 2 or units of 64 subdivisions, consider having your map extents (lower +left and upper right map corners) fall onto neat units, power of 2 units. In +mpterra2, the extents were set up to make the mesh triangles have sides of 256 +units.

+
+

+
+

Figure 2.

+

      Figure 2 shows an example of a top view of a terrain mesh that is 8 x 8 rows +and colums of triangles (on a side).

+

      Just as you would plan out a game map, give thought to the layout and flow of +your terrain map. Will it be all-open in one view? Can you use natural terrain +features to block vis? How complicated will your buildings (if any) be? Do you +want to include trees, water, weather effects or other items that could add to +the visual cost of your map?

+

      Begin the creation of your height map by making a new grayscale file. If your +program doesn’t allow you to easily modify a .bmp format file, work in another +format and then convert it when you save. You can make the dimensions of your +height map art whatever you want. The extents you set in GenSurf for the map +dimensions are what determine the final size of the terrain piece. Some may find +it easier to work with a large file initially, using their favorite painting +tools to lay in the shades of gray.

+

      However, when you get down to making final and precise changes in your height +map you should (and this is STRONGLY recommended), change the size of the art +file such that the pixel dimensions of the map are 1 pixel larger than the +number of divisions (rows and columns) in the terrain mesh you want to create. +If you are making a 64 x 64 division map, then you want to create a 65 x 65 +pixel height map.

+

      If there is not a one-to-one match between the number of vertexes in the mesh +(one more than the number of divisions) and the number of pixels in the height +map, then GenSurf interpolates the number values (0 to 255 range) of the pixels +to get an averaged value instead of an exact value for the height of the vertex +at that point.

+

      When you save out the height map art file, you must save it in 8-bit .BMP +format. Currently, this is the only the file format that GenSurf recognizes.

+ +

Tips and things to consider for making Height Maps

+
+
+ +

· Read through the section on blocking +vis later in the document. Plan your vis blocking terrain structures in advance +instead of having to start over when you discover that too much of your world is +in view.

+ +

· Consider what type of geometry will +form the edges of your map. The terrain maps in Q3:TA resolve the issue by +creating canyon-like settings … valleys bordered by high canyon or mountain +walls.

+ +

· Start by filling your map with a +neutral gray (value 127 or 128). Paint the high areas lighter and the low areas +darker.

+ +

· Keep your terrain shapes simple when +you start. You can add greater complexity as your map develops.

+ +

· You will probably want to keep the “playable” +area of your map within a fairly close or “narrow” range of gray values +close to the middle range of values. This allows you to use very dark shades of +gray to create deep chasms and very light shades of gray to create high +mountains, canyon walls or visual barriers.

+ +

· Extreme jumps between the gray values +in adjacent areas means steep slopes.

+ +

· Avoid making vertical or near vertical +terrain surfaces … unless you don’t mind the resulting textured surface +looking like barcode. Q3Map planar projects the textures onto the terrain entity’s +surface (Normal brushes are box mapped). The pixels will stretch and stretch to +fill the space. The farther the surface is from horizontal, the greater the +stretching.

+ +

· Use the roughness feature of GenSurf +to add a little, um … roughness to your map … so flat areas aren’t +completely flat. If you are using a 1 to 1 scale height map, adding “noise” +to the file will also accomplish this.

+ +

· If you want an area, such as a path, +to be flat, you need to make the gray value affecting two adjacent vertexes the +same value.

+ +

· You can create gentle slopes by +changing the gray values between adjacent areas by very small amounts.

+ +

· Slopes greater than 45 degrees are +close to becoming unplayable barriers.

+

 

+
+
+

If you are building a symmetrical team style map, only create one side of the +terrain. Create a new piece of art that has the dimensions of the final piece. +Paste the map half into the new file and move it into position. If the map will +have an even number of vertexes, paste the map again and then rotate or mirror +(as you choose) the selection and move it into position. If the number of +vertexes is odd, after you paste the first half of the map, select all but the +row or column of pixels along which the two halves of the map will face and copy +it. Paste it, rotate or mirror it, then position it. Now, select and copy half +the row or column of pixels you didn’t copy in the last operation. Paste it, +transform it as you did in the last operation, and then position it so that it +is in the same row or column, but on the opposite side of the piece you copied.

+

When you make significant changes to a height map, consider saving it as +version rather than over-writing the older file. Always nice to have a back up +when you realize that you’ve messed up more than you’ve fixed.

+
+ +

Back - Table +of Contents - Other Height +Map Tools

+ +

 

+
+
+

 

+

-8-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/introduction.html b/docs/manual/quake3/Terrain_Manual/pages/introduction.html new file mode 100644 index 00000000..23b6085f --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/introduction.html @@ -0,0 +1,49 @@ + + + + + + +Introduction + + + + + +

Introduction

+
+
+ + + + +
+

      Creating workable terrain style maps for the Q3A engine takes some +reorganizing of thought, but in many ways is not substantially different from +making a halls-and-rooms type of map. The designer still has to be concerned +about how much can be seen at one time and give thought to map flow and play. +The rules and restrictions that guide conventional map design are still there +… it just occurs on a much grander scale. You still have to think about poly +counts, that hasn’t changed; but generally speaking, the polys that you will +use to make your game terrain are VERY large and less are likely to be seen all +at once during a game.

+

      +The “terrain” style maps in Quake III: Team Arena do not represent any +changes to the Quake 3 Engine. The power to make them work has always been there, +unrealized and untapped. What has changed is the way map files are created and +processed. These construction techniques rely on changes in the Q3Radiant editor +and the q3map program that processes the map files into game files.

+
+

Back - Table +of Contents - Key Changes

+ +
+
+
+

 

+

 

+

-3-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/key_changes.html b/docs/manual/quake3/Terrain_Manual/pages/key_changes.html new file mode 100644 index 00000000..e1ce97d5 --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/key_changes.html @@ -0,0 +1,64 @@ + + + + + + +Key changes that have been made include + + + + + +

Key changes that have been made include:

+ +
+ + + + +
+
+

 

+
+ +

· A variant of the func_group entity + has been added to the game. When a func_group of brushes (only) is given a + terrain key and a numerical value (an ID number for that terrain) and several + other key attributes, it becomes a terrain entity and is treated differently + than other brushes during the compile.

+ +

· The map area has been expanded to + 128,000 units in all extents (256,000 units on any edge of the map volume). + While this does not mean that a map that large could actually run on current + game hardware, it does give the designer room to explore what the actual + limits may be. As a point of reference, mpterra2.bsp is roughly 12K x 16K x 3K + units in size … the largest map in the game by far.

+ +

· A terrain texture mapping system + plots textures across the terrain entity using a specially created .pcx or .tga + art file as a map for planar projecting and blending shaders on terrain + surfaces.

+ +

· A “meta-shader” is used to + organize and calculate blends between the shaders that are mapped onto the + terrain.

+ +

· Textures designed for use under + vertex lighting can be substituted at map load time for more complex shader-manipulated + textures that may not look correct in a vertex light only situation.

+
+
+ +

Back - Table +of Contents - Art Tools

+ +

 

+
+
+

 

+

-4-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/lighting_the_terrain.html b/docs/manual/quake3/Terrain_Manual/pages/lighting_the_terrain.html new file mode 100644 index 00000000..e77ec51c --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/lighting_the_terrain.html @@ -0,0 +1,135 @@ + + + + + + +Lighting the Terrain + + + + + +

Lighting the Terrain

+
+ + + + +
+

      Terrain maps also require some rethinking about the way you light maps.

+
+

Vertex Only

+
+

      If you are making a large terrain map, you should plan on making your terrain +textures be lit by vertex lighting only. Lightmaps can quickly become far too +large for the game to handle.

+

Make sure your large terrain textures contain the following parameters:

+ +

Surfaceparm nolightmap //signifies vertex lighting only.

+ +

Q3map_novertexshadows //this is what keeps those caulk vis blockers from +causing ugly shadows to form on your terrain.

+

      If you are using q3map_sun in your sky …

+ +

Q3map_forcesunlight //this makes the light emitted by a q3map_sun +parameter affect the vertex lit surface.

+
+

Light Sources

+
+

      For outdoor maps, the obvious source of lighting ought to be the sky. The +skies in the mpterra maps began with skies used in more conventional Team Arena +maps, but were modified to better suit the needs of the terrain worlds.

+
+
+ +

· Slow Down Those Clouds. + One thing to consider is slowing down the rate of cloud movement. What looks + OK in smaller maps looks wrong in vast panoramas.

+ +

· Strong Sunlight is + Good. For team maps, + you want to try and keep the light relatively the same in both base areas, so + if you have mountains or large base structures, having the light come in at a + nearly vertical angle is good, but less dramatic. +

+ +

· Ambient Light is Not + So Bad. Since the + beginning of Q3A map development we’ve said things like “Ambient Lighting + is bad”. Well, the problems caused by ambient lighting are still there + (flattening of shadows and colors), but with the distance of the play areas + from the sky surface (in some maps), adding an ambient really helps bring up + the overall light value in the map. Start low, maybe around an ambient value + of 5 and creep upwards until the map looks right. It is VERY IMPORTANT that + you give your ambient light a color. If you leave it white, you get ugly pink + light instead of white. Even specifying white makes it look wrong. Best + suggestion is to sample the sky texture color and translate that into an rgb + formula for your ambient. One warning + though … if you include “interior spaces” in your maps, the ambient + light will affect those areas too. You will not get the deep dark shadows you + may want in there. +

+ +

· Sky Shader Trick #1: Lose the + Backsplash. The attributes of the sky + shader can have a significant effect on the amount of time it takes to perform + a light compile on a map. You have to think of the sky as a huge area light. + However, unlike light emitting textures (like your average light fixture), the + sky doesn’t need to be illuminated itself. Therefore, you can eliminate the + backsplash light feature which is the default status of the q3map_surfacelight + parameter. Your sky shader should have the parameter q3map_backsplash with a + value of -1. Removing backsplash light doesn’t affect the appearance of the + sky, but does remove a significant amount of compiling overhead when the + -light algorithm is used (the normal way you light things).

+ +

· Sky Shader Trick#2: Big + Subdivisions. Q3Map automatically + subdivides the sky into triangle quads. The more triangle quads, the more + light emitting surfaces you have on your sky (if q3map_surfacelight is used). + The light compile calculates for every one of these light emitting surfaces. + Increase the size of the subdivision and you get less light emitters and a + faster compile.

+ +

· Sky Shader Trick #3: -V-light. + This is a fast lighting algorithm. It’s especially fast for calculating sky + lighting. It loses a little precision, but it can greatly speed up the time it + takes to light a map. Even if you decide to use a normal light operation for + your final map, using -vlight for interim compiles can mean a lot less time + spent waiting on the compiler to see your results.

+ +

 

+
+
+ +

The Light Grid

+
+

      This is discussed in detail under terrain-related Worldspawn features. One of +the things that can add enough memory complexity to a large terrain map, enough +to make it unplayable (read crash the game), is the light grid. Think of the +light grid as a map for determining how to light entities in the world. It’s +what makes player models appear to move in and out of shadows as they move +through the world. It’s a nice effect, but costly in memory terms. For the +largest maps in Q3:TA, we “traded down” to a less detailed light grid. +Increasing the size of grid subdivisions from 32 units to 256 units did this. We +experimented with smaller and larger grids and settled on 256 x 256 x 256 as the +best size. Smaller and the grid became large and unwieldy. Larger (especially on +the z dimension) and not enough light reached some of the entities.

+

      The details of this feature are noted below under Terrain-Related WorldSpawn +Features.

+
+ +

Back - Table +of Contents - Terrain +Worldspawn Features

+ +

 

+
+
+

 

+

 

+

-22-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/manipulating_the_terrain_mesh.html b/docs/manual/quake3/Terrain_Manual/pages/manipulating_the_terrain_mesh.html new file mode 100644 index 00000000..2d154ca7 --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/manipulating_the_terrain_mesh.html @@ -0,0 +1,42 @@ + + + + + + +Manipulating the Terrain Mesh + + + + + +

Manipulating the Terrain Mesh

+
+ + + + +
+

      Once the terrain mesh has been generated, it’s very likely that you will +want to fine-tune the triangles inside the editor. Do this by pulling vertexes +up and down along the Z axis. Once you start fine-tuning in this manner, the +height map no longer exactly represents the map.

+ +

WARNING: If you revise and convert the height map, your manipulations +here are lost.

+
+ +

Back - Table +of Contents - Terrain Mesh +into Terrain Entity

+ +

 

+
+
+

 

+

 

+

-12-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/mapping_the_textures.html b/docs/manual/quake3/Terrain_Manual/pages/mapping_the_textures.html new file mode 100644 index 00000000..d44b8e61 --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/mapping_the_textures.html @@ -0,0 +1,71 @@ + + + + + + +Mapping the Textures + + + + + +

Mapping the Textures

+
+ + + + +
+

      The key to making this stuff look good is the q3map routine that works with +alphamap and the metashader (see below) to smoothly blends textures across the +terrain entity.

+
+

Texturing Overview

+
+

      As noted earlier, Q3Map assigns textures, or more correctly, shader +manipulated textures, to each triangle used to create the terrain map. The +shaders used are part of a group of shaders called a metashader. The metashader +is the family name for the shader. Individidual shaders within it are identified +by a suffix, either an underline character followed by a number, or an underline +character followed by a string indicating a blend between two other shaders.

+

      Within the body of the metashader, there are two types of shaders used. The +first, is the root shader. A root shader represents a terrain texture in +its unblended state. The naming convention for a root shader is <metashader>_#. +The second type is the blended shader. The blended shader creates a +crossfade between two root shaders across the face of a single geometry +triangle. The naming convention for a blended shader is <metashader>_#to#. +The map maker does not need to make a blend between each root shader, but for a +blend to occur, there must be a blend shader for the two root shaders.

+

      Q3map will map a shader (root or blended) once and only once across the face +of the triangle. The shaders will not tile or repeat across the triangle face.

+

      As noted earlier, the textures are planar mapped or projected on the surface +of terrain texture. The angle of any individual triangle does not affect the +angle or direction at which the texture lies on the brush surface. The angle, +however, does affect the apparent stretching of the texture on the surface. The +steeper the angle of the brush surface, the greater will be the stretch of the +shader on that surface.

+

      Q3map looks at the pixel on the alphamap that corresponds to a given vertex. +It uses the color of that pixel (or more correctly the identification number of +the position that color occupies in the palette) to determine which root shader +will be applied. That root shader is applied to triangles that have one vertex +located at the given vertex. It then examines the alphamap color of the vertexes +adjacent to the given vertex. If an adjacent vertex has the same color as the +given vertex, the root shader is applied to the surface. If an adjacent vertex +has a different alphamap color, the blended shader that crossfades between the +two.

+
+ +

Back - Table +of Contents - The Meta-Shader

+ +

 

+
+
+

 

+

 

+

-20-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/new_or_revised_q3map_shader_comm.html b/docs/manual/quake3/Terrain_Manual/pages/new_or_revised_q3map_shader_comm.html new file mode 100644 index 00000000..48fe65a2 --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/new_or_revised_q3map_shader_comm.html @@ -0,0 +1,361 @@ + + + + + + +New or Revised Q3map Shader Commands + + + + + +

New or Revised Q3map Shader Commands

+
+
+ + + + +
+

q3map command line switches:

+
+q3map
+-----
+
+-threads 
+	Number of threads used to compile the map. For the fastest compile
+	times the number of threads is set to the number of system processors.
+-glview
+	Write a .gl file of the bsp tree for debugging.
+-v
+	Output verbose information.
+-draw
+	Enable realtime debug drawing output.
+-nowater
+	Water, slime and lava brushes are not compiled and won't show up when running the map in Quake.
+-noopt
+	unused.
+-nofill
+	unused.
+-nodetail
+	Detail brushes are not compiled and won't show up when running the map in Quake.
+-fulldetail
+	Detail brushes will be treated as normal brushes.
+-onlyents
+	Only change the entities in a .bsp using a .ent file.
+-onlytextures
+	Only change the textures in a .bsp file.
+-micro
+	unused.
+-nofog
+	Visible surfaces that cross fog boundaries will not be split along the bound.
+	This can cause visually incorrect fog in the map.
+-nosubdivide
+	Visible surfaces are not subdivided as required by shader tesselation.
+	The shader parameter "tesssize" sets the tesselation of a surface.
+-leaktest
+	Only test the map for leaks. If a leak is found the compilation is stopped.
+-verboseentities
+	Output verbose information about entity sub-models.
+-nocurves
+	Curves are not compiled and won't show up when running the map in Quake.
+-notjunc
+	T-junctions are not fixed. This can cause tiny slits where a surface meets halfway another surface.
+-expand
+	Expands all the brush planes and saves a new map out to allow visual inspection of the clipping bevels
+-tmpout
+	Output files to a folder called "tmp".
+-fakemap
+	Write out a fakemap.map This map will contain a worldspawn entity with all the world brushes.
+-samplesize 
+	Set the lightmap pixel size to NxN units. Default 16x16.
+-custinfoparms
+	Will enable custom surface flags (see below)
+
+q3map -vis
+----------
+
+-threads 
+	Number of threads used to compile the map. For the fastest compile
+	times the number of threads is set to the number of system processors.
+-fast
+	Only calculate a very loose visiblity list. It doesn't take much time to
+	calculate but a lot more polygons will be drawn by the Q3 engine than necesary.
+-merge
+	Merge bsp leaves before calculating the visibility list. This will speed up
+	the vis calculations but mostly more polygons will be drawn by the Q3 engine
+	than necesary.
+-nopassage
+	Disable the passage visibility algorithm. The passage vis is faster and a bit more
+	tight than the old algorithm.
+-level
+	unused.
+-v
+	Output verbose information.
+-nosort
+	Don't sort the portals on complexity. Sorting mostly speeds up visibility calculations
+	because more complex portals can use information from less complex portals.
+-saveprt
+	Don't delete the .prt file after creating the visibility list.
+-tmpin 
+	Input files will be read from a folder called "tmp".
+-tmpout 
+	Output files will be written to a folder called "tmp".
+
+
+q3map -light
+------------
+
+-threads 
+	Number of threads used to compile the map. For the fastest compile
+	times the number of threads is set to the number of system processors.
+-area 
+	This scales the light intensity of area lights.
+-point 
+	This scales the light intensity of point lights.
+-notrace
+	No light tracing is performed. As a result no shadows will be casted.
+-patchshadows
+	Enable patches casting shadows.
+-novertex
+	Don't calculate vertex lighting.
+-nogrid
+	Don't calculate light grid for dynamic model lighting.
+-extra
+	Take four samples per lightmap pixel and store the average light value of these
+	four samples for the actual lightmap pixel.
+	This super sampling is used for anti-aliasing.
+-extrawide
+	Just like -extra four samples per lightmap pixel are calculated. However the
+	average of 12 samples is stored per lightmap pixel.
+-samplesize 
+	Set the lightmap pixel size to NxN units. Default 16x16.
+-border
+	Create a debugging border around the lightmap.
+-v
+	Output verbose information.
+-nosurf
+	unused.
+-dump
+	unused.
+
+
+q3map -vlight
+-------------
+
+-threads 
+	Number of threads used to compile the map. For the fastest compile
+	times the number of threads is set to the number of system processors.
+-area 
+	This scales the light intensity of area lights.
+-point 
+	This scales the light intensity of point lights.
+-novertex
+	Don't calculate vertex lighting.
+-nogrid
+	Don't calculate light grid for dynamic model lighting.
+-nostitching
+	No polygon stitching before lighting.
+-noalphashading
+	Don't use alpha shading at all.
+-nocolorshading
+	Don't use colored alpha shading. The alpha channel will be used as if it were binary.
+	The light goes through or not and does not change color.
+-tracelight
+	Use the "-light" light algorithm for all surface unless a surface
+	uses a shader with the shader option "q3map_vlight".
+-samplesize 
+	Set the lightmap pixel size to NxN units. Default 16x16.
+-v
+	Output verbose information.
+
+

The q3map options are a subset of the shader instructions that require +recompiling of the map.

+

q3map_tracelight

+

      [NEW] Surfaces using a shader with this option will always be lit with the +original "-light" light algorithm. Patches will not cast shadows on +this surface unless the shader option q3map_patchshadows is used.

+

q3map_patchshadows

+

      [NEW] When this option is used in conjunction with the original (-light) +lighting algorithm, surfaces with textures modified by this option will will +show shadows cast by curve patches (under normal circumstances, curve patches do +not cast shadows).

+

q3map_vertexshadows

+

      [NEW] By default, no shadows are cast on vertex-only lit surfaces (see +surfaceparm pointlight). Also when running Quake III Arena in vertex  lighting +mode, no shadows are cast upon any surfaces (shadows are part of the light map). +When using this shader option shadows *will* be cast on the surface when vertex +lit. However sharp shadow edges won't be seen on the surface because light +values are only calculated at the vertexes.

+

q3map_novertexshadows

+

      [NEW] Shaders used for misc_models and terrain can now use +q3map_novertexshadows to disable shadows to be cast at the vertex lit surfaces. +Shadows being cast at small misc_model objects often makes sense. However +shadows on large vertex lit terrain surfaces often look bad. By default no +shadows are cast at forced vertex list surfaces ( shaders with "pointlight" +).

+

q3map_forcesunlight

+

      [NEW] No sunlight is cast at vertex lit md3 models and terrain by default. +Using this option sunlight (overbright bits created by q3map_sun option) will be +cast on these surfaces.

+

q3map_vertexscale <scale>

+

      [NEW] The light value at the vertexes of a surface using a shader with this +option is multiplied by the scale value. This is a way to lighten or darken a +vertex light only surface in comparison to other, light-map lit surfaces around +it.

+

q3map_notjunc

+

      [NEW] Surfaces modified by a shader with this option are not used for +tjunction fixing.

+

q3map_vlight

+

      [NEW] Surfaces modified by a shader with this option will always be lit with +the "-vlight" algorithm when q3map is used with the options "-vlight +-tracelight".

+

q3map_lightmapsamplesize <S>

+

      [NEW] Surfaces using a shader with this shader option will use lightmaps with +pixel size SxS. This option can be used to produce high resolution shadows on +certain surfaces or can be used to reduce the size of lightmap data where high +resolution shadows are not required.

+

q3map_lightimage <image>

+

      Image to use for the light color of a surface light instead of the image(s) +used by the shader. Color is averaged from the texture. Texture must be the same +size as the base image map.

+

q3map_surfacelight <value>

+

Sets the amount of light this surface emits.

+

q3map_lightsubdivide <value>

+

      A surface light is subdivided into a bunch of point lights for the actual +lighting of the world. This parameter controls the space between those point +lights. Default value is 120.

+

q3map_backsplash <percent> <distance>

+

      A surface light is also lit by itself using back splash point lights with a +lower intensity. The <percent> parameter specifies the intensity +percentage they use from the q3map_surfacelight <value> parameter. The +<distance> parameter controls the distance of these back splash lights +from the surface. You can set the <percent> to zero or a negative value to +disable the back splash lights.

+

      q3map_globaltexture

+

When this option is set the texture is not aligned to the world.

+

      q3map_backshader <shader>

+

<shader> is the path/name of the shader or texture to be used at the +back side of the surface.

+

      q3map_flare <shader>

+

Creates a flare using the specified <shader> at the center of the +surface using a shader with this option.

+

      light <value>

+

Old style flare specification always using the shader "flareshader". +The <value> parameter is unused.

+

      q3map_sun <red> <green> <blue> <intensity> +<degrees> <elevation>

+

Color will be normalized, so it doesn't matter what range you use. The +intensity falls off with angle but not distance. A value of 100 is a fairly +bright sun.

+

      degree of 0 = from the east, 90 = north, etc.

+

      elevation of 0 = sunrise/set, 90 = noon

+

      surfaceparm pointlight

+

Surfaces using a shader with this parameter will always be vertex lit

+

This option can be used to reduce the lightmap data. Often used on surfaces

+

that don't need any shadows.

+

Surfaceparm dust

+

If a player lands (jumps onto) on a surfaces using a shader with this +parameter, a put of dust will appear at the player’s feet. Note that the +worldspawn entity of that map must have an enableDust key set to a value of 1.

+ + +

Custom surfaceparms

+
+

With the new q3map tool you can add custom surface parameters for mods +without the need to recompile the q3map tool. These custom surfaceparms are +stored in a file called ‘custinfoparms.txt’ in the folder scripts/. An +example of this file with the new surfaceparm treacle and surfaceparm grass is +shown below.

+

// Custom Infoparms File
+// Custom Contentsflags
+{
+treacle 0x4000
+}
+// Custom Surfaceflags
+{
+grass 0x80000
+}

+

 

+ +

NOTE: For linux users, when using the -custinfoparms parameter q3map +first looks in your homedir, and only if it doesn't find a custinfoparms.txt +there, it uses the one stored in the

+

quake3 install dir (usually /usr/local/games).

+

 

+
+

Content Flags

+
+

Contents flags are flags similar to CONTENTS_FOG in the original Q3A. These +flags define the contents of volumes inside the game (for instance lava, fog, +water, etc.).

+

If you look in the source file game/surfaceflags.h, it has defines for all +contents flags. The define is split into a name and a hexadecimal value, for +instance CONTENTS_PLAYERCLIP 0x10000. These hexadecimal values are powers of 2 +and can be ored together (binary) to form a bit mask. Up to 32 contents flags +can be ored together this way.

+ +

Example: creating a volume with treacle.

+

The following outlines how a custom contents flag can be added and used in a +mod. First open the ‘custinfoparms.txt’ file and add ‘treacle 0x4000’ +to the Custom Contentsflags section as shown in the example file above (0x4000 +is one of the unused values available for custom use). Next write a shader +script which uses ‘surfaceparm treacle’. Apply this new shader to all sides +of a brush in a test map. When you compile the map, add the -custinfoparms +parameter to the command line following q3map.

+

Next, add CONTENTS_TREACLE 0x4000 to the source file game/surfaceflags.h in +your mod. Now you can call the point contents function. If the point is inside +the brush with the shader using the ‘surfaceparm treacle’ then the point +contents call will return a bit mask with CONTENTS_TREACLE set. This can for +instance be used to slow down player movement when a player is inside such a +brush.

+

 

+
+

Surface Flags

+
+

The surface flags are texture properties that often affect entities in +contact with surfaces using such flags. The ‘surfaceparm metalsteps’ +parameter from Q3A is a good example.

+

If you look in the source file game/surfaceflags.h, it has defines for all +surface flags. The define is split into a name and a hexadecimal value, for +instance SURF_NODAMAGE 0x1. These hexadecimal values are powers of 2 and can be +ored together (binary) to form a bit mask. Up to 32 surface flags can be ored +together this way.

+ +

Example: Making ‘footsteps on grass’ sounds

+

The following outlines how a custom surface flag can be added and used in a +mod. First open up the ‘custinfoparms.txt’ file and add 'grass 0x80000' to +the Custom Surfaceflags section as shown in the example file above (0x80000 is +the first available unused value in surfaceflags.h for surface flags). Next +write a shader script which uses a grass image and has 'surfaceparm grass’. +Create a test map with the grass shader covering the ground surface. When you +compile the map, add the -custinfoparms parameter to the command line following +q3map.

+

Next, add SURF_GRASS 0x80000 to the source file game/surfaceflags.h in your +mod. Now you'll be able to execute a trace and the trace information will be +returned in the trace_t structure. If the trace hits a surface with the grass +surfaceparm then the SURF_GRASS flag will be set in trace_t->surfaceFlags. +Such a trace can be used to trigger playing a sound of a person stepping on +grass. For a reference example, see the existing metal steps in the game code.

+

 

+
+

 

+ +
+ +

Back - Table +of Contents - Links

+ + + +

 

+
+
+

 

+

 

+

-27-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/other_possible_height_map_tools.html b/docs/manual/quake3/Terrain_Manual/pages/other_possible_height_map_tools.html new file mode 100644 index 00000000..3265cd71 --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/other_possible_height_map_tools.html @@ -0,0 +1,62 @@ + + + + + + +Other Possible Height Map Tools + + + + + +

Other Possible Height Map Tools

+
+ + + + +
+

      There are even some editors for other (non-fps) games that can be used to +manipulate a surface in 3D and then output a .bmp format file. It is worth +noting that we found it particularly challenging to use them … possibly more +challenging than the benefits of working in 3D.

+ +

SC3K Map Editor

+
+

      The first of these programs was a terrain editor for SimCity3000 called the +SC3K Map Editor from Tenermerx. It is a free download available here: sc3maped

+ +

Loathing

+
+

      The other editor we tried was the “Loathing” terrain editor that comes +with Bungie’s Myth II game. If you’ve a copy of Myth II, this is something +you could play around with. Both of these programs could output a .bmp format +file. If you’ve used it to make some Myth II maps you may have some idea of +how it works already. It is my opinion that if you use an editor for either of +these two games to create your height map, you may still want to or need to +manipulate it in an art program. If you can visualize the relationship between +shades of gray and relative heights and slopes, the art program is probably the +easier way to go.

+ +

Pencils, paintbrushes and a scanner

+
+

      You can also make your heightmap by painting it by traditional methods and +then scanning in the file and saving it as a .bmp. Though at some point you’ll +probably want to switch over to digital manipulation.

+
+ +

 

+

Back - Table +of Contents - Height Map into +Terrain

+ +

 

+
+
+

 

+

-9-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/related_links.html b/docs/manual/quake3/Terrain_Manual/pages/related_links.html new file mode 100644 index 00000000..8a23b51d --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/related_links.html @@ -0,0 +1,40 @@ + + + + + + + +Related Links + + + + +

Related Links

+ +

 

+

 

+

-28-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/suggested_gensurf_settings.html b/docs/manual/quake3/Terrain_Manual/pages/suggested_gensurf_settings.html new file mode 100644 index 00000000..9c81114c --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/suggested_gensurf_settings.html @@ -0,0 +1,135 @@ + + + + + + +Suggested GenSurf settings + + + + + +

Suggested GenSurf settings (by Tab)

+
+ + + + +
+ + +

The General TAB:

+
+
+
+ +

· Select Quake 3 Arena under Game.

+ +

· Select From Bitmap under Waveform. Of course, you may want to + play around with some of the other wave forms. But bitmaps give you the + greatest degree of control.

+ +

· Orientation: as appropriate

+ +

· If you don’t want GenSurf to add any “noise” or + randomization to the height of the mesh, set the Roughness to zero. The + preview window gives you a good representation of what roughness does to + your surface. The random seed changes the distribution of the noise. Adjust + both fields accordingly.

+
+
+ +

The Extents TAB:

+

Extents: The extents of a map are the points on a map that define its +lowermost t and leftmost corner and its uppermost and rightmost corner. They are +given in terms of  X, Y coordinates.

+
+
+ +

· Under Extents, you should chose number values that are even + multiples of your number of Divisions so that the grid rectangles are all + the same size (this produces better texturing results). It also makes extra + work for the compiler. Furthermore, use the Extents to position the terrain + entity on the map (XY only). You will want to make sure that the terrain + locates exactly where you want it each time you revise it. Repositioning a + terrain file can be time consuming.

+ +

· Set your X and Y divisions to equal the number of rows and + columns of triangles you want. You may want to strongly consider playing + with the numbers so that your triangle sides end up be large powers of two + (64, 128, 256 units etc.).

+ +

· Do not check Use Bezier Patches.

+ +

· Do not Decimate (keep it set to 0%). The process that applies + textures to the surfaces and blends textures between vertexes works best if + the size of the triangles is consistent and constant.

+
+
+ +

The Bitmap TAB:

+
+
+ +

· Filename should point to the .bmp file you are using as a height + map. Reload will bring in any changes you have made to the art file without + having to restart the program.

+ +

· GenSurf assigns an integer value to each of 256 shades of gray. + The value is based on the position of the color in the palette. In a grayscale + palette, the values typically range from 0 (black) to 255 (white). Map Color 0 + corresponds (usually) to the lowest point on the height map and Map Color 255 + to the highest. If you set Map Color 0 to 0 and Map Color 255 to 2048, each + increase in color value adds 8 units to the height of the vertex. When you + increase the difference between to the two values, the height changes are + steeper. Decrease the difference and the height changes are more global. You + can control the “Z” location at which the terrain draws by adding any + extra height above (or below) zero to the height values for both numbers.

+
+
+ +

The Fix Points TAB:

+
+

The general recommendation for this TAB is to leave it alone. You should +either modify the height map or directly manipulate vertexes inside the +Q3Radiant editor.

+ +

Texture TAB:

+
+
+ +

· Set the main texture to common/terrain. The “Steep” angle is + irrelevant for terrain texture mapping.

+ +

· Make sure that the Use detail brushes setting is checked.

+
+
+

Once you’ve tweaked all your settings, do a Save as. If you make changes to +the settings, consider saving again as a new file. It’s nice to have a back up +if you screw things up.

+ +

GenSurf Tips

+
+
+ +

· Setting extents to correspond exactly with the desired map + location is important. You want to be able to drop revised terrain into a map + without a lot of repositioning.

+
+
+ +

Back - Table +of Contents - Manipulating the +Terrain Mesh

+ +

 

+
+
+ +

 

+

-11-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/table_of_contents.html b/docs/manual/quake3/Terrain_Manual/pages/table_of_contents.html new file mode 100644 index 00000000..82d36038 --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/table_of_contents.html @@ -0,0 +1,88 @@ + + + + + + + +Table of Contents + + + + +

Table of Contents
+
(HTML Conversion by AstroCreep)
+

+
+ + + + + +
+

Title Page............1
+Table of Contents............2

+
+
Introduction + ...........3
+Key Changes that have been made............4
+Art Tools Required
............5
+ +The Terrain Entity............6
+ +Creating the Terrain “Mesh”............7
+ +Height Maps............8
+ +Other Possible Height Map Tools............9
+ +Height Map into Terrain Mesh..........10
+ +Suggested GenSurf settings (by Tab)..........11
+ +Manipulating the Terrain Mesh..........12
+ +Terrain Mesh into Terrain Entity..........13
+ +Boxing in the World..........14
+ +Entity Keys and Values..........15
+ +Creating the Alphamap..........16
+ +The Terrain Texture..........17
+ +Blocking Vis..........18
+ +Clipping the terrain..........19
+ +Mapping the Textures..........20
+ +The Meta-Shader..........21
+ +Lighting the Terrain..........22
+ +Terrain Related Worldspawn Features..........23
+ +Adding Buildings to Terrai
n..........24
+ +Adding Bots..........25
+Glossary..........26
+ +New or Revised Q3Map Shader Commands..........27
+
+ +Related Links..........28

+
+

+
+ +

 

+

Back - Table +of Contents- Introduction

+ +

-2-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/terrain_entity.html b/docs/manual/quake3/Terrain_Manual/pages/terrain_entity.html new file mode 100644 index 00000000..b5e87f9c --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/terrain_entity.html @@ -0,0 +1,50 @@ + + + + + + +The Terrain Entity + + + + + +

The Terrain Entity

+
+ + + + +
+

      The process of building a piece of terrain focuses on a new thing called the +“Terrain Entity.” Technically speaking, the terrain in Team Arena is nothing +more than a func_group entity (brushes only) with a number of key/value pair +combinations that are unique to it. These key/value pairs define it as terrain (terrain), establish the piece of art that will be used to locate textures on it +the terrain (alphamap), define the group of shaders used to blend textures +across its surface (shader), and tell how many different unique shaders will be +used. The bsp-making utility, Q3Map compiles and textures the terrain entity +based on the parameters specified in those key/value pairs.

+

      It is possible to have multiple terrain entities in a map (see Terrain +Entities below). Once you learn the method and the techniques, terrain is +relatively easy to create. One warning though … easy to create does not mean +easy to compile. Large maps take a much longer time to compile, and huge maps +are likely to take what seems like forever. However, there are some +construction, lighting, and shader options that can significantly cut down on +compile time - as will be noted later.

+
+ +

Back - Table +of Contents - Creating the terrain +"Mesh"

+ +

 

+
+
+

 

+

 

+

-6-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/terrain_mesh_into_terrain_entity.html b/docs/manual/quake3/Terrain_Manual/pages/terrain_mesh_into_terrain_entity.html new file mode 100644 index 00000000..70c0e139 --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/terrain_mesh_into_terrain_entity.html @@ -0,0 +1,44 @@ + + + + + + +Terrain Mesh into Terrain Entity + + + + + +

Terrain Mesh into Terrain Entity

+
+ + + + +
+

      GenSurf outputs its terrain as a func_group entity. If you create a terrain +mesh by any other means, you need to group it as a func_group entity.

+

      Make certain that all the non-visible surfaces of the func_group brushes are +textured with common/caulk.

+

      Texture the visible surfaces with common/terrain or common/terrain2.

+

      Select the func_group and turn it to detail content (CTRL M) or use the +Selection menu.

+

      It is possible to map terrain onto something that is not a “terrain” +mesh. Keep in mind that textures will be planar projected onto all surfaces in +the terrain entity and that brush vertexes will be used to determine where +blends start and end.

+
+ +

Back - Table +of Contents - Boxing in the World

+ +

 

+
+
+

 

+

-13-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/terrain_related_worldspawn_features.html b/docs/manual/quake3/Terrain_Manual/pages/terrain_related_worldspawn_features.html new file mode 100644 index 00000000..3140ea3c --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/terrain_related_worldspawn_features.html @@ -0,0 +1,222 @@ + + + + + + +Terrain + + + + + +

Terrain-related WorldSpawn Features

+
+ + + + +
+

A number of worldspawn key/value pairs were created to deal with issues +arising out of terrain creation.

+
+

Cold Breath and Hot Dust

+
+

+The following two features need not be directly related to terrain, although +they first appear in the Q3:TA maps. Each key/value pair needs to be the +worldspawn for that particular feature to work.

+ +

+Key/value pairs:

+

+Key: + enableBreath

+ +

+Value: + 1

+

+When written into the worldspawn, this enables the appearance of “frosty +breath” in the air in front of players. The frosty break does not appear in a +player’s first person view, but will be seen in front of other players and in +3rd person view.

+ +

+Key/value pair:

+

+Key: + enableDust

+ +

+Value: + 1

+

+When written into the worldspawn, this enables the appearance of dust puffs +at the player’s feet when he lands on or run on a “dusty” surface. Adding +the surface parameter “surfaceparm dust” to the shader for that surface +creates a dusty surface. The common/terrain2 texture already contains the +enableDust parameter.

+ +

Texture Remapping: Shaders for vertex light mode in Q3A

+
+

+One thing we quickly discovered when mapping the metatexture onto the terrain +world was that it didn’t work if a player chose to run in the game’s vertex +lighting only mode. That mode compresses shaders into a single pass. Usually, +the engine makes a reasonable choice for which pass is mapped, but with the +metashaders, that wasn’t the case. The solution: allow the mapper to choose a +substitute texture that only is used in the game’s vertex lighting mode. +

+

+For each shader that will be remapped a key/value pair must be entered in the +map’s worldspawn. +

+ +

+Key: vertexremapshader

+ +

+Value: + + normal_shader;vertexlighting_shader +

+

+The normal_shader is the shader normally used on the terrain. The +vertexlighting_shader is the shader to be used when people run the map in Q3 in +vertex lit mode. The normal_shader and the vertexlighting_shader are seperated +by a semi-colon ; +

+

+As many shaders can be remapped as needed by using the key. However, if more +than one shader is remapped in a map, each one must have a unique identifier … +either a number or a letter after the Key word, as shown by “vertexremapshaderX”, +where X is a number or any character set. Examples, vertexremapshader01, +vertexremapshader02, vertexremapshaderA, vertexremapshaderB, +vertexremapshadermpterra2_1, etc. +

+

+In mpterra2, the key/value pair for one of the replaced shaders looked like +this: +

+ +

+Key: + + vertexremapshader1 +

+ +

+Value: + + textures/terrain/mpterra2_0to1;textures/terrain/vxmpterra2 +

+

+Each of the three root shaders and the two blend shaders had to replaced in +this manner. +

+

+The following is a sample of the shader used to replace ALL the terrain +shaders in mpterra2: +

+ +

// *************************************************

+

// *

+

// * Vertex Lighting Replacement Shaders

+

// *

+

// *************************************************

+

textures/terrain/vxmpterra2

+

{

+

surfaceparm nolightmap

+

q3map_novertexshadows

+

q3map_forcesunlight

+

{

+

map textures/stone/pjrock10b_2.tga

+

rgbGen vertex

+

tcmod scale 0.125 0.125

+

}

+

}

+
+ + +

GridSize

+
+
+
+ +
+ + +

+The Light Grid Size (as noted earlier) is the map that the Q3A engine uses to +light entities. It’s what gives the illusion of players moving in and out of +shadowed areas on the game levels. We decided, that for large terrain maps, it +should not be as detailed (and therefore nowhere near as large) as we had done +for smaller, interior maps. After experimenting with placing controls for the +grid size on the bsp command line, we finally settled on putting the command +information in the map’s world spawn. In that way, the grid size could be +easily tailored to the individual map.

+ + + + +

+Key/value pair: +

+

+Key: + + gridsize +

+ +

+Value: + + X Y Z +

+
+ +
+
+ +
+

+Note that the values are the dimensions of those coordinates. It’s best to +keep them to power of 2 values. The default value for the gridsize (if left +unchanged) is 64 64 128. Setting higher x y and z values reduces the size of the +light grid data in both the .bsp file and in the Q3A game, but it also creates +less accurate dynamic model lighting.

+ +

+Errors

+
+

+Definitely set the x y and z values higher if you get:

+

+************ ERROR ************

+

+MAX_MAP_LIGHTGRID

+

+when compiling your map with q3map.

+ +

Back - Table +of Contents - Adding Buildings

+ + + + + +

 

+ +
+ +
+
+
+

 

+

 

+

-23-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/terrain_texture.html b/docs/manual/quake3/Terrain_Manual/pages/terrain_texture.html new file mode 100644 index 00000000..bb2e81a1 --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/terrain_texture.html @@ -0,0 +1,65 @@ + + + + + + +The Terrain Texture + + + + + +

The Terrain Texture

+
+ + + + +
+

In Q3:TA, there are two “terrain” textures in the common shader script. +One handles all the uses of terrain where the designer does not want “dust” +to rise up as the player jumps onto the terrain (common/terrain). The second +(common/terrain2) has an enable_dust surface parameter. The terrain texture +should be applied to all visible (in game) surfaces of the terrain entity.

+

Q3map looks for the word “terrain” in the name of the shader when +texturing terrain entities. If a shader is used without the word +"terrain" in it, and it’s not marked as nodraw, q3map will still do +a planar projection, but using that texture. It will not blend between textures, +however. This can be used to create hard edge texture transitions, or in cases +where you want to apply textures manually, and aren’t concerned about +blending.

+

If the terrain texture is applied to a non-terrain entity brush, the surface +will not draw. The projected terrain surface textures only work on surfaces that +are a part of entities with the proper terrain entity keys and values.

+

Their scripts for terrain are as follows:

+
+

textures/common/terrain
+{
+surfaceparm nodraw
+surfaceparm nomarks
+surfaceparm nolightmap
+}
+textures/common/terrain2
+{
+qer_editorimage textures/common/terrain.tga
+surfaceparm dust
+surfaceparm nodraw
+surfaceparm nomarks
+surfaceparm nolightmap
+}

+
+ +

Back - Table +of Contents - Blocking Vis

+ +

 

+
+
+

 

+

 

+

-17-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pages/the_meta_shader.html b/docs/manual/quake3/Terrain_Manual/pages/the_meta_shader.html new file mode 100644 index 00000000..b24d7ff9 --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/pages/the_meta_shader.html @@ -0,0 +1,192 @@ + + + + + + +The Meta + + + + + +

The Meta-Shader

+
+ + + + +
+

      The shader is the group or family of related shaders used to texture a +terrain entity. The shader key/value pair in the entity identifies the +metashader to be used. The suffix (either “_#” for a root shader or “#to#” +for a blended shader.

+

      For each root shader that you want to blend, you need a blend shader. Note +that you only need to make the blend once. If you have mpterra2_0to2, you don’t +need mpterra2_2to0.

+

 

+
+

Example Terrain Shader

+
+

      This was the shader used to map textures on mpterra2 (hence the metashader +name)

+
+

//****************************************************
+// *************************************************
+// *
+// * MPTerra2 terrain shaders
+// *
+// *************************************************
+textures/terrain/mpterra2_0
+{
+surfaceparm nolightmap
+q3map_novertexshadows
+q3map_forcesunlight
+{
+map textures/stone/pjrock9b_2.tga
+rgbGen vertex
+tcmod scale 0.125 0.125
+}
+{
+map textures/skies2/clouds.tga
+blendfunc filter
+detail
+tcmod scale 0.01 0.01
+tcMod scroll -0.05 0.05
+tcmod transform 1 0 1 1 1 1
+}
+}
+textures/terrain/mpterra2_1
+{
+surfaceparm nolightmap
+q3map_novertexshadows
+q3map_forcesunlight
+{
+map textures/stone/pjrock12b_2.tga
+rgbGen vertex
+tcmod scale 0.1 0.1
+}
+{
+map textures/skies2/clouds.tga
+blendfunc filter
+detail
+tcmod scale 0.01 0.01
+tcMod scroll -0.05 0.05
+tcmod transform 1 0 1 1 1 1
+}
+}
+textures/terrain/mpterra2_2
+{
+surfaceparm nolightmap
+q3map_novertexshadows
+q3map_forcesunlight
+{
+map textures/stone/pjrock10b_2.tga
+tcmod scale 0.05 0.05
+rgbGen vertex
+}
+{
+map textures/skies2/clouds.tga
+blendfunc filter
+detail
+tcmod scale 0.01 0.01
+tcMod scroll -0.05 0.05
+tcmod transform 1 0 1 1 1 1
+}
+}
+textures/terrain/mpterra2_0to1
+{
+surfaceparm nolightmap
+q3map_novertexshadows
+q3map_forcesunlight
+{
+map textures/stone/pjrock9b_2.tga
+rgbGen vertex
+alphaGen vertex
+tcmod scale 0.125 0.125
+}
+{
+map textures/stone/pjrock12b_2.tga
+tcmod scale 0.1 0.1
+rgbGen vertex
+alphaGen vertex
+blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+}
+{
+map textures/skies2/clouds.tga
+blendfunc filter
+detail
+tcmod scale 0.01 0.01
+tcMod scroll -0.05 0.05
+tcmod transform 1 0 1 1 1 1
+}
+}
+textures/terrain/mpterra2_0to2
+{
+surfaceparm nolightmap
+q3map_novertexshadows
+q3map_forcesunlight
+{
+map textures/stone/pjrock9b_2.tga
+rgbGen vertex
+alphaGen vertex
+tcmod scale 0.125 0.125
+}
+{
+map textures/stone/pjrock10b_2.tga
+rgbGen vertex
+alphaGen vertex
+tcmod scale 0.05 0.05
+blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+}
+{
+map textures/skies2/clouds.tga
+blendfunc filter
+detail
+tcmod scale 0.01 0.01
+tcMod scroll -0.05 0.05
+tcmod transform 1 0 1 1 1 1
+}
+}
+textures/terrain/mpterra2_1to2
+{
+surfaceparm nolightmap
+q3map_novertexshadows
+q3map_forcesunlight
+{
+map textures/stone/pjrock12b_2.tga
+rgbGen vertex
+alphaGen vertex
+tcmod scale 0.1 0.1
+}
+{
+map textures/stone/pjrock10b_2.tga
+tcmod scale 0.05 0.05
+rgbGen vertex
+alphaGen vertex
+blendFunc GL_SRC_ALPHA GL_ONE_MINUS_SRC_ALPHA
+}
+{
+map textures/skies2/clouds.tga
+blendfunc filter
+detail
+tcmod scale 0.01 0.01
+tcMod scroll -0.05 0.05
+tcmod transform 1 0 1 1 1 1
+}
+}

+
+ +

Back - Table +of Contents - Lighting the Terrain

+ +

 

+
+
+

 

+

 

+

-21-

+ + + + diff --git a/docs/manual/quake3/Terrain_Manual/pics/background.jpg b/docs/manual/quake3/Terrain_Manual/pics/background.jpg new file mode 100644 index 00000000..1f1d8d48 Binary files /dev/null and b/docs/manual/quake3/Terrain_Manual/pics/background.jpg differ diff --git a/docs/manual/quake3/Terrain_Manual/pics/start.gif b/docs/manual/quake3/Terrain_Manual/pics/start.gif new file mode 100644 index 00000000..f84e2ffc Binary files /dev/null and b/docs/manual/quake3/Terrain_Manual/pics/start.gif differ diff --git a/docs/manual/quake3/Terrain_Manual/pics/terrain.jpg b/docs/manual/quake3/Terrain_Manual/pics/terrain.jpg new file mode 100644 index 00000000..c550f682 Binary files /dev/null and b/docs/manual/quake3/Terrain_Manual/pics/terrain.jpg differ diff --git a/docs/manual/quake3/Terrain_Manual/start.html b/docs/manual/quake3/Terrain_Manual/start.html new file mode 100644 index 00000000..677bcd35 --- /dev/null +++ b/docs/manual/quake3/Terrain_Manual/start.html @@ -0,0 +1,30 @@ + + + + + + +Terrain Construction for Quake 3 Engine Games + + + + + +

+

  + +Special Thanks to Jim Dosé and Jan Paul van Waveren +for their assistance and review (and making this all work in the first place) +and the same gratitude to Astrocreep for his review and suggestions for making +it into something people could understand.

+

The material here is for use in conjunction with the Q3Radiant manual for the +Quake 3 Engine and presumes familiarity with that tool and game engine. Although +compiling switches and shader commands are included here, this is not intended +to be a general update or revision to the Q3Radiant manual

+

Table of Contents

+ +

-1-

+ + + + diff --git a/gen.readme b/gen.readme new file mode 100644 index 00000000..a12941c5 --- /dev/null +++ b/gen.readme @@ -0,0 +1,4 @@ +Dummy file for gen.dsp + +gen.dsp is used with MSVC to generate include/version.h and include/aboutmsg.h +you need python installed and configured to make this work diff --git a/gen.vcproj b/gen.vcproj new file mode 100644 index 00000000..b7d426ae --- /dev/null +++ b/gen.vcproj @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/gendox b/gendox new file mode 100644 index 00000000..935e052b --- /dev/null +++ b/gendox @@ -0,0 +1,150 @@ +#!/bin/bash +# +# Shell script to make doxygen documentation by specifying a target directory +# on the command line +# +# Gef (gefdavis@dingoblue.net.au) -- August 2001 + +# TODO: +# - Dynamic ChangeLog (page gets updated with each commit) +# - Have the ability to specify server dox or local dox, which will then +# change the content on the main page +# - Incorporate a scaled gtkradiant splash image into the pages + +#------------------------------------------------------------------------ +# Set some variables +#------------------------------------------------------------------------ +# WORKINGDIR=`pwd`; +RETVAL=0; +TARGETSTRING=''; +EXTRAS_PATH="./Doxygen_files"; +CONFIG_OUTPUT="$EXTRAS_PATH/genConf"; +DOXYCONFIG="./DoxyConfig"; +DOXYFILE="$EXTRAS_PATH/Doxyfile"; +NEWDOXYFILE="$EXTRAS_PATH/genDoxyfile"; +declare -a TARGETLIST[$#]; +COUNTER=0; +TARGETCOUNT=0; +QUIETMODE=0; +# added -k command line option to kill running doxygen procs +KILLON=0 + +#------------------------------------------------------------------------ +# load the functions +#------------------------------------------------------------------------ +if [ -f "$EXTRAS_PATH/gendoxfunctions" ] ; then + . $EXTRAS_PATH/gendoxfunctions +else + echo -e "Missing critical files...\n"; + exit 1; +fi + +#------------------------------------------------------------------------ +# parse the command line options +#------------------------------------------------------------------------ +COMLINE="$*"; +OPTCOUNT="$#"; +parse_commandline; +if [ $RETVAL -gt 0 ] ; then + echo -e "Exiting."; + exit $RETVAL; +fi + + +if [ $KILLON -gt 0 ] ; then + PIDOF_DOXYGEN=`pidof -x doxygen` + MYPID=$$ + + if [ -z "$PIDOF_DOXYGEN" ] ; then + [ $QUIETMODE -gt 0 ] || echo -e " * Killing other doxygen pids"; + killall -q -9 doxygen + else + [ $QUIETMODE -gt 0 ] || echo -e " * Killing other doxygen pids"; + kill -9 $PIDOF_DOXYGEN &> /dev/null + fi + + [ $QUIETMODE -gt 0 ] || echo -e " * Cleaning up gendox pids"; + killall -q -9 `pidof -x gendox | sed -e s/$MYPID//` &> /dev/null + +fi + +# If the output dir hasn't been set yet... +#if [ -z "$OUTPUTDIR" ] ; then +# OUTPUTDIR="../$(basename `pwd`)-doxygen"; +#fi + +#------------------------------------------------------------------------ +# execute some functions to determine stuff(c) +# Get the perl path (either from the config file, or find it) +#------------------------------------------------------------------------ +get_perlpath; +if [ X"$PERLPATH" == "X" ] ; then + echo -e "\nError: A working install of perl is needed to use doxygen"; + exit 2; +fi +[ $QUIETMODE -gt 0 ] || echo -e " -> Set PERL_PATH to: $PERLPATH"; + +get_dotpath; +[ $QUIETMODE -gt 0 ] || echo -e " -> Set HAVE_DOT to: $HAVEDOT"; +if [ X"$HAVEDOT" == "XYes" ] ; then + [ $QUIETMODE -gt 0 ] || echo -e " -> Set DOT_PATH to: $DOTPATH"; +fi + +get_language; +[ $QUIETMODE -gt 0 ] || echo -e " -> Set OUTPUT_LANGUAGE to: $OUPUTLANGUAGE"; + +get_projectname; +[ $QUIETMODE -gt 0 ] || echo -e " -> Set PROJECT_NAME to: $PROJECTNAME"; + +get_version; +[ $QUIETMODE -gt 0 ] || echo -e " -> Set PROJECT_NUMBER to: $VERSION"; +#------------------------------------------------------------------------ +# Got everything we need, now write the DoxyConfig file and run doxygen +#------------------------------------------------------------------------ + +# Clean up first +clean_up; + +# Put the images & reference pages in the right place +move_stuff; +if [ $RETVAL -ge 666 ] ; then + exit 666; +fi + +# Generate the config file +gen_doxyconfig; +if [ $RETVAL -gt 0 ] ; then + echo -e "Error: You are missing critical files." + exit RETVAL; +fi + +# build the reference page and the index +build_extra_html; + +# Generate documentation +RETVAL=0; +run_doxygen; +if [ $RETVAL -gt 0 ] ; then + echo -e "Doxygen error: returned $RETVAL"; + echo -e " Check doxygen.log for details"; +elif [ $RETVAL -lt 0 ] ; then + echo -e "Doxygen error: Doxygen returned $RETVAL"; +fi + +# if the log file is empty, remove it +if [ ! -s ./doxygen.log ] ; then + rm -f ./doxygen.log +fi + +#------------------------------------------------------------------------ +# Done. +#------------------------------------------------------------------------ +[ $QUIETMODE -gt 0 ] || echo -e "Finished..."; +[ $QUIETMODE -gt 0 ] || echo -e "Duration: $SECONDS seconds\n"; + +# echo -e "** Removing output while in debug mode **"; +# echo -e "** Output dir: $OUTPUTDIR **\n"; +# rm -rf $OUTPUTDIR + +exit 0; + diff --git a/include/.cvsignore b/include/.cvsignore new file mode 100644 index 00000000..36594088 --- /dev/null +++ b/include/.cvsignore @@ -0,0 +1,8 @@ +version +version.h +version.new +aboutmsg +aboutmsg.h +aboutmsg.new +RADIANT_MAJOR +RADIANT_MINOR diff --git a/include/aboutmsg.default b/include/aboutmsg.default new file mode 100644 index 00000000..2f135e2e --- /dev/null +++ b/include/aboutmsg.default @@ -0,0 +1 @@ +Custom build by Average Joe diff --git a/include/aboutmsg.h b/include/aboutmsg.h new file mode 100644 index 00000000..213fe347 --- /dev/null +++ b/include/aboutmsg.h @@ -0,0 +1,2 @@ +// generated header, see makeversion.py +#define RADIANT_ABOUTMSG "ZeroRadiant build" diff --git a/include/gtkr_list.h b/include/gtkr_list.h new file mode 100644 index 00000000..64ac1710 --- /dev/null +++ b/include/gtkr_list.h @@ -0,0 +1,23 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "stl_check.h" diff --git a/include/gtkr_vector.h b/include/gtkr_vector.h new file mode 100644 index 00000000..3964be67 --- /dev/null +++ b/include/gtkr_vector.h @@ -0,0 +1,23 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include "stl_check.h" diff --git a/include/ibrush.h b/include/ibrush.h new file mode 100644 index 00000000..47eb7a81 --- /dev/null +++ b/include/ibrush.h @@ -0,0 +1,73 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _IBRUSH_H_ +#define _IBRUSH_H_ + +// +// API for brush stuff +// + +#define BRUSH_MAJOR "brush" +// {c1c3f567-2541-4aa3-9d5b-031fbe2a013b} +static const GUID QERBrushTable_GUID = +{ 0xc1c3f567, 0x2541, 0x4aa3, { 0x9d, 0x5b, 0x03, 0x1f, 0xbe, 0x2a, 0x01, 0x3b } }; + +typedef void (* PFN_BRUSHADDTOLIST) (brush_t *b, brush_t *lst); +typedef void (* PFN_BRUSHBUILD) (brush_t *b, bool bSnap, bool bMarkMap, bool bConvert, bool bFilterTest); +typedef brush_t* (* PFN_BRUSHCREATE) (vec3_t mins, vec3_t maxs, texdef_t *texdef); +typedef void (* PFN_BRUSHFREE) (brush_t *b, bool bRemoveNode); +typedef void (* PFN_BRUSHROTATE) (brush_t *b, vec3_t vAngle, vec3_t vOrigin, bool bBuild); +typedef brush_t* (* PFN_BRUSHALLOC) (); +typedef int (* PFN_BPMESSAGEBOX) (int); +typedef face_t* (* PFN_FACEALLOC) (void); +typedef eclass_t* (* PFN_HASMODEL) (brush_t *b); + +struct _QERBrushTable +{ + int m_nSize; + PFN_BRUSHADDTOLIST m_pfnBrush_AddToList; + PFN_BRUSHBUILD m_pfnBrush_Build; + PFN_BRUSHCREATE m_pfnBrush_Create; + PFN_BRUSHFREE m_pfnBrush_Free; + PFN_BRUSHROTATE m_pfnBrush_Rotate; + PFN_BRUSHALLOC m_pfnBrushAlloc; + PFN_BPMESSAGEBOX m_pfnBP_MessageBox; + PFN_FACEALLOC m_pfnFace_Alloc; + PFN_HASMODEL m_pfnHasModel; +}; + +#ifdef USE_BRUSHTABLE_DEFINE +#ifndef __BRUSHTABLENAME +#define __BRUSHTABLENAME g_BrushTable +#endif +#define Brush_AddToList __BRUSHTABLENAME.m_pfnBrush_AddToList +#define Brush_Build __BRUSHTABLENAME.m_pfnBrush_Build +#define Brush_Create __BRUSHTABLENAME.m_pfnBrush_Create +#define Brush_Free __BRUSHTABLENAME.m_pfnBrush_Free +#define Brush_Rotate __BRUSHTABLENAME.m_pfnBrush_Rotate +#define Brush_Alloc __BRUSHTABLENAME.m_pfnBrushAlloc +#define BP_MessageBox __BRUSHTABLENAME.m_pfnBP_MessageBox +#define Face_Alloc __BRUSHTABLENAME.m_pfnFace_Alloc +#define HasModel __BRUSHTABLENAME.m_pfnHasModel +#endif + +#endif diff --git a/include/ibspfrontend.h b/include/ibspfrontend.h new file mode 100644 index 00000000..c00217fb --- /dev/null +++ b/include/ibspfrontend.h @@ -0,0 +1,77 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// interface for BSP frontends plugins +// + +// DONE: - change BSP menu to Q3Build menu ? +// DONE: - detect when Q3Build dies ? +// DELAYED: - hotkeys ! +// SUCCESS: - try again getting feedback from Q3Build + +#ifndef __IBSPFRONTEND_H_ +#define __IBSPFRONTEND_H_ + +// define a GUID for this interface so plugins can access and reference it +// {8ED6A480-BA5E-11d3-A3E3-0004AC96D4C3} +static const GUID QERPlugBSPFrontendTable_GUID = +{ 0x8ed6a480, 0xba5e, 0x11d3, { 0xa3, 0xe3, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; + +// ask the plugin about the items to show up in the BSP menu +typedef char * (WINAPI* PFN_GETBSPMENU) (); +// dispatch a BSP menu command +typedef void (WINAPI* PFN_DISPATCHBSPCOMMAND) (char *); +// this one gets called after a monitoring loop ends +// 0: all good +// 1: timed out / Radiant didn't get the connection +// 2: got a connection, compilation ended with an error +typedef void (WINAPI* PFN_ENDLISTEN) (int status); + +struct _QERPlugBSPFrontendTable +{ + int m_nSize; + PFN_GETBSPMENU m_pfnGetBSPMenu; + PFN_DISPATCHBSPCOMMAND m_pfnDispatchBSPCommand; + PFN_ENDLISTEN m_pfnEndListen; +}; + +// interface provided by Radiant to the plugin +// {A2CCF366-BA60-11d3-A3E3-0004AC96D4C3} +static const GUID QERAppBSPFrontendTable_GUID = +{ 0xa2ccf366, 0xba60, 0x11d3, { 0xa3, 0xe3, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; + +typedef char * (WINAPI* PFN_GETMAPNAME) (); +typedef void (WINAPI* PFN_LISTEN) (); +typedef void (WINAPI* PFN_SLEEP) (); + +struct _QERAppBSPFrontendTable +{ + int m_nSize; + PFN_GETMAPNAME m_pfnGetMapName; + PFN_LISTEN m_pfnListen; + PFN_SLEEP m_pfnSleep; + //++timo TODO: needs a hook to reset the debug window (in regular mode it's done at startup of the BSP operation) +}; + +#endif diff --git a/include/icamera.h b/include/icamera.h new file mode 100644 index 00000000..22faf0fe --- /dev/null +++ b/include/icamera.h @@ -0,0 +1,45 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// camera interface +// + +#ifndef __ICAMERA_H_ +#define __ICAMERA_H_ + +#define CAMERA_MAJOR "camera" + +typedef void (* PFN_GETCAMERA) ( vec3_t origin, vec3_t angles ); +typedef void (* PFN_SETCAMERA) ( vec3_t origin, vec3_t angles ); +typedef void (* PFN_GETCAMWINDOWEXTENTS) ( int *x, int *y, int *width, int *height ); + +struct _QERCameraTable +{ + int m_nSize; + PFN_GETCAMERA m_pfnGetCamera; + PFN_SETCAMERA m_pfnSetCamera; + PFN_GETCAMWINDOWEXTENTS m_pfnGetCamWindowExtents; +}; + +#endif diff --git a/include/idata.h b/include/idata.h new file mode 100644 index 00000000..eb39cfa9 --- /dev/null +++ b/include/idata.h @@ -0,0 +1,57 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// interface table to access low-level data inside Radiant (brushes, patches and generic editing primitives) + +#ifndef __IDATA_H_ +#define __IDATA_H_ + +// FIXME TTimo this should probably go away and be replaced by a more flat structure +// having to write access functions for every single var is a big annoyance +// see IMapData_t, generalize it? + +#define DATA_MAJOR "data" +// FIXME: remove +// define a GUID for this interface so plugins can access and reference it +// {608A9870-BCE7-11d4-A454-0004AC96D4C3} +static const GUID QERAppDataTable_GUID = +{ 0x608a9870, 0xbce7, 0x11d4, { 0xa4, 0x54, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; + + +// pointers to active_brushes, selected_brushes and filtered_brushes +typedef brush_t* (WINAPI* PFN_ACTIVEBRUSHES) (); +typedef brush_t* (WINAPI* PFN_SELECTEDBRUSHES) (); +typedef brush_t* (WINAPI* PFN_FILTEREDBRUSHES) (); +typedef CPtrArray* (WINAPI* PFN_LSTSKINCACHE) (); + +struct _QERAppDataTable +{ + int m_nSize; + PFN_ACTIVEBRUSHES m_pfnActiveBrushes; + PFN_SELECTEDBRUSHES m_pfnSelectedBrushes; + PFN_FILTEREDBRUSHES m_pfnFilteredBrushes; + PFN_LSTSKINCACHE m_pfnLstSkinCache; +}; + +#endif diff --git a/include/idatastream.h b/include/idatastream.h new file mode 100644 index 00000000..8f6b0b8c --- /dev/null +++ b/include/idatastream.h @@ -0,0 +1,71 @@ +/* +Copyright (c) 2001, Loki software, inc. +modifications (c) 2001, Id software, inc. +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 Loki software 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 REGENTS 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. +*/ + +#ifndef _ISTREAM_H_ +#define _ISTREAM_H_ + +/*! +API for data streams + +Based on an initial implementation by Loki software +modified to be abstracted and shared across modules + +NOTE: why IDataStream and not IStream? because IStream is defined in windows IDL headers +*/ + +class IDataStream +{ +public: + IDataStream(); + virtual ~IDataStream(); + + virtual void IncRef () = 0; ///< Increment the number of references to this object + virtual void DecRef () = 0; ///< Decrement the reference count + + virtual unsigned long GetPosition() const = 0; + virtual unsigned long Seek(long lOff, int nFrom) = 0; + virtual void SetLength(unsigned long nNewLen) = 0; + virtual unsigned long GetLength() const = 0; + + virtual char* ReadString(char* pBuf, unsigned long nMax)=0; + virtual unsigned long Read(void* pBuf, unsigned long nCount)=0; + virtual unsigned long Write(const void* pBuf, unsigned long nCount)=0; + virtual int GetChar()=0; + virtual int PutChar(int c)=0; + + virtual void printf(const char*, ...) = 0; ///< completely matches the usual printf behaviour + + virtual void Abort()=0; + virtual void Flush()=0; + virtual void Close()=0; +}; + +#endif // _ISTREAM_H_ diff --git a/include/ieclass.h b/include/ieclass.h new file mode 100644 index 00000000..bfca1d60 --- /dev/null +++ b/include/ieclass.h @@ -0,0 +1,84 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/*! \file ieclass.h + \brief entity files loader API + this describes the APIs involved when loading entity description files + (initially, .def and .fgd) +*/ + +#ifndef _IECLASS_H_ +#define _IECLASS_H_ + +#define ECLASS_MAJOR "eclass" + +typedef void (* PFN_ECLASS_SCANFILE) (char *filename); +typedef const char* (* PFN_ECLASS_GETEXTENSION) (); + +struct _EClassTable +{ + int m_nSize; + PFN_ECLASS_SCANFILE m_pfnScanFile; + PFN_ECLASS_GETEXTENSION m_pfnGetExtension; +}; + +#ifdef USE_ECLASSTABLE_DEFINE +#ifndef __ECLASSTABLENAME +#define __ECLASSTABLENAME g_EClassTable +#endif +#define EClass_ScanFile __ECLASSTABLENAME.m_pfnEClass_ScanFile +#define EClass_GetExtension __ECLASSTABLENAME.m_pfnEClass_GetExtension +#endif + +#define ECLASSMANAGER_MAJOR "eclassmanager" + +typedef void (* PFN_ECLASS_INSERTALPHABETIZED) (eclass_t *e); +typedef eclass_t** (* PFN_GET_ECLASS_E) (); +typedef void (* PFN_SET_ECLASS_FOUND) (qboolean); +typedef qboolean (* PFN_GET_PARSING_SINGLE) (); +typedef eclass_t* (* PFN_ECLASS_CREATE) (const char *name, float col1, float col2, float col3, const vec3_t *mins, const vec3_t *maxs, const char *comments); +typedef eclass_t* (* PFN_ECLASS_FORNAME) (const char* name, qboolean has_brushes); + +struct _EClassManagerTable +{ + int m_nSize; + PFN_ECLASS_INSERTALPHABETIZED m_pfnEclass_InsertAlphabetized; + PFN_GET_ECLASS_E m_pfnGet_Eclass_E; + PFN_SET_ECLASS_FOUND m_pfnSet_Eclass_Found; + PFN_GET_PARSING_SINGLE m_pfnGet_Parsing_Single; + PFN_ECLASS_CREATE m_pfnEClass_Create; + PFN_ECLASS_FORNAME m_pfnEclass_ForName; +}; + +#ifdef USE_ECLASSMANAGER_DEFINE +#ifndef __ECLASSMANAGERTABLENAME +#define __ECLASSMANAGERTABLENAME g_EClassManagerTable +#endif +#define Eclass_InsertAlphabetized __ECLASSMANAGERTABLENAME.m_pfnEclass_InsertAlphabetized +#define Get_Eclass_E __ECLASSMANAGERTABLENAME.m_pfnGet_Eclass_E +#define Set_Eclass_Found __ECLASSMANAGERTABLENAME.m_pfnSet_Eclass_Found +#define Get_Parsing_Single __ECLASSMANAGERTABLENAME.m_pfnGet_Parsing_Single +#define EClass_Create __ECLASSMANAGERTABLENAME.m_pfnEClass_Create +#define Eclass_ForName __ECLASSMANAGERTABLENAME.m_pfnEclass_ForName +#endif + +#endif + diff --git a/include/ientity.h b/include/ientity.h new file mode 100644 index 00000000..51ca389f --- /dev/null +++ b/include/ientity.h @@ -0,0 +1,116 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _IENTITY_H_ +#define _IENTITY_H_ + +// +// API for entity manip stuff +// + +// FIXME TTimo this prolly needs to merge with iepairs.h? + +/*! +SPoG +generic "entity" module... +at first, there will only be one implementation for all entities, +perhaps later there will be one for each entity type? +it would probably make more sense to have a single implementation, +a generic one that is very flexible and can adapt the visualisation of +itself depending on an xml config specified in the entity definitions file +*/ +#define ENTITY_MAJOR "entity" +// {A1C9F9FD-75D5-4e4d-9D65-235D6D3F254C} +static const GUID QEREntityTable_GUID = +{ 0xa1c9f9fd, 0x75d5, 0x4e4d, { 0x9d, 0x65, 0x23, 0x5d, 0x6d, 0x3f, 0x25, 0x4c } }; + +typedef entity_t* (* PFN_ENTITYALLOC) (); +typedef void (* PFN_ENTITYFREE) (entity_t *e); +typedef entity_t* (* PFN_ENTITYCREATE) (eclass_t *c); +typedef entity_t* (* PFN_ENTITYCLONE) (entity_t *e); +typedef void (* PFN_ENTITYSETKEYVALUE) (entity_t *ent, const char *key, const char *value); +typedef void (* PFN_ENTITYDELETEKEY) (entity_t *ent, const char *key); +typedef const char* (* PFN_ENTITYVALUEFORKEY) (entity_t *ent, const char *key); +typedef float (* PFN_ENTITYFLOATFORKEY) (entity_t *ent, const char *key); +typedef int (* PFN_ENTITYINTFORKEY) (entity_t *ent, const char *key); +typedef void (* PFN_ENTITYVECTORFORKEY) (entity_t *ent, const char *key, vec3_t vec); +typedef void (* PFN_ENTITYADDTOLIST) (entity_t *e, entity_t *lst); +typedef void (* PFN_ENTITYREMOVEFROMLIST) (entity_t *e); +typedef void (* PFN_ENTITYLINKBRUSH) (entity_t *e, brush_t *b); +typedef void (* PFN_ENTITYUNLINKBRUSH) (brush_t *b); +typedef void (* PFN_ENTITYDRAWLIGHT) (entity_t* e, int nGLState, int pref, int nViewType); +typedef int (* PFN_ENTITYMEMORYSIZE) (entity_t *e); +typedef void (* PFN_ENTITYUPDATEMODEL) (entity_t *e); +typedef epair_t* (* PFN_ALLOCATEEPAIR) (const char *key, const char *value); +typedef epair_t** (* PFN_GETENTITYKEYVALLIST) (entity_t *e); +typedef void (* PFN_SETENTITYKEYVALLIST) (entity_t *e, epair_t* ep); + + +struct _QEREntityTable +{ + int m_nSize; + PFN_ENTITYALLOC m_pfnEntity_Alloc; + PFN_ENTITYFREE m_pfnEntity_Free; + PFN_ENTITYCREATE m_pfnEntity_Create; + PFN_ENTITYCLONE m_pfnEntity_Clone; + PFN_ENTITYSETKEYVALUE m_pfnSetKeyValue; + PFN_ENTITYDELETEKEY m_pfnDeleteKey; + PFN_ENTITYVALUEFORKEY m_pfnValueForKey; + PFN_ENTITYFLOATFORKEY m_pfnFloatForKey; + PFN_ENTITYINTFORKEY m_pfnIntForKey; + PFN_ENTITYVECTORFORKEY m_pfnGetVectorForKey; + PFN_ENTITYADDTOLIST m_pfnEntity_AddToList; + PFN_ENTITYREMOVEFROMLIST m_pfnEntity_RemoveFromList; + PFN_ENTITYLINKBRUSH m_pfnEntity_LinkBrush; + PFN_ENTITYUNLINKBRUSH m_pfnEntity_UnlinkBrush; + PFN_ENTITYDRAWLIGHT m_pfnDrawLight; + PFN_ENTITYMEMORYSIZE m_pfnEntity_MemorySize; + PFN_ALLOCATEEPAIR m_pfnAllocateEpair; + PFN_GETENTITYKEYVALLIST m_pfnGetEntityKeyValList; + PFN_SETENTITYKEYVALLIST m_pfnSetEntityKeyValList; +}; + +#ifdef USE_ENTITYTABLE_DEFINE +#ifndef __ENTITYTABLENAME +#define __ENTITYTABLENAME g_EntityTable +#endif +#define Entity_Alloc __ENTITYTABLENAME.m_pfnEntity_Alloc +#define Entity_Free __ENTITYTABLENAME.m_pfnEntity_Free +#define Entity_Clone __ENTITYTABLENAME.m_pfnEntity_Clone +#define SetKeyValue __ENTITYTABLENAME.m_pfnSetKeyValue +#define DeleteKey __ENTITYTABLENAME.m_pfnDeleteKey +#define ValueForKey __ENTITYTABLENAME.m_pfnValueForKey +#define FloatForKey __ENTITYTABLENAME.m_pfnFloatForKey +#define IntForKey __ENTITYTABLENAME.m_pfnIntForKey +#define GetVectorForKey __ENTITYTABLENAME.m_pfnGetVectorForKey +#define Entity_AddToList __ENTITYTABLENAME.m_pfnEntity_AddToList +#define Entity_RemoveFromList __ENTITYTABLENAME.m_pfnEntity_RemoveFromList +#define Entity_LinkBrush __ENTITYTABLENAME.m_pfnEntity_LinkBrush +#define Entity_UnlinkBrush __ENTITYTABLENAME.m_pfnEntity_UnlinkBrush +#define DrawLight __ENTITYTABLENAME.m_pfnDrawLight +#define Entity_MemorySize __ENTITYTABLENAME.m_pfnEntity_MemorySize +#define Entity_AllocateEpair __ENTITYTABLENAME.m_pfnAllocateEpair +#define Entity_GetKeyValList __ENTITYTABLENAME.m_pfnGetEntityKeyValList +#define Entity_SetKeyValList __ENTITYTABLENAME.m_pfnSetEntityKeyValList +#endif + +#endif + diff --git a/include/ifilesystem.h b/include/ifilesystem.h new file mode 100644 index 00000000..8a9a2006 --- /dev/null +++ b/include/ifilesystem.h @@ -0,0 +1,140 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _IFILESYSTEM_H_ +#define _IFILESYSTEM_H_ + +// +// Plugin interface for the virtual filesystem used by Radiant +// + +// NOTE: If you want to write a VFS plugin then you must export +// "QERPlug_ListInterfaces" and "QERPlug_RequestInterface" +// (see qerplugin.h for more information) + +#ifdef _WIN32 +#define VFS_NATIVESEPARATOR '\\' +#else +#define VFS_NATIVESEPARATOR '/' +#endif + +#define VFS_MAJOR "VFS" + +// return the file system supported by the plugin, for example: "quake1" or "quake3" +//typedef const char* (WINAPI* PFN_VFSGETFORMAT) (); +// add all files from a directory to the vfs +typedef void (* PFN_VFSINITDIRECTORY) (const char *path); +// free all resources used by the plugin +typedef void (* PFN_VFSSHUTDOWN) (); +// free memory allocated by VFS for this pointer +typedef void (* PFN_VFSFREEFILE) (void *p); +// return a GSList with all the directories under basedir +typedef GSList* (* PFN_VFSGETDIRLIST) (const char *basedir); +// return a GSList with all the files under basedir (extension can be NULL) +typedef GSList* (* PFN_VFSGETFILELIST) (const char *basedir, const char *extension); +// free a dirlist or filelist returned from one of the above functions +typedef void (* PFN_VFSCLEARFILEDIRLIST) (GSList **lst); +#define VFS_SEARCH_PAK 0x1 +#define VFS_SEARCH_DIR 0x2 +/*! +\brief return the number of files with the exact name described in filename +there can be several hits for a given file, or this can be used to check for existence +\param flags is optional and can be used with VFS_SEARCH_* bits, if flag is 0, everything is searched, else only the specified bits +paks are searched first, then search directories +*/ +typedef int (* PFN_VFSGETFILECOUNT) (const char *filename, int flags); +/*! +\brief load file, allocate buffer +\return -1 if fails or the size of the buffer allocated +\param index is used to load the i-th file in the search directories (see vfsGetFileCount) +this will scan in the search directories first, then it will search in the pak files +WARNING: the allocated buffer must be freed with a g_free call +NOTE TTimo: the g_free release is utter horror + see http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=491 +*/ +typedef int (* PFN_VFSLOADFILE) (const char *filename, void **buffer, int index); +// load a file from it's full path into the buffer, returns the file size or -1 +// the allocated buffer must be freed with a g_free call +typedef int (* PFN_VFSLOADFULLPATHFILE) (const char *filename, void **buffer); +// takes an absolute file path, returns a shortened relative file path if the absolute path matches a valid basedir or NULL if an error occured +typedef char* (* PFN_VFSEXTRACTRELATIVEPATH) (const char *in); +/*! +\return the full path (in a static buff) to a file given it's relative path (NULL if not found) +\param index if several files are matching (as returned in a call to vfsGetFileCount), get the index-th file +\param flag 0 or a combination of VFS_SEARCH_PAK or VFS_SEARCH_DIR +HYDRA: + this now searches VFS/PAK files in addition to the filesystem + if FLAG is 0 then ONLY dirs are searched. + PAK's are searched before DIRs to mimic engine behaviour + index is ignored when searching PAK files. + when searching VFS, files are searched case insensitive. + +WARNING: if you use index from vfsGetFileCount, it works only with a vfsGetFileCount for the search directories only (not the pak files) +FIXME TTimo our VFS names are case insensitive. + this function is not able to build the full path from case-insensitive name + ( this is http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=130 ) +*/ +typedef char* (* PFN_VFSGETFULLPATH) (const char *in, int index, int flag); +/*! +these return a static char*, doesn't need to be freed or anything +get the base path to use when raising file dialogs +we manually add "maps/" or "sounds/" or "mapobjects/models/" etc. +FIXME: I'm not sure this is used / relevant anymore +*/ +typedef const char* (* PFN_VFSBASEPROMPTPATH) (); + +// VFS API +struct _QERFileSystemTable +{ + int m_nSize; + PFN_VFSINITDIRECTORY m_pfnInitDirectory; + PFN_VFSSHUTDOWN m_pfnShutdown; + PFN_VFSFREEFILE m_pfnFreeFile; + PFN_VFSGETDIRLIST m_pfnGetDirList; + PFN_VFSGETFILELIST m_pfnGetFileList; + PFN_VFSCLEARFILEDIRLIST m_pfnClearFileDirList; + PFN_VFSGETFILECOUNT m_pfnGetFileCount; + PFN_VFSLOADFILE m_pfnLoadFile; + PFN_VFSLOADFULLPATHFILE m_pfnLoadFullPathFile; + PFN_VFSEXTRACTRELATIVEPATH m_pfnExtractRelativePath; + PFN_VFSGETFULLPATH m_pfnGetFullPath; + PFN_VFSBASEPROMPTPATH m_pfnBasePromptPath; +}; + +#ifdef USE_VFSTABLE_DEFINE +#ifndef __VFSTABLENAME +#define __VFSTABLENAME g_FileSystemTable +#endif +#define vfsInitDirectory __VFSTABLENAME.m_pfnInitDirectory +#define vfsShutdown __VFSTABLENAME.m_pfnShutdown +#define vfsFreeFile __VFSTABLENAME.m_pfnFreeFile +#define vfsGetDirList __VFSTABLENAME.m_pfnGetDirList +#define vfsGetFileList __VFSTABLENAME.m_pfnGetFileList +#define vfsClearFileDirList __VFSTABLENAME.m_pfnClearFileDirList +#define vfsGetFileCount __VFSTABLENAME.m_pfnGetFileCount +#define vfsLoadFile __VFSTABLENAME.m_pfnLoadFile +#define vfsLoadFullPathFile __VFSTABLENAME.m_pfnLoadFullPathFile +#define vfsExtractRelativePath __VFSTABLENAME.m_pfnExtractRelativePath +#define vfsGetFullPath __VFSTABLENAME.m_pfnGetFullPath +#define vfsBasePromptPath __VFSTABLENAME.m_pfnBasePromptPath +#endif + +#endif // _IFILESYSTEM_H_ diff --git a/include/igl.h b/include/igl.h new file mode 100644 index 00000000..99e4141f --- /dev/null +++ b/include/igl.h @@ -0,0 +1,266 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// +// DESCRIPTION: +// all purpose OpenGL interface for Q3Radiant plugins +// + +#ifndef __IGL_H__ +#define __IGL_H__ + +#if defined (__linux__) || defined (__APPLE__) +#include +#endif + +// we use these classes to let plugins draw inside the Radiant windows +// 2D window like YZ XZ XY +class IGL2DWindow +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + virtual void Draw2D( VIEWTYPE vt ) = 0; +}; + +// 3D window +class IGL3DWindow +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + virtual void Draw3D() = 0; +}; + +#define QGL_MAJOR "qgl" + +#include + +typedef void (APIENTRY* PFN_QGLALPHAFUNC) (GLenum func, GLclampf ref); +typedef void (APIENTRY* PFN_QGLBEGIN) (GLenum); +typedef void (APIENTRY* PFN_QGLBINDTEXTURE) (GLenum target, GLuint texture); +typedef void (APIENTRY* PFN_QGLBLENDFUNC) (GLenum sfactor, GLenum dfactor); +typedef void (APIENTRY* PFN_QGLCALLLIST) (GLuint list); +typedef void (APIENTRY* PFN_QGLCALLLISTS) (GLsizei n, GLenum type, const GLvoid *lists); +typedef void (APIENTRY* PFN_QGLCLEAR) (GLbitfield mask); +typedef void (APIENTRY* PFN_QGLCLEARCOLOR) (GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +typedef void (APIENTRY* PFN_QGLCLEARDEPTH) (GLclampd depth); +typedef void (APIENTRY* PFN_QGLCOLOR3F) (GLfloat red, GLfloat green, GLfloat blue); +typedef void (APIENTRY* PFN_QGLCOLOR3FV) (const GLfloat *v); +typedef void (APIENTRY* PFN_QGLCOLOR4F) (GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +typedef void (APIENTRY* PFN_QGLCOLOR4FV) (const GLfloat *v); +typedef void (APIENTRY* PFN_QGLCOLOR4UBV) (const GLubyte *v); +typedef void (APIENTRY* PFN_QGLCOLORPOINTER) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRY* PFN_QGLCULLFACE) (GLenum mode); +typedef void (APIENTRY* PFN_QGLDELETELISTS) (GLuint list, GLsizei range); +typedef void (APIENTRY* PFN_QGLDELETETEXTURES) (GLsizei n, const GLuint *textures); +typedef void (APIENTRY* PFN_QGLDEPTHFUNC) (GLenum func); +typedef void (APIENTRY* PFN_QGLDEPTHMASK) (GLboolean flag); +typedef void (APIENTRY* PFN_QGLDISABLE) (GLenum cap); +typedef void (APIENTRY* PFN_QGLDISABLECLIENTSTATE) (GLenum array); +typedef void (APIENTRY* PFN_QGLDRAWELEMENTS) (GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +typedef void (APIENTRY* PFN_QGLENABLE) (GLenum cap); +typedef void (APIENTRY* PFN_QGLENABLECLIENTSTATE) (GLenum array); +typedef void (APIENTRY* PFN_QGLEND) (); +typedef void (APIENTRY* PFN_QGLENDLIST) (); +typedef void (APIENTRY* PFN_QGLFOGF) (GLenum pname, GLfloat param); +typedef void (APIENTRY* PFN_QGLFOGFV) (GLenum pname, const GLfloat *params); +typedef void (APIENTRY* PFN_QGLFOGFI) (GLenum pname, GLint param); +typedef GLuint (APIENTRY* PFN_QGLGENLISTS) (GLsizei range); +typedef void (APIENTRY *PFN_QGLGENTEXTURES) (GLsizei n, GLuint *textures); +typedef void (APIENTRY* PFN_QGLGETDOUBLEV) (GLenum pname, GLdouble *params); +typedef void (APIENTRY* PFN_QGLHINT) (GLenum target, GLenum mode); +typedef void (APIENTRY* PFN_QGLGETINTEGERV) (GLenum pname, GLint *params); +typedef void (APIENTRY* PFN_QGLLIGHTFV) (GLenum light, GLenum pname, const GLfloat *params); +typedef void (APIENTRY* PFN_QGLLINEWIDTH) (GLfloat size); +typedef void (APIENTRY* PFN_QGLLINESTIPPLE) (GLint factor, GLushort pattern); +typedef void (APIENTRY* PFN_QGLLINEWIDTH) (GLfloat size); +typedef void (APIENTRY* PFN_QGLLISTBASE) (GLuint base); +typedef void (APIENTRY* PFN_QGLLOADIDENTITY) (); +typedef void (APIENTRY* PFN_QGLMATERIALF) (GLenum face, GLenum pname, GLfloat param); +typedef void (APIENTRY* PFN_QGLMATERIALFV) (GLenum face, GLenum pname, const GLfloat *params); +typedef void (APIENTRY* PFN_QGLMATRIXMODE) (GLenum mode); +typedef void (APIENTRY* PFN_QGLMULTMATRIXF) (const GLfloat *m); +typedef void (APIENTRY* PFN_QGLNEWLIST) (GLuint list, GLenum mode); +typedef void (APIENTRY* PFN_QGLNORMAL3F) (GLfloat nx, GLfloat ny, GLfloat nz); +typedef void (APIENTRY* PFN_QGLNORMAL3FV) (const GLfloat *n); +typedef void (APIENTRY* PFN_QGLNORMALPOINTER) (GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRY* PFN_QGLORTHO) (GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +typedef void (APIENTRY* PFN_QGLPOINTSIZE) (GLfloat size); +typedef void (APIENTRY* PFN_QGLPOLYGONMODE) (GLenum face, GLenum mode); +typedef void (APIENTRY* PFN_QGLPOPATTRIB) (); +typedef void (APIENTRY* PFN_QGLPOPMATRIX) (); +typedef void (APIENTRY* PFN_QGLPUSHATTRIB) (GLbitfield mask); +typedef void (APIENTRY* PFN_QGLPUSHMATRIX) (); +typedef void (APIENTRY* PFN_QGLRASTERPOS3FV) (const GLfloat *v); +typedef void (APIENTRY* PFN_QGLROTATED) (GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRY* PFN_QGLROTATEF) (GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRY* PFN_QGLSCALEF) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRY* PFN_QGLSCISSOR) (GLint x, GLint y, GLsizei width, GLsizei height); +typedef void (APIENTRY* PFN_QGLSCALEF) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRY* PFN_QGLSHADEMODEL) (GLenum mode); +typedef void (APIENTRY* PFN_QGLTEXCOORD2F) (GLfloat s, GLfloat t); +typedef void (APIENTRY* PFN_QGLTEXCOORD2FV) (const GLfloat *v); +typedef void (APIENTRY* PFN_QGLTEXCOORDPOINTER) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRY* PFN_QGLTEXENVF) (GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRY* PFN_QGLTEXGENF) (GLenum coord, GLenum pname, GLfloat param); +typedef void (APIENTRY* PFN_QGLTEXIMAGE1D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRY* PFN_QGLTEXIMAGE2D) (GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRY* PFN_QGLTEXPARAMETERF) (GLenum target, GLenum pname, GLfloat param); +typedef void (APIENTRY* PFN_QGLTEXPARAMETERFV) (GLenum target, GLenum pname, const GLfloat *params); +typedef void (APIENTRY* PFN_QGLTEXPARAMETERI) (GLenum target, GLenum pname, GLint param); +typedef void (APIENTRY* PFN_QGLTEXPARAMETERIV) (GLenum target, GLenum pname, const GLint *params); +typedef void (APIENTRY* PFN_QGLTEXSUBIMAGE1D) (GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRY* PFN_QGLTEXSUBIMAGE2D) (GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +typedef void (APIENTRY* PFN_QGLTRANSLATED) (GLdouble x, GLdouble y, GLdouble z); +typedef void (APIENTRY* PFN_QGLTRANSLATEF) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRY* PFN_QGLVERTEX2F) (GLfloat x, GLfloat y); +typedef void (APIENTRY* PFN_QGLVERTEX3F) (GLfloat x, GLfloat y, GLfloat z); +typedef void (APIENTRY* PFN_QGLVERTEX3FV) (const GLfloat *v); +typedef void (APIENTRY* PFN_QGLVERTEXPOINTER) (GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +typedef void (APIENTRY* PFN_QGLVIEWPORT) (GLint x, GLint y, GLsizei width, GLsizei height); + +typedef void (WINAPI* PFN_QE_CHECKOPENGLFORERRORS) (); + +// glu stuff +// TTimo: NOTE: relying on glu might not be such a good idea. On many systems, the GLU lib is outdated, misversioned etc. +typedef void (APIENTRY * PFN_QGLUPERSPECTIVE) (GLdouble fovy, GLdouble aspect, GLdouble zNear, GLdouble zFar); +typedef void (APIENTRY * PFN_QGLULOOKAT) (GLdouble eyex, GLdouble eyey, GLdouble eyez, + GLdouble centerx, GLdouble centery, GLdouble centerz, + GLdouble upx, GLdouble upy, GLdouble upz); +//++timo gluErrorString is defined but not exposed in the IGL interface + + +// plugins drawing inside the GL windows +//++timo TODO: add hooking into other windows (Z and .. texture??) +//+timo NOTE: this could be moved to the messaging system instead of having a dedicated interface <- yet I don't know how +typedef void (WINAPI* PFN_QERAPP_HOOKGL2DWINDOW) (IGL2DWindow *); +typedef void (WINAPI* PFN_QERAPP_UNHOOKGL2DWINDOW) (IGL2DWindow *); +typedef void (WINAPI* PFN_QERAPP_HOOKGL3DWINDOW) (IGL3DWindow *); +typedef void (WINAPI* PFN_QERAPP_UNHOOKGL3DWINDOW) (IGL3DWindow *); + +struct _QERQglTable +{ + //++timo do we really wanna play with versions ? + // float m_fVersion; + int m_nSize; + PFN_QGLALPHAFUNC m_pfn_qglAlphaFunc; + PFN_QGLBEGIN m_pfn_qglBegin; + PFN_QGLBINDTEXTURE m_pfn_qglBindTexture; + PFN_QGLBLENDFUNC m_pfn_qglBlendFunc; + PFN_QGLCALLLIST m_pfn_qglCallList; + PFN_QGLCLEAR m_pfn_qglClear; + PFN_QGLCLEARCOLOR m_pfn_qglClearColor; + PFN_QGLCALLLISTS m_pfn_qglCallLists; + PFN_QGLCLEARDEPTH m_pfn_qglClearDepth; + PFN_QGLCOLOR3F m_pfn_qglColor3f; + PFN_QGLCOLOR3FV m_pfn_qglColor3fv; + PFN_QGLCOLOR4F m_pfn_qglColor4f; + PFN_QGLCOLOR4FV m_pfn_qglColor4fv; + PFN_QGLCOLOR4UBV m_pfn_qglColor4ubv; // ydnar + PFN_QGLCOLORPOINTER m_pfn_qglColorPointer; + PFN_QGLCULLFACE m_pfn_qglCullFace; + PFN_QGLDELETELISTS m_pfn_qglDeleteLists; + PFN_QGLDELETETEXTURES m_pfn_qglDeleteTextures; + PFN_QGLDEPTHFUNC m_pfn_qglDepthFunc; + PFN_QGLDEPTHMASK m_pfn_qglDepthMask; + PFN_QGLDISABLE m_pfn_qglDisable; + PFN_QGLDISABLECLIENTSTATE m_pfn_qglDisableClientState; + PFN_QGLDRAWELEMENTS m_pfn_qglDrawElements; + PFN_QGLENABLE m_pfn_qglEnable; + PFN_QGLENABLECLIENTSTATE m_pfn_qglEnableClientState; + PFN_QGLEND m_pfn_qglEnd; + PFN_QGLENDLIST m_pfn_qglEndList; + PFN_QGLFOGF m_pfn_qglFogf; + PFN_QGLFOGFV m_pfn_qglFogfv; + PFN_QGLFOGFI m_pfn_qglFogi; + PFN_QGLGENLISTS m_pfn_qglGenLists; + PFN_QGLGENTEXTURES m_pfn_qglGenTextures; + PFN_QGLGETDOUBLEV m_pfn_qglGetDoublev; + PFN_QGLGETINTEGERV m_pfn_qglGetIntegerv; + PFN_QGLHINT m_pfn_qglHint; + PFN_QGLLIGHTFV m_pfn_qglLightfv; + PFN_QGLLINESTIPPLE m_pfn_qglLineStipple; + PFN_QGLLINEWIDTH m_pfn_qglLineWidth; + PFN_QGLLISTBASE m_pfn_qglListBase; + PFN_QGLLOADIDENTITY m_pfn_qglLoadIdentity; + PFN_QGLMATERIALF m_pfn_qglMaterialf; + PFN_QGLMATERIALFV m_pfn_qglMaterialfv; + PFN_QGLMATRIXMODE m_pfn_qglMatrixMode; + PFN_QGLMULTMATRIXF m_pfn_qglMultMatrixf; + PFN_QGLNEWLIST m_pfn_qglNewList; + PFN_QGLNORMAL3F m_pfn_qglNormal3f; + PFN_QGLNORMAL3FV m_pfn_qglNormal3fv; + PFN_QGLNORMALPOINTER m_pfn_qglNormalPointer; + PFN_QGLORTHO m_pfn_qglOrtho; + PFN_QGLPOINTSIZE m_pfn_qglPointSize; + PFN_QGLPOLYGONMODE m_pfn_qglPolygonMode; + PFN_QGLPOPATTRIB m_pfn_qglPopAttrib; + PFN_QGLPOPMATRIX m_pfn_qglPopMatrix; + PFN_QGLPUSHATTRIB m_pfn_qglPushAttrib; + PFN_QGLPUSHMATRIX m_pfn_qglPushMatrix; + PFN_QGLRASTERPOS3FV m_pfn_qglRasterPos3fv; + PFN_QGLROTATED m_pfn_qglRotated; + PFN_QGLROTATEF m_pfn_qglRotatef; + PFN_QGLSCALEF m_pfn_qglScalef; + PFN_QGLSCISSOR m_pfn_qglScissor; + PFN_QGLSHADEMODEL m_pfn_qglShadeModel; + PFN_QGLTEXCOORD2F m_pfn_qglTexCoord2f; + PFN_QGLTEXCOORD2FV m_pfn_qglTexCoord2fv; + PFN_QGLTEXCOORDPOINTER m_pfn_qglTexCoordPointer; + PFN_QGLTEXENVF m_pfn_qglTexEnvf; + PFN_QGLTEXGENF m_pfn_qglTexGenf; + PFN_QGLTEXIMAGE1D m_pfn_qglTexImage1D; + PFN_QGLTEXIMAGE2D m_pfn_qglTexImage2D; + PFN_QGLTEXPARAMETERF m_pfn_qglTexParameterf; + PFN_QGLTEXPARAMETERFV m_pfn_qglTexParameterfv; + PFN_QGLTEXPARAMETERI m_pfn_qglTexParameteri; + PFN_QGLTEXPARAMETERIV m_pfn_qglTexParameteriv; + PFN_QGLTEXSUBIMAGE1D m_pfn_qglTexSubImage1D; + PFN_QGLTEXSUBIMAGE2D m_pfn_qglTexSubImage2D; + PFN_QGLTRANSLATED m_pfn_qglTranslated; + PFN_QGLTRANSLATEF m_pfn_qglTranslatef; + PFN_QGLVERTEX2F m_pfn_qglVertex2f; + PFN_QGLVERTEX3F m_pfn_qglVertex3f; + PFN_QGLVERTEX3FV m_pfn_qglVertex3fv; + PFN_QGLVERTEXPOINTER m_pfn_qglVertexPointer; + PFN_QGLVIEWPORT m_pfn_qglViewport; + + PFN_QE_CHECKOPENGLFORERRORS m_pfn_QE_CheckOpenGLForErrors; + + // glu stuff + PFN_QGLUPERSPECTIVE m_pfn_qgluPerspective; + PFN_QGLULOOKAT m_pfn_qgluLookAt; + + // plugin entities drawing inside Radiant windows + PFN_QERAPP_HOOKGL2DWINDOW m_pfnHookGL2DWindow; + PFN_QERAPP_UNHOOKGL2DWINDOW m_pfnUnHookGL2DWindow; + PFN_QERAPP_HOOKGL3DWINDOW m_pfnHookGL3DWindow; + PFN_QERAPP_UNHOOKGL3DWINDOW m_pfnUnHookGL3DWindow; +}; + +#endif diff --git a/include/iimage.h b/include/iimage.h new file mode 100644 index 00000000..e473c4fe --- /dev/null +++ b/include/iimage.h @@ -0,0 +1,40 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// Plugin interface for loading image files +// + +#ifndef _IIMAGE_H_ +#define _IIMAGE_H_ + +#define IMAGE_MAJOR "image" + +// Load an image file +typedef void (* PFN_QERPLUG_LOADIMAGE) (const char *name, unsigned char **pic, int *width, int *height); + +struct _QERPlugImageTable +{ + int m_nSize; + PFN_QERPLUG_LOADIMAGE m_pfnLoadImage; +}; + +#endif // _IIMAGE_H_ diff --git a/include/imap.h b/include/imap.h new file mode 100644 index 00000000..230d5dd1 --- /dev/null +++ b/include/imap.h @@ -0,0 +1,82 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//---------------------------------------------------------------------------- +// +// DESCRIPTION: +// map format interface (.map and .xmap, Q3 and other games) +// + +#ifndef __IMAP_H__ +#define __IMAP_H__ + +/*! IMap depends on IDataStream, including the header there for now */ +#include "idatastream.h" + +/*! header for CPtrArray */ +#include "missing.h" + +#define MAP_MAJOR "map" +/*! +define a GUID for this interface so everyone can acces and reference it +{75076973-3414-49c9-be5b-2378ec5601af} +*/ +static const GUID QERPlugMapTable_GUID = +{ 0x75076973, 0x3414, 0x49c9, { 0xbe, 0x5b, 0x23, 0x78, 0xec, 0x56, 0x01, 0xaf } }; + +/*! +read from a stream into a list of entities +\param in the input stream. For regular map file parsing it's possible to copy the content in a text buffer +and use the old school parser +\param ents the list of entities read from the stream. They are not linked to the world, and their brushes +are not either. +*/ +typedef void (* PFN_MAP_READ) (IDataStream *in, CPtrArray *ents); ///< read from a stream into a list of entities +typedef void (* PFN_MAP_WRITE) (CPtrArray *ents, IDataStream *out); ///< save a list of entities into a stream + +struct _QERPlugMapTable +{ + int m_nSize; + PFN_MAP_READ m_pfnMap_Read; + PFN_MAP_WRITE m_pfnMap_Write; +}; + +/*! +this set of macros will define the functions to map on a given table + it should be used in the headers (see modules source, plugin.h) +we don't want those defines in the part where WE implement the Map_LoadFile + so we're using a define to disable .. should find a standard define name + (for instance QCOM_CLIENT / QCOM_SERVER ?) + or the name should be specific to any interface .. it's not a client/server thing here anyway +*/ +#ifdef USE_MAPTABLE_DEFINE +#ifndef __MAPTABLENAME +/*! +TTimo NOTE: this is the default table name we map to + if you are using a different table name, just define __MAPTABLENAME before you include the imap.h header +*/ +#define __MAPTABLENAME g_MapTable +#endif +#define Map_Read __MAPTABLENAME.m_pfnMap_Read +#define Map_Write __MAPTABLENAME.m_pfnMap_Write +#endif + +#endif diff --git a/include/imodel.h b/include/imodel.h new file mode 100644 index 00000000..de5964a8 --- /dev/null +++ b/include/imodel.h @@ -0,0 +1,106 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _IMODEL_H_ +#define _IMODEL_H_ + +#define MODEL_MAJOR "model" + +/*! +loads model from model file name specified, +fills model struct with pointers to model interfaces + +name is a relative path, we'll use VFS to extract a basepath to add to get the absolute path. +*/ +typedef void (* PFN_LOADMODEL) (entity_interfaces_t *model, const char *name); + +struct _QERPlugModelTable +{ + int m_nSize; + PFN_LOADMODEL m_pfnLoadModel; +}; + + +//forward declare entity_t +struct entity_s; +typedef struct entity_s entity_t; + +// any module relying on imodel will need to link against the mathlib +#include "mathlib.h" + +// state flags +#define DRAW_GL_FILL 0x0001 +#define DRAW_GL_LIGHTING 0x0010 +#define DRAW_GL_TEXTURE_2D 0x0100 +#define DRAW_GL_BLEND 0x1000 + +// predefined state combinations +#define DRAW_GL_WIRE 0x0000 +#define DRAW_GL_FLAT 0x0001 +#define DRAW_GL_SOLID 0x0011 +#define DRAW_GL_TEXTURED 0x0111 + +// mode +#define DRAW_WIRE 0 +#define DRAW_SOLID 1 +#define DRAW_TEXTURED 2 + +// render flags +#define DRAW_RF_NONE 0x0000 +#define DRAW_RF_SEL_OUTLINE 0x0001 +#define DRAW_RF_SEL_FILL 0x0010 +#define DRAW_RF_XY 0x0011 +#define DRAW_RF_CAM 0x0100 + +class IRender +{ +public: + virtual ~IRender() { } + virtual void IncRef() = 0; // increments the reference counter for this object + virtual void DecRef() = 0; // decrements the reference counter for this object, deletes the object if reference count is zero + virtual void Draw(int state, int rflags) const = 0; // render the object - state = the opengl state + virtual const aabb_t *GetAABB() const = 0; +}; + +class ISelect +{ +public: + virtual ~ISelect() { } + virtual void IncRef() = 0; // increments the reference counter for this object + virtual void DecRef() = 0; // decrements the reference counter for this object, deletes the object if reference count is zero + virtual bool TestRay(const ray_t *ray, vec_t *dist) const = 0; // test ray intersection, return bool true if intersects, and store distance to closest point of intersection + //virtual bool TestBox(const aabb_t *aabb) const = 0; // test aabb intersection, return bool true if touching or intersecting +}; + +class IEdit +{ +public: + virtual ~IEdit() { } + virtual void IncRef() = 0; // increments the reference counter for this object + virtual void DecRef() = 0; // decrements the reference counter for this object, deletes the object if reference count is zero + virtual void Translate(const vec3_t translation) = 0; + virtual void Rotate(const vec3_t pivot, const vec3_t rotation) = 0; + virtual const vec_t *GetTranslation() const = 0; + virtual const vec_t *GetRotation() const = 0; + virtual void OnKeyValueChanged(entity_t *e, const char *key, const char* value) = 0; +}; + +#endif /* _IMODEL_H_ */ diff --git a/include/ipatch.h b/include/ipatch.h new file mode 100644 index 00000000..ccfd39ed --- /dev/null +++ b/include/ipatch.h @@ -0,0 +1,53 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _IPATCH_H_ +#define _IPATCH_H_ + +// +// API for patch stuff +// + +#define PATCH_MAJOR "patch" +// {4715565b-ab3a-49fa-841f-ee965b6d88a5} +static const GUID QERPatchTable_GUID = +{ 0x4715565b, 0xab3a, 0x49fa, { 0x84, 0x1f, 0xee, 0x96, 0x5b, 0x6d, 0x88, 0xa5 } }; + +typedef patchMesh_t* (* PFN_PATCHALLOC) (); +typedef patchMesh_t* (* PFN_MAKENEWPATCH) (); +typedef brush_t* (* PFN_ADDBRUSHFORPATCH) (patchMesh_t *pm, bool bLinkToWorld ); + +struct _QERPatchTable +{ + int m_nSize; + PFN_PATCHALLOC m_pfnPatch_Alloc; + PFN_MAKENEWPATCH m_pfnMakeNewPatch; + PFN_ADDBRUSHFORPATCH m_pfnAddBrushForPatch; +}; + +#ifdef USE_PATCHTABLE_DEFINE +#define __PATCHTABLENAME g_PatchTable +#define Patch_Alloc __PATCHTABLENAME.m_pfnPatch_Alloc +#define MakeNewPatch __PATCHTABLENAME.m_pfnMakeNewPatch +#define AddBrushForPatch __PATCHTABLENAME.m_pfnAddBrushForPatch +#endif + +#endif diff --git a/include/iplugin.h b/include/iplugin.h new file mode 100644 index 00000000..e2974b9b --- /dev/null +++ b/include/iplugin.h @@ -0,0 +1,41 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _IPLUGIN_H_ +#define _IPLUGIN_H_ + +#define PLUGIN_MAJOR "plugin" + +typedef const char* (* PFN_QERPLUG_INIT) (void* hApp, void* pMainWidget); +typedef const char* (* PFN_QERPLUG_GETNAME) (); +typedef const char* (* PFN_QERPLUG_GETCOMMANDLIST) (); +typedef void (* PFN_QERPLUG_DISPATCH) (const char* p, float* vMin, float* vMax, bool bSingleBrush); + +struct _QERPluginTable +{ + int m_nSize; + PFN_QERPLUG_INIT m_pfnQERPlug_Init; + PFN_QERPLUG_GETNAME m_pfnQERPlug_GetName; + PFN_QERPLUG_GETCOMMANDLIST m_pfnQERPlug_GetCommandList; + PFN_QERPLUG_DISPATCH m_pfnQERPlug_Dispatch; +}; + +#endif diff --git a/include/irefcount.h b/include/irefcount.h new file mode 100644 index 00000000..2fc495ad --- /dev/null +++ b/include/irefcount.h @@ -0,0 +1,62 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __IREFCOUNT_H__ +#define __IREFCOUNT_H__ + +/*! +\class IRefCounted +\brief reference counted objects + +general hints: how to use ref count properly + we consider ref counting as an extension of new and delete operators + the main issue is 'when to incref' 'when to decref' + in most cases connected to function calls + the general thinking about that: + - if you get a pointer to a refcounted object through a call to a function, assume that this object has been 'reserved' for you + already (i.e. allocated if you think this the new/delete way). so if you keep the object, you don't need to incref it, and if + you don't keep it you need to decref it. + - if you are called in a function and a refcounted object passed as parameter, then you should assume that this is an optional + object given to you FYI, which you don't need to decref if you don't keep / need to incref if you keep + + refcount is initialized to 1 in constructor. that serves for static objects and memory allocator + when you allocate in memory a ref counted object, it's default ref count will be 1, you should never delete it but just call DecRef on it + +define an interface and an implementation macro to make things easier +NOTE: we may have to provide a static library to go with that + in case we would move irecount.h out of here into libs/ + +\todo functionality needed: +mostly enable/disable some features with compile time flags (independently from each other as much as possible) +- log the destructor calls with != 0 ref count +- log all incref/decref (with module info, and maybe even file/line number etc.?) +*/ +class IRefCounted +{ + int refCount; +public: + IRefCounted() { refCount = 1; } + virtual ~IRefCounted() { } + void IncRef() { refCount++; } + void DecRef() { refCount--; if (refCount <= 0) delete this; } +}; + +#endif // __ISYNAPSE_H__ diff --git a/include/iscriplib.h b/include/iscriplib.h new file mode 100644 index 00000000..00ba6617 --- /dev/null +++ b/include/iscriplib.h @@ -0,0 +1,86 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// all purpose scriplib interface for Q3Radiant plugins (cf. parse.h) +// + +#ifndef __ISCRIPLIB_H_ +#define __ISCRIPLIB_H_ + +/*! \file iscriplib.h + \brief function tables for Radiant core's text parsing functions + two token based parsers cohexist in Radiant + the primary one (GetToken UnGetToken etc.) is used on the .map parsing etc. + COM_Parse is another parser, used on .def parse for instance + + NOTE: I hope we can totally get rid of this part when we have XML support +*/ + +#define SCRIPLIB_MAJOR "scriptlib" + +typedef qboolean (* PFN_GETTOKEN) (qboolean crossline); +typedef void (* PFN_UNGETTOKEN) (); +// only used to retrieve &token +typedef char* (* PFN_TOKEN) (); +typedef void (* PFN_STARTTOKENPARSING) (char *); +// script line +typedef int (* PFN_SCRIPTLINE) (); +typedef qboolean (* PFN_TOKENAVAILABLE) (); +// COM_Parse +typedef char* (* PFN_COM_PARSE) (char *data); +typedef char* (* PFN_GET_COM_TOKEN) (); +// Hydra: added support for GetTokenExtra() +typedef qboolean (* PFN_GETTOKENEXTRA) (qboolean crossline,char *delimiters,qboolean keepdelimiter); + +struct _QERScripLibTable +{ + float m_fVersion; + int m_nSize; + PFN_GETTOKEN m_pfnGetToken; + PFN_GETTOKENEXTRA m_pfnGetTokenExtra; // Hydra: added support for GetTokenExtra() + PFN_UNGETTOKEN m_pfnUnGetToken; + PFN_TOKEN m_pfnToken; + PFN_STARTTOKENPARSING m_pfnStartTokenParsing; + PFN_SCRIPTLINE m_pfnScriptLine; + PFN_TOKENAVAILABLE m_pfnTokenAvailable; + PFN_COM_PARSE m_pfnCOM_Parse; + PFN_GET_COM_TOKEN m_pfnGet_COM_Token; +}; + +#ifdef USE_SCRIPLIBTABLE_DEFINE +#ifndef __SCRIPLIBTABLENAME +#define __SCRIPLIBTABLENAME g_ScripLibTable +#endif +#define GetToken __SCRIPLIBTABLENAME.m_pfnGetToken +#define Token __SCRIPLIBTABLENAME.m_pfnToken +#define UnGetToken __SCRIPLIBTABLENAME.m_pfnUnGetToken +#define StartTokenParsing __SCRIPLIBTABLENAME.m_pfnStartTokenParsing +#define ScriptLine __SCRIPLIBTABLENAME.m_pfnScriptLine +#define TokenAvailable __SCRIPLIBTABLENAME.m_pfnTokenAvailable +#define COM_Parse __SCRIPLIBTABLENAME.m_pfnCOM_Parse +#define Get_COM_Token __SCRIPLIBTABLENAME.m_pfnGet_COM_Token +#define GetTokenExtra __SCRIPLIBTABLENAME.m_pfnGetTokenExtra // Hydra: added support for GetTokenExtra() +#endif + +#endif diff --git a/include/iselectedface.h b/include/iselectedface.h new file mode 100644 index 00000000..a01c5283 --- /dev/null +++ b/include/iselectedface.h @@ -0,0 +1,88 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// Quick interface hack for selected face interface +// this one really needs more work, but I'm in a hurry with TexTool + +#ifndef __ISELECTEDFACE_H_ +#define __ISELECTEDFACE_H_ + +#define SELECTEDFACE_MAJOR "selectedface" +// v2.0 +// support for multiple faces selection (first use in textool v2) +// using the g_ptrSelectedFaces indexes, get the face_t* with GETFACE +// still relies on the _QERFaceData*, unless you cast the face_t* to do your own stuff +// removed PFN_TEXTUREFORNAME, it's in the IShaders API now + +//++timo TODO: this interface needs some cleanup with the new texture / shaders interface + +// number of selected textures +typedef int (WINAPI* PFN_GETSELECTEDFACECOUNT) (); +// retrieve the corresponding brush_t* (we need it when we need to explicitely rebuild stuff) +typedef brush_t* (WINAPI* PFN_GETFACEBRUSH) (int iface); +// retrieve a given face_t* +typedef face_t* (WINAPI* PFN_GETFACE) (int iface); +// winding_t is assumed to have MAX_POINTS_ON_WINDING allocated and waiting +typedef int (WINAPI* PFN_GETFACEINFO) (int iface, _QERFaceData*, winding_t* ); +// tell editor to update the selected face data +typedef int (WINAPI* PFN_SETFACEINFO) (int iface, _QERFaceData*); +// retrieve the texture number to bind to +typedef int (WINAPI* PFN_GETTEXTURENUMBER) (int iface); +// retrieving some texture information +typedef void (WINAPI* PFN_GETTEXTURESIZE) (int iface, int Size[2] ); +// straight func pointer to Select_SetTexture +// last parameter must be casted to an IPluginTexdef +typedef void (WINAPI* PFN_SELECT_SETTEXTURE) (texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef, bool bFitScale, void* pPlugTexdef); + +// NOTE: some things in there are not really related to the selected face +// having some stuff moved into a textures-dedicated part ? +struct _QERSelectedFaceTable +{ + int m_nSize; + PFN_GETSELECTEDFACECOUNT m_pfnGetSelectedFaceCount; + PFN_GETFACEBRUSH m_pfnGetFaceBrush; + PFN_GETFACE m_pfnGetFace; + PFN_GETFACEINFO m_pfnGetFaceInfo; + PFN_SETFACEINFO m_pfnSetFaceInfo; + PFN_GETTEXTURENUMBER m_pfnGetTextureNumber; + PFN_GETTEXTURESIZE m_pfnGetTextureSize; + PFN_SELECT_SETTEXTURE m_pfnSelect_SetTexture; +}; + +#ifdef USE_SELECTEDFACETABLE_DEFINE + #ifndef __SELECTEDFACETABLENAME + #define __SELECTEDFACETABLENAME g_SelectedFaceTable + #endif + + #define GetSelectedFaceCount __SELECTEDFACETABLENAME.m_pfnGetSelectedFaceCount + #define GetFaceBrush __SELECTEDFACETABLENAME.m_pfnGetFaceBrush + #define GetFace __SELECTEDFACETABLENAME.m_pfnGetFace + #define GetFaceInfo __SELECTEDFACETABLENAME.m_pfnGetFaceInfo + #define SetFaceInfo __SELECTEDFACETABLENAME.m_pfnSetFaceInfo + #define GetTextureNumber __SELECTEDFACETABLENAME.m_pfnGetTextureNumber + #define GetTextureSize __SELECTEDFACETABLENAME.m_pfnGetTextureSize + #define Select_SetTexture __SELECTEDFACETABLENAME.m_pfnSelect_SetTexture +#endif + +#endif diff --git a/include/ishaders.h b/include/ishaders.h new file mode 100644 index 00000000..17cafc36 --- /dev/null +++ b/include/ishaders.h @@ -0,0 +1,284 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// +// DESCRIPTION: +// a set of functions to manipulate textures in Radiant +// + +#ifndef __ISHADERS_H_ +#define __ISHADERS_H_ + +#define SHADERS_MAJOR "shaders" +// define a GUID for this interface so plugins can access and reference it +// {D42F798A-DF57-11d3-A3EE-0004AC96D4C3} +static const GUID QERShadersTable_GUID = +{ 0xd42f798a, 0xdf57, 0x11d3, { 0xa3, 0xee, 0x0, 0x4, 0xac, 0x96, 0xd4, 0xc3 } }; + +// NOTES ABOUT SYNTAX: +// if a function starts by 'Try' it means that if the requested thing could not be found / loaded it will return nothing / NULL +// otherwise a default object will be created +// the _QERShadersTable is also used by shader code inside Radiant. but for speed and "keep it simple" consideration you +// can get the static equivalent of the func pointers by adding 'QERApp_' (access to _QERShadersTable is better thought .. +// see the note to move all the shader language out of Radiant below) + +/*! +\todo FIXME TTimo +fix the reference count strategy +- define the policy. It seems the initial policy of doing an inc ref when you create the shader is not good +(it doesn't work, and it's not being used right) +so, when you request an IShader and store it, incref it yourself +as a debugging safe check: push the created increfed objects into a list, and scan them at next idle loop +to make sure they have been decref'ed ? (sounds easy, may not be that much). +*/ + +class IShader +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + // get/set the qtexture_t* Radiant uses to represent this shader object + virtual qtexture_t* getTexture() const = 0; + virtual void setTexture(qtexture_t *pTex) = 0; + // get shader name + virtual const char* getName() const = 0; + // is this shader in use? + // NOTE: this flag can mean this shader has been in use at least once since the last rescan of in-use stuff + // (rescan of in-use happens in several cases, user command or during a texture directory load) + // NOTE: this is used to draw the green outline in the texture window + // NOTE: when does Radiant set the InUse flag? Whenever Select_SetTexture is called (well that doesn't necessarily means the texture actually gets in use, but that's close enough) + virtual bool IsInUse() const = 0; + virtual void SetInUse(bool) = 0; + // is this shader displayed in the texture browser? + // NOTE: if IsInUse() == true, the shader will always be displayed in the texture window and this flag ingored + virtual bool IsDisplayed() const = 0; + virtual void SetDisplayed(bool) = 0; + // get the editor flags (QER_NOCARVE QER_TRANS) + virtual int getFlags() = 0; + // get the transparency value + virtual float getTrans() = 0; + // test if it's a true shader, or a default shader created to wrap around a texture + virtual bool IsDefault() = 0; + // test if it's a plain color shader, i.e. a shader we use on plain color stuff (like info_playerstart) + virtual bool IsColor() = 0; + // get the related color then! + virtual void getColor(vec3_t v) = 0; + // get the alphaFunc + virtual void getAlphaFunc(int *func, float *ref) = 0; + // get the cull type + virtual int getCull() = 0; + // get shader file name (ie the file where this one is defined) + virtual const char* getShaderFileName() const = 0; +}; + +// NOTE: how to move all the shader language out of Radiant in a plugin? +// -> change this _QERShadersTable into an IShadersManager +// -> let the plugin create an instance of IShadersManager +// -> make sure Radiant uses this IShadersManager to load / query the shaders + +// NOTE: shader and texture names used must be full path, ie. most often with "textures/" prefix +// (since shaders are defined in .shader files with textures/) + +// free all shaders +// free the shaders, will not free the qtexture_t* +typedef void (WINAPI* PFN_FREESHADERS) (); +// reload all the shaders +// this will free everything (shaders and their textures), then reload all in use stuff +typedef void (WINAPI* PFN_RELOADSHADERS) (); +// load all shaders in a given directory +// this will scan the list of in-memory shaders, and load the related qtexture_t if needed +typedef int (WINAPI* PFN_LOADSHADERSFROMDIR)(const char* path); +// load a shader file (ie a set of shaders) +// after LoadShaderFile shaders will be in memory, next step is to load the qtexture_t Radiant uses to represent them +// if a shader with the same name exists, new one will not be loaded - don't use this to refresh the shaders! +typedef void (WINAPI* PFN_LOADSHADERFILE) (const char* filename); +// tell if a given shader exists in our shader table +// NOTE: this doesn't tell wether it's corresponding qtexture is loaded +typedef int (WINAPI* PFN_HASSHADER) (const char* name); +// return the shader for a given name +// if the qtexture is not already in memory, will try loading it +// if the qtexture could not be found, will use default +// will return NULL on shader not found +typedef IShader* (WINAPI* PFN_TRYSHADERFORNAME) (const char* name); +// return the shader for a given name +// if the qtexture is not already in memory, will try loading it +// will create a default shader if not found (will use a default texture) +typedef IShader* (WINAPI* PFN_SHADERFORNAME) (const char* name); +// query / load a texture +// will not try loading a shader, will look for the actual image file .. +// returns NULL on file not found +// NOTE: strategy for file lookup: +// paths must be relative, ie. textures/me/myfile +// if a 3-letters filename extension (such as .jpg or .tga) is provided, it will get loaded first +// if not found or no extension, will try loading after adding .tga and .jpg (in this order) +typedef qtexture_t* (WINAPI* PFN_TRYTEXTUREFORNAME) (const char* filename); +// query / load a texture +// will not try loading a shader, will look for the actual image file .. +// on file not found will use the "texture not found" +typedef qtexture_t* (WINAPI* PFN_TEXTUREFORNAME) (const char* filename); +// get the number of active shaders +// these are the shaders currently loaded, that have an associated qtexture_t* +typedef int (WINAPI* PFN_GETACTIVESHADERCOUNT) (); +// for stuff that needs to be represented by a plain texture +// the shader will get a "color" name, use GetColor to get the actual color +typedef IShader* (WINAPI* PFN_COLORSHADERFORNAME) (const char* name); +// reload a shaderfile - update shaders and their display properties/qtexture_t if needed +// will not reload the texture files +// will switch to "show in use" atfer use +// filename must be reletive path of the shader, ex. scripts/gothic_wall.shader +typedef void (WINAPI* PFN_RELOADSHADERFILE)(const char* filename); +// retrieve a shader if exists, without loading the textures for it etc. +// use this function if you want special info on a shader +typedef IShader* (WINAPI* PFN_SHADERFORNAMENOLOAD) (const char* name); +// force the "in use" flag on all active shaders +typedef void (WINAPI* PFN_ACTIVESHADERSSETINUSE) (bool b); +// sort the shaders in alphabetical order, we use the order in the texture inspector +typedef void (WINAPI* PFN_SORTACTIVESHADERS) (); +// check if there exists an active shader with the given texture name (loaded or not, doesn't matter) +// (used to detect the textures we need to create a default shader for .. while scanning a directory) +typedef IShader* (WINAPI* PFN_ACTIVESHADERFORTEXTURENAME) (char *); +// create a shader to wrap around a texture name, we use this when loading a texture directory and some textures +// are not present as shaders +typedef IShader* (WINAPI* PFN_CREATESHADERFORTEXTURENAME) (const char* name); +// switch the IsDisplayed flag on all the active shaders +typedef void (WINAPI* PFN_ACTIVESHADERSSETDISPLAYED) (bool b); +// retrieve an active shader based on index +typedef IShader* (WINAPI* PFN_ACTIVESHADERFORINDEX) (int i); +// will cleanup a texture name and force it to the right format +// the debug version is painfully slow, but will detect more problems +// the idea being to avoid loading the same file several time because of uppercase/lowercase etc. +typedef const char* (WINAPI* PFN_CLEANTEXTURENAME) (const char* name, bool bAddTexture); + +struct _QERShadersTable +{ + int m_nSize; + PFN_FREESHADERS m_pfnFreeShaders; + PFN_RELOADSHADERS m_pfnReloadShaders; + PFN_LOADSHADERSFROMDIR m_pfnLoadShadersFromDir; + PFN_LOADSHADERFILE m_pfnLoadShaderFile; + PFN_RELOADSHADERFILE m_pfnReloadShaderFile; + PFN_HASSHADER m_pfnHasShader; + PFN_TRYSHADERFORNAME m_pfnTry_Shader_ForName; + PFN_SHADERFORNAME m_pfnShader_ForName; + PFN_TRYTEXTUREFORNAME m_pfnTry_Texture_ForName; + PFN_TEXTUREFORNAME m_pfnTexture_ForName; + PFN_GETACTIVESHADERCOUNT m_pfnGetActiveShaderCount; + PFN_COLORSHADERFORNAME m_pfnColorShader_ForName; + PFN_SHADERFORNAMENOLOAD m_pfnShader_ForName_NoLoad; + PFN_ACTIVESHADERSSETINUSE m_pfnActiveShaders_SetInUse; + PFN_SORTACTIVESHADERS m_pfnSortActiveShaders; + PFN_ACTIVESHADERFORTEXTURENAME m_pfnActiveShader_ForTextureName; + PFN_CREATESHADERFORTEXTURENAME m_pfnCreateShader_ForTextureName; + PFN_ACTIVESHADERSSETDISPLAYED m_pfnActiveShaders_SetDisplayed; + PFN_ACTIVESHADERFORINDEX m_pfnActiveShader_ForIndex; + PFN_CLEANTEXTURENAME m_pfnCleanTextureName; +}; + +/*! +\todo FIXME fix the QERApp_ prototyping on shaders module +make it homogeneous with other modules, should be straight calls +*/ + +#ifdef USE_SHADERSTABLE_DEFINE + #ifndef __SHADERSTABLENAME + #define __SHADERSTABLENAME g_ShadersTable + #endif +#define QERApp_Shader_ForName __SHADERSTABLENAME.m_pfnShader_ForName +#define QERApp_Texture_ForName2 __SHADERSTABLENAME.m_pfnTexture_ForName +#define QERApp_FreeShaders __SHADERSTABLENAME.m_pfnFreeShaders +#define QERApp_ReloadShaders __SHADERSTABLENAME.m_pfnReloadShaders +#define QERApp_SortActiveShaders __SHADERSTABLENAME.m_pfnSortActiveShaders +#define QERApp_ReloadShaderFile __SHADERSTABLENAME.m_pfnReloadShaderFile +#define QERApp_LoadShaderFile __SHADERSTABLENAME.m_pfnLoadShaderFile +#define QERApp_HasShader __SHADERSTABLENAME.m_pfnHasShader +#define QERApp_Try_Shader_ForName __SHADERSTABLENAME.m_pfnTry_Shader_ForName +#define QERApp_Try_Texture_ForName __SHADERSTABLENAME.m_pfnTry_Texture_ForName +#define QERApp_ColorShader_ForName __SHADERSTABLENAME.m_pfnColorShader_ForName +#define QERApp_Shader_ForName_NoLoad __SHADERSTABLENAME.m_pfnShader_ForName_NoLoad +#define QERApp_LoadShadersFromDir __SHADERSTABLENAME.m_pfnLoadShadersFromDir +#define QERApp_LoadShadersFromDir __SHADERSTABLENAME.m_pfnLoadShadersFromDir +#define QERApp_CreateShader_ForTextureName __SHADERSTABLENAME.m_pfnCreateShader_ForTextureName +#define QERApp_GetActiveShaderCount __SHADERSTABLENAME.m_pfnGetActiveShaderCount +#define QERApp_ActiveShaders_SetDisplayed __SHADERSTABLENAME.m_pfnActiveShaders_SetDisplayed +#define QERApp_ActiveShader_ForIndex __SHADERSTABLENAME.m_pfnActiveShader_ForIndex +#define QERApp_ActiveShaders_SetInUse __SHADERSTABLENAME.m_pfnActiveShaders_SetInUse +#define QERApp_ActiveShader_ForTextureName __SHADERSTABLENAME.m_pfnActiveShader_ForTextureName +#define QERApp_ActiveShader_ForIndex __SHADERSTABLENAME.m_pfnActiveShader_ForIndex +#define QERApp_CleanTextureName __SHADERSTABLENAME.m_pfnCleanTextureName +#endif + +#define APPSHADERS_MAJOR "appshaders" +// FIXME: remove +static const GUID QERAppShadersTable_GUID = +{ 0xec3008a8, 0xbd0b, 0x11d4, { 0x82, 0x51, 0x20, 0x4c, 0x4f, 0x4f, 0x50, 0x20 } }; + +// g_qeglobals.d_qtextures is used internally by the editor for actual camera drawing +typedef qtexture_t** (WINAPI* PFN_QTEXTURES)(); +// g_qeglobals.d_qtexmap is a map for fast access +typedef GHashTable* (WINAPI* PFN_QTEXMAP)(); +// d_texturewin +//++timo NOTE: this same function is also in isurface.h table, we would eventually have to merge some stuff +typedef texturewin_t* (* PFN_QEGLOBALSTEXTUREWIN)(); +// Texture_SetTexture +//++timo NOTE: this one may have to be reorganized too .. putting it here is a bit clumsy +// NOTE: the C++ function used internally has a lot of default values +typedef void (WINAPI* PFN_TEXTURESETTEXTURE)(texdef_t *texdef, brushprimit_texdef_t *brushprimit_texdef); +// Texture_ShowInuse +typedef void (WINAPI* PFN_TEXTURESHOWINUSE)(); +// BuildShaderList +typedef void (* PFN_BUILDSHADERLIST)(); +// PreloadShaders +typedef void (* PFN_PRELOADSHADERS)(); + +// a table that Radiant makes available to the shader module in return +struct _QERAppShadersTable +{ + int m_nSize; + PFN_QTEXTURES m_pfnQTextures; + PFN_QTEXMAP m_pfnQTexmap; + PFN_QEGLOBALSTEXTUREWIN m_pfnQeglobalsTexturewin; + PFN_TEXTURESETTEXTURE m_pfnTexture_SetTexture; + PFN_TEXTURESHOWINUSE m_pfnTexture_ShowInuse; + PFN_BUILDSHADERLIST m_pfnBuildShaderList; + PFN_PRELOADSHADERS m_pfnPreloadShaders; +}; + +#ifdef USE_APPSHADERSTABLE_DEFINE + #ifndef __APPSHADERTABLENAME + #define __APPSHADERTABLENAME g_AppShadersTable + #endif +#define Texture_ShowInuse __APPSHADERTABLENAME.m_pfnTexture_ShowInuse +#endif + +/*! +NOTE TTimo: there is an important distinction between SHADER_NOT_FOUND and SHADER_NOTEX: +SHADER_NOT_FOUND means we didn't find the raw texture or the shader for this +SHADER_NOTEX means we recognize this as a shader script, but we are missing the texture to represent it +this was in the initial design of the shader code since early GtkRadiant alpha, and got sort of foxed in 1.2 and put back in +*/ +#define SHADER_NOT_FOUND "textures/radiant/notex" +#define SHADER_NOTEX "textures/radiant/shadernotex" ///< Q3 tech specific + +#endif diff --git a/include/ishadersmanager.h b/include/ishadersmanager.h new file mode 100644 index 00000000..a9bf0f03 --- /dev/null +++ b/include/ishadersmanager.h @@ -0,0 +1,102 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _ISHADERSMANAGER_H_ +#define _ISHADERSMANAGER_H_ + +class IShadersManager +{ + public: + IShadersManager (); + virtual ~IShadersManager (); + + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + + // free all shaders + // free the shaders, will not free the qtexture_t* + virtual void FreeShaders () = 0; + + // reload all the shaders + // this will free everything (shaders and their textures), then reload all in use stuff + virtual void ReloadShaders () = 0; + + // load all shaders in a given directory + // this will scan the list of in-memory shaders, and load the related qtexture_t if needed + virtual void LoadShadersFromDir (const char* path) = 0; + + // load a shader file (ie a set of shaders) + // after LoadShaderFile shaders will be in memory, next step is to load the qtexture_t Radiant uses + // to represent them if a shader with the same name exists, new one will not be loaded + // don't use this to refresh the shaders! + virtual void LoadShaderFile (const char* filename) = 0; + + // tell if a given shader exists in our shader table + // NOTE: this doesn't tell wether it's corresponding qtexture is loaded + virtual int HasShader (const char* name) = 0; + + // return the shader for a given name + // if the qtexture is not already in memory, will try loading it + // if the qtexture could not be found, will use default + // will return NULL on shader not found + virtual IShader* Try_Shader_ForName (const char* name) = 0; + + // return the shader for a given name + // if the qtexture is not already in memory, will try loading it + // will create a default shader if not found (will use a default texture) + virtual IShader* Shader_ForName (const char* name) = 0; + + // query / load a texture + // will not try loading a shader, will look for the actual image file .. + // returns NULL on file not found + // NOTE: strategy for file lookup: + // paths must be relative, ie. textures/me/myfile + // if a 3-letters filename extension (such as .jpg or .tga) is provided, it will get loaded first + // if not found or no extension, will try loading after adding .tga and .jpg (in this order) + virtual qtexture_t* Try_Texture_ForName (const char* filename) = 0; + + // query / load a texture + // will not try loading a shader, will look for the actual image file .. + // on file not found will use the "texture not found" + virtual qtexture_t* Texture_ForName (const char* filename) = 0; + + // get the number of active shaders + // these are the shaders currently loaded, that have an associated qtexture_t* + virtual int GetActiveShaderCount () = 0; + + // for stuff that needs to be represented by a plain texture + // the shader will get a "color" name, use GetColor to get the actual color + virtual IShader* ColorShader_ForName (const char* name) = 0; + + // reload a shaderfile - update shaders and their display properties/qtexture_t if needed + // will not reload the texture files + // will switch to "show in use" atfer use + // filename must be reletive path of the shader, ex. scripts/gothic_wall.shader + virtual void ReloadShaderFile (const char* filename) = 0; + + // retrieve a shader if exists, without loading the textures for it etc. + // use this function if you want special info on a shader + virtual IShader* Shader_ForName_NoLoad (const char* name) = 0; +}; + +#endif // _ISHADERSMANAGER_H_ diff --git a/include/isurfaceplugin.h b/include/isurfaceplugin.h new file mode 100644 index 00000000..6783bb2c --- /dev/null +++ b/include/isurfaceplugin.h @@ -0,0 +1,158 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// +// + +#ifndef __ISURFACEPLUGIN_H_ +#define __ISURFACEPLUGIN_H_ + +typedef struct _GtkWidget GtkWidget; +typedef struct _GtkWindow GtkWindow; + +#define SURFACEDIALOG_MAJOR "surfdialog" + +// there's a void* in each qtexture_t, must be casted to a IPluginTexdef* +// there's a void* in each face_t, must be casted to a IPluginTexdef* +// NOTE: IPluginTexdef stores a pointer to the qtexture_t or face_t it's stored in +// members of IPluginTexdef often access the qtexture_t or face_t they are connected to + +// Write texdef needs a function pointer, because Radiant either writes into a FILE or a CMemFile +typedef void (* PFN_QERAPP_MAPPRINTF) ( char *text, ... ); + +class IPluginTexdef +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; +}; + + + +// Nurail: For SI module +class texdef_to_face_t +{ +public: + texdef_to_face_t* next; + brush_t *brush; // Brush faces belong to (for Undo) + face_t *face; // Face of Texdef + texdef_t texdef; // Working texdef + texdef_t orig_texdef; // Original, for baselining changes +}; + + +typedef void (* PFN_QERPLUG_DOSURFACE) (); +typedef void (* PFN_QERPLUG_TOGGLESURFACE) (); +typedef void (* PFN_QERPLUG_UPDATESURFACEDIALOG) (); +typedef void (* PFN_QERPLUG_SURFACEDLGFITALL) (); +typedef GtkWidget* (* PFN_GET_SI_MODULE_WIDGET) (); + +struct _QERPlugSurfaceTable +{ + int m_nSize; + PFN_QERPLUG_TOGGLESURFACE m_pfnToggleSurface; + PFN_QERPLUG_DOSURFACE m_pfnDoSurface; + PFN_QERPLUG_UPDATESURFACEDIALOG m_pfnUpdateSurfaceDialog; + PFN_QERPLUG_SURFACEDLGFITALL m_pfnSurfaceDlgFitAll; + PFN_GET_SI_MODULE_WIDGET m_pfnGet_SI_Module_Widget; +}; + +// this one is used by the plugin to access some Radiant stuff + +#define APPSURFACEDIALOG_MAJOR "appsurfdialog" + +// {42BAE4C0-9787-11d3-8EF3-0000E8E8657B} +static const GUID QERAppSurfaceTable_GUID = +{ 0x42bae4c0, 0x9787, 0x11d3, { 0x8e, 0xf3, 0x0, 0x0, 0xe8, 0xe8, 0x65, 0x7b } }; + +typedef bool (* PFN_PATCHESSELECTED) (); +// retrieve g_qeglobals.texturewin_t +//++timo FIXME: this should move in a dedicated table for all g_qeglobals stuff +typedef texturewin_t* (* PFN_QEGLOBALSTEXTUREWIN) (); +// look for the first selected patch mesh +//++timo FIXME: this is a convenient func since there's no way to scan patches ( yet ) +typedef patchMesh_t* (* PFN_GETSELECTEDPATCH) (); +//++timo FIXME: this one in particular is a hack +typedef void (* PFN_GETTWOSELECTEDPATCH) (patchMesh_t **p1, patchMesh_t **p2); + + +// leo FIXME: hacks uglier than the ones above +typedef void (* PFN_TEXMATTOFAKETEXCOORDS) (vec_t texMat[2][3], float shift[2], float *rot, float scale[2]); +typedef void (* PFN_CONVERTTEXMATWITHQTEXTURE) (brushprimit_texdef_t *texMat1, qtexture_t *qtex1, brushprimit_texdef_t *texMat2, qtexture_t *qtex2); +typedef void (* PFN_FAKETEXCOORDSTOTEXMAT) (float shift[2], float rot, float scale[2], vec_t texMat[2][3]); +typedef void (* PFN_PATCH_RESETTEXTURING) (float fx, float fy); +typedef void (* PFN_PATCH_FITTEXTURING) (); +typedef void (* PFN_PATCH_NATURALIZESELECTED) (bool bCap); +typedef const char* (* PFN_PATCH_GETTEXTURENAME) (); +typedef qboolean (* PFN_QE_SINGLEBRUSH) (bool bQuiet); +typedef qboolean (* PFN_ISBRUSHPRIMITMODE) (); +typedef void (* PFN_SELECT_FITTEXTURE)(int nHeight, int nWidth); +typedef void (*PFN_COMPUTEAXISBASE)(vec3_t normal,vec3_t texS,vec3_t texT ); +typedef void (*PFN_BPMATMUL)(vec_t A[2][3], vec_t B[2][3], vec_t C[2][3]); +typedef void (*PFN_EMITBRUSHPRIMITTEXCOORDS)(face_t * f, winding_t * w); +typedef texdef_t* (*PFN_QEGLOBALSSAVEDINFO_SIINC) (); +typedef float (* PFN_QEGLOBALSGETGRIDSIZE) (); +typedef void (* PFN_FACELIST_FITTEXTURE) (texdef_to_face_t* texdef_face_list, int nHeight, int nWidth); +typedef GtkWindow* (* PFN_GETMAINWINDOW)(); +typedef void (* PFN_SETWINPOS_FROM_PREFS) (GtkWidget *win); +typedef int (* PFN_GETSELECTEDFACECOUNT_BRUSH) (); +typedef void (* PFN_GETSELFACESTEXDEF) (texdef_to_face_t *); +typedef void (* PFN_SETTEXDEF_FACELIST) (texdef_to_face_t* texdef_face_list, bool b_SetUndoPoint, bool bFit_to_Scale); +typedef void (* PFN_SETACTIVEINRADIANT) (); + + +struct _QERAppSurfaceTable +{ + int m_nSize; + PFN_PATCHESSELECTED m_pfnOnlyPatchesSelected; + PFN_PATCHESSELECTED m_pfnAnyPatchesSelected; + PFN_GETSELECTEDPATCH m_pfnGetSelectedPatch; + PFN_GETTWOSELECTEDPATCH m_pfnGetTwoSelectedPatch; + PFN_TEXMATTOFAKETEXCOORDS m_pfnTexMatToFakeTexCoords; + PFN_CONVERTTEXMATWITHQTEXTURE m_pfnConvertTexMatWithQTexture; + PFN_FAKETEXCOORDSTOTEXMAT m_pfnFakeTexCoordsToTexMat; + PFN_PATCH_RESETTEXTURING m_pfnPatch_ResetTexturing; + PFN_PATCH_FITTEXTURING m_pfnPatch_FitTexturing; + PFN_PATCH_NATURALIZESELECTED m_pfnPatch_NaturalizeSelected; + PFN_PATCH_GETTEXTURENAME m_pfnPatch_GetTextureName; + PFN_QE_SINGLEBRUSH m_pfnQE_SingleBrush; + PFN_ISBRUSHPRIMITMODE m_pfnIsBrushPrimitMode; + PFN_COMPUTEAXISBASE m_pfnComputeAxisBase; + PFN_BPMATMUL m_pfnBPMatMul; + PFN_EMITBRUSHPRIMITTEXCOORDS m_pfnEmitBrushPrimitTextureCoordinates; + PFN_QEGLOBALSTEXTUREWIN m_pfnQeglobalsTexturewin; + PFN_SELECT_FITTEXTURE m_pfnSelect_FitTexture; + PFN_QEGLOBALSSAVEDINFO_SIINC m_pfnQERApp_QeglobalsSavedinfo_SIInc; + PFN_QEGLOBALSGETGRIDSIZE m_pfnQeglobalsGetGridSize; + PFN_FACELIST_FITTEXTURE m_pfnFaceList_FitTexture; + PFN_GETMAINWINDOW m_pfnGetMainWindow; + PFN_SETWINPOS_FROM_PREFS m_pfnSetWinPos_From_Prefs; + PFN_GETSELECTEDFACECOUNT_BRUSH m_pfnGetSelectedFaceCountfromBrushes; + PFN_GETSELFACESTEXDEF m_pfnGetSelFacesTexdef; + PFN_SETTEXDEF_FACELIST m_pfnSetTexdef_FaceList; +}; + +#endif diff --git a/include/itoolbar.h b/include/itoolbar.h new file mode 100644 index 00000000..05a05559 --- /dev/null +++ b/include/itoolbar.h @@ -0,0 +1,61 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __IPLUGTOOLBAR_H_ +#define __IPLUGTOOLBAR_H_ + +/* +NOTE: this API requires Gtk +it's a good practice to avoid putting #include here +in some cases, the compiler will get confused because of 'list' identifiers between Gtk and STL headers +*/ + +#define TOOLBAR_MAJOR "toolbar" + +class IToolbarButton +{ +public: + enum EType + { + eSpace, + eButton, + eToggleButton, + eRadioButton, + }; + + virtual const char* getImage() const = 0; + virtual const char* getText() const = 0; + virtual const char* getTooltip() const = 0; + virtual EType getType() const = 0; + virtual void activate() const = 0; +}; + +typedef unsigned int (* PFN_TOOLBARBUTTONCOUNT)(); +typedef const IToolbarButton* (* PFN_GETTOOLBARBUTTON)(unsigned int index); + +struct _QERPlugToolbarTable +{ + int m_nSize; + PFN_TOOLBARBUTTONCOUNT m_pfnToolbarButtonCount; + PFN_GETTOOLBARBUTTON m_pfnGetToolbarButton; +}; + +#endif diff --git a/include/iui.h b/include/iui.h new file mode 100644 index 00000000..16b7c8cd --- /dev/null +++ b/include/iui.h @@ -0,0 +1,158 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION: +// interface for all-purpose messaging and UI +// window class for MFC, Gtk or Q3 UI +// each version of Radiant implements the API, using the native code that it needs + +#ifndef __IUI_H_ +#define __IUI_H_ + +// this one can be hooked in the GL window procs for customizing GUI through plugins +// the class is implemented by the plugin module, and given to Radiant who calls into it +class IWindowListener +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + // since Radiant is MFC we don't use a WNDPROC, we wrap the MFC handlers + // the handler is called first, if returns false Radiant continues processing + //++timo maybe add more later ? OnKeyUp and OnKeyDown for instance + //++timo TODO: add handlers everywhere + // Gef: Changed 2nd & 3rd params to gdouble's for sub-integer grid sizes + virtual bool OnLButtonDown(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnMButtonDown(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnRButtonDown(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnLButtonUp(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnMButtonUp(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnRButtonUp(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnMouseMove(guint32 nFlags, gdouble x, gdouble y) = 0; + virtual bool OnKeyPressed(char *s) = 0; + + // paint message, the caller makes the GL context current, calls Paint, then swaps GL buffers + // return value might be false if something failed and closure is requested .. then the buffer swap will be cancelled + virtual bool Paint() = 0; + // window is closing (nothing you can do, just telling) + virtual void Close() = 0; +}; + +// IWindowListener with additional properties +// NOTE: for now it is both a window and the GL widget +// in the case of Gtk, there are two widgets, the window widget (a container) and the GL widget +class IWindow +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + // misc data ------------------------------------------------ + // get pixel size + virtual int getHeight() = 0; + virtual int getWidth() = 0; + // initialisation stuff ------------------------------------- + // set pixel size and other parameters before showing it + virtual void setSizeParm(int width, int height) = 0; + // set the IWindowListener (implemented by the plugin using this window) + virtual void setListener(IWindowListener *) = 0; + // set the window name + virtual void setName(char *) = 0; + // will actually create the GL and the window based on the parameters + virtual bool Show() = 0; + // commands ------------------------------------------------- + // call this to ask for a Redraw + virtual void Redraw() = 0; +}; + +// various Radiant messages -------- +// this one holds the total number of supported messages (this is used to allocate structs) +#define RADIANT_MSGCOUNT 5 +// they start with a 0, can be indexed in an array +// something was selected / deselected +#define RADIANT_SELECTION 0 +// a brush face was selected / deselected +#define RADIANT_SFACE 1 +// current texture / shader changed +#define RADIANT_TEXTURE 2 +// Radiant is going to enter "sleep mode" (all GL contexts will be destroyed) +#define RADIANT_SLEEP 3 +// Radiant has left "sleep mode" (GL contexts are recreated) +#define RADIANT_WAKEUP 4 + + +// this one can be used to listen for Radiant-specific events, not related to a window +class IListener +{ +public: + // Increment the number of references to this object + virtual void IncRef () = 0; + // Decrement the reference count + virtual void DecRef () = 0; + // message is one of the RADIANT_* consts + virtual void DispatchRadiantMsg( int Msg ) = 0; +}; + +// this one is provided by Radiant, it's a wrapper for some usefull functions +class IXYWndWrapper +{ +public: + virtual void SnapToGrid( int x1, int y1, vec3_t pt ) = 0; + virtual VIEWTYPE GetViewType( void ) = 0; +}; + +#define UI_MAJOR "ui" + +// create an IWindow with GL context +typedef IWindow* (WINAPI* PFN_QERAPP_CREATEGLWINDOW) (); + +// will hook the given IWindowListener to the XY window and increment the ref count +//++timo TODO: add hooking in the CAM view and Z view +typedef void (WINAPI* PFN_QERAPP_HOOKWINDOW) (IWindowListener *); +// will unhook the given IWindowListener +typedef void (WINAPI* PFN_QERAPP_UNHOOKWINDOW) (IWindowListener *); +// to retrieve the IXYWndWrapper +typedef IXYWndWrapper* (WINAPI* PFN_QERAPP_GETXYWNDWRAPPER) (); + +// will hook a given listener into Radiant listening for the given message and increment ref count +// call several times to listen for several messages +typedef void (WINAPI* PFN_QERAPP_HOOKLISTENER) (IListener *, int Msg); +// will unhook the listener and return the number of messages the given listener was removed from +typedef int (WINAPI* PFN_QERAPP_UNHOOKLISTENER)(IListener *); + +// TODO: create GL widget, destroy it + +struct _QERUITable +{ + int m_nSize; + PFN_QERAPP_CREATEGLWINDOW m_pfnCreateGLWindow; + PFN_QERAPP_HOOKWINDOW m_pfnHookWindow; + PFN_QERAPP_UNHOOKWINDOW m_pfnUnHookWindow; + PFN_QERAPP_GETXYWNDWRAPPER m_pfnGetXYWndWrapper; + PFN_QERAPP_HOOKLISTENER m_pfnHookListener; + PFN_QERAPP_UNHOOKLISTENER m_pfnUnHookListener; +}; + +#endif diff --git a/include/iui_gtk.h b/include/iui_gtk.h new file mode 100644 index 00000000..5cd820c4 --- /dev/null +++ b/include/iui_gtk.h @@ -0,0 +1,59 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//----------------------------------------------------------------------------- +// +// DESCRIPTION +// This contains functions specific to the UI toolkit +// it is best to avoid using them, but they are provided for backward compatibility with the older interfaces +// the abstracted UI layer in iUI.h is not sufficient for some tasks .. no other choice than to rely on UI specific code + +#ifndef __IGL_GTK_H__ +#define __IGL_GTK_H__ + +#define UIGTK_MAJOR "uigtk" + +// All OpenGL stuff is handled by GLWidget to ensure portability +typedef GtkWidget* (WINAPI* PFN_QERAPP_GETQEGLOBALSGLWIDGET) (); +typedef GtkWidget* (WINAPI* PFN_GLWIDGET_NEW) (gboolean zbufffer, GtkWidget* share); +typedef void (WINAPI* PFN_GLWIDGET_SWAPBUFFERS) (GtkWidget* widget); +typedef gboolean (WINAPI* PFN_GLWIDGET_MAKECURRENT) (GtkWidget* widget); +typedef void (WINAPI* PFN_GLWIDGET_DESTROYCONTEXT) (GtkWidget* widget); +typedef void (WINAPI* PFN_GLWIDGET_CREATECONTEXT) (GtkWidget* widget); +#if 0 +typedef gpointer (WINAPI* PFN_GLWIDGET_GETCONTEXT) (GtkWidget* widget); +#endif + +struct _QERUIGtkTable +{ + int m_nSize; + PFN_QERAPP_GETQEGLOBALSGLWIDGET m_pfn_GetQeglobalsGLWidget; + PFN_GLWIDGET_NEW m_pfn_glwidget_new; + PFN_GLWIDGET_SWAPBUFFERS m_pfn_glwidget_swap_buffers; + PFN_GLWIDGET_MAKECURRENT m_pfn_glwidget_make_current; + PFN_GLWIDGET_DESTROYCONTEXT m_pfn_glwidget_destroy_context; + PFN_GLWIDGET_CREATECONTEXT m_pfn_glwidget_create_context; +#if 0 + PFN_GLWIDGET_GETCONTEXT m_pfn_glwidget_get_context; +#endif +}; + +#endif diff --git a/include/iundo.h b/include/iundo.h new file mode 100644 index 00000000..d5194b52 --- /dev/null +++ b/include/iundo.h @@ -0,0 +1,87 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _IUNDO_H_ +#define _IUNDO_H_ + +#define UNDO_MAJOR "undo" + +//start operation +typedef void (*PFN_UNDOSTART) (char *operation); +//end operation +typedef void (*PFN_UNDOEND) (void); +//add brush to the undo +typedef void (*PFN_UNDOADDBRUSH) (brush_t *pBrush); +//end a brush after the operation is performed +typedef void (*PFN_UNDOENDBRUSH) (brush_t *pBrush); +//add a list with brushes to the undo +typedef void (*PFN_UNDOADDBRUSHLIST) (brush_t *brushlist); +//end a list with brushes after the operation is performed +typedef void (*PFN_UNDOENDBRUSHLIST) (brush_t *brushlist); +//add entity to undo +typedef void (*PFN_UNDOADDENTITY) (entity_t *entity); +//end an entity after the operation is performed +typedef void (*PFN_UNDOENDENTITY) (entity_t *entity); +//undo last operation (bSilent == true -> will not print the "undone blah blah message") +typedef void (*PFN_UNDO) (unsigned char bSilent); +//redo last undone operation +typedef void (*PFN_REDO) (void); +//get the undo Id of the next undo (0 if none available) +typedef int (*PFN_GETUNDOID) (void); +//returns true if there is something to be undone available +typedef int (*PFN_UNDOAVAILABLE) (void); +//returns true if there is something to redo available +typedef int (*PFN_REDOAVAILABLE) (void); + +struct _QERUndoTable +{ + int m_nSize; + PFN_UNDOSTART m_pfnUndo_Start; + PFN_UNDOEND m_pfnUndo_End; + PFN_UNDOADDBRUSH m_pfnUndo_AddBrush; + PFN_UNDOENDBRUSH m_pfnUndo_EndBrush; + PFN_UNDOADDBRUSHLIST m_pfnUndo_AddBrushList; + PFN_UNDOENDBRUSHLIST m_pfnUndo_EndBrushList; + PFN_UNDOADDENTITY m_pfnUndo_AddEntity; + PFN_UNDOENDENTITY m_pfnUndo_EndEntity; + PFN_UNDO m_pfnUndo_Undo; + PFN_REDO m_pfnUndo_Redo; + PFN_GETUNDOID m_pfnUndo_GetUndoId; + PFN_UNDOAVAILABLE m_pfnUndo_UndoAvailable; + PFN_REDOAVAILABLE m_pfnUndo_RedoAvailable; +}; + +#ifdef USE_UNDOTABLE_DEFINE +#ifndef __UNDOTABLENAME +#define __UNDOTABLENAME g_UndoTable +#endif +#define Undo_Start __UNDOTABLENAME.m_pfnUndo_Start +#define Undo_End __UNDOTABLENAME.m_pfnUndo_End +#define Undo_AddBrush __UNDOTABLENAME.m_pfnUndo_AddBrush +#define Undo_EndBrush __UNDOTABLENAME.m_pfnUndo_EndBrush +#define Undo_AddBrushList __UNDOTABLENAME.m_pfnUndo_AddBrushList +#define Undo_EndBrushList __UNDOTABLENAME.m_pfnUndo_EndBrushList +#define Undo_AddEntity __UNDOTABLENAME.m_pfnUndo_AddEntity +#define Undo_EndEntity __UNDOTABLENAME.m_pfnUndo_EndEntity +#endif + +#endif // _IUNDO_H_ + diff --git a/include/misc_def.h b/include/misc_def.h new file mode 100644 index 00000000..ea5a600b --- /dev/null +++ b/include/misc_def.h @@ -0,0 +1,64 @@ +#ifndef _WIN32 + +#define WINAPI +#define APIENTRY + +typedef void* HMODULE; +typedef void* LPVOID; +typedef char* LPCSTR; +typedef char* LPSTR; + +#define IsEqualGUID(a,b) (memcmp(&a,&b,sizeof(a)) == 0) + +#ifndef GUID_DEFINED +#define GUID_DEFINED +typedef struct _GUID +{ + unsigned long Data1; + unsigned short Data2; + unsigned short Data3; + unsigned char Data4[8]; +} GUID; +#endif + +#if defined(__cplusplus) +#ifndef _REFGUID_DEFINED +#define _REFGUID_DEFINED +#define REFGUID const GUID & +#endif // !_REFGUID_DEFINED +#endif + +// Message box constants +#define MB_OK 0x00000000L +#define MB_OKCANCEL 0x00000001L +#define MB_ABORTRETRYIGNORE 0x00000002L +#define MB_YESNOCANCEL 0x00000003L +#define MB_YESNO 0x00000004L +#define MB_RETRYCANCEL 0x00000005L + +#define MB_ICONHAND 0x00000010L +#define MB_ICONQUESTION 0x00000020L +#define MB_ICONEXCLAMATION 0x00000030L +#define MB_ICONASTERISK 0x00000040L + +#define MB_USERICON 0x00000080L +#define MB_ICONWARNING MB_ICONEXCLAMATION +#define MB_ICONERROR MB_ICONHAND +#define MB_ICONINFORMATION MB_ICONASTERISK +#define MB_ICONSTOP MB_ICONHAND + +#define MB_TYPEMASK 0x0000000FL +#define MB_ICONMASK 0x000000F0L +#define MB_DEFMASK 0x00000F00L +#define MB_MODEMASK 0x00003000L +#define MB_MISCMASK 0x0000C000L + +#define IDOK 1 +#define IDCANCEL 2 +#define IDABORT 3 +#define IDRETRY 4 +#define IDIGNORE 5 +#define IDYES 6 +#define IDNO 7 + +#endif diff --git a/include/qerplugin.h b/include/qerplugin.h new file mode 100644 index 00000000..907a4bee --- /dev/null +++ b/include/qerplugin.h @@ -0,0 +1,787 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// QERadiant PlugIns +// +// + +#ifndef __QERPLUGIN_H__ +#define __QERPLUGIN_H__ + +/*! +\todo this header is intended to be turned into a header for the core editor functionality +some portability related code should be moved to synapse (such as the GUID stuff) +*/ + +#include +#include +// TTimo +// ideally the plugin API would be UI toolkit independent, but removing the dependency with GLib seems tricky right now.. +#include +#include "qertypes.h" + +// FIXME TTimo: +// GUID declaration here should be trashed, it is in synapse.h +#ifdef _WIN32 +#include +#endif + +#define QER_MAX_NAMELEN 1024 + +#ifndef _WIN32 +#include "misc_def.h" +#endif + +// the editor will look for plugins in two places, the plugins path +// under the application path, and the path under the basepath as defined +// in the project (.qe4) file. +// +// you can drop any number of new texture, model format DLL's in the standard plugin path +// but only one plugin that overrides map loading/saving, surface dialog, surface flags, etc.. +// should be used at one time.. if multiples are loaded then the last one loaded will be the +// active one +// +// type of services the plugin supplies, pass any combo of these flags +// it is assumed the plugin will have a matching function as defined below +// to correlate to the implied functionality +// + +#define RADIANT_MAJOR "radiant" + +// basics +#define QERPLUG_INIT "QERPlug_Init" +#define QERPLUG_GETNAME "QERPlug_GetName" +#define QERPLUG_GETCOMMANDLIST "QERPlug_GetCommandList" +#define QERPLUG_DISPATCH "QERPlug_Dispatch" +#define QERPLUG_GETFUNCTABLE "QERPlug_GetFuncTable" + +// game stuff +#define QERPLUG_GETTEXTUREINFO "QERPlug_GetTextureInfo" // gets a texture info structure +#define QERPLUG_LOADTEXTURE "QERPlug_LoadTexture" // loads a texture, will return an RGBA structure + // and any surface flags/contents for it +#define QERPLUG_GETSURFACEFLAGS "QERPlug_GetSurfaceFlags" // gets a list of surface/content flag names from a plugin + +struct _QERTextureInfo +{ + char m_TextureExtension[QER_MAX_NAMELEN]; // the extension these textures have + qboolean m_bHiColor; // if textures are NOT high color, the default + // palette (as described inthe qe4 file will be used for gamma correction) + // if they are high color, gamma and shading are computed on the fly + // based on the rgba data + //--bool m_bIsShader; // will probably do q3 shaders this way when i merge + qboolean m_bWadStyle; // if this is true, the plugin will be presented with the texture path + // defined in the .qe4 file and is expected to preload all the textures + qboolean m_bHalfLife; // causes brushes to be saved/parsed without the surface contents/flags/value +}; + +struct _QERTextureLoad // returned by a plugin +{ + _QERTextureLoad() + { + memset(reinterpret_cast(this), 0, sizeof(_QERTextureLoad)); + }; + + ~_QERTextureLoad() + { + delete []m_pRGBA; + delete []m_pName; + }; + + void makeSpace(int nSize) + { + m_pRGBA = new unsigned char[nSize+1]; + }; + + void setName(const char* p) + { + m_pName = new char[strlen(p)+1]; + strcpy(m_pName, p); + }; + + + unsigned char *m_pRGBA; // rgba data (alpha channel is supported and drawn appropriately) + int m_nWidth; // width + int m_nHeight; // height + int m_nContents; // default contents + int m_nFlags; // "" flags + int m_nValue; // "" value + char *m_pName; // name to be referenced in map, build tools, etc. +}; + +struct _QERModelInfo +{ + char m_ModelExtension[QER_MAX_NAMELEN]; + bool m_bSkinned; + bool m_bMultipart; +}; + +struct _QERModelLoad +{ + // vertex and skin data +}; + + +//========================================= +// plugin functions +#if 0 +// NOTE TTimo: hack to make old plugin tech and new plugin tech live together +#ifndef _IPLUGIN_H_ +// toolkit-independant interface, cast hwndMain to GtkWidget* +typedef const char* (WINAPI *PFN_QERPLUG_INIT)(void* hApp, void* hwndMain); +typedef const char* (WINAPI *PFN_QERPLUG_GETNAME)(); +typedef const char* (WINAPI *PFN_QERPLUG_GETCOMMANDLIST)(); +typedef void (WINAPI *PFN_QERPLUG_DISPATCH)(const char* p, vec3_t vMin, vec3_t vMax, bool bSingleBrush); +#endif +#endif + +typedef char* (WINAPI *PFN_QERPLUG_GETFUNCTABLE)(); + +// v1.5 +// +// Texture loading +// returns a ptr to _QERTextureInfo +typedef void* (WINAPI *PFN_QERPLUG_GETTEXTUREINFO)(); +// +// loads a texture by calling the texture load func in the editor (defined below) +// transparency (for water, fog, lava, etc.. ) can be emulated in the editor +// by passing in appropriate alpha data or by setting the appropriate surface flags +// expected by q2 (which the editor will use.. ) +typedef void (WINAPI *PFN_QERPLUG_LOADTEXTURE)(const char* pFilename); + +// v1.6 +typedef void* (WINAPI *PFN_QERPLUG_GETSURFACEFLAGS)(); + +// v1.7 +// if exists in plugin, gets called between INIT and GETCOMMANDLIST +// the plugin can register the EClasses he wants to handle +//++timo TODO: this has got to move into the table, and be requested by QERPlug_RequestInterface +//++timo FIXME: the LPVOID parameter must be casted to an IEpair interface +#define QERPLUG_REGISTERPLUGINENTITIES "QERPlug_RegisterPluginEntities" +typedef void (WINAPI * PFN_QERPLUG_REGISTERPLUGINENTITIES)( void* ); + +// if exists in plugin, gets called between INIT and GETCOMMANDLIST +// the plugin can Init all it needs for surface properties +#define QERPLUG_INITSURFACEPROPERTIES "QERPlug_InitSurfaceProperties" +typedef void (WINAPI * PFN_QERPLUG_INITSURFACEPROPERTIES)(); + +// if Radiant needs to use a particular set of commands, it can request the plugin to fill a func table +// this is similar to PFN_QERAPP_REQUESTINTERFACE +#define QERPLUG_REQUESTINTERFACE "QERPlug_RequestInterface" +typedef int (WINAPI * PFN_QERPLUG_REQUESTINTERFACE) (REFGUID refGUID, void* pInterface, const char *version_name); + +// Load an image file +typedef void (* PFN_QERAPP_LOADIMAGE) (const char *name, unsigned char **pic, int *width, int *height); + +// TTimo FIXME: the logic for this is in synapse now + +// MODULES specific: +// if it exports this entry point, will be considered as a module +// a module is a plugin that provides some REQUIRED interfaces to Radiant, such as the shader module +// Radiant will call QERPLUG_LISTINTERFACES to get a list of the interfaces a given plugin implements +// then it will call PFN_QERPLUG_REQUESTINTERFACE to actually get them + +// following leo's code .. looks ok to use a string to identify the various versions of a same interface +// obviously it would be handy to have the same string naming for the interfaces. +// best way would be to have the names come in when you list the interfaces +// NOTE: we might have a problem with the order in which the interfaces are filled in +// there's some kind of dependency graph, the shader module expects to find the VFS ready etc. +typedef struct moduleentry_s { + const GUID *interface_GUID; + const char* interface_name; + const char* version_name; +} moduleentry_t; + +#define QERPLUG_LISTINTERFACES "QERPlug_ListInterfaces" +#define MAX_QERPLUG_INTERFACES 10 +typedef int (WINAPI* PFN_QERPLUG_LISTINTERFACES) (moduleentry_t table[MAX_QERPLUG_INTERFACES]); + +// ======================================== +// GTK+ helper functions + +// NOTE: parent can be NULL in all functions but it's best to set them + +// simple Message Box, see above for the 'type' flags +// toolkit-independent, cast parent ot a GtkWidget* +typedef gint (WINAPI* PFN_QERAPP_MESSAGEBOX) (void *parent, const char* text, + const char* caption, guint32 type, const char *URL); + +// file and directory selection functions return NULL if the user hits cancel +// or a gchar* string that must be g_free'd by the user +// - 'title' is the dialog title (can be NULL) +// - 'path' is used to set the initial directory (can be NULL) +// - 'pattern': the first pattern is for the win32 mode, then comes the Gtk pattern list, see Radiant source for samples +// TTimo 04/01/2001 toolkit-independant, cast parent to a GtkWidget* +typedef const gchar* (* PFN_QERAPP_FILEDIALOG) (void *parent, gboolean open, const char* title, + const char* path, const char* pattern); +typedef gchar* (WINAPI* PFN_QERAPP_DIRDIALOG) (void *parent, const char* title, + const char* path); + +// return true if the user closed the dialog with 'Ok' +// 'color' is used to set the initial value and store the selected value +typedef bool (WINAPI* PFN_QERAPP_COLORDIALOG) (void *parent, float *color, + const char* title); + +// load a .bmp file and store the results in 'gdkpixmap' and 'mask' +// returns TRUE on success but even if it fails, it creates an empty pixmap +// NOTE: 'filename' is relative to /plugins/bitmaps/ +// TTimo 04/01/2001 toolkit-independant, cast gkpixmap to GdkPixmap and mask to GdkBitmap +typedef bool (WINAPI* PFN_QERAPP_LOADBITMAP) (const char* filename, void **gdkpixmap, void **mask); + +// ======================================== +// read/write preferences file + +// use this function to get the directory where the preferences file are stored +typedef const char* (WINAPI* PFN_QERAPP_PROFILE_GETDIR) (); + +// 'filename' is the absolute path +typedef bool (WINAPI* PFN_QERAPP_PROFILE_SAVEINT) (const char *filename, const char *section, + const char *key, int value); +typedef bool (WINAPI* PFN_QERAPP_PROFILE_SAVESTR) (const char *filename, const char *section, + const char *key, const char *value); +typedef int (WINAPI* PFN_QERAPP_PROFILE_LOADINT) (const char *filename, const char *section, + const char *key, int default_value); +typedef char* (WINAPI* PFN_QERAPP_PROFILE_LOADSTR) (const char *filename, const char *section, + const char *key, const char *default_value); + +//========================================= +// editor functions + +// There are 3 potential brush handle lists +// 1. the list that contains brushes a plugin creates using CreateBrushHandle +// 2. the selected brush list (brushes the user has selected) +// 3. the active brush list (brushes in the map that are not selected) +// +// In general, the same things can be done to brush handles (face manip, delete brushhandle, etc.. ) in each +// list. There are a few exceptions. +// 1. You cannot commit a selected or active brush handle to the map. This is because it is already in the map. +// 2. You cannot bind brush handles from the selected or active brush list to an entity. As of v1.0 of the plugins +// the only way for a plugin to create entities is to create a brush handles (or a list of handles) and then bind +// them to an entity. This will commit the brush(s) and/or the entities to the map as well. +// +// To use the active or selected brush lists, you must first allocate them (which returns a count) and then +// release them when you are finish manipulating brushes in one of those lists. + +//++timo NOTE : the #defines here are never used, but can help finding where things are done in the editor +#if 0 +// brush manipulation routines +#define QERAPP_CREATEBRUSH "QERApp_CreateBrush" +#define QERAPP_CREATEBRUSHHANDLE "QERApp_CreateBrushHandle" +#define QERAPP_DELETEBRUSHHANDLE "QERApp_DeleteBrushHandle" +#define QERAPP_COMMITBRUSHHANDLETOMAP "QERApp_CommitBrushHandleToMap" +//++timo not implemented .. remove +// #define QERAPP_BINDHANDLESTOENTITY "QERApp_BindHandlesToEntity" +#define QERAPP_ADDFACE "QERApp_AddFace" +#define QERAPP_ADDFACEDATA "QERApp_AddFaceData" +#define QERAPP_GETFACECOUNT "QERApp_GetFaceCount" +#define QERAPP_GETFACEDATA "QERApp_GetFaceData" +#define QERAPP_SETFACEDATA "QERApp_SetFaceData" +#define QERAPP_DELETEFACE "QERApp_DeleteFace" +#define QERAPP_TEXTUREBRUSH "QERApp_TextureBrush" +#define QERAPP_BUILDBRUSH "QERApp_BuildBrush" // PGM +#define QERAPP_SELECTEDBRUSHCOUNT "QERApp_SelectedBrushCount" +#define QERAPP_ALLOCATESELECTEDBRUSHHANDLES "QERApp_AllocateSelectedBrushHandles" +#define QERAPP_RELEASESELECTEDBRUSHHANDLES "QERApp_ReleaseSelectedBrushHandles" +#define QERAPP_GETSELECTEDBRUSHHANDLE "QERApp_GetSelectedBrushHandle" +#define QERAPP_ACTIVEBRUSHCOUNT "QERApp_ActiveBrushCount" +#define QERAPP_ALLOCATEACTIVEBRUSHHANDLES "QERApp_AllocateActiveBrushHandles" +#define QERAPP_RELEASEACTIVEBRUSHHANDLES "QERApp_ReleaseActiveBrushHandles" +#define QERAPP_GETACTIVEBRUSHHANDLE "QERApp_GetActiveBrushHandle" + +// texture stuff +#define QERAPP_TEXTURECOUNT "QERApp_TextureCount" +#define QERAPP_GETTEXTURE "QERApp_GetTexture" +#define QERAPP_GETCURRENTTEXTURE "QERApp_GetCurrentTexture" +#define QERAPP_SETCURRENTTEXTURE "QERApp_SetCurrentTexture" + +// selection +#define QERAPP_DELETESELECTION "QERApp_DeleteSelection" +#define QERAPP_SELECTBRUSH "QERApp_SelectBrush" // PGM +#define QERAPP_DESELECTBRUSH "QERApp_DeselectBrush" // PGM +#define QERAPP_DESELECTALLBRUSHES "QERApp_DeselectAllBrushes" // PGM + +// data gathering +#define QERAPP_GETPOINTS "QERApp_GetPoints" +#define QERAPP_SELECTBRUSHES "QERApp_GetBrushes" + +// entity class stuff +// the entity handling is very basic for 1.0 +#define QERAPP_GETECLASSCOUNT "QERApp_GetEClassCount" +#define QERAPP_GETECLASS "QERApp_GetEClass" + +// misc +#define QERAPP_SYSMSG "QERApp_SysMsg" +#define QERAPP_INFOMSG "QERApp_InfoMsg" +#define QERAPP_HIDEINFOMSG "QERApp_HideInfoMsg" +#define QERAPP_RESET_PLUGINS "QERApp_ResetPlugins" + +// texture loading +#define QERAPP_LOADTEXTURERGBA "QERApp_LoadTextureRGBA" + +// FIXME: the following are not implemented yet +// hook registrations +#define QERAPP_REGISTER_MAPLOADFUNC "QERApp_Register_MapLoadFunc" +#define QERAPP_REGISTER_MAPSAVEFUNC "QERApp_Register_MapSaveFunc" + +// FIXME: the following are not implemented yet +#define QERAPP_REGISTER_PROJECTLOADFUNC "QERApp_Register_ProjectLoadFunc" +#define QERAPP_REGISTER_MOUSEHANDLER "QERApp_Register_MouseHandler" +#define QERAPP_REGISTER_KEYHANDLER "QERApp_Register_KeyHandler" + +// FIXME: new primtives do not work in v1.00 +// primitives are new types of things in the map +// for instance, the Q3 curves could have been done as +// primitives instead of being built in +// it will be a plugins responsibility to hook the map load and save funcs to load +// and/or save any additional data (like new primitives of some type) +// the editor will call each registered renderer during the rendering process to repaint +// any primitives the plugin owns +// each primitive object has a temporary sibling brush that lives in the map +// FIXME: go backwards on this a bit.. orient it more towards the temp brush mode as it will be cleaner +// basically a plugin will hook the map load and save and will add the primitives to the map.. this will +// produce a temporary 'primitive' brush and the appropriate renderer will be called as well as the +// edit handler (for edge drags, sizes, rotates, etc.. ) and the vertex maker will be called when vertex +// mode is attemped on the brush.. there will need to be a GetPrimitiveBounds callback in the edit handler +// so the brush can resize appropriately as needed.. this might be the plugins responsibility to set the +// sibling brushes size.. it will then be the plugins responsibility to hook map save to save the primitives +// as the editor will discard any temp primitive brushes.. (there probably needs to be some kind of sanity check +// here as far as keeping the brushes and the plugin in sync.. i suppose the edit handler can deal with all of that +// crap but it looks like a nice place for a mess) +#define QERAPP_REGISTER_PRIMITIVE "QERApp_Register_Primitive" +#define QERAPP_REGISTER_RENDERER "QERApp_Register_Renderer" +#define QERAPP_REGISTER_EDITHANDLER "QERApp_Register_EditHandler" +#define QERAPP_REGISTER_VERTEXMAKER "QERApp_Register_VertexMaker" +#define QERAPP_ADDPRIMITIVE "QERApp_AddPrimitive" + +// v1.70 +#define QERAPP_GETENTITYCOUNT "QERApp_GetEntityCount" +#define QERAPP_GETENTITYHANDLE "QERApp_GetEntityHandle" +//++timo not implemented for the moment +// #define QERAPP_GETENTITYINFO "QERApp_GetEntityInfo" +//++timo does the keyval need some more funcs to add/remove ? +// get the pointer and do the changes yourself +#define QERAPP_ALLOCATEEPAIR "QERApp_AllocateEpair" +#define QERAPP_ALLOCATEENTITYBRUSHHANDLES "QERApp_AllocateEntityBrushHandles" +#define QERAPP_RELEASEENTITYBRUSHHANDLES "QERApp_ReleaseEntityBrushHandles" +#define QERAPP_GETENTITYBRUSHHANDLE "QERApp_GetEntityBrushHandle" +#define QERAPP_CREATEENTITYHANDLE "QERApp_CreateEntityHandle" +#define QERAPP_COMMITBRUSHHANDLETOENTITY "QERApp_CommitBrushHandleToEntity" +#define QERAPP_COMMITENTITYHANDLETOMAP "QERApp_CommitEntityHandleToMap" +#define QERAPP_SETSCREENUPDATE "QERApp_SetScreenUpdate" +#define QERAPP_BUILDBRUSH2 "QERApp_BuildBrush2" +#endif + +// v1.80 +#define QERAPP_GETDISPATCHPARAMS "QERApp_GetDispatchParams" + +struct _QERPointData +{ + int m_nCount; + vec3_t *m_pVectors; +}; + +struct _QERFaceData +{ + char m_TextureName[QER_MAX_NAMELEN]; + int m_nContents; + int m_nFlags; + int m_nValue; + float m_fShift[2]; + float m_fRotate; + float m_fScale[2]; + vec3_t m_v1, m_v2, m_v3; + // brush primitive additions + qboolean m_bBPrimit; + brushprimit_texdef_t brushprimit_texdef; +}; + +typedef void (WINAPI * PFN_QERAPP_CREATEBRUSH)(vec3_t vMin, vec3_t vMax); + +typedef void* (WINAPI * PFN_QERAPP_CREATEBRUSHHANDLE)(); +typedef void (WINAPI * PFN_QERAPP_DELETEBRUSHHANDLE)(void* pv); +typedef void (WINAPI * PFN_QERAPP_COMMITBRUSHHANDLETOMAP)(void* pv); +typedef void (WINAPI * PFN_QERAPP_ADDFACE)(void* pv, vec3_t v1, vec3_t v2, vec3_t v3); + +typedef void (WINAPI * PFN_QERAPP_ADDFACEDATA)(void* pv, _QERFaceData *pData); +typedef int (WINAPI * PFN_QERAPP_GETFACECOUNT)(void* pv); +typedef _QERFaceData* (WINAPI * PFN_QERAPP_GETFACEDATA)(void* pv, int nFaceIndex); +typedef void (WINAPI * PFN_QERAPP_SETFACEDATA)(void* pv, int nFaceIndex, _QERFaceData *pData); +typedef void (WINAPI * PFN_QERAPP_DELETEFACE)(void* pv, int nFaceIndex); +typedef void (WINAPI * PFN_QERAPP_TEXTUREBRUSH)(void* pv, char* pName); +typedef void (WINAPI * PFN_QERAPP_BUILDBRUSH)(void* pv); // PGM +typedef void (WINAPI * PFN_QERAPP_SELECTBRUSH)(void* pv); // PGM +typedef void (WINAPI * PFN_QERAPP_DESELECTBRUSH)(void* pv); // PGM +typedef void (WINAPI * PFN_QERAPP_DESELECTALLBRUSHES)(); // PGM + +typedef void (WINAPI * PFN_QERAPP_DELETESELECTION)(); +typedef void (WINAPI * PFN_QERAPP_GETPOINTS)(int nMax, _QERPointData *pData, char* pMsg); + +typedef int (WINAPI * PFN_QERAPP_SELECTEDBRUSHCOUNT)(); +typedef int (WINAPI * PFN_QERAPP_ALLOCATESELECTEDBRUSHHANDLES)(); +typedef void (WINAPI * PFN_QERAPP_RELEASESELECTEDBRUSHHANDLES)(); +typedef void* (WINAPI * PFN_QERAPP_GETSELECTEDBRUSHHANDLE)(int nIndex); + +typedef int (WINAPI * PFN_QERAPP_ACTIVEBRUSHCOUNT)(); +typedef int (WINAPI * PFN_QERAPP_ALLOCATEACTIVEBRUSHHANDLES)(); +typedef void (WINAPI * PFN_QERAPP_RELEASEACTIVEBRUSHHANDLES)(); +typedef void* (WINAPI * PFN_QERAPP_GETACTIVEBRUSHHANDLE)(int nIndex); + +typedef int (WINAPI * PFN_QERAPP_TEXTURECOUNT)(); +typedef char* (WINAPI * PFN_QERAPP_GETTEXTURE)(int nIndex); +typedef char* (WINAPI * PFN_QERAPP_GETCURRENTTEXTURE)(); +typedef void (WINAPI * PFN_QERAPP_SETCURRENTTEXTURE)(char* pName); + +typedef void (WINAPI * PFN_QERAPP_REGISTERMAPLOAD)(void* vp); +typedef void (WINAPI * PFN_QERAPP_REGISTERMAPSAVE)(void* vp); + +typedef int (WINAPI * PFN_QERAPP_GETECLASSCOUNT)(); +typedef char* (WINAPI * PFN_QERAPP_GETECLASS)(int nIndex); + +typedef void (WINAPI * PFN_QERAPP_RESETPLUGINS)(); +//--typedef int (WINAPI* PFN_QERAPP_GETENTITYCOUNT)(); + +/*! +\fn LoadTextureRGBA +\param pPixels is the raw RGBA pixel data (24bits, 8 bit depth) +\param nWidth image width +\param nHeight image height +this will work from the RGBA data and create a GL texture (accessed through a GL bind number) +it takes care of creating the mipmapping levels too +see http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=575 for some related issues +*/ +typedef qtexture_t* (* PFN_QERAPP_LOADTEXTURERGBA)(unsigned char* pPixels, int nWidth, int nHeight); + +//--typedef LPCSTR (WINAPI* PFN_QERAPP_GETENTITY)(int nIndex); + +// v1.70 +typedef int (WINAPI * PFN_QERAPP_GETENTITYCOUNT)(); +typedef void* (WINAPI * PFN_QERAPP_GETENTITYHANDLE)(int nIndex); +// FIXME: those two are fairly outdated, you get the epairs +// but you don't have a clean epair read/write query +// and you rely on the C structs directly, which might go away soon +// ok now, stop using, it's bad for your karma (see iepairs.h instead) +typedef epair_t* (WINAPI * PFN_QERAPP_ALLOCATEEPAIR)( char*, char* ); +typedef int (WINAPI * PFN_QERAPP_ALLOCATEENTITYBRUSHHANDLES)(void* vp); +typedef void (WINAPI * PFN_QERAPP_RELEASEENTITYBRUSHHANDLES)(); +typedef void* (WINAPI * PFN_QERAPP_GETENTITYBRUSHHANDLE)(int nIndex); +typedef void* (WINAPI * PFN_QERAPP_CREATEENTITYHANDLE)(); +typedef void (WINAPI * PFN_QERAPP_COMMITBRUSHHANDLETOENTITY)( void* vpBrush, void* vpEntity); +typedef void (WINAPI * PFN_QERAPP_COMMITENTITYHANDLETOMAP)(void* vp); +typedef void (WINAPI * PFN_QERAPP_SETSCREENUPDATE)(int bScreenUpdate); +// this one uses window flags defined in qertypes.h +typedef void (WINAPI * PFN_QERAPP_SYSUPDATEWINDOWS)(int bits); +//++timo remove this one +typedef void (WINAPI * PFN_QERAPP_BUILDBRUSH2)(void* vp, int bConvert); + +// v1.80 +typedef void (WINAPI * PFN_QERAPP_GETDISPATCHPARAMS)(vec3_t vMin, vec3_t vMax, bool *bSingleBrush); + +typedef int (WINAPI * PFN_QERAPP_REQUESTINTERFACE)( REFGUID, void* ); +// use this one for errors, Radiant will stop after the "edit preferences" dialog +typedef void (WINAPI * PFN_QERAPP_ERROR)(char* pMsg, ...); +// use to gain read access to the project epairs +// FIXME: removed, accessed through QERPlug_RegisterPluginEntities with the IEpair interface +// typedef void (WINAPI* PFN_QERAPP_GETPROJECTEPAIR)(epair_t **); +// used to allocate and read a buffer +//++timo NOTE: perhaps this would need moving to some kind of dedicated interface +typedef int (WINAPI * PFN_QERAPP_LOADFILE)(const char *pLocation, void ** buffer); +typedef char* (WINAPI * PFN_QERAPP_EXPANDRELETIVEPATH)(char *); +typedef void (WINAPI * PFN_QERAPP_QECONVERTDOSTOUNIXNAME)( char *dst, const char *src ); +typedef int (WINAPI * PFN_QERAPP_HASSHADER)(const char *); +typedef int (WINAPI * PFN_QERAPP_TEXTURELOADSKIN)(char *pName, int *pnWidth, int *pnHeight); +// retrieves the path to the engine from the preferences dialog box +typedef const char* (WINAPI * PFN_QERAPP_GETGAMEPATH)(); +// retrieves full Radiant path +typedef const char* (WINAPI * PFN_QERAPP_GETQERPATH)(); +// retieves .game name of current active game +typedef const char* (WINAPI * PFN_QERAPP_GETGAMEFILE)(); + +// patches in/out +// NOTE: this is a bit different from the brushes in/out, no LPVOID handles this time +// use int indexes instead +// if you call AllocateActivePatchHandles, you'll be playing with active patches +// AllocateSelectedPatcheHandles for selected stuff +// a call to CreatePatchHandle will move you to a seperate index table +typedef int (WINAPI * PFN_QERAPP_ALLOCATEACTIVEPATCHHANDLES) (); +typedef int (WINAPI * PFN_QERAPP_ALLOCATESELECTEDPATCHHANDLES) (); +typedef void (WINAPI * PFN_QERAPP_RELEASEPATCHHANDLES) (); +typedef patchMesh_t* (WINAPI * PFN_QERAPP_GETPATCHDATA) (int); +typedef patchMesh_t* (WINAPI * PFN_QERAPP_GETPATCHHANDLE) (int); +typedef void (WINAPI * PFN_QERAPP_DELETEPATCH) (int); +typedef int (WINAPI * PFN_QERAPP_CREATEPATCHHANDLE) (); +// when commiting, only a few patchMesh_t members are relevant: +// int width, height; // in control points, not patches +// int contents, flags, value, type; +// drawVert_t ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT]; +// once you have commited the index is still available, if the patch handle was allocated by you +// then you can re-use the index to commit other patches .. otherwise you can change existing patches +// NOTE: the handle thing for plugin-allocated patches is a bit silly (nobody's perfect) +// TODO: change current behaviour to an index = 0 to tell Radiant to allocate, other indexes to existing patches +// patch is selected after a commit +// you can add an optional texture / shader name .. if NULL will use the current texture +typedef void (WINAPI * PFN_QERAPP_COMMITPATCHHANDLETOMAP) (int, patchMesh_t* pMesh, char *texName); +typedef void (WINAPI * PFN_QERAPP_COMMITPATCHHANDLETOENTITY) (int, patchMesh_t* pMesh, char *texName, void* vpEntity); + +// console output +#define SYS_VRB 0 ///< verbose support (on/off) +#define SYS_STD 1 ///< standard print level - this is the default +#define SYS_WRN 2 ///< warnings +#define SYS_ERR 3 ///< error +#define SYS_NOCON 4 ///< no console, only print to the file (useful whenever Sys_Printf and output IS the problem) +typedef void (WINAPI* PFN_QERAPP_SYSPRINTF) (const char *text, ...); +typedef void (WINAPI* PFN_QERAPP_SYSFPRINTF) (int flag, const char *text, ...); + +typedef void (WINAPI* PFN_QERAPP_SYSBEGINWAIT) (); +typedef void (WINAPI* PFN_QERAPP_SYSENDWAIT) (); + +typedef void (* PFN_QERAPP_SYSBEEP) (); + +typedef void (* PFN_QERAPP_SYSSTATUS) (const char *psz, int part ); + +// core map functionality +typedef void (* PFN_QERAPP_MAPNEW) (); +typedef void (* PFN_QERAPP_MAPFREE) (); +typedef void (* PFN_QERAPP_MAPBUILDBRUSHDATA) (); +typedef qboolean (* PFN_QERAPP_MAPISBRUSHFILTERED) (brush_t *); +typedef void (* PFN_QERAPP_MAPSTARTPOSITION) (); +typedef void (* PFN_QERAPP_MAPREGIONOFF) (); +//typedef void (* PFN_QERAPP_SAVEASDIALOG) (bool bRegion); +typedef void (* PFN_QERAPP_SETBUILDWINDINGSNOTEXBUILD) (bool); +typedef void (* PFN_QERAPP_POINTFILECLEAR) (); + +typedef void (* PFN_QERAPP_SYSSETTITLE) (const char *text); + +typedef void (* PFN_QERAPP_CSGMAKEHOLLOW) (); + +typedef void (* PFN_QERAPP_REGIONSPAWNPOINT) (FILE *f); + +/*! +access to a portable GetTickCount +*/ +typedef unsigned long (* PFN_QERAPP_GETTICKCOUNT) (); + +class IModelCache +{ +public: + virtual entity_interfaces_t *GetByID(const char *id, const char* version) = 0; + virtual void DeleteByID(const char *id, const char* version) = 0; + virtual void RefreshAll() = 0; +}; + +typedef IModelCache* (* PFN_GETMODELCACHE)(); + +class IFileTypeList +{ +public: + virtual void addType(filetype_t type) = 0; +}; + +class IFileTypeRegistry +{ +public: + virtual void addType(const char* key, filetype_t type) = 0; + virtual void getTypeList(const char* key, IFileTypeList* typelist) = 0; +private: +}; + +typedef IFileTypeRegistry* (* PFN_GETFILETYPEREGISTRY)(); + +typedef const char* (* PFN_QERAPP_READPROJECTKEY)(const char* key); + +typedef char* (* PFN_GETMAPFILENAME)(); + + // FIXME: +// add map format extensions +// add texture format handlers +// add surface dialog handler +// add model handler/displayer + +// v1 func table +// Plugins need to declare one of these and implement the getfunctable as described above +struct _QERFuncTable_1 +{ + int m_nSize; + PFN_QERAPP_CREATEBRUSH m_pfnCreateBrush; + PFN_QERAPP_CREATEBRUSHHANDLE m_pfnCreateBrushHandle; + PFN_QERAPP_DELETEBRUSHHANDLE m_pfnDeleteBrushHandle; + PFN_QERAPP_COMMITBRUSHHANDLETOMAP m_pfnCommitBrushHandle; + PFN_QERAPP_ADDFACE m_pfnAddFace; + PFN_QERAPP_ADDFACEDATA m_pfnAddFaceData; + PFN_QERAPP_GETFACEDATA m_pfnGetFaceData; + PFN_QERAPP_GETFACECOUNT m_pfnGetFaceCount; + PFN_QERAPP_SETFACEDATA m_pfnSetFaceData; + PFN_QERAPP_DELETEFACE m_pfnDeleteFace; + PFN_QERAPP_TEXTUREBRUSH m_pfnTextureBrush; + PFN_QERAPP_BUILDBRUSH m_pfnBuildBrush; // PGM + PFN_QERAPP_SELECTBRUSH m_pfnSelectBrush; // PGM + PFN_QERAPP_DESELECTBRUSH m_pfnDeselectBrush; // PGM + PFN_QERAPP_DESELECTALLBRUSHES m_pfnDeselectAllBrushes; // PGM + + PFN_QERAPP_DELETESELECTION m_pfnDeleteSelection; + PFN_QERAPP_GETPOINTS m_pfnGetPoints; + + PFN_QERAPP_SELECTEDBRUSHCOUNT m_pfnSelectedBrushCount; + PFN_QERAPP_ALLOCATESELECTEDBRUSHHANDLES m_pfnAllocateSelectedBrushHandles; + PFN_QERAPP_RELEASESELECTEDBRUSHHANDLES m_pfnReleaseSelectedBrushHandles; + PFN_QERAPP_GETSELECTEDBRUSHHANDLE m_pfnGetSelectedBrushHandle; + + PFN_QERAPP_ACTIVEBRUSHCOUNT m_pfnActiveBrushCount; + PFN_QERAPP_ALLOCATEACTIVEBRUSHHANDLES m_pfnAllocateActiveBrushHandles; + PFN_QERAPP_RELEASEACTIVEBRUSHHANDLES m_pfnReleaseActiveBrushHandles; + PFN_QERAPP_GETACTIVEBRUSHHANDLE m_pfnGetActiveBrushHandle; + + //++timo this would need to be removed and replaced by the IShaders interface + PFN_QERAPP_TEXTURECOUNT m_pfnTextureCount; + PFN_QERAPP_GETTEXTURE m_pfnGetTexture; + PFN_QERAPP_GETCURRENTTEXTURE m_pfnGetCurrentTexture; + PFN_QERAPP_SETCURRENTTEXTURE m_pfnSetCurrentTexture; + + PFN_QERAPP_GETECLASSCOUNT m_pfnGetEClassCount; + PFN_QERAPP_GETECLASS m_pfnGetEClass; + PFN_QERAPP_RESETPLUGINS m_pfnResetPlugins; + // v1.00 ends here + // v1.50 starts here + PFN_QERAPP_LOADTEXTURERGBA m_pfnLoadTextureRGBA; + // v1.50 ends here + // v1.70 starts here + PFN_QERAPP_GETENTITYCOUNT m_pfnGetEntityCount; + PFN_QERAPP_GETENTITYHANDLE m_pfnGetEntityHandle; + PFN_QERAPP_ALLOCATEENTITYBRUSHHANDLES m_pfnAllocateEntityBrushHandles; + PFN_QERAPP_RELEASEENTITYBRUSHHANDLES m_pfnReleaseEntityBrushHandles; + PFN_QERAPP_GETENTITYBRUSHHANDLE m_pfnGetEntityBrushHandle; + PFN_QERAPP_CREATEENTITYHANDLE m_pfnCreateEntityHandle; + PFN_QERAPP_COMMITBRUSHHANDLETOENTITY m_pfnCommitBrushHandleToEntity; + PFN_QERAPP_COMMITENTITYHANDLETOMAP m_pfnCommitEntityHandleToMap; + PFN_QERAPP_ALLOCATEEPAIR m_pfnAllocateEpair; + PFN_QERAPP_SETSCREENUPDATE m_pfnSetScreenUpdate; + PFN_QERAPP_BUILDBRUSH2 m_pfnBuildBrush2; + // v1.70 ends here + // v1.80 starts here + PFN_QERAPP_GETDISPATCHPARAMS m_pfnGetDispatchParams; + + // plugins can request additional interfaces + PFN_QERAPP_REQUESTINTERFACE m_pfnRequestInterface; + PFN_QERAPP_ERROR m_pfnError; + // loading a file into a buffer + PFN_QERAPP_LOADFILE m_pfnLoadFile; + PFN_QERAPP_EXPANDRELETIVEPATH m_pfnExpandReletivePath; + PFN_QERAPP_QECONVERTDOSTOUNIXNAME m_pfnQE_ConvertDOSToUnixName; + PFN_QERAPP_HASSHADER m_pfnHasShader; + PFN_QERAPP_TEXTURELOADSKIN m_pfnTexture_LoadSkin; + PFN_QERAPP_GETGAMEPATH m_pfnGetGamePath; + PFN_QERAPP_GETQERPATH m_pfnGetQERPath; + PFN_QERAPP_GETGAMEFILE m_pfnGetGameFile; + // patches in / out + PFN_QERAPP_ALLOCATEACTIVEPATCHHANDLES m_pfnAllocateActivePatchHandles; + PFN_QERAPP_ALLOCATESELECTEDPATCHHANDLES m_pfnAllocateSelectedPatchHandles; + PFN_QERAPP_RELEASEPATCHHANDLES m_pfnReleasePatchHandles; + PFN_QERAPP_GETPATCHDATA m_pfnGetPatchData; + PFN_QERAPP_GETPATCHHANDLE m_pfnGetPatchHandle; + PFN_QERAPP_DELETEPATCH m_pfnDeletePatch; + PFN_QERAPP_CREATEPATCHHANDLE m_pfnCreatePatchHandle; + PFN_QERAPP_COMMITPATCHHANDLETOMAP m_pfnCommitPatchHandleToMap; + PFN_QERAPP_COMMITPATCHHANDLETOENTITY m_pfnCommitPatchHandleToEntity; + + PFN_QERAPP_LOADIMAGE m_pfnLoadImage; + + // GTK+ functions + PFN_QERAPP_MESSAGEBOX m_pfnMessageBox; + PFN_QERAPP_FILEDIALOG m_pfnFileDialog; + PFN_QERAPP_DIRDIALOG m_pfnDirDialog; + PFN_QERAPP_COLORDIALOG m_pfnColorDialog; + PFN_QERAPP_LOADBITMAP m_pfnLoadBitmap; + + // Profile functions + PFN_QERAPP_PROFILE_GETDIR m_pfnProfileGetDirectory; + PFN_QERAPP_PROFILE_SAVEINT m_pfnProfileSaveInt; + PFN_QERAPP_PROFILE_SAVESTR m_pfnProfileSaveString; + PFN_QERAPP_PROFILE_LOADINT m_pfnProfileLoadInt; + PFN_QERAPP_PROFILE_LOADSTR m_pfnProfileLoadString; + + // Sys_ functions + PFN_QERAPP_SYSUPDATEWINDOWS m_pfnSysUpdateWindows; + PFN_QERAPP_SYSBEEP m_pfnSysBeep; + PFN_QERAPP_SYSPRINTF m_pfnSysPrintf; + PFN_QERAPP_SYSFPRINTF m_pfnSysFPrintf; + PFN_QERAPP_SYSBEGINWAIT m_pfnSysBeginWait; + PFN_QERAPP_SYSENDWAIT m_pfnSysEndWait; + PFN_QERAPP_SYSSETTITLE m_pfnSys_SetTitle; + PFN_QERAPP_SYSSTATUS m_pfnSys_Status; + + // some core functionality on the map + PFN_QERAPP_MAPNEW m_pfnMapNew; + PFN_QERAPP_MAPFREE m_pfnMapFree; + PFN_QERAPP_MAPBUILDBRUSHDATA m_pfnMapBuildBrushData; + PFN_QERAPP_MAPISBRUSHFILTERED m_pfnMap_IsBrushFiltered; + PFN_QERAPP_MAPSTARTPOSITION m_pfnMapStartPosition; + PFN_QERAPP_MAPREGIONOFF m_pfnMapRegionOff; + PFN_QERAPP_SETBUILDWINDINGSNOTEXBUILD m_pfnSetBuildWindingsNoTexBuild; +// PFN_QERAPP_SAVEASDIALOG m_pfnSaveAsDialog; + PFN_QERAPP_POINTFILECLEAR m_pfnPointFileClear; + + // FIXME TTimo prolly want to move that somewhere else + PFN_QERAPP_CSGMAKEHOLLOW m_pfnCSG_MakeHollow; + + PFN_QERAPP_REGIONSPAWNPOINT m_pfnRegionSpawnPoint; + PFN_QERAPP_GETTICKCOUNT m_pfnQGetTickCount; + PFN_GETMODELCACHE m_pfnGetModelCache; + PFN_GETFILETYPEREGISTRY m_pfnGetFileTypeRegistry; + + PFN_QERAPP_READPROJECTKEY m_pfnReadProjectKey; + + // digibob from the old _QERAppBSPFrontendTable table + PFN_GETMAPFILENAME m_pfnGetMapName; +}; + +// macros to access those faster in plugins +#ifdef USE_QERTABLE_DEFINE +#ifndef __QERTABLENAME +#define __QERTABLENAME g_FuncTable +#endif +#define CSG_MakeHollow __QERTABLENAME.m_pfnCSG_MakeHollow +#define Sys_Beep __QERTABLENAME.m_pfnSysBeep +#define Sys_Printf __QERTABLENAME.m_pfnSysPrintf +#define Sys_FPrintf __QERTABLENAME.m_pfnSysFPrintf +#define Sys_BeginWait __QERTABLENAME.m_pfnSysBeginWait +#define Sys_EndWait __QERTABLENAME.m_pfnSysEndWait +#define Sys_UpdateWindows __QERTABLENAME.m_pfnSysUpdateWindows +#define Sys_SetTitle __QERTABLENAME.m_pfnSys_SetTitle +#define Sys_Status __QERTABLENAME.m_pfnSys_Status +#define Select_Deselect __QERTABLENAME.m_pfnDeselectAllBrushes +#define Map_New __QERTABLENAME.m_pfnMapNew +#define Map_Free __QERTABLENAME.m_pfnMapFree +#define Map_IsBrushFiltered __QERTABLENAME.m_pfnMap_IsBrushFiltered +#define Map_BuildBrushData __QERTABLENAME.m_pfnMapBuildBrushData +#define Map_StartPosition __QERTABLENAME.m_pfnMapStartPosition +#define Map_RegionOff __QERTABLENAME.m_pfnMapRegionOff +#define QE_ConvertDOSToUnixName __QERTABLENAME.m_pfnQE_ConvertDOSToUnixName +#define SetBuildWindingsNoTexBuild __QERTABLENAME.m_pfnSetBuildWindingsNoTexBuild +//#define SaveAsDialog __QERTABLENAME.m_pfnSaveAsDialog +#define Pointfile_Clear __QERTABLENAME.m_pfnPointFileClear +#define SetScreenUpdate __QERTABLENAME.m_pfnSetScreenUpdate +#define Region_SpawnPoint __QERTABLENAME.m_pfnRegionSpawnPoint +#define QGetTickCount __QERTABLENAME.m_pfnGetTickCount +#define GetModelCache __QERTABLENAME.m_pfnGetModelCache +#define GetFileTypeRegistry __QERTABLENAME.m_pfnGetFileTypeRegistry +#else +IFileTypeRegistry* GetFileTypeRegistry(); +#endif + +#endif diff --git a/include/qertypes.h b/include/qertypes.h new file mode 100644 index 00000000..0c6ebbdb --- /dev/null +++ b/include/qertypes.h @@ -0,0 +1,911 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// qertypes.h +// +// common types +// merged from brush.h, etc. for plugin support +// +#ifndef _QERTYPES_H_ +#define _QERTYPES_H_ + +#ifdef _WIN32 +#include +#endif + +#include + +#include "str.h" + +#ifdef _WIN32 +#define PATH_MAX 260 +#endif + +// HACK glib-2.0 +#define NAME_MAX 255 + +typedef bool qboolean; + +#define MAXPOINTS 16 + +// merged from qedefs.h ------ + +#define MAX_EDGES 512 +#define MAX_POINTS 1024 + +#define COLOR_TEXTUREBACK 0 +#define COLOR_GRIDBACK 1 +#define COLOR_GRIDMINOR 2 +#define COLOR_GRIDMAJOR 3 +#define COLOR_CAMERABACK 4 +#define COLOR_ENTITY 5 +#define COLOR_GRIDBLOCK 6 +#define COLOR_GRIDTEXT 7 +#define COLOR_BRUSHES 8 +#define COLOR_SELBRUSHES 9 +#define COLOR_CLIPPER 10 +#define COLOR_VIEWNAME 11 +#define COLOR_SELBRUSHES3D 12 + +#define COLOR_GRIDMINOR_ALT 13 +#define COLOR_GRIDMAJOR_ALT 14 + +#define COLOR_LAST 15 + +// ---------------------------- + +typedef float vec_t; +typedef vec_t vec3_t[3]; + +// turn this on/off to use a static texdef or a memory one +// THIS MUST BE CONSISTENT throughout a whole build of Radiant / modules / plugins +// DO_TEXDEF_ALLOC is more memory efficient, but I suspect it to be wacky on win32 / C runtime etc. +#define DO_TEXDEF_ALLOC 1 +#if DO_TEXDEF_ALLOC + +class texdef_t +{ +private: + char *name; +public: + texdef_t() + { + name = new char[1]; + name[0] = '\0'; + shift[0] = 0.0f; + shift[1] = 0.0f; + rotate = 0.0f; + scale[0] = 1.0f; + scale[1] = 1.0f; + contents = 0; + flags = 0; + value = 0; + } + texdef_t(const texdef_t& other) + { + name = NULL; + SetName(other.name); + shift[0] = other.shift[0]; + shift[1] = other.shift[1]; + rotate = other.rotate; + scale[0] = other.scale[0]; + scale[1] = other.scale[1]; + contents = other.contents; + flags = other.flags; + value = other.value; + } + ~texdef_t() + { + if (name) + { + delete []name; + name = (char*)NULL; + } + } + + void SetName(const char *p) + { + if (name) + { + delete []name; + name = NULL; + } + if (p) + { + name = strcpy(new char[strlen(p)+1], p); + } + else + { + name = new char[1]; + name[0] = '\0'; + } + } + + const char * GetName() const + { + return name; + } + + // NOTE TTimo when loading prefs as binary, we load a bogus value in texdef.. + void DropName() + { + name = NULL; + SetName(NULL); + } + + texdef_t& operator =(const texdef_t& rhs) + { + if (&rhs != this) + { + SetName(rhs.name); + shift[0] = rhs.shift[0]; + shift[1] = rhs.shift[1]; + rotate = rhs.rotate; + scale[0] = rhs.scale[0]; + scale[1] = rhs.scale[1]; + contents = rhs.contents; + flags = rhs.flags; + value = rhs.value; + } + return *this; + } + float shift[2]; + float rotate; + float scale[2]; + int contents; + int flags; + int value; +}; + +#else + +// max length of a vfs texture path +#define QPATH 64 +class texdef_t +{ +private: + char name[QPATH]; +public: + texdef_t() { name[0] = '\0'; } + ~texdef_t() { } + + void SetName(const char *p) + { + strncpy(name, p, QPATH); + } + + const char * GetName() const + { + return name; + } + + // NOTE TTimo when loading prefs as binary, we load a bogus value in texdef.. + void DropName() + { + name[0] = '\0'; + } + + texdef_t& operator =(const texdef_t& rhs) + { + if (&rhs != this) + { + SetName(rhs.name); + shift[0] = rhs.shift[0]; + shift[1] = rhs.shift[1]; + rotate = rhs.rotate; + scale[0] = rhs.scale[0]; + scale[1] = rhs.scale[1]; + contents = rhs.contents; + flags = rhs.flags; + value = rhs.value; + } + return *this; + } + float shift[2]; + float rotate; + float scale[2]; + int contents; + int flags; + int value; +}; + +#endif + +// forward declare +class IShader; + +// Timo +// new brush primitive texdef +typedef struct brushprimit_texdef_s +{ + vec_t coords[2][3]; +} brushprimit_texdef_t; + +// this structure is used in Radiant to reflect the state of the texture window +// it gives information on current shader and various flags +class texturewin_t +{ +public: + texturewin_t() + { + } + ~texturewin_t() + { + } + int width, height; + int originy; + // add brushprimit_texdef_t for brush primitive coordinates storage + brushprimit_texdef_t brushprimit_texdef; + int m_nTotalHeight; + // surface plugin, must be casted to a IPluginTexdef* + void* pTexdef; + texdef_t texdef; + // shader + // NOTE: never NULL, initialized in Texture_Init + // NOTE: the reference name of the shader is texdef.name (see QERApp_ReloadShaders for an example) + IShader *pShader; +}; + +#define QER_TRANS 0x00000001 +#define QER_NOCARVE 0x00000002 +#define QER_NODRAW 0x00000004 +#define QER_NONSOLID 0x00000008 +#define QER_WATER 0x00000010 +#define QER_LAVA 0x00000020 +#define QER_FOG 0x00000040 +#define QER_ALPHAFUNC 0x00000080 +#define QER_CULL 0x00000100 + + +// describes a GL texture that Radiant uses to represent a shader +// NOTE: all qtexture_t are stored in a main list at g_qeglobals.d_qtextures +// shaders have reference couting, but qtexture_t don't (they're way too deep into Radiant) +typedef struct qtexture_s +{ + struct qtexture_s *next; + // name of the texture file (the physical image file we are using) + // NOTE: used for lookup, must be unique .. vfs path of the texture, lowercase, NO FILE EXTENSION + // ex textures/gothic_wall/iron + // NOTE: the "textures/" prefix might seem unnecessary .. but it's better to stick to the vfs name + char name[64]; + int width, height; + GLuint texture_number; // gl bind number (the qtexture_t are usually loaded and binded by the shaders module) + vec3_t color; // for flat shade mode + qboolean inuse; // true = is present on the level (for the texture browser interface) +} qtexture_t; + +// NOTE: don't trust this definition! +// you should read float points[..][5] +// see NewWinding definition +// WARNING: don't touch anything to this struct unless you looked into winding.cpp and WINDING_SIZE(pt) +#define MAX_POINTS_ON_WINDING 64 +typedef struct +{ + int numpoints; + int maxpoints; + float points[8][5]; // variable sized +} winding_t; + +typedef struct +{ + vec3_t normal; + double dist; + int type; +} plane_t; + +// pShader is a shortcut to the shader +// it's only up-to-date after a Brush_Build call +// to initialize the pShader, use QERApp_Shader_ForName(texdef.name) +typedef struct face_s +{ + struct face_s *next; + struct face_s *prev; + struct face_s *original; //used for vertex movement + vec3_t planepts[3]; + texdef_t texdef; + plane_t plane; + + // Nurail: Face Undo + int undoId; + int redoId; + + winding_t *face_winding; + + vec3_t d_color; + vec_t d_shade; + // calls through here have indirections (pure virtual) + // it would be good if the rendering loop would avoid scanning there (for the GL binding number for example) + IShader *pShader; + //++timo FIXME: remove! + qtexture_t *d_texture; + + // Timo new brush primit texdef + brushprimit_texdef_t brushprimit_texdef; + + // cast this one to an IPluginTexdef if you are using it + // NOTE: casting can be done with a GETPLUGINTEXDEF defined in isurfaceplugin.h + // TODO: if the __ISURFACEPLUGIN_H_ header is used, use a union { void *pData; IPluginTexdef *pPluginTexdef } kind of thing ? + void *pData; +} face_t; + +typedef struct { + vec3_t xyz; + float sideST[2]; + float capST[2]; +} curveVertex_t; + +typedef struct { + curveVertex_t v[2]; +} sideVertex_t; + + +#define MIN_PATCH_WIDTH 3 +#define MIN_PATCH_HEIGHT 3 + +#define MAX_PATCH_WIDTH 16 +#define MAX_PATCH_HEIGHT 16 + +// patch type info +// type in lower 16 bits, flags in upper +// endcaps directly follow this patch in the list + +// types +#define PATCH_GENERIC 0x00000000 // generic flat patch +#define PATCH_CYLINDER 0x00000001 // cylinder +#define PATCH_BEVEL 0x00000002 // bevel +#define PATCH_ENDCAP 0x00000004 // endcap +#define PATCH_HEMISPHERE 0x00000008 // hemisphere +#define PATCH_CONE 0x00000010 // cone +#define PATCH_TRIANGLE 0x00000020 // simple tri, assumes 3x3 patch + +// behaviour styles +#define PATCH_CAP 0x00001000 // flat patch applied as a cap +#define PATCH_SEAM 0x00002000 // flat patch applied as a seam +#define PATCH_THICK 0x00004000 // patch applied as a thick portion + +// styles +#define PATCH_BEZIER 0x00000000 // default bezier +#define PATCH_BSPLINE 0x10000000 // bspline + +#define PATCH_TYPEMASK 0x00000fff // +#define PATCH_BTYPEMASK 0x0000f000 // +#define PATCH_STYLEMASK 0xffff0000 // + +typedef struct { + vec3_t xyz; + float st[2]; + float lightmap[2]; + vec3_t normal; +} drawVert_t; + +// spog - used for patch LOD trees + +struct BTNode_t +{ + BTNode_t *left, *right; + drawVert_t info; + drawVert_t vMid; +}; + +struct BTreeList_t +{ + BTreeList_t *next; + BTNode_t *pBT; + drawVert_t vLeft, vRight; +}; + +struct BTListList_t +{ + BTListList_t *next; + BTreeList_t *list; +}; + +// used in brush primitive AND entities +typedef struct epair_s +{ + struct epair_s *next; + char *key; + char *value; +} epair_t; + +struct brush_s; +typedef struct brush_s brush_t; + +typedef struct { + int width, height; // in control points, not patches + int contents, flags, value, type; + qtexture_t *d_texture; + IShader *pShader; + drawVert_t ctrl[MAX_PATCH_WIDTH][MAX_PATCH_HEIGHT]; + brush_t *pSymbiot; + qboolean bSelected; + qboolean bOverlay; + qboolean bDirty; + int nListID; + epair_t *epairs; + // cast this one to an IPluginTexdef if you are using it + // NOTE: casting can be done with a GETPLUGINTEXDEF defined in isurfaceplugin.h + // TODO: if the __ISURFACEPLUGIN_H_ header is used, use a union { void *pData; IPluginTexdef *pPluginTexdef } kind of thing ? + void *pData; + // spog - curve LOD binary trees and lists + BTNode_t *rowLOD[((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT]; // = ((MAX_PATCH_WIDTH-1)/2) * MAX_PATCH_HEIGHT + BTNode_t *colLOD[((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH]; // = ((MAX_PATCH_HEIGHT-1)/2) * MAX_PATCH_WIDTH + bool rowDirty[((MAX_PATCH_WIDTH-1)-1)/2]; + bool colDirty[((MAX_PATCH_HEIGHT-1)-1)/2]; + bool LODUpdated; + void *drawLists; // pointer to std::list +} patchMesh_t; + +typedef struct brush_s +{ + struct brush_s *prev, *next; // links in active/selected + struct brush_s *oprev, *onext; // links in entity + struct entity_s *owner; + vec3_t mins, maxs; + face_t *brush_faces; + + qboolean bModelFailed; + // + // curve brush extensions + // all are derived from brush_faces + qboolean patchBrush; + qboolean hiddenBrush; + + //int nPatchID; + + patchMesh_t *pPatch; + struct entity_s *pUndoOwner; + + int undoId; //undo ID + int redoId; //redo ID + int ownerId; //entityId of the owner entity for undo + + // TTimo: this is not legal, we are not supposed to put UI toolkit dependant stuff in the interfaces + // NOTE: the grouping stuff never worked, there is embryonary code everywhere though + int numberId; + void* itemOwner; // GtkCTreeNode* ? + + // brush primitive only + epair_t *epairs; + + // brush filtered toggle + bool bFiltered; + bool bCamCulled; + bool bBrushDef; +} brush_t; + +#define MAX_FLAGS 16 + +typedef struct vertmodel_t +{ + float v[3]; + float st[2]; + float normal[3]; +} vertmodel; + +typedef struct triindex_t +{ + int indexes[3]; +} triindex; + +// TTimo: NOTE: we don't have dedicated stuff to copy/allocate/delete this structure like we do for entity_t and brush_t +// could be necessary, I'm adding GString *strSkin that needs to be copied around +// TTimo 04/01/2001 removing the GString* for toolkit-independent interfaces .. cast it .. +typedef struct entitymodel_t +{ + struct entitymodel_t *pNext; + int nTriCount; + //trimodel *pTriList; + //md3Triangle_t *pTriList; + triindex *pTriList; + vertmodel *pVertList; + int numVerts; + int nTextureBind; + void *strSkin; // toolkit-independent .. cast to a GString* + int nSkinWidth; + int nSkinHeight; + int nModelPosition; +} entitymodel; + +// eclass show flags + +#define ECLASS_LIGHT 0x00000001 +#define ECLASS_ANGLE 0x00000002 +#define ECLASS_PATH 0x00000004 +#define ECLASS_MISCMODEL 0x00000008 + +#ifdef USEPLUGINENTITIES +#define ECLASS_PLUGINENTITY 0x00000010 +#endif // USEPLUGINENTITIES + +typedef struct eclass_s +{ + struct eclass_s *next; + char *name; + qboolean fixedsize; + qboolean unknown; // wasn't found in source + vec3_t mins, maxs; + vec3_t color; + texdef_t texdef; + char *comments; + char flagnames[MAX_FLAGS][32]; + + entitymodel *model; + char *modelpath; + //++timo NOTE: I don't know what this is used for exactly. But don't trust it for the real skin paths on models (screws up with long/short path names) + //++hydra NOTE: this, hopefully, will be used to use specific shaders on the bounding boxes of the eclass instead of a color. + char *skinpath; + int nFrame; + unsigned int nShowFlags; + + void* hPlug; +} eclass_t; + +extern eclass_t *eclass; + +/* +** window bits +*/ +#define W_CAMERA 0x0001 +#define W_XY 0x0002 +#define W_XY_OVERLAY 0x0004 +#define W_Z 0x0008 +#define W_TEXTURE 0x0010 +#define W_Z_OVERLAY 0x0020 +#define W_CONSOLE 0x0040 +#define W_ENTITY 0x0080 +#define W_CAMERA_IFON 0x0100 +#define W_XZ 0x0200 //--| only used for patch vertex manip stuff +#define W_YZ 0x0400 //--| +#define W_GROUP 0x0800 +#define W_MEDIA 0x1000 +#define W_ALL 0xFFFFFFFF + +// used in some Drawing routines +enum VIEWTYPE {YZ, XZ, XY}; +const char g_AxisName[3] = { 'X', 'Y', 'Z' }; + +// dynamically allocated string +class string_t +{ +public: + inline string_t() + { + copy(""); + } + inline string_t(const string_t& other) + { + copy(other.m_string); + } + inline string_t(const char* string) + { + copy(string); + } + inline ~string_t() + { + destroy(); + } + inline const string_t& operator=(const string_t& other) + { + destroy(); + copy(other.m_string); + return *this; + } + inline const string_t& operator=(const char* string) + { + destroy(); + copy(string); + return *this; + } + inline bool operator<(const string_t& other) const + { + return compare(other) < 0; + } + inline bool operator>(const string_t& other) const + { + return compare(other) > 0; + } + inline bool operator==(const string_t& other) const + { + return compare(other) == 0; + } + inline bool operator!=(const string_t& other) const + { + return compare(other) != 0; + } + inline const char* c_str() const + { + return m_string; + } +private: + inline void copy(const char* string) + { + m_string = new char[strlen(string)+1]; + strcpy(m_string, string); + } + inline void destroy() + { + delete[] m_string; + } + inline int compare(const string_t& other) const + { + return strcmp(m_string, other.m_string); + } + + char* m_string; +}; + +class filetype_t +{ +public: + filetype_t() + : name(""), pattern("") + {} + filetype_t(const char* _name, const char* _pattern) + : name(_name), pattern(_pattern) + {} + const char* name; + const char* pattern; +}; + + +/* +** Outline bits +*/ +#define OUTLINE_ZBUF 0x01 // zbuffered outline +#define OUTLINE_BSEL 0x02 // selection overlay + +#ifdef USEPLUGINENTITIES +// forward declare this one +class IPluginEntity; +#endif // USEPLUGINENTITIES + +// MODEL + +class IRender; +class ISelect; +class IEdit; + +// NOTE TTimo about ~entity_interfaces_t +// using constructors / destructors on C structs is bad practice +struct entity_interfaces_t +{ + IRender *pRender; + ISelect *pSelect; + IEdit *pEdit; +}; +// MODEL END + +typedef struct entity_s +{ + struct entity_s *prev, *next; + + /*! + \todo can use a brushes list, or the blind data below + for now, blind data should be interpreted as CPtrArray*, only use in the IMAP API + */ + brush_t brushes; // head/tail of list + void *pData; + + int undoId, redoId, entityId; // used for undo/redo + vec3_t origin; + eclass_t *eclass; + epair_t *epairs; + entity_interfaces_t model; +#ifdef USEPLUGINENTITIES + IPluginEntity *pPlugEnt; +#endif // USEPLUGINENTITIES + + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=252 + // this is cam code addition? + vec3_t color; + + // Arnout: HACK-ish and change for 1.3 (in 1.3 we have a blind data pointer according to TTimo) + float fLightEnvelope1[3]; + float fLightEnvelope2[2]; +} entity_t; + +typedef struct +{ + int p1, p2; + face_t *f1, *f2; +} pedge_t; + +// window system independent camera view code +// NOTE TTimo taken from xy.h +typedef struct +{ + int width, height; + + qboolean timing; + + vec3_t origin; // at center of window + float scale; + + float topclip, bottomclip; + + qboolean d_dirty; +} xy_t; + +// spog - struct used for nodes in filters list +struct bfilter_t //c++ style +{ + bfilter_t *next; + int attribute; // 1=brush->face->pShader->getName() + // 2=brush->pPatch->pShader->getFlags() + // 3=brush->owner->eclass->name + // 4=brush->owner->eclass->nShowFlags + int mask; + char *string; + bool active; +}; + +// djbob: no longer any need to add only to end, versioning removed, it is no longer saved as binary +// IMPORTANT: whenever you update this struct, you need to add the relevant load/save code +// preferences.cpp LoadPref / SavePref +typedef struct +{ + int iTexMenu; // nearest, linear, etc + float fGamma; // gamma for textures + vec3_t colors[COLOR_LAST]; + int exclude; + int include; + texdef_t m_SIIncrement; // increments for the surface inspector + texdef_t m_PIIncrement; // increments for the patch inspector + vec3_t AxisColors[3]; // colors used for X, Y Z axis + // these are in the View > Show menu with Show coordinates + qboolean show_names; + qboolean show_coordinates; + qboolean show_angles; + qboolean show_outline; + qboolean show_axis; + qboolean bNoSelectedOutlines; + bfilter_t *filters; // FIXME spog - might be better in another location? + int iSelectedOutlinesStyle; +} SavedInfo_t; + +typedef enum +{ + sel_brush, + sel_brush_on, + sel_brush_off, + // sel_sticky_brush, + // sel_face, + sel_vertex, + sel_edge, + sel_singlevertex, + sel_curvepoint, + sel_area, + sel_areatall, + sel_facets_on, + sel_facets_off, +} select_t; + +// most of the QE globals are stored in this structure +typedef struct +{ + qboolean d_showgrid; + float d_gridsize; + qboolean d_bSmallGrid; // we use this flag to hack our way into editing of <1 grids + + int d_num_entities; + + entity_t *d_project_entity; + + // defines the boundaries of the current work area + // is used to guess brushes and drop points third coordinate when creating from 2D view + vec3_t d_work_min,d_work_max; + // not stored in registry, default is off + qboolean d_show_work; + + vec3_t d_points[MAX_POINTS]; + int d_numpoints; + pedge_t d_edges[MAX_EDGES]; + int d_numedges; + + int d_num_move_points; + float *d_move_points[4096]; + + qtexture_t *d_qtextures; + // used to speedup access, specially in QERApp_Try_Texture_ForName + // must always be kept up-to-date with d_qtextures* + //++timo FIXME at some point in the future it would even be better to remove d_qtextures and use this instead + GHashTable *d_qtexmap; + + texturewin_t d_texturewin; + + int d_pointfile_display_list; + + xy_t d_xyOld; + + SavedInfo_t d_savedinfo; + + int d_workcount; + + // connect entities uses the last two brushes selected + int d_select_count; + brush_t *d_select_order[2]; + vec3_t d_select_translate; // for dragging w/o making new display lists + select_t d_select_mode; + + int d_parsed_brushes; + + qboolean show_blocks; + int blockSize; + + // NOTE TTimo + // a lot of this data should be in a property bag and available to the other modules through an API + // this is generated from game configuration and the project settings, and should be still be part of it + + // tells if we are internally using brush primitive (texture coordinates and map format) + // this is a shortcut for IntForKey( g_qeglobals.d_project_entity, "brush_primit" ) + // NOTE: must keep the two ones in sync + bool m_bBrushPrimitMode; + + /*! + win32: engine full path. + unix: user home full path + engine dir. + */ + Str m_strHomeGame; + /*! + cache for m_strHomeGame + mod subdirectory. + */ + Str m_strHomeMaps; + + // used while importing brush data from file or memory buffer + // tells if conversion between map format and internal preferences ( m_bBrushPrimitMode ) is needed + qboolean bNeedConvert; + qboolean bOldBrushes; + qboolean bPrimitBrushes; + + vec3_t d_vAreaTL; + vec3_t d_vAreaBR; + + // tells if we are using .INI files for prefs instead of registry + qboolean use_ini; + // even in .INI mode we use the registry for all void* prefs + char use_ini_registry[64]; + // disabled all INI / registry read write .. used when shutting down after registry cleanup + qboolean disable_ini; + + // tells we are using a BSP frontend plugin + qboolean bBSPFrontendPlugin; + + // handle to the console log file + // we use low level I/O to get rid of buffering and have everything on file if we crash + int hLogFile; + + qboolean bTextureCompressionSupported; // is texture compression supported by hardware? + GLint texture_components; + + // temporary values that should be initialised only once at run-time + // there are too many uneccessary calls to Sys_QGL_ExtensionSupported + // NOTE TTimo: those are unused atm (set right, but not used) + // http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=623 + bool m_bOpenGLCompressionSupported; + bool m_bS3CompressionSupported; + + // set to true after OpenGL has been initialized and extensions have been tested + bool m_bOpenGLReady; + +} QEGlobals_t; + +#endif // _QERTYPES_H_ diff --git a/include/qsysprintf.h b/include/qsysprintf.h new file mode 100644 index 00000000..83622784 --- /dev/null +++ b/include/qsysprintf.h @@ -0,0 +1,67 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __QSYSPRINTF_H__ +#define __QSYSPRINTF_H__ + +/*! +this header is provided in libs/ in an attempt to provide a common API +for all the diagnostic printing / fatal error situations + +this is oriented at synapse server targets ONLY +synapse clients should not include this, as they are supposed to go +through the function tables to report print diagnostics +(or use Syn_Printf for situations where the func table may not be available) + +each server target implements that in it's own way. Radiant logs to +a file and sends to the console, q3map prints to stdout and to the +XML network stream, etc. +*/ + +#if defined(__cplusplus) +extern "C" +{ +#endif + +// NOTE: might want to switch to bits if needed +#define SYS_VRB 0 ///< verbose support (on/off) +#define SYS_STD 1 ///< standard print level - this is the default +#define SYS_WRN 2 ///< warnings +#define SYS_ERR 3 ///< error +#define SYS_NOCON 4 ///< no console, only print to the file (useful whenever Sys_Printf and output IS the problem) + +/*! +those are the real implementation +*/ +void Sys_Printf_VA (const char *text, va_list args); ///< matches PFN_SYN_PRINTF_VA prototype +void Sys_FPrintf_VA (int level, const char *text, va_list args); + +/*! +this is easy to call, wrappers around va_list version +*/ +void Sys_Printf (const char *text, ...); +void Sys_FPrintf (int flag, const char *text, ...); + +#if defined(__cplusplus) +}; +#endif + +#endif diff --git a/include/stl_check.h b/include/stl_check.h new file mode 100644 index 00000000..b30481df --- /dev/null +++ b/include/stl_check.h @@ -0,0 +1,60 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/*! +This header is used to make sure the STL we are using is what we expect +this allows to catch some weird errors early at compile time +*/ + +#ifdef Q_NO_STLPORT + +// not using STLPort (gcc 3.x build) +using namespace std; + +#else + +#ifndef _STLPORT_VERSION +#error "Can't find _STLPORT_VERSION, check you are compiling against STLPort" +#endif + +#if !defined(_STLP_DONT_USE_EXCEPTIONS) +#error exc +#endif + +#if !defined(_STLP_NO_NAMESPACES) +#error namespace +#endif + +#if !defined(_STLP_NO_IOSTREAMS) +#error io +#endif + +// now check a few more things (paranoid) +// if you use our custom STLPort distribution it should be alright though +#if !defined(_STLP_DONT_USE_EXCEPTIONS) || !defined(_STLP_NO_NAMESPACES) || !defined(_STLP_NO_IOSTREAMS) +#error "There is something broken in your STLPort config" +#endif + +#ifdef _WIN32 +#pragma warning(disable : 4786) +#endif + +#endif diff --git a/include/stream_version.h b/include/stream_version.h new file mode 100644 index 00000000..d9271854 --- /dev/null +++ b/include/stream_version.h @@ -0,0 +1,3 @@ +// version defines for q3map stream +#define Q3MAP_STREAM_VERSION "1" + diff --git a/include/version.default b/include/version.default new file mode 100644 index 00000000..7455fe00 --- /dev/null +++ b/include/version.default @@ -0,0 +1 @@ +1.4.0 diff --git a/include/version.h b/include/version.h new file mode 100644 index 00000000..f3905933 --- /dev/null +++ b/include/version.h @@ -0,0 +1,4 @@ +// generated header, see makeversion.py +#define RADIANT_VERSION "1.4.0" +#define RADIANT_MINOR_VERSION "0" +#define RADIANT_MAJOR_VERSION "4" diff --git a/install.py b/install.py new file mode 100644 index 00000000..7d1807d8 --- /dev/null +++ b/install.py @@ -0,0 +1,48 @@ +#!/usr/bin/env python + +import os.path, sys, shutil + +def install_file( path, src_path, f ): + src = os.path.join( src_path, f ) + dst = os.path.join( path, f ) + print '%s -> %s' % ( src, dst ) + shutil.copyfile( src, dst ) + +def install( path, src_path ): + for f in [ 'radiant.exe', 'radiant.pdb' ]: + install_file( path, src_path, f ) + + modules_path = os.path.join( path, 'modules' ) + try: + os.makedirs( modules_path ) + except: + pass + assert( os.path.exists( modules_path ) ) + + modules_src = os.path.join( src_path, 'modules' ) + assert( os.path.exists( modules_src ) ) + + for e in os.listdir( modules_src ): + if ( e[-4:] == '.dll' or e[-4:] == '.pdb' ): + install_file( modules_path, modules_src, e ) + + plugins_path = os.path.join( path, 'plugins' ) + try: + os.makedirs( plugins_path ) + except: + pass + assert( os.path.exists( plugins_path ) ) + + plugins_src = os.path.join( src_path, 'plugins' ) + assert( os.path.exists( plugins_src ) ) + + for e in os.listdir( plugins_src ): + if ( e[-4:] == '.dll' or e[-4:] == '.pdb' ): + install_file( plugins_path, plugins_src, e ) + +if __name__ == '__main__': + if ( len( sys.argv ) <= 2 or not os.path.exists( sys.argv[1] ) or not os.path.exists( sys.argv[2] ) ): + print 'usage: install [target directory] [source directory]' + sys.exit(1) + print 'Install %s into %s' % ( sys.argv[2], sys.argv[1] ) + install( sys.argv[1], sys.argv[2] ) diff --git a/libs/.cvsignore b/libs/.cvsignore new file mode 100644 index 00000000..62555de1 --- /dev/null +++ b/libs/.cvsignore @@ -0,0 +1 @@ +.consign diff --git a/libs/bytebool.h b/libs/bytebool.h new file mode 100644 index 00000000..9253bd35 --- /dev/null +++ b/libs/bytebool.h @@ -0,0 +1,20 @@ +#ifndef __BYTEBOOL__ +#define __BYTEBOOL__ + +// bool is a C++ type +// if we are compiling for C, use an enum + +// this header is not really meant for direct inclusion, +// it is used by mathlib and cmdlib + +#ifdef __cplusplus +typedef bool qboolean; +#define qtrue true +#define qfalse false +#else +typedef enum { qfalse, qtrue } qboolean; +#endif + +typedef unsigned char byte; + +#endif diff --git a/libs/cmdlib.h b/libs/cmdlib.h new file mode 100644 index 00000000..84833fcd --- /dev/null +++ b/libs/cmdlib.h @@ -0,0 +1,111 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// start of shared cmdlib stuff +// + +#ifndef __CMDLIB__ +#define __CMDLIB__ + +#include +#include +#include +#include +#include +#include +#include +#include +#ifdef _WIN32 + #define PATH_MAX 260 +#endif + +// some easy portability crap +#ifdef _WIN32 + #include + #define Q_mkdir(a,b) _mkdir(a) +#else + #include + #define Q_mkdir(a,b) mkdir(a,b) +#endif + +#ifdef __cplusplus + typedef bool qboolean; +#endif + +// NOTE TTimo: is this worth anything? +#ifndef __BYTEBOOL__ +#define __BYTEBOOL__ + +#ifndef __cplusplus + typedef enum {false, true} boolean; +#else + typedef unsigned char boolean; +#endif + +typedef unsigned char byte; + +#endif // __BYTEBOOL__ + +void DefaultExtension( char *path, char *extension ); +void DefaultPath( char *path, char *basepath ); +void StripFilename( char *path ); +void StripExtension( char *path ); +void ExtractFilePath( const char *path, char *dest ); +void ExtractFileName( const char *path, char *dest ); +void ExtractFileBase( const char *path, char *dest ); +void ExtractFileExtension( const char *path, char *dest ); +/*! +\brief create all directories leading to a file path. if you pass a directory, terminate it with a '/' +*/ +void CreateDirectoryPath (const char *path); + +short BigShort (short l); +short LittleShort (short l); +int BigLong (int l); +int LittleLong (int l); +float BigFloat (float l); +float LittleFloat (float l); +void *qmalloc (size_t size); +void* qblockmalloc(size_t nSize); + +void ConvertDOSToUnixName( char *dst, const char *src ); +#ifdef __cplusplus + char* StrDup(char* pStr); +#endif +char* StrDup(const char* pStr); + +// TTimo started adding portability code: +// return true if spawning was successful, false otherwise +// on win32 we have a bCreateConsole flag to create a new console or run inside the current one +//boolean Q_Exec(const char* pCmd, boolean bCreateConsole); +// execute a system command: +// cmd: the command to run +// cmdline: the command line +// NOTE TTimo following are win32 specific: +// execdir: the directory to execute in +// bCreateConsole: spawn a new console or not +// return values; +// if the spawn was fine +// TODO TTimo add functionality to track the process until it dies +bool Q_Exec(const char *cmd, char *cmdline, const char *execdir, bool bCreateConsole); + +#endif diff --git a/libs/cmdlib/.cvsignore b/libs/cmdlib/.cvsignore new file mode 100644 index 00000000..b5ee5ae1 --- /dev/null +++ b/libs/cmdlib/.cvsignore @@ -0,0 +1 @@ +Debug Release *.ncb *.opt *.plg *.001 *.BAK \ No newline at end of file diff --git a/libs/cmdlib/.cvswrappers b/libs/cmdlib/.cvswrappers new file mode 100644 index 00000000..cdfd6d4a --- /dev/null +++ b/libs/cmdlib/.cvswrappers @@ -0,0 +1,3 @@ +*.dsp -m 'COPY' -k 'b' +*.dsw -m 'COPY' -k 'b' +*.scc -m 'COPY' -k 'b' diff --git a/libs/cmdlib/cmdlib.cpp b/libs/cmdlib/cmdlib.cpp new file mode 100644 index 00000000..6aeee9f6 --- /dev/null +++ b/libs/cmdlib/cmdlib.cpp @@ -0,0 +1,496 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// +// start of shared cmdlib stuff +// + +#include "cmdlib.h" + +#ifdef _WIN32 + #include +#endif +#if defined (__linux__) || defined (__APPLE__) + #include +#endif + +// FIXME TTimo this should be cleaned up .. +// NOTE: we don't use this crap .. with the total mess of mixing win32/unix paths we need to recognize both '/' and '\\' +#define PATHSEPERATOR '/' + +#if defined (__linux__) || defined (__APPLE__) +bool Q_Exec(const char *cmd, char *cmdline, const char *execdir, bool bCreateConsole) +{ + char fullcmd[2048]; + char *pCmd; +#ifdef _DEBUG + printf("Q_Exec damnit\n"); +#endif + switch (fork()) + { + case -1: + return true; + break; + case 0: + // always concat the command on linux + if (cmd) + { + strcpy(fullcmd, cmd); + } + else + fullcmd[0] = '\0'; + if (cmdline) + { + strcat(fullcmd, " "); + strcat(fullcmd, cmdline); + } + pCmd = fullcmd; + while (*pCmd == ' ') + pCmd++; +#ifdef _DEBUG + printf("Running system...\n"); + printf("Command: %s\n", pCmd); +#endif + system( pCmd ); +#ifdef _DEBUG + printf ("system() returned\n"); +#endif + _exit (0); + break; + } + return true; +} +#endif + +#ifdef _WIN32 +// NOTE TTimo windows is VERY nitpicky about the syntax in CreateProcess +bool Q_Exec(const char *cmd, char *cmdline, const char *execdir, bool bCreateConsole) +{ + PROCESS_INFORMATION ProcessInformation; + STARTUPINFO startupinfo = {0}; + DWORD dwCreationFlags; + GetStartupInfo (&startupinfo); + if (bCreateConsole) + dwCreationFlags = CREATE_NEW_CONSOLE | NORMAL_PRIORITY_CLASS; + else + dwCreationFlags = DETACHED_PROCESS | NORMAL_PRIORITY_CLASS; + const char *pCmd; + char *pCmdline; + pCmd = cmd; + if (pCmd) + { + while (*pCmd == ' ') + pCmd++; + } + pCmdline = cmdline; + if (pCmdline) + { + while (*pCmdline == ' ') + pCmdline++; + } + if (CreateProcess( + pCmd, + pCmdline, + NULL, + NULL, + FALSE, + dwCreationFlags, + NULL, + execdir, + &startupinfo, + &ProcessInformation + )) + return true; + return false; +} +#endif + +#define MEM_BLOCKSIZE 4096 +void* qblockmalloc(size_t nSize) +{ + void *b; + // round up to threshold + int nAllocSize = nSize % MEM_BLOCKSIZE; + if ( nAllocSize > 0) + { + nSize += MEM_BLOCKSIZE - nAllocSize; + } + b = malloc(nSize + 1); + memset (b, 0, nSize); + return b; +} + +//++timo NOTE: can be replaced by g_malloc0(nSize+1) when moving to glib memory handling +void* qmalloc (size_t nSize) +{ + void *b; + b = malloc(nSize + 1); + memset (b, 0, nSize); + return b; +} + +/* +================ +Q_filelength +================ +*/ +int Q_filelength (FILE *f) +{ + int pos; + int end; + + pos = ftell (f); + fseek (f, 0, SEEK_END); + end = ftell (f); + fseek (f, pos, SEEK_SET); + + return end; +} + +void DefaultExtension (char *path, char *extension) +{ + char *src; +// +// if path doesn't have a .EXT, append extension +// (extension should include the .) +// + src = path + strlen(path) - 1; + + while (*src != PATHSEPERATOR && src != path) + { + if (*src == '.') + return; // it has an extension + src--; + } + + strcat (path, extension); +} + +void DefaultPath (char *path, char *basepath) +{ + char temp[128]; + + if (path[0] == PATHSEPERATOR) + return; // absolute path location + strcpy (temp,path); + strcpy (path,basepath); + strcat (path,temp); +} + + +void StripFilename (char *path) +{ + int length; + + length = strlen(path)-1; + while (length > 0 && path[length] != PATHSEPERATOR) + length--; + path[length] = 0; +} + +void StripExtension (char *path) +{ + int length; + + length = strlen(path)-1; + while (length > 0 && path[length] != '.') + { + length--; + if (path[length] == '/') + return; // no extension + } + if (length) + path[length] = 0; +} + + +/* +==================== +Extract file parts +==================== +*/ +void ExtractFilePath (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' && *(src-1) != '\\') + src--; + + memcpy (dest, path, src-path); + dest[src-path] = 0; +} + +void ExtractFileName (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' + && *(src-1) != '\\' ) + src--; + + while (*src) + { + *dest++ = *src++; + } + *dest = 0; +} + +inline const char* path_get_filename_start(const char* path) +{ + { + const char* last_forward_slash = strrchr(path, '/'); + if(last_forward_slash != NULL) + return last_forward_slash + 1; + } + + { + const char* last_backward_slash = strrchr(path, '\\'); + if(last_backward_slash != NULL) + return last_backward_slash + 1; + } + + return path; +} + +inline unsigned int filename_get_base_length(const char* filename) +{ + const char* last_period = strrchr(filename, '.'); + return (last_period != NULL) ? last_period - filename : strlen(filename); +} + +void ExtractFileBase (const char *path, char *dest) +{ + const char* filename = path_get_filename_start(path); + unsigned int length = filename_get_base_length(filename); + strncpy(dest, filename, length); + dest[length] = '\0'; +} + +void ExtractFileExtension (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a . or the start +// + while (src != path && *(src-1) != '.') + src--; + if (src == path) + { + *dest = 0; // no extension + return; + } + + strcpy (dest,src); +} + + +void ConvertDOSToUnixName( char *dst, const char *src ) +{ + while ( *src ) + { + if ( *src == '\\' ) + *dst = '/'; + else + *dst = *src; + dst++; src++; + } + *dst = 0; +} + + +char* StrDup(char* pStr) +{ + if (pStr) + { + return strcpy(new char[strlen(pStr)+1], pStr); + } + return NULL; +} + +char* StrDup(const char* pStr) +{ + if (pStr) + { + return strcpy(new char[strlen(pStr)+1], pStr); + } + return NULL; +} + +void CreateDirectoryPath (const char *path) { + char base[PATH_MAX]; + char *src; + char back; + + ExtractFilePath(path, base); + + src = base+1; + while (1) { + while (*src != '\0' && *src != '/' && *src != '\\') { + src++; + } + if (*src == '\0') { + break; + } + back = *src; *src = '\0'; + Q_mkdir(base, 0755); + *src = back; src++; + } +} + +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +#ifdef _SGI_SOURCE + #define __BIG_ENDIAN__ +#endif + +#ifdef __BIG_ENDIAN__ + +short LittleShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return(b1<<8) + b2; +} + +short BigShort (short l) +{ + return l; +} + + +int LittleLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int BigLong (int l) +{ + return l; +} + + +float LittleFloat (float l) +{ + union + { + byte b[4]; float f; + } in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float BigFloat (float l) +{ + return l; +} + +#else + +short BigShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return(b1<<8) + b2; +} + +short LittleShort (short l) +{ + return l; +} + + +int BigLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int LittleLong (int l) +{ + return l; +} + +float BigFloat (float l) +{ + union + { + byte b[4]; float f; + } in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float LittleFloat (float l) +{ + return l; +} + +#endif diff --git a/libs/cmdlib/cmdlib.vcproj b/libs/cmdlib/cmdlib.vcproj new file mode 100644 index 00000000..3586a963 --- /dev/null +++ b/libs/cmdlib/cmdlib.vcproj @@ -0,0 +1,53 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/ddslib.h b/libs/ddslib.h new file mode 100644 index 00000000..246e31be --- /dev/null +++ b/libs/ddslib.h @@ -0,0 +1,250 @@ +/* ----------------------------------------------------------------------------- + +DDS Library + +Based on code from Nvidia's DDS example: +http://www.nvidia.com/object/dxtc_decompression_code.html + +Copyright (c) 2003 Randy Reddig +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 names of the copyright holders 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. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef DDSLIB_H +#define DDSLIB_H + + + +/* dependencies */ +#include +#include + + + +/* c++ marker */ +#ifdef __cplusplus +extern "C" +{ +#endif + + + +/* dds definition */ +typedef enum +{ + DDS_PF_ARGB8888, + DDS_PF_DXT1, + DDS_PF_DXT2, + DDS_PF_DXT3, + DDS_PF_DXT4, + DDS_PF_DXT5, + DDS_PF_UNKNOWN +} +ddsPF_t; + + +/* 16bpp stuff */ +#define DDS_LOW_5 0x001F; +#define DDS_MID_6 0x07E0; +#define DDS_HIGH_5 0xF800; +#define DDS_MID_555 0x03E0; +#define DDS_HI_555 0x7C00; + + +/* structures */ +typedef struct ddsColorKey_s +{ + unsigned int colorSpaceLowValue; + unsigned int colorSpaceHighValue; +} +ddsColorKey_t; + + +typedef struct ddsCaps_s +{ + unsigned int caps1; + unsigned int caps2; + unsigned int caps3; + unsigned int caps4; +} +ddsCaps_t; + + +typedef struct ddsMultiSampleCaps_s +{ + unsigned short flipMSTypes; + unsigned short bltMSTypes; +} +ddsMultiSampleCaps_t; + + +typedef struct ddsPixelFormat_s +{ + unsigned int size; + unsigned int flags; + unsigned int fourCC; + union + { + unsigned int rgbBitCount; + unsigned int yuvBitCount; + unsigned int zBufferBitDepth; + unsigned int alphaBitDepth; + unsigned int luminanceBitCount; + unsigned int bumpBitCount; + unsigned int privateFormatBitCount; + }; + union + { + unsigned int rBitMask; + unsigned int yBitMask; + unsigned int stencilBitDepth; + unsigned int luminanceBitMask; + unsigned int bumpDuBitMask; + unsigned int operations; + }; + union + { + unsigned int gBitMask; + unsigned int uBitMask; + unsigned int zBitMask; + unsigned int bumpDvBitMask; + ddsMultiSampleCaps_t multiSampleCaps; + }; + union + { + unsigned int bBitMask; + unsigned int vBitMask; + unsigned int stencilBitMask; + unsigned int bumpLuminanceBitMask; + }; + union + { + unsigned int rgbAlphaBitMask; + unsigned int yuvAlphaBitMask; + unsigned int luminanceAlphaBitMask; + unsigned int rgbZBitMask; + unsigned int yuvZBitMask; + }; +} +ddsPixelFormat_t; + + +typedef struct ddsBuffer_s +{ + /* magic: 'dds ' */ + char magic[ 4 ]; + + /* directdraw surface */ + unsigned int size; + unsigned int flags; + unsigned int height; + unsigned int width; + union + { + int pitch; + unsigned int linearSize; + }; + unsigned int backBufferCount; + union + { + unsigned int mipMapCount; + unsigned int refreshRate; + unsigned int srcVBHandle; + }; + unsigned int alphaBitDepth; + unsigned int reserved; + void *surface; + union + { + ddsColorKey_t ckDestOverlay; + unsigned int emptyFaceColor; + }; + ddsColorKey_t ckDestBlt; + ddsColorKey_t ckSrcOverlay; + ddsColorKey_t ckSrcBlt; + union + { + ddsPixelFormat_t pixelFormat; + unsigned int fvf; + }; + ddsCaps_t ddsCaps; + unsigned int textureStage; + + /* data (Varying size) */ + unsigned char data[ 4 ]; +} +ddsBuffer_t; + + +typedef struct ddsColorBlock_s +{ + unsigned short colors[ 2 ]; + unsigned char row[ 4 ]; +} +ddsColorBlock_t; + + +typedef struct ddsAlphaBlockExplicit_s +{ + unsigned short row[ 4 ]; +} +ddsAlphaBlockExplicit_t; + + +typedef struct ddsAlphaBlock3BitLinear_s +{ + unsigned char alpha0; + unsigned char alpha1; + unsigned char stuff[ 6 ]; +} +ddsAlphaBlock3BitLinear_t; + + +typedef struct ddsColor_s +{ + unsigned char r, g, b, a; +} +ddsColor_t; + + + +/* public functions */ +int DDSGetInfo( ddsBuffer_t *dds, int *width, int *height, ddsPF_t *pf ); +int DDSDecompress( ddsBuffer_t *dds, unsigned char *pixels ); + + + +/* end marker */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/ddslib/ddslib.c b/libs/ddslib/ddslib.c new file mode 100644 index 00000000..e7bfeb2b --- /dev/null +++ b/libs/ddslib/ddslib.c @@ -0,0 +1,781 @@ +/* ----------------------------------------------------------------------------- + +DDS Library + +Based on code from Nvidia's DDS example: +http://www.nvidia.com/object/dxtc_decompression_code.html + +Copyright (c) 2003 Randy Reddig +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 names of the copyright holders 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. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define DDSLIB_C + + + +/* dependencies */ +#include "ddslib.h" + + + +/* endian tomfoolery */ +typedef union +{ + float f; + char c[ 4 ]; +} +floatSwapUnion; + + +#ifndef __BIG_ENDIAN__ + #ifdef _SGI_SOURCE + #define __BIG_ENDIAN__ + #endif +#endif + + +#ifdef __BIG_ENDIAN__ + + int DDSBigLong( int src ) { return src; } + short DDSBigShort( short src ) { return src; } + float DDSBigFloat( float src ) { return src; } + + int DDSLittleLong( int src ) + { + return ((src & 0xFF000000) >> 24) | + ((src & 0x00FF0000) >> 8) | + ((src & 0x0000FF00) << 8) | + ((src & 0x000000FF) << 24); + } + + short DDSLittleShort( short src ) + { + return ((src & 0xFF00) >> 8) | + ((src & 0x00FF) << 8); + } + + float DDSLittleFloat( float src ) + { + floatSwapUnion in,out; + in.f = src; + out.c[ 0 ] = in.c[ 3 ]; + out.c[ 1 ] = in.c[ 2 ]; + out.c[ 2 ] = in.c[ 1 ]; + out.c[ 3 ] = in.c[ 0 ]; + return out.f; + } + +#else /*__BIG_ENDIAN__*/ + + int DDSLittleLong( int src ) { return src; } + short DDSLittleShort( short src ) { return src; } + float DDSLittleFloat( float src ) { return src; } + + int DDSBigLong( int src ) + { + return ((src & 0xFF000000) >> 24) | + ((src & 0x00FF0000) >> 8) | + ((src & 0x0000FF00) << 8) | + ((src & 0x000000FF) << 24); + } + + short DDSBigShort( short src ) + { + return ((src & 0xFF00) >> 8) | + ((src & 0x00FF) << 8); + } + + float DDSBigFloat( float src ) + { + floatSwapUnion in,out; + in.f = src; + out.c[ 0 ] = in.c[ 3 ]; + out.c[ 1 ] = in.c[ 2 ]; + out.c[ 2 ] = in.c[ 1 ]; + out.c[ 3 ] = in.c[ 0 ]; + return out.f; + } + +#endif /*__BIG_ENDIAN__*/ + + + +/* +DDSDecodePixelFormat() +determines which pixel format the dds texture is in +*/ + +static void DDSDecodePixelFormat( ddsBuffer_t *dds, ddsPF_t *pf ) +{ + unsigned int fourCC; + + + /* dummy check */ + if( dds == NULL || pf == NULL ) + return; + + /* extract fourCC */ + fourCC = dds->pixelFormat.fourCC; + + /* test it */ + if( fourCC == 0 ) + *pf = DDS_PF_ARGB8888; + else if( fourCC == *((unsigned int*) "DXT1") ) + *pf = DDS_PF_DXT1; + else if( fourCC == *((unsigned int*) "DXT2") ) + *pf = DDS_PF_DXT2; + else if( fourCC == *((unsigned int*) "DXT3") ) + *pf = DDS_PF_DXT3; + else if( fourCC == *((unsigned int*) "DXT4") ) + *pf = DDS_PF_DXT4; + else if( fourCC == *((unsigned int*) "DXT5") ) + *pf = DDS_PF_DXT5; + else + *pf = DDS_PF_UNKNOWN; +} + + + +/* +DDSGetInfo() +extracts relevant info from a dds texture, returns 0 on success +*/ + +int DDSGetInfo( ddsBuffer_t *dds, int *width, int *height, ddsPF_t *pf ) +{ + /* dummy test */ + if( dds == NULL ) + return -1; + + /* test dds header */ + if( *((int*) dds->magic) != *((int*) "DDS ") ) + return -1; + if( DDSLittleLong( dds->size ) != 124 ) + return -1; + + /* extract width and height */ + if( width != NULL ) + *width = DDSLittleLong( dds->width ); + if( height != NULL ) + *height = DDSLittleLong( dds->height ); + + /* get pixel format */ + DDSDecodePixelFormat( dds, pf ); + + /* return ok */ + return 0; +} + + + +/* +DDSGetColorBlockColors() +extracts colors from a dds color block +*/ + +static void DDSGetColorBlockColors( ddsColorBlock_t *block, ddsColor_t colors[ 4 ] ) +{ + unsigned short word; + + + /* color 0 */ + word = DDSLittleShort( block->colors[ 0 ] ); + colors[ 0 ].a = 0xff; + + /* extract rgb bits */ + colors[ 0 ].b = (unsigned char) word; + colors[ 0 ].b <<= 3; + colors[ 0 ].b |= (colors[ 0 ].b >> 5); + word >>= 5; + colors[ 0 ].g = (unsigned char) word; + colors[ 0 ].g <<= 2; + colors[ 0 ].g |= (colors[ 0 ].g >> 5); + word >>= 6; + colors[ 0 ].r = (unsigned char) word; + colors[ 0 ].r <<= 3; + colors[ 0 ].r |= (colors[ 0 ].r >> 5); + + /* same for color 1 */ + word = DDSLittleShort( block->colors[ 1 ] ); + colors[ 1 ].a = 0xff; + + /* extract rgb bits */ + colors[ 1 ].b = (unsigned char) word; + colors[ 1 ].b <<= 3; + colors[ 1 ].b |= (colors[ 1 ].b >> 5); + word >>= 5; + colors[ 1 ].g = (unsigned char) word; + colors[ 1 ].g <<= 2; + colors[ 1 ].g |= (colors[ 1 ].g >> 5); + word >>= 6; + colors[ 1 ].r = (unsigned char) word; + colors[ 1 ].r <<= 3; + colors[ 1 ].r |= (colors[ 1 ].r >> 5); + + /* use this for all but the super-freak math method */ + if( block->colors[ 0 ] > block->colors[ 1 ] ) + { + /* four-color block: derive the other two colors. + 00 = color 0, 01 = color 1, 10 = color 2, 11 = color 3 + these two bit codes correspond to the 2-bit fields + stored in the 64-bit block. */ + + word = ((unsigned short) colors[ 0 ].r * 2 + (unsigned short) colors[ 1 ].r ) / 3; + /* no +1 for rounding */ + /* as bits have been shifted to 888 */ + colors[ 2 ].r = (unsigned char) word; + word = ((unsigned short) colors[ 0 ].g * 2 + (unsigned short) colors[ 1 ].g) / 3; + colors[ 2 ].g = (unsigned char) word; + word = ((unsigned short) colors[ 0 ].b * 2 + (unsigned short) colors[ 1 ].b) / 3; + colors[ 2 ].b = (unsigned char) word; + colors[ 2 ].a = 0xff; + + word = ((unsigned short) colors[ 0 ].r + (unsigned short) colors[ 1 ].r * 2) / 3; + colors[ 3 ].r = (unsigned char) word; + word = ((unsigned short) colors[ 0 ].g + (unsigned short) colors[ 1 ].g * 2) / 3; + colors[ 3 ].g = (unsigned char) word; + word = ((unsigned short) colors[ 0 ].b + (unsigned short) colors[ 1 ].b * 2) / 3; + colors[ 3 ].b = (unsigned char) word; + colors[ 3 ].a = 0xff; + } + else + { + /* three-color block: derive the other color. + 00 = color 0, 01 = color 1, 10 = color 2, + 11 = transparent. + These two bit codes correspond to the 2-bit fields + stored in the 64-bit block */ + + word = ((unsigned short) colors[ 0 ].r + (unsigned short) colors[ 1 ].r) / 2; + colors[ 2 ].r = (unsigned char) word; + word = ((unsigned short) colors[ 0 ].g + (unsigned short) colors[ 1 ].g) / 2; + colors[ 2 ].g = (unsigned char) word; + word = ((unsigned short) colors[ 0 ].b + (unsigned short) colors[ 1 ].b) / 2; + colors[ 2 ].b = (unsigned char) word; + colors[ 2 ].a = 0xff; + + /* random color to indicate alpha */ + colors[ 3 ].r = 0x00; + colors[ 3 ].g = 0xff; + colors[ 3 ].b = 0xff; + colors[ 3 ].a = 0x00; + } +} + + + +/* +DDSDecodeColorBlock() +decodes a dds color block +fixme: make endian-safe +*/ + +static void DDSDecodeColorBlock( unsigned int *pixel, ddsColorBlock_t *block, int width, unsigned int colors[ 4 ] ) +{ + int r, n; + unsigned int bits; + unsigned int masks[] = { 3, 12, 3 << 4, 3 << 6 }; /* bit masks = 00000011, 00001100, 00110000, 11000000 */ + int shift[] = { 0, 2, 4, 6 }; + + + /* r steps through lines in y */ + for( r = 0; r < 4; r++, pixel += (width - 4) ) /* no width * 4 as unsigned int ptr inc will * 4 */ + { + /* width * 4 bytes per pixel per line, each j dxtc row is 4 lines of pixels */ + + /* n steps through pixels */ + for( n = 0; n < 4; n++ ) + { + bits = block->row[ r ] & masks[ n ]; + bits >>= shift[ n ]; + + switch( bits ) + { + case 0: + *pixel = colors[ 0 ]; + pixel++; + break; + + case 1: + *pixel = colors[ 1 ]; + pixel++; + break; + + case 2: + *pixel = colors[ 2 ]; + pixel++; + break; + + case 3: + *pixel = colors[ 3 ]; + pixel++; + break; + + default: + /* invalid */ + pixel++; + break; + } + } + } +} + + + +/* +DDSDecodeAlphaExplicit() +decodes a dds explicit alpha block +*/ + +static void DDSDecodeAlphaExplicit( unsigned int *pixel, ddsAlphaBlockExplicit_t *alphaBlock, int width, unsigned int alphaZero ) +{ + int row, pix; + unsigned short word; + ddsColor_t color; + + + /* clear color */ + color.r = 0; + color.g = 0; + color.b = 0; + + /* walk rows */ + for( row = 0; row < 4; row++, pixel += (width - 4) ) + { + word = DDSLittleShort( alphaBlock->row[ row ] ); + + /* walk pixels */ + for( pix = 0; pix < 4; pix++ ) + { + /* zero the alpha bits of image pixel */ + *pixel &= alphaZero; + color.a = word & 0x000F; + color.a = color.a | (color.a << 4); + *pixel |= *((unsigned int*) &color); + word >>= 4; /* move next bits to lowest 4 */ + pixel++; /* move to next pixel in the row */ + + } + } +} + + + +/* +DDSDecodeAlpha3BitLinear() +decodes interpolated alpha block +*/ + +static void DDSDecodeAlpha3BitLinear( unsigned int *pixel, ddsAlphaBlock3BitLinear_t *alphaBlock, int width, unsigned int alphaZero ) +{ + + int row, pix; + unsigned int stuff; + unsigned char bits[ 4 ][ 4 ]; + unsigned short alphas[ 8 ]; + ddsColor_t aColors[ 4 ][ 4 ]; + + + /* get initial alphas */ + alphas[ 0 ] = alphaBlock->alpha0; + alphas[ 1 ] = alphaBlock->alpha1; + + /* 8-alpha block */ + if( alphas[ 0 ] > alphas[ 1 ] ) + { + /* 000 = alpha_0, 001 = alpha_1, others are interpolated */ + alphas[ 2 ] = ( 6 * alphas[ 0 ] + alphas[ 1 ]) / 7; /* bit code 010 */ + alphas[ 3 ] = ( 5 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 7; /* bit code 011 */ + alphas[ 4 ] = ( 4 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 7; /* bit code 100 */ + alphas[ 5 ] = ( 3 * alphas[ 0 ] + 4 * alphas[ 1 ]) / 7; /* bit code 101 */ + alphas[ 6 ] = ( 2 * alphas[ 0 ] + 5 * alphas[ 1 ]) / 7; /* bit code 110 */ + alphas[ 7 ] = ( alphas[ 0 ] + 6 * alphas[ 1 ]) / 7; /* bit code 111 */ + } + + /* 6-alpha block */ + else + { + /* 000 = alpha_0, 001 = alpha_1, others are interpolated */ + alphas[ 2 ] = (4 * alphas[ 0 ] + alphas[ 1 ]) / 5; /* bit code 010 */ + alphas[ 3 ] = (3 * alphas[ 0 ] + 2 * alphas[ 1 ]) / 5; /* bit code 011 */ + alphas[ 4 ] = (2 * alphas[ 0 ] + 3 * alphas[ 1 ]) / 5; /* bit code 100 */ + alphas[ 5 ] = ( alphas[ 0 ] + 4 * alphas[ 1 ]) / 5; /* bit code 101 */ + alphas[ 6 ] = 0; /* bit code 110 */ + alphas[ 7 ] = 255; /* bit code 111 */ + } + + /* decode 3-bit fields into array of 16 bytes with same value */ + + /* first two rows of 4 pixels each */ + stuff = *((unsigned int*) &(alphaBlock->stuff[ 0 ])); + + bits[ 0 ][ 0 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 0 ][ 1 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 0 ][ 2 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 0 ][ 3 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 0 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 1 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 2 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 1 ][ 3 ] = (unsigned char) (stuff & 0x00000007); + + /* last two rows */ + stuff = *((unsigned int*) &(alphaBlock->stuff[ 3 ])); /* last 3 bytes */ + + bits[ 2 ][ 0 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 2 ][ 1 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 2 ][ 2 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 2 ][ 3 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 0 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 1 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 2 ] = (unsigned char) (stuff & 0x00000007); + stuff >>= 3; + bits[ 3 ][ 3 ] = (unsigned char) (stuff & 0x00000007); + + /* decode the codes into alpha values */ + for( row = 0; row < 4; row++ ) + { + for( pix=0; pix < 4; pix++ ) + { + aColors[ row ][ pix ].r = 0; + aColors[ row ][ pix ].g = 0; + aColors[ row ][ pix ].b = 0; + aColors[ row ][ pix ].a = (unsigned char) alphas[ bits[ row ][ pix ] ]; + } + } + + /* write out alpha values to the image bits */ + for( row = 0; row < 4; row++, pixel += width-4 ) + { + for( pix = 0; pix < 4; pix++ ) + { + /* zero the alpha bits of image pixel */ + *pixel &= alphaZero; + + /* or the bits into the prev. nulled alpha */ + *pixel |= *((unsigned int*) &(aColors[ row ][ pix ])); + pixel++; + } + } +} + + + +/* +DDSDecompressDXT1() +decompresses a dxt1 format texture +*/ + +static int DDSDecompressDXT1( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) +{ + int x, y, xBlocks, yBlocks; + unsigned int *pixel; + ddsColorBlock_t *block; + ddsColor_t colors[ 4 ]; + + + /* setup */ + xBlocks = width / 4; + yBlocks = height / 4; + + /* walk y */ + for( y = 0; y < yBlocks; y++ ) + { + /* 8 bytes per block */ + block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 8); + + /* walk x */ + for( x = 0; x < xBlocks; x++, block++ ) + { + DDSGetColorBlockColors( block, colors ); + pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4); + DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors ); + } + } + + /* return ok */ + return 0; +} + + + +/* +DDSDecompressDXT3() +decompresses a dxt3 format texture +*/ + +static int DDSDecompressDXT3( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) +{ + int x, y, xBlocks, yBlocks; + unsigned int *pixel, alphaZero; + ddsColorBlock_t *block; + ddsAlphaBlockExplicit_t *alphaBlock; + ddsColor_t colors[ 4 ]; + + + /* setup */ + xBlocks = width / 4; + yBlocks = height / 4; + + /* create zero alpha */ + colors[ 0 ].a = 0; + colors[ 0 ].r = 0xFF; + colors[ 0 ].g = 0xFF; + colors[ 0 ].b = 0xFF; + alphaZero = *((unsigned int*) &colors[ 0 ]); + + /* walk y */ + for( y = 0; y < yBlocks; y++ ) + { + /* 8 bytes per block, 1 block for alpha, 1 block for color */ + block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 16); + + /* walk x */ + for( x = 0; x < xBlocks; x++, block++ ) + { + /* get alpha block */ + alphaBlock = (ddsAlphaBlockExplicit_t*) block; + + /* get color block */ + block++; + DDSGetColorBlockColors( block, colors ); + + /* decode color block */ + pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4); + DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors ); + + /* overwrite alpha bits with alpha block */ + DDSDecodeAlphaExplicit( pixel, alphaBlock, width, alphaZero ); + } + } + + /* return ok */ + return 0; +} + + + +/* +DDSDecompressDXT5() +decompresses a dxt5 format texture +*/ + +static int DDSDecompressDXT5( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) +{ + int x, y, xBlocks, yBlocks; + unsigned int *pixel, alphaZero; + ddsColorBlock_t *block; + ddsAlphaBlock3BitLinear_t *alphaBlock; + ddsColor_t colors[ 4 ]; + + + /* setup */ + xBlocks = width / 4; + yBlocks = height / 4; + + /* create zero alpha */ + colors[ 0 ].a = 0; + colors[ 0 ].r = 0xFF; + colors[ 0 ].g = 0xFF; + colors[ 0 ].b = 0xFF; + alphaZero = *((unsigned int*) &colors[ 0 ]); + + /* walk y */ + for( y = 0; y < yBlocks; y++ ) + { + /* 8 bytes per block, 1 block for alpha, 1 block for color */ + block = (ddsColorBlock_t*) ((unsigned int) dds->data + y * xBlocks * 16); + + /* walk x */ + for( x = 0; x < xBlocks; x++, block++ ) + { + /* get alpha block */ + alphaBlock = (ddsAlphaBlock3BitLinear_t*) block; + + /* get color block */ + block++; + DDSGetColorBlockColors( block, colors ); + + /* decode color block */ + pixel = (unsigned int*) (pixels + x * 16 + (y * 4) * width * 4); + DDSDecodeColorBlock( pixel, block, width, (unsigned int*) colors ); + + /* overwrite alpha bits with alpha block */ + DDSDecodeAlpha3BitLinear( pixel, alphaBlock, width, alphaZero ); + } + } + + /* return ok */ + return 0; +} + + + +/* +DDSDecompressDXT2() +decompresses a dxt2 format texture (fixme: un-premultiply alpha) +*/ + +static int DDSDecompressDXT2( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) +{ + int r; + + + /* decompress dxt3 first */ + r = DDSDecompressDXT3( dds, width, height, pixels ); + + /* return to sender */ + return r; +} + + + +/* +DDSDecompressDXT4() +decompresses a dxt4 format texture (fixme: un-premultiply alpha) +*/ + +static int DDSDecompressDXT4( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) +{ + int r; + + + /* decompress dxt5 first */ + r = DDSDecompressDXT5( dds, width, height, pixels ); + + /* return to sender */ + return r; +} + + + +/* +DDSDecompressARGB8888() +decompresses an argb 8888 format texture +*/ + +static int DDSDecompressARGB8888( ddsBuffer_t *dds, int width, int height, unsigned char *pixels ) +{ + int x, y; + unsigned char *in, *out; + + + /* setup */ + in = dds->data; + out = pixels; + + /* walk y */ + for( y = 0; y < height; y++ ) + { + /* walk x */ + for( x = 0; x < width; x++ ) + { + *out++ = *in++; + *out++ = *in++; + *out++ = *in++; + *out++ = *in++; + } + } + + /* return ok */ + return 0; +} + + + +/* +DDSDecompress() +decompresses a dds texture into an rgba image buffer, returns 0 on success +*/ + +int DDSDecompress( ddsBuffer_t *dds, unsigned char *pixels ) +{ + int width, height, r; + ddsPF_t pf; + + + /* get dds info */ + r = DDSGetInfo( dds, &width, &height, &pf ); + if( r ) + return r; + + /* decompress */ + switch( pf ) + { + case DDS_PF_ARGB8888: + /* fixme: support other [a]rgb formats */ + r = DDSDecompressARGB8888( dds, width, height, pixels ); + break; + + case DDS_PF_DXT1: + r = DDSDecompressDXT1( dds, width, height, pixels ); + break; + + case DDS_PF_DXT2: + r = DDSDecompressDXT2( dds, width, height, pixels ); + break; + + case DDS_PF_DXT3: + r = DDSDecompressDXT3( dds, width, height, pixels ); + break; + + case DDS_PF_DXT4: + r = DDSDecompressDXT4( dds, width, height, pixels ); + break; + + case DDS_PF_DXT5: + r = DDSDecompressDXT5( dds, width, height, pixels ); + break; + + default: + case DDS_PF_UNKNOWN: + memset( pixels, 0xFF, width * height * 4 ); + r = -1; + break; + } + + /* return to sender */ + return r; +} + diff --git a/libs/ddslib/ddslib.vcproj b/libs/ddslib/ddslib.vcproj new file mode 100644 index 00000000..e79f997a --- /dev/null +++ b/libs/ddslib/ddslib.vcproj @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/igl_to_qgl.h b/libs/igl_to_qgl.h new file mode 100644 index 00000000..a71ecd2e --- /dev/null +++ b/libs/igl_to_qgl.h @@ -0,0 +1,806 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* +IGL tp QGL mapping header +Copyright (C) 2002 Splash Damage Ltd. +*/ + +#ifndef _IGL_TO_QGL_H_ +#define _IGL_TO_QGL_H_ + +#ifdef _WIN32 +#include +#endif + +enum VIEWTYPE {YZ, XZ, XY}; + +#include "igl.h" + +#ifndef APIENTRY + #define APIENTRY +#endif + +void ( APIENTRY * qglAccum )(GLenum op, GLfloat value); +void ( APIENTRY * qglAlphaFunc )(GLenum func, GLclampf ref); +GLboolean ( APIENTRY * qglAreTexturesResident )(GLsizei n, const GLuint *textures, GLboolean *residences); +void ( APIENTRY * qglArrayElement )(GLint i); +void ( APIENTRY * qglBegin )(GLenum mode); +void ( APIENTRY * qglBindTexture )(GLenum target, GLuint texture); +void ( APIENTRY * qglBitmap )(GLsizei width, GLsizei height, GLfloat xorig, GLfloat yorig, GLfloat xmove, GLfloat ymove, const GLubyte *bitmap); +void ( APIENTRY * qglBlendFunc )(GLenum sfactor, GLenum dfactor); +void ( APIENTRY * qglCallList )(GLuint list); +void ( APIENTRY * qglCallLists )(GLsizei n, GLenum type, const GLvoid *lists); +void ( APIENTRY * qglClear )(GLbitfield mask); +void ( APIENTRY * qglClearAccum )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +void ( APIENTRY * qglClearColor )(GLclampf red, GLclampf green, GLclampf blue, GLclampf alpha); +void ( APIENTRY * qglClearDepth )(GLclampd depth); +void ( APIENTRY * qglClearIndex )(GLfloat c); +void ( APIENTRY * qglClearStencil )(GLint s); +void ( APIENTRY * qglClipPlane )(GLenum plane, const GLdouble *equation); +void ( APIENTRY * qglColor3b )(GLbyte red, GLbyte green, GLbyte blue); +void ( APIENTRY * qglColor3bv )(const GLbyte *v); +void ( APIENTRY * qglColor3d )(GLdouble red, GLdouble green, GLdouble blue); +void ( APIENTRY * qglColor3dv )(const GLdouble *v); +void ( APIENTRY * qglColor3f )(GLfloat red, GLfloat green, GLfloat blue); +void ( APIENTRY * qglColor3fv )(const GLfloat *v); +void ( APIENTRY * qglColor3i )(GLint red, GLint green, GLint blue); +void ( APIENTRY * qglColor3iv )(const GLint *v); +void ( APIENTRY * qglColor3s )(GLshort red, GLshort green, GLshort blue); +void ( APIENTRY * qglColor3sv )(const GLshort *v); +void ( APIENTRY * qglColor3ub )(GLubyte red, GLubyte green, GLubyte blue); +void ( APIENTRY * qglColor3ubv )(const GLubyte *v); +void ( APIENTRY * qglColor3ui )(GLuint red, GLuint green, GLuint blue); +void ( APIENTRY * qglColor3uiv )(const GLuint *v); +void ( APIENTRY * qglColor3us )(GLushort red, GLushort green, GLushort blue); +void ( APIENTRY * qglColor3usv )(const GLushort *v); +void ( APIENTRY * qglColor4b )(GLbyte red, GLbyte green, GLbyte blue, GLbyte alpha); +void ( APIENTRY * qglColor4bv )(const GLbyte *v); +void ( APIENTRY * qglColor4d )(GLdouble red, GLdouble green, GLdouble blue, GLdouble alpha); +void ( APIENTRY * qglColor4dv )(const GLdouble *v); +void ( APIENTRY * qglColor4f )(GLfloat red, GLfloat green, GLfloat blue, GLfloat alpha); +void ( APIENTRY * qglColor4fv )(const GLfloat *v); +void ( APIENTRY * qglColor4i )(GLint red, GLint green, GLint blue, GLint alpha); +void ( APIENTRY * qglColor4iv )(const GLint *v); +void ( APIENTRY * qglColor4s )(GLshort red, GLshort green, GLshort blue, GLshort alpha); +void ( APIENTRY * qglColor4sv )(const GLshort *v); +void ( APIENTRY * qglColor4ub )(GLubyte red, GLubyte green, GLubyte blue, GLubyte alpha); +void ( APIENTRY * qglColor4ubv )(const GLubyte *v); +void ( APIENTRY * qglColor4ui )(GLuint red, GLuint green, GLuint blue, GLuint alpha); +void ( APIENTRY * qglColor4uiv )(const GLuint *v); +void ( APIENTRY * qglColor4us )(GLushort red, GLushort green, GLushort blue, GLushort alpha); +void ( APIENTRY * qglColor4usv )(const GLushort *v); +void ( APIENTRY * qglColorMask )(GLboolean red, GLboolean green, GLboolean blue, GLboolean alpha); +void ( APIENTRY * qglColorMaterial )(GLenum face, GLenum mode); +void ( APIENTRY * qglColorPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglCopyPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum type); +void ( APIENTRY * qglCopyTexImage1D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLint border); +void ( APIENTRY * qglCopyTexImage2D )(GLenum target, GLint level, GLenum internalFormat, GLint x, GLint y, GLsizei width, GLsizei height, GLint border); +void ( APIENTRY * qglCopyTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLint x, GLint y, GLsizei width); +void ( APIENTRY * qglCopyTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLint x, GLint y, GLsizei width, GLsizei height); +void ( APIENTRY * qglCullFace )(GLenum mode); +void ( APIENTRY * qglDeleteLists )(GLuint list, GLsizei range); +void ( APIENTRY * qglDeleteTextures )(GLsizei n, const GLuint *textures); +void ( APIENTRY * qglDepthFunc )(GLenum func); +void ( APIENTRY * qglDepthMask )(GLboolean flag); +void ( APIENTRY * qglDepthRange )(GLclampd zNear, GLclampd zFar); +void ( APIENTRY * qglDisable )(GLenum cap); +void ( APIENTRY * qglDisableClientState )(GLenum array); +void ( APIENTRY * qglDrawArrays )(GLenum mode, GLint first, GLsizei count); +void ( APIENTRY * qglDrawBuffer )(GLenum mode); +void ( APIENTRY * qglDrawElements )(GLenum mode, GLsizei count, GLenum type, const GLvoid *indices); +void ( APIENTRY * qglDrawPixels )(GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglEdgeFlag )(GLboolean flag); +void ( APIENTRY * qglEdgeFlagPointer )(GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglEdgeFlagv )(const GLboolean *flag); +void ( APIENTRY * qglEnable )(GLenum cap); +void ( APIENTRY * qglEnableClientState )(GLenum array); +void ( APIENTRY * qglEnd )(void); +void ( APIENTRY * qglEndList )(void); +void ( APIENTRY * qglEvalCoord1d )(GLdouble u); +void ( APIENTRY * qglEvalCoord1dv )(const GLdouble *u); +void ( APIENTRY * qglEvalCoord1f )(GLfloat u); +void ( APIENTRY * qglEvalCoord1fv )(const GLfloat *u); +void ( APIENTRY * qglEvalCoord2d )(GLdouble u, GLdouble v); +void ( APIENTRY * qglEvalCoord2dv )(const GLdouble *u); +void ( APIENTRY * qglEvalCoord2f )(GLfloat u, GLfloat v); +void ( APIENTRY * qglEvalCoord2fv )(const GLfloat *u); +void ( APIENTRY * qglEvalMesh1 )(GLenum mode, GLint i1, GLint i2); +void ( APIENTRY * qglEvalMesh2 )(GLenum mode, GLint i1, GLint i2, GLint j1, GLint j2); +void ( APIENTRY * qglEvalPoint1 )(GLint i); +void ( APIENTRY * qglEvalPoint2 )(GLint i, GLint j); +void ( APIENTRY * qglFeedbackBuffer )(GLsizei size, GLenum type, GLfloat *buffer); +void ( APIENTRY * qglFinish )(void); +void ( APIENTRY * qglFlush )(void); +void ( APIENTRY * qglFogf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglFogfv )(GLenum pname, const GLfloat *params); +void ( APIENTRY * qglFogi )(GLenum pname, GLint param); +void ( APIENTRY * qglFogiv )(GLenum pname, const GLint *params); +void ( APIENTRY * qglFrontFace )(GLenum mode); +void ( APIENTRY * qglFrustum )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +GLuint ( APIENTRY * qglGenLists )(GLsizei range); +void ( APIENTRY * qglGenTextures )(GLsizei n, GLuint *textures); +void ( APIENTRY * qglGetBooleanv )(GLenum pname, GLboolean *params); +void ( APIENTRY * qglGetClipPlane )(GLenum plane, GLdouble *equation); +void ( APIENTRY * qglGetDoublev )(GLenum pname, GLdouble *params); +GLenum ( APIENTRY * qglGetError )(void); +void ( APIENTRY * qglGetFloatv )(GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetIntegerv )(GLenum pname, GLint *params); +void ( APIENTRY * qglGetLightfv )(GLenum light, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetLightiv )(GLenum light, GLenum pname, GLint *params); +void ( APIENTRY * qglGetMapdv )(GLenum target, GLenum query, GLdouble *v); +void ( APIENTRY * qglGetMapfv )(GLenum target, GLenum query, GLfloat *v); +void ( APIENTRY * qglGetMapiv )(GLenum target, GLenum query, GLint *v); +void ( APIENTRY * qglGetMaterialfv )(GLenum face, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetMaterialiv )(GLenum face, GLenum pname, GLint *params); +void ( APIENTRY * qglGetPixelMapfv )(GLenum map, GLfloat *values); +void ( APIENTRY * qglGetPixelMapuiv )(GLenum map, GLuint *values); +void ( APIENTRY * qglGetPixelMapusv )(GLenum map, GLushort *values); +void ( APIENTRY * qglGetPointerv )(GLenum pname, GLvoid* *params); +void ( APIENTRY * qglGetPolygonStipple )(GLubyte *mask); +const GLubyte * ( APIENTRY * qglGetString )(GLenum name); +void ( APIENTRY * qglGetTexEnvfv )(GLenum target, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexEnviv )(GLenum target, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexGendv )(GLenum coord, GLenum pname, GLdouble *params); +void ( APIENTRY * qglGetTexGenfv )(GLenum coord, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexGeniv )(GLenum coord, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexImage )(GLenum target, GLint level, GLenum format, GLenum type, GLvoid *pixels); +void ( APIENTRY * qglGetTexLevelParameterfv )(GLenum target, GLint level, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexLevelParameteriv )(GLenum target, GLint level, GLenum pname, GLint *params); +void ( APIENTRY * qglGetTexParameterfv )(GLenum target, GLenum pname, GLfloat *params); +void ( APIENTRY * qglGetTexParameteriv )(GLenum target, GLenum pname, GLint *params); +void ( APIENTRY * qglHint )(GLenum target, GLenum mode); +void ( APIENTRY * qglIndexMask )(GLuint mask); +void ( APIENTRY * qglIndexPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglIndexd )(GLdouble c); +void ( APIENTRY * qglIndexdv )(const GLdouble *c); +void ( APIENTRY * qglIndexf )(GLfloat c); +void ( APIENTRY * qglIndexfv )(const GLfloat *c); +void ( APIENTRY * qglIndexi )(GLint c); +void ( APIENTRY * qglIndexiv )(const GLint *c); +void ( APIENTRY * qglIndexs )(GLshort c); +void ( APIENTRY * qglIndexsv )(const GLshort *c); +void ( APIENTRY * qglIndexub )(GLubyte c); +void ( APIENTRY * qglIndexubv )(const GLubyte *c); +void ( APIENTRY * qglInitNames )(void); +void ( APIENTRY * qglInterleavedArrays )(GLenum format, GLsizei stride, const GLvoid *pointer); +GLboolean ( APIENTRY * qglIsEnabled )(GLenum cap); +GLboolean ( APIENTRY * qglIsList )(GLuint list); +GLboolean ( APIENTRY * qglIsTexture )(GLuint texture); +void ( APIENTRY * qglLightModelf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglLightModelfv )(GLenum pname, const GLfloat *params); +void ( APIENTRY * qglLightModeli )(GLenum pname, GLint param); +void ( APIENTRY * qglLightModeliv )(GLenum pname, const GLint *params); +void ( APIENTRY * qglLightf )(GLenum light, GLenum pname, GLfloat param); +void ( APIENTRY * qglLightfv )(GLenum light, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglLighti )(GLenum light, GLenum pname, GLint param); +void ( APIENTRY * qglLightiv )(GLenum light, GLenum pname, const GLint *params); +void ( APIENTRY * qglLineStipple )(GLint factor, GLushort pattern); +void ( APIENTRY * qglLineWidth )(GLfloat width); +void ( APIENTRY * qglListBase )(GLuint base); +void ( APIENTRY * qglLoadIdentity )(void); +void ( APIENTRY * qglLoadMatrixd )(const GLdouble *m); +void ( APIENTRY * qglLoadMatrixf )(const GLfloat *m); +void ( APIENTRY * qglLoadName )(GLuint name); +void ( APIENTRY * qglLogicOp )(GLenum opcode); +void ( APIENTRY * qglMap1d )(GLenum target, GLdouble u1, GLdouble u2, GLint stride, GLint order, const GLdouble *points); +void ( APIENTRY * qglMap1f )(GLenum target, GLfloat u1, GLfloat u2, GLint stride, GLint order, const GLfloat *points); +void ( APIENTRY * qglMap2d )(GLenum target, GLdouble u1, GLdouble u2, GLint ustride, GLint uorder, GLdouble v1, GLdouble v2, GLint vstride, GLint vorder, const GLdouble *points); +void ( APIENTRY * qglMap2f )(GLenum target, GLfloat u1, GLfloat u2, GLint ustride, GLint uorder, GLfloat v1, GLfloat v2, GLint vstride, GLint vorder, const GLfloat *points); +void ( APIENTRY * qglMapGrid1d )(GLint un, GLdouble u1, GLdouble u2); +void ( APIENTRY * qglMapGrid1f )(GLint un, GLfloat u1, GLfloat u2); +void ( APIENTRY * qglMapGrid2d )(GLint un, GLdouble u1, GLdouble u2, GLint vn, GLdouble v1, GLdouble v2); +void ( APIENTRY * qglMapGrid2f )(GLint un, GLfloat u1, GLfloat u2, GLint vn, GLfloat v1, GLfloat v2); +void ( APIENTRY * qglMaterialf )(GLenum face, GLenum pname, GLfloat param); +void ( APIENTRY * qglMaterialfv )(GLenum face, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglMateriali )(GLenum face, GLenum pname, GLint param); +void ( APIENTRY * qglMaterialiv )(GLenum face, GLenum pname, const GLint *params); +void ( APIENTRY * qglMatrixMode )(GLenum mode); +void ( APIENTRY * qglMultMatrixd )(const GLdouble *m); +void ( APIENTRY * qglMultMatrixf )(const GLfloat *m); +void ( APIENTRY * qglNewList )(GLuint list, GLenum mode); +void ( APIENTRY * qglNormal3b )(GLbyte nx, GLbyte ny, GLbyte nz); +void ( APIENTRY * qglNormal3bv )(const GLbyte *v); +void ( APIENTRY * qglNormal3d )(GLdouble nx, GLdouble ny, GLdouble nz); +void ( APIENTRY * qglNormal3dv )(const GLdouble *v); +void ( APIENTRY * qglNormal3f )(GLfloat nx, GLfloat ny, GLfloat nz); +void ( APIENTRY * qglNormal3fv )(const GLfloat *v); +void ( APIENTRY * qglNormal3i )(GLint nx, GLint ny, GLint nz); +void ( APIENTRY * qglNormal3iv )(const GLint *v); +void ( APIENTRY * qglNormal3s )(GLshort nx, GLshort ny, GLshort nz); +void ( APIENTRY * qglNormal3sv )(const GLshort *v); +void ( APIENTRY * qglNormalPointer )(GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglOrtho )(GLdouble left, GLdouble right, GLdouble bottom, GLdouble top, GLdouble zNear, GLdouble zFar); +void ( APIENTRY * qglPassThrough )(GLfloat token); +void ( APIENTRY * qglPixelMapfv )(GLenum map, GLsizei mapsize, const GLfloat *values); +void ( APIENTRY * qglPixelMapuiv )(GLenum map, GLsizei mapsize, const GLuint *values); +void ( APIENTRY * qglPixelMapusv )(GLenum map, GLsizei mapsize, const GLushort *values); +void ( APIENTRY * qglPixelStoref )(GLenum pname, GLfloat param); +void ( APIENTRY * qglPixelStorei )(GLenum pname, GLint param); +void ( APIENTRY * qglPixelTransferf )(GLenum pname, GLfloat param); +void ( APIENTRY * qglPixelTransferi )(GLenum pname, GLint param); +void ( APIENTRY * qglPixelZoom )(GLfloat xfactor, GLfloat yfactor); +void ( APIENTRY * qglPointSize )(GLfloat size); +void ( APIENTRY * qglPolygonMode )(GLenum face, GLenum mode); +void ( APIENTRY * qglPolygonOffset )(GLfloat factor, GLfloat units); +void ( APIENTRY * qglPolygonStipple )(const GLubyte *mask); +void ( APIENTRY * qglPopAttrib )(void); +void ( APIENTRY * qglPopClientAttrib )(void); +void ( APIENTRY * qglPopMatrix )(void); +void ( APIENTRY * qglPopName )(void); +void ( APIENTRY * qglPrioritizeTextures )(GLsizei n, const GLuint *textures, const GLclampf *priorities); +void ( APIENTRY * qglPushAttrib )(GLbitfield mask); +void ( APIENTRY * qglPushClientAttrib )(GLbitfield mask); +void ( APIENTRY * qglPushMatrix )(void); +void ( APIENTRY * qglPushName )(GLuint name); +void ( APIENTRY * qglRasterPos2d )(GLdouble x, GLdouble y); +void ( APIENTRY * qglRasterPos2dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos2f )(GLfloat x, GLfloat y); +void ( APIENTRY * qglRasterPos2fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos2i )(GLint x, GLint y); +void ( APIENTRY * qglRasterPos2iv )(const GLint *v); +void ( APIENTRY * qglRasterPos2s )(GLshort x, GLshort y); +void ( APIENTRY * qglRasterPos2sv )(const GLshort *v); +void ( APIENTRY * qglRasterPos3d )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglRasterPos3dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos3f )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglRasterPos3fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos3i )(GLint x, GLint y, GLint z); +void ( APIENTRY * qglRasterPos3iv )(const GLint *v); +void ( APIENTRY * qglRasterPos3s )(GLshort x, GLshort y, GLshort z); +void ( APIENTRY * qglRasterPos3sv )(const GLshort *v); +void ( APIENTRY * qglRasterPos4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +void ( APIENTRY * qglRasterPos4dv )(const GLdouble *v); +void ( APIENTRY * qglRasterPos4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +void ( APIENTRY * qglRasterPos4fv )(const GLfloat *v); +void ( APIENTRY * qglRasterPos4i )(GLint x, GLint y, GLint z, GLint w); +void ( APIENTRY * qglRasterPos4iv )(const GLint *v); +void ( APIENTRY * qglRasterPos4s )(GLshort x, GLshort y, GLshort z, GLshort w); +void ( APIENTRY * qglRasterPos4sv )(const GLshort *v); +void ( APIENTRY * qglReadBuffer )(GLenum mode); +void ( APIENTRY * qglReadPixels )(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLvoid *pixels); +void ( APIENTRY * qglRectd )(GLdouble x1, GLdouble y1, GLdouble x2, GLdouble y2); +void ( APIENTRY * qglRectdv )(const GLdouble *v1, const GLdouble *v2); +void ( APIENTRY * qglRectf )(GLfloat x1, GLfloat y1, GLfloat x2, GLfloat y2); +void ( APIENTRY * qglRectfv )(const GLfloat *v1, const GLfloat *v2); +void ( APIENTRY * qglRecti )(GLint x1, GLint y1, GLint x2, GLint y2); +void ( APIENTRY * qglRectiv )(const GLint *v1, const GLint *v2); +void ( APIENTRY * qglRects )(GLshort x1, GLshort y1, GLshort x2, GLshort y2); +void ( APIENTRY * qglRectsv )(const GLshort *v1, const GLshort *v2); +GLint ( APIENTRY * qglRenderMode )(GLenum mode); +void ( APIENTRY * qglRotated )(GLdouble angle, GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglRotatef )(GLfloat angle, GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglScaled )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglScalef )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglScissor )(GLint x, GLint y, GLsizei width, GLsizei height); +void ( APIENTRY * qglSelectBuffer )(GLsizei size, GLuint *buffer); +void ( APIENTRY * qglShadeModel )(GLenum mode); +void ( APIENTRY * qglStencilFunc )(GLenum func, GLint ref, GLuint mask); +void ( APIENTRY * qglStencilMask )(GLuint mask); +void ( APIENTRY * qglStencilOp )(GLenum fail, GLenum zfail, GLenum zpass); +void ( APIENTRY * qglTexCoord1d )(GLdouble s); +void ( APIENTRY * qglTexCoord1dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord1f )(GLfloat s); +void ( APIENTRY * qglTexCoord1fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord1i )(GLint s); +void ( APIENTRY * qglTexCoord1iv )(const GLint *v); +void ( APIENTRY * qglTexCoord1s )(GLshort s); +void ( APIENTRY * qglTexCoord1sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord2d )(GLdouble s, GLdouble t); +void ( APIENTRY * qglTexCoord2dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord2f )(GLfloat s, GLfloat t); +void ( APIENTRY * qglTexCoord2fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord2i )(GLint s, GLint t); +void ( APIENTRY * qglTexCoord2iv )(const GLint *v); +void ( APIENTRY * qglTexCoord2s )(GLshort s, GLshort t); +void ( APIENTRY * qglTexCoord2sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord3d )(GLdouble s, GLdouble t, GLdouble r); +void ( APIENTRY * qglTexCoord3dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord3f )(GLfloat s, GLfloat t, GLfloat r); +void ( APIENTRY * qglTexCoord3fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord3i )(GLint s, GLint t, GLint r); +void ( APIENTRY * qglTexCoord3iv )(const GLint *v); +void ( APIENTRY * qglTexCoord3s )(GLshort s, GLshort t, GLshort r); +void ( APIENTRY * qglTexCoord3sv )(const GLshort *v); +void ( APIENTRY * qglTexCoord4d )(GLdouble s, GLdouble t, GLdouble r, GLdouble q); +void ( APIENTRY * qglTexCoord4dv )(const GLdouble *v); +void ( APIENTRY * qglTexCoord4f )(GLfloat s, GLfloat t, GLfloat r, GLfloat q); +void ( APIENTRY * qglTexCoord4fv )(const GLfloat *v); +void ( APIENTRY * qglTexCoord4i )(GLint s, GLint t, GLint r, GLint q); +void ( APIENTRY * qglTexCoord4iv )(const GLint *v); +void ( APIENTRY * qglTexCoord4s )(GLshort s, GLshort t, GLshort r, GLshort q); +void ( APIENTRY * qglTexCoord4sv )(const GLshort *v); +void ( APIENTRY * qglTexCoordPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglTexEnvf )(GLenum target, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexEnvfv )(GLenum target, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexEnvi )(GLenum target, GLenum pname, GLint param); +void ( APIENTRY * qglTexEnviv )(GLenum target, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexGend )(GLenum coord, GLenum pname, GLdouble param); +void ( APIENTRY * qglTexGendv )(GLenum coord, GLenum pname, const GLdouble *params); +void ( APIENTRY * qglTexGenf )(GLenum coord, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexGenfv )(GLenum coord, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexGeni )(GLenum coord, GLenum pname, GLint param); +void ( APIENTRY * qglTexGeniv )(GLenum coord, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexImage1D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexImage2D )(GLenum target, GLint level, GLint internalformat, GLsizei width, GLsizei height, GLint border, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexParameterf )(GLenum target, GLenum pname, GLfloat param); +void ( APIENTRY * qglTexParameterfv )(GLenum target, GLenum pname, const GLfloat *params); +void ( APIENTRY * qglTexParameteri )(GLenum target, GLenum pname, GLint param); +void ( APIENTRY * qglTexParameteriv )(GLenum target, GLenum pname, const GLint *params); +void ( APIENTRY * qglTexSubImage1D )(GLenum target, GLint level, GLint xoffset, GLsizei width, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTexSubImage2D )(GLenum target, GLint level, GLint xoffset, GLint yoffset, GLsizei width, GLsizei height, GLenum format, GLenum type, const GLvoid *pixels); +void ( APIENTRY * qglTranslated )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglTranslatef )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglVertex2d )(GLdouble x, GLdouble y); +void ( APIENTRY * qglVertex2dv )(const GLdouble *v); +void ( APIENTRY * qglVertex2f )(GLfloat x, GLfloat y); +void ( APIENTRY * qglVertex2fv )(const GLfloat *v); +void ( APIENTRY * qglVertex2i )(GLint x, GLint y); +void ( APIENTRY * qglVertex2iv )(const GLint *v); +void ( APIENTRY * qglVertex2s )(GLshort x, GLshort y); +void ( APIENTRY * qglVertex2sv )(const GLshort *v); +void ( APIENTRY * qglVertex3d )(GLdouble x, GLdouble y, GLdouble z); +void ( APIENTRY * qglVertex3dv )(const GLdouble *v); +void ( APIENTRY * qglVertex3f )(GLfloat x, GLfloat y, GLfloat z); +void ( APIENTRY * qglVertex3fv )(const GLfloat *v); +void ( APIENTRY * qglVertex3i )(GLint x, GLint y, GLint z); +void ( APIENTRY * qglVertex3iv )(const GLint *v); +void ( APIENTRY * qglVertex3s )(GLshort x, GLshort y, GLshort z); +void ( APIENTRY * qglVertex3sv )(const GLshort *v); +void ( APIENTRY * qglVertex4d )(GLdouble x, GLdouble y, GLdouble z, GLdouble w); +void ( APIENTRY * qglVertex4dv )(const GLdouble *v); +void ( APIENTRY * qglVertex4f )(GLfloat x, GLfloat y, GLfloat z, GLfloat w); +void ( APIENTRY * qglVertex4fv )(const GLfloat *v); +void ( APIENTRY * qglVertex4i )(GLint x, GLint y, GLint z, GLint w); +void ( APIENTRY * qglVertex4iv )(const GLint *v); +void ( APIENTRY * qglVertex4s )(GLshort x, GLshort y, GLshort z, GLshort w); +void ( APIENTRY * qglVertex4sv )(const GLshort *v); +void ( APIENTRY * qglVertexPointer )(GLint size, GLenum type, GLsizei stride, const GLvoid *pointer); +void ( APIENTRY * qglViewport )(GLint x, GLint y, GLsizei width, GLsizei height); + +void ( APIENTRY * qglPointParameterfEXT)( GLenum param, GLfloat value ); +void ( APIENTRY * qglPointParameterfvEXT)( GLenum param, const GLfloat *value ); +void ( APIENTRY * qglColorTableEXT)( int, int, int, int, int, const void * ); + +void ( APIENTRY * qglMTexCoord2fSGIS)( GLenum, GLfloat, GLfloat ); +void ( APIENTRY * qglSelectTextureSGIS)( GLenum ); + +void ( APIENTRY * qglActiveTextureARB) (GLenum texture); +void ( APIENTRY * qglClientActiveTextureARB) (GLenum texture); +void ( APIENTRY * qglMultiTexCoord1dARB) (GLenum target, GLdouble s); +void ( APIENTRY * qglMultiTexCoord1dvARB) (GLenum target, const GLdouble *v); +void ( APIENTRY * qglMultiTexCoord1fARB) (GLenum target, GLfloat s); +void ( APIENTRY * qglMultiTexCoord1fvARB) (GLenum target, const GLfloat *v); +void ( APIENTRY * qglMultiTexCoord1iARB) (GLenum target, GLint s); +void ( APIENTRY * qglMultiTexCoord1ivARB) (GLenum target, const GLint *v); +void ( APIENTRY * qglMultiTexCoord1sARB) (GLenum target, GLshort s); +void ( APIENTRY * qglMultiTexCoord1svARB) (GLenum target, const GLshort *v); +void ( APIENTRY * qglMultiTexCoord2dARB) (GLenum target, GLdouble s); +void ( APIENTRY * qglMultiTexCoord2dvARB) (GLenum target, const GLdouble *v); +void ( APIENTRY * qglMultiTexCoord2fARB) (GLenum target, GLfloat s); +void ( APIENTRY * qglMultiTexCoord2fvARB) (GLenum target, const GLfloat *v); +void ( APIENTRY * qglMultiTexCoord2iARB) (GLenum target, GLint s); +void ( APIENTRY * qglMultiTexCoord2ivARB) (GLenum target, const GLint *v); +void ( APIENTRY * qglMultiTexCoord2sARB) (GLenum target, GLshort s); +void ( APIENTRY * qglMultiTexCoord2svARB) (GLenum target, const GLshort *v); +void ( APIENTRY * qglMultiTexCoord3dARB) (GLenum target, GLdouble s); +void ( APIENTRY * qglMultiTexCoord3dvARB) (GLenum target, const GLdouble *v); +void ( APIENTRY * qglMultiTexCoord3fARB) (GLenum target, GLfloat s); +void ( APIENTRY * qglMultiTexCoord3fvARB) (GLenum target, const GLfloat *v); +void ( APIENTRY * qglMultiTexCoord3iARB) (GLenum target, GLint s); +void ( APIENTRY * qglMultiTexCoord3ivARB) (GLenum target, const GLint *v); +void ( APIENTRY * qglMultiTexCoord3sARB) (GLenum target, GLshort s); +void ( APIENTRY * qglMultiTexCoord3svARB) (GLenum target, const GLshort *v); +void ( APIENTRY * qglMultiTexCoord4dARB) (GLenum target, GLdouble s); +void ( APIENTRY * qglMultiTexCoord4dvARB) (GLenum target, const GLdouble *v); +void ( APIENTRY * qglMultiTexCoord4fARB) (GLenum target, GLfloat s); +void ( APIENTRY * qglMultiTexCoord4fvARB) (GLenum target, const GLfloat *v); +void ( APIENTRY * qglMultiTexCoord4iARB) (GLenum target, GLint s); +void ( APIENTRY * qglMultiTexCoord4ivARB) (GLenum target, const GLint *v); +void ( APIENTRY * qglMultiTexCoord4sARB) (GLenum target, GLshort s); +void ( APIENTRY * qglMultiTexCoord4svARB) (GLenum target, const GLshort *v); + +extern "C" void InitIglToQgl( _QERQglTable *g_QglTable ) +{ +/* + // initialze the qgl functions + qglAccum = NULL; + qglAlphaFunc = g_QglTable->m_pfn_qglAlphaFunc; + qglAreTexturesResident = NULL; + qglArrayElement = NULL; + qglBegin = g_QglTable->m_pfn_qglBegin; + qglBindTexture = g_QglTable->m_pfn_qglBindTexture; + qglBitmap = NULL; + qglBlendFunc = g_QglTable->m_pfn_qglBlendFunc; + qglCallList = g_QglTable->m_pfn_qglCallList; + qglCallLists = g_QglTable->m_pfn_qglCallLists; + qglClear = g_QglTable->m_pfn_qglClear; + qglClearAccum = NULL; + qglClearColor = g_QglTable->m_pfn_qglClearColor; + qglClearDepth = g_QglTable->m_pfn_qglClearDepth; + qglClearIndex = NULL; + qglClearStencil = NULL; + qglClipPlane = NULL; + qglColor3b = NULL; + qglColor3bv = NULL; + qglColor3d = NULL; + qglColor3dv = NULL; + qglColor3f = g_QglTable->m_pfn_qglColor3f; + qglColor3fv = g_QglTable->m_pfn_qglColor3fv; + qglColor3i = NULL; + qglColor3iv = NULL; + qglColor3s = NULL; + qglColor3sv = NULL; + qglColor3ub = NULL; + qglColor3ubv = NULL; + qglColor3ui = NULL; + qglColor3uiv = NULL; + qglColor3us = NULL; + qglColor3usv = NULL; + qglColor4b = NULL; + qglColor4bv = NULL; + qglColor4d = NULL; + qglColor4dv = NULL; + qglColor4f = g_QglTable->m_pfn_qglColor4f; + qglColor4fv = g_QglTable->m_pfn_qglColor4fv; + qglColor4i = NULL; + qglColor4iv = NULL; + qglColor4s = NULL; + qglColor4sv = NULL; + qglColor4ub = NULL; + qglColor4ubv = NULL; + qglColor4ui = NULL; + qglColor4uiv = NULL; + qglColor4us = NULL; + qglColor4usv = NULL; + qglColorMask = NULL; + qglColorMaterial = NULL; + qglColorPointer = NULL; + qglCopyPixels = NULL; + qglCopyTexImage1D = NULL; + qglCopyTexImage2D = NULL; + qglCopyTexSubImage1D = NULL; + qglCopyTexSubImage2D = NULL; + qglCullFace = g_QglTable->m_pfn_qglCullFace; + qglDeleteLists = g_QglTable->m_pfn_qglDeleteLists; + qglDeleteTextures = g_QglTable->m_pfn_qglDeleteTextures; + qglDepthFunc = g_QglTable->m_pfn_qglDepthFunc; + qglDepthMask = g_QglTable->m_pfn_qglDepthMask; + qglDepthRange = NULL; + qglDisable = g_QglTable->m_pfn_qglDisable; + qglDisableClientState = NULL; + qglDrawArrays = NULL; + qglDrawBuffer = NULL; + qglDrawElements = NULL; + qglDrawPixels = NULL; + qglEdgeFlag = NULL; + qglEdgeFlagPointer = NULL; + qglEdgeFlagv = NULL; + qglEnable = g_QglTable->m_pfn_qglEnable; + qglEnableClientState = NULL; + qglEnd = g_QglTable->m_pfn_qglEnd; + qglEndList = g_QglTable->m_pfn_qglEndList; + qglEvalCoord1d = NULL; + qglEvalCoord1dv = NULL; + qglEvalCoord1f = NULL; + qglEvalCoord1fv = NULL; + qglEvalCoord2d = NULL; + qglEvalCoord2dv = NULL; + qglEvalCoord2f= NULL; + qglEvalCoord2fv = NULL; + qglEvalMesh1 = NULL; + qglEvalMesh2 = NULL; + qglEvalPoint1 = NULL; + qglEvalPoint2 = NULL; + qglFeedbackBuffer = NULL; + qglFinish = NULL; + qglFlush = NULL; + qglFogf = g_QglTable->m_pfn_qglFogf; + qglFogfv = g_QglTable->m_pfn_qglFogfv; + qglFogi = g_QglTable->m_pfn_qglFogi; + qglFogiv = NULL; + qglFrontFace = NULL; + qglFrustum = NULL; + qglGenLists = g_QglTable->m_pfn_qglGenLists; + qglGenTextures = g_QglTable->m_pfn_qglGenTextures; + qglGetBooleanv = NULL; + qglGetClipPlane = NULL; + qglGetDoublev = NULL; + qglGetError = NULL; + qglGetFloatv = NULL; + qglGetIntegerv = NULL; + qglGetLightfv = NULL; + qglGetLightiv = NULL; + qglGetMapdv = NULL; + qglGetMapfv = NULL; + qglGetMapiv = NULL; + qglGetMaterialfv = NULL; + qglGetMaterialiv = NULL; + qglGetPixelMapfv = NULL; + qglGetPixelMapuiv = NULL; + qglGetPixelMapusv = NULL; + qglGetPointerv = NULL; + qglGetPolygonStipple = NULL; + qglGetString = NULL; + qglGetTexEnvfv = NULL; + qglGetTexEnviv = NULL; + qglGetTexGendv = NULL; + qglGetTexGenfv = NULL; + qglGetTexGeniv = NULL; + qglGetTexImage = NULL; + qglGetTexLevelParameterfv = NULL; + qglGetTexLevelParameteriv = NULL; + qglGetTexParameterfv = NULL; + qglGetTexParameteriv = NULL; + qglHint = g_QglTable->m_pfn_qglHint; + qglIndexMask = NULL; + qglIndexPointer = NULL; + qglIndexd = NULL; + qglIndexdv = NULL; + qglIndexf = NULL; + qglIndexfv = NULL; + qglIndexi = NULL; + qglIndexiv = NULL; + qglIndexs = NULL; + qglIndexsv = NULL; + qglIndexub = NULL; + qglIndexubv = NULL; + qglInitNames = NULL; + qglInterleavedArrays = NULL; + qglIsEnabled = NULL; + qglIsList = NULL; + qglIsTexture = NULL; + qglLightModelf = NULL; + qglLightModelfv = NULL; + qglLightModeli = NULL; + qglLightModeliv = NULL; + qglLightf = NULL; + qglLightfv = g_QglTable->m_pfn_qglLightfv; + qglLighti = NULL; + qglLightiv = NULL; + qglLineStipple = g_QglTable->m_pfn_qglLineStipple; + qglLineWidth = g_QglTable->m_pfn_qglLineWidth; + qglListBase = g_QglTable->m_pfn_qglListBase; + qglLoadIdentity = g_QglTable->m_pfn_qglLoadIdentity; + qglLoadMatrixd = NULL; + qglLoadMatrixf = NULL; + qglLoadName = NULL; + qglLogicOp = NULL; + qglMap1d = NULL; + qglMap1f = NULL; + qglMap2d = NULL; + qglMap2f = NULL; + qglMapGrid1d = NULL; + qglMapGrid1f = NULL; + qglMapGrid2d = NULL; + qglMapGrid2f = NULL; + qglMaterialf = g_QglTable->m_pfn_qglMaterialf; + qglMaterialfv = g_QglTable->m_pfn_qglMaterialfv; + qglMateriali = NULL; + qglMaterialiv = NULL; + qglMatrixMode = g_QglTable->m_pfn_qglMatrixMode; + qglMultMatrixd = NULL; + qglMultMatrixf = g_QglTable->m_pfn_qglMultMatrixf; + qglNewList = g_QglTable->m_pfn_qglNewList; + qglNormal3b = NULL; + qglNormal3bv = NULL; + qglNormal3d = NULL; + qglNormal3dv = NULL; + qglNormal3f = g_QglTable->m_pfn_qglNormal3f; + qglNormal3fv = g_QglTable->m_pfn_qglNormal3fv; + qglNormal3i = NULL; + qglNormal3iv = NULL; + qglNormal3s = NULL; + qglNormal3sv = NULL; + qglNormalPointer = NULL; + qglOrtho = g_QglTable->m_pfn_qglOrtho; + qglPassThrough = NULL; + qglPixelMapfv = NULL; + qglPixelMapuiv = NULL; + qglPixelMapusv = NULL; + qglPixelStoref = NULL; + qglPixelStorei = NULL; + qglPixelTransferf = NULL; + qglPixelTransferi = NULL; + qglPixelZoom = NULL; + qglPointSize = g_QglTable->m_pfn_qglPointSize; + qglPolygonMode = g_QglTable->m_pfn_qglPolygonMode; + qglPolygonOffset = NULL; + qglPolygonStipple = NULL; + qglPopAttrib = g_QglTable->m_pfn_qglPopAttrib; + qglPopClientAttrib = NULL; + qglPopMatrix = g_QglTable->m_pfn_qglPopMatrix; + qglPopName = NULL; + qglPrioritizeTextures = NULL; + qglPushAttrib = g_QglTable->m_pfn_qglPushAttrib; + qglPushClientAttrib = NULL; + qglPushMatrix = g_QglTable->m_pfn_qglPushMatrix; + qglPushName = NULL; + qglRasterPos2d = NULL; + qglRasterPos2dv = NULL; + qglRasterPos2f = NULL; + qglRasterPos2fv = NULL; + qglRasterPos2i = NULL; + qglRasterPos2iv = NULL; + qglRasterPos2s = NULL; + qglRasterPos2sv = NULL; + qglRasterPos3d = NULL; + qglRasterPos3dv = NULL; + qglRasterPos3f = NULL; + qglRasterPos3fv = g_QglTable->m_pfn_qglRasterPos3fv; + qglRasterPos3i = NULL; + qglRasterPos3iv = NULL; + qglRasterPos3s = NULL; + qglRasterPos3sv = NULL; + qglRasterPos4d = NULL; + qglRasterPos4dv = NULL; + qglRasterPos4f = NULL; + qglRasterPos4fv = NULL; + qglRasterPos4i = NULL; + qglRasterPos4iv = NULL; + qglRasterPos4s = NULL; + qglRasterPos4sv = NULL; + qglReadBuffer = NULL; + qglReadPixels = NULL; + qglRectd = NULL; + qglRectdv = NULL; + qglRectf = NULL; + qglRectfv = NULL; + qglRecti = NULL; + qglRectiv = NULL; + qglRects = NULL; + qglRectsv = NULL; + qglRenderMode = NULL; + qglRotated = g_QglTable->m_pfn_qglRotated; + qglRotatef = g_QglTable->m_pfn_qglRotatef; + qglScaled = NULL; + qglScalef = g_QglTable->m_pfn_qglScalef; + qglScissor = g_QglTable->m_pfn_qglScissor; + qglSelectBuffer = NULL; + qglShadeModel = g_QglTable->m_pfn_qglShadeModel; + qglStencilFunc = NULL; + qglStencilMask = NULL; + qglStencilOp = NULL; + qglTexCoord1d = NULL; + qglTexCoord1dv = NULL; + qglTexCoord1f = NULL; + qglTexCoord1fv = NULL; + qglTexCoord1i = NULL; + qglTexCoord1iv = NULL; + qglTexCoord1s = NULL; + qglTexCoord1sv = NULL; + qglTexCoord2d = NULL; + qglTexCoord2dv = NULL; + qglTexCoord2f = g_QglTable->m_pfn_qglTexCoord2f; + qglTexCoord2fv = g_QglTable->m_pfn_qglTexCoord2fv; + qglTexCoord2i = NULL; + qglTexCoord2iv = NULL; + qglTexCoord2s = NULL; + qglTexCoord2sv = NULL; + qglTexCoord3d = NULL; + qglTexCoord3dv = NULL; + qglTexCoord3f = NULL; + qglTexCoord3fv = NULL; + qglTexCoord3i = NULL; + qglTexCoord3iv = NULL; + qglTexCoord3s = NULL; + qglTexCoord3sv = NULL; + qglTexCoord4d = NULL; + qglTexCoord4dv = NULL; + qglTexCoord4f = NULL; + qglTexCoord4fv = NULL; + qglTexCoord4i = NULL; + qglTexCoord4iv = NULL; + qglTexCoord4s = NULL; + qglTexCoord4sv = NULL; + qglTexCoordPointer = NULL; + qglTexEnvf = g_QglTable->m_pfn_qglTexEnvf; + qglTexEnvfv = NULL; + qglTexEnvi = NULL; + qglTexEnviv = NULL; + qglTexGend = NULL; + qglTexGendv = NULL; + qglTexGenf = g_QglTable->m_pfn_qglTexGenf; + qglTexGenfv = NULL; + qglTexGeni = NULL; + qglTexGeniv = NULL; + qglTexImage1D = g_QglTable->m_pfn_qglTexImage1D; + qglTexImage2D = g_QglTable->m_pfn_qglTexImage2D; + qglTexParameterf = g_QglTable->m_pfn_qglTexParameterf; + qglTexParameterfv = g_QglTable->m_pfn_qglTexParameterfv; + qglTexParameteri = g_QglTable->m_pfn_qglTexParameteri; + qglTexParameteriv = g_QglTable->m_pfn_qglTexParameteriv; + qglTexSubImage1D = g_QglTable->m_pfn_qglTexSubImage1D; + qglTexSubImage2D = g_QglTable->m_pfn_qglTexSubImage2D; + qglTranslated = g_QglTable->m_pfn_qglTranslated; + qglTranslatef = g_QglTable->m_pfn_qglTranslatef; + qglVertex2d = NULL; + qglVertex2dv = NULL; + qglVertex2f = g_QglTable->m_pfn_qglVertex2f; + qglVertex2fv = NULL; + qglVertex2i = NULL; + qglVertex2iv = NULL; + qglVertex2s = NULL; + qglVertex2sv = NULL; + qglVertex3d = NULL; + qglVertex3dv = NULL; + qglVertex3f = g_QglTable->m_pfn_qglVertex3f; + qglVertex3fv = g_QglTable->m_pfn_qglVertex3fv; + qglVertex3i = NULL; + qglVertex3iv = NULL; + qglVertex3s = NULL; + qglVertex3sv = NULL; + qglVertex4d = NULL; + qglVertex4dv = NULL; + qglVertex4f = NULL; + qglVertex4fv = NULL; + qglVertex4i = NULL; + qglVertex4iv = NULL; + qglVertex4s = NULL; + qglVertex4sv = NULL; + qglVertexPointer = NULL; + qglViewport = g_QglTable->m_pfn_qglViewport; + + qglPointParameterfEXT = NULL; + qglPointParameterfvEXT = NULL; + qglColorTableEXT = NULL; + + qglMTexCoord2fSGIS = NULL; + qglSelectTextureSGIS = NULL; + + qglActiveTextureARB = NULL; + qglClientActiveTextureARB = NULL; + qglMultiTexCoord1dARB = NULL; + qglMultiTexCoord1dvARB = NULL; + qglMultiTexCoord1fARB = NULL; + qglMultiTexCoord1fvARB = NULL; + qglMultiTexCoord1iARB = NULL; + qglMultiTexCoord1ivARB = NULL; + qglMultiTexCoord1sARB = NULL; + qglMultiTexCoord1svARB = NULL; + qglMultiTexCoord2dARB = NULL; + qglMultiTexCoord2dvARB = NULL; + qglMultiTexCoord2fARB = NULL; + qglMultiTexCoord2fvARB = NULL; + qglMultiTexCoord2iARB = NULL; + qglMultiTexCoord2ivARB = NULL; + qglMultiTexCoord2sARB = NULL; + qglMultiTexCoord2svARB = NULL; + qglMultiTexCoord3dARB = NULL; + qglMultiTexCoord3dvARB = NULL; + qglMultiTexCoord3fARB = NULL; + qglMultiTexCoord3fvARB = NULL; + qglMultiTexCoord3iARB = NULL; + qglMultiTexCoord3ivARB = NULL; + qglMultiTexCoord3sARB = NULL; + qglMultiTexCoord3svARB = NULL; + qglMultiTexCoord4dARB = NULL; + qglMultiTexCoord4dvARB = NULL; + qglMultiTexCoord4fARB = NULL; + qglMultiTexCoord4fvARB = NULL; + qglMultiTexCoord4iARB = NULL; + qglMultiTexCoord4ivARB = NULL; + qglMultiTexCoord4sARB = NULL; + qglMultiTexCoord4svARB = NULL; +*/ +} + +#endif // _IGL_TO_QGL_H_ diff --git a/libs/jpeg6/.cvsignore b/libs/jpeg6/.cvsignore new file mode 100644 index 00000000..face6ad3 --- /dev/null +++ b/libs/jpeg6/.cvsignore @@ -0,0 +1,8 @@ +Debug +Release +*.ncb +*.opt +*.plg +*.001 +*.BAK +.consign diff --git a/libs/jpeg6/.cvswrappers b/libs/jpeg6/.cvswrappers new file mode 100644 index 00000000..cdfd6d4a --- /dev/null +++ b/libs/jpeg6/.cvswrappers @@ -0,0 +1,3 @@ +*.dsp -m 'COPY' -k 'b' +*.dsw -m 'COPY' -k 'b' +*.scc -m 'COPY' -k 'b' diff --git a/libs/jpeg6/jchuff.h b/libs/jpeg6/jchuff.h new file mode 100644 index 00000000..7ae05e85 --- /dev/null +++ b/libs/jpeg6/jchuff.h @@ -0,0 +1,68 @@ +/* + + * jchuff.h + + * + + * Copyright (C) 1991-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains declarations for Huffman entropy encoding routines + + * that are shared between the sequential encoder (jchuff.c) and the + + * progressive encoder (jcphuff.c). No other modules need to see these. + + */ + + + +/* Derived data constructed for each Huffman table */ + + + +typedef struct { + + unsigned int ehufco[256]; /* code for each symbol */ + + char ehufsi[256]; /* length of code for each symbol */ + + /* If no code has been allocated for a symbol S, ehufsi[S] contains 0 */ + +} c_derived_tbl; + + + +/* Short forms of external names for systems with brain-damaged linkers. */ + + + +#ifdef NEED_SHORT_EXTERNAL_NAMES + +#define jpeg_make_c_derived_tbl jMkCDerived + +#define jpeg_gen_optimal_table jGenOptTbl + +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + + +/* Expand a Huffman table definition into the derived format */ + +EXTERN void jpeg_make_c_derived_tbl JPP((j_compress_ptr cinfo, + + JHUFF_TBL * htbl, c_derived_tbl ** pdtbl)); + + + +/* Generate an optimal table definition given the specified counts */ + +EXTERN void jpeg_gen_optimal_table JPP((j_compress_ptr cinfo, + + JHUFF_TBL * htbl, long freq[])); + diff --git a/libs/jpeg6/jcomapi.cpp b/libs/jpeg6/jcomapi.cpp new file mode 100644 index 00000000..ebf2d791 --- /dev/null +++ b/libs/jpeg6/jcomapi.cpp @@ -0,0 +1,188 @@ +/* + + * jcomapi.c + + * + + * Copyright (C) 1994, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains application interface routines that are used for both + + * compression and decompression. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + + + + + +/* + + * Abort processing of a JPEG compression or decompression operation, + + * but don't destroy the object itself. + + * + + * For this, we merely clean up all the nonpermanent memory pools. + + * Note that temp files (virtual arrays) are not allowed to belong to + + * the permanent pool, so we will be able to close all temp files here. + + * Closing a data source or destination, if necessary, is the application's + + * responsibility. + + */ + + + +GLOBAL void + +jpeg_abort (j_common_ptr cinfo) + +{ + + int pool; + + + + /* Releasing pools in reverse order might help avoid fragmentation + + * with some (brain-damaged) malloc libraries. + + */ + + for (pool = JPOOL_NUMPOOLS-1; pool > JPOOL_PERMANENT; pool--) { + + (*cinfo->mem->free_pool) (cinfo, pool); + + } + + + + /* Reset overall state for possible reuse of object */ + + cinfo->global_state = (cinfo->is_decompressor ? DSTATE_START : CSTATE_START); + +} + + + + + +/* + + * Destruction of a JPEG object. + + * + + * Everything gets deallocated except the master jpeg_compress_struct itself + + * and the error manager struct. Both of these are supplied by the application + + * and must be freed, if necessary, by the application. (Often they are on + + * the stack and so don't need to be freed anyway.) + + * Closing a data source or destination, if necessary, is the application's + + * responsibility. + + */ + + + +GLOBAL void + +jpeg_destroy (j_common_ptr cinfo) + +{ + + /* We need only tell the memory manager to release everything. */ + + /* NB: mem pointer is NULL if memory mgr failed to initialize. */ + + if (cinfo->mem != NULL) + + (*cinfo->mem->self_destruct) (cinfo); + + cinfo->mem = NULL; /* be safe if jpeg_destroy is called twice */ + + cinfo->global_state = 0; /* mark it destroyed */ + +} + + + + + +/* + + * Convenience routines for allocating quantization and Huffman tables. + + * (Would jutils.c be a more reasonable place to put these?) + + */ + + + +GLOBAL JQUANT_TBL * + +jpeg_alloc_quant_table (j_common_ptr cinfo) + +{ + + JQUANT_TBL *tbl; + + + + tbl = (JQUANT_TBL *) + + (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JQUANT_TBL)); + + tbl->sent_table = FALSE; /* make sure this is false in any new table */ + + return tbl; + +} + + + + + +GLOBAL JHUFF_TBL * + +jpeg_alloc_huff_table (j_common_ptr cinfo) + +{ + + JHUFF_TBL *tbl; + + + + tbl = (JHUFF_TBL *) + + (*cinfo->mem->alloc_small) (cinfo, JPOOL_PERMANENT, SIZEOF(JHUFF_TBL)); + + tbl->sent_table = FALSE; /* make sure this is false in any new table */ + + return tbl; + +} + diff --git a/libs/jpeg6/jconfig.h b/libs/jpeg6/jconfig.h new file mode 100644 index 00000000..c727519b --- /dev/null +++ b/libs/jpeg6/jconfig.h @@ -0,0 +1,82 @@ +/* jconfig.wat --- jconfig.h for Watcom C/C++ on MS-DOS or OS/2. */ + +/* see jconfig.doc for explanations */ + + + +#define HAVE_PROTOTYPES + +#define HAVE_UNSIGNED_CHAR + +#define HAVE_UNSIGNED_SHORT + +/* #define void char */ + +/* #define const */ + +#define CHAR_IS_UNSIGNED + +#define HAVE_STDDEF_H + +#define HAVE_STDLIB_H + +#undef NEED_BSD_STRINGS + +#undef NEED_SYS_TYPES_H + +#undef NEED_FAR_POINTERS /* Watcom uses flat 32-bit addressing */ + +#undef NEED_SHORT_EXTERNAL_NAMES + +#undef INCOMPLETE_TYPES_BROKEN + + + +#define JDCT_DEFAULT JDCT_FLOAT + +#define JDCT_FASTEST JDCT_FLOAT + + + +#ifdef JPEG_INTERNALS + + + +#undef RIGHT_SHIFT_IS_UNSIGNED + + + +#endif /* JPEG_INTERNALS */ + + + +#ifdef JPEG_CJPEG_DJPEG + + + +#define BMP_SUPPORTED /* BMP image file format */ + +#define GIF_SUPPORTED /* GIF image file format */ + +#define PPM_SUPPORTED /* PBMPLUS PPM/PGM image file format */ + +#undef RLE_SUPPORTED /* Utah RLE image file format */ + +#define TARGA_SUPPORTED /* Targa image file format */ + + + +#undef TWO_FILE_COMMANDLINE /* optional */ + +#define USE_SETMODE /* Needed to make one-file style work in Watcom */ + +#undef NEED_SIGNAL_CATCHER /* Define this if you use jmemname.c */ + +#undef DONT_USE_B_MODE + +#undef PROGRESS_REPORT /* optional */ + + + +#endif /* JPEG_CJPEG_DJPEG */ + diff --git a/libs/jpeg6/jdapimin.cpp b/libs/jpeg6/jdapimin.cpp new file mode 100644 index 00000000..9086b490 --- /dev/null +++ b/libs/jpeg6/jdapimin.cpp @@ -0,0 +1,800 @@ +/* + + * jdapimin.c + + * + + * Copyright (C) 1994-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains application interface code for the decompression half + + * of the JPEG library. These are the "minimum" API routines that may be + + * needed in either the normal full-decompression case or the + + * transcoding-only case. + + * + + * Most of the routines intended to be called directly by an application + + * are in this file or in jdapistd.c. But also see jcomapi.c for routines + + * shared by compression and decompression, and jdtrans.c for the transcoding + + * case. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + + + + + +/* + + * Initialization of a JPEG decompression object. + + * The error manager must already be set up (in case memory manager fails). + + */ + + + +GLOBAL void + +jpeg_create_decompress (j_decompress_ptr cinfo) + +{ + + int i; + + + + /* For debugging purposes, zero the whole master structure. + + * But error manager pointer is already there, so save and restore it. + + */ + + { + + struct jpeg_error_mgr * err = cinfo->err; + + i = sizeof(struct jpeg_decompress_struct); + + i = SIZEOF(struct jpeg_decompress_struct); + + MEMZERO(cinfo, SIZEOF(struct jpeg_decompress_struct)); + + cinfo->err = err; + + } + + cinfo->is_decompressor = TRUE; + + + + /* Initialize a memory manager instance for this object */ + + jinit_memory_mgr((j_common_ptr) cinfo); + + + + /* Zero out pointers to permanent structures. */ + + cinfo->progress = NULL; + + cinfo->src = NULL; + + + + for (i = 0; i < NUM_QUANT_TBLS; i++) + + cinfo->quant_tbl_ptrs[i] = NULL; + + + + for (i = 0; i < NUM_HUFF_TBLS; i++) { + + cinfo->dc_huff_tbl_ptrs[i] = NULL; + + cinfo->ac_huff_tbl_ptrs[i] = NULL; + + } + + + + /* Initialize marker processor so application can override methods + + * for COM, APPn markers before calling jpeg_read_header. + + */ + + jinit_marker_reader(cinfo); + + + + /* And initialize the overall input controller. */ + + jinit_input_controller(cinfo); + + + + /* OK, I'm ready */ + + cinfo->global_state = DSTATE_START; + +} + + + + + +/* + + * Destruction of a JPEG decompression object + + */ + + + +GLOBAL void + +jpeg_destroy_decompress (j_decompress_ptr cinfo) + +{ + + jpeg_destroy((j_common_ptr) cinfo); /* use common routine */ + +} + + + + + +/* + + * Abort processing of a JPEG decompression operation, + + * but don't destroy the object itself. + + */ + + + +GLOBAL void + +jpeg_abort_decompress (j_decompress_ptr cinfo) + +{ + + jpeg_abort((j_common_ptr) cinfo); /* use common routine */ + +} + + + + + +/* + + * Install a special processing method for COM or APPn markers. + + */ + + + +GLOBAL void + +jpeg_set_marker_processor (j_decompress_ptr cinfo, int marker_code, + + jpeg_marker_parser_method routine) + +{ + + if (marker_code == JPEG_COM) + + cinfo->marker->process_COM = routine; + + else if (marker_code >= JPEG_APP0 && marker_code <= JPEG_APP0+15) + + cinfo->marker->process_APPn[marker_code-JPEG_APP0] = routine; + + else + + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, marker_code); + +} + + + + + +/* + + * Set default decompression parameters. + + */ + + + +LOCAL void + +default_decompress_parms (j_decompress_ptr cinfo) + +{ + + /* Guess the input colorspace, and set output colorspace accordingly. */ + + /* (Wish JPEG committee had provided a real way to specify this...) */ + + /* Note application may override our guesses. */ + + switch (cinfo->num_components) { + + case 1: + + cinfo->jpeg_color_space = JCS_GRAYSCALE; + + cinfo->out_color_space = JCS_GRAYSCALE; + + break; + + + + case 3: + + if (cinfo->saw_JFIF_marker) { + + cinfo->jpeg_color_space = JCS_YCbCr; /* JFIF implies YCbCr */ + + } else if (cinfo->saw_Adobe_marker) { + + switch (cinfo->Adobe_transform) { + + case 0: + + cinfo->jpeg_color_space = JCS_RGB; + + break; + + case 1: + + cinfo->jpeg_color_space = JCS_YCbCr; + + break; + + default: + + WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); + + cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ + + break; + + } + + } else { + + /* Saw no special markers, try to guess from the component IDs */ + + int cid0 = cinfo->comp_info[0].component_id; + + int cid1 = cinfo->comp_info[1].component_id; + + int cid2 = cinfo->comp_info[2].component_id; + + + + if (cid0 == 1 && cid1 == 2 && cid2 == 3) + + cinfo->jpeg_color_space = JCS_YCbCr; /* assume JFIF w/out marker */ + + else if (cid0 == 82 && cid1 == 71 && cid2 == 66) + + cinfo->jpeg_color_space = JCS_RGB; /* ASCII 'R', 'G', 'B' */ + + else { + + TRACEMS3(cinfo, 1, JTRC_UNKNOWN_IDS, cid0, cid1, cid2); + + cinfo->jpeg_color_space = JCS_YCbCr; /* assume it's YCbCr */ + + } + + } + + /* Always guess RGB is proper output colorspace. */ + + cinfo->out_color_space = JCS_RGB; + + break; + + + + case 4: + + if (cinfo->saw_Adobe_marker) { + + switch (cinfo->Adobe_transform) { + + case 0: + + cinfo->jpeg_color_space = JCS_CMYK; + + break; + + case 2: + + cinfo->jpeg_color_space = JCS_YCCK; + + break; + + default: + + WARNMS1(cinfo, JWRN_ADOBE_XFORM, cinfo->Adobe_transform); + + cinfo->jpeg_color_space = JCS_YCCK; /* assume it's YCCK */ + + break; + + } + + } else { + + /* No special markers, assume straight CMYK. */ + + cinfo->jpeg_color_space = JCS_CMYK; + + } + + cinfo->out_color_space = JCS_CMYK; + + break; + + + + default: + + cinfo->jpeg_color_space = JCS_UNKNOWN; + + cinfo->out_color_space = JCS_UNKNOWN; + + break; + + } + + + + /* Set defaults for other decompression parameters. */ + + cinfo->scale_num = 1; /* 1:1 scaling */ + + cinfo->scale_denom = 1; + + cinfo->output_gamma = 1.0; + + cinfo->buffered_image = FALSE; + + cinfo->raw_data_out = FALSE; + + cinfo->dct_method = JDCT_DEFAULT; + + cinfo->do_fancy_upsampling = TRUE; + + cinfo->do_block_smoothing = TRUE; + + cinfo->quantize_colors = FALSE; + + /* We set these in case application only sets quantize_colors. */ + + cinfo->dither_mode = JDITHER_FS; + +#ifdef QUANT_2PASS_SUPPORTED + + cinfo->two_pass_quantize = TRUE; + +#else + + cinfo->two_pass_quantize = FALSE; + +#endif + + cinfo->desired_number_of_colors = 256; + + cinfo->colormap = NULL; + + /* Initialize for no mode change in buffered-image mode. */ + + cinfo->enable_1pass_quant = FALSE; + + cinfo->enable_external_quant = FALSE; + + cinfo->enable_2pass_quant = FALSE; + +} + + + + + +/* + + * Decompression startup: read start of JPEG datastream to see what's there. + + * Need only initialize JPEG object and supply a data source before calling. + + * + + * This routine will read as far as the first SOS marker (ie, actual start of + + * compressed data), and will save all tables and parameters in the JPEG + + * object. It will also initialize the decompression parameters to default + + * values, and finally return JPEG_HEADER_OK. On return, the application may + + * adjust the decompression parameters and then call jpeg_start_decompress. + + * (Or, if the application only wanted to determine the image parameters, + + * the data need not be decompressed. In that case, call jpeg_abort or + + * jpeg_destroy to release any temporary space.) + + * If an abbreviated (tables only) datastream is presented, the routine will + + * return JPEG_HEADER_TABLES_ONLY upon reaching EOI. The application may then + + * re-use the JPEG object to read the abbreviated image datastream(s). + + * It is unnecessary (but OK) to call jpeg_abort in this case. + + * The JPEG_SUSPENDED return code only occurs if the data source module + + * requests suspension of the decompressor. In this case the application + + * should load more source data and then re-call jpeg_read_header to resume + + * processing. + + * If a non-suspending data source is used and require_image is TRUE, then the + + * return code need not be inspected since only JPEG_HEADER_OK is possible. + + * + + * This routine is now just a front end to jpeg_consume_input, with some + + * extra error checking. + + */ + + + +GLOBAL int + +jpeg_read_header (j_decompress_ptr cinfo, boolean require_image) + +{ + + int retcode; + + + + if (cinfo->global_state != DSTATE_START && + + cinfo->global_state != DSTATE_INHEADER) + + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + + + retcode = jpeg_consume_input(cinfo); + + + + switch (retcode) { + + case JPEG_REACHED_SOS: + + retcode = JPEG_HEADER_OK; + + break; + + case JPEG_REACHED_EOI: + + if (require_image) /* Complain if application wanted an image */ + + ERREXIT(cinfo, JERR_NO_IMAGE); + + /* Reset to start state; it would be safer to require the application to + + * call jpeg_abort, but we can't change it now for compatibility reasons. + + * A side effect is to free any temporary memory (there shouldn't be any). + + */ + + jpeg_abort((j_common_ptr) cinfo); /* sets state = DSTATE_START */ + + retcode = JPEG_HEADER_TABLES_ONLY; + + break; + + case JPEG_SUSPENDED: + + /* no work */ + + break; + + } + + + + return retcode; + +} + + + + + +/* + + * Consume data in advance of what the decompressor requires. + + * This can be called at any time once the decompressor object has + + * been created and a data source has been set up. + + * + + * This routine is essentially a state machine that handles a couple + + * of critical state-transition actions, namely initial setup and + + * transition from header scanning to ready-for-start_decompress. + + * All the actual input is done via the input controller's consume_input + + * method. + + */ + + + +GLOBAL int + +jpeg_consume_input (j_decompress_ptr cinfo) + +{ + + int retcode = JPEG_SUSPENDED; + + + + /* NB: every possible DSTATE value should be listed in this switch */ + + switch (cinfo->global_state) { + + case DSTATE_START: + + /* Start-of-datastream actions: reset appropriate modules */ + + (*cinfo->inputctl->reset_input_controller) (cinfo); + + /* Initialize application's data source module */ + + (*cinfo->src->init_source) (cinfo); + + cinfo->global_state = DSTATE_INHEADER; + + /*FALLTHROUGH*/ + + case DSTATE_INHEADER: + + retcode = (*cinfo->inputctl->consume_input) (cinfo); + + if (retcode == JPEG_REACHED_SOS) { /* Found SOS, prepare to decompress */ + + /* Set up default parameters based on header data */ + + default_decompress_parms(cinfo); + + /* Set global state: ready for start_decompress */ + + cinfo->global_state = DSTATE_READY; + + } + + break; + + case DSTATE_READY: + + /* Can't advance past first SOS until start_decompress is called */ + + retcode = JPEG_REACHED_SOS; + + break; + + case DSTATE_PRELOAD: + + case DSTATE_PRESCAN: + + case DSTATE_SCANNING: + + case DSTATE_RAW_OK: + + case DSTATE_BUFIMAGE: + + case DSTATE_BUFPOST: + + case DSTATE_STOPPING: + + retcode = (*cinfo->inputctl->consume_input) (cinfo); + + break; + + default: + + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + } + + return retcode; + +} + + + + + +/* + + * Have we finished reading the input file? + + */ + + + +GLOBAL boolean + +jpeg_input_complete (j_decompress_ptr cinfo) + +{ + + /* Check for valid jpeg object */ + + if (cinfo->global_state < DSTATE_START || + + cinfo->global_state > DSTATE_STOPPING) + + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + return cinfo->inputctl->eoi_reached; + +} + + + + + +/* + + * Is there more than one scan? + + */ + + + +GLOBAL boolean + +jpeg_has_multiple_scans (j_decompress_ptr cinfo) + +{ + + /* Only valid after jpeg_read_header completes */ + + if (cinfo->global_state < DSTATE_READY || + + cinfo->global_state > DSTATE_STOPPING) + + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + return cinfo->inputctl->has_multiple_scans; + +} + + + + + +/* + + * Finish JPEG decompression. + + * + + * This will normally just verify the file trailer and release temp storage. + + * + + * Returns FALSE if suspended. The return value need be inspected only if + + * a suspending data source is used. + + */ + + + +GLOBAL boolean + +jpeg_finish_decompress (j_decompress_ptr cinfo) + +{ + + if ((cinfo->global_state == DSTATE_SCANNING || + + cinfo->global_state == DSTATE_RAW_OK) && ! cinfo->buffered_image) { + + /* Terminate final pass of non-buffered mode */ + + if (cinfo->output_scanline < cinfo->output_height) + + ERREXIT(cinfo, JERR_TOO_LITTLE_DATA); + + (*cinfo->master->finish_output_pass) (cinfo); + + cinfo->global_state = DSTATE_STOPPING; + + } else if (cinfo->global_state == DSTATE_BUFIMAGE) { + + /* Finishing after a buffered-image operation */ + + cinfo->global_state = DSTATE_STOPPING; + + } else if (cinfo->global_state != DSTATE_STOPPING) { + + /* STOPPING = repeat call after a suspension, anything else is error */ + + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + } + + /* Read until EOI */ + + while (! cinfo->inputctl->eoi_reached) { + + if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) + + return FALSE; /* Suspend, come back later */ + + } + + /* Do final cleanup */ + + (*cinfo->src->term_source) (cinfo); + + /* We can use jpeg_abort to release memory and reset global_state */ + + jpeg_abort((j_common_ptr) cinfo); + + return TRUE; + +} + diff --git a/libs/jpeg6/jdapistd.cpp b/libs/jpeg6/jdapistd.cpp new file mode 100644 index 00000000..0718fb3b --- /dev/null +++ b/libs/jpeg6/jdapistd.cpp @@ -0,0 +1,550 @@ +/* + + * jdapistd.c + + * + + * Copyright (C) 1994-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains application interface code for the decompression half + + * of the JPEG library. These are the "standard" API routines that are + + * used in the normal full-decompression case. They are not used by a + + * transcoding-only application. Note that if an application links in + + * jpeg_start_decompress, it will end up linking in the entire decompressor. + + * We thus must separate this file from jdapimin.c to avoid linking the + + * whole decompression library into a transcoder. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + + + + + +/* Forward declarations */ + +LOCAL boolean output_pass_setup JPP((j_decompress_ptr cinfo)); + + + + + +/* + + * Decompression initialization. + + * jpeg_read_header must be completed before calling this. + + * + + * If a multipass operating mode was selected, this will do all but the + + * last pass, and thus may take a great deal of time. + + * + + * Returns FALSE if suspended. The return value need be inspected only if + + * a suspending data source is used. + + */ + + + +GLOBAL boolean + +jpeg_start_decompress (j_decompress_ptr cinfo) + +{ + + if (cinfo->global_state == DSTATE_READY) { + + /* First call: initialize master control, select active modules */ + + jinit_master_decompress(cinfo); + + if (cinfo->buffered_image) { + + /* No more work here; expecting jpeg_start_output next */ + + cinfo->global_state = DSTATE_BUFIMAGE; + + return TRUE; + + } + + cinfo->global_state = DSTATE_PRELOAD; + + } + + if (cinfo->global_state == DSTATE_PRELOAD) { + + /* If file has multiple scans, absorb them all into the coef buffer */ + + if (cinfo->inputctl->has_multiple_scans) { + +#ifdef D_MULTISCAN_FILES_SUPPORTED + + for (;;) { + + int retcode; + + /* Call progress monitor hook if present */ + + if (cinfo->progress != NULL) + + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + + /* Absorb some more input */ + + retcode = (*cinfo->inputctl->consume_input) (cinfo); + + if (retcode == JPEG_SUSPENDED) + + return FALSE; + + if (retcode == JPEG_REACHED_EOI) + + break; + + /* Advance progress counter if appropriate */ + + if (cinfo->progress != NULL && + + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + + /* jdmaster underestimated number of scans; ratchet up one scan */ + + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + + } + + } + + } + +#else + + ERREXIT(cinfo, JERR_NOT_COMPILED); + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + } + + cinfo->output_scan_number = cinfo->input_scan_number; + + } else if (cinfo->global_state != DSTATE_PRESCAN) + + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Perform any dummy output passes, and set up for the final pass */ + + return output_pass_setup(cinfo); + +} + + + + + +/* + + * Set up for an output pass, and perform any dummy pass(es) needed. + + * Common subroutine for jpeg_start_decompress and jpeg_start_output. + + * Entry: global_state = DSTATE_PRESCAN only if previously suspended. + + * Exit: If done, returns TRUE and sets global_state for proper output mode. + + * If suspended, returns FALSE and sets global_state = DSTATE_PRESCAN. + + */ + + + +LOCAL boolean + +output_pass_setup (j_decompress_ptr cinfo) + +{ + + if (cinfo->global_state != DSTATE_PRESCAN) { + + /* First call: do pass setup */ + + (*cinfo->master->prepare_for_output_pass) (cinfo); + + cinfo->output_scanline = 0; + + cinfo->global_state = DSTATE_PRESCAN; + + } + + /* Loop over any required dummy passes */ + + while (cinfo->master->is_dummy_pass) { + +#ifdef QUANT_2PASS_SUPPORTED + + /* Crank through the dummy pass */ + + while (cinfo->output_scanline < cinfo->output_height) { + + JDIMENSION last_scanline; + + /* Call progress monitor hook if present */ + + if (cinfo->progress != NULL) { + + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + + cinfo->progress->pass_limit = (long) cinfo->output_height; + + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + + } + + /* Process some data */ + + last_scanline = cinfo->output_scanline; + + (*cinfo->main->process_data) (cinfo, (JSAMPARRAY) NULL, + + &cinfo->output_scanline, (JDIMENSION) 0); + + if (cinfo->output_scanline == last_scanline) + + return FALSE; /* No progress made, must suspend */ + + } + + /* Finish up dummy pass, and set up for another one */ + + (*cinfo->master->finish_output_pass) (cinfo); + + (*cinfo->master->prepare_for_output_pass) (cinfo); + + cinfo->output_scanline = 0; + +#else + + ERREXIT(cinfo, JERR_NOT_COMPILED); + +#endif /* QUANT_2PASS_SUPPORTED */ + + } + + /* Ready for application to drive output pass through + + * jpeg_read_scanlines or jpeg_read_raw_data. + + */ + + cinfo->global_state = cinfo->raw_data_out ? DSTATE_RAW_OK : DSTATE_SCANNING; + + return TRUE; + +} + + + + + +/* + + * Read some scanlines of data from the JPEG decompressor. + + * + + * The return value will be the number of lines actually read. + + * This may be less than the number requested in several cases, + + * including bottom of image, data source suspension, and operating + + * modes that emit multiple scanlines at a time. + + * + + * Note: we warn about excess calls to jpeg_read_scanlines() since + + * this likely signals an application programmer error. However, + + * an oversize buffer (max_lines > scanlines remaining) is not an error. + + */ + + + +GLOBAL JDIMENSION + +jpeg_read_scanlines (j_decompress_ptr cinfo, JSAMPARRAY scanlines, + + JDIMENSION max_lines) + +{ + + JDIMENSION row_ctr; + + + + if (cinfo->global_state != DSTATE_SCANNING) + + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (cinfo->output_scanline >= cinfo->output_height) { + + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + + return 0; + + } + + + + /* Call progress monitor hook if present */ + + if (cinfo->progress != NULL) { + + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + + cinfo->progress->pass_limit = (long) cinfo->output_height; + + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + + } + + + + /* Process some data */ + + row_ctr = 0; + + (*cinfo->main->process_data) (cinfo, scanlines, &row_ctr, max_lines); + + cinfo->output_scanline += row_ctr; + + return row_ctr; + +} + + + + + +/* + + * Alternate entry point to read raw data. + + * Processes exactly one iMCU row per call, unless suspended. + + */ + + + +GLOBAL JDIMENSION + +jpeg_read_raw_data (j_decompress_ptr cinfo, JSAMPIMAGE data, + + JDIMENSION max_lines) + +{ + + JDIMENSION lines_per_iMCU_row; + + + + if (cinfo->global_state != DSTATE_RAW_OK) + + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (cinfo->output_scanline >= cinfo->output_height) { + + WARNMS(cinfo, JWRN_TOO_MUCH_DATA); + + return 0; + + } + + + + /* Call progress monitor hook if present */ + + if (cinfo->progress != NULL) { + + cinfo->progress->pass_counter = (long) cinfo->output_scanline; + + cinfo->progress->pass_limit = (long) cinfo->output_height; + + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + + } + + + + /* Verify that at least one iMCU row can be returned. */ + + lines_per_iMCU_row = cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size; + + if (max_lines < lines_per_iMCU_row) + + ERREXIT(cinfo, JERR_BUFFER_SIZE); + + + + /* Decompress directly into user's buffer. */ + + if (! (*cinfo->coef->decompress_data) (cinfo, data)) + + return 0; /* suspension forced, can do nothing more */ + + + + /* OK, we processed one iMCU row. */ + + cinfo->output_scanline += lines_per_iMCU_row; + + return lines_per_iMCU_row; + +} + + + + + +/* Additional entry points for buffered-image mode. */ + + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + + + +/* + + * Initialize for an output pass in buffered-image mode. + + */ + + + +GLOBAL boolean + +jpeg_start_output (j_decompress_ptr cinfo, int scan_number) + +{ + + if (cinfo->global_state != DSTATE_BUFIMAGE && + + cinfo->global_state != DSTATE_PRESCAN) + + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Limit scan number to valid range */ + + if (scan_number <= 0) + + scan_number = 1; + + if (cinfo->inputctl->eoi_reached && + + scan_number > cinfo->input_scan_number) + + scan_number = cinfo->input_scan_number; + + cinfo->output_scan_number = scan_number; + + /* Perform any dummy output passes, and set up for the real pass */ + + return output_pass_setup(cinfo); + +} + + + + + +/* + + * Finish up after an output pass in buffered-image mode. + + * + + * Returns FALSE if suspended. The return value need be inspected only if + + * a suspending data source is used. + + */ + + + +GLOBAL boolean + +jpeg_finish_output (j_decompress_ptr cinfo) + +{ + + if ((cinfo->global_state == DSTATE_SCANNING || + + cinfo->global_state == DSTATE_RAW_OK) && cinfo->buffered_image) { + + /* Terminate this pass. */ + + /* We do not require the whole pass to have been completed. */ + + (*cinfo->master->finish_output_pass) (cinfo); + + cinfo->global_state = DSTATE_BUFPOST; + + } else if (cinfo->global_state != DSTATE_BUFPOST) { + + /* BUFPOST = repeat call after a suspension, anything else is error */ + + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + } + + /* Read markers looking for SOS or EOI */ + + while (cinfo->input_scan_number <= cinfo->output_scan_number && + + ! cinfo->inputctl->eoi_reached) { + + if ((*cinfo->inputctl->consume_input) (cinfo) == JPEG_SUSPENDED) + + return FALSE; /* Suspend, come back later */ + + } + + cinfo->global_state = DSTATE_BUFIMAGE; + + return TRUE; + +} + + + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + diff --git a/libs/jpeg6/jdatasrc.cpp b/libs/jpeg6/jdatasrc.cpp new file mode 100644 index 00000000..ae95d214 --- /dev/null +++ b/libs/jpeg6/jdatasrc.cpp @@ -0,0 +1,215 @@ +/* + * jdatasrc.c + * + * Copyright (C) 1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains decompression data source routines for the case of + * reading JPEG data from a file (or any stdio stream). While these routines + * are sufficient for most applications, some will want to use a different + * source manager. + * IMPORTANT: we assume that fread() will correctly transcribe an array of + * JOCTETs from 8-bit-wide elements on external storage. If char is wider + * than 8 bits on your machine, you may need to do some tweaking. + */ + + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "radiant_jpeglib.h" +#include "jerror.h" + +//extern int leo_buf_size; // FIXME ? merged in from Alpha - replaced by my_source_mgr->src_size + +/* Expanded data source object for stdio input */ + +typedef struct { + struct jpeg_source_mgr pub; /* public fields */ + int src_size; // FIXME ? merged from Alpha + unsigned char *infile; /* source stream */ + JOCTET * buffer; /* start of buffer */ + boolean start_of_file; /* have we gotten any data yet? */ +} my_source_mgr; + +typedef my_source_mgr * my_src_ptr; + +#define INPUT_BUF_SIZE 4096 /* choose an efficiently fread'able size */ + + +/* + * Initialize source --- called by jpeg_read_header + * before any data is actually read. + */ + +METHODDEF void +init_source (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* We reset the empty-input-file flag for each image, + * but we don't clear the input buffer. + * This is correct behavior for reading a series of images from one source. + */ + src->start_of_file = TRUE; +} + + +/* + * Fill the input buffer --- called whenever buffer is emptied. + * + * In typical applications, this should read fresh data into the buffer + * (ignoring the current state of next_input_byte & bytes_in_buffer), + * reset the pointer & count to the start of the buffer, and return TRUE + * indicating that the buffer has been reloaded. It is not necessary to + * fill the buffer entirely, only to obtain at least one more byte. + * + * There is no such thing as an EOF return. If the end of the file has been + * reached, the routine has a choice of ERREXIT() or inserting fake data into + * the buffer. In most cases, generating a warning message and inserting a + * fake EOI marker is the best course of action --- this will allow the + * decompressor to output however much of the image is there. However, + * the resulting error message is misleading if the real problem is an empty + * input file, so we handle that case specially. + * + * In applications that need to be able to suspend compression due to input + * not being available yet, a FALSE return indicates that no more data can be + * obtained right now, but more may be forthcoming later. In this situation, + * the decompressor will return to its caller (with an indication of the + * number of scanlines it has read, if any). The application should resume + * decompression after it has loaded more data into the input buffer. Note + * that there are substantial restrictions on the use of suspension --- see + * the documentation. + * + * When suspending, the decompressor will back up to a convenient restart point + * (typically the start of the current MCU). next_input_byte & bytes_in_buffer + * indicate where the restart point will be if the current call returns FALSE. + * Data beyond this point must be rescanned after resumption, so move it to + * the front of the buffer rather than discarding it. + */ + +METHODDEF boolean +// FIXME ? merged in from Alpha +fill_input_buffer (j_decompress_ptr cinfo) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + size_t nbytes; + + if (src->src_size > INPUT_BUF_SIZE) + nbytes = INPUT_BUF_SIZE; + else + nbytes = src->src_size; + + memcpy (src->buffer, src->infile, nbytes); + + src->infile += nbytes; + src->src_size -= nbytes; + + src->pub.next_input_byte = src->buffer; + src->pub.bytes_in_buffer = nbytes; + src->start_of_file = FALSE; + + return TRUE; +} + + +/* + * Skip data --- used to skip over a potentially large amount of + * uninteresting data (such as an APPn marker). + * + * Writers of suspendable-input applications must note that skip_input_data + * is not granted the right to give a suspension return. If the skip extends + * beyond the data currently in the buffer, the buffer can be marked empty so + * that the next read will cause a fill_input_buffer call that can suspend. + * Arranging for additional bytes to be discarded before reloading the input + * buffer is the application writer's problem. + */ + +METHODDEF void +skip_input_data (j_decompress_ptr cinfo, long num_bytes) +{ + my_src_ptr src = (my_src_ptr) cinfo->src; + + /* Just a dumb implementation for now. Could use fseek() except + * it doesn't work on pipes. Not clear that being smart is worth + * any trouble anyway --- large skips are infrequent. + */ + if (num_bytes > 0) { + while (num_bytes > (long) src->pub.bytes_in_buffer) { + num_bytes -= (long) src->pub.bytes_in_buffer; + (void) fill_input_buffer(cinfo); + /* note we assume that fill_input_buffer will never return FALSE, + * so suspension need not be handled. + */ + } + src->pub.next_input_byte += (size_t) num_bytes; + src->pub.bytes_in_buffer -= (size_t) num_bytes; + } +} + + +/* + * An additional method that can be provided by data source modules is the + * resync_to_restart method for error recovery in the presence of RST markers. + * For the moment, this source module just uses the default resync method + * provided by the JPEG library. That method assumes that no backtracking + * is possible. + */ + + +/* + * Terminate source --- called by jpeg_finish_decompress + * after all data has been read. Often a no-op. + * + * NB: *not* called by jpeg_abort or jpeg_destroy; surrounding + * application must deal with any cleanup that should happen even + * for error exit. + */ + +METHODDEF void +term_source (j_decompress_ptr cinfo) +{ + /* no work necessary here */ +} + + +/* + * Prepare for input from a stdio stream. + * The caller must have already opened the stream, and is responsible + * for closing it after finishing decompression. + */ + +GLOBAL void +jpeg_stdio_src (j_decompress_ptr cinfo, unsigned char *infile, int bufsize) +{ + my_src_ptr src; + + /* The source object and input buffer are made permanent so that a series + * of JPEG images can be read from the same file by calling jpeg_stdio_src + * only before the first one. (If we discarded the buffer at the end of + * one image, we'd likely lose the start of the next one.) + * This makes it unsafe to use this manager and a different source + * manager serially with the same JPEG object. Caveat programmer. + */ + if (cinfo->src == NULL) { /* first time for this JPEG object? */ + cinfo->src = (struct jpeg_source_mgr *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(my_source_mgr)); + src = (my_src_ptr) cinfo->src; + src->buffer = (JOCTET *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + INPUT_BUF_SIZE * SIZEOF(JOCTET)); + } + + src = (my_src_ptr) cinfo->src; + src->pub.init_source = init_source; + src->pub.fill_input_buffer = fill_input_buffer; + src->pub.skip_input_data = skip_input_data; + src->pub.resync_to_restart = jpeg_resync_to_restart; /* use default method */ + src->pub.term_source = term_source; + src->infile = infile; + src->src_size = bufsize; // FIXME ? merged from Alpha + src->pub.bytes_in_buffer = 0; /* forces fill_input_buffer on first read */ + src->pub.next_input_byte = NULL; /* until buffer loaded */ +} + diff --git a/libs/jpeg6/jdcoefct.cpp b/libs/jpeg6/jdcoefct.cpp new file mode 100644 index 00000000..f9a1f7ec --- /dev/null +++ b/libs/jpeg6/jdcoefct.cpp @@ -0,0 +1,1450 @@ +/* + + * jdcoefct.c + + * + + * Copyright (C) 1994-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains the coefficient buffer controller for decompression. + + * This controller is the top level of the JPEG decompressor proper. + + * The coefficient buffer lies between entropy decoding and inverse-DCT steps. + + * + + * In buffered-image mode, this controller is the interface between + + * input-oriented processing and output-oriented processing. + + * Also, the input side (only) is used when reading a file for transcoding. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + + + +/* Block smoothing is only applicable for progressive JPEG, so: */ + +#ifndef D_PROGRESSIVE_SUPPORTED + +#undef BLOCK_SMOOTHING_SUPPORTED + +#endif + + + +/* Private buffer controller object */ + + + +typedef struct { + + struct jpeg_d_coef_controller pub; /* public fields */ + + + + /* These variables keep track of the current location of the input side. */ + + /* cinfo->input_iMCU_row is also used for this. */ + + JDIMENSION MCU_ctr; /* counts MCUs processed in current row */ + + int MCU_vert_offset; /* counts MCU rows within iMCU row */ + + int MCU_rows_per_iMCU_row; /* number of such rows needed */ + + + + /* The output side's location is represented by cinfo->output_iMCU_row. */ + + + + /* In single-pass modes, it's sufficient to buffer just one MCU. + + * We allocate a workspace of D_MAX_BLOCKS_IN_MCU coefficient blocks, + + * and let the entropy decoder write into that workspace each time. + + * (On 80x86, the workspace is FAR even though it's not really very big; + + * this is to keep the module interfaces unchanged when a large coefficient + + * buffer is necessary.) + + * In multi-pass modes, this array points to the current MCU's blocks + + * within the virtual arrays; it is used only by the input side. + + */ + + JBLOCKROW MCU_buffer[D_MAX_BLOCKS_IN_MCU]; + + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + + /* In multi-pass modes, we need a virtual block array for each component. */ + + jvirt_barray_ptr whole_image[MAX_COMPONENTS]; + +#endif + + + +#ifdef BLOCK_SMOOTHING_SUPPORTED + + /* When doing block smoothing, we latch coefficient Al values here */ + + int * coef_bits_latch; + +#define SAVED_COEFS 6 /* we save coef_bits[0..5] */ + +#endif + +} my_coef_controller; + + + +typedef my_coef_controller * my_coef_ptr; + + + +/* Forward declarations */ + +METHODDEF int decompress_onepass + + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +METHODDEF int decompress_data + + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); + +#endif + +#ifdef BLOCK_SMOOTHING_SUPPORTED + +LOCAL boolean smoothing_ok JPP((j_decompress_ptr cinfo)); + +METHODDEF int decompress_smooth_data + + JPP((j_decompress_ptr cinfo, JSAMPIMAGE output_buf)); + +#endif + + + + + +LOCAL void + +start_iMCU_row (j_decompress_ptr cinfo) + +/* Reset within-iMCU-row counters for a new row (input side) */ + +{ + + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + + + /* In an interleaved scan, an MCU row is the same as an iMCU row. + + * In a noninterleaved scan, an iMCU row has v_samp_factor MCU rows. + + * But at the bottom of the image, process only what's left. + + */ + + if (cinfo->comps_in_scan > 1) { + + coef->MCU_rows_per_iMCU_row = 1; + + } else { + + if (cinfo->input_iMCU_row < (cinfo->total_iMCU_rows-1)) + + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->v_samp_factor; + + else + + coef->MCU_rows_per_iMCU_row = cinfo->cur_comp_info[0]->last_row_height; + + } + + + + coef->MCU_ctr = 0; + + coef->MCU_vert_offset = 0; + +} + + + + + +/* + + * Initialize for an input processing pass. + + */ + + + +METHODDEF void + +start_input_pass (j_decompress_ptr cinfo) + +{ + + cinfo->input_iMCU_row = 0; + + start_iMCU_row(cinfo); + +} + + + + + +/* + + * Initialize for an output processing pass. + + */ + + + +METHODDEF void + +start_output_pass (j_decompress_ptr cinfo) + +{ + +#ifdef BLOCK_SMOOTHING_SUPPORTED + + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + + + /* If multipass, check to see whether to use block smoothing on this pass */ + + if (coef->pub.coef_arrays != NULL) { + + if (cinfo->do_block_smoothing && smoothing_ok(cinfo)) + + coef->pub.decompress_data = decompress_smooth_data; + + else + + coef->pub.decompress_data = decompress_data; + + } + +#endif + + cinfo->output_iMCU_row = 0; + +} + + + + + +/* + + * Decompress and return some data in the single-pass case. + + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + + * Input and output must run in lockstep since we have only a one-MCU buffer. + + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + + * + + * NB: output_buf contains a plane for each component in image. + + * For single pass, this is the same as the components in the scan. + + */ + + + +METHODDEF int + +decompress_onepass (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) + +{ + + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + JDIMENSION MCU_col_num; /* index of current MCU within row */ + + JDIMENSION last_MCU_col = cinfo->MCUs_per_row - 1; + + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + + int blkn, ci, xindex, yindex, yoffset, useful_width; + + JSAMPARRAY output_ptr; + + JDIMENSION start_col, output_col; + + jpeg_component_info *compptr; + + inverse_DCT_method_ptr inverse_DCT; + + + + /* Loop to process as much as one whole iMCU row */ + + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + + yoffset++) { + + for (MCU_col_num = coef->MCU_ctr; MCU_col_num <= last_MCU_col; + + MCU_col_num++) { + + /* Try to fetch an MCU. Entropy decoder expects buffer to be zeroed. */ + + jzero_far((void FAR *) coef->MCU_buffer[0], + + (size_t) (cinfo->blocks_in_MCU * SIZEOF(JBLOCK))); + + if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) { + + /* Suspension forced; update state counters and exit */ + + coef->MCU_vert_offset = yoffset; + + coef->MCU_ctr = MCU_col_num; + + return JPEG_SUSPENDED; + + } + + /* Determine where data should go in output_buf and do the IDCT thing. + + * We skip dummy blocks at the right and bottom edges (but blkn gets + + * incremented past them!). Note the inner loop relies on having + + * allocated the MCU_buffer[] blocks sequentially. + + */ + + blkn = 0; /* index of current DCT block within MCU */ + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + + compptr = cinfo->cur_comp_info[ci]; + + /* Don't bother to IDCT an uninteresting component. */ + + if (! compptr->component_needed) { + + blkn += compptr->MCU_blocks; + + continue; + + } + + inverse_DCT = cinfo->idct->inverse_DCT[compptr->component_index]; + + useful_width = (MCU_col_num < last_MCU_col) ? compptr->MCU_width + + : compptr->last_col_width; + + output_ptr = output_buf[ci] + yoffset * compptr->DCT_scaled_size; + + start_col = MCU_col_num * compptr->MCU_sample_width; + + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + + if (cinfo->input_iMCU_row < last_iMCU_row || + + yoffset+yindex < compptr->last_row_height) { + + output_col = start_col; + + for (xindex = 0; xindex < useful_width; xindex++) { + + (*inverse_DCT) (cinfo, compptr, + + (JCOEFPTR) coef->MCU_buffer[blkn+xindex], + + output_ptr, output_col); + + output_col += compptr->DCT_scaled_size; + + } + + } + + blkn += compptr->MCU_width; + + output_ptr += compptr->DCT_scaled_size; + + } + + } + + } + + /* Completed an MCU row, but perhaps not an iMCU row */ + + coef->MCU_ctr = 0; + + } + + /* Completed the iMCU row, advance counters for next one */ + + cinfo->output_iMCU_row++; + + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + + start_iMCU_row(cinfo); + + return JPEG_ROW_COMPLETED; + + } + + /* Completed the scan */ + + (*cinfo->inputctl->finish_input_pass) (cinfo); + + return JPEG_SCAN_COMPLETED; + +} + + + + + +/* + + * Dummy consume-input routine for single-pass operation. + + */ + + + +METHODDEF int + +dummy_consume_data (j_decompress_ptr cinfo) + +{ + + return JPEG_SUSPENDED; /* Always indicate nothing was done */ + +} + + + + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + + + +/* + + * Consume input data and store it in the full-image coefficient buffer. + + * We read as much as one fully interleaved MCU row ("iMCU" row) per call, + + * ie, v_samp_factor block rows for each component in the scan. + + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + + */ + + + +METHODDEF int + +consume_data (j_decompress_ptr cinfo) + +{ + + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + JDIMENSION MCU_col_num; /* index of current MCU within row */ + + int blkn, ci, xindex, yindex, yoffset; + + JDIMENSION start_col; + + JBLOCKARRAY buffer[MAX_COMPS_IN_SCAN]; + + JBLOCKROW buffer_ptr; + + jpeg_component_info *compptr; + + + + /* Align the virtual buffers for the components used in this scan. */ + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + + compptr = cinfo->cur_comp_info[ci]; + + buffer[ci] = (*cinfo->mem->access_virt_barray) + + ((j_common_ptr) cinfo, coef->whole_image[compptr->component_index], + + cinfo->input_iMCU_row * compptr->v_samp_factor, + + (JDIMENSION) compptr->v_samp_factor, TRUE); + + /* Note: entropy decoder expects buffer to be zeroed, + + * but this is handled automatically by the memory manager + + * because we requested a pre-zeroed array. + + */ + + } + + + + /* Loop to process one whole iMCU row */ + + for (yoffset = coef->MCU_vert_offset; yoffset < coef->MCU_rows_per_iMCU_row; + + yoffset++) { + + for (MCU_col_num = coef->MCU_ctr; MCU_col_num < cinfo->MCUs_per_row; + + MCU_col_num++) { + + /* Construct list of pointers to DCT blocks belonging to this MCU */ + + blkn = 0; /* index of current DCT block within MCU */ + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + + compptr = cinfo->cur_comp_info[ci]; + + start_col = MCU_col_num * compptr->MCU_width; + + for (yindex = 0; yindex < compptr->MCU_height; yindex++) { + + buffer_ptr = buffer[ci][yindex+yoffset] + start_col; + + for (xindex = 0; xindex < compptr->MCU_width; xindex++) { + + coef->MCU_buffer[blkn++] = buffer_ptr++; + + } + + } + + } + + /* Try to fetch the MCU. */ + + if (! (*cinfo->entropy->decode_mcu) (cinfo, coef->MCU_buffer)) { + + /* Suspension forced; update state counters and exit */ + + coef->MCU_vert_offset = yoffset; + + coef->MCU_ctr = MCU_col_num; + + return JPEG_SUSPENDED; + + } + + } + + /* Completed an MCU row, but perhaps not an iMCU row */ + + coef->MCU_ctr = 0; + + } + + /* Completed the iMCU row, advance counters for next one */ + + if (++(cinfo->input_iMCU_row) < cinfo->total_iMCU_rows) { + + start_iMCU_row(cinfo); + + return JPEG_ROW_COMPLETED; + + } + + /* Completed the scan */ + + (*cinfo->inputctl->finish_input_pass) (cinfo); + + return JPEG_SCAN_COMPLETED; + +} + + + + + +/* + + * Decompress and return some data in the multi-pass case. + + * Always attempts to emit one fully interleaved MCU row ("iMCU" row). + + * Return value is JPEG_ROW_COMPLETED, JPEG_SCAN_COMPLETED, or JPEG_SUSPENDED. + + * + + * NB: output_buf contains a plane for each component in image. + + */ + + + +METHODDEF int + +decompress_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) + +{ + + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + + JDIMENSION block_num; + + int ci, block_row, block_rows; + + JBLOCKARRAY buffer; + + JBLOCKROW buffer_ptr; + + JSAMPARRAY output_ptr; + + JDIMENSION output_col; + + jpeg_component_info *compptr; + + inverse_DCT_method_ptr inverse_DCT; + + + + /* Force some input to be done if we are getting ahead of the input. */ + + while (cinfo->input_scan_number < cinfo->output_scan_number || + + (cinfo->input_scan_number == cinfo->output_scan_number && + + cinfo->input_iMCU_row <= cinfo->output_iMCU_row)) { + + if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) + + return JPEG_SUSPENDED; + + } + + + + /* OK, output from the virtual arrays. */ + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + /* Don't bother to IDCT an uninteresting component. */ + + if (! compptr->component_needed) + + continue; + + /* Align the virtual buffer for this component. */ + + buffer = (*cinfo->mem->access_virt_barray) + + ((j_common_ptr) cinfo, coef->whole_image[ci], + + cinfo->output_iMCU_row * compptr->v_samp_factor, + + (JDIMENSION) compptr->v_samp_factor, FALSE); + + /* Count non-dummy DCT block rows in this iMCU row. */ + + if (cinfo->output_iMCU_row < last_iMCU_row) + + block_rows = compptr->v_samp_factor; + + else { + + /* NB: can't use last_row_height here; it is input-side-dependent! */ + + block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + + if (block_rows == 0) block_rows = compptr->v_samp_factor; + + } + + inverse_DCT = cinfo->idct->inverse_DCT[ci]; + + output_ptr = output_buf[ci]; + + /* Loop over all DCT blocks to be processed. */ + + for (block_row = 0; block_row < block_rows; block_row++) { + + buffer_ptr = buffer[block_row]; + + output_col = 0; + + for (block_num = 0; block_num < compptr->width_in_blocks; block_num++) { + + (*inverse_DCT) (cinfo, compptr, (JCOEFPTR) buffer_ptr, + + output_ptr, output_col); + + buffer_ptr++; + + output_col += compptr->DCT_scaled_size; + + } + + output_ptr += compptr->DCT_scaled_size; + + } + + } + + + + if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) + + return JPEG_ROW_COMPLETED; + + return JPEG_SCAN_COMPLETED; + +} + + + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + + + + +#ifdef BLOCK_SMOOTHING_SUPPORTED + + + +/* + + * This code applies interblock smoothing as described by section K.8 + + * of the JPEG standard: the first 5 AC coefficients are estimated from + + * the DC values of a DCT block and its 8 neighboring blocks. + + * We apply smoothing only for progressive JPEG decoding, and only if + + * the coefficients it can estimate are not yet known to full precision. + + */ + + + +/* + + * Determine whether block smoothing is applicable and safe. + + * We also latch the current states of the coef_bits[] entries for the + + * AC coefficients; otherwise, if the input side of the decompressor + + * advances into a new scan, we might think the coefficients are known + + * more accurately than they really are. + + */ + + + +LOCAL boolean + +smoothing_ok (j_decompress_ptr cinfo) + +{ + + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + boolean smoothing_useful = FALSE; + + int ci, coefi; + + jpeg_component_info *compptr; + + JQUANT_TBL * qtable; + + int * coef_bits; + + int * coef_bits_latch; + + + + if (! cinfo->progressive_mode || cinfo->coef_bits == NULL) + + return FALSE; + + + + /* Allocate latch area if not already done */ + + if (coef->coef_bits_latch == NULL) + + coef->coef_bits_latch = (int *) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + cinfo->num_components * + + (SAVED_COEFS * SIZEOF(int))); + + coef_bits_latch = coef->coef_bits_latch; + + + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + /* All components' quantization values must already be latched. */ + + if ((qtable = compptr->quant_table) == NULL) + + return FALSE; + + /* Verify DC & first 5 AC quantizers are nonzero to avoid zero-divide. */ + + for (coefi = 0; coefi <= 5; coefi++) { + + if (qtable->quantval[coefi] == 0) + + return FALSE; + + } + + /* DC values must be at least partly known for all components. */ + + coef_bits = cinfo->coef_bits[ci]; + + if (coef_bits[0] < 0) + + return FALSE; + + /* Block smoothing is helpful if some AC coefficients remain inaccurate. */ + + for (coefi = 1; coefi <= 5; coefi++) { + + coef_bits_latch[coefi] = coef_bits[coefi]; + + if (coef_bits[coefi] != 0) + + smoothing_useful = TRUE; + + } + + coef_bits_latch += SAVED_COEFS; + + } + + + + return smoothing_useful; + +} + + + + + +/* + + * Variant of decompress_data for use when doing block smoothing. + + */ + + + +METHODDEF int + +decompress_smooth_data (j_decompress_ptr cinfo, JSAMPIMAGE output_buf) + +{ + + my_coef_ptr coef = (my_coef_ptr) cinfo->coef; + + JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; + + JDIMENSION block_num, last_block_column; + + int ci, block_row, block_rows, access_rows; + + JBLOCKARRAY buffer; + + JBLOCKROW buffer_ptr, prev_block_row, next_block_row; + + JSAMPARRAY output_ptr; + + JDIMENSION output_col; + + jpeg_component_info *compptr; + + inverse_DCT_method_ptr inverse_DCT; + + boolean first_row, last_row; + + JBLOCK workspace; + + int *coef_bits; + + JQUANT_TBL *quanttbl; + + INT32 Q00,Q01,Q02,Q10,Q11,Q20, num; + + int DC1,DC2,DC3,DC4,DC5,DC6,DC7,DC8,DC9; + + int Al, pred; + + + + /* Force some input to be done if we are getting ahead of the input. */ + + while (cinfo->input_scan_number <= cinfo->output_scan_number && + + ! cinfo->inputctl->eoi_reached) { + + if (cinfo->input_scan_number == cinfo->output_scan_number) { + + /* If input is working on current scan, we ordinarily want it to + + * have completed the current row. But if input scan is DC, + + * we want it to keep one row ahead so that next block row's DC + + * values are up to date. + + */ + + JDIMENSION delta = (cinfo->Ss == 0) ? 1 : 0; + + if (cinfo->input_iMCU_row > cinfo->output_iMCU_row+delta) + + break; + + } + + if ((*cinfo->inputctl->consume_input)(cinfo) == JPEG_SUSPENDED) + + return JPEG_SUSPENDED; + + } + + + + /* OK, output from the virtual arrays. */ + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + /* Don't bother to IDCT an uninteresting component. */ + + if (! compptr->component_needed) + + continue; + + /* Count non-dummy DCT block rows in this iMCU row. */ + + if (cinfo->output_iMCU_row < last_iMCU_row) { + + block_rows = compptr->v_samp_factor; + + access_rows = block_rows * 2; /* this and next iMCU row */ + + last_row = FALSE; + + } else { + + /* NB: can't use last_row_height here; it is input-side-dependent! */ + + block_rows = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + + if (block_rows == 0) block_rows = compptr->v_samp_factor; + + access_rows = block_rows; /* this iMCU row only */ + + last_row = TRUE; + + } + + /* Align the virtual buffer for this component. */ + + if (cinfo->output_iMCU_row > 0) { + + access_rows += compptr->v_samp_factor; /* prior iMCU row too */ + + buffer = (*cinfo->mem->access_virt_barray) + + ((j_common_ptr) cinfo, coef->whole_image[ci], + + (cinfo->output_iMCU_row - 1) * compptr->v_samp_factor, + + (JDIMENSION) access_rows, FALSE); + + buffer += compptr->v_samp_factor; /* point to current iMCU row */ + + first_row = FALSE; + + } else { + + buffer = (*cinfo->mem->access_virt_barray) + + ((j_common_ptr) cinfo, coef->whole_image[ci], + + (JDIMENSION) 0, (JDIMENSION) access_rows, FALSE); + + first_row = TRUE; + + } + + /* Fetch component-dependent info */ + + coef_bits = coef->coef_bits_latch + (ci * SAVED_COEFS); + + quanttbl = compptr->quant_table; + + Q00 = quanttbl->quantval[0]; + + Q01 = quanttbl->quantval[1]; + + Q10 = quanttbl->quantval[2]; + + Q20 = quanttbl->quantval[3]; + + Q11 = quanttbl->quantval[4]; + + Q02 = quanttbl->quantval[5]; + + inverse_DCT = cinfo->idct->inverse_DCT[ci]; + + output_ptr = output_buf[ci]; + + /* Loop over all DCT blocks to be processed. */ + + for (block_row = 0; block_row < block_rows; block_row++) { + + buffer_ptr = buffer[block_row]; + + if (first_row && block_row == 0) + + prev_block_row = buffer_ptr; + + else + + prev_block_row = buffer[block_row-1]; + + if (last_row && block_row == block_rows-1) + + next_block_row = buffer_ptr; + + else + + next_block_row = buffer[block_row+1]; + + /* We fetch the surrounding DC values using a sliding-register approach. + + * Initialize all nine here so as to do the right thing on narrow pics. + + */ + + DC1 = DC2 = DC3 = (int) prev_block_row[0][0]; + + DC4 = DC5 = DC6 = (int) buffer_ptr[0][0]; + + DC7 = DC8 = DC9 = (int) next_block_row[0][0]; + + output_col = 0; + + last_block_column = compptr->width_in_blocks - 1; + + for (block_num = 0; block_num <= last_block_column; block_num++) { + + /* Fetch current DCT block into workspace so we can modify it. */ + + jcopy_block_row(buffer_ptr, (JBLOCKROW) workspace, (JDIMENSION) 1); + + /* Update DC values */ + + if (block_num < last_block_column) { + + DC3 = (int) prev_block_row[1][0]; + + DC6 = (int) buffer_ptr[1][0]; + + DC9 = (int) next_block_row[1][0]; + + } + + /* Compute coefficient estimates per K.8. + + * An estimate is applied only if coefficient is still zero, + + * and is not known to be fully accurate. + + */ + + /* AC01 */ + + if ((Al=coef_bits[1]) != 0 && workspace[1] == 0) { + + num = 36 * Q00 * (DC4 - DC6); + + if (num >= 0) { + + pred = (int) (((Q01<<7) + num) / (Q01<<8)); + + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + + pred = (int) (((Q10<<7) + num) / (Q10<<8)); + + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + + pred = (int) (((Q20<<7) + num) / (Q20<<8)); + + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + + pred = (int) (((Q11<<7) + num) / (Q11<<8)); + + if (Al > 0 && pred >= (1< 0 && pred >= (1<= 0) { + + pred = (int) (((Q02<<7) + num) / (Q02<<8)); + + if (Al > 0 && pred >= (1< 0 && pred >= (1<DCT_scaled_size; + + } + + output_ptr += compptr->DCT_scaled_size; + + } + + } + + + + if (++(cinfo->output_iMCU_row) < cinfo->total_iMCU_rows) + + return JPEG_ROW_COMPLETED; + + return JPEG_SCAN_COMPLETED; + +} + + + +#endif /* BLOCK_SMOOTHING_SUPPORTED */ + + + + + +/* + + * Initialize coefficient buffer controller. + + */ + + + +GLOBAL void + +jinit_d_coef_controller (j_decompress_ptr cinfo, boolean need_full_buffer) + +{ + + my_coef_ptr coef; + + + + coef = (my_coef_ptr) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + SIZEOF(my_coef_controller)); + + cinfo->coef = (struct jpeg_d_coef_controller *) coef; + + coef->pub.start_input_pass = start_input_pass; + + coef->pub.start_output_pass = start_output_pass; + +#ifdef BLOCK_SMOOTHING_SUPPORTED + + coef->coef_bits_latch = NULL; + +#endif + + + + /* Create the coefficient buffer. */ + + if (need_full_buffer) { + +#ifdef D_MULTISCAN_FILES_SUPPORTED + + /* Allocate a full-image virtual array for each component, */ + + /* padded to a multiple of samp_factor DCT blocks in each direction. */ + + /* Note we ask for a pre-zeroed array. */ + + int ci, access_rows; + + jpeg_component_info *compptr; + + + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + access_rows = compptr->v_samp_factor; + +#ifdef BLOCK_SMOOTHING_SUPPORTED + + /* If block smoothing could be used, need a bigger window */ + + if (cinfo->progressive_mode) + + access_rows *= 3; + +#endif + + coef->whole_image[ci] = (*cinfo->mem->request_virt_barray) + + ((j_common_ptr) cinfo, JPOOL_IMAGE, TRUE, + + (JDIMENSION) jround_up((long) compptr->width_in_blocks, + + (long) compptr->h_samp_factor), + + (JDIMENSION) jround_up((long) compptr->height_in_blocks, + + (long) compptr->v_samp_factor), + + (JDIMENSION) access_rows); + + } + + coef->pub.consume_data = consume_data; + + coef->pub.decompress_data = decompress_data; + + coef->pub.coef_arrays = coef->whole_image; /* link to virtual arrays */ + +#else + + ERREXIT(cinfo, JERR_NOT_COMPILED); + +#endif + + } else { + + /* We only need a single-MCU buffer. */ + + JBLOCKROW buffer; + + int i; + + + + buffer = (JBLOCKROW) + + (*cinfo->mem->alloc_large) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + D_MAX_BLOCKS_IN_MCU * SIZEOF(JBLOCK)); + + for (i = 0; i < D_MAX_BLOCKS_IN_MCU; i++) { + + coef->MCU_buffer[i] = buffer + i; + + } + + coef->pub.consume_data = dummy_consume_data; + + coef->pub.decompress_data = decompress_onepass; + + coef->pub.coef_arrays = NULL; /* flag for no virtual arrays */ + + } + +} + diff --git a/libs/jpeg6/jdcolor.cpp b/libs/jpeg6/jdcolor.cpp new file mode 100644 index 00000000..5c173597 --- /dev/null +++ b/libs/jpeg6/jdcolor.cpp @@ -0,0 +1,734 @@ +/* + + * jdcolor.c + + * + + * Copyright (C) 1991-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains output colorspace conversion routines. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + + + + + +/* Private subobject */ + + + +typedef struct { + + struct jpeg_color_deconverter pub; /* public fields */ + + + + /* Private state for YCC->RGB conversion */ + + int * Cr_r_tab; /* => table for Cr to R conversion */ + + int * Cb_b_tab; /* => table for Cb to B conversion */ + + INT32 * Cr_g_tab; /* => table for Cr to G conversion */ + + INT32 * Cb_g_tab; /* => table for Cb to G conversion */ + +} my_color_deconverter; + + + +typedef my_color_deconverter * my_cconvert_ptr; + + + + + +/**************** YCbCr -> RGB conversion: most common case **************/ + + + +/* + + * YCbCr is defined per CCIR 601-1, except that Cb and Cr are + + * normalized to the range 0..MAXJSAMPLE rather than -0.5 .. 0.5. + + * The conversion equations to be implemented are therefore + + * R = Y + 1.40200 * Cr + + * G = Y - 0.34414 * Cb - 0.71414 * Cr + + * B = Y + 1.77200 * Cb + + * where Cb and Cr represent the incoming values less CENTERJSAMPLE. + + * (These numbers are derived from TIFF 6.0 section 21, dated 3-June-92.) + + * + + * To avoid floating-point arithmetic, we represent the fractional constants + + * as integers scaled up by 2^16 (about 4 digits precision); we have to divide + + * the products by 2^16, with appropriate rounding, to get the correct answer. + + * Notice that Y, being an integral input, does not contribute any fraction + + * so it need not participate in the rounding. + + * + + * For even more speed, we avoid doing any multiplications in the inner loop + + * by precalculating the constants times Cb and Cr for all possible values. + + * For 8-bit JSAMPLEs this is very reasonable (only 256 entries per table); + + * for 12-bit samples it is still acceptable. It's not very reasonable for + + * 16-bit samples, but if you want lossless storage you shouldn't be changing + + * colorspace anyway. + + * The Cr=>R and Cb=>B values can be rounded to integers in advance; the + + * values for the G calculation are left scaled up, since we must add them + + * together before rounding. + + */ + + + +#define SCALEBITS 16 /* speediest right-shift on some machines */ + +#define ONE_HALF ((INT32) 1 << (SCALEBITS-1)) + +#define FIX(x) ((INT32) ((x) * (1L<RGB colorspace conversion. + + */ + + + +LOCAL void + +build_ycc_rgb_table (j_decompress_ptr cinfo) + +{ + + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + + int i; + + INT32 x; + + SHIFT_TEMPS + + + + cconvert->Cr_r_tab = (int *) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + (MAXJSAMPLE+1) * SIZEOF(int)); + + cconvert->Cb_b_tab = (int *) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + (MAXJSAMPLE+1) * SIZEOF(int)); + + cconvert->Cr_g_tab = (INT32 *) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + (MAXJSAMPLE+1) * SIZEOF(INT32)); + + cconvert->Cb_g_tab = (INT32 *) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + (MAXJSAMPLE+1) * SIZEOF(INT32)); + + + + for (i = 0, x = -CENTERJSAMPLE; i <= MAXJSAMPLE; i++, x++) { + + /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */ + + /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */ + + /* Cr=>R value is nearest int to 1.40200 * x */ + + cconvert->Cr_r_tab[i] = (int) + + RIGHT_SHIFT(FIX(1.40200) * x + ONE_HALF, SCALEBITS); + + /* Cb=>B value is nearest int to 1.77200 * x */ + + cconvert->Cb_b_tab[i] = (int) + + RIGHT_SHIFT(FIX(1.77200) * x + ONE_HALF, SCALEBITS); + + /* Cr=>G value is scaled-up -0.71414 * x */ + + cconvert->Cr_g_tab[i] = (- FIX(0.71414)) * x; + + /* Cb=>G value is scaled-up -0.34414 * x */ + + /* We also add in ONE_HALF so that need not do it in inner loop */ + + cconvert->Cb_g_tab[i] = (- FIX(0.34414)) * x + ONE_HALF; + + } + +} + + + + + +/* + + * Convert some rows of samples to the output colorspace. + + * + + * Note that we change from noninterleaved, one-plane-per-component format + + * to interleaved-pixel format. The output buffer is therefore three times + + * as wide as the input buffer. + + * A starting row offset is provided only for the input buffer. The caller + + * can easily adjust the passed output_buf value to accommodate any row + + * offset required on that side. + + */ + + + +METHODDEF void + +ycc_rgb_convert (j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION input_row, + + JSAMPARRAY output_buf, int num_rows) + +{ + + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + + register int y, cb, cr; + + register JSAMPROW outptr; + + register JSAMPROW inptr0, inptr1, inptr2; + + register JDIMENSION col; + + JDIMENSION num_cols = cinfo->output_width; + + /* copy these pointers into registers if possible */ + + register JSAMPLE * range_limit = cinfo->sample_range_limit; + + register int * Crrtab = cconvert->Cr_r_tab; + + register int * Cbbtab = cconvert->Cb_b_tab; + + register INT32 * Crgtab = cconvert->Cr_g_tab; + + register INT32 * Cbgtab = cconvert->Cb_g_tab; + + SHIFT_TEMPS + + + + while (--num_rows >= 0) { + + inptr0 = input_buf[0][input_row]; + + inptr1 = input_buf[1][input_row]; + + inptr2 = input_buf[2][input_row]; + + input_row++; + + outptr = *output_buf++; + + for (col = 0; col < num_cols; col++) { + + y = GETJSAMPLE(inptr0[col]); + + cb = GETJSAMPLE(inptr1[col]); + + cr = GETJSAMPLE(inptr2[col]); + + /* Range-limiting is essential due to noise introduced by DCT losses. */ + + outptr[RGB_RED] = range_limit[y + Crrtab[cr]]; + + outptr[RGB_GREEN] = range_limit[y + + + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + + SCALEBITS))]; + + outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]]; + + outptr += RGB_PIXELSIZE; + + } + + } + +} + + + + + +/**************** Cases other than YCbCr -> RGB **************/ + + + + + +/* + + * Color conversion for no colorspace change: just copy the data, + + * converting from separate-planes to interleaved representation. + + */ + + + +METHODDEF void + +null_convert (j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION input_row, + + JSAMPARRAY output_buf, int num_rows) + +{ + + register JSAMPROW inptr, outptr; + + register JDIMENSION count; + + register int num_components = cinfo->num_components; + + JDIMENSION num_cols = cinfo->output_width; + + int ci; + + + + while (--num_rows >= 0) { + + for (ci = 0; ci < num_components; ci++) { + + inptr = input_buf[ci][input_row]; + + outptr = output_buf[0] + ci; + + for (count = num_cols; count > 0; count--) { + + *outptr = *inptr++; /* needn't bother with GETJSAMPLE() here */ + + outptr += num_components; + + } + + } + + input_row++; + + output_buf++; + + } + +} + + + + + +/* + + * Color conversion for grayscale: just copy the data. + + * This also works for YCbCr -> grayscale conversion, in which + + * we just copy the Y (luminance) component and ignore chrominance. + + */ + + + +METHODDEF void + +grayscale_convert (j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION input_row, + + JSAMPARRAY output_buf, int num_rows) + +{ + + jcopy_sample_rows(input_buf[0], (int) input_row, output_buf, 0, + + num_rows, cinfo->output_width); + +} + + + + + +/* + + * Adobe-style YCCK->CMYK conversion. + + * We convert YCbCr to R=1-C, G=1-M, and B=1-Y using the same + + * conversion as above, while passing K (black) unchanged. + + * We assume build_ycc_rgb_table has been called. + + */ + + + +METHODDEF void + +ycck_cmyk_convert (j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION input_row, + + JSAMPARRAY output_buf, int num_rows) + +{ + + my_cconvert_ptr cconvert = (my_cconvert_ptr) cinfo->cconvert; + + register int y, cb, cr; + + register JSAMPROW outptr; + + register JSAMPROW inptr0, inptr1, inptr2, inptr3; + + register JDIMENSION col; + + JDIMENSION num_cols = cinfo->output_width; + + /* copy these pointers into registers if possible */ + + register JSAMPLE * range_limit = cinfo->sample_range_limit; + + register int * Crrtab = cconvert->Cr_r_tab; + + register int * Cbbtab = cconvert->Cb_b_tab; + + register INT32 * Crgtab = cconvert->Cr_g_tab; + + register INT32 * Cbgtab = cconvert->Cb_g_tab; + + SHIFT_TEMPS + + + + while (--num_rows >= 0) { + + inptr0 = input_buf[0][input_row]; + + inptr1 = input_buf[1][input_row]; + + inptr2 = input_buf[2][input_row]; + + inptr3 = input_buf[3][input_row]; + + input_row++; + + outptr = *output_buf++; + + for (col = 0; col < num_cols; col++) { + + y = GETJSAMPLE(inptr0[col]); + + cb = GETJSAMPLE(inptr1[col]); + + cr = GETJSAMPLE(inptr2[col]); + + /* Range-limiting is essential due to noise introduced by DCT losses. */ + + outptr[0] = range_limit[MAXJSAMPLE - (y + Crrtab[cr])]; /* red */ + + outptr[1] = range_limit[MAXJSAMPLE - (y + /* green */ + + ((int) RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr], + + SCALEBITS)))]; + + outptr[2] = range_limit[MAXJSAMPLE - (y + Cbbtab[cb])]; /* blue */ + + /* K passes through unchanged */ + + outptr[3] = inptr3[col]; /* don't need GETJSAMPLE here */ + + outptr += 4; + + } + + } + +} + + + + + +/* + + * Empty method for start_pass. + + */ + + + +METHODDEF void + +start_pass_dcolor (j_decompress_ptr cinfo) + +{ + + /* no work needed */ + +} + + + + + +/* + + * Module initialization routine for output colorspace conversion. + + */ + + + +GLOBAL void + +jinit_color_deconverter (j_decompress_ptr cinfo) + +{ + + my_cconvert_ptr cconvert; + + int ci; + + + + cconvert = (my_cconvert_ptr) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + SIZEOF(my_color_deconverter)); + + cinfo->cconvert = (struct jpeg_color_deconverter *) cconvert; + + cconvert->pub.start_pass = start_pass_dcolor; + + + + /* Make sure num_components agrees with jpeg_color_space */ + + switch (cinfo->jpeg_color_space) { + + case JCS_GRAYSCALE: + + if (cinfo->num_components != 1) + + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + + break; + + + + case JCS_RGB: + + case JCS_YCbCr: + + if (cinfo->num_components != 3) + + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + + break; + + + + case JCS_CMYK: + + case JCS_YCCK: + + if (cinfo->num_components != 4) + + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + + break; + + + + default: /* JCS_UNKNOWN can be anything */ + + if (cinfo->num_components < 1) + + ERREXIT(cinfo, JERR_BAD_J_COLORSPACE); + + break; + + } + + + + /* Set out_color_components and conversion method based on requested space. + + * Also clear the component_needed flags for any unused components, + + * so that earlier pipeline stages can avoid useless computation. + + */ + + + + switch (cinfo->out_color_space) { + + case JCS_GRAYSCALE: + + cinfo->out_color_components = 1; + + if (cinfo->jpeg_color_space == JCS_GRAYSCALE || + + cinfo->jpeg_color_space == JCS_YCbCr) { + + cconvert->pub.color_convert = grayscale_convert; + + /* For color->grayscale conversion, only the Y (0) component is needed */ + + for (ci = 1; ci < cinfo->num_components; ci++) + + cinfo->comp_info[ci].component_needed = FALSE; + + } else + + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + + break; + + + + case JCS_RGB: + + cinfo->out_color_components = RGB_PIXELSIZE; + + if (cinfo->jpeg_color_space == JCS_YCbCr) { + + cconvert->pub.color_convert = ycc_rgb_convert; + + build_ycc_rgb_table(cinfo); + + } else if (cinfo->jpeg_color_space == JCS_RGB && RGB_PIXELSIZE == 3) { + + cconvert->pub.color_convert = null_convert; + + } else + + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + + break; + + + + case JCS_CMYK: + + cinfo->out_color_components = 4; + + if (cinfo->jpeg_color_space == JCS_YCCK) { + + cconvert->pub.color_convert = ycck_cmyk_convert; + + build_ycc_rgb_table(cinfo); + + } else if (cinfo->jpeg_color_space == JCS_CMYK) { + + cconvert->pub.color_convert = null_convert; + + } else + + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + + break; + + + + default: + + /* Permit null conversion to same output space */ + + if (cinfo->out_color_space == cinfo->jpeg_color_space) { + + cinfo->out_color_components = cinfo->num_components; + + cconvert->pub.color_convert = null_convert; + + } else /* unsupported non-null conversion */ + + ERREXIT(cinfo, JERR_CONVERSION_NOTIMPL); + + break; + + } + + + + if (cinfo->quantize_colors) + + cinfo->output_components = 1; /* single colormapped output component */ + + else + + cinfo->output_components = cinfo->out_color_components; + +} + diff --git a/libs/jpeg6/jdct.h b/libs/jpeg6/jdct.h new file mode 100644 index 00000000..cebb118e --- /dev/null +++ b/libs/jpeg6/jdct.h @@ -0,0 +1,352 @@ +/* + + * jdct.h + + * + + * Copyright (C) 1994, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This include file contains common declarations for the forward and + + * inverse DCT modules. These declarations are private to the DCT managers + + * (jcdctmgr.c, jddctmgr.c) and the individual DCT algorithms. + + * The individual DCT algorithms are kept in separate files to ease + + * machine-dependent tuning (e.g., assembly coding). + + */ + + + + + +/* + + * A forward DCT routine is given a pointer to a work area of type DCTELEM[]; + + * the DCT is to be performed in-place in that buffer. Type DCTELEM is int + + * for 8-bit samples, INT32 for 12-bit samples. (NOTE: Floating-point DCT + + * implementations use an array of type FAST_FLOAT, instead.) + + * The DCT inputs are expected to be signed (range +-CENTERJSAMPLE). + + * The DCT outputs are returned scaled up by a factor of 8; they therefore + + * have a range of +-8K for 8-bit data, +-128K for 12-bit data. This + + * convention improves accuracy in integer implementations and saves some + + * work in floating-point ones. + + * Quantization of the output coefficients is done by jcdctmgr.c. + + */ + + + +#if BITS_IN_JSAMPLE == 8 + +typedef int DCTELEM; /* 16 or 32 bits is fine */ + +#else + +typedef INT32 DCTELEM; /* must have 32 bits */ + +#endif + + + +typedef JMETHOD(void, forward_DCT_method_ptr, (DCTELEM * data)); + +typedef JMETHOD(void, float_DCT_method_ptr, (FAST_FLOAT * data)); + + + + + +/* + + * An inverse DCT routine is given a pointer to the input JBLOCK and a pointer + + * to an output sample array. The routine must dequantize the input data as + + * well as perform the IDCT; for dequantization, it uses the multiplier table + + * pointed to by compptr->dct_table. The output data is to be placed into the + + * sample array starting at a specified column. (Any row offset needed will + + * be applied to the array pointer before it is passed to the IDCT code.) + + * Note that the number of samples emitted by the IDCT routine is + + * DCT_scaled_size * DCT_scaled_size. + + */ + + + +/* typedef inverse_DCT_method_ptr is declared in jpegint.h */ + + + +/* + + * Each IDCT routine has its own ideas about the best dct_table element type. + + */ + + + +typedef MULTIPLIER ISLOW_MULT_TYPE; /* short or int, whichever is faster */ + +#if BITS_IN_JSAMPLE == 8 + +typedef MULTIPLIER IFAST_MULT_TYPE; /* 16 bits is OK, use short if faster */ + +#define IFAST_SCALE_BITS 2 /* fractional bits in scale factors */ + +#else + +typedef INT32 IFAST_MULT_TYPE; /* need 32 bits for scaled quantizers */ + +#define IFAST_SCALE_BITS 13 /* fractional bits in scale factors */ + +#endif + +typedef FAST_FLOAT FLOAT_MULT_TYPE; /* preferred floating type */ + + + + + +/* + + * Each IDCT routine is responsible for range-limiting its results and + + * converting them to unsigned form (0..MAXJSAMPLE). The raw outputs could + + * be quite far out of range if the input data is corrupt, so a bulletproof + + * range-limiting step is required. We use a mask-and-table-lookup method + + * to do the combined operations quickly. See the comments with + + * prepare_range_limit_table (in jdmaster.c) for more info. + + */ + + + +#define IDCT_range_limit(cinfo) ((cinfo)->sample_range_limit + CENTERJSAMPLE) + + + +#define RANGE_MASK (MAXJSAMPLE * 4 + 3) /* 2 bits wider than legal samples */ + + + + + +/* Short forms of external names for systems with brain-damaged linkers. */ + + + +#ifdef NEED_SHORT_EXTERNAL_NAMES + +#define jpeg_fdct_islow jFDislow + +#define jpeg_fdct_ifast jFDifast + +#define jpeg_fdct_float jFDfloat + +#define jpeg_idct_islow jRDislow + +#define jpeg_idct_ifast jRDifast + +#define jpeg_idct_float jRDfloat + +#define jpeg_idct_4x4 jRD4x4 + +#define jpeg_idct_2x2 jRD2x2 + +#define jpeg_idct_1x1 jRD1x1 + +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + + +/* Extern declarations for the forward and inverse DCT routines. */ + + + +EXTERN void jpeg_fdct_islow JPP((DCTELEM * data)); + +EXTERN void jpeg_fdct_ifast JPP((DCTELEM * data)); + +EXTERN void jpeg_fdct_float JPP((FAST_FLOAT * data)); + + + +EXTERN void jpeg_idct_islow + + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); + +EXTERN void jpeg_idct_ifast + + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); + +EXTERN void jpeg_idct_float + + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); + +EXTERN void jpeg_idct_4x4 + + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); + +EXTERN void jpeg_idct_2x2 + + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); + +EXTERN void jpeg_idct_1x1 + + JPP((j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JCOEFPTR coef_block, JSAMPARRAY output_buf, JDIMENSION output_col)); + + + + + +/* + + * Macros for handling fixed-point arithmetic; these are used by many + + * but not all of the DCT/IDCT modules. + + * + + * All values are expected to be of type INT32. + + * Fractional constants are scaled left by CONST_BITS bits. + + * CONST_BITS is defined within each module using these macros, + + * and may differ from one module to the next. + + */ + + + +#define ONE ((INT32) 1) + +#define CONST_SCALE (ONE << CONST_BITS) + + + +/* Convert a positive real constant to an integer scaled by CONST_SCALE. + + * Caution: some C compilers fail to reduce "FIX(constant)" at compile time, + + * thus causing a lot of useless floating-point operations at run time. + + */ + + + +#define FIX(x) ((INT32) ((x) * CONST_SCALE + 0.5)) + + + +/* Descale and correctly round an INT32 value that's scaled by N bits. + + * We assume RIGHT_SHIFT rounds towards minus infinity, so adding + + * the fudge factor is correct for either sign of X. + + */ + + + +#define DESCALE(x,n) RIGHT_SHIFT((x) + (ONE << ((n)-1)), n) + + + +/* Multiply an INT32 variable by an INT32 constant to yield an INT32 result. + + * This macro is used only when the two inputs will actually be no more than + + * 16 bits wide, so that a 16x16->32 bit multiply can be used instead of a + + * full 32x32 multiply. This provides a useful speedup on many machines. + + * Unfortunately there is no way to specify a 16x16->32 multiply portably + + * in C, but some C compilers will do the right thing if you provide the + + * correct combination of casts. + + */ + + + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ + +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT16) (const))) + +#endif + +#ifdef SHORTxLCONST_32 /* known to work with Microsoft C 6.0 */ + +#define MULTIPLY16C16(var,const) (((INT16) (var)) * ((INT32) (const))) + +#endif + + + +#ifndef MULTIPLY16C16 /* default definition */ + +#define MULTIPLY16C16(var,const) ((var) * (const)) + +#endif + + + +/* Same except both inputs are variables. */ + + + +#ifdef SHORTxSHORT_32 /* may work if 'int' is 32 bits */ + +#define MULTIPLY16V16(var1,var2) (((INT16) (var1)) * ((INT16) (var2))) + +#endif + + + +#ifndef MULTIPLY16V16 /* default definition */ + +#define MULTIPLY16V16(var1,var2) ((var1) * (var2)) + +#endif + diff --git a/libs/jpeg6/jddctmgr.cpp b/libs/jpeg6/jddctmgr.cpp new file mode 100644 index 00000000..cdf107e0 --- /dev/null +++ b/libs/jpeg6/jddctmgr.cpp @@ -0,0 +1,540 @@ +/* + + * jddctmgr.c + + * + + * Copyright (C) 1994-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains the inverse-DCT management logic. + + * This code selects a particular IDCT implementation to be used, + + * and it performs related housekeeping chores. No code in this file + + * is executed per IDCT step, only during output pass setup. + + * + + * Note that the IDCT routines are responsible for performing coefficient + + * dequantization as well as the IDCT proper. This module sets up the + + * dequantization multiplier table needed by the IDCT routine. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + +#include "jdct.h" /* Private declarations for DCT subsystem */ + + + + + +/* + + * The decompressor input side (jdinput.c) saves away the appropriate + + * quantization table for each component at the start of the first scan + + * involving that component. (This is necessary in order to correctly + + * decode files that reuse Q-table slots.) + + * When we are ready to make an output pass, the saved Q-table is converted + + * to a multiplier table that will actually be used by the IDCT routine. + + * The multiplier table contents are IDCT-method-dependent. To support + + * application changes in IDCT method between scans, we can remake the + + * multiplier tables if necessary. + + * In buffered-image mode, the first output pass may occur before any data + + * has been seen for some components, and thus before their Q-tables have + + * been saved away. To handle this case, multiplier tables are preset + + * to zeroes; the result of the IDCT will be a neutral gray level. + + */ + + + + + +/* Private subobject for this module */ + + + +typedef struct { + + struct jpeg_inverse_dct pub; /* public fields */ + + + + /* This array contains the IDCT method code that each multiplier table + + * is currently set up for, or -1 if it's not yet set up. + + * The actual multiplier tables are pointed to by dct_table in the + + * per-component comp_info structures. + + */ + + int cur_method[MAX_COMPONENTS]; + +} my_idct_controller; + + + +typedef my_idct_controller * my_idct_ptr; + + + + + +/* Allocated multiplier tables: big enough for any supported variant */ + + + +typedef union { + + ISLOW_MULT_TYPE islow_array[DCTSIZE2]; + +#ifdef DCT_IFAST_SUPPORTED + + IFAST_MULT_TYPE ifast_array[DCTSIZE2]; + +#endif + +#ifdef DCT_FLOAT_SUPPORTED + + FLOAT_MULT_TYPE float_array[DCTSIZE2]; + +#endif + +} multiplier_table; + + + + + +/* The current scaled-IDCT routines require ISLOW-style multiplier tables, + + * so be sure to compile that code if either ISLOW or SCALING is requested. + + */ + +#ifdef DCT_ISLOW_SUPPORTED + +#define PROVIDE_ISLOW_TABLES + +#else + +#ifdef IDCT_SCALING_SUPPORTED + +#define PROVIDE_ISLOW_TABLES + +#endif + +#endif + + + + + +/* + + * Prepare for an output pass. + + * Here we select the proper IDCT routine for each component and build + + * a matching multiplier table. + + */ + + + +METHODDEF void + +start_pass (j_decompress_ptr cinfo) + +{ + + my_idct_ptr idct = (my_idct_ptr) cinfo->idct; + + int ci, i; + + jpeg_component_info *compptr; + + int method = 0; + + inverse_DCT_method_ptr method_ptr = NULL; + + JQUANT_TBL * qtbl; + + + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + /* Select the proper IDCT routine for this component's scaling */ + + switch (compptr->DCT_scaled_size) { + +#ifdef IDCT_SCALING_SUPPORTED + + case 1: + + method_ptr = jpeg_idct_1x1; + + method = JDCT_ISLOW; /* jidctred uses islow-style table */ + + break; + + case 2: + + method_ptr = jpeg_idct_2x2; + + method = JDCT_ISLOW; /* jidctred uses islow-style table */ + + break; + + case 4: + + method_ptr = jpeg_idct_4x4; + + method = JDCT_ISLOW; /* jidctred uses islow-style table */ + + break; + +#endif + + case DCTSIZE: + + switch (cinfo->dct_method) { + +#ifdef DCT_ISLOW_SUPPORTED + + case JDCT_ISLOW: + + method_ptr = jpeg_idct_islow; + + method = JDCT_ISLOW; + + break; + +#endif + +#ifdef DCT_IFAST_SUPPORTED + + case JDCT_IFAST: + + method_ptr = jpeg_idct_ifast; + + method = JDCT_IFAST; + + break; + +#endif + +#ifdef DCT_FLOAT_SUPPORTED + + case JDCT_FLOAT: + + method_ptr = jpeg_idct_float; + + method = JDCT_FLOAT; + + break; + +#endif + + default: + + ERREXIT(cinfo, JERR_NOT_COMPILED); + + break; + + } + + break; + + default: + + ERREXIT1(cinfo, JERR_BAD_DCTSIZE, compptr->DCT_scaled_size); + + break; + + } + + idct->pub.inverse_DCT[ci] = method_ptr; + + /* Create multiplier table from quant table. + + * However, we can skip this if the component is uninteresting + + * or if we already built the table. Also, if no quant table + + * has yet been saved for the component, we leave the + + * multiplier table all-zero; we'll be reading zeroes from the + + * coefficient controller's buffer anyway. + + */ + + if (! compptr->component_needed || idct->cur_method[ci] == method) + + continue; + + qtbl = compptr->quant_table; + + if (qtbl == NULL) /* happens if no data yet for component */ + + continue; + + idct->cur_method[ci] = method; + + switch (method) { + +#ifdef PROVIDE_ISLOW_TABLES + + case JDCT_ISLOW: + + { + + /* For LL&M IDCT method, multipliers are equal to raw quantization + + * coefficients, but are stored in natural order as ints. + + */ + + ISLOW_MULT_TYPE * ismtbl = (ISLOW_MULT_TYPE *) compptr->dct_table; + + for (i = 0; i < DCTSIZE2; i++) { + + ismtbl[i] = (ISLOW_MULT_TYPE) qtbl->quantval[jpeg_zigzag_order[i]]; + + } + + } + + break; + +#endif + +#ifdef DCT_IFAST_SUPPORTED + + case JDCT_IFAST: + + { + + /* For AA&N IDCT method, multipliers are equal to quantization + + * coefficients scaled by scalefactor[row]*scalefactor[col], where + + * scalefactor[0] = 1 + + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + + * For integer operation, the multiplier table is to be scaled by + + * IFAST_SCALE_BITS. The multipliers are stored in natural order. + + */ + + IFAST_MULT_TYPE * ifmtbl = (IFAST_MULT_TYPE *) compptr->dct_table; + +#define CONST_BITS 14 + + static const INT16 aanscales[DCTSIZE2] = { + + /* precomputed values scaled up by 14 bits */ + + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + + 22725, 31521, 29692, 26722, 22725, 17855, 12299, 6270, + + 21407, 29692, 27969, 25172, 21407, 16819, 11585, 5906, + + 19266, 26722, 25172, 22654, 19266, 15137, 10426, 5315, + + 16384, 22725, 21407, 19266, 16384, 12873, 8867, 4520, + + 12873, 17855, 16819, 15137, 12873, 10114, 6967, 3552, + + 8867, 12299, 11585, 10426, 8867, 6967, 4799, 2446, + + 4520, 6270, 5906, 5315, 4520, 3552, 2446, 1247 + + }; + + SHIFT_TEMPS + + + + for (i = 0; i < DCTSIZE2; i++) { + + ifmtbl[i] = (IFAST_MULT_TYPE) + + DESCALE(MULTIPLY16V16((INT32) qtbl->quantval[jpeg_zigzag_order[i]], + + (INT32) aanscales[i]), + + CONST_BITS-IFAST_SCALE_BITS); + + } + + } + + break; + +#endif + +#ifdef DCT_FLOAT_SUPPORTED + + case JDCT_FLOAT: + + { + + /* For float AA&N IDCT method, multipliers are equal to quantization + + * coefficients scaled by scalefactor[row]*scalefactor[col], where + + * scalefactor[0] = 1 + + * scalefactor[k] = cos(k*PI/16) * sqrt(2) for k=1..7 + + * The multipliers are stored in natural order. + + */ + + FLOAT_MULT_TYPE * fmtbl = (FLOAT_MULT_TYPE *) compptr->dct_table; + + int row, col; + + static const double aanscalefactor[DCTSIZE] = { + + 1.0, 1.387039845, 1.306562965, 1.175875602, + + 1.0, 0.785694958, 0.541196100, 0.275899379 + + }; + + + + i = 0; + + for (row = 0; row < DCTSIZE; row++) { + + for (col = 0; col < DCTSIZE; col++) { + + fmtbl[i] = (FLOAT_MULT_TYPE) + + ((double) qtbl->quantval[jpeg_zigzag_order[i]] * + + aanscalefactor[row] * aanscalefactor[col]); + + i++; + + } + + } + + } + + break; + +#endif + + default: + + ERREXIT(cinfo, JERR_NOT_COMPILED); + + break; + + } + + } + +} + + + + + +/* + + * Initialize IDCT manager. + + */ + + + +GLOBAL void + +jinit_inverse_dct (j_decompress_ptr cinfo) + +{ + + my_idct_ptr idct; + + int ci; + + jpeg_component_info *compptr; + + + + idct = (my_idct_ptr) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + SIZEOF(my_idct_controller)); + + cinfo->idct = (struct jpeg_inverse_dct *) idct; + + idct->pub.start_pass = start_pass; + + + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + /* Allocate and pre-zero a multiplier table for each component */ + + compptr->dct_table = + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + SIZEOF(multiplier_table)); + + MEMZERO(compptr->dct_table, SIZEOF(multiplier_table)); + + /* Mark multiplier table not yet set up for any method */ + + idct->cur_method[ci] = -1; + + } + +} + diff --git a/libs/jpeg6/jdhuff.cpp b/libs/jpeg6/jdhuff.cpp new file mode 100644 index 00000000..4ed8bc3a --- /dev/null +++ b/libs/jpeg6/jdhuff.cpp @@ -0,0 +1,574 @@ +/* + * jdhuff.c + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains Huffman entropy decoding routines. + * + * Much of the complexity here has to do with supporting input suspension. + * If the data source module demands suspension, we want to be able to back + * up to the start of the current MCU. To do this, we copy state variables + * into local working storage, and update them back to the permanent + * storage only upon successful completion of an MCU. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "radiant_jpeglib.h" +#include "jdhuff.h" /* Declarations shared with jdphuff.c */ + + +/* + * Expanded entropy decoder object for Huffman decoding. + * + * The savable_state subrecord contains fields that change within an MCU, + * but must not be updated permanently until we complete the MCU. + */ + +typedef struct { + int last_dc_val[MAX_COMPS_IN_SCAN]; /* last DC coef for each component */ +} savable_state; + +/* This macro is to work around compilers with missing or broken + * structure assignment. You'll need to fix this code if you have + * such a compiler and you change MAX_COMPS_IN_SCAN. + */ + +#ifndef NO_STRUCT_ASSIGN +#define ASSIGN_STATE(dest,src) ((dest) = (src)) +#else +#if MAX_COMPS_IN_SCAN == 4 +#define ASSIGN_STATE(dest,src) \ + ((dest).last_dc_val[0] = (src).last_dc_val[0], \ + (dest).last_dc_val[1] = (src).last_dc_val[1], \ + (dest).last_dc_val[2] = (src).last_dc_val[2], \ + (dest).last_dc_val[3] = (src).last_dc_val[3]) +#endif +#endif + + +typedef struct { + struct jpeg_entropy_decoder pub; /* public fields */ + + /* These fields are loaded into local variables at start of each MCU. + * In case of suspension, we exit WITHOUT updating them. + */ + bitread_perm_state bitstate; /* Bit buffer at start of MCU */ + savable_state saved; /* Other state at start of MCU */ + + /* These fields are NOT loaded into local working state. */ + unsigned int restarts_to_go; /* MCUs left in this restart interval */ + + /* Pointers to derived tables (these workspaces have image lifespan) */ + d_derived_tbl * dc_derived_tbls[NUM_HUFF_TBLS]; + d_derived_tbl * ac_derived_tbls[NUM_HUFF_TBLS]; +} huff_entropy_decoder; + +typedef huff_entropy_decoder * huff_entropy_ptr; + + +/* + * Initialize for a Huffman-compressed scan. + */ + +METHODDEF void +start_pass_huff_decoder (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci, dctbl, actbl; + jpeg_component_info * compptr; + + /* Check that the scan parameters Ss, Se, Ah/Al are OK for sequential JPEG. + * This ought to be an error condition, but we make it a warning because + * there are some baseline files out there with all zeroes in these bytes. + */ + if (cinfo->Ss != 0 || cinfo->Se != DCTSIZE2-1 || + cinfo->Ah != 0 || cinfo->Al != 0) + WARNMS(cinfo, JWRN_NOT_SEQUENTIAL); + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + compptr = cinfo->cur_comp_info[ci]; + dctbl = compptr->dc_tbl_no; + actbl = compptr->ac_tbl_no; + /* Make sure requested tables are present */ + if (dctbl < 0 || dctbl >= NUM_HUFF_TBLS || + cinfo->dc_huff_tbl_ptrs[dctbl] == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, dctbl); + if (actbl < 0 || actbl >= NUM_HUFF_TBLS || + cinfo->ac_huff_tbl_ptrs[actbl] == NULL) + ERREXIT1(cinfo, JERR_NO_HUFF_TABLE, actbl); + /* Compute derived values for Huffman tables */ + /* We may do this more than once for a table, but it's not expensive */ + jpeg_make_d_derived_tbl(cinfo, cinfo->dc_huff_tbl_ptrs[dctbl], + & entropy->dc_derived_tbls[dctbl]); + jpeg_make_d_derived_tbl(cinfo, cinfo->ac_huff_tbl_ptrs[actbl], + & entropy->ac_derived_tbls[actbl]); + /* Initialize DC predictions to 0 */ + entropy->saved.last_dc_val[ci] = 0; + } + + /* Initialize bitread state variables */ + entropy->bitstate.bits_left = 0; + entropy->bitstate.get_buffer = 0; /* unnecessary, but keeps Purify quiet */ + entropy->bitstate.printed_eod = FALSE; + + /* Initialize restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; +} + + +/* + * Compute the derived values for a Huffman table. + * Note this is also used by jdphuff.c. + */ + +GLOBAL void +jpeg_make_d_derived_tbl (j_decompress_ptr cinfo, JHUFF_TBL * htbl, + d_derived_tbl ** pdtbl) +{ + d_derived_tbl *dtbl; + int p, i, l, si; + int lookbits, ctr; + char huffsize[257]; + unsigned int huffcode[257]; + unsigned int code; + + /* Allocate a workspace if we haven't already done so. */ + if (*pdtbl == NULL) + *pdtbl = (d_derived_tbl *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(d_derived_tbl)); + dtbl = *pdtbl; + dtbl->pub = htbl; /* fill in back link */ + + /* Figure C.1: make table of Huffman code length for each symbol */ + /* Note that this is in code-length order. */ + + p = 0; + for (l = 1; l <= 16; l++) { + for (i = 1; i <= (int) htbl->bits[l]; i++) + huffsize[p++] = (char) l; + } + huffsize[p] = 0; + + /* Figure C.2: generate the codes themselves */ + /* Note that this is in code-length order. */ + + code = 0; + si = huffsize[0]; + p = 0; + while (huffsize[p]) { + while (((int) huffsize[p]) == si) { + huffcode[p++] = code; + code++; + } + code <<= 1; + si++; + } + + /* Figure F.15: generate decoding tables for bit-sequential decoding */ + + p = 0; + for (l = 1; l <= 16; l++) { + if (htbl->bits[l]) { + dtbl->valptr[l] = p; /* huffval[] index of 1st symbol of code length l */ + dtbl->mincode[l] = huffcode[p]; /* minimum code of length l */ + p += htbl->bits[l]; + dtbl->maxcode[l] = huffcode[p-1]; /* maximum code of length l */ + } else { + dtbl->maxcode[l] = -1; /* -1 if no codes of this length */ + } + } + dtbl->maxcode[17] = 0xFFFFFL; /* ensures jpeg_huff_decode terminates */ + + /* Compute lookahead tables to speed up decoding. + * First we set all the table entries to 0, indicating "too long"; + * then we iterate through the Huffman codes that are short enough and + * fill in all the entries that correspond to bit sequences starting + * with that code. + */ + + MEMZERO(dtbl->look_nbits, SIZEOF(dtbl->look_nbits)); + + p = 0; + for (l = 1; l <= HUFF_LOOKAHEAD; l++) { + for (i = 1; i <= (int) htbl->bits[l]; i++, p++) { + /* l = current code's length, p = its index in huffcode[] & huffval[]. */ + /* Generate left-justified code followed by all possible bit sequences */ + lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l); + for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) { + dtbl->look_nbits[lookbits] = l; + dtbl->look_sym[lookbits] = htbl->huffval[p]; + lookbits++; + } + } + } +} + + +/* + * Out-of-line code for bit fetching (shared with jdphuff.c). + * See jdhuff.h for info about usage. + * Note: current values of get_buffer and bits_left are passed as parameters, + * but are returned in the corresponding fields of the state struct. + * + * On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width + * of get_buffer to be used. (On machines with wider words, an even larger + * buffer could be used.) However, on some machines 32-bit shifts are + * quite slow and take time proportional to the number of places shifted. + * (This is true with most PC compilers, for instance.) In this case it may + * be a win to set MIN_GET_BITS to the minimum value of 15. This reduces the + * average shift distance at the cost of more calls to jpeg_fill_bit_buffer. + */ + +#ifdef SLOW_SHIFT_32 +#define MIN_GET_BITS 15 /* minimum allowable value */ +#else +#define MIN_GET_BITS (BIT_BUF_SIZE-7) +#endif + + +GLOBAL boolean +jpeg_fill_bit_buffer (bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + int nbits) +/* Load up the bit buffer to a depth of at least nbits */ +{ + /* Copy heavily used state fields into locals (hopefully registers) */ + register const JOCTET * next_input_byte = state->next_input_byte; + register size_t bytes_in_buffer = state->bytes_in_buffer; + register int c; + + /* Attempt to load at least MIN_GET_BITS bits into get_buffer. */ + /* (It is assumed that no request will be for more than that many bits.) */ + + while (bits_left < MIN_GET_BITS) { + /* Attempt to read a byte */ + if (state->unread_marker != 0) + goto no_more_data; /* can't advance past a marker */ + + if (bytes_in_buffer == 0) { + if (! (*state->cinfo->src->fill_input_buffer) (state->cinfo)) + return FALSE; + next_input_byte = state->cinfo->src->next_input_byte; + bytes_in_buffer = state->cinfo->src->bytes_in_buffer; + } + bytes_in_buffer--; + c = GETJOCTET(*next_input_byte++); + + /* If it's 0xFF, check and discard stuffed zero byte */ + if (c == 0xFF) { + do { + if (bytes_in_buffer == 0) { + if (! (*state->cinfo->src->fill_input_buffer) (state->cinfo)) + return FALSE; + next_input_byte = state->cinfo->src->next_input_byte; + bytes_in_buffer = state->cinfo->src->bytes_in_buffer; + } + bytes_in_buffer--; + c = GETJOCTET(*next_input_byte++); + } while (c == 0xFF); + + if (c == 0) { + /* Found FF/00, which represents an FF data byte */ + c = 0xFF; + } else { + /* Oops, it's actually a marker indicating end of compressed data. */ + /* Better put it back for use later */ + state->unread_marker = c; + + no_more_data: + /* There should be enough bits still left in the data segment; */ + /* if so, just break out of the outer while loop. */ + if (bits_left >= nbits) + break; + /* Uh-oh. Report corrupted data to user and stuff zeroes into + * the data stream, so that we can produce some kind of image. + * Note that this code will be repeated for each byte demanded + * for the rest of the segment. We use a nonvolatile flag to ensure + * that only one warning message appears. + */ + if (! *(state->printed_eod_ptr)) { + WARNMS(state->cinfo, JWRN_HIT_MARKER); + *(state->printed_eod_ptr) = TRUE; + } + c = 0; /* insert a zero byte into bit buffer */ + } + } + + /* OK, load c into get_buffer */ + get_buffer = (get_buffer << 8) | c; + bits_left += 8; + } + + /* Unload the local registers */ + state->next_input_byte = next_input_byte; + state->bytes_in_buffer = bytes_in_buffer; + state->get_buffer = get_buffer; + state->bits_left = bits_left; + + return TRUE; +} + + +/* + * Out-of-line code for Huffman code decoding. + * See jdhuff.h for info about usage. + */ + +GLOBAL int +jpeg_huff_decode (bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + d_derived_tbl * htbl, int min_bits) +{ + register int l = min_bits; + register INT32 code; + + /* HUFF_DECODE has determined that the code is at least min_bits */ + /* bits long, so fetch that many bits in one swoop. */ + + CHECK_BIT_BUFFER(*state, l, return -1); + code = GET_BITS(l); + + /* Collect the rest of the Huffman code one bit at a time. */ + /* This is per Figure F.16 in the JPEG spec. */ + + while (code > htbl->maxcode[l]) { + code <<= 1; + CHECK_BIT_BUFFER(*state, 1, return -1); + code |= GET_BITS(1); + l++; + } + + /* Unload the local registers */ + state->get_buffer = get_buffer; + state->bits_left = bits_left; + + /* With garbage input we may reach the sentinel value l = 17. */ + + if (l > 16) { + WARNMS(state->cinfo, JWRN_HUFF_BAD_CODE); + return 0; /* fake a zero as the safest result */ + } + + return htbl->pub->huffval[ htbl->valptr[l] + + ((int) (code - htbl->mincode[l])) ]; +} + + +/* + * Figure F.12: extend sign bit. + * On some machines, a shift and add will be faster than a table lookup. + */ + +#ifdef AVOID_TABLES + +#define HUFF_EXTEND(x,s) ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x)) + +#else + +#define HUFF_EXTEND(x,s) ((x) < extend_test[s] ? (x) + extend_offset[s] : (x)) + +static const int extend_test[16] = /* entry n is 2**(n-1) */ + { 0, 0x0001, 0x0002, 0x0004, 0x0008, 0x0010, 0x0020, 0x0040, 0x0080, + 0x0100, 0x0200, 0x0400, 0x0800, 0x1000, 0x2000, 0x4000 }; + +static const int extend_offset[16] = /* entry n is (-1 << n) + 1 */ + { 0, ((-1)<<1) + 1, ((-1)<<2) + 1, ((-1)<<3) + 1, ((-1)<<4) + 1, + ((-1)<<5) + 1, ((-1)<<6) + 1, ((-1)<<7) + 1, ((-1)<<8) + 1, + ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1, + ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 }; + +#endif /* AVOID_TABLES */ + + +/* + * Check for a restart marker & resynchronize decoder. + * Returns FALSE if must suspend. + */ + +LOCAL boolean +process_restart (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + int ci; + + /* Throw away any unused bits remaining in bit buffer; */ + /* include any full bytes in next_marker's count of discarded bytes */ + cinfo->marker->discarded_bytes += entropy->bitstate.bits_left / 8; + entropy->bitstate.bits_left = 0; + + /* Advance past the RSTn marker */ + if (! (*cinfo->marker->read_restart_marker) (cinfo)) + return FALSE; + + /* Re-initialize DC predictions to 0 */ + for (ci = 0; ci < cinfo->comps_in_scan; ci++) + entropy->saved.last_dc_val[ci] = 0; + + /* Reset restart counter */ + entropy->restarts_to_go = cinfo->restart_interval; + + /* Next segment can get another out-of-data warning */ + entropy->bitstate.printed_eod = FALSE; + + return TRUE; +} + + +/* + * Decode and return one MCU's worth of Huffman-compressed coefficients. + * The coefficients are reordered from zigzag order into natural array order, + * but are not dequantized. + * + * The i'th block of the MCU is stored into the block pointed to by + * MCU_data[i]. WE ASSUME THIS AREA HAS BEEN ZEROED BY THE CALLER. + * (Wholesale zeroing is usually a little faster than retail...) + * + * Returns FALSE if data source requested suspension. In that case no + * changes have been made to permanent state. (Exception: some output + * coefficients may already have been assigned. This is harmless for + * this module, since we'll just re-assign them on the next call.) + */ + +METHODDEF boolean +decode_mcu (j_decompress_ptr cinfo, JBLOCKROW *MCU_data) +{ + huff_entropy_ptr entropy = (huff_entropy_ptr) cinfo->entropy; + register int s, k, r; + int blkn, ci; + JBLOCKROW block; + BITREAD_STATE_VARS; + savable_state state; + d_derived_tbl * dctbl; + d_derived_tbl * actbl; + jpeg_component_info * compptr; + + /* Process restart marker if needed; may have to suspend */ + if (cinfo->restart_interval) { + if (entropy->restarts_to_go == 0) + if (! process_restart(cinfo)) + return FALSE; + } + + /* Load up working state */ + BITREAD_LOAD_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(state, entropy->saved); + + /* Outer loop handles each block in the MCU */ + + for (blkn = 0; blkn < cinfo->blocks_in_MCU; blkn++) { + block = MCU_data[blkn]; + ci = cinfo->MCU_membership[blkn]; + compptr = cinfo->cur_comp_info[ci]; + dctbl = entropy->dc_derived_tbls[compptr->dc_tbl_no]; + actbl = entropy->ac_derived_tbls[compptr->ac_tbl_no]; + + /* Decode a single block's worth of coefficients */ + + /* Section F.2.2.1: decode the DC coefficient difference */ + HUFF_DECODE(s, br_state, dctbl, return FALSE, label1); + if (s) { + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + } + + /* Shortcut if component's values are not interesting */ + if (! compptr->component_needed) + goto skip_ACs; + + /* Convert DC difference to actual value, update last_dc_val */ + s += state.last_dc_val[ci]; + state.last_dc_val[ci] = s; + /* Output the DC coefficient (assumes jpeg_natural_order[0] = 0) */ + (*block)[0] = (JCOEF) s; + + /* Do we need to decode the AC coefficients for this component? */ + if (compptr->DCT_scaled_size > 1) { + + /* Section F.2.2.2: decode the AC coefficients */ + /* Since zeroes are skipped, output area must be cleared beforehand */ + for (k = 1; k < DCTSIZE2; k++) { + HUFF_DECODE(s, br_state, actbl, return FALSE, label2); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + r = GET_BITS(s); + s = HUFF_EXTEND(r, s); + /* Output coefficient in natural (dezigzagged) order. + * Note: the extra entries in jpeg_natural_order[] will save us + * if k >= DCTSIZE2, which could happen if the data is corrupted. + */ + (*block)[jpeg_natural_order[k]] = (JCOEF) s; + } else { + if (r != 15) + break; + k += 15; + } + } + + } else { +skip_ACs: + + /* Section F.2.2.2: decode the AC coefficients */ + /* In this path we just discard the values */ + for (k = 1; k < DCTSIZE2; k++) { + HUFF_DECODE(s, br_state, actbl, return FALSE, label3); + + r = s >> 4; + s &= 15; + + if (s) { + k += r; + CHECK_BIT_BUFFER(br_state, s, return FALSE); + DROP_BITS(s); + } else { + if (r != 15) + break; + k += 15; + } + } + + } + } + + /* Completed MCU, so update state */ + BITREAD_SAVE_STATE(cinfo,entropy->bitstate); + ASSIGN_STATE(entropy->saved, state); + + /* Account for restart interval (no-op if not using restarts) */ + entropy->restarts_to_go--; + + return TRUE; +} + + +/* + * Module initialization routine for Huffman entropy decoding. + */ + +GLOBAL void +jinit_huff_decoder (j_decompress_ptr cinfo) +{ + huff_entropy_ptr entropy; + int i; + + entropy = (huff_entropy_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(huff_entropy_decoder)); + cinfo->entropy = (struct jpeg_entropy_decoder *) entropy; + entropy->pub.start_pass = start_pass_huff_decoder; + entropy->pub.decode_mcu = decode_mcu; + + /* Mark tables unallocated */ + for (i = 0; i < NUM_HUFF_TBLS; i++) { + entropy->dc_derived_tbls[i] = entropy->ac_derived_tbls[i] = NULL; + } +} diff --git a/libs/jpeg6/jdhuff.h b/libs/jpeg6/jdhuff.h new file mode 100644 index 00000000..65f3054f --- /dev/null +++ b/libs/jpeg6/jdhuff.h @@ -0,0 +1,202 @@ +/* + * jdhuff.h + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains declarations for Huffman entropy decoding routines + * that are shared between the sequential decoder (jdhuff.c) and the + * progressive decoder (jdphuff.c). No other modules need to see these. + */ + +/* Short forms of external names for systems with brain-damaged linkers. */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_make_d_derived_tbl jMkDDerived +#define jpeg_fill_bit_buffer jFilBitBuf +#define jpeg_huff_decode jHufDecode +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Derived data constructed for each Huffman table */ + +#define HUFF_LOOKAHEAD 8 /* # of bits of lookahead */ + +typedef struct { + /* Basic tables: (element [0] of each array is unused) */ + INT32 mincode[17]; /* smallest code of length k */ + INT32 maxcode[18]; /* largest code of length k (-1 if none) */ + /* (maxcode[17] is a sentinel to ensure jpeg_huff_decode terminates) */ + int valptr[17]; /* huffval[] index of 1st symbol of length k */ + + /* Link to public Huffman table (needed only in jpeg_huff_decode) */ + JHUFF_TBL *pub; + + /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of + * the input data stream. If the next Huffman code is no more + * than HUFF_LOOKAHEAD bits long, we can obtain its length and + * the corresponding symbol directly from these tables. + */ + int look_nbits[1< 32 bits on your machine, and shifting/masking longs is + * reasonably fast, making bit_buf_type be long and setting BIT_BUF_SIZE + * appropriately should be a win. Unfortunately we can't do this with + * something like #define BIT_BUF_SIZE (sizeof(bit_buf_type)*8) + * because not all machines measure sizeof in 8-bit bytes. + */ + +typedef struct { /* Bitreading state saved across MCUs */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ + boolean printed_eod; /* flag to suppress multiple warning msgs */ +} bitread_perm_state; + +typedef struct { /* Bitreading working state within an MCU */ + /* current data source state */ + const JOCTET * next_input_byte; /* => next byte to read from source */ + size_t bytes_in_buffer; /* # of bytes remaining in source buffer */ + int unread_marker; /* nonzero if we have hit a marker */ + /* bit input buffer --- note these values are kept in register variables, + * not in this struct, inside the inner loops. + */ + bit_buf_type get_buffer; /* current bit-extraction buffer */ + int bits_left; /* # of unused bits in it */ + /* pointers needed by jpeg_fill_bit_buffer */ + j_decompress_ptr cinfo; /* back link to decompress master record */ + boolean * printed_eod_ptr; /* => flag in permanent state */ +} bitread_working_state; + +/* Macros to declare and load/save bitread local variables. */ +#define BITREAD_STATE_VARS \ + register bit_buf_type get_buffer; \ + register int bits_left; \ + bitread_working_state br_state + +#define BITREAD_LOAD_STATE(cinfop,permstate) \ + br_state.cinfo = cinfop; \ + br_state.next_input_byte = cinfop->src->next_input_byte; \ + br_state.bytes_in_buffer = cinfop->src->bytes_in_buffer; \ + br_state.unread_marker = cinfop->unread_marker; \ + get_buffer = permstate.get_buffer; \ + bits_left = permstate.bits_left; \ + br_state.printed_eod_ptr = & permstate.printed_eod + +#define BITREAD_SAVE_STATE(cinfop,permstate) \ + cinfop->src->next_input_byte = br_state.next_input_byte; \ + cinfop->src->bytes_in_buffer = br_state.bytes_in_buffer; \ + cinfop->unread_marker = br_state.unread_marker; \ + permstate.get_buffer = get_buffer; \ + permstate.bits_left = bits_left + +/* + * These macros provide the in-line portion of bit fetching. + * Use CHECK_BIT_BUFFER to ensure there are N bits in get_buffer + * before using GET_BITS, PEEK_BITS, or DROP_BITS. + * The variables get_buffer and bits_left are assumed to be locals, + * but the state struct might not be (jpeg_huff_decode needs this). + * CHECK_BIT_BUFFER(state,n,action); + * Ensure there are N bits in get_buffer; if suspend, take action. + * val = GET_BITS(n); + * Fetch next N bits. + * val = PEEK_BITS(n); + * Fetch next N bits without removing them from the buffer. + * DROP_BITS(n); + * Discard next N bits. + * The value N should be a simple variable, not an expression, because it + * is evaluated multiple times. + */ + +#define CHECK_BIT_BUFFER(state,nbits,action) \ + { if (bits_left < (nbits)) { \ + if (! jpeg_fill_bit_buffer(&(state),get_buffer,bits_left,nbits)) \ + { action; } \ + get_buffer = (state).get_buffer; bits_left = (state).bits_left; } } + +#define GET_BITS(nbits) \ + (((int) (get_buffer >> (bits_left -= (nbits)))) & ((1<<(nbits))-1)) + +#define PEEK_BITS(nbits) \ + (((int) (get_buffer >> (bits_left - (nbits)))) & ((1<<(nbits))-1)) + +#define DROP_BITS(nbits) \ + (bits_left -= (nbits)) + +/* Load up the bit buffer to a depth of at least nbits */ +EXTERN boolean jpeg_fill_bit_buffer JPP((bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + int nbits)); + + +/* + * Code for extracting next Huffman-coded symbol from input bit stream. + * Again, this is time-critical and we make the main paths be macros. + * + * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits + * without looping. Usually, more than 95% of the Huffman codes will be 8 + * or fewer bits long. The few overlength codes are handled with a loop, + * which need not be inline code. + * + * Notes about the HUFF_DECODE macro: + * 1. Near the end of the data segment, we may fail to get enough bits + * for a lookahead. In that case, we do it the hard way. + * 2. If the lookahead table contains no entry, the next code must be + * more than HUFF_LOOKAHEAD bits long. + * 3. jpeg_huff_decode returns -1 if forced to suspend. + */ + +#define HUFF_DECODE(result,state,htbl,failaction,slowlabel) \ +{ register int nb, look; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + if (! jpeg_fill_bit_buffer(&state,get_buffer,bits_left, 0)) {failaction;} \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + if (bits_left < HUFF_LOOKAHEAD) { \ + nb = 1; goto slowlabel; \ + } \ + } \ + look = PEEK_BITS(HUFF_LOOKAHEAD); \ + if ((nb = htbl->look_nbits[look]) != 0) { \ + DROP_BITS(nb); \ + result = htbl->look_sym[look]; \ + } else { \ + nb = HUFF_LOOKAHEAD+1; \ +slowlabel: \ + if ((result=jpeg_huff_decode(&state,get_buffer,bits_left,htbl,nb)) < 0) \ + { failaction; } \ + get_buffer = state.get_buffer; bits_left = state.bits_left; \ + } \ +} + +/* Out-of-line case for Huffman code fetching */ +EXTERN int jpeg_huff_decode JPP((bitread_working_state * state, + register bit_buf_type get_buffer, register int bits_left, + d_derived_tbl * htbl, int min_bits)); diff --git a/libs/jpeg6/jdinput.cpp b/libs/jpeg6/jdinput.cpp new file mode 100644 index 00000000..4def2162 --- /dev/null +++ b/libs/jpeg6/jdinput.cpp @@ -0,0 +1,762 @@ +/* + + * jdinput.c + + * + + * Copyright (C) 1991-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains input control logic for the JPEG decompressor. + + * These routines are concerned with controlling the decompressor's input + + * processing (marker reading and coefficient decoding). The actual input + + * reading is done in jdmarker.c, jdhuff.c, and jdphuff.c. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + + + + + +/* Private state */ + + + +typedef struct { + + struct jpeg_input_controller pub; /* public fields */ + + + + boolean inheaders; /* TRUE until first SOS is reached */ + +} my_input_controller; + + + +typedef my_input_controller * my_inputctl_ptr; + + + + + +/* Forward declarations */ + +METHODDEF int consume_markers JPP((j_decompress_ptr cinfo)); + + + + + +/* + + * Routines to calculate various quantities related to the size of the image. + + */ + + + +LOCAL void + +initial_setup (j_decompress_ptr cinfo) + +/* Called once, when first SOS marker is reached */ + +{ + + int ci; + + jpeg_component_info *compptr; + + + + /* Make sure image isn't bigger than I can handle */ + + if ((long) cinfo->image_height > (long) JPEG_MAX_DIMENSION || + + (long) cinfo->image_width > (long) JPEG_MAX_DIMENSION) + + ERREXIT1(cinfo, JERR_IMAGE_TOO_BIG, (unsigned int) JPEG_MAX_DIMENSION); + + + + /* For now, precision must match compiled-in value... */ + + if (cinfo->data_precision != BITS_IN_JSAMPLE) + + ERREXIT1(cinfo, JERR_BAD_PRECISION, cinfo->data_precision); + + + + /* Check that number of components won't exceed internal array sizes */ + + if (cinfo->num_components > MAX_COMPONENTS) + + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->num_components, + + MAX_COMPONENTS); + + + + /* Compute maximum sampling factors; check factor validity */ + + cinfo->max_h_samp_factor = 1; + + cinfo->max_v_samp_factor = 1; + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + if (compptr->h_samp_factor<=0 || compptr->h_samp_factor>MAX_SAMP_FACTOR || + + compptr->v_samp_factor<=0 || compptr->v_samp_factor>MAX_SAMP_FACTOR) + + ERREXIT(cinfo, JERR_BAD_SAMPLING); + + cinfo->max_h_samp_factor = MAX(cinfo->max_h_samp_factor, + + compptr->h_samp_factor); + + cinfo->max_v_samp_factor = MAX(cinfo->max_v_samp_factor, + + compptr->v_samp_factor); + + } + + + + /* We initialize DCT_scaled_size and min_DCT_scaled_size to DCTSIZE. + + * In the full decompressor, this will be overridden by jdmaster.c; + + * but in the transcoder, jdmaster.c is not used, so we must do it here. + + */ + + cinfo->min_DCT_scaled_size = DCTSIZE; + + + + /* Compute dimensions of components */ + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + compptr->DCT_scaled_size = DCTSIZE; + + /* Size in DCT blocks */ + + compptr->width_in_blocks = (JDIMENSION) + + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + + compptr->height_in_blocks = (JDIMENSION) + + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + + (long) (cinfo->max_v_samp_factor * DCTSIZE)); + + /* downsampled_width and downsampled_height will also be overridden by + + * jdmaster.c if we are doing full decompression. The transcoder library + + * doesn't use these values, but the calling application might. + + */ + + /* Size in samples */ + + compptr->downsampled_width = (JDIMENSION) + + jdiv_round_up((long) cinfo->image_width * (long) compptr->h_samp_factor, + + (long) cinfo->max_h_samp_factor); + + compptr->downsampled_height = (JDIMENSION) + + jdiv_round_up((long) cinfo->image_height * (long) compptr->v_samp_factor, + + (long) cinfo->max_v_samp_factor); + + /* Mark component needed, until color conversion says otherwise */ + + compptr->component_needed = TRUE; + + /* Mark no quantization table yet saved for component */ + + compptr->quant_table = NULL; + + } + + + + /* Compute number of fully interleaved MCU rows. */ + + cinfo->total_iMCU_rows = (JDIMENSION) + + jdiv_round_up((long) cinfo->image_height, + + (long) (cinfo->max_v_samp_factor*DCTSIZE)); + + + + /* Decide whether file contains multiple scans */ + + if (cinfo->comps_in_scan < cinfo->num_components || cinfo->progressive_mode) + + cinfo->inputctl->has_multiple_scans = TRUE; + + else + + cinfo->inputctl->has_multiple_scans = FALSE; + +} + + + + + +LOCAL void + +per_scan_setup (j_decompress_ptr cinfo) + +/* Do computations that are needed before processing a JPEG scan */ + +/* cinfo->comps_in_scan and cinfo->cur_comp_info[] were set from SOS marker */ + +{ + + int ci, mcublks, tmp; + + jpeg_component_info *compptr; + + + + if (cinfo->comps_in_scan == 1) { + + + + /* Noninterleaved (single-component) scan */ + + compptr = cinfo->cur_comp_info[0]; + + + + /* Overall image size in MCUs */ + + cinfo->MCUs_per_row = compptr->width_in_blocks; + + cinfo->MCU_rows_in_scan = compptr->height_in_blocks; + + + + /* For noninterleaved scan, always one block per MCU */ + + compptr->MCU_width = 1; + + compptr->MCU_height = 1; + + compptr->MCU_blocks = 1; + + compptr->MCU_sample_width = compptr->DCT_scaled_size; + + compptr->last_col_width = 1; + + /* For noninterleaved scans, it is convenient to define last_row_height + + * as the number of block rows present in the last iMCU row. + + */ + + tmp = (int) (compptr->height_in_blocks % compptr->v_samp_factor); + + if (tmp == 0) tmp = compptr->v_samp_factor; + + compptr->last_row_height = tmp; + + + + /* Prepare array describing MCU composition */ + + cinfo->blocks_in_MCU = 1; + + cinfo->MCU_membership[0] = 0; + + + + } else { + + + + /* Interleaved (multi-component) scan */ + + if (cinfo->comps_in_scan <= 0 || cinfo->comps_in_scan > MAX_COMPS_IN_SCAN) + + ERREXIT2(cinfo, JERR_COMPONENT_COUNT, cinfo->comps_in_scan, + + MAX_COMPS_IN_SCAN); + + + + /* Overall image size in MCUs */ + + cinfo->MCUs_per_row = (JDIMENSION) + + jdiv_round_up((long) cinfo->image_width, + + (long) (cinfo->max_h_samp_factor*DCTSIZE)); + + cinfo->MCU_rows_in_scan = (JDIMENSION) + + jdiv_round_up((long) cinfo->image_height, + + (long) (cinfo->max_v_samp_factor*DCTSIZE)); + + + + cinfo->blocks_in_MCU = 0; + + + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + + compptr = cinfo->cur_comp_info[ci]; + + /* Sampling factors give # of blocks of component in each MCU */ + + compptr->MCU_width = compptr->h_samp_factor; + + compptr->MCU_height = compptr->v_samp_factor; + + compptr->MCU_blocks = compptr->MCU_width * compptr->MCU_height; + + compptr->MCU_sample_width = compptr->MCU_width * compptr->DCT_scaled_size; + + /* Figure number of non-dummy blocks in last MCU column & row */ + + tmp = (int) (compptr->width_in_blocks % compptr->MCU_width); + + if (tmp == 0) tmp = compptr->MCU_width; + + compptr->last_col_width = tmp; + + tmp = (int) (compptr->height_in_blocks % compptr->MCU_height); + + if (tmp == 0) tmp = compptr->MCU_height; + + compptr->last_row_height = tmp; + + /* Prepare array describing MCU composition */ + + mcublks = compptr->MCU_blocks; + + if (cinfo->blocks_in_MCU + mcublks > D_MAX_BLOCKS_IN_MCU) + + ERREXIT(cinfo, JERR_BAD_MCU_SIZE); + + while (mcublks-- > 0) { + + cinfo->MCU_membership[cinfo->blocks_in_MCU++] = ci; + + } + + } + + + + } + +} + + + + + +/* + + * Save away a copy of the Q-table referenced by each component present + + * in the current scan, unless already saved during a prior scan. + + * + + * In a multiple-scan JPEG file, the encoder could assign different components + + * the same Q-table slot number, but change table definitions between scans + + * so that each component uses a different Q-table. (The IJG encoder is not + + * currently capable of doing this, but other encoders might.) Since we want + + * to be able to dequantize all the components at the end of the file, this + + * means that we have to save away the table actually used for each component. + + * We do this by copying the table at the start of the first scan containing + + * the component. + + * The JPEG spec prohibits the encoder from changing the contents of a Q-table + + * slot between scans of a component using that slot. If the encoder does so + + * anyway, this decoder will simply use the Q-table values that were current + + * at the start of the first scan for the component. + + * + + * The decompressor output side looks only at the saved quant tables, + + * not at the current Q-table slots. + + */ + + + +LOCAL void + +latch_quant_tables (j_decompress_ptr cinfo) + +{ + + int ci, qtblno; + + jpeg_component_info *compptr; + + JQUANT_TBL * qtbl; + + + + for (ci = 0; ci < cinfo->comps_in_scan; ci++) { + + compptr = cinfo->cur_comp_info[ci]; + + /* No work if we already saved Q-table for this component */ + + if (compptr->quant_table != NULL) + + continue; + + /* Make sure specified quantization table is present */ + + qtblno = compptr->quant_tbl_no; + + if (qtblno < 0 || qtblno >= NUM_QUANT_TBLS || + + cinfo->quant_tbl_ptrs[qtblno] == NULL) + + ERREXIT1(cinfo, JERR_NO_QUANT_TABLE, qtblno); + + /* OK, save away the quantization table */ + + qtbl = (JQUANT_TBL *) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + SIZEOF(JQUANT_TBL)); + + MEMCOPY(qtbl, cinfo->quant_tbl_ptrs[qtblno], SIZEOF(JQUANT_TBL)); + + compptr->quant_table = qtbl; + + } + +} + + + + + +/* + + * Initialize the input modules to read a scan of compressed data. + + * The first call to this is done by jdmaster.c after initializing + + * the entire decompressor (during jpeg_start_decompress). + + * Subsequent calls come from consume_markers, below. + + */ + + + +METHODDEF void + +start_input_pass (j_decompress_ptr cinfo) + +{ + + per_scan_setup(cinfo); + + latch_quant_tables(cinfo); + + (*cinfo->entropy->start_pass) (cinfo); + + (*cinfo->coef->start_input_pass) (cinfo); + + cinfo->inputctl->consume_input = cinfo->coef->consume_data; + +} + + + + + +/* + + * Finish up after inputting a compressed-data scan. + + * This is called by the coefficient controller after it's read all + + * the expected data of the scan. + + */ + + + +METHODDEF void + +finish_input_pass (j_decompress_ptr cinfo) + +{ + + cinfo->inputctl->consume_input = consume_markers; + +} + + + + + +/* + + * Read JPEG markers before, between, or after compressed-data scans. + + * Change state as necessary when a new scan is reached. + + * Return value is JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + + * + + * The consume_input method pointer points either here or to the + + * coefficient controller's consume_data routine, depending on whether + + * we are reading a compressed data segment or inter-segment markers. + + */ + + + +METHODDEF int + +consume_markers (j_decompress_ptr cinfo) + +{ + + my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; + + int val; + + + + if (inputctl->pub.eoi_reached) /* After hitting EOI, read no further */ + + return JPEG_REACHED_EOI; + + + + val = (*cinfo->marker->read_markers) (cinfo); + + + + switch (val) { + + case JPEG_REACHED_SOS: /* Found SOS */ + + if (inputctl->inheaders) { /* 1st SOS */ + + initial_setup(cinfo); + + inputctl->inheaders = FALSE; + + /* Note: start_input_pass must be called by jdmaster.c + + * before any more input can be consumed. jdapi.c is + + * responsible for enforcing this sequencing. + + */ + + } else { /* 2nd or later SOS marker */ + + if (! inputctl->pub.has_multiple_scans) + + ERREXIT(cinfo, JERR_EOI_EXPECTED); /* Oops, I wasn't expecting this! */ + + start_input_pass(cinfo); + + } + + break; + + case JPEG_REACHED_EOI: /* Found EOI */ + + inputctl->pub.eoi_reached = TRUE; + + if (inputctl->inheaders) { /* Tables-only datastream, apparently */ + + if (cinfo->marker->saw_SOF) + + ERREXIT(cinfo, JERR_SOF_NO_SOS); + + } else { + + /* Prevent infinite loop in coef ctlr's decompress_data routine + + * if user set output_scan_number larger than number of scans. + + */ + + if (cinfo->output_scan_number > cinfo->input_scan_number) + + cinfo->output_scan_number = cinfo->input_scan_number; + + } + + break; + + case JPEG_SUSPENDED: + + break; + + } + + + + return val; + +} + + + + + +/* + + * Reset state to begin a fresh datastream. + + */ + + + +METHODDEF void + +reset_input_controller (j_decompress_ptr cinfo) + +{ + + my_inputctl_ptr inputctl = (my_inputctl_ptr) cinfo->inputctl; + + + + inputctl->pub.consume_input = consume_markers; + + inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ + + inputctl->pub.eoi_reached = FALSE; + + inputctl->inheaders = TRUE; + + /* Reset other modules */ + + (*cinfo->err->reset_error_mgr) ((j_common_ptr) cinfo); + + (*cinfo->marker->reset_marker_reader) (cinfo); + + /* Reset progression state -- would be cleaner if entropy decoder did this */ + + cinfo->coef_bits = NULL; + +} + + + + + +/* + + * Initialize the input controller module. + + * This is called only once, when the decompression object is created. + + */ + + + +GLOBAL void + +jinit_input_controller (j_decompress_ptr cinfo) + +{ + + my_inputctl_ptr inputctl; + + + + /* Create subobject in permanent pool */ + + inputctl = (my_inputctl_ptr) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + + SIZEOF(my_input_controller)); + + cinfo->inputctl = (struct jpeg_input_controller *) inputctl; + + /* Initialize method pointers */ + + inputctl->pub.consume_input = consume_markers; + + inputctl->pub.reset_input_controller = reset_input_controller; + + inputctl->pub.start_input_pass = start_input_pass; + + inputctl->pub.finish_input_pass = finish_input_pass; + + /* Initialize state: can't use reset_input_controller since we don't + + * want to try to reset other modules yet. + + */ + + inputctl->pub.has_multiple_scans = FALSE; /* "unknown" would be better */ + + inputctl->pub.eoi_reached = FALSE; + + inputctl->inheaders = TRUE; + +} + diff --git a/libs/jpeg6/jdmainct.cpp b/libs/jpeg6/jdmainct.cpp new file mode 100644 index 00000000..7b4c2559 --- /dev/null +++ b/libs/jpeg6/jdmainct.cpp @@ -0,0 +1,1024 @@ +/* + + * jdmainct.c + + * + + * Copyright (C) 1994-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains the main buffer controller for decompression. + + * The main buffer lies between the JPEG decompressor proper and the + + * post-processor; it holds downsampled data in the JPEG colorspace. + + * + + * Note that this code is bypassed in raw-data mode, since the application + + * supplies the equivalent of the main buffer in that case. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + + + + + +/* + + * In the current system design, the main buffer need never be a full-image + + * buffer; any full-height buffers will be found inside the coefficient or + + * postprocessing controllers. Nonetheless, the main controller is not + + * trivial. Its responsibility is to provide context rows for upsampling/ + + * rescaling, and doing this in an efficient fashion is a bit tricky. + + * + + * Postprocessor input data is counted in "row groups". A row group + + * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size) + + * sample rows of each component. (We require DCT_scaled_size values to be + + * chosen such that these numbers are integers. In practice DCT_scaled_size + + * values will likely be powers of two, so we actually have the stronger + + * condition that DCT_scaled_size / min_DCT_scaled_size is an integer.) + + * Upsampling will typically produce max_v_samp_factor pixel rows from each + + * row group (times any additional scale factor that the upsampler is + + * applying). + + * + + * The coefficient controller will deliver data to us one iMCU row at a time; + + * each iMCU row contains v_samp_factor * DCT_scaled_size sample rows, or + + * exactly min_DCT_scaled_size row groups. (This amount of data corresponds + + * to one row of MCUs when the image is fully interleaved.) Note that the + + * number of sample rows varies across components, but the number of row + + * groups does not. Some garbage sample rows may be included in the last iMCU + + * row at the bottom of the image. + + * + + * Depending on the vertical scaling algorithm used, the upsampler may need + + * access to the sample row(s) above and below its current input row group. + + * The upsampler is required to set need_context_rows TRUE at global selection + + * time if so. When need_context_rows is FALSE, this controller can simply + + * obtain one iMCU row at a time from the coefficient controller and dole it + + * out as row groups to the postprocessor. + + * + + * When need_context_rows is TRUE, this controller guarantees that the buffer + + * passed to postprocessing contains at least one row group's worth of samples + + * above and below the row group(s) being processed. Note that the context + + * rows "above" the first passed row group appear at negative row offsets in + + * the passed buffer. At the top and bottom of the image, the required + + * context rows are manufactured by duplicating the first or last real sample + + * row; this avoids having special cases in the upsampling inner loops. + + * + + * The amount of context is fixed at one row group just because that's a + + * convenient number for this controller to work with. The existing + + * upsamplers really only need one sample row of context. An upsampler + + * supporting arbitrary output rescaling might wish for more than one row + + * group of context when shrinking the image; tough, we don't handle that. + + * (This is justified by the assumption that downsizing will be handled mostly + + * by adjusting the DCT_scaled_size values, so that the actual scale factor at + + * the upsample step needn't be much less than one.) + + * + + * To provide the desired context, we have to retain the last two row groups + + * of one iMCU row while reading in the next iMCU row. (The last row group + + * can't be processed until we have another row group for its below-context, + + * and so we have to save the next-to-last group too for its above-context.) + + * We could do this most simply by copying data around in our buffer, but + + * that'd be very slow. We can avoid copying any data by creating a rather + + * strange pointer structure. Here's how it works. We allocate a workspace + + * consisting of M+2 row groups (where M = min_DCT_scaled_size is the number + + * of row groups per iMCU row). We create two sets of redundant pointers to + + * the workspace. Labeling the physical row groups 0 to M+1, the synthesized + + * pointer lists look like this: + + * M+1 M-1 + + * master pointer --> 0 master pointer --> 0 + + * 1 1 + + * ... ... + + * M-3 M-3 + + * M-2 M + + * M-1 M+1 + + * M M-2 + + * M+1 M-1 + + * 0 0 + + * We read alternate iMCU rows using each master pointer; thus the last two + + * row groups of the previous iMCU row remain un-overwritten in the workspace. + + * The pointer lists are set up so that the required context rows appear to + + * be adjacent to the proper places when we pass the pointer lists to the + + * upsampler. + + * + + * The above pictures describe the normal state of the pointer lists. + + * At top and bottom of the image, we diddle the pointer lists to duplicate + + * the first or last sample row as necessary (this is cheaper than copying + + * sample rows around). + + * + + * This scheme breaks down if M < 2, ie, min_DCT_scaled_size is 1. In that + + * situation each iMCU row provides only one row group so the buffering logic + + * must be different (eg, we must read two iMCU rows before we can emit the + + * first row group). For now, we simply do not support providing context + + * rows when min_DCT_scaled_size is 1. That combination seems unlikely to + + * be worth providing --- if someone wants a 1/8th-size preview, they probably + + * want it quick and dirty, so a context-free upsampler is sufficient. + + */ + + + + + +/* Private buffer controller object */ + + + +typedef struct { + + struct jpeg_d_main_controller pub; /* public fields */ + + + + /* Pointer to allocated workspace (M or M+2 row groups). */ + + JSAMPARRAY buffer[MAX_COMPONENTS]; + + + + boolean buffer_full; /* Have we gotten an iMCU row from decoder? */ + + JDIMENSION rowgroup_ctr; /* counts row groups output to postprocessor */ + + + + /* Remaining fields are only used in the context case. */ + + + + /* These are the master pointers to the funny-order pointer lists. */ + + JSAMPIMAGE xbuffer[2]; /* pointers to weird pointer lists */ + + + + int whichptr; /* indicates which pointer set is now in use */ + + int context_state; /* process_data state machine status */ + + JDIMENSION rowgroups_avail; /* row groups available to postprocessor */ + + JDIMENSION iMCU_row_ctr; /* counts iMCU rows to detect image top/bot */ + +} my_main_controller; + + + +typedef my_main_controller * my_main_ptr; + + + +/* context_state values: */ + +#define CTX_PREPARE_FOR_IMCU 0 /* need to prepare for MCU row */ + +#define CTX_PROCESS_IMCU 1 /* feeding iMCU to postprocessor */ + +#define CTX_POSTPONED_ROW 2 /* feeding postponed row group */ + + + + + +/* Forward declarations */ + +METHODDEF void process_data_simple_main + + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); + +METHODDEF void process_data_context_main + + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); + +#ifdef QUANT_2PASS_SUPPORTED + +METHODDEF void process_data_crank_post + + JPP((j_decompress_ptr cinfo, JSAMPARRAY output_buf, + + JDIMENSION *out_row_ctr, JDIMENSION out_rows_avail)); + +#endif + + + + + +LOCAL void + +alloc_funny_pointers (j_decompress_ptr cinfo) + +/* Allocate space for the funny pointer lists. + + * This is done only once, not once per pass. + + */ + +{ + + my_main_ptr main = (my_main_ptr) cinfo->main; + + int ci, rgroup; + + int M = cinfo->min_DCT_scaled_size; + + jpeg_component_info *compptr; + + JSAMPARRAY xbuf; + + + + /* Get top-level space for component array pointers. + + * We alloc both arrays with one call to save a few cycles. + + */ + + main->xbuffer[0] = (JSAMPIMAGE) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + cinfo->num_components * 2 * SIZEOF(JSAMPARRAY)); + + main->xbuffer[1] = main->xbuffer[0] + cinfo->num_components; + + + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + + /* Get space for pointer lists --- M+4 row groups in each list. + + * We alloc both pointer lists with one call to save a few cycles. + + */ + + xbuf = (JSAMPARRAY) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + 2 * (rgroup * (M + 4)) * SIZEOF(JSAMPROW)); + + xbuf += rgroup; /* want one row group at negative offsets */ + + main->xbuffer[0][ci] = xbuf; + + xbuf += rgroup * (M + 4); + + main->xbuffer[1][ci] = xbuf; + + } + +} + + + + + +LOCAL void + +make_funny_pointers (j_decompress_ptr cinfo) + +/* Create the funny pointer lists discussed in the comments above. + + * The actual workspace is already allocated (in main->buffer), + + * and the space for the pointer lists is allocated too. + + * This routine just fills in the curiously ordered lists. + + * This will be repeated at the beginning of each pass. + + */ + +{ + + my_main_ptr main = (my_main_ptr) cinfo->main; + + int ci, i, rgroup; + + int M = cinfo->min_DCT_scaled_size; + + jpeg_component_info *compptr; + + JSAMPARRAY buf, xbuf0, xbuf1; + + + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + + xbuf0 = main->xbuffer[0][ci]; + + xbuf1 = main->xbuffer[1][ci]; + + /* First copy the workspace pointers as-is */ + + buf = main->buffer[ci]; + + for (i = 0; i < rgroup * (M + 2); i++) { + + xbuf0[i] = xbuf1[i] = buf[i]; + + } + + /* In the second list, put the last four row groups in swapped order */ + + for (i = 0; i < rgroup * 2; i++) { + + xbuf1[rgroup*(M-2) + i] = buf[rgroup*M + i]; + + xbuf1[rgroup*M + i] = buf[rgroup*(M-2) + i]; + + } + + /* The wraparound pointers at top and bottom will be filled later + + * (see set_wraparound_pointers, below). Initially we want the "above" + + * pointers to duplicate the first actual data line. This only needs + + * to happen in xbuffer[0]. + + */ + + for (i = 0; i < rgroup; i++) { + + xbuf0[i - rgroup] = xbuf0[0]; + + } + + } + +} + + + + + +LOCAL void + +set_wraparound_pointers (j_decompress_ptr cinfo) + +/* Set up the "wraparound" pointers at top and bottom of the pointer lists. + + * This changes the pointer list state from top-of-image to the normal state. + + */ + +{ + + my_main_ptr main = (my_main_ptr) cinfo->main; + + int ci, i, rgroup; + + int M = cinfo->min_DCT_scaled_size; + + jpeg_component_info *compptr; + + JSAMPARRAY xbuf0, xbuf1; + + + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + + xbuf0 = main->xbuffer[0][ci]; + + xbuf1 = main->xbuffer[1][ci]; + + for (i = 0; i < rgroup; i++) { + + xbuf0[i - rgroup] = xbuf0[rgroup*(M+1) + i]; + + xbuf1[i - rgroup] = xbuf1[rgroup*(M+1) + i]; + + xbuf0[rgroup*(M+2) + i] = xbuf0[i]; + + xbuf1[rgroup*(M+2) + i] = xbuf1[i]; + + } + + } + +} + + + + + +LOCAL void + +set_bottom_pointers (j_decompress_ptr cinfo) + +/* Change the pointer lists to duplicate the last sample row at the bottom + + * of the image. whichptr indicates which xbuffer holds the final iMCU row. + + * Also sets rowgroups_avail to indicate number of nondummy row groups in row. + + */ + +{ + + my_main_ptr main = (my_main_ptr) cinfo->main; + + int ci, i, rgroup, iMCUheight, rows_left; + + jpeg_component_info *compptr; + + JSAMPARRAY xbuf; + + + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + /* Count sample rows in one iMCU row and in one row group */ + + iMCUheight = compptr->v_samp_factor * compptr->DCT_scaled_size; + + rgroup = iMCUheight / cinfo->min_DCT_scaled_size; + + /* Count nondummy sample rows remaining for this component */ + + rows_left = (int) (compptr->downsampled_height % (JDIMENSION) iMCUheight); + + if (rows_left == 0) rows_left = iMCUheight; + + /* Count nondummy row groups. Should get same answer for each component, + + * so we need only do it once. + + */ + + if (ci == 0) { + + main->rowgroups_avail = (JDIMENSION) ((rows_left-1) / rgroup + 1); + + } + + /* Duplicate the last real sample row rgroup*2 times; this pads out the + + * last partial rowgroup and ensures at least one full rowgroup of context. + + */ + + xbuf = main->xbuffer[main->whichptr][ci]; + + for (i = 0; i < rgroup * 2; i++) { + + xbuf[rows_left + i] = xbuf[rows_left-1]; + + } + + } + +} + + + + + +/* + + * Initialize for a processing pass. + + */ + + + +METHODDEF void + +start_pass_main (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) + +{ + + my_main_ptr main = (my_main_ptr) cinfo->main; + + + + switch (pass_mode) { + + case JBUF_PASS_THRU: + + if (cinfo->upsample->need_context_rows) { + + main->pub.process_data = process_data_context_main; + + make_funny_pointers(cinfo); /* Create the xbuffer[] lists */ + + main->whichptr = 0; /* Read first iMCU row into xbuffer[0] */ + + main->context_state = CTX_PREPARE_FOR_IMCU; + + main->iMCU_row_ctr = 0; + + } else { + + /* Simple case with no context needed */ + + main->pub.process_data = process_data_simple_main; + + } + + main->buffer_full = FALSE; /* Mark buffer empty */ + + main->rowgroup_ctr = 0; + + break; + +#ifdef QUANT_2PASS_SUPPORTED + + case JBUF_CRANK_DEST: + + /* For last pass of 2-pass quantization, just crank the postprocessor */ + + main->pub.process_data = process_data_crank_post; + + break; + +#endif + + default: + + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + break; + + } + +} + + + + + +/* + + * Process some data. + + * This handles the simple case where no context is required. + + */ + + + +METHODDEF void + +process_data_simple_main (j_decompress_ptr cinfo, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail) + +{ + + my_main_ptr main = (my_main_ptr) cinfo->main; + + JDIMENSION rowgroups_avail; + + + + /* Read input data if we haven't filled the main buffer yet */ + + if (! main->buffer_full) { + + if (! (*cinfo->coef->decompress_data) (cinfo, main->buffer)) + + return; /* suspension forced, can do nothing more */ + + main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ + + } + + + + /* There are always min_DCT_scaled_size row groups in an iMCU row. */ + + rowgroups_avail = (JDIMENSION) cinfo->min_DCT_scaled_size; + + /* Note: at the bottom of the image, we may pass extra garbage row groups + + * to the postprocessor. The postprocessor has to check for bottom + + * of image anyway (at row resolution), so no point in us doing it too. + + */ + + + + /* Feed the postprocessor */ + + (*cinfo->post->post_process_data) (cinfo, main->buffer, + + &main->rowgroup_ctr, rowgroups_avail, + + output_buf, out_row_ctr, out_rows_avail); + + + + /* Has postprocessor consumed all the data yet? If so, mark buffer empty */ + + if (main->rowgroup_ctr >= rowgroups_avail) { + + main->buffer_full = FALSE; + + main->rowgroup_ctr = 0; + + } + +} + + + + + +/* + + * Process some data. + + * This handles the case where context rows must be provided. + + */ + + + +METHODDEF void + +process_data_context_main (j_decompress_ptr cinfo, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail) + +{ + + my_main_ptr main = (my_main_ptr) cinfo->main; + + + + /* Read input data if we haven't filled the main buffer yet */ + + if (! main->buffer_full) { + + if (! (*cinfo->coef->decompress_data) (cinfo, + + main->xbuffer[main->whichptr])) + + return; /* suspension forced, can do nothing more */ + + main->buffer_full = TRUE; /* OK, we have an iMCU row to work with */ + + main->iMCU_row_ctr++; /* count rows received */ + + } + + + + /* Postprocessor typically will not swallow all the input data it is handed + + * in one call (due to filling the output buffer first). Must be prepared + + * to exit and restart. This switch lets us keep track of how far we got. + + * Note that each case falls through to the next on successful completion. + + */ + + switch (main->context_state) { + + case CTX_POSTPONED_ROW: + + /* Call postprocessor using previously set pointers for postponed row */ + + (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr], + + &main->rowgroup_ctr, main->rowgroups_avail, + + output_buf, out_row_ctr, out_rows_avail); + + if (main->rowgroup_ctr < main->rowgroups_avail) + + return; /* Need to suspend */ + + main->context_state = CTX_PREPARE_FOR_IMCU; + + if (*out_row_ctr >= out_rows_avail) + + return; /* Postprocessor exactly filled output buf */ + + /*FALLTHROUGH*/ + + case CTX_PREPARE_FOR_IMCU: + + /* Prepare to process first M-1 row groups of this iMCU row */ + + main->rowgroup_ctr = 0; + + main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size - 1); + + /* Check for bottom of image: if so, tweak pointers to "duplicate" + + * the last sample row, and adjust rowgroups_avail to ignore padding rows. + + */ + + if (main->iMCU_row_ctr == cinfo->total_iMCU_rows) + + set_bottom_pointers(cinfo); + + main->context_state = CTX_PROCESS_IMCU; + + /*FALLTHROUGH*/ + + case CTX_PROCESS_IMCU: + + /* Call postprocessor using previously set pointers */ + + (*cinfo->post->post_process_data) (cinfo, main->xbuffer[main->whichptr], + + &main->rowgroup_ctr, main->rowgroups_avail, + + output_buf, out_row_ctr, out_rows_avail); + + if (main->rowgroup_ctr < main->rowgroups_avail) + + return; /* Need to suspend */ + + /* After the first iMCU, change wraparound pointers to normal state */ + + if (main->iMCU_row_ctr == 1) + + set_wraparound_pointers(cinfo); + + /* Prepare to load new iMCU row using other xbuffer list */ + + main->whichptr ^= 1; /* 0=>1 or 1=>0 */ + + main->buffer_full = FALSE; + + /* Still need to process last row group of this iMCU row, */ + + /* which is saved at index M+1 of the other xbuffer */ + + main->rowgroup_ctr = (JDIMENSION) (cinfo->min_DCT_scaled_size + 1); + + main->rowgroups_avail = (JDIMENSION) (cinfo->min_DCT_scaled_size + 2); + + main->context_state = CTX_POSTPONED_ROW; + + } + +} + + + + + +/* + + * Process some data. + + * Final pass of two-pass quantization: just call the postprocessor. + + * Source data will be the postprocessor controller's internal buffer. + + */ + + + +#ifdef QUANT_2PASS_SUPPORTED + + + +METHODDEF void + +process_data_crank_post (j_decompress_ptr cinfo, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail) + +{ + + (*cinfo->post->post_process_data) (cinfo, (JSAMPIMAGE) NULL, + + (JDIMENSION *) NULL, (JDIMENSION) 0, + + output_buf, out_row_ctr, out_rows_avail); + +} + + + +#endif /* QUANT_2PASS_SUPPORTED */ + + + + + +/* + + * Initialize main buffer controller. + + */ + + + +GLOBAL void + +jinit_d_main_controller (j_decompress_ptr cinfo, boolean need_full_buffer) + +{ + + my_main_ptr main; + + int ci, rgroup, ngroups; + + jpeg_component_info *compptr; + + + + main = (my_main_ptr) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + SIZEOF(my_main_controller)); + + cinfo->main = (struct jpeg_d_main_controller *) main; + + main->pub.start_pass = start_pass_main; + + + + if (need_full_buffer) /* shouldn't happen */ + + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + + + /* Allocate the workspace. + + * ngroups is the number of row groups we need. + + */ + + if (cinfo->upsample->need_context_rows) { + + if (cinfo->min_DCT_scaled_size < 2) /* unsupported, see comments above */ + + ERREXIT(cinfo, JERR_NOTIMPL); + + alloc_funny_pointers(cinfo); /* Alloc space for xbuffer[] lists */ + + ngroups = cinfo->min_DCT_scaled_size + 2; + + } else { + + ngroups = cinfo->min_DCT_scaled_size; + + } + + + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + rgroup = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + + cinfo->min_DCT_scaled_size; /* height of a row group of component */ + + main->buffer[ci] = (*cinfo->mem->alloc_sarray) + + ((j_common_ptr) cinfo, JPOOL_IMAGE, + + compptr->width_in_blocks * compptr->DCT_scaled_size, + + (JDIMENSION) (rgroup * ngroups)); + + } + +} + diff --git a/libs/jpeg6/jdmarker.cpp b/libs/jpeg6/jdmarker.cpp new file mode 100644 index 00000000..15760981 --- /dev/null +++ b/libs/jpeg6/jdmarker.cpp @@ -0,0 +1,1052 @@ +/* + * jdmarker.c + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains routines to decode JPEG datastream markers. + * Most of the complexity arises from our desire to support input + * suspension: if not all of the data for a marker is available, + * we must exit back to the application. On resumption, we reprocess + * the marker. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "radiant_jpeglib.h" + + +typedef enum { /* JPEG marker codes */ + M_SOF0 = 0xc0, + M_SOF1 = 0xc1, + M_SOF2 = 0xc2, + M_SOF3 = 0xc3, + + M_SOF5 = 0xc5, + M_SOF6 = 0xc6, + M_SOF7 = 0xc7, + + M_JPG = 0xc8, + M_SOF9 = 0xc9, + M_SOF10 = 0xca, + M_SOF11 = 0xcb, + + M_SOF13 = 0xcd, + M_SOF14 = 0xce, + M_SOF15 = 0xcf, + + M_DHT = 0xc4, + + M_DAC = 0xcc, + + M_RST0 = 0xd0, + M_RST1 = 0xd1, + M_RST2 = 0xd2, + M_RST3 = 0xd3, + M_RST4 = 0xd4, + M_RST5 = 0xd5, + M_RST6 = 0xd6, + M_RST7 = 0xd7, + + M_SOI = 0xd8, + M_EOI = 0xd9, + M_SOS = 0xda, + M_DQT = 0xdb, + M_DNL = 0xdc, + M_DRI = 0xdd, + M_DHP = 0xde, + M_EXP = 0xdf, + + M_APP0 = 0xe0, + M_APP1 = 0xe1, + M_APP2 = 0xe2, + M_APP3 = 0xe3, + M_APP4 = 0xe4, + M_APP5 = 0xe5, + M_APP6 = 0xe6, + M_APP7 = 0xe7, + M_APP8 = 0xe8, + M_APP9 = 0xe9, + M_APP10 = 0xea, + M_APP11 = 0xeb, + M_APP12 = 0xec, + M_APP13 = 0xed, + M_APP14 = 0xee, + M_APP15 = 0xef, + + M_JPG0 = 0xf0, + M_JPG13 = 0xfd, + M_COM = 0xfe, + + M_TEM = 0x01, + + M_ERROR = 0x100 +} JPEG_MARKER; + + +/* + * Macros for fetching data from the data source module. + * + * At all times, cinfo->src->next_input_byte and ->bytes_in_buffer reflect + * the current restart point; we update them only when we have reached a + * suitable place to restart if a suspension occurs. + */ + +/* Declare and initialize local copies of input pointer/count */ +#define INPUT_VARS(cinfo) \ + struct jpeg_source_mgr * datasrc = (cinfo)->src; \ + const JOCTET * next_input_byte = datasrc->next_input_byte; \ + size_t bytes_in_buffer = datasrc->bytes_in_buffer + +/* Unload the local copies --- do this only at a restart boundary */ +#define INPUT_SYNC(cinfo) \ + ( datasrc->next_input_byte = next_input_byte, \ + datasrc->bytes_in_buffer = bytes_in_buffer ) + +/* Reload the local copies --- seldom used except in MAKE_BYTE_AVAIL */ +#define INPUT_RELOAD(cinfo) \ + ( next_input_byte = datasrc->next_input_byte, \ + bytes_in_buffer = datasrc->bytes_in_buffer ) + +/* Internal macro for INPUT_BYTE and INPUT_2BYTES: make a byte available. + * Note we do *not* do INPUT_SYNC before calling fill_input_buffer, + * but we must reload the local copies after a successful fill. + */ +#define MAKE_BYTE_AVAIL(cinfo,action) \ + if (bytes_in_buffer == 0) { \ + if (! (*datasrc->fill_input_buffer) (cinfo)) \ + { action; } \ + INPUT_RELOAD(cinfo); \ + } \ + bytes_in_buffer-- + +/* Read a byte into variable V. + * If must suspend, take the specified action (typically "return FALSE"). + */ +#define INPUT_BYTE(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + V = GETJOCTET(*next_input_byte++); ) + +/* As above, but read two bytes interpreted as an unsigned 16-bit integer. + * V should be declared unsigned int or perhaps INT32. + */ +#define INPUT_2BYTES(cinfo,V,action) \ + MAKESTMT( MAKE_BYTE_AVAIL(cinfo,action); \ + V = ((unsigned int) GETJOCTET(*next_input_byte++)) << 8; \ + MAKE_BYTE_AVAIL(cinfo,action); \ + V += GETJOCTET(*next_input_byte++); ) + + +/* + * Routines to process JPEG markers. + * + * Entry condition: JPEG marker itself has been read and its code saved + * in cinfo->unread_marker; input restart point is just after the marker. + * + * Exit: if return TRUE, have read and processed any parameters, and have + * updated the restart point to point after the parameters. + * If return FALSE, was forced to suspend before reaching end of + * marker parameters; restart point has not been moved. Same routine + * will be called again after application supplies more input data. + * + * This approach to suspension assumes that all of a marker's parameters can + * fit into a single input bufferload. This should hold for "normal" + * markers. Some COM/APPn markers might have large parameter segments, + * but we use skip_input_data to get past those, and thereby put the problem + * on the source manager's shoulders. + * + * Note that we don't bother to avoid duplicate trace messages if a + * suspension occurs within marker parameters. Other side effects + * require more care. + */ + + +LOCAL boolean +get_soi (j_decompress_ptr cinfo) +/* Process an SOI marker */ +{ + int i; + + TRACEMS(cinfo, 1, JTRC_SOI); + + if (cinfo->marker->saw_SOI) + ERREXIT(cinfo, JERR_SOI_DUPLICATE); + + /* Reset all parameters that are defined to be reset by SOI */ + + for (i = 0; i < NUM_ARITH_TBLS; i++) { + cinfo->arith_dc_L[i] = 0; + cinfo->arith_dc_U[i] = 1; + cinfo->arith_ac_K[i] = 5; + } + cinfo->restart_interval = 0; + + /* Set initial assumptions for colorspace etc */ + + cinfo->jpeg_color_space = JCS_UNKNOWN; + cinfo->CCIR601_sampling = FALSE; /* Assume non-CCIR sampling??? */ + + cinfo->saw_JFIF_marker = FALSE; + cinfo->density_unit = 0; /* set default JFIF APP0 values */ + cinfo->X_density = 1; + cinfo->Y_density = 1; + cinfo->saw_Adobe_marker = FALSE; + cinfo->Adobe_transform = 0; + + cinfo->marker->saw_SOI = TRUE; + + return TRUE; +} + + +LOCAL boolean +get_sof (j_decompress_ptr cinfo, boolean is_prog, boolean is_arith) +/* Process a SOFn marker */ +{ + INT32 length; + int c, ci; + jpeg_component_info * compptr; + INPUT_VARS(cinfo); + + cinfo->progressive_mode = is_prog; + cinfo->arith_code = is_arith; + + INPUT_2BYTES(cinfo, length, return FALSE); + + INPUT_BYTE(cinfo, cinfo->data_precision, return FALSE); + INPUT_2BYTES(cinfo, cinfo->image_height, return FALSE); + INPUT_2BYTES(cinfo, cinfo->image_width, return FALSE); + INPUT_BYTE(cinfo, cinfo->num_components, return FALSE); + + length -= 8; + + TRACEMS4(cinfo, 1, JTRC_SOF, cinfo->unread_marker, + (int) cinfo->image_width, (int) cinfo->image_height, + cinfo->num_components); + + if (cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOF_DUPLICATE); + + /* We don't support files in which the image height is initially specified */ + /* as 0 and is later redefined by DNL. As long as we have to check that, */ + /* might as well have a general sanity check. */ + if (cinfo->image_height <= 0 || cinfo->image_width <= 0 + || cinfo->num_components <= 0) + ERREXIT(cinfo, JERR_EMPTY_IMAGE); + + if (length != (cinfo->num_components * 3)) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + if (cinfo->comp_info == NULL) /* do only once, even if suspend */ + cinfo->comp_info = (jpeg_component_info *) (*cinfo->mem->alloc_small) + ((j_common_ptr) cinfo, JPOOL_IMAGE, + cinfo->num_components * SIZEOF(jpeg_component_info)); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + compptr->component_index = ci; + INPUT_BYTE(cinfo, compptr->component_id, return FALSE); + INPUT_BYTE(cinfo, c, return FALSE); + compptr->h_samp_factor = (c >> 4) & 15; + compptr->v_samp_factor = (c ) & 15; + INPUT_BYTE(cinfo, compptr->quant_tbl_no, return FALSE); + + TRACEMS4(cinfo, 1, JTRC_SOF_COMPONENT, + compptr->component_id, compptr->h_samp_factor, + compptr->v_samp_factor, compptr->quant_tbl_no); + } + + cinfo->marker->saw_SOF = TRUE; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL boolean +get_sos (j_decompress_ptr cinfo) +/* Process a SOS marker */ +{ + INT32 length; + int i, ci, n, c, cc; + jpeg_component_info * compptr; + INPUT_VARS(cinfo); + + if (! cinfo->marker->saw_SOF) + ERREXIT(cinfo, JERR_SOS_NO_SOF); + + INPUT_2BYTES(cinfo, length, return FALSE); + + INPUT_BYTE(cinfo, n, return FALSE); /* Number of components */ + + if (length != (n * 2 + 6) || n < 1 || n > MAX_COMPS_IN_SCAN) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + TRACEMS1(cinfo, 1, JTRC_SOS, n); + + cinfo->comps_in_scan = n; + + /* Collect the component-spec parameters */ + + for (i = 0; i < n; i++) { + INPUT_BYTE(cinfo, cc, return FALSE); + INPUT_BYTE(cinfo, c, return FALSE); + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + if (cc == compptr->component_id) + goto id_found; + } + + ERREXIT1(cinfo, JERR_BAD_COMPONENT_ID, cc); + + id_found: + + cinfo->cur_comp_info[i] = compptr; + compptr->dc_tbl_no = (c >> 4) & 15; + compptr->ac_tbl_no = (c ) & 15; + + TRACEMS3(cinfo, 1, JTRC_SOS_COMPONENT, cc, + compptr->dc_tbl_no, compptr->ac_tbl_no); + } + + /* Collect the additional scan parameters Ss, Se, Ah/Al. */ + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Ss = c; + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Se = c; + INPUT_BYTE(cinfo, c, return FALSE); + cinfo->Ah = (c >> 4) & 15; + cinfo->Al = (c ) & 15; + + TRACEMS4(cinfo, 1, JTRC_SOS_PARAMS, cinfo->Ss, cinfo->Se, + cinfo->Ah, cinfo->Al); + + /* Prepare to scan data & restart markers */ + cinfo->marker->next_restart_num = 0; + + /* Count another SOS marker */ + cinfo->input_scan_number++; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +METHODDEF boolean +get_app0 (j_decompress_ptr cinfo) +/* Process an APP0 marker */ +{ +#define JFIF_LEN 14 + INT32 length; + UINT8 b[JFIF_LEN]; + int buffp; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + /* See if a JFIF APP0 marker is present */ + + if (length >= JFIF_LEN) { + for (buffp = 0; buffp < JFIF_LEN; buffp++) + INPUT_BYTE(cinfo, b[buffp], return FALSE); + length -= JFIF_LEN; + + if (b[0]==0x4A && b[1]==0x46 && b[2]==0x49 && b[3]==0x46 && b[4]==0) { + /* Found JFIF APP0 marker: check version */ + /* Major version must be 1, anything else signals an incompatible change. + * We used to treat this as an error, but now it's a nonfatal warning, + * because some bozo at Hijaak couldn't read the spec. + * Minor version should be 0..2, but process anyway if newer. + */ + if (b[5] != 1) + WARNMS2(cinfo, JWRN_JFIF_MAJOR, b[5], b[6]); + else if (b[6] > 2) + TRACEMS2(cinfo, 1, JTRC_JFIF_MINOR, b[5], b[6]); + /* Save info */ + cinfo->saw_JFIF_marker = TRUE; + cinfo->density_unit = b[7]; + cinfo->X_density = (b[8] << 8) + b[9]; + cinfo->Y_density = (b[10] << 8) + b[11]; + TRACEMS3(cinfo, 1, JTRC_JFIF, + cinfo->X_density, cinfo->Y_density, cinfo->density_unit); + if (b[12] | b[13]) + TRACEMS2(cinfo, 1, JTRC_JFIF_THUMBNAIL, b[12], b[13]); + if (length != ((INT32) b[12] * (INT32) b[13] * (INT32) 3)) + TRACEMS1(cinfo, 1, JTRC_JFIF_BADTHUMBNAILSIZE, (int) length); + } else { + /* Start of APP0 does not match "JFIF" */ + TRACEMS1(cinfo, 1, JTRC_APP0, (int) length + JFIF_LEN); + } + } else { + /* Too short to be JFIF marker */ + TRACEMS1(cinfo, 1, JTRC_APP0, (int) length); + } + + INPUT_SYNC(cinfo); + if (length > 0) /* skip any remaining data -- could be lots */ + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + + +METHODDEF boolean +get_app14 (j_decompress_ptr cinfo) +/* Process an APP14 marker */ +{ +#define ADOBE_LEN 12 + INT32 length; + UINT8 b[ADOBE_LEN]; + int buffp; + unsigned int version, flags0, flags1, transform; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + /* See if an Adobe APP14 marker is present */ + + if (length >= ADOBE_LEN) { + for (buffp = 0; buffp < ADOBE_LEN; buffp++) + INPUT_BYTE(cinfo, b[buffp], return FALSE); + length -= ADOBE_LEN; + + if (b[0]==0x41 && b[1]==0x64 && b[2]==0x6F && b[3]==0x62 && b[4]==0x65) { + /* Found Adobe APP14 marker */ + version = (b[5] << 8) + b[6]; + flags0 = (b[7] << 8) + b[8]; + flags1 = (b[9] << 8) + b[10]; + transform = b[11]; + TRACEMS4(cinfo, 1, JTRC_ADOBE, version, flags0, flags1, transform); + cinfo->saw_Adobe_marker = TRUE; + cinfo->Adobe_transform = (UINT8) transform; + } else { + /* Start of APP14 does not match "Adobe" */ + TRACEMS1(cinfo, 1, JTRC_APP14, (int) length + ADOBE_LEN); + } + } else { + /* Too short to be Adobe marker */ + TRACEMS1(cinfo, 1, JTRC_APP14, (int) length); + } + + INPUT_SYNC(cinfo); + if (length > 0) /* skip any remaining data -- could be lots */ + (*cinfo->src->skip_input_data) (cinfo, (long) length); + + return TRUE; +} + + +LOCAL boolean +get_dac (j_decompress_ptr cinfo) +/* Process a DAC marker */ +{ + INT32 length; + int index, val; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + INPUT_BYTE(cinfo, index, return FALSE); + INPUT_BYTE(cinfo, val, return FALSE); + + length -= 2; + + TRACEMS2(cinfo, 1, JTRC_DAC, index, val); + + if (index < 0 || index >= (2*NUM_ARITH_TBLS)) + ERREXIT1(cinfo, JERR_DAC_INDEX, index); + + if (index >= NUM_ARITH_TBLS) { /* define AC table */ + cinfo->arith_ac_K[index-NUM_ARITH_TBLS] = (UINT8) val; + } else { /* define DC table */ + cinfo->arith_dc_L[index] = (UINT8) (val & 0x0F); + cinfo->arith_dc_U[index] = (UINT8) (val >> 4); + if (cinfo->arith_dc_L[index] > cinfo->arith_dc_U[index]) + ERREXIT1(cinfo, JERR_DAC_VALUE, val); + } + } + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL boolean +get_dht (j_decompress_ptr cinfo) +/* Process a DHT marker */ +{ + INT32 length; + UINT8 bits[17]; + UINT8 huffval[256]; + int i, index, count; + JHUFF_TBL **htblptr; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + INPUT_BYTE(cinfo, index, return FALSE); + + TRACEMS1(cinfo, 1, JTRC_DHT, index); + + bits[0] = 0; + count = 0; + for (i = 1; i <= 16; i++) { + INPUT_BYTE(cinfo, bits[i], return FALSE); + count += bits[i]; + } + + length -= 1 + 16; + + TRACEMS8(cinfo, 2, JTRC_HUFFBITS, + bits[1], bits[2], bits[3], bits[4], + bits[5], bits[6], bits[7], bits[8]); + TRACEMS8(cinfo, 2, JTRC_HUFFBITS, + bits[9], bits[10], bits[11], bits[12], + bits[13], bits[14], bits[15], bits[16]); + + if (count > 256 || ((INT32) count) > length) + ERREXIT(cinfo, JERR_DHT_COUNTS); + + for (i = 0; i < count; i++) + INPUT_BYTE(cinfo, huffval[i], return FALSE); + + length -= count; + + if (index & 0x10) { /* AC table definition */ + index -= 0x10; + htblptr = &cinfo->ac_huff_tbl_ptrs[index]; + } else { /* DC table definition */ + htblptr = &cinfo->dc_huff_tbl_ptrs[index]; + } + + if (index < 0 || index >= NUM_HUFF_TBLS) + ERREXIT1(cinfo, JERR_DHT_INDEX, index); + + if (*htblptr == NULL) + *htblptr = jpeg_alloc_huff_table((j_common_ptr) cinfo); + + MEMCOPY((*htblptr)->bits, bits, SIZEOF((*htblptr)->bits)); + MEMCOPY((*htblptr)->huffval, huffval, SIZEOF((*htblptr)->huffval)); + } + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL boolean +get_dqt (j_decompress_ptr cinfo) +/* Process a DQT marker */ +{ + INT32 length; + int n, i, prec; + unsigned int tmp; + JQUANT_TBL *quant_ptr; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + length -= 2; + + while (length > 0) { + INPUT_BYTE(cinfo, n, return FALSE); + prec = n >> 4; + n &= 0x0F; + + TRACEMS2(cinfo, 1, JTRC_DQT, n, prec); + + if (n >= NUM_QUANT_TBLS) + ERREXIT1(cinfo, JERR_DQT_INDEX, n); + + if (cinfo->quant_tbl_ptrs[n] == NULL) + cinfo->quant_tbl_ptrs[n] = jpeg_alloc_quant_table((j_common_ptr) cinfo); + quant_ptr = cinfo->quant_tbl_ptrs[n]; + + for (i = 0; i < DCTSIZE2; i++) { + if (prec) + INPUT_2BYTES(cinfo, tmp, return FALSE); + else + INPUT_BYTE(cinfo, tmp, return FALSE); + quant_ptr->quantval[i] = (UINT16) tmp; + } + + for (i = 0; i < DCTSIZE2; i += 8) { + TRACEMS8(cinfo, 2, JTRC_QUANTVALS, + quant_ptr->quantval[i ], quant_ptr->quantval[i+1], + quant_ptr->quantval[i+2], quant_ptr->quantval[i+3], + quant_ptr->quantval[i+4], quant_ptr->quantval[i+5], + quant_ptr->quantval[i+6], quant_ptr->quantval[i+7]); + } + + length -= DCTSIZE2+1; + if (prec) length -= DCTSIZE2; + } + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL boolean +get_dri (j_decompress_ptr cinfo) +/* Process a DRI marker */ +{ + INT32 length; + unsigned int tmp; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + + if (length != 4) + ERREXIT(cinfo, JERR_BAD_LENGTH); + + INPUT_2BYTES(cinfo, tmp, return FALSE); + + TRACEMS1(cinfo, 1, JTRC_DRI, tmp); + + cinfo->restart_interval = tmp; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +METHODDEF boolean +skip_variable (j_decompress_ptr cinfo) +/* Skip over an unknown or uninteresting variable-length marker */ +{ + INT32 length; + INPUT_VARS(cinfo); + + INPUT_2BYTES(cinfo, length, return FALSE); + + TRACEMS2(cinfo, 1, JTRC_MISC_MARKER, cinfo->unread_marker, (int) length); + + INPUT_SYNC(cinfo); /* do before skip_input_data */ + (*cinfo->src->skip_input_data) (cinfo, (long) length - 2L); + + return TRUE; +} + + +/* + * Find the next JPEG marker, save it in cinfo->unread_marker. + * Returns FALSE if had to suspend before reaching a marker; + * in that case cinfo->unread_marker is unchanged. + * + * Note that the result might not be a valid marker code, + * but it will never be 0 or FF. + */ + +LOCAL boolean +next_marker (j_decompress_ptr cinfo) +{ + int c; + INPUT_VARS(cinfo); + + for (;;) { + INPUT_BYTE(cinfo, c, return FALSE); + /* Skip any non-FF bytes. + * This may look a bit inefficient, but it will not occur in a valid file. + * We sync after each discarded byte so that a suspending data source + * can discard the byte from its buffer. + */ + while (c != 0xFF) { + cinfo->marker->discarded_bytes++; + INPUT_SYNC(cinfo); + INPUT_BYTE(cinfo, c, return FALSE); + } + /* This loop swallows any duplicate FF bytes. Extra FFs are legal as + * pad bytes, so don't count them in discarded_bytes. We assume there + * will not be so many consecutive FF bytes as to overflow a suspending + * data source's input buffer. + */ + do { + INPUT_BYTE(cinfo, c, return FALSE); + } while (c == 0xFF); + if (c != 0) + break; /* found a valid marker, exit loop */ + /* Reach here if we found a stuffed-zero data sequence (FF/00). + * Discard it and loop back to try again. + */ + cinfo->marker->discarded_bytes += 2; + INPUT_SYNC(cinfo); + } + + if (cinfo->marker->discarded_bytes != 0) { + WARNMS2(cinfo, JWRN_EXTRANEOUS_DATA, cinfo->marker->discarded_bytes, c); + cinfo->marker->discarded_bytes = 0; + } + + cinfo->unread_marker = c; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +LOCAL boolean +first_marker (j_decompress_ptr cinfo) +/* Like next_marker, but used to obtain the initial SOI marker. */ +/* For this marker, we do not allow preceding garbage or fill; otherwise, + * we might well scan an entire input file before realizing it ain't JPEG. + * If an application wants to process non-JFIF files, it must seek to the + * SOI before calling the JPEG library. + */ +{ + int c, c2; + INPUT_VARS(cinfo); + + INPUT_BYTE(cinfo, c, return FALSE); + INPUT_BYTE(cinfo, c2, return FALSE); + if (c != 0xFF || c2 != (int) M_SOI) + ERREXIT2(cinfo, JERR_NO_SOI, c, c2); + + cinfo->unread_marker = c2; + + INPUT_SYNC(cinfo); + return TRUE; +} + + +/* + * Read markers until SOS or EOI. + * + * Returns same codes as are defined for jpeg_consume_input: + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + */ + +METHODDEF int +read_markers (j_decompress_ptr cinfo) +{ + /* Outer loop repeats once for each marker. */ + for (;;) { + /* Collect the marker proper, unless we already did. */ + /* NB: first_marker() enforces the requirement that SOI appear first. */ + if (cinfo->unread_marker == 0) { + if (! cinfo->marker->saw_SOI) { + if (! first_marker(cinfo)) + return JPEG_SUSPENDED; + } else { + if (! next_marker(cinfo)) + return JPEG_SUSPENDED; + } + } + /* At this point cinfo->unread_marker contains the marker code and the + * input point is just past the marker proper, but before any parameters. + * A suspension will cause us to return with this state still true. + */ + switch (cinfo->unread_marker) { + case M_SOI: + if (! get_soi(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_SOF0: /* Baseline */ + case M_SOF1: /* Extended sequential, Huffman */ + if (! get_sof(cinfo, FALSE, FALSE)) + return JPEG_SUSPENDED; + break; + + case M_SOF2: /* Progressive, Huffman */ + if (! get_sof(cinfo, TRUE, FALSE)) + return JPEG_SUSPENDED; + break; + + case M_SOF9: /* Extended sequential, arithmetic */ + if (! get_sof(cinfo, FALSE, TRUE)) + return JPEG_SUSPENDED; + break; + + case M_SOF10: /* Progressive, arithmetic */ + if (! get_sof(cinfo, TRUE, TRUE)) + return JPEG_SUSPENDED; + break; + + /* Currently unsupported SOFn types */ + case M_SOF3: /* Lossless, Huffman */ + case M_SOF5: /* Differential sequential, Huffman */ + case M_SOF6: /* Differential progressive, Huffman */ + case M_SOF7: /* Differential lossless, Huffman */ + case M_JPG: /* Reserved for JPEG extensions */ + case M_SOF11: /* Lossless, arithmetic */ + case M_SOF13: /* Differential sequential, arithmetic */ + case M_SOF14: /* Differential progressive, arithmetic */ + case M_SOF15: /* Differential lossless, arithmetic */ + ERREXIT1(cinfo, JERR_SOF_UNSUPPORTED, cinfo->unread_marker); + break; + + case M_SOS: + if (! get_sos(cinfo)) + return JPEG_SUSPENDED; + cinfo->unread_marker = 0; /* processed the marker */ + return JPEG_REACHED_SOS; + + case M_EOI: + TRACEMS(cinfo, 1, JTRC_EOI); + cinfo->unread_marker = 0; /* processed the marker */ + return JPEG_REACHED_EOI; + + case M_DAC: + if (! get_dac(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DHT: + if (! get_dht(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DQT: + if (! get_dqt(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_DRI: + if (! get_dri(cinfo)) + return JPEG_SUSPENDED; + break; + + case M_APP0: + case M_APP1: + case M_APP2: + case M_APP3: + case M_APP4: + case M_APP5: + case M_APP6: + case M_APP7: + case M_APP8: + case M_APP9: + case M_APP10: + case M_APP11: + case M_APP12: + case M_APP13: + case M_APP14: + case M_APP15: + if (! (*cinfo->marker->process_APPn[cinfo->unread_marker - (int) M_APP0]) (cinfo)) + return JPEG_SUSPENDED; + break; + + case M_COM: + if (! (*cinfo->marker->process_COM) (cinfo)) + return JPEG_SUSPENDED; + break; + + case M_RST0: /* these are all parameterless */ + case M_RST1: + case M_RST2: + case M_RST3: + case M_RST4: + case M_RST5: + case M_RST6: + case M_RST7: + case M_TEM: + TRACEMS1(cinfo, 1, JTRC_PARMLESS_MARKER, cinfo->unread_marker); + break; + + case M_DNL: /* Ignore DNL ... perhaps the wrong thing */ + if (! skip_variable(cinfo)) + return JPEG_SUSPENDED; + break; + + default: /* must be DHP, EXP, JPGn, or RESn */ + /* For now, we treat the reserved markers as fatal errors since they are + * likely to be used to signal incompatible JPEG Part 3 extensions. + * Once the JPEG 3 version-number marker is well defined, this code + * ought to change! + */ + ERREXIT1(cinfo, JERR_UNKNOWN_MARKER, cinfo->unread_marker); + break; + } + /* Successfully processed marker, so reset state variable */ + cinfo->unread_marker = 0; + } /* end loop */ +} + + +/* + * Read a restart marker, which is expected to appear next in the datastream; + * if the marker is not there, take appropriate recovery action. + * Returns FALSE if suspension is required. + * + * This is called by the entropy decoder after it has read an appropriate + * number of MCUs. cinfo->unread_marker may be nonzero if the entropy decoder + * has already read a marker from the data source. Under normal conditions + * cinfo->unread_marker will be reset to 0 before returning; if not reset, + * it holds a marker which the decoder will be unable to read past. + */ + +METHODDEF boolean +read_restart_marker (j_decompress_ptr cinfo) +{ + /* Obtain a marker unless we already did. */ + /* Note that next_marker will complain if it skips any data. */ + if (cinfo->unread_marker == 0) { + if (! next_marker(cinfo)) + return FALSE; + } + + if (cinfo->unread_marker == + ((int) M_RST0 + cinfo->marker->next_restart_num)) { + /* Normal case --- swallow the marker and let entropy decoder continue */ + TRACEMS1(cinfo, 2, JTRC_RST, cinfo->marker->next_restart_num); + cinfo->unread_marker = 0; + } else { + /* Uh-oh, the restart markers have been messed up. */ + /* Let the data source manager determine how to resync. */ + if (! (*cinfo->src->resync_to_restart) (cinfo, + cinfo->marker->next_restart_num)) + return FALSE; + } + + /* Update next-restart state */ + cinfo->marker->next_restart_num = (cinfo->marker->next_restart_num + 1) & 7; + + return TRUE; +} + + +/* + * This is the default resync_to_restart method for data source managers + * to use if they don't have any better approach. Some data source managers + * may be able to back up, or may have additional knowledge about the data + * which permits a more intelligent recovery strategy; such managers would + * presumably supply their own resync method. + * + * read_restart_marker calls resync_to_restart if it finds a marker other than + * the restart marker it was expecting. (This code is *not* used unless + * a nonzero restart interval has been declared.) cinfo->unread_marker is + * the marker code actually found (might be anything, except 0 or FF). + * The desired restart marker number (0..7) is passed as a parameter. + * This routine is supposed to apply whatever error recovery strategy seems + * appropriate in order to position the input stream to the next data segment. + * Note that cinfo->unread_marker is treated as a marker appearing before + * the current data-source input point; usually it should be reset to zero + * before returning. + * Returns FALSE if suspension is required. + * + * This implementation is substantially constrained by wanting to treat the + * input as a data stream; this means we can't back up. Therefore, we have + * only the following actions to work with: + * 1. Simply discard the marker and let the entropy decoder resume at next + * byte of file. + * 2. Read forward until we find another marker, discarding intervening + * data. (In theory we could look ahead within the current bufferload, + * without having to discard data if we don't find the desired marker. + * This idea is not implemented here, in part because it makes behavior + * dependent on buffer size and chance buffer-boundary positions.) + * 3. Leave the marker unread (by failing to zero cinfo->unread_marker). + * This will cause the entropy decoder to process an empty data segment, + * inserting dummy zeroes, and then we will reprocess the marker. + * + * #2 is appropriate if we think the desired marker lies ahead, while #3 is + * appropriate if the found marker is a future restart marker (indicating + * that we have missed the desired restart marker, probably because it got + * corrupted). + * We apply #2 or #3 if the found marker is a restart marker no more than + * two counts behind or ahead of the expected one. We also apply #2 if the + * found marker is not a legal JPEG marker code (it's certainly bogus data). + * If the found marker is a restart marker more than 2 counts away, we do #1 + * (too much risk that the marker is erroneous; with luck we will be able to + * resync at some future point). + * For any valid non-restart JPEG marker, we apply #3. This keeps us from + * overrunning the end of a scan. An implementation limited to single-scan + * files might find it better to apply #2 for markers other than EOI, since + * any other marker would have to be bogus data in that case. + */ + +GLOBAL boolean +jpeg_resync_to_restart (j_decompress_ptr cinfo, int desired) +{ + int marker = cinfo->unread_marker; + int action = 1; + + /* Always put up a warning. */ + WARNMS2(cinfo, JWRN_MUST_RESYNC, marker, desired); + + /* Outer loop handles repeated decision after scanning forward. */ + for (;;) { + if (marker < (int) M_SOF0) + action = 2; /* invalid marker */ + else if (marker < (int) M_RST0 || marker > (int) M_RST7) + action = 3; /* valid non-restart marker */ + else { + if (marker == ((int) M_RST0 + ((desired+1) & 7)) || + marker == ((int) M_RST0 + ((desired+2) & 7))) + action = 3; /* one of the next two expected restarts */ + else if (marker == ((int) M_RST0 + ((desired-1) & 7)) || + marker == ((int) M_RST0 + ((desired-2) & 7))) + action = 2; /* a prior restart, so advance */ + else + action = 1; /* desired restart or too far away */ + } + TRACEMS2(cinfo, 4, JTRC_RECOVERY_ACTION, marker, action); + switch (action) { + case 1: + /* Discard marker and let entropy decoder resume processing. */ + cinfo->unread_marker = 0; + return TRUE; + case 2: + /* Scan to the next marker, and repeat the decision loop. */ + if (! next_marker(cinfo)) + return FALSE; + marker = cinfo->unread_marker; + break; + case 3: + /* Return without advancing past this marker. */ + /* Entropy decoder will be forced to process an empty segment. */ + return TRUE; + } + } /* end loop */ +} + + +/* + * Reset marker processing state to begin a fresh datastream. + */ + +METHODDEF void +reset_marker_reader (j_decompress_ptr cinfo) +{ + cinfo->comp_info = NULL; /* until allocated by get_sof */ + cinfo->input_scan_number = 0; /* no SOS seen yet */ + cinfo->unread_marker = 0; /* no pending marker */ + cinfo->marker->saw_SOI = FALSE; /* set internal state too */ + cinfo->marker->saw_SOF = FALSE; + cinfo->marker->discarded_bytes = 0; +} + + +/* + * Initialize the marker reader module. + * This is called only once, when the decompression object is created. + */ + +GLOBAL void +jinit_marker_reader (j_decompress_ptr cinfo) +{ + int i; + + /* Create subobject in permanent pool */ + cinfo->marker = (struct jpeg_marker_reader *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_PERMANENT, + SIZEOF(struct jpeg_marker_reader)); + /* Initialize method pointers */ + cinfo->marker->reset_marker_reader = reset_marker_reader; + cinfo->marker->read_markers = read_markers; + cinfo->marker->read_restart_marker = read_restart_marker; + cinfo->marker->process_COM = skip_variable; + for (i = 0; i < 16; i++) + cinfo->marker->process_APPn[i] = skip_variable; + cinfo->marker->process_APPn[0] = get_app0; + cinfo->marker->process_APPn[14] = get_app14; + /* Reset marker processing state */ + reset_marker_reader(cinfo); +} diff --git a/libs/jpeg6/jdmaster.cpp b/libs/jpeg6/jdmaster.cpp new file mode 100644 index 00000000..9d88bb2f --- /dev/null +++ b/libs/jpeg6/jdmaster.cpp @@ -0,0 +1,558 @@ +/* + * jdmaster.c + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains master control logic for the JPEG decompressor. + * These routines are concerned with selecting the modules to be executed + * and with determining the number of passes and the work to be done in each + * pass. + */ + +#define JPEG_INTERNALS +#include "jinclude.h" +#include "radiant_jpeglib.h" + + +/* Private state */ + +typedef struct { + struct jpeg_decomp_master pub; /* public fields */ + + int pass_number; /* # of passes completed */ + + boolean using_merged_upsample; /* TRUE if using merged upsample/cconvert */ + + /* Saved references to initialized quantizer modules, + * in case we need to switch modes. + */ + struct jpeg_color_quantizer * quantizer_1pass; + struct jpeg_color_quantizer * quantizer_2pass; +} my_decomp_master; + +typedef my_decomp_master * my_master_ptr; + + +/* + * Determine whether merged upsample/color conversion should be used. + * CRUCIAL: this must match the actual capabilities of jdmerge.c! + */ + +LOCAL boolean +use_merged_upsample (j_decompress_ptr cinfo) +{ +#ifdef UPSAMPLE_MERGING_SUPPORTED + /* Merging is the equivalent of plain box-filter upsampling */ + if (cinfo->do_fancy_upsampling || cinfo->CCIR601_sampling) + return FALSE; + /* jdmerge.c only supports YCC=>RGB color conversion */ + if (cinfo->jpeg_color_space != JCS_YCbCr || cinfo->num_components != 3 || + cinfo->out_color_space != JCS_RGB || + cinfo->out_color_components != RGB_PIXELSIZE) + return FALSE; + /* and it only handles 2h1v or 2h2v sampling ratios */ + if (cinfo->comp_info[0].h_samp_factor != 2 || + cinfo->comp_info[1].h_samp_factor != 1 || + cinfo->comp_info[2].h_samp_factor != 1 || + cinfo->comp_info[0].v_samp_factor > 2 || + cinfo->comp_info[1].v_samp_factor != 1 || + cinfo->comp_info[2].v_samp_factor != 1) + return FALSE; + /* furthermore, it doesn't work if we've scaled the IDCTs differently */ + if (cinfo->comp_info[0].DCT_scaled_size != cinfo->min_DCT_scaled_size || + cinfo->comp_info[1].DCT_scaled_size != cinfo->min_DCT_scaled_size || + cinfo->comp_info[2].DCT_scaled_size != cinfo->min_DCT_scaled_size) + return FALSE; + /* ??? also need to test for upsample-time rescaling, when & if supported */ + return TRUE; /* by golly, it'll work... */ +#else + return FALSE; +#endif +} + + +/* + * Compute output image dimensions and related values. + * NOTE: this is exported for possible use by application. + * Hence it mustn't do anything that can't be done twice. + * Also note that it may be called before the master module is initialized! + */ + +GLOBAL void +jpeg_calc_output_dimensions (j_decompress_ptr cinfo) +/* Do computations that are needed before master selection phase */ +{ +#if 0 // JDC: commented out to remove warning + int ci; + jpeg_component_info *compptr; +#endif + + /* Prevent application from calling me at wrong times */ + if (cinfo->global_state != DSTATE_READY) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + +#ifdef IDCT_SCALING_SUPPORTED + + /* Compute actual output image dimensions and DCT scaling choices. */ + if (cinfo->scale_num * 8 <= cinfo->scale_denom) { + /* Provide 1/8 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 8L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 8L); + cinfo->min_DCT_scaled_size = 1; + } else if (cinfo->scale_num * 4 <= cinfo->scale_denom) { + /* Provide 1/4 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 4L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 4L); + cinfo->min_DCT_scaled_size = 2; + } else if (cinfo->scale_num * 2 <= cinfo->scale_denom) { + /* Provide 1/2 scaling */ + cinfo->output_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width, 2L); + cinfo->output_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height, 2L); + cinfo->min_DCT_scaled_size = 4; + } else { + /* Provide 1/1 scaling */ + cinfo->output_width = cinfo->image_width; + cinfo->output_height = cinfo->image_height; + cinfo->min_DCT_scaled_size = DCTSIZE; + } + /* In selecting the actual DCT scaling for each component, we try to + * scale up the chroma components via IDCT scaling rather than upsampling. + * This saves time if the upsampler gets to use 1:1 scaling. + * Note this code assumes that the supported DCT scalings are powers of 2. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + int ssize = cinfo->min_DCT_scaled_size; + while (ssize < DCTSIZE && + (compptr->h_samp_factor * ssize * 2 <= + cinfo->max_h_samp_factor * cinfo->min_DCT_scaled_size) && + (compptr->v_samp_factor * ssize * 2 <= + cinfo->max_v_samp_factor * cinfo->min_DCT_scaled_size)) { + ssize = ssize * 2; + } + compptr->DCT_scaled_size = ssize; + } + + /* Recompute downsampled dimensions of components; + * application needs to know these if using raw downsampled data. + */ + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + ci++, compptr++) { + /* Size in samples, after IDCT scaling */ + compptr->downsampled_width = (JDIMENSION) + jdiv_round_up((long) cinfo->image_width * + (long) (compptr->h_samp_factor * compptr->DCT_scaled_size), + (long) (cinfo->max_h_samp_factor * DCTSIZE)); + compptr->downsampled_height = (JDIMENSION) + jdiv_round_up((long) cinfo->image_height * + (long) (compptr->v_samp_factor * compptr->DCT_scaled_size), + (long) (cinfo->max_v_samp_factor * DCTSIZE)); + } + +#else /* !IDCT_SCALING_SUPPORTED */ + + /* Hardwire it to "no scaling" */ + cinfo->output_width = cinfo->image_width; + cinfo->output_height = cinfo->image_height; + /* jdinput.c has already initialized DCT_scaled_size to DCTSIZE, + * and has computed unscaled downsampled_width and downsampled_height. + */ + +#endif /* IDCT_SCALING_SUPPORTED */ + + /* Report number of components in selected colorspace. */ + /* Probably this should be in the color conversion module... */ + switch (cinfo->out_color_space) { + case JCS_GRAYSCALE: + cinfo->out_color_components = 1; + break; + case JCS_RGB: +#if RGB_PIXELSIZE != 3 + cinfo->out_color_components = RGB_PIXELSIZE; + break; +#endif /* else share code with YCbCr */ + case JCS_YCbCr: + cinfo->out_color_components = 3; + break; + case JCS_CMYK: + case JCS_YCCK: + cinfo->out_color_components = 4; + break; + default: /* else must be same colorspace as in file */ + cinfo->out_color_components = cinfo->num_components; + break; + } + cinfo->output_components = (cinfo->quantize_colors ? 1 : + cinfo->out_color_components); + + /* See if upsampler will want to emit more than one row at a time */ + if (use_merged_upsample(cinfo)) + cinfo->rec_outbuf_height = cinfo->max_v_samp_factor; + else + cinfo->rec_outbuf_height = 1; +} + + +/* + * Several decompression processes need to range-limit values to the range + * 0..MAXJSAMPLE; the input value may fall somewhat outside this range + * due to noise introduced by quantization, roundoff error, etc. These + * processes are inner loops and need to be as fast as possible. On most + * machines, particularly CPUs with pipelines or instruction prefetch, + * a (subscript-check-less) C table lookup + * x = sample_range_limit[x]; + * is faster than explicit tests + * if (x < 0) x = 0; + * else if (x > MAXJSAMPLE) x = MAXJSAMPLE; + * These processes all use a common table prepared by the routine below. + * + * For most steps we can mathematically guarantee that the initial value + * of x is within MAXJSAMPLE+1 of the legal range, so a table running from + * -(MAXJSAMPLE+1) to 2*MAXJSAMPLE+1 is sufficient. But for the initial + * limiting step (just after the IDCT), a wildly out-of-range value is + * possible if the input data is corrupt. To avoid any chance of indexing + * off the end of memory and getting a bad-pointer trap, we perform the + * post-IDCT limiting thus: + * x = range_limit[x & MASK]; + * where MASK is 2 bits wider than legal sample data, ie 10 bits for 8-bit + * samples. Under normal circumstances this is more than enough range and + * a correct output will be generated; with bogus input data the mask will + * cause wraparound, and we will safely generate a bogus-but-in-range output. + * For the post-IDCT step, we want to convert the data from signed to unsigned + * representation by adding CENTERJSAMPLE at the same time that we limit it. + * So the post-IDCT limiting table ends up looking like this: + * CENTERJSAMPLE,CENTERJSAMPLE+1,...,MAXJSAMPLE, + * MAXJSAMPLE (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), + * 0 (repeat 2*(MAXJSAMPLE+1)-CENTERJSAMPLE times), + * 0,1,...,CENTERJSAMPLE-1 + * Negative inputs select values from the upper half of the table after + * masking. + * + * We can save some space by overlapping the start of the post-IDCT table + * with the simpler range limiting table. The post-IDCT table begins at + * sample_range_limit + CENTERJSAMPLE. + * + * Note that the table is allocated in near data space on PCs; it's small + * enough and used often enough to justify this. + */ + +LOCAL void +prepare_range_limit_table (j_decompress_ptr cinfo) +/* Allocate and fill in the sample_range_limit table */ +{ + JSAMPLE * table; + int i; + + table = (JSAMPLE *) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + (5 * (MAXJSAMPLE+1) + CENTERJSAMPLE) * SIZEOF(JSAMPLE)); + table += (MAXJSAMPLE+1); /* allow negative subscripts of simple table */ + cinfo->sample_range_limit = table; + /* First segment of "simple" table: limit[x] = 0 for x < 0 */ + MEMZERO(table - (MAXJSAMPLE+1), (MAXJSAMPLE+1) * SIZEOF(JSAMPLE)); + /* Main part of "simple" table: limit[x] = x */ + for (i = 0; i <= MAXJSAMPLE; i++) + table[i] = (JSAMPLE) i; + table += CENTERJSAMPLE; /* Point to where post-IDCT table starts */ + /* End of simple table, rest of first half of post-IDCT table */ + for (i = CENTERJSAMPLE; i < 2*(MAXJSAMPLE+1); i++) + table[i] = MAXJSAMPLE; + /* Second half of post-IDCT table */ + MEMZERO(table + (2 * (MAXJSAMPLE+1)), + (2 * (MAXJSAMPLE+1) - CENTERJSAMPLE) * SIZEOF(JSAMPLE)); + MEMCOPY(table + (4 * (MAXJSAMPLE+1) - CENTERJSAMPLE), + cinfo->sample_range_limit, CENTERJSAMPLE * SIZEOF(JSAMPLE)); +} + + +/* + * Master selection of decompression modules. + * This is done once at jpeg_start_decompress time. We determine + * which modules will be used and give them appropriate initialization calls. + * We also initialize the decompressor input side to begin consuming data. + * + * Since jpeg_read_header has finished, we know what is in the SOF + * and (first) SOS markers. We also have all the application parameter + * settings. + */ + +LOCAL void +master_selection (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + boolean use_c_buffer; + long samplesperrow; + JDIMENSION jd_samplesperrow; + + /* Initialize dimensions and other stuff */ + jpeg_calc_output_dimensions(cinfo); + prepare_range_limit_table(cinfo); + + /* Width of an output scanline must be representable as JDIMENSION. */ + samplesperrow = (long) cinfo->output_width * (long) cinfo->out_color_components; + jd_samplesperrow = (JDIMENSION) samplesperrow; + if ((long) jd_samplesperrow != samplesperrow) + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + /* Initialize my private state */ + master->pass_number = 0; + master->using_merged_upsample = use_merged_upsample(cinfo); + + /* Color quantizer selection */ + master->quantizer_1pass = NULL; + master->quantizer_2pass = NULL; + /* No mode changes if not using buffered-image mode. */ + if (! cinfo->quantize_colors || ! cinfo->buffered_image) { + cinfo->enable_1pass_quant = FALSE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; + } + if (cinfo->quantize_colors) { + if (cinfo->raw_data_out) + ERREXIT(cinfo, JERR_NOTIMPL); + /* 2-pass quantizer only works in 3-component color space. */ + if (cinfo->out_color_components != 3) { + cinfo->enable_1pass_quant = TRUE; + cinfo->enable_external_quant = FALSE; + cinfo->enable_2pass_quant = FALSE; + cinfo->colormap = NULL; + } else if (cinfo->colormap != NULL) { + cinfo->enable_external_quant = TRUE; + } else if (cinfo->two_pass_quantize) { + cinfo->enable_2pass_quant = TRUE; + } else { + cinfo->enable_1pass_quant = TRUE; + } + + if (cinfo->enable_1pass_quant) { +#ifdef QUANT_1PASS_SUPPORTED + jinit_1pass_quantizer(cinfo); + master->quantizer_1pass = cinfo->cquantize; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + + /* We use the 2-pass code to map to external colormaps. */ + if (cinfo->enable_2pass_quant || cinfo->enable_external_quant) { +#ifdef QUANT_2PASS_SUPPORTED + jinit_2pass_quantizer(cinfo); + master->quantizer_2pass = cinfo->cquantize; +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } + /* If both quantizers are initialized, the 2-pass one is left active; + * this is necessary for starting with quantization to an external map. + */ + } + + /* Post-processing: in particular, color conversion first */ + if (! cinfo->raw_data_out) { + if (master->using_merged_upsample) { +#ifdef UPSAMPLE_MERGING_SUPPORTED + jinit_merged_upsampler(cinfo); /* does color conversion too */ +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif + } else { + jinit_color_deconverter(cinfo); + jinit_upsampler(cinfo); + } + jinit_d_post_controller(cinfo, cinfo->enable_2pass_quant); + } + /* Inverse DCT */ + jinit_inverse_dct(cinfo); + /* Entropy decoding: either Huffman or arithmetic coding. */ + if (cinfo->arith_code) { + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); + } else { + if (cinfo->progressive_mode) { +#ifdef D_PROGRESSIVE_SUPPORTED + jinit_phuff_decoder(cinfo); +#else + ERREXIT(cinfo, JERR_NO_PROGRESSIVE); +#endif + } else + jinit_huff_decoder(cinfo); + } + + /* Initialize principal buffer controllers. */ + use_c_buffer = cinfo->inputctl->has_multiple_scans || cinfo->buffered_image; + jinit_d_coef_controller(cinfo, use_c_buffer); + + if (! cinfo->raw_data_out) + jinit_d_main_controller(cinfo, FALSE /* never need full buffer here */); + + /* We can now tell the memory manager to allocate virtual arrays. */ + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + /* Initialize input side of decompressor to consume first scan. */ + (*cinfo->inputctl->start_input_pass) (cinfo); + +#ifdef D_MULTISCAN_FILES_SUPPORTED + /* If jpeg_start_decompress will read the whole file, initialize + * progress monitoring appropriately. The input step is counted + * as one pass. + */ + if (cinfo->progress != NULL && ! cinfo->buffered_image && + cinfo->inputctl->has_multiple_scans) { + int nscans; + /* Estimate number of scans to set pass_limit. */ + if (cinfo->progressive_mode) { + /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ + nscans = 2 + 3 * cinfo->num_components; + } else { + /* For a nonprogressive multiscan file, estimate 1 scan per component. */ + nscans = cinfo->num_components; + } + cinfo->progress->pass_counter = 0L; + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; + cinfo->progress->completed_passes = 0; + cinfo->progress->total_passes = (cinfo->enable_2pass_quant ? 3 : 2); + /* Count the input pass as done */ + master->pass_number++; + } +#endif /* D_MULTISCAN_FILES_SUPPORTED */ +} + + +/* + * Per-pass setup. + * This is called at the beginning of each output pass. We determine which + * modules will be active during this pass and give them appropriate + * start_pass calls. We also set is_dummy_pass to indicate whether this + * is a "real" output pass or a dummy pass for color quantization. + * (In the latter case, jdapi.c will crank the pass to completion.) + */ + +METHODDEF void +prepare_for_output_pass (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + if (master->pub.is_dummy_pass) { +#ifdef QUANT_2PASS_SUPPORTED + /* Final pass of 2-pass quantization */ + master->pub.is_dummy_pass = FALSE; + (*cinfo->cquantize->start_pass) (cinfo, FALSE); + (*cinfo->post->start_pass) (cinfo, JBUF_CRANK_DEST); + (*cinfo->main->start_pass) (cinfo, JBUF_CRANK_DEST); +#else + ERREXIT(cinfo, JERR_NOT_COMPILED); +#endif /* QUANT_2PASS_SUPPORTED */ + } else { + if (cinfo->quantize_colors && cinfo->colormap == NULL) { + /* Select new quantization method */ + if (cinfo->two_pass_quantize && cinfo->enable_2pass_quant) { + cinfo->cquantize = master->quantizer_2pass; + master->pub.is_dummy_pass = TRUE; + } else if (cinfo->enable_1pass_quant) { + cinfo->cquantize = master->quantizer_1pass; + } else { + ERREXIT(cinfo, JERR_MODE_CHANGE); + } + } + (*cinfo->idct->start_pass) (cinfo); + (*cinfo->coef->start_output_pass) (cinfo); + if (! cinfo->raw_data_out) { + if (! master->using_merged_upsample) + (*cinfo->cconvert->start_pass) (cinfo); + (*cinfo->upsample->start_pass) (cinfo); + if (cinfo->quantize_colors) + (*cinfo->cquantize->start_pass) (cinfo, master->pub.is_dummy_pass); + (*cinfo->post->start_pass) (cinfo, + (master->pub.is_dummy_pass ? JBUF_SAVE_AND_PASS : JBUF_PASS_THRU)); + (*cinfo->main->start_pass) (cinfo, JBUF_PASS_THRU); + } + } + + /* Set up progress monitor's pass info if present */ + if (cinfo->progress != NULL) { + cinfo->progress->completed_passes = master->pass_number; + cinfo->progress->total_passes = master->pass_number + + (master->pub.is_dummy_pass ? 2 : 1); + /* In buffered-image mode, we assume one more output pass if EOI not + * yet reached, but no more passes if EOI has been reached. + */ + if (cinfo->buffered_image && ! cinfo->inputctl->eoi_reached) { + cinfo->progress->total_passes += (cinfo->enable_2pass_quant ? 2 : 1); + } + } +} + + +/* + * Finish up at end of an output pass. + */ + +METHODDEF void +finish_output_pass (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + if (cinfo->quantize_colors) + (*cinfo->cquantize->finish_pass) (cinfo); + master->pass_number++; +} + + +#ifdef D_MULTISCAN_FILES_SUPPORTED + +/* + * Switch to a new external colormap between output passes. + */ + +GLOBAL void +jpeg_new_colormap (j_decompress_ptr cinfo) +{ + my_master_ptr master = (my_master_ptr) cinfo->master; + + /* Prevent application from calling me at wrong times */ + if (cinfo->global_state != DSTATE_BUFIMAGE) + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + if (cinfo->quantize_colors && cinfo->enable_external_quant && + cinfo->colormap != NULL) { + /* Select 2-pass quantizer for external colormap use */ + cinfo->cquantize = master->quantizer_2pass; + /* Notify quantizer of colormap change */ + (*cinfo->cquantize->new_color_map) (cinfo); + master->pub.is_dummy_pass = FALSE; /* just in case */ + } else + ERREXIT(cinfo, JERR_MODE_CHANGE); +} + +#endif /* D_MULTISCAN_FILES_SUPPORTED */ + + +/* + * Initialize master decompression control and select active modules. + * This is performed at the start of jpeg_start_decompress. + */ + +GLOBAL void +jinit_master_decompress (j_decompress_ptr cinfo) +{ + my_master_ptr master; + + master = (my_master_ptr) + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + SIZEOF(my_decomp_master)); + cinfo->master = (struct jpeg_decomp_master *) master; + master->pub.prepare_for_output_pass = prepare_for_output_pass; + master->pub.finish_output_pass = finish_output_pass; + + master->pub.is_dummy_pass = FALSE; + + master_selection(cinfo); +} + diff --git a/libs/jpeg6/jdpostct.cpp b/libs/jpeg6/jdpostct.cpp new file mode 100644 index 00000000..3aba0a38 --- /dev/null +++ b/libs/jpeg6/jdpostct.cpp @@ -0,0 +1,580 @@ +/* + + * jdpostct.c + + * + + * Copyright (C) 1994-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains the decompression postprocessing controller. + + * This controller manages the upsampling, color conversion, and color + + * quantization/reduction steps; specifically, it controls the buffering + + * between upsample/color conversion and color quantization/reduction. + + * + + * If no color quantization/reduction is required, then this module has no + + * work to do, and it just hands off to the upsample/color conversion code. + + * An integrated upsample/convert/quantize process would replace this module + + * entirely. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + + + + + +/* Private buffer controller object */ + + + +typedef struct { + + struct jpeg_d_post_controller pub; /* public fields */ + + + + /* Color quantization source buffer: this holds output data from + + * the upsample/color conversion step to be passed to the quantizer. + + * For two-pass color quantization, we need a full-image buffer; + + * for one-pass operation, a strip buffer is sufficient. + + */ + + jvirt_sarray_ptr whole_image; /* virtual array, or NULL if one-pass */ + + JSAMPARRAY buffer; /* strip buffer, or current strip of virtual */ + + JDIMENSION strip_height; /* buffer size in rows */ + + /* for two-pass mode only: */ + + JDIMENSION starting_row; /* row # of first row in current strip */ + + JDIMENSION next_row; /* index of next row to fill/empty in strip */ + +} my_post_controller; + + + +typedef my_post_controller * my_post_ptr; + + + + + +/* Forward declarations */ + +METHODDEF void post_process_1pass + + JPP((j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + + JDIMENSION in_row_groups_avail, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail)); + +#ifdef QUANT_2PASS_SUPPORTED + +METHODDEF void post_process_prepass + + JPP((j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + + JDIMENSION in_row_groups_avail, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail)); + +METHODDEF void post_process_2pass + + JPP((j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + + JDIMENSION in_row_groups_avail, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail)); + +#endif + + + + + +/* + + * Initialize for a processing pass. + + */ + + + +METHODDEF void + +start_pass_dpost (j_decompress_ptr cinfo, J_BUF_MODE pass_mode) + +{ + + my_post_ptr post = (my_post_ptr) cinfo->post; + + + + switch (pass_mode) { + + case JBUF_PASS_THRU: + + if (cinfo->quantize_colors) { + + /* Single-pass processing with color quantization. */ + + post->pub.post_process_data = post_process_1pass; + + /* We could be doing buffered-image output before starting a 2-pass + + * color quantization; in that case, jinit_d_post_controller did not + + * allocate a strip buffer. Use the virtual-array buffer as workspace. + + */ + + if (post->buffer == NULL) { + + post->buffer = (*cinfo->mem->access_virt_sarray) + + ((j_common_ptr) cinfo, post->whole_image, + + (JDIMENSION) 0, post->strip_height, TRUE); + + } + + } else { + + /* For single-pass processing without color quantization, + + * I have no work to do; just call the upsampler directly. + + */ + + post->pub.post_process_data = cinfo->upsample->upsample; + + } + + break; + +#ifdef QUANT_2PASS_SUPPORTED + + case JBUF_SAVE_AND_PASS: + + /* First pass of 2-pass quantization */ + + if (post->whole_image == NULL) + + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + post->pub.post_process_data = post_process_prepass; + + break; + + case JBUF_CRANK_DEST: + + /* Second pass of 2-pass quantization */ + + if (post->whole_image == NULL) + + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + post->pub.post_process_data = post_process_2pass; + + break; + +#endif /* QUANT_2PASS_SUPPORTED */ + + default: + + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + + break; + + } + + post->starting_row = post->next_row = 0; + +} + + + + + +/* + + * Process some data in the one-pass (strip buffer) case. + + * This is used for color precision reduction as well as one-pass quantization. + + */ + + + +METHODDEF void + +post_process_1pass (j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + + JDIMENSION in_row_groups_avail, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail) + +{ + + my_post_ptr post = (my_post_ptr) cinfo->post; + + JDIMENSION num_rows, max_rows; + + + + /* Fill the buffer, but not more than what we can dump out in one go. */ + + /* Note we rely on the upsampler to detect bottom of image. */ + + max_rows = out_rows_avail - *out_row_ctr; + + if (max_rows > post->strip_height) + + max_rows = post->strip_height; + + num_rows = 0; + + (*cinfo->upsample->upsample) (cinfo, + + input_buf, in_row_group_ctr, in_row_groups_avail, + + post->buffer, &num_rows, max_rows); + + /* Quantize and emit data. */ + + (*cinfo->cquantize->color_quantize) (cinfo, + + post->buffer, output_buf + *out_row_ctr, (int) num_rows); + + *out_row_ctr += num_rows; + +} + + + + + +#ifdef QUANT_2PASS_SUPPORTED + + + +/* + + * Process some data in the first pass of 2-pass quantization. + + */ + + + +METHODDEF void + +post_process_prepass (j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + + JDIMENSION in_row_groups_avail, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail) + +{ + + my_post_ptr post = (my_post_ptr) cinfo->post; + + JDIMENSION old_next_row, num_rows; + + + + /* Reposition virtual buffer if at start of strip. */ + + if (post->next_row == 0) { + + post->buffer = (*cinfo->mem->access_virt_sarray) + + ((j_common_ptr) cinfo, post->whole_image, + + post->starting_row, post->strip_height, TRUE); + + } + + + + /* Upsample some data (up to a strip height's worth). */ + + old_next_row = post->next_row; + + (*cinfo->upsample->upsample) (cinfo, + + input_buf, in_row_group_ctr, in_row_groups_avail, + + post->buffer, &post->next_row, post->strip_height); + + + + /* Allow quantizer to scan new data. No data is emitted, */ + + /* but we advance out_row_ctr so outer loop can tell when we're done. */ + + if (post->next_row > old_next_row) { + + num_rows = post->next_row - old_next_row; + + (*cinfo->cquantize->color_quantize) (cinfo, post->buffer + old_next_row, + + (JSAMPARRAY) NULL, (int) num_rows); + + *out_row_ctr += num_rows; + + } + + + + /* Advance if we filled the strip. */ + + if (post->next_row >= post->strip_height) { + + post->starting_row += post->strip_height; + + post->next_row = 0; + + } + +} + + + + + +/* + + * Process some data in the second pass of 2-pass quantization. + + */ + + + +METHODDEF void + +post_process_2pass (j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + + JDIMENSION in_row_groups_avail, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail) + +{ + + my_post_ptr post = (my_post_ptr) cinfo->post; + + JDIMENSION num_rows, max_rows; + + + + /* Reposition virtual buffer if at start of strip. */ + + if (post->next_row == 0) { + + post->buffer = (*cinfo->mem->access_virt_sarray) + + ((j_common_ptr) cinfo, post->whole_image, + + post->starting_row, post->strip_height, FALSE); + + } + + + + /* Determine number of rows to emit. */ + + num_rows = post->strip_height - post->next_row; /* available in strip */ + + max_rows = out_rows_avail - *out_row_ctr; /* available in output area */ + + if (num_rows > max_rows) + + num_rows = max_rows; + + /* We have to check bottom of image here, can't depend on upsampler. */ + + max_rows = cinfo->output_height - post->starting_row; + + if (num_rows > max_rows) + + num_rows = max_rows; + + + + /* Quantize and emit data. */ + + (*cinfo->cquantize->color_quantize) (cinfo, + + post->buffer + post->next_row, output_buf + *out_row_ctr, + + (int) num_rows); + + *out_row_ctr += num_rows; + + + + /* Advance if we filled the strip. */ + + post->next_row += num_rows; + + if (post->next_row >= post->strip_height) { + + post->starting_row += post->strip_height; + + post->next_row = 0; + + } + +} + + + +#endif /* QUANT_2PASS_SUPPORTED */ + + + + + +/* + + * Initialize postprocessing controller. + + */ + + + +GLOBAL void + +jinit_d_post_controller (j_decompress_ptr cinfo, boolean need_full_buffer) + +{ + + my_post_ptr post; + + + + post = (my_post_ptr) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + SIZEOF(my_post_controller)); + + cinfo->post = (struct jpeg_d_post_controller *) post; + + post->pub.start_pass = start_pass_dpost; + + post->whole_image = NULL; /* flag for no virtual arrays */ + + post->buffer = NULL; /* flag for no strip buffer */ + + + + /* Create the quantization buffer, if needed */ + + if (cinfo->quantize_colors) { + + /* The buffer strip height is max_v_samp_factor, which is typically + + * an efficient number of rows for upsampling to return. + + * (In the presence of output rescaling, we might want to be smarter?) + + */ + + post->strip_height = (JDIMENSION) cinfo->max_v_samp_factor; + + if (need_full_buffer) { + + /* Two-pass color quantization: need full-image storage. */ + + /* We round up the number of rows to a multiple of the strip height. */ + +#ifdef QUANT_2PASS_SUPPORTED + + post->whole_image = (*cinfo->mem->request_virt_sarray) + + ((j_common_ptr) cinfo, JPOOL_IMAGE, FALSE, + + cinfo->output_width * cinfo->out_color_components, + + (JDIMENSION) jround_up((long) cinfo->output_height, + + (long) post->strip_height), + + post->strip_height); + +#else + + ERREXIT(cinfo, JERR_BAD_BUFFER_MODE); + +#endif /* QUANT_2PASS_SUPPORTED */ + + } else { + + /* One-pass color quantization: just make a strip buffer. */ + + post->buffer = (*cinfo->mem->alloc_sarray) + + ((j_common_ptr) cinfo, JPOOL_IMAGE, + + cinfo->output_width * cinfo->out_color_components, + + post->strip_height); + + } + + } + +} + diff --git a/libs/jpeg6/jdsample.cpp b/libs/jpeg6/jdsample.cpp new file mode 100644 index 00000000..a15e252c --- /dev/null +++ b/libs/jpeg6/jdsample.cpp @@ -0,0 +1,956 @@ +/* + + * jdsample.c + + * + + * Copyright (C) 1991-1994, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains upsampling routines. + + * + + * Upsampling input data is counted in "row groups". A row group + + * is defined to be (v_samp_factor * DCT_scaled_size / min_DCT_scaled_size) + + * sample rows of each component. Upsampling will normally produce + + * max_v_samp_factor pixel rows from each row group (but this could vary + + * if the upsampler is applying a scale factor of its own). + + * + + * An excellent reference for image resampling is + + * Digital Image Warping, George Wolberg, 1990. + + * Pub. by IEEE Computer Society Press, Los Alamitos, CA. ISBN 0-8186-8944-7. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + + + + + +/* Pointer to routine to upsample a single component */ + +typedef JMETHOD(void, upsample1_ptr, + + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr)); + + + +/* Private subobject */ + + + +typedef struct { + + struct jpeg_upsampler pub; /* public fields */ + + + + /* Color conversion buffer. When using separate upsampling and color + + * conversion steps, this buffer holds one upsampled row group until it + + * has been color converted and output. + + * Note: we do not allocate any storage for component(s) which are full-size, + + * ie do not need rescaling. The corresponding entry of color_buf[] is + + * simply set to point to the input data array, thereby avoiding copying. + + */ + + JSAMPARRAY color_buf[MAX_COMPONENTS]; + + + + /* Per-component upsampling method pointers */ + + upsample1_ptr methods[MAX_COMPONENTS]; + + + + int next_row_out; /* counts rows emitted from color_buf */ + + JDIMENSION rows_to_go; /* counts rows remaining in image */ + + + + /* Height of an input row group for each component. */ + + int rowgroup_height[MAX_COMPONENTS]; + + + + /* These arrays save pixel expansion factors so that int_expand need not + + * recompute them each time. They are unused for other upsampling methods. + + */ + + UINT8 h_expand[MAX_COMPONENTS]; + + UINT8 v_expand[MAX_COMPONENTS]; + +} my_upsampler; + + + +typedef my_upsampler * my_upsample_ptr; + + + + + +/* + + * Initialize for an upsampling pass. + + */ + + + +METHODDEF void + +start_pass_upsample (j_decompress_ptr cinfo) + +{ + + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + + + /* Mark the conversion buffer empty */ + + upsample->next_row_out = cinfo->max_v_samp_factor; + + /* Initialize total-height counter for detecting bottom of image */ + + upsample->rows_to_go = cinfo->output_height; + +} + + + + + +/* + + * Control routine to do upsampling (and color conversion). + + * + + * In this version we upsample each component independently. + + * We upsample one row group into the conversion buffer, then apply + + * color conversion a row at a time. + + */ + + + +METHODDEF void + +sep_upsample (j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION *in_row_group_ctr, + + JDIMENSION in_row_groups_avail, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail) + +{ + + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + int ci; + + jpeg_component_info * compptr; + + JDIMENSION num_rows; + + + + /* Fill the conversion buffer, if it's empty */ + + if (upsample->next_row_out >= cinfo->max_v_samp_factor) { + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + /* Invoke per-component upsample method. Notice we pass a POINTER + + * to color_buf[ci], so that fullsize_upsample can change it. + + */ + + (*upsample->methods[ci]) (cinfo, compptr, + + input_buf[ci] + (*in_row_group_ctr * upsample->rowgroup_height[ci]), + + upsample->color_buf + ci); + + } + + upsample->next_row_out = 0; + + } + + + + /* Color-convert and emit rows */ + + + + /* How many we have in the buffer: */ + + num_rows = (JDIMENSION) (cinfo->max_v_samp_factor - upsample->next_row_out); + + /* Not more than the distance to the end of the image. Need this test + + * in case the image height is not a multiple of max_v_samp_factor: + + */ + + if (num_rows > upsample->rows_to_go) + + num_rows = upsample->rows_to_go; + + /* And not more than what the client can accept: */ + + out_rows_avail -= *out_row_ctr; + + if (num_rows > out_rows_avail) + + num_rows = out_rows_avail; + + + + (*cinfo->cconvert->color_convert) (cinfo, upsample->color_buf, + + (JDIMENSION) upsample->next_row_out, + + output_buf + *out_row_ctr, + + (int) num_rows); + + + + /* Adjust counts */ + + *out_row_ctr += num_rows; + + upsample->rows_to_go -= num_rows; + + upsample->next_row_out += num_rows; + + /* When the buffer is emptied, declare this input row group consumed */ + + if (upsample->next_row_out >= cinfo->max_v_samp_factor) + + (*in_row_group_ctr)++; + +} + + + + + +/* + + * These are the routines invoked by sep_upsample to upsample pixel values + + * of a single component. One row group is processed per call. + + */ + + + + + +/* + + * For full-size components, we just make color_buf[ci] point at the + + * input buffer, and thus avoid copying any data. Note that this is + + * safe only because sep_upsample doesn't declare the input row group + + * "consumed" until we are done color converting and emitting it. + + */ + + + +METHODDEF void + +fullsize_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + +{ + + *output_data_ptr = input_data; + +} + + + + + +/* + + * This is a no-op version used for "uninteresting" components. + + * These components will not be referenced by color conversion. + + */ + + + +METHODDEF void + +noop_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + +{ + + *output_data_ptr = NULL; /* safety check */ + +} + + + + + +/* + + * This version handles any integral sampling ratios. + + * This is not used for typical JPEG files, so it need not be fast. + + * Nor, for that matter, is it particularly accurate: the algorithm is + + * simple replication of the input pixel onto the corresponding output + + * pixels. The hi-falutin sampling literature refers to this as a + + * "box filter". A box filter tends to introduce visible artifacts, + + * so if you are actually going to use 3:1 or 4:1 sampling ratios + + * you would be well advised to improve this code. + + */ + + + +METHODDEF void + +int_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + +{ + + my_upsample_ptr upsample = (my_upsample_ptr) cinfo->upsample; + + JSAMPARRAY output_data = *output_data_ptr; + + register JSAMPROW inptr, outptr; + + register JSAMPLE invalue; + + register int h; + + JSAMPROW outend; + + int h_expand, v_expand; + + int inrow, outrow; + + + + h_expand = upsample->h_expand[compptr->component_index]; + + v_expand = upsample->v_expand[compptr->component_index]; + + + + inrow = outrow = 0; + + while (outrow < cinfo->max_v_samp_factor) { + + /* Generate one output row with proper horizontal expansion */ + + inptr = input_data[inrow]; + + outptr = output_data[outrow]; + + outend = outptr + cinfo->output_width; + + while (outptr < outend) { + + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + + for (h = h_expand; h > 0; h--) { + + *outptr++ = invalue; + + } + + } + + /* Generate any additional output rows by duplicating the first one */ + + if (v_expand > 1) { + + jcopy_sample_rows(output_data, outrow, output_data, outrow+1, + + v_expand-1, cinfo->output_width); + + } + + inrow++; + + outrow += v_expand; + + } + +} + + + + + +/* + + * Fast processing for the common case of 2:1 horizontal and 1:1 vertical. + + * It's still a box filter. + + */ + + + +METHODDEF void + +h2v1_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + +{ + + JSAMPARRAY output_data = *output_data_ptr; + + register JSAMPROW inptr, outptr; + + register JSAMPLE invalue; + + JSAMPROW outend; + + int inrow; + + + + for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { + + inptr = input_data[inrow]; + + outptr = output_data[inrow]; + + outend = outptr + cinfo->output_width; + + while (outptr < outend) { + + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + + *outptr++ = invalue; + + *outptr++ = invalue; + + } + + } + +} + + + + + +/* + + * Fast processing for the common case of 2:1 horizontal and 2:1 vertical. + + * It's still a box filter. + + */ + + + +METHODDEF void + +h2v2_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + +{ + + JSAMPARRAY output_data = *output_data_ptr; + + register JSAMPROW inptr, outptr; + + register JSAMPLE invalue; + + JSAMPROW outend; + + int inrow, outrow; + + + + inrow = outrow = 0; + + while (outrow < cinfo->max_v_samp_factor) { + + inptr = input_data[inrow]; + + outptr = output_data[outrow]; + + outend = outptr + cinfo->output_width; + + while (outptr < outend) { + + invalue = *inptr++; /* don't need GETJSAMPLE() here */ + + *outptr++ = invalue; + + *outptr++ = invalue; + + } + + jcopy_sample_rows(output_data, outrow, output_data, outrow+1, + + 1, cinfo->output_width); + + inrow++; + + outrow += 2; + + } + +} + + + + + +/* + + * Fancy processing for the common case of 2:1 horizontal and 1:1 vertical. + + * + + * The upsampling algorithm is linear interpolation between pixel centers, + + * also known as a "triangle filter". This is a good compromise between + + * speed and visual quality. The centers of the output pixels are 1/4 and 3/4 + + * of the way between input pixel centers. + + * + + * A note about the "bias" calculations: when rounding fractional values to + + * integer, we do not want to always round 0.5 up to the next integer. + + * If we did that, we'd introduce a noticeable bias towards larger values. + + * Instead, this code is arranged so that 0.5 will be rounded up or down at + + * alternate pixel locations (a simple ordered dither pattern). + + */ + + + +METHODDEF void + +h2v1_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + +{ + + JSAMPARRAY output_data = *output_data_ptr; + + register JSAMPROW inptr, outptr; + + register int invalue; + + register JDIMENSION colctr; + + int inrow; + + + + for (inrow = 0; inrow < cinfo->max_v_samp_factor; inrow++) { + + inptr = input_data[inrow]; + + outptr = output_data[inrow]; + + /* Special case for first column */ + + invalue = GETJSAMPLE(*inptr++); + + *outptr++ = (JSAMPLE) invalue; + + *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(*inptr) + 2) >> 2); + + + + for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) { + + /* General case: 3/4 * nearer pixel + 1/4 * further pixel */ + + invalue = GETJSAMPLE(*inptr++) * 3; + + *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(inptr[-2]) + 1) >> 2); + + *outptr++ = (JSAMPLE) ((invalue + GETJSAMPLE(*inptr) + 2) >> 2); + + } + + + + /* Special case for last column */ + + invalue = GETJSAMPLE(*inptr); + + *outptr++ = (JSAMPLE) ((invalue * 3 + GETJSAMPLE(inptr[-1]) + 1) >> 2); + + *outptr++ = (JSAMPLE) invalue; + + } + +} + + + + + +/* + + * Fancy processing for the common case of 2:1 horizontal and 2:1 vertical. + + * Again a triangle filter; see comments for h2v1 case, above. + + * + + * It is OK for us to reference the adjacent input rows because we demanded + + * context from the main buffer controller (see initialization code). + + */ + + + +METHODDEF void + +h2v2_fancy_upsample (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JSAMPARRAY input_data, JSAMPARRAY * output_data_ptr) + +{ + + JSAMPARRAY output_data = *output_data_ptr; + + register JSAMPROW inptr0, inptr1, outptr; + +#if BITS_IN_JSAMPLE == 8 + + register int thiscolsum, lastcolsum, nextcolsum; + +#else + + register INT32 thiscolsum, lastcolsum, nextcolsum; + +#endif + + register JDIMENSION colctr; + + int inrow, outrow, v; + + + + inrow = outrow = 0; + + while (outrow < cinfo->max_v_samp_factor) { + + for (v = 0; v < 2; v++) { + + /* inptr0 points to nearest input row, inptr1 points to next nearest */ + + inptr0 = input_data[inrow]; + + if (v == 0) /* next nearest is row above */ + + inptr1 = input_data[inrow-1]; + + else /* next nearest is row below */ + + inptr1 = input_data[inrow+1]; + + outptr = output_data[outrow++]; + + + + /* Special case for first column */ + + thiscolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + + nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + + *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 8) >> 4); + + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4); + + lastcolsum = thiscolsum; thiscolsum = nextcolsum; + + + + for (colctr = compptr->downsampled_width - 2; colctr > 0; colctr--) { + + /* General case: 3/4 * nearer pixel + 1/4 * further pixel in each */ + + /* dimension, thus 9/16, 3/16, 3/16, 1/16 overall */ + + nextcolsum = GETJSAMPLE(*inptr0++) * 3 + GETJSAMPLE(*inptr1++); + + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4); + + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + nextcolsum + 7) >> 4); + + lastcolsum = thiscolsum; thiscolsum = nextcolsum; + + } + + + + /* Special case for last column */ + + *outptr++ = (JSAMPLE) ((thiscolsum * 3 + lastcolsum + 8) >> 4); + + *outptr++ = (JSAMPLE) ((thiscolsum * 4 + 7) >> 4); + + } + + inrow++; + + } + +} + + + + + +/* + + * Module initialization routine for upsampling. + + */ + + + +GLOBAL void + +jinit_upsampler (j_decompress_ptr cinfo) + +{ + + my_upsample_ptr upsample; + + int ci; + + jpeg_component_info * compptr; + + boolean need_buffer, do_fancy; + + int h_in_group, v_in_group, h_out_group, v_out_group; + + + + upsample = (my_upsample_ptr) + + (*cinfo->mem->alloc_small) ((j_common_ptr) cinfo, JPOOL_IMAGE, + + SIZEOF(my_upsampler)); + + cinfo->upsample = (struct jpeg_upsampler *) upsample; + + upsample->pub.start_pass = start_pass_upsample; + + upsample->pub.upsample = sep_upsample; + + upsample->pub.need_context_rows = FALSE; /* until we find out differently */ + + + + if (cinfo->CCIR601_sampling) /* this isn't supported */ + + ERREXIT(cinfo, JERR_CCIR601_NOTIMPL); + + + + /* jdmainct.c doesn't support context rows when min_DCT_scaled_size = 1, + + * so don't ask for it. + + */ + + do_fancy = cinfo->do_fancy_upsampling && cinfo->min_DCT_scaled_size > 1; + + + + /* Verify we can handle the sampling factors, select per-component methods, + + * and create storage as needed. + + */ + + for (ci = 0, compptr = cinfo->comp_info; ci < cinfo->num_components; + + ci++, compptr++) { + + /* Compute size of an "input group" after IDCT scaling. This many samples + + * are to be converted to max_h_samp_factor * max_v_samp_factor pixels. + + */ + + h_in_group = (compptr->h_samp_factor * compptr->DCT_scaled_size) / + + cinfo->min_DCT_scaled_size; + + v_in_group = (compptr->v_samp_factor * compptr->DCT_scaled_size) / + + cinfo->min_DCT_scaled_size; + + h_out_group = cinfo->max_h_samp_factor; + + v_out_group = cinfo->max_v_samp_factor; + + upsample->rowgroup_height[ci] = v_in_group; /* save for use later */ + + need_buffer = TRUE; + + if (! compptr->component_needed) { + + /* Don't bother to upsample an uninteresting component. */ + + upsample->methods[ci] = noop_upsample; + + need_buffer = FALSE; + + } else if (h_in_group == h_out_group && v_in_group == v_out_group) { + + /* Fullsize components can be processed without any work. */ + + upsample->methods[ci] = fullsize_upsample; + + need_buffer = FALSE; + + } else if (h_in_group * 2 == h_out_group && + + v_in_group == v_out_group) { + + /* Special cases for 2h1v upsampling */ + + if (do_fancy && compptr->downsampled_width > 2) + + upsample->methods[ci] = h2v1_fancy_upsample; + + else + + upsample->methods[ci] = h2v1_upsample; + + } else if (h_in_group * 2 == h_out_group && + + v_in_group * 2 == v_out_group) { + + /* Special cases for 2h2v upsampling */ + + if (do_fancy && compptr->downsampled_width > 2) { + + upsample->methods[ci] = h2v2_fancy_upsample; + + upsample->pub.need_context_rows = TRUE; + + } else + + upsample->methods[ci] = h2v2_upsample; + + } else if ((h_out_group % h_in_group) == 0 && + + (v_out_group % v_in_group) == 0) { + + /* Generic integral-factors upsampling method */ + + upsample->methods[ci] = int_upsample; + + upsample->h_expand[ci] = (UINT8) (h_out_group / h_in_group); + + upsample->v_expand[ci] = (UINT8) (v_out_group / v_in_group); + + } else + + ERREXIT(cinfo, JERR_FRACT_SAMPLE_NOTIMPL); + + if (need_buffer) { + + upsample->color_buf[ci] = (*cinfo->mem->alloc_sarray) + + ((j_common_ptr) cinfo, JPOOL_IMAGE, + + (JDIMENSION) jround_up((long) cinfo->output_width, + + (long) cinfo->max_h_samp_factor), + + (JDIMENSION) cinfo->max_v_samp_factor); + + } + + } + +} + diff --git a/libs/jpeg6/jdtrans.cpp b/libs/jpeg6/jdtrans.cpp new file mode 100644 index 00000000..70e67379 --- /dev/null +++ b/libs/jpeg6/jdtrans.cpp @@ -0,0 +1,244 @@ +/* + + * jdtrans.c + + * + + * Copyright (C) 1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains library routines for transcoding decompression, + + * that is, reading raw DCT coefficient arrays from an input JPEG file. + + * The routines in jdapimin.c will also be needed by a transcoder. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + + + + + +/* Forward declarations */ + +LOCAL void transdecode_master_selection JPP((j_decompress_ptr cinfo)); + + + + + +/* + + * Read the coefficient arrays from a JPEG file. + + * jpeg_read_header must be completed before calling this. + + * + + * The entire image is read into a set of virtual coefficient-block arrays, + + * one per component. The return value is a pointer to the array of + + * virtual-array descriptors. These can be manipulated directly via the + + * JPEG memory manager, or handed off to jpeg_write_coefficients(). + + * To release the memory occupied by the virtual arrays, call + + * jpeg_finish_decompress() when done with the data. + + * + + * Returns NULL if suspended. This case need be checked only if + + * a suspending data source is used. + + */ + + + +GLOBAL jvirt_barray_ptr * + +jpeg_read_coefficients (j_decompress_ptr cinfo) + +{ + + if (cinfo->global_state == DSTATE_READY) { + + /* First call: initialize active modules */ + + transdecode_master_selection(cinfo); + + cinfo->global_state = DSTATE_RDCOEFS; + + } else if (cinfo->global_state != DSTATE_RDCOEFS) + + ERREXIT1(cinfo, JERR_BAD_STATE, cinfo->global_state); + + /* Absorb whole file into the coef buffer */ + + for (;;) { + + int retcode; + + /* Call progress monitor hook if present */ + + if (cinfo->progress != NULL) + + (*cinfo->progress->progress_monitor) ((j_common_ptr) cinfo); + + /* Absorb some more input */ + + retcode = (*cinfo->inputctl->consume_input) (cinfo); + + if (retcode == JPEG_SUSPENDED) + + return NULL; + + if (retcode == JPEG_REACHED_EOI) + + break; + + /* Advance progress counter if appropriate */ + + if (cinfo->progress != NULL && + + (retcode == JPEG_ROW_COMPLETED || retcode == JPEG_REACHED_SOS)) { + + if (++cinfo->progress->pass_counter >= cinfo->progress->pass_limit) { + + /* startup underestimated number of scans; ratchet up one scan */ + + cinfo->progress->pass_limit += (long) cinfo->total_iMCU_rows; + + } + + } + + } + + /* Set state so that jpeg_finish_decompress does the right thing */ + + cinfo->global_state = DSTATE_STOPPING; + + return cinfo->coef->coef_arrays; + +} + + + + + +/* + + * Master selection of decompression modules for transcoding. + + * This substitutes for jdmaster.c's initialization of the full decompressor. + + */ + + + +LOCAL void + +transdecode_master_selection (j_decompress_ptr cinfo) + +{ + + /* Entropy decoding: either Huffman or arithmetic coding. */ + + if (cinfo->arith_code) { + + ERREXIT(cinfo, JERR_ARITH_NOTIMPL); + + } else { + + if (cinfo->progressive_mode) { + +#ifdef D_PROGRESSIVE_SUPPORTED + + jinit_phuff_decoder(cinfo); + +#else + + ERREXIT(cinfo, JERR_NOT_COMPILED); + +#endif + + } else + + jinit_huff_decoder(cinfo); + + } + + + + /* Always get a full-image coefficient buffer. */ + + jinit_d_coef_controller(cinfo, TRUE); + + + + /* We can now tell the memory manager to allocate virtual arrays. */ + + (*cinfo->mem->realize_virt_arrays) ((j_common_ptr) cinfo); + + + + /* Initialize input side of decompressor to consume first scan. */ + + (*cinfo->inputctl->start_input_pass) (cinfo); + + + + /* Initialize progress monitoring. */ + + if (cinfo->progress != NULL) { + + int nscans; + + /* Estimate number of scans to set pass_limit. */ + + if (cinfo->progressive_mode) { + + /* Arbitrarily estimate 2 interleaved DC scans + 3 AC scans/component. */ + + nscans = 2 + 3 * cinfo->num_components; + + } else if (cinfo->inputctl->has_multiple_scans) { + + /* For a nonprogressive multiscan file, estimate 1 scan per component. */ + + nscans = cinfo->num_components; + + } else { + + nscans = 1; + + } + + cinfo->progress->pass_counter = 0L; + + cinfo->progress->pass_limit = (long) cinfo->total_iMCU_rows * nscans; + + cinfo->progress->completed_passes = 0; + + cinfo->progress->total_passes = 1; + + } + +} + diff --git a/libs/jpeg6/jerror.cpp b/libs/jpeg6/jerror.cpp new file mode 100644 index 00000000..e4f65f78 --- /dev/null +++ b/libs/jpeg6/jerror.cpp @@ -0,0 +1,233 @@ +/* + * jerror.c + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file contains simple error-reporting and trace-message routines. + * These are suitable for Unix-like systems and others where writing to + * stderr is the right thing to do. Many applications will want to replace + * some or all of these routines. + * + * These routines are used by both the compression and decompression code. + */ + +/* this is not a core library module, so it doesn't define JPEG_INTERNALS */ +#include "jinclude.h" +#include "radiant_jpeglib.h" +#include "jversion.h" +#include "jerror.h" + +#ifndef EXIT_FAILURE /* define exit() codes if not provided */ +#define EXIT_FAILURE 1 +#endif + + +/* + * Create the message string table. + * We do this from the master message list in jerror.h by re-reading + * jerror.h with a suitable definition for macro JMESSAGE. + * The message table is made an external symbol just in case any applications + * want to refer to it directly. + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_message_table jMsgTable +#endif + +#define JMESSAGE(code,string) string , + +const char * const jpeg_std_message_table[] = { +#include "jerror.h" + NULL +}; + +// Rad additions, longjmp out of the LoadJPGBuff +GLOBAL jmp_buf rad_loadfailed; +GLOBAL char rad_errormsg[JMSG_LENGTH_MAX]; + +/* + * Error exit handler: must not return to caller. + * + * Applications may override this if they want to get control back after + * an error. Typically one would longjmp somewhere instead of exiting. + * The setjmp buffer can be made a private field within an expanded error + * handler object. Note that the info needed to generate an error message + * is stored in the error object, so you can generate the message now or + * later, at your convenience. + * You should make sure that the JPEG object is cleaned up (with jpeg_abort + * or jpeg_destroy) at some point. + */ + +METHODDEF void +error_exit (j_common_ptr cinfo) +{ +// char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message) (cinfo,rad_errormsg); + + /* Let the memory manager delete any temp files before we die */ + jpeg_destroy(cinfo); + + longjmp( rad_loadfailed, -1 ); +} + + +/* + * Actual output of an error or trace message. + * Applications may override this method to send JPEG messages somewhere + * other than stderr. + */ + +METHODDEF void +output_message (j_common_ptr cinfo) +{ + char buffer[JMSG_LENGTH_MAX]; + + /* Create the message */ + (*cinfo->err->format_message) (cinfo, buffer); + + /* Send it to stderr, adding a newline */ + printf("%s\n", buffer); +} + + +/* + * Decide whether to emit a trace or warning message. + * msg_level is one of: + * -1: recoverable corrupt-data warning, may want to abort. + * 0: important advisory messages (always display to user). + * 1: first level of tracing detail. + * 2,3,...: successively more detailed tracing messages. + * An application might override this method if it wanted to abort on warnings + * or change the policy about which messages to display. + */ + +METHODDEF void +emit_message (j_common_ptr cinfo, int msg_level) +{ + struct jpeg_error_mgr * err = cinfo->err; + + if (msg_level < 0) { + /* It's a warning message. Since corrupt files may generate many warnings, + * the policy implemented here is to show only the first warning, + * unless trace_level >= 3. + */ + if (err->num_warnings == 0 || err->trace_level >= 3) + (*err->output_message) (cinfo); + /* Always count warnings in num_warnings. */ + err->num_warnings++; + } else { + /* It's a trace message. Show it if trace_level >= msg_level. */ + if (err->trace_level >= msg_level) + (*err->output_message) (cinfo); + } +} + + +/* + * Format a message string for the most recent JPEG error or message. + * The message is stored into buffer, which should be at least JMSG_LENGTH_MAX + * characters. Note that no '\n' character is added to the string. + * Few applications should need to override this method. + */ + +METHODDEF void +format_message (j_common_ptr cinfo, char * buffer) +{ + struct jpeg_error_mgr * err = cinfo->err; + int msg_code = err->msg_code; + const char * msgtext = NULL; + const char * msgptr; + char ch; + boolean isstring; + + /* Look up message string in proper table */ + if (msg_code > 0 && msg_code <= err->last_jpeg_message) { + msgtext = err->jpeg_message_table[msg_code]; + } else if (err->addon_message_table != NULL && + msg_code >= err->first_addon_message && + msg_code <= err->last_addon_message) { + msgtext = err->addon_message_table[msg_code - err->first_addon_message]; + } + + /* Defend against bogus message number */ + if (msgtext == NULL) { + err->msg_parm.i[0] = msg_code; + msgtext = err->jpeg_message_table[0]; + } + + /* Check for string parameter, as indicated by %s in the message text */ + isstring = FALSE; + msgptr = msgtext; + while ((ch = *msgptr++) != '\0') { + if (ch == '%') { + if (*msgptr == 's') isstring = TRUE; + break; + } + } + + /* Format the message into the passed buffer */ + if (isstring) + sprintf(buffer, msgtext, err->msg_parm.s); + else + sprintf(buffer, msgtext, + err->msg_parm.i[0], err->msg_parm.i[1], + err->msg_parm.i[2], err->msg_parm.i[3], + err->msg_parm.i[4], err->msg_parm.i[5], + err->msg_parm.i[6], err->msg_parm.i[7]); +} + + +/* + * Reset error state variables at start of a new image. + * This is called during compression startup to reset trace/error + * processing to default state, without losing any application-specific + * method pointers. An application might possibly want to override + * this method if it has additional error processing state. + */ + +METHODDEF void +reset_error_mgr (j_common_ptr cinfo) +{ + cinfo->err->num_warnings = 0; + /* trace_level is not reset since it is an application-supplied parameter */ + cinfo->err->msg_code = 0; /* may be useful as a flag for "no error" */ +} + + +/* + * Fill in the standard error-handling methods in a jpeg_error_mgr object. + * Typical call is: + * struct jpeg_compress_struct cinfo; + * struct jpeg_error_mgr err; + * + * cinfo.err = jpeg_std_error(&err); + * after which the application may override some of the methods. + */ + +GLOBAL struct jpeg_error_mgr * +jpeg_std_error (struct jpeg_error_mgr * err) +{ + err->error_exit = error_exit; + err->emit_message = emit_message; + err->output_message = output_message; + err->format_message = format_message; + err->reset_error_mgr = reset_error_mgr; + + err->trace_level = 0; /* default = no tracing */ + err->num_warnings = 0; /* no warnings emitted yet */ + err->msg_code = 0; /* may be useful as a flag for "no error" */ + + /* Initialize message table pointers */ + err->jpeg_message_table = jpeg_std_message_table; + err->last_jpeg_message = (int) JMSG_LASTMSGCODE - 1; + + err->addon_message_table = NULL; + err->first_addon_message = 0; /* for safety */ + err->last_addon_message = 0; + + return err; +} diff --git a/libs/jpeg6/jerror.h b/libs/jpeg6/jerror.h new file mode 100644 index 00000000..d23dfb0c --- /dev/null +++ b/libs/jpeg6/jerror.h @@ -0,0 +1,278 @@ +/* + * jerror.h + * + * Copyright (C) 1994-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the error and message codes for the JPEG library. + * Edit this file to add new codes, or to translate the message strings to + * some other language. + * A set of error-reporting macros are defined too. Some applications using + * the JPEG library may wish to include this file to get the error codes + * and/or the macros. + */ + +/* + * To define the enum list of message codes, include this file without + * defining macro JMESSAGE. To create a message string table, include it + * again with a suitable JMESSAGE definition (see jerror.c for an example). + */ +#ifndef JMESSAGE +#ifndef JERROR_H +/* First time through, define the enum list */ +#define JMAKE_ENUM_LIST +#else +/* Repeated inclusions of this file are no-ops unless JMESSAGE is defined */ +#define JMESSAGE(code,string) +#endif /* JERROR_H */ +#endif /* JMESSAGE */ + +#ifdef JMAKE_ENUM_LIST + +typedef enum { + +#define JMESSAGE(code,string) code , + +#endif /* JMAKE_ENUM_LIST */ + +JMESSAGE(JMSG_NOMESSAGE, "Bogus message code %d") /* Must be first entry! */ + +/* For maintenance convenience, list is alphabetical by message code name */ +JMESSAGE(JERR_ARITH_NOTIMPL, + "Sorry, there are legal restrictions on arithmetic coding") +JMESSAGE(JERR_BAD_ALIGN_TYPE, "ALIGN_TYPE is wrong, please fix") +JMESSAGE(JERR_BAD_ALLOC_CHUNK, "MAX_ALLOC_CHUNK is wrong, please fix") +JMESSAGE(JERR_BAD_BUFFER_MODE, "Bogus buffer control mode") +JMESSAGE(JERR_BAD_COMPONENT_ID, "Invalid component ID %d in SOS") +JMESSAGE(JERR_BAD_DCTSIZE, "IDCT output block size %d not supported") +JMESSAGE(JERR_BAD_IN_COLORSPACE, "Bogus input colorspace") +JMESSAGE(JERR_BAD_J_COLORSPACE, "Bogus JPEG colorspace") +JMESSAGE(JERR_BAD_LENGTH, "Bogus marker length") +JMESSAGE(JERR_BAD_MCU_SIZE, "Sampling factors too large for interleaved scan") +JMESSAGE(JERR_BAD_POOL_ID, "Invalid memory pool code %d") +JMESSAGE(JERR_BAD_PRECISION, "Unsupported JPEG data precision %d") +JMESSAGE(JERR_BAD_PROGRESSION, + "Invalid progressive parameters Ss=%d Se=%d Ah=%d Al=%d") +JMESSAGE(JERR_BAD_PROG_SCRIPT, + "Invalid progressive parameters at scan script entry %d") +JMESSAGE(JERR_BAD_SAMPLING, "Bogus sampling factors") +JMESSAGE(JERR_BAD_SCAN_SCRIPT, "Invalid scan script at entry %d") +JMESSAGE(JERR_BAD_STATE, "Improper call to JPEG library in state %d") +JMESSAGE(JERR_BAD_VIRTUAL_ACCESS, "Bogus virtual array access") +JMESSAGE(JERR_BUFFER_SIZE, "Buffer passed to JPEG library is too small") +JMESSAGE(JERR_CANT_SUSPEND, "Suspension not allowed here") +JMESSAGE(JERR_CCIR601_NOTIMPL, "CCIR601 sampling not implemented yet") +JMESSAGE(JERR_COMPONENT_COUNT, "Too many color components: %d, max %d") +JMESSAGE(JERR_CONVERSION_NOTIMPL, "Unsupported color conversion request") +JMESSAGE(JERR_DAC_INDEX, "Bogus DAC index %d") +JMESSAGE(JERR_DAC_VALUE, "Bogus DAC value 0x%x") +JMESSAGE(JERR_DHT_COUNTS, "Bogus DHT counts") +JMESSAGE(JERR_DHT_INDEX, "Bogus DHT index %d") +JMESSAGE(JERR_DQT_INDEX, "Bogus DQT index %d") +JMESSAGE(JERR_EMPTY_IMAGE, "Empty JPEG image (DNL not supported)") +JMESSAGE(JERR_EMS_READ, "Read from EMS failed") +JMESSAGE(JERR_EMS_WRITE, "Write to EMS failed") +JMESSAGE(JERR_EOI_EXPECTED, "Didn't expect more than one scan") +JMESSAGE(JERR_FILE_READ, "Input file read error") +JMESSAGE(JERR_FILE_WRITE, "Output file write error --- out of disk space?") +JMESSAGE(JERR_FRACT_SAMPLE_NOTIMPL, "Fractional sampling not implemented yet") +JMESSAGE(JERR_HUFF_CLEN_OVERFLOW, "Huffman code size table overflow") +JMESSAGE(JERR_HUFF_MISSING_CODE, "Missing Huffman code table entry") +JMESSAGE(JERR_IMAGE_TOO_BIG, "Maximum supported image dimension is %u pixels") +JMESSAGE(JERR_INPUT_EMPTY, "Empty input file") +JMESSAGE(JERR_INPUT_EOF, "Premature end of input file") +JMESSAGE(JERR_MISMATCHED_QUANT_TABLE, + "Cannot transcode due to multiple use of quantization table %d") +JMESSAGE(JERR_MISSING_DATA, "Scan script does not transmit all data") +JMESSAGE(JERR_MODE_CHANGE, "Invalid color quantization mode change") +JMESSAGE(JERR_NOTIMPL, "Not implemented yet") +JMESSAGE(JERR_NOT_COMPILED, "Requested feature was omitted at compile time") +JMESSAGE(JERR_NO_PROGRESSIVE, "Progressive JPEGs not supported, use regular JPEG instead") +JMESSAGE(JERR_NO_BACKING_STORE, "Backing store not supported") +JMESSAGE(JERR_NO_HUFF_TABLE, "Huffman table 0x%02x was not defined") +JMESSAGE(JERR_NO_IMAGE, "JPEG datastream contains no image") +JMESSAGE(JERR_NO_QUANT_TABLE, "Quantization table 0x%02x was not defined") +JMESSAGE(JERR_NO_SOI, "Not a JPEG file: starts with 0x%02x 0x%02x") +JMESSAGE(JERR_OUT_OF_MEMORY, "Insufficient memory (case %d)") +JMESSAGE(JERR_QUANT_COMPONENTS, + "Cannot quantize more than %d color components") +JMESSAGE(JERR_QUANT_FEW_COLORS, "Cannot quantize to fewer than %d colors") +JMESSAGE(JERR_QUANT_MANY_COLORS, "Cannot quantize to more than %d colors") +JMESSAGE(JERR_SOF_DUPLICATE, "Invalid JPEG file structure: two SOF markers") +JMESSAGE(JERR_SOF_NO_SOS, "Invalid JPEG file structure: missing SOS marker") +JMESSAGE(JERR_SOF_UNSUPPORTED, "Unsupported JPEG process: SOF type 0x%02x") +JMESSAGE(JERR_SOI_DUPLICATE, "Invalid JPEG file structure: two SOI markers") +JMESSAGE(JERR_SOS_NO_SOF, "Invalid JPEG file structure: SOS before SOF") +JMESSAGE(JERR_TFILE_CREATE, "Failed to create temporary file %s") +JMESSAGE(JERR_TFILE_READ, "Read failed on temporary file") +JMESSAGE(JERR_TFILE_SEEK, "Seek failed on temporary file") +JMESSAGE(JERR_TFILE_WRITE, + "Write failed on temporary file --- out of disk space?") +JMESSAGE(JERR_TOO_LITTLE_DATA, "Application transferred too few scanlines") +JMESSAGE(JERR_UNKNOWN_MARKER, "Unsupported marker type 0x%02x") +JMESSAGE(JERR_VIRTUAL_BUG, "Virtual array controller messed up") +JMESSAGE(JERR_WIDTH_OVERFLOW, "Image too wide for this implementation") +JMESSAGE(JERR_XMS_READ, "Read from XMS failed") +JMESSAGE(JERR_XMS_WRITE, "Write to XMS failed") +JMESSAGE(JMSG_COPYRIGHT, JCOPYRIGHT) +JMESSAGE(JMSG_VERSION, JVERSION) +JMESSAGE(JTRC_16BIT_TABLES, + "Caution: quantization tables are too coarse for baseline JPEG") +JMESSAGE(JTRC_ADOBE, + "Adobe APP14 marker: version %d, flags 0x%04x 0x%04x, transform %d") +JMESSAGE(JTRC_APP0, "Unknown APP0 marker (not JFIF), length %u") +JMESSAGE(JTRC_APP14, "Unknown APP14 marker (not Adobe), length %u") +JMESSAGE(JTRC_DAC, "Define Arithmetic Table 0x%02x: 0x%02x") +JMESSAGE(JTRC_DHT, "Define Huffman Table 0x%02x") +JMESSAGE(JTRC_DQT, "Define Quantization Table %d precision %d") +JMESSAGE(JTRC_DRI, "Define Restart Interval %u") +JMESSAGE(JTRC_EMS_CLOSE, "Freed EMS handle %u") +JMESSAGE(JTRC_EMS_OPEN, "Obtained EMS handle %u") +JMESSAGE(JTRC_EOI, "End Of Image") +JMESSAGE(JTRC_HUFFBITS, " %3d %3d %3d %3d %3d %3d %3d %3d") +JMESSAGE(JTRC_JFIF, "JFIF APP0 marker, density %dx%d %d") +JMESSAGE(JTRC_JFIF_BADTHUMBNAILSIZE, + "Warning: thumbnail image size does not match data length %u") +JMESSAGE(JTRC_JFIF_MINOR, "Unknown JFIF minor revision number %d.%02d") +JMESSAGE(JTRC_JFIF_THUMBNAIL, " with %d x %d thumbnail image") +JMESSAGE(JTRC_MISC_MARKER, "Skipping marker 0x%02x, length %u") +JMESSAGE(JTRC_PARMLESS_MARKER, "Unexpected marker 0x%02x") +JMESSAGE(JTRC_QUANTVALS, " %4u %4u %4u %4u %4u %4u %4u %4u") +JMESSAGE(JTRC_QUANT_3_NCOLORS, "Quantizing to %d = %d*%d*%d colors") +JMESSAGE(JTRC_QUANT_NCOLORS, "Quantizing to %d colors") +JMESSAGE(JTRC_QUANT_SELECTED, "Selected %d colors for quantization") +JMESSAGE(JTRC_RECOVERY_ACTION, "At marker 0x%02x, recovery action %d") +JMESSAGE(JTRC_RST, "RST%d") +JMESSAGE(JTRC_SMOOTH_NOTIMPL, + "Smoothing not supported with nonstandard sampling ratios") +JMESSAGE(JTRC_SOF, "Start Of Frame 0x%02x: width=%u, height=%u, components=%d") +JMESSAGE(JTRC_SOF_COMPONENT, " Component %d: %dhx%dv q=%d") +JMESSAGE(JTRC_SOI, "Start of Image") +JMESSAGE(JTRC_SOS, "Start Of Scan: %d components") +JMESSAGE(JTRC_SOS_COMPONENT, " Component %d: dc=%d ac=%d") +JMESSAGE(JTRC_SOS_PARAMS, " Ss=%d, Se=%d, Ah=%d, Al=%d") +JMESSAGE(JTRC_TFILE_CLOSE, "Closed temporary file %s") +JMESSAGE(JTRC_TFILE_OPEN, "Opened temporary file %s") +JMESSAGE(JTRC_UNKNOWN_IDS, + "Unrecognized component IDs %d %d %d, assuming YCbCr") +JMESSAGE(JTRC_XMS_CLOSE, "Freed XMS handle %u") +JMESSAGE(JTRC_XMS_OPEN, "Obtained XMS handle %u") +JMESSAGE(JWRN_ADOBE_XFORM, "Unknown Adobe color transform code %d") +JMESSAGE(JWRN_BOGUS_PROGRESSION, + "Inconsistent progression sequence for component %d coefficient %d") +JMESSAGE(JWRN_EXTRANEOUS_DATA, + "Corrupt JPEG data: %u extraneous bytes before marker 0x%02x") +JMESSAGE(JWRN_HIT_MARKER, "Corrupt JPEG data: premature end of data segment") +JMESSAGE(JWRN_HUFF_BAD_CODE, "Corrupt JPEG data: bad Huffman code") +JMESSAGE(JWRN_JFIF_MAJOR, "Warning: unknown JFIF revision number %d.%02d") +JMESSAGE(JWRN_JPEG_EOF, "Premature end of JPEG file") +JMESSAGE(JWRN_MUST_RESYNC, + "Corrupt JPEG data: found marker 0x%02x instead of RST%d") +JMESSAGE(JWRN_NOT_SEQUENTIAL, "Invalid SOS parameters for sequential JPEG") +JMESSAGE(JWRN_TOO_MUCH_DATA, "Application transferred too many scanlines") + +#ifdef JMAKE_ENUM_LIST + + JMSG_LASTMSGCODE +} J_MESSAGE_CODE; + +#undef JMAKE_ENUM_LIST +#endif /* JMAKE_ENUM_LIST */ + +/* Zap JMESSAGE macro so that future re-inclusions do nothing by default */ +#undef JMESSAGE + +#ifndef JERROR_H +#define JERROR_H + +// Rad additions, using longjmp to recover from errors +#include +EXTERN jmp_buf rad_loadfailed; +EXTERN char rad_errormsg[JMSG_LENGTH_MAX]; + +/* Macros to simplify using the error and trace message stuff */ +/* The first parameter is either type of cinfo pointer */ + +/* Fatal errors (print message and exit) */ +#define ERREXIT(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT3(cinfo,code,p1,p2,p3) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXIT4(cinfo,code,p1,p2,p3,p4) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (cinfo)->err->msg_parm.i[2] = (p3), \ + (cinfo)->err->msg_parm.i[3] = (p4), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) +#define ERREXITS(cinfo,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->error_exit) ((j_common_ptr) (cinfo))) + +#define MAKESTMT(stuff) do { stuff } while (0) + +/* Nonfatal errors (we can keep going, but the data is probably corrupt) */ +#define WARNMS(cinfo,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS1(cinfo,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) +#define WARNMS2(cinfo,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), -1)) + +/* Informational/debugging messages */ +#define TRACEMS(cinfo,lvl,code) \ + ((cinfo)->err->msg_code = (code), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS1(cinfo,lvl,code,p1) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS2(cinfo,lvl,code,p1,p2) \ + ((cinfo)->err->msg_code = (code), \ + (cinfo)->err->msg_parm.i[0] = (p1), \ + (cinfo)->err->msg_parm.i[1] = (p2), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) +#define TRACEMS3(cinfo,lvl,code,p1,p2,p3) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS4(cinfo,lvl,code,p1,p2,p3,p4) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMS8(cinfo,lvl,code,p1,p2,p3,p4,p5,p6,p7,p8) \ + MAKESTMT(int * _mp = (cinfo)->err->msg_parm.i; \ + _mp[0] = (p1); _mp[1] = (p2); _mp[2] = (p3); _mp[3] = (p4); \ + _mp[4] = (p5); _mp[5] = (p6); _mp[6] = (p7); _mp[7] = (p8); \ + (cinfo)->err->msg_code = (code); \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl)); ) +#define TRACEMSS(cinfo,lvl,code,str) \ + ((cinfo)->err->msg_code = (code), \ + strncpy((cinfo)->err->msg_parm.s, (str), JMSG_STR_PARM_MAX), \ + (*(cinfo)->err->emit_message) ((j_common_ptr) (cinfo), (lvl))) + +#endif /* JERROR_H */ diff --git a/libs/jpeg6/jfdctflt.cpp b/libs/jpeg6/jfdctflt.cpp new file mode 100644 index 00000000..f41bff82 --- /dev/null +++ b/libs/jpeg6/jfdctflt.cpp @@ -0,0 +1,336 @@ +/* + + * jfdctflt.c + + * + + * Copyright (C) 1994, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains a floating-point implementation of the + + * forward DCT (Discrete Cosine Transform). + + * + + * This implementation should be more accurate than either of the integer + + * DCT implementations. However, it may not give the same results on all + + * machines because of differences in roundoff behavior. Speed will depend + + * on the hardware's floating point capacity. + + * + + * A 2-D DCT can be done by 1-D DCT on each row followed by 1-D DCT + + * on each column. Direct algorithms are also available, but they are + + * much more complex and seem not to be any faster when reduced to code. + + * + + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + + * JPEG textbook (see REFERENCES section in file README). The following code + + * is based directly on figure 4-8 in P&M. + + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + + * possible to arrange the computation so that many of the multiplies are + + * simple scalings of the final outputs. These multiplies can then be + + * folded into the multiplications or divisions by the JPEG quantization + + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + + * to be done in the DCT itself. + + * The primary disadvantage of this method is that with a fixed-point + + * implementation, accuracy is lost due to imprecise representation of the + + * scaled quantization values. However, that problem does not arise if + + * we use floating point arithmetic. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + +#include "jdct.h" /* Private declarations for DCT subsystem */ + + + +#ifdef DCT_FLOAT_SUPPORTED + + + + + +/* + + * This module is specialized to the case DCTSIZE = 8. + + */ + + + +#if DCTSIZE != 8 + + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ + +#endif + + + + + +/* + + * Perform the forward DCT on one block of samples. + + */ + + + +GLOBAL void + +jpeg_fdct_float (FAST_FLOAT * data) + +{ + + FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + + FAST_FLOAT tmp10, tmp11, tmp12, tmp13; + + FAST_FLOAT z1, z2, z3, z4, z5, z11, z13; + + FAST_FLOAT *dataptr; + + int ctr; + + + + /* Pass 1: process rows. */ + + + + dataptr = data; + + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + + tmp0 = dataptr[0] + dataptr[7]; + + tmp7 = dataptr[0] - dataptr[7]; + + tmp1 = dataptr[1] + dataptr[6]; + + tmp6 = dataptr[1] - dataptr[6]; + + tmp2 = dataptr[2] + dataptr[5]; + + tmp5 = dataptr[2] - dataptr[5]; + + tmp3 = dataptr[3] + dataptr[4]; + + tmp4 = dataptr[3] - dataptr[4]; + + + + /* Even part */ + + + + tmp10 = tmp0 + tmp3; /* phase 2 */ + + tmp13 = tmp0 - tmp3; + + tmp11 = tmp1 + tmp2; + + tmp12 = tmp1 - tmp2; + + + + dataptr[0] = tmp10 + tmp11; /* phase 3 */ + + dataptr[4] = tmp10 - tmp11; + + + + z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ + + dataptr[2] = tmp13 + z1; /* phase 5 */ + + dataptr[6] = tmp13 - z1; + + + + /* Odd part */ + + + + tmp10 = tmp4 + tmp5; /* phase 2 */ + + tmp11 = tmp5 + tmp6; + + tmp12 = tmp6 + tmp7; + + + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + + z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ + + z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ + + z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ + + z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ + + + + z11 = tmp7 + z3; /* phase 5 */ + + z13 = tmp7 - z3; + + + + dataptr[5] = z13 + z2; /* phase 6 */ + + dataptr[3] = z13 - z2; + + dataptr[1] = z11 + z4; + + dataptr[7] = z11 - z4; + + + + dataptr += DCTSIZE; /* advance pointer to next row */ + + } + + + + /* Pass 2: process columns. */ + + + + dataptr = data; + + for (ctr = DCTSIZE-1; ctr >= 0; ctr--) { + + tmp0 = dataptr[DCTSIZE*0] + dataptr[DCTSIZE*7]; + + tmp7 = dataptr[DCTSIZE*0] - dataptr[DCTSIZE*7]; + + tmp1 = dataptr[DCTSIZE*1] + dataptr[DCTSIZE*6]; + + tmp6 = dataptr[DCTSIZE*1] - dataptr[DCTSIZE*6]; + + tmp2 = dataptr[DCTSIZE*2] + dataptr[DCTSIZE*5]; + + tmp5 = dataptr[DCTSIZE*2] - dataptr[DCTSIZE*5]; + + tmp3 = dataptr[DCTSIZE*3] + dataptr[DCTSIZE*4]; + + tmp4 = dataptr[DCTSIZE*3] - dataptr[DCTSIZE*4]; + + + + /* Even part */ + + + + tmp10 = tmp0 + tmp3; /* phase 2 */ + + tmp13 = tmp0 - tmp3; + + tmp11 = tmp1 + tmp2; + + tmp12 = tmp1 - tmp2; + + + + dataptr[DCTSIZE*0] = tmp10 + tmp11; /* phase 3 */ + + dataptr[DCTSIZE*4] = tmp10 - tmp11; + + + + z1 = (tmp12 + tmp13) * ((FAST_FLOAT) 0.707106781); /* c4 */ + + dataptr[DCTSIZE*2] = tmp13 + z1; /* phase 5 */ + + dataptr[DCTSIZE*6] = tmp13 - z1; + + + + /* Odd part */ + + + + tmp10 = tmp4 + tmp5; /* phase 2 */ + + tmp11 = tmp5 + tmp6; + + tmp12 = tmp6 + tmp7; + + + + /* The rotator is modified from fig 4-8 to avoid extra negations. */ + + z5 = (tmp10 - tmp12) * ((FAST_FLOAT) 0.382683433); /* c6 */ + + z2 = ((FAST_FLOAT) 0.541196100) * tmp10 + z5; /* c2-c6 */ + + z4 = ((FAST_FLOAT) 1.306562965) * tmp12 + z5; /* c2+c6 */ + + z3 = tmp11 * ((FAST_FLOAT) 0.707106781); /* c4 */ + + + + z11 = tmp7 + z3; /* phase 5 */ + + z13 = tmp7 - z3; + + + + dataptr[DCTSIZE*5] = z13 + z2; /* phase 6 */ + + dataptr[DCTSIZE*3] = z13 - z2; + + dataptr[DCTSIZE*1] = z11 + z4; + + dataptr[DCTSIZE*7] = z11 - z4; + + + + dataptr++; /* advance pointer to next column */ + + } + +} + + + +#endif /* DCT_FLOAT_SUPPORTED */ + diff --git a/libs/jpeg6/jidctflt.cpp b/libs/jpeg6/jidctflt.cpp new file mode 100644 index 00000000..9e966daf --- /dev/null +++ b/libs/jpeg6/jidctflt.cpp @@ -0,0 +1,482 @@ +/* + + * jidctflt.c + + * + + * Copyright (C) 1994, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains a floating-point implementation of the + + * inverse DCT (Discrete Cosine Transform). In the IJG code, this routine + + * must also perform dequantization of the input coefficients. + + * + + * This implementation should be more accurate than either of the integer + + * IDCT implementations. However, it may not give the same results on all + + * machines because of differences in roundoff behavior. Speed will depend + + * on the hardware's floating point capacity. + + * + + * A 2-D IDCT can be done by 1-D IDCT on each column followed by 1-D IDCT + + * on each row (or vice versa, but it's more convenient to emit a row at + + * a time). Direct algorithms are also available, but they are much more + + * complex and seem not to be any faster when reduced to code. + + * + + * This implementation is based on Arai, Agui, and Nakajima's algorithm for + + * scaled DCT. Their original paper (Trans. IEICE E-71(11):1095) is in + + * Japanese, but the algorithm is described in the Pennebaker & Mitchell + + * JPEG textbook (see REFERENCES section in file README). The following code + + * is based directly on figure 4-8 in P&M. + + * While an 8-point DCT cannot be done in less than 11 multiplies, it is + + * possible to arrange the computation so that many of the multiplies are + + * simple scalings of the final outputs. These multiplies can then be + + * folded into the multiplications or divisions by the JPEG quantization + + * table entries. The AA&N method leaves only 5 multiplies and 29 adds + + * to be done in the DCT itself. + + * The primary disadvantage of this method is that with a fixed-point + + * implementation, accuracy is lost due to imprecise representation of the + + * scaled quantization values. However, that problem does not arise if + + * we use floating point arithmetic. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + +#include "jdct.h" /* Private declarations for DCT subsystem */ + + + +#ifdef DCT_FLOAT_SUPPORTED + + + + + +/* + + * This module is specialized to the case DCTSIZE = 8. + + */ + + + +#if DCTSIZE != 8 + + Sorry, this code only copes with 8x8 DCTs. /* deliberate syntax err */ + +#endif + + + + + +/* Dequantize a coefficient by multiplying it by the multiplier-table + + * entry; produce a float result. + + */ + + + +#define DEQUANTIZE(coef,quantval) (((FAST_FLOAT) (coef)) * (quantval)) + + + + + +/* + + * Perform dequantization and inverse DCT on one block of coefficients. + + */ + + + +GLOBAL void + +jpeg_idct_float (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JCOEFPTR coef_block, + + JSAMPARRAY output_buf, JDIMENSION output_col) + +{ + + FAST_FLOAT tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7; + + FAST_FLOAT tmp10, tmp11, tmp12, tmp13; + + FAST_FLOAT z5, z10, z11, z12, z13; + + JCOEFPTR inptr; + + FLOAT_MULT_TYPE * quantptr; + + FAST_FLOAT * wsptr; + + JSAMPROW outptr; + + JSAMPLE *range_limit = IDCT_range_limit(cinfo); + + int ctr; + + FAST_FLOAT workspace[DCTSIZE2]; /* buffers data between passes */ + + SHIFT_TEMPS + + + + /* Pass 1: process columns from input, store into work array. */ + + + + inptr = coef_block; + + quantptr = (FLOAT_MULT_TYPE *) compptr->dct_table; + + wsptr = workspace; + + for (ctr = DCTSIZE; ctr > 0; ctr--) { + + /* Due to quantization, we will usually find that many of the input + + * coefficients are zero, especially the AC terms. We can exploit this + + * by short-circuiting the IDCT calculation for any column in which all + + * the AC terms are zero. In that case each output is equal to the + + * DC coefficient (with scale factor as needed). + + * With typical images and quantization tables, half or more of the + + * column DCT calculations can be simplified this way. + + */ + + + + if ((inptr[DCTSIZE*1] | inptr[DCTSIZE*2] | inptr[DCTSIZE*3] | + + inptr[DCTSIZE*4] | inptr[DCTSIZE*5] | inptr[DCTSIZE*6] | + + inptr[DCTSIZE*7]) == 0) { + + /* AC terms all zero */ + + FAST_FLOAT dcval = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + + + wsptr[DCTSIZE*0] = dcval; + + wsptr[DCTSIZE*1] = dcval; + + wsptr[DCTSIZE*2] = dcval; + + wsptr[DCTSIZE*3] = dcval; + + wsptr[DCTSIZE*4] = dcval; + + wsptr[DCTSIZE*5] = dcval; + + wsptr[DCTSIZE*6] = dcval; + + wsptr[DCTSIZE*7] = dcval; + + + + inptr++; /* advance pointers to next column */ + + quantptr++; + + wsptr++; + + continue; + + } + + + + /* Even part */ + + + + tmp0 = DEQUANTIZE(inptr[DCTSIZE*0], quantptr[DCTSIZE*0]); + + tmp1 = DEQUANTIZE(inptr[DCTSIZE*2], quantptr[DCTSIZE*2]); + + tmp2 = DEQUANTIZE(inptr[DCTSIZE*4], quantptr[DCTSIZE*4]); + + tmp3 = DEQUANTIZE(inptr[DCTSIZE*6], quantptr[DCTSIZE*6]); + + + + tmp10 = tmp0 + tmp2; /* phase 3 */ + + tmp11 = tmp0 - tmp2; + + + + tmp13 = tmp1 + tmp3; /* phases 5-3 */ + + tmp12 = (tmp1 - tmp3) * ((FAST_FLOAT) 1.414213562) - tmp13; /* 2*c4 */ + + + + tmp0 = tmp10 + tmp13; /* phase 2 */ + + tmp3 = tmp10 - tmp13; + + tmp1 = tmp11 + tmp12; + + tmp2 = tmp11 - tmp12; + + + + /* Odd part */ + + + + tmp4 = DEQUANTIZE(inptr[DCTSIZE*1], quantptr[DCTSIZE*1]); + + tmp5 = DEQUANTIZE(inptr[DCTSIZE*3], quantptr[DCTSIZE*3]); + + tmp6 = DEQUANTIZE(inptr[DCTSIZE*5], quantptr[DCTSIZE*5]); + + tmp7 = DEQUANTIZE(inptr[DCTSIZE*7], quantptr[DCTSIZE*7]); + + + + z13 = tmp6 + tmp5; /* phase 6 */ + + z10 = tmp6 - tmp5; + + z11 = tmp4 + tmp7; + + z12 = tmp4 - tmp7; + + + + tmp7 = z11 + z13; /* phase 5 */ + + tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); /* 2*c4 */ + + + + z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ + + tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */ + + tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */ + + + + tmp6 = tmp12 - tmp7; /* phase 2 */ + + tmp5 = tmp11 - tmp6; + + tmp4 = tmp10 + tmp5; + + + + wsptr[DCTSIZE*0] = tmp0 + tmp7; + + wsptr[DCTSIZE*7] = tmp0 - tmp7; + + wsptr[DCTSIZE*1] = tmp1 + tmp6; + + wsptr[DCTSIZE*6] = tmp1 - tmp6; + + wsptr[DCTSIZE*2] = tmp2 + tmp5; + + wsptr[DCTSIZE*5] = tmp2 - tmp5; + + wsptr[DCTSIZE*4] = tmp3 + tmp4; + + wsptr[DCTSIZE*3] = tmp3 - tmp4; + + + + inptr++; /* advance pointers to next column */ + + quantptr++; + + wsptr++; + + } + + + + /* Pass 2: process rows from work array, store into output array. */ + + /* Note that we must descale the results by a factor of 8 == 2**3. */ + + + + wsptr = workspace; + + for (ctr = 0; ctr < DCTSIZE; ctr++) { + + outptr = output_buf[ctr] + output_col; + + /* Rows of zeroes can be exploited in the same way as we did with columns. + + * However, the column calculation has created many nonzero AC terms, so + + * the simplification applies less often (typically 5% to 10% of the time). + + * And testing floats for zero is relatively expensive, so we don't bother. + + */ + + + + /* Even part */ + + + + tmp10 = wsptr[0] + wsptr[4]; + + tmp11 = wsptr[0] - wsptr[4]; + + + + tmp13 = wsptr[2] + wsptr[6]; + + tmp12 = (wsptr[2] - wsptr[6]) * ((FAST_FLOAT) 1.414213562) - tmp13; + + + + tmp0 = tmp10 + tmp13; + + tmp3 = tmp10 - tmp13; + + tmp1 = tmp11 + tmp12; + + tmp2 = tmp11 - tmp12; + + + + /* Odd part */ + + + + z13 = wsptr[5] + wsptr[3]; + + z10 = wsptr[5] - wsptr[3]; + + z11 = wsptr[1] + wsptr[7]; + + z12 = wsptr[1] - wsptr[7]; + + + + tmp7 = z11 + z13; + + tmp11 = (z11 - z13) * ((FAST_FLOAT) 1.414213562); + + + + z5 = (z10 + z12) * ((FAST_FLOAT) 1.847759065); /* 2*c2 */ + + tmp10 = ((FAST_FLOAT) 1.082392200) * z12 - z5; /* 2*(c2-c6) */ + + tmp12 = ((FAST_FLOAT) -2.613125930) * z10 + z5; /* -2*(c2+c6) */ + + + + tmp6 = tmp12 - tmp7; + + tmp5 = tmp11 - tmp6; + + tmp4 = tmp10 + tmp5; + + + + /* Final output stage: scale down by a factor of 8 and range-limit */ + + + + outptr[0] = range_limit[(int) DESCALE((INT32) (tmp0 + tmp7), 3) + + & RANGE_MASK]; + + outptr[7] = range_limit[(int) DESCALE((INT32) (tmp0 - tmp7), 3) + + & RANGE_MASK]; + + outptr[1] = range_limit[(int) DESCALE((INT32) (tmp1 + tmp6), 3) + + & RANGE_MASK]; + + outptr[6] = range_limit[(int) DESCALE((INT32) (tmp1 - tmp6), 3) + + & RANGE_MASK]; + + outptr[2] = range_limit[(int) DESCALE((INT32) (tmp2 + tmp5), 3) + + & RANGE_MASK]; + + outptr[5] = range_limit[(int) DESCALE((INT32) (tmp2 - tmp5), 3) + + & RANGE_MASK]; + + outptr[4] = range_limit[(int) DESCALE((INT32) (tmp3 + tmp4), 3) + + & RANGE_MASK]; + + outptr[3] = range_limit[(int) DESCALE((INT32) (tmp3 - tmp4), 3) + + & RANGE_MASK]; + + + + wsptr += DCTSIZE; /* advance pointer to next row */ + + } + +} + + + +#endif /* DCT_FLOAT_SUPPORTED */ + diff --git a/libs/jpeg6/jinclude.h b/libs/jpeg6/jinclude.h new file mode 100644 index 00000000..5ff60fed --- /dev/null +++ b/libs/jpeg6/jinclude.h @@ -0,0 +1,91 @@ +/* + * jinclude.h + * + * Copyright (C) 1991-1994, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file exists to provide a single place to fix any problems with + * including the wrong system include files. (Common problems are taken + * care of by the standard jconfig symbols, but on really weird systems + * you may have to edit this file.) + * + * NOTE: this file is NOT intended to be included by applications using the + * JPEG library. Most applications need only include jpeglib.h. + */ + + +/* Include auto-config file to find out which system include files we need. */ + +#include "jconfig.h" /* auto configuration options */ +#define JCONFIG_INCLUDED /* so that jpeglib.h doesn't do it again */ + +/* + * We need the NULL macro and size_t typedef. + * On an ANSI-conforming system it is sufficient to include . + * Otherwise, we get them from or ; we may have to + * pull in as well. + * Note that the core JPEG library does not require ; + * only the default error handler and data source/destination modules do. + * But we must pull it in because of the references to FILE in jpeglib.h. + * You can remove those references if you want to compile without . + */ + +#ifdef HAVE_STDDEF_H +#include +#endif + +#ifdef HAVE_STDLIB_H +#include +#endif + +#ifdef NEED_SYS_TYPES_H +#include +#endif + +#include + +/* + * We need memory copying and zeroing functions, plus strncpy(). + * ANSI and System V implementations declare these in . + * BSD doesn't have the mem() functions, but it does have bcopy()/bzero(). + * Some systems may declare memset and memcpy in . + * + * NOTE: we assume the size parameters to these functions are of type size_t. + * Change the casts in these macros if not! + */ + +#ifdef NEED_BSD_STRINGS + +#include +#define MEMZERO(target,size) bzero((void *)(target), (size_t)(size)) +#define MEMCOPY(dest,src,size) bcopy((const void *)(src), (void *)(dest), (size_t)(size)) + +#else /* not BSD, assume ANSI/SysV string lib */ + +#include +#define MEMZERO(target,size) memset((void *)(target), 0, (size_t)(size)) +#define MEMCOPY(dest,src,size) memcpy((void *)(dest), (const void *)(src), (size_t)(size)) + +#endif + +/* + * In ANSI C, and indeed any rational implementation, size_t is also the + * type returned by sizeof(). However, it seems there are some irrational + * implementations out there, in which sizeof() returns an int even though + * size_t is defined as long or unsigned long. To ensure consistent results + * we always use this SIZEOF() macro in place of using sizeof() directly. + */ + +#define SIZEOF(object) ((size_t) sizeof(object)) + +/* + * The modules that use fread() and fwrite() always invoke them through + * these macros. On some systems you may need to twiddle the argument casts. + * CAUTION: argument order is different from underlying functions! + */ + +#define JFREAD(file,buf,sizeofbuf) \ + ((size_t) fread((void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) +#define JFWRITE(file,buf,sizeofbuf) \ + ((size_t) fwrite((const void *) (buf), (size_t) 1, (size_t) (sizeofbuf), (file))) diff --git a/libs/jpeg6/jmemmgr.cpp b/libs/jpeg6/jmemmgr.cpp new file mode 100644 index 00000000..9204b324 --- /dev/null +++ b/libs/jpeg6/jmemmgr.cpp @@ -0,0 +1,2230 @@ +/* + + * jmemmgr.c + + * + + * Copyright (C) 1991-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains the JPEG system-independent memory management + + * routines. This code is usable across a wide variety of machines; most + + * of the system dependencies have been isolated in a separate file. + + * The major functions provided here are: + + * * pool-based allocation and freeing of memory; + + * * policy decisions about how to divide available memory among the + + * virtual arrays; + + * * control logic for swapping virtual arrays between main memory and + + * backing storage. + + * The separate system-dependent file provides the actual backing-storage + + * access code, and it contains the policy decision about how much total + + * main memory to use. + + * This file is system-dependent in the sense that some of its functions + + * are unnecessary in some systems. For example, if there is enough virtual + + * memory so that backing storage will never be used, much of the virtual + + * array control logic could be removed. (Of course, if you have that much + + * memory then you shouldn't care about a little bit of unused code...) + + */ + + + +#define JPEG_INTERNALS + +#define AM_MEMORY_MANAGER /* we define jvirt_Xarray_control structs */ + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + +#include "jmemsys.h" /* import the system-dependent declarations */ + + + +#ifndef NO_GETENV + +#ifndef HAVE_STDLIB_H /* should declare getenv() */ + +extern char * getenv JPP((const char * name)); + +#endif + +#endif + + + + + +/* + + * Some important notes: + + * The allocation routines provided here must never return NULL. + + * They should exit to error_exit if unsuccessful. + + * + + * It's not a good idea to try to merge the sarray and barray routines, + + * even though they are textually almost the same, because samples are + + * usually stored as bytes while coefficients are shorts or ints. Thus, + + * in machines where byte pointers have a different representation from + + * word pointers, the resulting machine code could not be the same. + + */ + + + + + +/* + + * Many machines require storage alignment: longs must start on 4-byte + + * boundaries, doubles on 8-byte boundaries, etc. On such machines, malloc() + + * always returns pointers that are multiples of the worst-case alignment + + * requirement, and we had better do so too. + + * There isn't any really portable way to determine the worst-case alignment + + * requirement. This module assumes that the alignment requirement is + + * multiples of sizeof(ALIGN_TYPE). + + * By default, we define ALIGN_TYPE as double. This is necessary on some + + * workstations (where doubles really do need 8-byte alignment) and will work + + * fine on nearly everything. If your machine has lesser alignment needs, + + * you can save a few bytes by making ALIGN_TYPE smaller. + + * The only place I know of where this will NOT work is certain Macintosh + + * 680x0 compilers that define double as a 10-byte IEEE extended float. + + * Doing 10-byte alignment is counterproductive because longwords won't be + + * aligned well. Put "#define ALIGN_TYPE long" in jconfig.h if you have + + * such a compiler. + + */ + + + +#ifndef ALIGN_TYPE /* so can override from jconfig.h */ + +#define ALIGN_TYPE double + +#endif + + + + + +/* + + * We allocate objects from "pools", where each pool is gotten with a single + + * request to jpeg_get_small() or jpeg_get_large(). There is no per-object + + * overhead within a pool, except for alignment padding. Each pool has a + + * header with a link to the next pool of the same class. + + * Small and large pool headers are identical except that the latter's + + * link pointer must be FAR on 80x86 machines. + + * Notice that the "real" header fields are union'ed with a dummy ALIGN_TYPE + + * field. This forces the compiler to make SIZEOF(small_pool_hdr) a multiple + + * of the alignment requirement of ALIGN_TYPE. + + */ + + + +typedef union small_pool_struct * small_pool_ptr; + + + +typedef union small_pool_struct { + + struct { + + small_pool_ptr next; /* next in list of pools */ + + size_t bytes_used; /* how many bytes already used within pool */ + + size_t bytes_left; /* bytes still available in this pool */ + + } hdr; + + ALIGN_TYPE dummy; /* included in union to ensure alignment */ + +} small_pool_hdr; + + + +typedef union large_pool_struct FAR * large_pool_ptr; + + + +typedef union large_pool_struct { + + struct { + + large_pool_ptr next; /* next in list of pools */ + + size_t bytes_used; /* how many bytes already used within pool */ + + size_t bytes_left; /* bytes still available in this pool */ + + } hdr; + + ALIGN_TYPE dummy; /* included in union to ensure alignment */ + +} large_pool_hdr; + + + + + +/* + + * Here is the full definition of a memory manager object. + + */ + + + +typedef struct { + + struct jpeg_memory_mgr pub; /* public fields */ + + + + /* Each pool identifier (lifetime class) names a linked list of pools. */ + + small_pool_ptr small_list[JPOOL_NUMPOOLS]; + + large_pool_ptr large_list[JPOOL_NUMPOOLS]; + + + + /* Since we only have one lifetime class of virtual arrays, only one + + * linked list is necessary (for each datatype). Note that the virtual + + * array control blocks being linked together are actually stored somewhere + + * in the small-pool list. + + */ + + jvirt_sarray_ptr virt_sarray_list; + + jvirt_barray_ptr virt_barray_list; + + + + /* This counts total space obtained from jpeg_get_small/large */ + + long total_space_allocated; + + + + /* alloc_sarray and alloc_barray set this value for use by virtual + + * array routines. + + */ + + JDIMENSION last_rowsperchunk; /* from most recent alloc_sarray/barray */ + +} my_memory_mgr; + + + +typedef my_memory_mgr * my_mem_ptr; + + + + + +/* + + * The control blocks for virtual arrays. + + * Note that these blocks are allocated in the "small" pool area. + + * System-dependent info for the associated backing store (if any) is hidden + + * inside the backing_store_info struct. + + */ + + + +struct jvirt_sarray_control { + + JSAMPARRAY mem_buffer; /* => the in-memory buffer */ + + JDIMENSION rows_in_array; /* total virtual array height */ + + JDIMENSION samplesperrow; /* width of array (and of memory buffer) */ + + JDIMENSION maxaccess; /* max rows accessed by access_virt_sarray */ + + JDIMENSION rows_in_mem; /* height of memory buffer */ + + JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ + + JDIMENSION cur_start_row; /* first logical row # in the buffer */ + + JDIMENSION first_undef_row; /* row # of first uninitialized row */ + + boolean pre_zero; /* pre-zero mode requested? */ + + boolean dirty; /* do current buffer contents need written? */ + + boolean b_s_open; /* is backing-store data valid? */ + + jvirt_sarray_ptr next; /* link to next virtual sarray control block */ + + backing_store_info b_s_info; /* System-dependent control info */ + +}; + + + +struct jvirt_barray_control { + + JBLOCKARRAY mem_buffer; /* => the in-memory buffer */ + + JDIMENSION rows_in_array; /* total virtual array height */ + + JDIMENSION blocksperrow; /* width of array (and of memory buffer) */ + + JDIMENSION maxaccess; /* max rows accessed by access_virt_barray */ + + JDIMENSION rows_in_mem; /* height of memory buffer */ + + JDIMENSION rowsperchunk; /* allocation chunk size in mem_buffer */ + + JDIMENSION cur_start_row; /* first logical row # in the buffer */ + + JDIMENSION first_undef_row; /* row # of first uninitialized row */ + + boolean pre_zero; /* pre-zero mode requested? */ + + boolean dirty; /* do current buffer contents need written? */ + + boolean b_s_open; /* is backing-store data valid? */ + + jvirt_barray_ptr next; /* link to next virtual barray control block */ + + backing_store_info b_s_info; /* System-dependent control info */ + +}; + + + + + +#ifdef MEM_STATS /* optional extra stuff for statistics */ + + + +LOCAL void + +print_mem_stats (j_common_ptr cinfo, int pool_id) + +{ + + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + + small_pool_ptr shdr_ptr; + + large_pool_ptr lhdr_ptr; + + + + /* Since this is only a debugging stub, we can cheat a little by using + + * fprintf directly rather than going through the trace message code. + + * This is helpful because message parm array can't handle longs. + + */ + + fprintf(stderr, "Freeing pool %d, total space = %ld\n", + + pool_id, mem->total_space_allocated); + + + + for (lhdr_ptr = mem->large_list[pool_id]; lhdr_ptr != NULL; + + lhdr_ptr = lhdr_ptr->hdr.next) { + + fprintf(stderr, " Large chunk used %ld\n", + + (long) lhdr_ptr->hdr.bytes_used); + + } + + + + for (shdr_ptr = mem->small_list[pool_id]; shdr_ptr != NULL; + + shdr_ptr = shdr_ptr->hdr.next) { + + fprintf(stderr, " Small chunk used %ld free %ld\n", + + (long) shdr_ptr->hdr.bytes_used, + + (long) shdr_ptr->hdr.bytes_left); + + } + +} + + + +#endif /* MEM_STATS */ + + + + + +LOCAL void + +out_of_memory (j_common_ptr cinfo, int which) + +/* Report an out-of-memory error and stop execution */ + +/* If we compiled MEM_STATS support, report alloc requests before dying */ + +{ + +#ifdef MEM_STATS + + cinfo->err->trace_level = 2; /* force self_destruct to report stats */ + +#endif + + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, which); + +} + + + + + +/* + + * Allocation of "small" objects. + + * + + * For these, we use pooled storage. When a new pool must be created, + + * we try to get enough space for the current request plus a "slop" factor, + + * where the slop will be the amount of leftover space in the new pool. + + * The speed vs. space tradeoff is largely determined by the slop values. + + * A different slop value is provided for each pool class (lifetime), + + * and we also distinguish the first pool of a class from later ones. + + * NOTE: the values given work fairly well on both 16- and 32-bit-int + + * machines, but may be too small if longs are 64 bits or more. + + */ + + + +static const size_t first_pool_slop[JPOOL_NUMPOOLS] = + +{ + + 1600, /* first PERMANENT pool */ + + 16000 /* first IMAGE pool */ + +}; + + + +static const size_t extra_pool_slop[JPOOL_NUMPOOLS] = + +{ + + 0, /* additional PERMANENT pools */ + + 5000 /* additional IMAGE pools */ + +}; + + + +#define MIN_SLOP 50 /* greater than 0 to avoid futile looping */ + + + + + +METHODDEF void * + +alloc_small (j_common_ptr cinfo, int pool_id, size_t sizeofobject) + +/* Allocate a "small" object */ + +{ + + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + + small_pool_ptr hdr_ptr, prev_hdr_ptr; + + char * data_ptr; + + size_t odd_bytes, min_request, slop; + + + + /* Check for unsatisfiable request (do now to ensure no overflow below) */ + + if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(small_pool_hdr))) + + out_of_memory(cinfo, 1); /* request exceeds malloc's ability */ + + + + /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ + + odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); + + if (odd_bytes > 0) + + sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; + + + + /* See if space is available in any existing pool */ + + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + prev_hdr_ptr = NULL; + + hdr_ptr = mem->small_list[pool_id]; + + while (hdr_ptr != NULL) { + + if (hdr_ptr->hdr.bytes_left >= sizeofobject) + + break; /* found pool with enough space */ + + prev_hdr_ptr = hdr_ptr; + + hdr_ptr = hdr_ptr->hdr.next; + + } + + + + /* Time to make a new pool? */ + + if (hdr_ptr == NULL) { + + /* min_request is what we need now, slop is what will be leftover */ + + min_request = sizeofobject + SIZEOF(small_pool_hdr); + + if (prev_hdr_ptr == NULL) /* first pool in class? */ + + slop = first_pool_slop[pool_id]; + + else + + slop = extra_pool_slop[pool_id]; + + /* Don't ask for more than MAX_ALLOC_CHUNK */ + + if (slop > (size_t) (MAX_ALLOC_CHUNK-min_request)) + + slop = (size_t) (MAX_ALLOC_CHUNK-min_request); + + /* Try to get space, if fail reduce slop and try again */ + + for (;;) { + + hdr_ptr = (small_pool_ptr) jpeg_get_small(cinfo, min_request + slop); + + if (hdr_ptr != NULL) + + break; + + slop /= 2; + + if (slop < MIN_SLOP) /* give up when it gets real small */ + + out_of_memory(cinfo, 2); /* jpeg_get_small failed */ + + } + + mem->total_space_allocated += min_request + slop; + + /* Success, initialize the new pool header and add to end of list */ + + hdr_ptr->hdr.next = NULL; + + hdr_ptr->hdr.bytes_used = 0; + + hdr_ptr->hdr.bytes_left = sizeofobject + slop; + + if (prev_hdr_ptr == NULL) /* first pool in class? */ + + mem->small_list[pool_id] = hdr_ptr; + + else + + prev_hdr_ptr->hdr.next = hdr_ptr; + + } + + + + /* OK, allocate the object from the current pool */ + + data_ptr = (char *) (hdr_ptr + 1); /* point to first data byte in pool */ + + data_ptr += hdr_ptr->hdr.bytes_used; /* point to place for object */ + + hdr_ptr->hdr.bytes_used += sizeofobject; + + hdr_ptr->hdr.bytes_left -= sizeofobject; + + + + return (void *) data_ptr; + +} + + + + + +/* + + * Allocation of "large" objects. + + * + + * The external semantics of these are the same as "small" objects, + + * except that FAR pointers are used on 80x86. However the pool + + * management heuristics are quite different. We assume that each + + * request is large enough that it may as well be passed directly to + + * jpeg_get_large; the pool management just links everything together + + * so that we can free it all on demand. + + * Note: the major use of "large" objects is in JSAMPARRAY and JBLOCKARRAY + + * structures. The routines that create these structures (see below) + + * deliberately bunch rows together to ensure a large request size. + + */ + + + +METHODDEF void FAR * + +alloc_large (j_common_ptr cinfo, int pool_id, size_t sizeofobject) + +/* Allocate a "large" object */ + +{ + + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + + large_pool_ptr hdr_ptr; + + size_t odd_bytes; + + + + /* Check for unsatisfiable request (do now to ensure no overflow below) */ + + if (sizeofobject > (size_t) (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr))) + + out_of_memory(cinfo, 3); /* request exceeds malloc's ability */ + + + + /* Round up the requested size to a multiple of SIZEOF(ALIGN_TYPE) */ + + odd_bytes = sizeofobject % SIZEOF(ALIGN_TYPE); + + if (odd_bytes > 0) + + sizeofobject += SIZEOF(ALIGN_TYPE) - odd_bytes; + + + + /* Always make a new pool */ + + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + + + hdr_ptr = (large_pool_ptr) jpeg_get_large(cinfo, sizeofobject + + + SIZEOF(large_pool_hdr)); + + if (hdr_ptr == NULL) + + out_of_memory(cinfo, 4); /* jpeg_get_large failed */ + + mem->total_space_allocated += sizeofobject + SIZEOF(large_pool_hdr); + + + + /* Success, initialize the new pool header and add to list */ + + hdr_ptr->hdr.next = mem->large_list[pool_id]; + + /* We maintain space counts in each pool header for statistical purposes, + + * even though they are not needed for allocation. + + */ + + hdr_ptr->hdr.bytes_used = sizeofobject; + + hdr_ptr->hdr.bytes_left = 0; + + mem->large_list[pool_id] = hdr_ptr; + + + + return (void FAR *) (hdr_ptr + 1); /* point to first data byte in pool */ + +} + + + + + +/* + + * Creation of 2-D sample arrays. + + * The pointers are in near heap, the samples themselves in FAR heap. + + * + + * To minimize allocation overhead and to allow I/O of large contiguous + + * blocks, we allocate the sample rows in groups of as many rows as possible + + * without exceeding MAX_ALLOC_CHUNK total bytes per allocation request. + + * NB: the virtual array control routines, later in this file, know about + + * this chunking of rows. The rowsperchunk value is left in the mem manager + + * object so that it can be saved away if this sarray is the workspace for + + * a virtual array. + + */ + + + +METHODDEF JSAMPARRAY + +alloc_sarray (j_common_ptr cinfo, int pool_id, + + JDIMENSION samplesperrow, JDIMENSION numrows) + +/* Allocate a 2-D sample array */ + +{ + + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + + JSAMPARRAY result; + + JSAMPROW workspace; + + JDIMENSION rowsperchunk, currow, i; + + long ltemp; + + + + /* Calculate max # of rows allowed in one allocation chunk */ + + ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / + + ((long) samplesperrow * SIZEOF(JSAMPLE)); + + if (ltemp <= 0) + + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + if (ltemp < (long) numrows) + + rowsperchunk = (JDIMENSION) ltemp; + + else + + rowsperchunk = numrows; + + mem->last_rowsperchunk = rowsperchunk; + + + + /* Get space for row pointers (small object) */ + + result = (JSAMPARRAY) alloc_small(cinfo, pool_id, + + (size_t) (numrows * SIZEOF(JSAMPROW))); + + + + /* Get the rows themselves (large objects) */ + + currow = 0; + + while (currow < numrows) { + + rowsperchunk = MIN(rowsperchunk, numrows - currow); + + workspace = (JSAMPROW) alloc_large(cinfo, pool_id, + + (size_t) ((size_t) rowsperchunk * (size_t) samplesperrow + + * SIZEOF(JSAMPLE))); + + for (i = rowsperchunk; i > 0; i--) { + + result[currow++] = workspace; + + workspace += samplesperrow; + + } + + } + + + + return result; + +} + + + + + +/* + + * Creation of 2-D coefficient-block arrays. + + * This is essentially the same as the code for sample arrays, above. + + */ + + + +METHODDEF JBLOCKARRAY + +alloc_barray (j_common_ptr cinfo, int pool_id, + + JDIMENSION blocksperrow, JDIMENSION numrows) + +/* Allocate a 2-D coefficient-block array */ + +{ + + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + + JBLOCKARRAY result; + + JBLOCKROW workspace; + + JDIMENSION rowsperchunk, currow, i; + + long ltemp; + + + + /* Calculate max # of rows allowed in one allocation chunk */ + + ltemp = (MAX_ALLOC_CHUNK-SIZEOF(large_pool_hdr)) / + + ((long) blocksperrow * SIZEOF(JBLOCK)); + + if (ltemp <= 0) + + ERREXIT(cinfo, JERR_WIDTH_OVERFLOW); + + if (ltemp < (long) numrows) + + rowsperchunk = (JDIMENSION) ltemp; + + else + + rowsperchunk = numrows; + + mem->last_rowsperchunk = rowsperchunk; + + + + /* Get space for row pointers (small object) */ + + result = (JBLOCKARRAY) alloc_small(cinfo, pool_id, + + (size_t) (numrows * SIZEOF(JBLOCKROW))); + + + + /* Get the rows themselves (large objects) */ + + currow = 0; + + while (currow < numrows) { + + rowsperchunk = MIN(rowsperchunk, numrows - currow); + + workspace = (JBLOCKROW) alloc_large(cinfo, pool_id, + + (size_t) ((size_t) rowsperchunk * (size_t) blocksperrow + + * SIZEOF(JBLOCK))); + + for (i = rowsperchunk; i > 0; i--) { + + result[currow++] = workspace; + + workspace += blocksperrow; + + } + + } + + + + return result; + +} + + + + + +/* + + * About virtual array management: + + * + + * The above "normal" array routines are only used to allocate strip buffers + + * (as wide as the image, but just a few rows high). Full-image-sized buffers + + * are handled as "virtual" arrays. The array is still accessed a strip at a + + * time, but the memory manager must save the whole array for repeated + + * accesses. The intended implementation is that there is a strip buffer in + + * memory (as high as is possible given the desired memory limit), plus a + + * backing file that holds the rest of the array. + + * + + * The request_virt_array routines are told the total size of the image and + + * the maximum number of rows that will be accessed at once. The in-memory + + * buffer must be at least as large as the maxaccess value. + + * + + * The request routines create control blocks but not the in-memory buffers. + + * That is postponed until realize_virt_arrays is called. At that time the + + * total amount of space needed is known (approximately, anyway), so free + + * memory can be divided up fairly. + + * + + * The access_virt_array routines are responsible for making a specific strip + + * area accessible (after reading or writing the backing file, if necessary). + + * Note that the access routines are told whether the caller intends to modify + + * the accessed strip; during a read-only pass this saves having to rewrite + + * data to disk. The access routines are also responsible for pre-zeroing + + * any newly accessed rows, if pre-zeroing was requested. + + * + + * In current usage, the access requests are usually for nonoverlapping + + * strips; that is, successive access start_row numbers differ by exactly + + * num_rows = maxaccess. This means we can get good performance with simple + + * buffer dump/reload logic, by making the in-memory buffer be a multiple + + * of the access height; then there will never be accesses across bufferload + + * boundaries. The code will still work with overlapping access requests, + + * but it doesn't handle bufferload overlaps very efficiently. + + */ + + + + + +METHODDEF jvirt_sarray_ptr + +request_virt_sarray (j_common_ptr cinfo, int pool_id, boolean pre_zero, + + JDIMENSION samplesperrow, JDIMENSION numrows, + + JDIMENSION maxaccess) + +/* Request a virtual 2-D sample array */ + +{ + + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + + jvirt_sarray_ptr result; + + + + /* Only IMAGE-lifetime virtual arrays are currently supported */ + + if (pool_id != JPOOL_IMAGE) + + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + + + /* get control block */ + + result = (jvirt_sarray_ptr) alloc_small(cinfo, pool_id, + + SIZEOF(struct jvirt_sarray_control)); + + + + result->mem_buffer = NULL; /* marks array not yet realized */ + + result->rows_in_array = numrows; + + result->samplesperrow = samplesperrow; + + result->maxaccess = maxaccess; + + result->pre_zero = pre_zero; + + result->b_s_open = FALSE; /* no associated backing-store object */ + + result->next = mem->virt_sarray_list; /* add to list of virtual arrays */ + + mem->virt_sarray_list = result; + + + + return result; + +} + + + + + +METHODDEF jvirt_barray_ptr + +request_virt_barray (j_common_ptr cinfo, int pool_id, boolean pre_zero, + + JDIMENSION blocksperrow, JDIMENSION numrows, + + JDIMENSION maxaccess) + +/* Request a virtual 2-D coefficient-block array */ + +{ + + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + + jvirt_barray_ptr result; + + + + /* Only IMAGE-lifetime virtual arrays are currently supported */ + + if (pool_id != JPOOL_IMAGE) + + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + + + /* get control block */ + + result = (jvirt_barray_ptr) alloc_small(cinfo, pool_id, + + SIZEOF(struct jvirt_barray_control)); + + + + result->mem_buffer = NULL; /* marks array not yet realized */ + + result->rows_in_array = numrows; + + result->blocksperrow = blocksperrow; + + result->maxaccess = maxaccess; + + result->pre_zero = pre_zero; + + result->b_s_open = FALSE; /* no associated backing-store object */ + + result->next = mem->virt_barray_list; /* add to list of virtual arrays */ + + mem->virt_barray_list = result; + + + + return result; + +} + + + + + +METHODDEF void + +realize_virt_arrays (j_common_ptr cinfo) + +/* Allocate the in-memory buffers for any unrealized virtual arrays */ + +{ + + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + + long space_per_minheight, maximum_space, avail_mem; + + long minheights, max_minheights; + + jvirt_sarray_ptr sptr; + + jvirt_barray_ptr bptr; + + + + /* Compute the minimum space needed (maxaccess rows in each buffer) + + * and the maximum space needed (full image height in each buffer). + + * These may be of use to the system-dependent jpeg_mem_available routine. + + */ + + space_per_minheight = 0; + + maximum_space = 0; + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + + if (sptr->mem_buffer == NULL) { /* if not realized yet */ + + space_per_minheight += (long) sptr->maxaccess * + + (long) sptr->samplesperrow * SIZEOF(JSAMPLE); + + maximum_space += (long) sptr->rows_in_array * + + (long) sptr->samplesperrow * SIZEOF(JSAMPLE); + + } + + } + + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + + if (bptr->mem_buffer == NULL) { /* if not realized yet */ + + space_per_minheight += (long) bptr->maxaccess * + + (long) bptr->blocksperrow * SIZEOF(JBLOCK); + + maximum_space += (long) bptr->rows_in_array * + + (long) bptr->blocksperrow * SIZEOF(JBLOCK); + + } + + } + + + + if (space_per_minheight <= 0) + + return; /* no unrealized arrays, no work */ + + + + /* Determine amount of memory to actually use; this is system-dependent. */ + + avail_mem = jpeg_mem_available(cinfo, space_per_minheight, maximum_space, + + mem->total_space_allocated); + + + + /* If the maximum space needed is available, make all the buffers full + + * height; otherwise parcel it out with the same number of minheights + + * in each buffer. + + */ + + if (avail_mem >= maximum_space) + + max_minheights = 1000000000L; + + else { + + max_minheights = avail_mem / space_per_minheight; + + /* If there doesn't seem to be enough space, try to get the minimum + + * anyway. This allows a "stub" implementation of jpeg_mem_available(). + + */ + + if (max_minheights <= 0) + + max_minheights = 1; + + } + + + + /* Allocate the in-memory buffers and initialize backing store as needed. */ + + + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + + if (sptr->mem_buffer == NULL) { /* if not realized yet */ + + minheights = ((long) sptr->rows_in_array - 1L) / sptr->maxaccess + 1L; + + if (minheights <= max_minheights) { + + /* This buffer fits in memory */ + + sptr->rows_in_mem = sptr->rows_in_array; + + } else { + + /* It doesn't fit in memory, create backing store. */ + + sptr->rows_in_mem = (JDIMENSION) (max_minheights * sptr->maxaccess); + + jpeg_open_backing_store(cinfo, & sptr->b_s_info, + + (long) sptr->rows_in_array * + + (long) sptr->samplesperrow * + + (long) SIZEOF(JSAMPLE)); + + sptr->b_s_open = TRUE; + + } + + sptr->mem_buffer = alloc_sarray(cinfo, JPOOL_IMAGE, + + sptr->samplesperrow, sptr->rows_in_mem); + + sptr->rowsperchunk = mem->last_rowsperchunk; + + sptr->cur_start_row = 0; + + sptr->first_undef_row = 0; + + sptr->dirty = FALSE; + + } + + } + + + + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + + if (bptr->mem_buffer == NULL) { /* if not realized yet */ + + minheights = ((long) bptr->rows_in_array - 1L) / bptr->maxaccess + 1L; + + if (minheights <= max_minheights) { + + /* This buffer fits in memory */ + + bptr->rows_in_mem = bptr->rows_in_array; + + } else { + + /* It doesn't fit in memory, create backing store. */ + + bptr->rows_in_mem = (JDIMENSION) (max_minheights * bptr->maxaccess); + + jpeg_open_backing_store(cinfo, & bptr->b_s_info, + + (long) bptr->rows_in_array * + + (long) bptr->blocksperrow * + + (long) SIZEOF(JBLOCK)); + + bptr->b_s_open = TRUE; + + } + + bptr->mem_buffer = alloc_barray(cinfo, JPOOL_IMAGE, + + bptr->blocksperrow, bptr->rows_in_mem); + + bptr->rowsperchunk = mem->last_rowsperchunk; + + bptr->cur_start_row = 0; + + bptr->first_undef_row = 0; + + bptr->dirty = FALSE; + + } + + } + +} + + + + + +LOCAL void + +do_sarray_io (j_common_ptr cinfo, jvirt_sarray_ptr ptr, boolean writing) + +/* Do backing store read or write of a virtual sample array */ + +{ + + long bytesperrow, file_offset, byte_count, rows, thisrow, i; + + + + bytesperrow = (long) ptr->samplesperrow * SIZEOF(JSAMPLE); + + file_offset = ptr->cur_start_row * bytesperrow; + + /* Loop to read or write each allocation chunk in mem_buffer */ + + for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { + + /* One chunk, but check for short chunk at end of buffer */ + + rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); + + /* Transfer no more than is currently defined */ + + thisrow = (long) ptr->cur_start_row + i; + + rows = MIN(rows, (long) ptr->first_undef_row - thisrow); + + /* Transfer no more than fits in file */ + + rows = MIN(rows, (long) ptr->rows_in_array - thisrow); + + if (rows <= 0) /* this chunk might be past end of file! */ + + break; + + byte_count = rows * bytesperrow; + + if (writing) + + (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, + + (void FAR *) ptr->mem_buffer[i], + + file_offset, byte_count); + + else + + (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, + + (void FAR *) ptr->mem_buffer[i], + + file_offset, byte_count); + + file_offset += byte_count; + + } + +} + + + + + +LOCAL void + +do_barray_io (j_common_ptr cinfo, jvirt_barray_ptr ptr, boolean writing) + +/* Do backing store read or write of a virtual coefficient-block array */ + +{ + + long bytesperrow, file_offset, byte_count, rows, thisrow, i; + + + + bytesperrow = (long) ptr->blocksperrow * SIZEOF(JBLOCK); + + file_offset = ptr->cur_start_row * bytesperrow; + + /* Loop to read or write each allocation chunk in mem_buffer */ + + for (i = 0; i < (long) ptr->rows_in_mem; i += ptr->rowsperchunk) { + + /* One chunk, but check for short chunk at end of buffer */ + + rows = MIN((long) ptr->rowsperchunk, (long) ptr->rows_in_mem - i); + + /* Transfer no more than is currently defined */ + + thisrow = (long) ptr->cur_start_row + i; + + rows = MIN(rows, (long) ptr->first_undef_row - thisrow); + + /* Transfer no more than fits in file */ + + rows = MIN(rows, (long) ptr->rows_in_array - thisrow); + + if (rows <= 0) /* this chunk might be past end of file! */ + + break; + + byte_count = rows * bytesperrow; + + if (writing) + + (*ptr->b_s_info.write_backing_store) (cinfo, & ptr->b_s_info, + + (void FAR *) ptr->mem_buffer[i], + + file_offset, byte_count); + + else + + (*ptr->b_s_info.read_backing_store) (cinfo, & ptr->b_s_info, + + (void FAR *) ptr->mem_buffer[i], + + file_offset, byte_count); + + file_offset += byte_count; + + } + +} + + + + + +METHODDEF JSAMPARRAY + +access_virt_sarray (j_common_ptr cinfo, jvirt_sarray_ptr ptr, + + JDIMENSION start_row, JDIMENSION num_rows, + + boolean writable) + +/* Access the part of a virtual sample array starting at start_row */ + +/* and extending for num_rows rows. writable is true if */ + +/* caller intends to modify the accessed area. */ + +{ + + JDIMENSION end_row = start_row + num_rows; + + JDIMENSION undef_row; + + + + /* debugging check */ + + if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || + + ptr->mem_buffer == NULL) + + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + + + /* Make the desired part of the virtual array accessible */ + + if (start_row < ptr->cur_start_row || + + end_row > ptr->cur_start_row+ptr->rows_in_mem) { + + if (! ptr->b_s_open) + + ERREXIT(cinfo, JERR_VIRTUAL_BUG); + + /* Flush old buffer contents if necessary */ + + if (ptr->dirty) { + + do_sarray_io(cinfo, ptr, TRUE); + + ptr->dirty = FALSE; + + } + + /* Decide what part of virtual array to access. + + * Algorithm: if target address > current window, assume forward scan, + + * load starting at target address. If target address < current window, + + * assume backward scan, load so that target area is top of window. + + * Note that when switching from forward write to forward read, will have + + * start_row = 0, so the limiting case applies and we load from 0 anyway. + + */ + + if (start_row > ptr->cur_start_row) { + + ptr->cur_start_row = start_row; + + } else { + + /* use long arithmetic here to avoid overflow & unsigned problems */ + + long ltemp; + + + + ltemp = (long) end_row - (long) ptr->rows_in_mem; + + if (ltemp < 0) + + ltemp = 0; /* don't fall off front end of file */ + + ptr->cur_start_row = (JDIMENSION) ltemp; + + } + + /* Read in the selected part of the array. + + * During the initial write pass, we will do no actual read + + * because the selected part is all undefined. + + */ + + do_sarray_io(cinfo, ptr, FALSE); + + } + + /* Ensure the accessed part of the array is defined; prezero if needed. + + * To improve locality of access, we only prezero the part of the array + + * that the caller is about to access, not the entire in-memory array. + + */ + + if (ptr->first_undef_row < end_row) { + + if (ptr->first_undef_row < start_row) { + + if (writable) /* writer skipped over a section of array */ + + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + undef_row = start_row; /* but reader is allowed to read ahead */ + + } else { + + undef_row = ptr->first_undef_row; + + } + + if (writable) + + ptr->first_undef_row = end_row; + + if (ptr->pre_zero) { + + size_t bytesperrow = (size_t) ptr->samplesperrow * SIZEOF(JSAMPLE); + + undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ + + end_row -= ptr->cur_start_row; + + while (undef_row < end_row) { + + jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); + + undef_row++; + + } + + } else { + + if (! writable) /* reader looking at undefined data */ + + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + } + + } + + /* Flag the buffer dirty if caller will write in it */ + + if (writable) + + ptr->dirty = TRUE; + + /* Return address of proper part of the buffer */ + + return ptr->mem_buffer + (start_row - ptr->cur_start_row); + +} + + + + + +METHODDEF JBLOCKARRAY + +access_virt_barray (j_common_ptr cinfo, jvirt_barray_ptr ptr, + + JDIMENSION start_row, JDIMENSION num_rows, + + boolean writable) + +/* Access the part of a virtual block array starting at start_row */ + +/* and extending for num_rows rows. writable is true if */ + +/* caller intends to modify the accessed area. */ + +{ + + JDIMENSION end_row = start_row + num_rows; + + JDIMENSION undef_row; + + + + /* debugging check */ + + if (end_row > ptr->rows_in_array || num_rows > ptr->maxaccess || + + ptr->mem_buffer == NULL) + + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + + + /* Make the desired part of the virtual array accessible */ + + if (start_row < ptr->cur_start_row || + + end_row > ptr->cur_start_row+ptr->rows_in_mem) { + + if (! ptr->b_s_open) + + ERREXIT(cinfo, JERR_VIRTUAL_BUG); + + /* Flush old buffer contents if necessary */ + + if (ptr->dirty) { + + do_barray_io(cinfo, ptr, TRUE); + + ptr->dirty = FALSE; + + } + + /* Decide what part of virtual array to access. + + * Algorithm: if target address > current window, assume forward scan, + + * load starting at target address. If target address < current window, + + * assume backward scan, load so that target area is top of window. + + * Note that when switching from forward write to forward read, will have + + * start_row = 0, so the limiting case applies and we load from 0 anyway. + + */ + + if (start_row > ptr->cur_start_row) { + + ptr->cur_start_row = start_row; + + } else { + + /* use long arithmetic here to avoid overflow & unsigned problems */ + + long ltemp; + + + + ltemp = (long) end_row - (long) ptr->rows_in_mem; + + if (ltemp < 0) + + ltemp = 0; /* don't fall off front end of file */ + + ptr->cur_start_row = (JDIMENSION) ltemp; + + } + + /* Read in the selected part of the array. + + * During the initial write pass, we will do no actual read + + * because the selected part is all undefined. + + */ + + do_barray_io(cinfo, ptr, FALSE); + + } + + /* Ensure the accessed part of the array is defined; prezero if needed. + + * To improve locality of access, we only prezero the part of the array + + * that the caller is about to access, not the entire in-memory array. + + */ + + if (ptr->first_undef_row < end_row) { + + if (ptr->first_undef_row < start_row) { + + if (writable) /* writer skipped over a section of array */ + + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + undef_row = start_row; /* but reader is allowed to read ahead */ + + } else { + + undef_row = ptr->first_undef_row; + + } + + if (writable) + + ptr->first_undef_row = end_row; + + if (ptr->pre_zero) { + + size_t bytesperrow = (size_t) ptr->blocksperrow * SIZEOF(JBLOCK); + + undef_row -= ptr->cur_start_row; /* make indexes relative to buffer */ + + end_row -= ptr->cur_start_row; + + while (undef_row < end_row) { + + jzero_far((void FAR *) ptr->mem_buffer[undef_row], bytesperrow); + + undef_row++; + + } + + } else { + + if (! writable) /* reader looking at undefined data */ + + ERREXIT(cinfo, JERR_BAD_VIRTUAL_ACCESS); + + } + + } + + /* Flag the buffer dirty if caller will write in it */ + + if (writable) + + ptr->dirty = TRUE; + + /* Return address of proper part of the buffer */ + + return ptr->mem_buffer + (start_row - ptr->cur_start_row); + +} + + + + + +/* + + * Release all objects belonging to a specified pool. + + */ + + + +METHODDEF void + +free_pool (j_common_ptr cinfo, int pool_id) + +{ + + my_mem_ptr mem = (my_mem_ptr) cinfo->mem; + + small_pool_ptr shdr_ptr; + + large_pool_ptr lhdr_ptr; + + size_t space_freed; + + + + if (pool_id < 0 || pool_id >= JPOOL_NUMPOOLS) + + ERREXIT1(cinfo, JERR_BAD_POOL_ID, pool_id); /* safety check */ + + + +#ifdef MEM_STATS + + if (cinfo->err->trace_level > 1) + + print_mem_stats(cinfo, pool_id); /* print pool's memory usage statistics */ + +#endif + + + + /* If freeing IMAGE pool, close any virtual arrays first */ + + if (pool_id == JPOOL_IMAGE) { + + jvirt_sarray_ptr sptr; + + jvirt_barray_ptr bptr; + + + + for (sptr = mem->virt_sarray_list; sptr != NULL; sptr = sptr->next) { + + if (sptr->b_s_open) { /* there may be no backing store */ + + sptr->b_s_open = FALSE; /* prevent recursive close if error */ + + (*sptr->b_s_info.close_backing_store) (cinfo, & sptr->b_s_info); + + } + + } + + mem->virt_sarray_list = NULL; + + for (bptr = mem->virt_barray_list; bptr != NULL; bptr = bptr->next) { + + if (bptr->b_s_open) { /* there may be no backing store */ + + bptr->b_s_open = FALSE; /* prevent recursive close if error */ + + (*bptr->b_s_info.close_backing_store) (cinfo, & bptr->b_s_info); + + } + + } + + mem->virt_barray_list = NULL; + + } + + + + /* Release large objects */ + + lhdr_ptr = mem->large_list[pool_id]; + + mem->large_list[pool_id] = NULL; + + + + while (lhdr_ptr != NULL) { + + large_pool_ptr next_lhdr_ptr = lhdr_ptr->hdr.next; + + space_freed = lhdr_ptr->hdr.bytes_used + + + lhdr_ptr->hdr.bytes_left + + + SIZEOF(large_pool_hdr); + + jpeg_free_large(cinfo, (void FAR *) lhdr_ptr, space_freed); + + mem->total_space_allocated -= space_freed; + + lhdr_ptr = next_lhdr_ptr; + + } + + + + /* Release small objects */ + + shdr_ptr = mem->small_list[pool_id]; + + mem->small_list[pool_id] = NULL; + + + + while (shdr_ptr != NULL) { + + small_pool_ptr next_shdr_ptr = shdr_ptr->hdr.next; + + space_freed = shdr_ptr->hdr.bytes_used + + + shdr_ptr->hdr.bytes_left + + + SIZEOF(small_pool_hdr); + + jpeg_free_small(cinfo, (void *) shdr_ptr, space_freed); + + mem->total_space_allocated -= space_freed; + + shdr_ptr = next_shdr_ptr; + + } + +} + + + + + +/* + + * Close up shop entirely. + + * Note that this cannot be called unless cinfo->mem is non-NULL. + + */ + + + +METHODDEF void + +self_destruct (j_common_ptr cinfo) + +{ + + int pool; + + + + /* Close all backing store, release all memory. + + * Releasing pools in reverse order might help avoid fragmentation + + * with some (brain-damaged) malloc libraries. + + */ + + for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { + + free_pool(cinfo, pool); + + } + + + + /* Release the memory manager control block too. */ + + jpeg_free_small(cinfo, (void *) cinfo->mem, SIZEOF(my_memory_mgr)); + + cinfo->mem = NULL; /* ensures I will be called only once */ + + + + jpeg_mem_term(cinfo); /* system-dependent cleanup */ + +} + + + + + +/* + + * Memory manager initialization. + + * When this is called, only the error manager pointer is valid in cinfo! + + */ + + + +GLOBAL void + +jinit_memory_mgr (j_common_ptr cinfo) + +{ + + my_mem_ptr mem; + + long max_to_use; + + int pool; + + size_t test_mac; + + + + cinfo->mem = NULL; /* for safety if init fails */ + + + + /* Check for configuration errors. + + * SIZEOF(ALIGN_TYPE) should be a power of 2; otherwise, it probably + + * doesn't reflect any real hardware alignment requirement. + + * The test is a little tricky: for X>0, X and X-1 have no one-bits + + * in common if and only if X is a power of 2, ie has only one one-bit. + + * Some compilers may give an "unreachable code" warning here; ignore it. + + */ + + if ((SIZEOF(ALIGN_TYPE) & (SIZEOF(ALIGN_TYPE)-1)) != 0) + + ERREXIT(cinfo, JERR_BAD_ALIGN_TYPE); + + /* MAX_ALLOC_CHUNK must be representable as type size_t, and must be + + * a multiple of SIZEOF(ALIGN_TYPE). + + * Again, an "unreachable code" warning may be ignored here. + + * But a "constant too large" warning means you need to fix MAX_ALLOC_CHUNK. + + */ + + test_mac = (size_t) MAX_ALLOC_CHUNK; + + if ((long) test_mac != MAX_ALLOC_CHUNK || + + (MAX_ALLOC_CHUNK % SIZEOF(ALIGN_TYPE)) != 0) + + ERREXIT(cinfo, JERR_BAD_ALLOC_CHUNK); + + + + max_to_use = jpeg_mem_init(cinfo); /* system-dependent initialization */ + + + + /* Attempt to allocate memory manager's control block */ + + mem = (my_mem_ptr) jpeg_get_small(cinfo, SIZEOF(my_memory_mgr)); + + + + if (mem == NULL) { + + jpeg_mem_term(cinfo); /* system-dependent cleanup */ + + ERREXIT1(cinfo, JERR_OUT_OF_MEMORY, 0); + + } + + + + /* OK, fill in the method pointers */ + + mem->pub.alloc_small = alloc_small; + + mem->pub.alloc_large = alloc_large; + + mem->pub.alloc_sarray = alloc_sarray; + + mem->pub.alloc_barray = alloc_barray; + + mem->pub.request_virt_sarray = request_virt_sarray; + + mem->pub.request_virt_barray = request_virt_barray; + + mem->pub.realize_virt_arrays = realize_virt_arrays; + + mem->pub.access_virt_sarray = access_virt_sarray; + + mem->pub.access_virt_barray = access_virt_barray; + + mem->pub.free_pool = free_pool; + + mem->pub.self_destruct = self_destruct; + + + + /* Initialize working state */ + + mem->pub.max_memory_to_use = max_to_use; + + + + for (pool = JPOOL_NUMPOOLS-1; pool >= JPOOL_PERMANENT; pool--) { + + mem->small_list[pool] = NULL; + + mem->large_list[pool] = NULL; + + } + + mem->virt_sarray_list = NULL; + + mem->virt_barray_list = NULL; + + + + mem->total_space_allocated = SIZEOF(my_memory_mgr); + + + + /* Declare ourselves open for business */ + + cinfo->mem = & mem->pub; + + + + /* Check for an environment variable JPEGMEM; if found, override the + + * default max_memory setting from jpeg_mem_init. Note that the + + * surrounding application may again override this value. + + * If your system doesn't support getenv(), define NO_GETENV to disable + + * this feature. + + */ + +#ifndef NO_GETENV + + { char * memenv; + + + + if ((memenv = getenv("JPEGMEM")) != NULL) { + + char ch = 'x'; + + + + if (sscanf(memenv, "%ld%c", &max_to_use, &ch) > 0) { + + if (ch == 'm' || ch == 'M') + + max_to_use *= 1000L; + + mem->pub.max_memory_to_use = max_to_use * 1000L; + + } + + } + + } + +#endif + + + +} + diff --git a/libs/jpeg6/jmemnobs.cpp b/libs/jpeg6/jmemnobs.cpp new file mode 100644 index 00000000..bd236e54 --- /dev/null +++ b/libs/jpeg6/jmemnobs.cpp @@ -0,0 +1,206 @@ +/* + + * jmemnobs.c + + * + + * Copyright (C) 1992-1994, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file provides a really simple implementation of the system- + + * dependent portion of the JPEG memory manager. This implementation + + * assumes that no backing-store files are needed: all required space + + * can be obtained from ri.Malloc(). + + * This is very portable in the sense that it'll compile on almost anything, + + * but you'd better have lots of main memory (or virtual memory) if you want + + * to process big images. + + * Note that the max_memory_to_use option is ignored by this implementation. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + +#include "jmemsys.h" /* import the system-dependent declarations */ + + + +/* + + * Memory allocation and ri.Freeing are controlled by the regular library + + * routines ri.Malloc() and ri.Free(). + + */ + + + +GLOBAL void * + +jpeg_get_small (j_common_ptr cinfo, size_t sizeofobject) + +{ + + return (void *) malloc(sizeofobject); + +} + + + +GLOBAL void + +jpeg_free_small (j_common_ptr cinfo, void * object, size_t sizeofobject) + +{ + + free(object); + +} + + + + + +/* + + * "Large" objects are treated the same as "small" ones. + + * NB: although we include FAR keywords in the routine declarations, + + * this file won't actually work in 80x86 small/medium model; at least, + + * you probably won't be able to process useful-size images in only 64KB. + + */ + + + +GLOBAL void FAR * + +jpeg_get_large (j_common_ptr cinfo, size_t sizeofobject) + +{ + + return (void FAR *) malloc(sizeofobject); + +} + + + +GLOBAL void + +jpeg_free_large (j_common_ptr cinfo, void FAR * object, size_t sizeofobject) + +{ + + free(object); + +} + + + + + +/* + + * This routine computes the total memory space available for allocation. + + * Here we always say, "we got all you want bud!" + + */ + + + +GLOBAL long + +jpeg_mem_available (j_common_ptr cinfo, long min_bytes_needed, + + long max_bytes_needed, long already_allocated) + +{ + + return max_bytes_needed; + +} + + + + + +/* + + * Backing store (temporary file) management. + + * Since jpeg_mem_available always promised the moon, + + * this should never be called and we can just error out. + + */ + + + +GLOBAL void + +jpeg_open_backing_store (j_common_ptr cinfo, backing_store_ptr info, + + long total_bytes_needed) + +{ + + ERREXIT(cinfo, JERR_NO_BACKING_STORE); + +} + + + + + +/* + + * These routines take care of any system-dependent initialization and + + * cleanup required. Here, there isn't any. + + */ + + + +GLOBAL long + +jpeg_mem_init (j_common_ptr cinfo) + +{ + + return 0; /* just set max_memory_to_use to 0 */ + +} + + + +GLOBAL void + +jpeg_mem_term (j_common_ptr cinfo) + +{ + + /* no work */ + +} + diff --git a/libs/jpeg6/jmemsys.h b/libs/jpeg6/jmemsys.h new file mode 100644 index 00000000..9c8028bc --- /dev/null +++ b/libs/jpeg6/jmemsys.h @@ -0,0 +1,364 @@ +/* + + * jmemsys.h + + * + + * Copyright (C) 1992-1994, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This include file defines the interface between the system-independent + + * and system-dependent portions of the JPEG memory manager. No other + + * modules need include it. (The system-independent portion is jmemmgr.c; + + * there are several different versions of the system-dependent portion.) + + * + + * This file works as-is for the system-dependent memory managers supplied + + * in the IJG distribution. You may need to modify it if you write a + + * custom memory manager. If system-dependent changes are needed in + + * this file, the best method is to #ifdef them based on a configuration + + * symbol supplied in jconfig.h, as we have done with USE_MSDOS_MEMMGR. + + */ + + + + + +/* Short forms of external names for systems with brain-damaged linkers. */ + + + +#ifdef NEED_SHORT_EXTERNAL_NAMES + +#define jpeg_get_small jGetSmall + +#define jpeg_free_small jFreeSmall + +#define jpeg_get_large jGetLarge + +#define jpeg_free_large jFreeLarge + +#define jpeg_mem_available jMemAvail + +#define jpeg_open_backing_store jOpenBackStore + +#define jpeg_mem_init jMemInit + +#define jpeg_mem_term jMemTerm + +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + + + + +/* + + * These two functions are used to allocate and release small chunks of + + * memory. (Typically the total amount requested through jpeg_get_small is + + * no more than 20K or so; this will be requested in chunks of a few K each.) + + * Behavior should be the same as for the standard library functions malloc + + * and free; in particular, jpeg_get_small must return NULL on failure. + + * On most systems, these ARE malloc and free. jpeg_free_small is passed the + + * size of the object being freed, just in case it's needed. + + * On an 80x86 machine using small-data memory model, these manage near heap. + + */ + + + +EXTERN void * jpeg_get_small JPP((j_common_ptr cinfo, size_t sizeofobject)); + +EXTERN void jpeg_free_small JPP((j_common_ptr cinfo, void * object, + + size_t sizeofobject)); + + + +/* + + * These two functions are used to allocate and release large chunks of + + * memory (up to the total free space designated by jpeg_mem_available). + + * The interface is the same as above, except that on an 80x86 machine, + + * far pointers are used. On most other machines these are identical to + + * the jpeg_get/free_small routines; but we keep them separate anyway, + + * in case a different allocation strategy is desirable for large chunks. + + */ + + + +EXTERN void FAR * jpeg_get_large JPP((j_common_ptr cinfo,size_t sizeofobject)); + +EXTERN void jpeg_free_large JPP((j_common_ptr cinfo, void FAR * object, + + size_t sizeofobject)); + + + +/* + + * The macro MAX_ALLOC_CHUNK designates the maximum number of bytes that may + + * be requested in a single call to jpeg_get_large (and jpeg_get_small for that + + * matter, but that case should never come into play). This macro is needed + + * to model the 64Kb-segment-size limit of far addressing on 80x86 machines. + + * On those machines, we expect that jconfig.h will provide a proper value. + + * On machines with 32-bit flat address spaces, any large constant may be used. + + * + + * NB: jmemmgr.c expects that MAX_ALLOC_CHUNK will be representable as type + + * size_t and will be a multiple of sizeof(align_type). + + */ + + + +#ifndef MAX_ALLOC_CHUNK /* may be overridden in jconfig.h */ + +#define MAX_ALLOC_CHUNK 1000000000L + +#endif + + + +/* + + * This routine computes the total space still available for allocation by + + * jpeg_get_large. If more space than this is needed, backing store will be + + * used. NOTE: any memory already allocated must not be counted. + + * + + * There is a minimum space requirement, corresponding to the minimum + + * feasible buffer sizes; jmemmgr.c will request that much space even if + + * jpeg_mem_available returns zero. The maximum space needed, enough to hold + + * all working storage in memory, is also passed in case it is useful. + + * Finally, the total space already allocated is passed. If no better + + * method is available, cinfo->mem->max_memory_to_use - already_allocated + + * is often a suitable calculation. + + * + + * It is OK for jpeg_mem_available to underestimate the space available + + * (that'll just lead to more backing-store access than is really necessary). + + * However, an overestimate will lead to failure. Hence it's wise to subtract + + * a slop factor from the true available space. 5% should be enough. + + * + + * On machines with lots of virtual memory, any large constant may be returned. + + * Conversely, zero may be returned to always use the minimum amount of memory. + + */ + + + +EXTERN long jpeg_mem_available JPP((j_common_ptr cinfo, + + long min_bytes_needed, + + long max_bytes_needed, + + long already_allocated)); + + + + + +/* + + * This structure holds whatever state is needed to access a single + + * backing-store object. The read/write/close method pointers are called + + * by jmemmgr.c to manipulate the backing-store object; all other fields + + * are private to the system-dependent backing store routines. + + */ + + + +#define TEMP_NAME_LENGTH 64 /* max length of a temporary file's name */ + + + +#ifdef USE_MSDOS_MEMMGR /* DOS-specific junk */ + + + +typedef unsigned short XMSH; /* type of extended-memory handles */ + +typedef unsigned short EMSH; /* type of expanded-memory handles */ + + + +typedef union { + + short file_handle; /* DOS file handle if it's a temp file */ + + XMSH xms_handle; /* handle if it's a chunk of XMS */ + + EMSH ems_handle; /* handle if it's a chunk of EMS */ + +} handle_union; + + + +#endif /* USE_MSDOS_MEMMGR */ + + + +typedef struct backing_store_struct * backing_store_ptr; + + + +typedef struct backing_store_struct { + + /* Methods for reading/writing/closing this backing-store object */ + + JMETHOD(void, read_backing_store, (j_common_ptr cinfo, + + backing_store_ptr info, + + void FAR * buffer_address, + + long file_offset, long byte_count)); + + JMETHOD(void, write_backing_store, (j_common_ptr cinfo, + + backing_store_ptr info, + + void FAR * buffer_address, + + long file_offset, long byte_count)); + + JMETHOD(void, close_backing_store, (j_common_ptr cinfo, + + backing_store_ptr info)); + + + + /* Private fields for system-dependent backing-store management */ + +#ifdef USE_MSDOS_MEMMGR + + /* For the MS-DOS manager (jmemdos.c), we need: */ + + handle_union handle; /* reference to backing-store storage object */ + + char temp_name[TEMP_NAME_LENGTH]; /* name if it's a file */ + +#else + + /* For a typical implementation with temp files, we need: */ + + FILE * temp_file; /* stdio reference to temp file */ + + char temp_name[TEMP_NAME_LENGTH]; /* name of temp file */ + +#endif + +} backing_store_info; + + + +/* + + * Initial opening of a backing-store object. This must fill in the + + * read/write/close pointers in the object. The read/write routines + + * may take an error exit if the specified maximum file size is exceeded. + + * (If jpeg_mem_available always returns a large value, this routine can + + * just take an error exit.) + + */ + + + +EXTERN void jpeg_open_backing_store JPP((j_common_ptr cinfo, + + backing_store_ptr info, + + long total_bytes_needed)); + + + + + +/* + + * These routines take care of any system-dependent initialization and + + * cleanup required. jpeg_mem_init will be called before anything is + + * allocated (and, therefore, nothing in cinfo is of use except the error + + * manager pointer). It should return a suitable default value for + + * max_memory_to_use; this may subsequently be overridden by the surrounding + + * application. (Note that max_memory_to_use is only important if + + * jpeg_mem_available chooses to consult it ... no one else will.) + + * jpeg_mem_term may assume that all requested memory has been freed and that + + * all opened backing-store objects have been closed. + + */ + + + +EXTERN long jpeg_mem_init JPP((j_common_ptr cinfo)); + +EXTERN void jpeg_mem_term JPP((j_common_ptr cinfo)); + diff --git a/libs/jpeg6/jmorecfg.h b/libs/jpeg6/jmorecfg.h new file mode 100644 index 00000000..afb6e26c --- /dev/null +++ b/libs/jpeg6/jmorecfg.h @@ -0,0 +1,693 @@ +/* + + * jmorecfg.h + + * + + * Copyright (C) 1991-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains additional configuration options that customize the + + * JPEG software for special applications or support machine-dependent + + * optimizations. Most users will not need to touch this file. + + */ + + + + + +/* + + * Define BITS_IN_JSAMPLE as either + + * 8 for 8-bit sample values (the usual setting) + + * 12 for 12-bit sample values + + * Only 8 and 12 are legal data precisions for lossy JPEG according to the + + * JPEG standard, and the IJG code does not support anything else! + + * We do not support run-time selection of data precision, sorry. + + */ + + + +#define BITS_IN_JSAMPLE 8 /* use 8 or 12 */ + + + + + +/* + + * Maximum number of components (color channels) allowed in JPEG image. + + * To meet the letter of the JPEG spec, set this to 255. However, darn + + * few applications need more than 4 channels (maybe 5 for CMYK + alpha + + * mask). We recommend 10 as a reasonable compromise; use 4 if you are + + * really short on memory. (Each allowed component costs a hundred or so + + * bytes of storage, whether actually used in an image or not.) + + */ + + + +#define MAX_COMPONENTS 10 /* maximum number of image components */ + + + + + +/* + + * Basic data types. + + * You may need to change these if you have a machine with unusual data + + * type sizes; for example, "char" not 8 bits, "short" not 16 bits, + + * or "long" not 32 bits. We don't care whether "int" is 16 or 32 bits, + + * but it had better be at least 16. + + */ + + + +/* Representation of a single sample (pixel element value). + + * We frequently allocate large arrays of these, so it's important to keep + + * them small. But if you have memory to burn and access to char or short + + * arrays is very slow on your hardware, you might want to change these. + + */ + + + +#if BITS_IN_JSAMPLE == 8 + +/* JSAMPLE should be the smallest type that will hold the values 0..255. + + * You can use a signed char by having GETJSAMPLE mask it with 0xFF. + + */ + + + +#ifdef HAVE_UNSIGNED_CHAR + + + +typedef unsigned char JSAMPLE; + +#define GETJSAMPLE(value) ((int) (value)) + + + +#else /* not HAVE_UNSIGNED_CHAR */ + + + +typedef char JSAMPLE; + +#ifdef CHAR_IS_UNSIGNED + +#define GETJSAMPLE(value) ((int) (value)) + +#else + +#define GETJSAMPLE(value) ((int) (value) & 0xFF) + +#endif /* CHAR_IS_UNSIGNED */ + + + +#endif /* HAVE_UNSIGNED_CHAR */ + + + +#define MAXJSAMPLE 255 + +#define CENTERJSAMPLE 128 + + + +#endif /* BITS_IN_JSAMPLE == 8 */ + + + + + +#if BITS_IN_JSAMPLE == 12 + +/* JSAMPLE should be the smallest type that will hold the values 0..4095. + + * On nearly all machines "short" will do nicely. + + */ + + + +typedef short JSAMPLE; + +#define GETJSAMPLE(value) ((int) (value)) + + + +#define MAXJSAMPLE 4095 + +#define CENTERJSAMPLE 2048 + + + +#endif /* BITS_IN_JSAMPLE == 12 */ + + + + + +/* Representation of a DCT frequency coefficient. + + * This should be a signed value of at least 16 bits; "short" is usually OK. + + * Again, we allocate large arrays of these, but you can change to int + + * if you have memory to burn and "short" is really slow. + + */ + + + +typedef short JCOEF; + + + + + +/* Compressed datastreams are represented as arrays of JOCTET. + + * These must be EXACTLY 8 bits wide, at least once they are written to + + * external storage. Note that when using the stdio data source/destination + + * managers, this is also the data type passed to fread/fwrite. + + */ + + + +#ifdef HAVE_UNSIGNED_CHAR + + + +typedef unsigned char JOCTET; + +#define GETJOCTET(value) (value) + + + +#else /* not HAVE_UNSIGNED_CHAR */ + + + +typedef char JOCTET; + +#ifdef CHAR_IS_UNSIGNED + +#define GETJOCTET(value) (value) + +#else + +#define GETJOCTET(value) ((value) & 0xFF) + +#endif /* CHAR_IS_UNSIGNED */ + + + +#endif /* HAVE_UNSIGNED_CHAR */ + + + + + +/* These typedefs are used for various table entries and so forth. + + * They must be at least as wide as specified; but making them too big + + * won't cost a huge amount of memory, so we don't provide special + + * extraction code like we did for JSAMPLE. (In other words, these + + * typedefs live at a different point on the speed/space tradeoff curve.) + + */ + + + +/* UINT8 must hold at least the values 0..255. */ + + + +#ifdef HAVE_UNSIGNED_CHAR + +typedef unsigned char UINT8; + +#else /* not HAVE_UNSIGNED_CHAR */ + +#ifdef CHAR_IS_UNSIGNED + +typedef char UINT8; + +#else /* not CHAR_IS_UNSIGNED */ + +typedef short UINT8; + +#endif /* CHAR_IS_UNSIGNED */ + +#endif /* HAVE_UNSIGNED_CHAR */ + + + +/* UINT16 must hold at least the values 0..65535. */ + + + +#ifdef HAVE_UNSIGNED_SHORT + +typedef unsigned short UINT16; + +#else /* not HAVE_UNSIGNED_SHORT */ + +typedef unsigned int UINT16; + +#endif /* HAVE_UNSIGNED_SHORT */ + + + +/* INT16 must hold at least the values -32768..32767. */ + + + +#ifndef XMD_H /* X11/xmd.h correctly defines INT16 */ + +typedef short INT16; + +#endif + + + +/* INT32 must hold at least signed 32-bit values. */ + + + +//#ifndef XMD_H /* X11/xmd.h correctly defines INT32 */ + +//typedef long INT32; + +//#endif + + + +/* Datatype used for image dimensions. The JPEG standard only supports + + * images up to 64K*64K due to 16-bit fields in SOF markers. Therefore + + * "unsigned int" is sufficient on all machines. However, if you need to + + * handle larger images and you don't mind deviating from the spec, you + + * can change this datatype. + + */ + + + +typedef unsigned int JDIMENSION; + + + +#define JPEG_MAX_DIMENSION 65500L /* a tad under 64K to prevent overflows */ + + + + + +/* These defines are used in all function definitions and extern declarations. + + * You could modify them if you need to change function linkage conventions. + + * Another application is to make all functions global for use with debuggers + + * or code profilers that require it. + + */ + + + +#define METHODDEF static /* a function called through method pointers */ + +#define LOCAL static /* a function used only in its module */ + +#define GLOBAL /* a function referenced thru EXTERNs */ + +#define EXTERN extern /* a reference to a GLOBAL function */ + + + + + +/* Here is the pseudo-keyword for declaring pointers that must be "far" + + * on 80x86 machines. Most of the specialized coding for 80x86 is handled + + * by just saying "FAR *" where such a pointer is needed. In a few places + + * explicit coding is needed; see uses of the NEED_FAR_POINTERS symbol. + + */ + + + +#ifdef NEED_FAR_POINTERS + +#undef FAR + +#define FAR far + +#else + +#undef FAR + +#define FAR + +#endif + + + + + +/* + + * On a few systems, type boolean and/or its values FALSE, TRUE may appear + + * in standard header files. Or you may have conflicts with application- + + * specific header files that you want to include together with these files. + + * Defining HAVE_BOOLEAN before including jpeglib.h should make it work. + + */ + + + +//#ifndef HAVE_BOOLEAN + +//typedef int boolean; + +//#endif + +#ifndef FALSE /* in case these macros already exist */ + +#define FALSE 0 /* values of boolean */ + +#endif + +#ifndef TRUE + +#define TRUE 1 + +#endif + + + + + +/* + + * The remaining options affect code selection within the JPEG library, + + * but they don't need to be visible to most applications using the library. + + * To minimize application namespace pollution, the symbols won't be + + * defined unless JPEG_INTERNALS or JPEG_INTERNAL_OPTIONS has been defined. + + */ + + + +#ifdef JPEG_INTERNALS + +#define JPEG_INTERNAL_OPTIONS + +#endif + + + +#ifdef JPEG_INTERNAL_OPTIONS + + + + + +/* + + * These defines indicate whether to include various optional functions. + + * Undefining some of these symbols will produce a smaller but less capable + + * library. Note that you can leave certain source files out of the + + * compilation/linking process if you've #undef'd the corresponding symbols. + + * (You may HAVE to do that if your compiler doesn't like null source files.) + + */ + + + +/* Arithmetic coding is unsupported for legal reasons. Complaints to IBM. */ + + + +/* Capability options common to encoder and decoder: */ + + + +#undef DCT_ISLOW_SUPPORTED /* slow but accurate integer algorithm */ + +#undef DCT_IFAST_SUPPORTED /* faster, less accurate integer method */ + +#define DCT_FLOAT_SUPPORTED /* floating-point: accurate, fast on fast HW */ + + + +/* Encoder capability options: */ + + + +#undef C_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ + +#define C_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ + +#define C_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ + +#define ENTROPY_OPT_SUPPORTED /* Optimization of entropy coding parms? */ + +/* Note: if you selected 12-bit data precision, it is dangerous to turn off + + * ENTROPY_OPT_SUPPORTED. The standard Huffman tables are only good for 8-bit + + * precision, so jchuff.c normally uses entropy optimization to compute + + * usable tables for higher precision. If you don't want to do optimization, + + * you'll have to supply different default Huffman tables. + + * The exact same statements apply for progressive JPEG: the default tables + + * don't work for progressive mode. (This may get fixed, however.) + + */ + +#define INPUT_SMOOTHING_SUPPORTED /* Input image smoothing option? */ + + + +/* Decoder capability options: */ + + + +#undef D_ARITH_CODING_SUPPORTED /* Arithmetic coding back end? */ + +#undef D_MULTISCAN_FILES_SUPPORTED /* Multiple-scan JPEG files? */ + +#undef D_PROGRESSIVE_SUPPORTED /* Progressive JPEG? (Requires MULTISCAN)*/ + +#undef BLOCK_SMOOTHING_SUPPORTED /* Block smoothing? (Progressive only) */ + +#undef IDCT_SCALING_SUPPORTED /* Output rescaling via IDCT? */ + +#undef UPSAMPLE_SCALING_SUPPORTED /* Output rescaling at upsample stage? */ + +#undef UPSAMPLE_MERGING_SUPPORTED /* Fast path for sloppy upsampling? */ + +#undef QUANT_1PASS_SUPPORTED /* 1-pass color quantization? */ + +#undef QUANT_2PASS_SUPPORTED /* 2-pass color quantization? */ + + + +/* more capability options later, no doubt */ + + + + + +/* + + * Ordering of RGB data in scanlines passed to or from the application. + + * If your application wants to deal with data in the order B,G,R, just + + * change these macros. You can also deal with formats such as R,G,B,X + + * (one extra byte per pixel) by changing RGB_PIXELSIZE. Note that changing + + * the offsets will also change the order in which colormap data is organized. + + * RESTRICTIONS: + + * 1. The sample applications cjpeg,djpeg do NOT support modified RGB formats. + + * 2. These macros only affect RGB<=>YCbCr color conversion, so they are not + + * useful if you are using JPEG color spaces other than YCbCr or grayscale. + + * 3. The color quantizer modules will not behave desirably if RGB_PIXELSIZE + + * is not 3 (they don't understand about dummy color components!). So you + + * can't use color quantization if you change that value. + + */ + + + +#define RGB_RED 0 /* Offset of Red in an RGB scanline element */ + +#define RGB_GREEN 1 /* Offset of Green */ + +#define RGB_BLUE 2 /* Offset of Blue */ + +// http://zerowing.idsoftware.com/bugzilla/show_bug.cgi?id=900 +// ydnar: setting this fucks jpeg loading in q3map2, disabling "fix" (3) +#define RGB_PIXELSIZE 4 /* JSAMPLEs per RGB scanline element */ + + + + + +/* Definitions for speed-related optimizations. */ + + + + + +/* If your compiler supports inline functions, define INLINE + + * as the inline keyword; otherwise define it as empty. + + */ + + + +#ifndef INLINE + +#ifdef __GNUC__ /* for instance, GNU C knows about inline */ + +#define INLINE __inline__ + +#endif + +#ifndef INLINE + +#define INLINE /* default is to define it as empty */ + +#endif + +#endif + + + + + +/* On some machines (notably 68000 series) "int" is 32 bits, but multiplying + + * two 16-bit shorts is faster than multiplying two ints. Define MULTIPLIER + + * as short on such a machine. MULTIPLIER must be at least 16 bits wide. + + */ + + + +#ifndef MULTIPLIER + +#define MULTIPLIER int /* type for fastest integer multiply */ + +#endif + + + + + +/* FAST_FLOAT should be either float or double, whichever is done faster + + * by your compiler. (Note that this type is only used in the floating point + + * DCT routines, so it only matters if you've defined DCT_FLOAT_SUPPORTED.) + + * Typically, float is faster in ANSI C compilers, while double is faster in + + * pre-ANSI compilers (because they insist on converting to double anyway). + + * The code below therefore chooses float if we have ANSI-style prototypes. + + */ + + + +#ifndef FAST_FLOAT + +#ifdef HAVE_PROTOTYPES + +#define FAST_FLOAT float + +#else + +#define FAST_FLOAT double + +#endif + +#endif + + + +#endif /* JPEG_INTERNAL_OPTIONS */ diff --git a/libs/jpeg6/jpeg6.vcproj b/libs/jpeg6/jpeg6.vcproj new file mode 100644 index 00000000..a763fd29 --- /dev/null +++ b/libs/jpeg6/jpeg6.vcproj @@ -0,0 +1,113 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/jpeg6/jpegint.h b/libs/jpeg6/jpegint.h new file mode 100644 index 00000000..9b02525d --- /dev/null +++ b/libs/jpeg6/jpegint.h @@ -0,0 +1,776 @@ +/* + + * jpegint.h + + * + + * Copyright (C) 1991-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file provides common declarations for the various JPEG modules. + + * These declarations are considered internal to the JPEG library; most + + * applications using the library shouldn't need to include this file. + + */ + + + + + +/* Declarations for both compression & decompression */ + + + +typedef enum { /* Operating modes for buffer controllers */ + + JBUF_PASS_THRU, /* Plain stripwise operation */ + + /* Remaining modes require a full-image buffer to have been created */ + + JBUF_SAVE_SOURCE, /* Run source subobject only, save output */ + + JBUF_CRANK_DEST, /* Run dest subobject only, using saved data */ + + JBUF_SAVE_AND_PASS /* Run both subobjects, save output */ + +} J_BUF_MODE; + + + +/* Values of global_state field (jdapi.c has some dependencies on ordering!) */ + +#define CSTATE_START 100 /* after create_compress */ + +#define CSTATE_SCANNING 101 /* start_compress done, write_scanlines OK */ + +#define CSTATE_RAW_OK 102 /* start_compress done, write_raw_data OK */ + +#define CSTATE_WRCOEFS 103 /* jpeg_write_coefficients done */ + +#define DSTATE_START 200 /* after create_decompress */ + +#define DSTATE_INHEADER 201 /* reading header markers, no SOS yet */ + +#define DSTATE_READY 202 /* found SOS, ready for start_decompress */ + +#define DSTATE_PRELOAD 203 /* reading multiscan file in start_decompress*/ + +#define DSTATE_PRESCAN 204 /* performing dummy pass for 2-pass quant */ + +#define DSTATE_SCANNING 205 /* start_decompress done, read_scanlines OK */ + +#define DSTATE_RAW_OK 206 /* start_decompress done, read_raw_data OK */ + +#define DSTATE_BUFIMAGE 207 /* expecting jpeg_start_output */ + +#define DSTATE_BUFPOST 208 /* looking for SOS/EOI in jpeg_finish_output */ + +#define DSTATE_RDCOEFS 209 /* reading file in jpeg_read_coefficients */ + +#define DSTATE_STOPPING 210 /* looking for EOI in jpeg_finish_decompress */ + + + + + +/* Declarations for compression modules */ + + + +/* Master control module */ + +struct jpeg_comp_master { + + JMETHOD(void, prepare_for_pass, (j_compress_ptr cinfo)); + + JMETHOD(void, pass_startup, (j_compress_ptr cinfo)); + + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); + + + + /* State variables made visible to other modules */ + + boolean call_pass_startup; /* True if pass_startup must be called */ + + boolean is_last_pass; /* True during last pass */ + +}; + + + +/* Main buffer control (downsampled-data buffer) */ + +struct jpeg_c_main_controller { + + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + + JMETHOD(void, process_data, (j_compress_ptr cinfo, + + JSAMPARRAY input_buf, JDIMENSION *in_row_ctr, + + JDIMENSION in_rows_avail)); + +}; + + + +/* Compression preprocessing (downsampling input buffer control) */ + +struct jpeg_c_prep_controller { + + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + + JMETHOD(void, pre_process_data, (j_compress_ptr cinfo, + + JSAMPARRAY input_buf, + + JDIMENSION *in_row_ctr, + + JDIMENSION in_rows_avail, + + JSAMPIMAGE output_buf, + + JDIMENSION *out_row_group_ctr, + + JDIMENSION out_row_groups_avail)); + +}; + + + +/* Coefficient buffer control */ + +struct jpeg_c_coef_controller { + + JMETHOD(void, start_pass, (j_compress_ptr cinfo, J_BUF_MODE pass_mode)); + + JMETHOD(boolean, compress_data, (j_compress_ptr cinfo, + + JSAMPIMAGE input_buf)); + +}; + + + +/* Colorspace conversion */ + +struct jpeg_color_converter { + + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + + JMETHOD(void, color_convert, (j_compress_ptr cinfo, + + JSAMPARRAY input_buf, JSAMPIMAGE output_buf, + + JDIMENSION output_row, int num_rows)); + +}; + + + +/* Downsampling */ + +struct jpeg_downsampler { + + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + + JMETHOD(void, downsample, (j_compress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION in_row_index, + + JSAMPIMAGE output_buf, + + JDIMENSION out_row_group_index)); + + + + boolean need_context_rows; /* TRUE if need rows above & below */ + +}; + + + +/* Forward DCT (also controls coefficient quantization) */ + +struct jpeg_forward_dct { + + JMETHOD(void, start_pass, (j_compress_ptr cinfo)); + + /* perhaps this should be an array??? */ + + JMETHOD(void, forward_DCT, (j_compress_ptr cinfo, + + jpeg_component_info * compptr, + + JSAMPARRAY sample_data, JBLOCKROW coef_blocks, + + JDIMENSION start_row, JDIMENSION start_col, + + JDIMENSION num_blocks)); + +}; + + + +/* Entropy encoding */ + +struct jpeg_entropy_encoder { + + JMETHOD(void, start_pass, (j_compress_ptr cinfo, boolean gather_statistics)); + + JMETHOD(boolean, encode_mcu, (j_compress_ptr cinfo, JBLOCKROW *MCU_data)); + + JMETHOD(void, finish_pass, (j_compress_ptr cinfo)); + +}; + + + +/* Marker writing */ + +struct jpeg_marker_writer { + + /* write_any_marker is exported for use by applications */ + + /* Probably only COM and APPn markers should be written */ + + JMETHOD(void, write_any_marker, (j_compress_ptr cinfo, int marker, + + const JOCTET *dataptr, unsigned int datalen)); + + JMETHOD(void, write_file_header, (j_compress_ptr cinfo)); + + JMETHOD(void, write_frame_header, (j_compress_ptr cinfo)); + + JMETHOD(void, write_scan_header, (j_compress_ptr cinfo)); + + JMETHOD(void, write_file_trailer, (j_compress_ptr cinfo)); + + JMETHOD(void, write_tables_only, (j_compress_ptr cinfo)); + +}; + + + + + +/* Declarations for decompression modules */ + + + +/* Master control module */ + +struct jpeg_decomp_master { + + JMETHOD(void, prepare_for_output_pass, (j_decompress_ptr cinfo)); + + JMETHOD(void, finish_output_pass, (j_decompress_ptr cinfo)); + + + + /* State variables made visible to other modules */ + + boolean is_dummy_pass; /* True during 1st pass for 2-pass quant */ + +}; + + + +/* Input control module */ + +struct jpeg_input_controller { + + JMETHOD(int, consume_input, (j_decompress_ptr cinfo)); + + JMETHOD(void, reset_input_controller, (j_decompress_ptr cinfo)); + + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + + JMETHOD(void, finish_input_pass, (j_decompress_ptr cinfo)); + + + + /* State variables made visible to other modules */ + + boolean has_multiple_scans; /* True if file has multiple scans */ + + boolean eoi_reached; /* True when EOI has been consumed */ + +}; + + + +/* Main buffer control (downsampled-data buffer) */ + +struct jpeg_d_main_controller { + + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + + JMETHOD(void, process_data, (j_decompress_ptr cinfo, + + JSAMPARRAY output_buf, JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail)); + +}; + + + +/* Coefficient buffer control */ + +struct jpeg_d_coef_controller { + + JMETHOD(void, start_input_pass, (j_decompress_ptr cinfo)); + + JMETHOD(int, consume_data, (j_decompress_ptr cinfo)); + + JMETHOD(void, start_output_pass, (j_decompress_ptr cinfo)); + + JMETHOD(int, decompress_data, (j_decompress_ptr cinfo, + + JSAMPIMAGE output_buf)); + + /* Pointer to array of coefficient virtual arrays, or NULL if none */ + + jvirt_barray_ptr *coef_arrays; + +}; + + + +/* Decompression postprocessing (color quantization buffer control) */ + +struct jpeg_d_post_controller { + + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, J_BUF_MODE pass_mode)); + + JMETHOD(void, post_process_data, (j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, + + JDIMENSION *in_row_group_ctr, + + JDIMENSION in_row_groups_avail, + + JSAMPARRAY output_buf, + + JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail)); + +}; + + + +/* Marker reading & parsing */ + +struct jpeg_marker_reader { + + JMETHOD(void, reset_marker_reader, (j_decompress_ptr cinfo)); + + /* Read markers until SOS or EOI. + + * Returns same codes as are defined for jpeg_consume_input: + + * JPEG_SUSPENDED, JPEG_REACHED_SOS, or JPEG_REACHED_EOI. + + */ + + JMETHOD(int, read_markers, (j_decompress_ptr cinfo)); + + /* Read a restart marker --- exported for use by entropy decoder only */ + + jpeg_marker_parser_method read_restart_marker; + + /* Application-overridable marker processing methods */ + + jpeg_marker_parser_method process_COM; + + jpeg_marker_parser_method process_APPn[16]; + + + + /* State of marker reader --- nominally internal, but applications + + * supplying COM or APPn handlers might like to know the state. + + */ + + boolean saw_SOI; /* found SOI? */ + + boolean saw_SOF; /* found SOF? */ + + int next_restart_num; /* next restart number expected (0-7) */ + + unsigned int discarded_bytes; /* # of bytes skipped looking for a marker */ + +}; + + + +/* Entropy decoding */ + +struct jpeg_entropy_decoder { + + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + + JMETHOD(boolean, decode_mcu, (j_decompress_ptr cinfo, + + JBLOCKROW *MCU_data)); + +}; + + + +/* Inverse DCT (also performs dequantization) */ + +typedef JMETHOD(void, inverse_DCT_method_ptr, + + (j_decompress_ptr cinfo, jpeg_component_info * compptr, + + JCOEFPTR coef_block, + + JSAMPARRAY output_buf, JDIMENSION output_col)); + + + +struct jpeg_inverse_dct { + + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + + /* It is useful to allow each component to have a separate IDCT method. */ + + inverse_DCT_method_ptr inverse_DCT[MAX_COMPONENTS]; + +}; + + + +/* Upsampling (note that upsampler must also call color converter) */ + +struct jpeg_upsampler { + + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + + JMETHOD(void, upsample, (j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, + + JDIMENSION *in_row_group_ctr, + + JDIMENSION in_row_groups_avail, + + JSAMPARRAY output_buf, + + JDIMENSION *out_row_ctr, + + JDIMENSION out_rows_avail)); + + + + boolean need_context_rows; /* TRUE if need rows above & below */ + +}; + + + +/* Colorspace conversion */ + +struct jpeg_color_deconverter { + + JMETHOD(void, start_pass, (j_decompress_ptr cinfo)); + + JMETHOD(void, color_convert, (j_decompress_ptr cinfo, + + JSAMPIMAGE input_buf, JDIMENSION input_row, + + JSAMPARRAY output_buf, int num_rows)); + +}; + + + +/* Color quantization or color precision reduction */ + +struct jpeg_color_quantizer { + + JMETHOD(void, start_pass, (j_decompress_ptr cinfo, boolean is_pre_scan)); + + JMETHOD(void, color_quantize, (j_decompress_ptr cinfo, + + JSAMPARRAY input_buf, JSAMPARRAY output_buf, + + int num_rows)); + + JMETHOD(void, finish_pass, (j_decompress_ptr cinfo)); + + JMETHOD(void, new_color_map, (j_decompress_ptr cinfo)); + +}; + + + + + +/* Miscellaneous useful macros */ + + + +#undef MAX + +#define MAX(a,b) ((a) > (b) ? (a) : (b)) + +#undef MIN + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + + + + + +/* We assume that right shift corresponds to signed division by 2 with + + * rounding towards minus infinity. This is correct for typical "arithmetic + + * shift" instructions that shift in copies of the sign bit. But some + + * C compilers implement >> with an unsigned shift. For these machines you + + * must define RIGHT_SHIFT_IS_UNSIGNED. + + * RIGHT_SHIFT provides a proper signed right shift of an INT32 quantity. + + * It is only applied with constant shift counts. SHIFT_TEMPS must be + + * included in the variables of any routine using RIGHT_SHIFT. + + */ + + + +#ifdef RIGHT_SHIFT_IS_UNSIGNED + +#define SHIFT_TEMPS INT32 shift_temp; + +#define RIGHT_SHIFT(x,shft) \ + + ((shift_temp = (x)) < 0 ? \ + + (shift_temp >> (shft)) | ((~((INT32) 0)) << (32-(shft))) : \ + + (shift_temp >> (shft))) + +#else + +#define SHIFT_TEMPS + +#define RIGHT_SHIFT(x,shft) ((x) >> (shft)) + +#endif + + + + + +/* Short forms of external names for systems with brain-damaged linkers. */ + + + +#ifdef NEED_SHORT_EXTERNAL_NAMES + +#define jinit_compress_master jICompress + +#define jinit_c_master_control jICMaster + +#define jinit_c_main_controller jICMainC + +#define jinit_c_prep_controller jICPrepC + +#define jinit_c_coef_controller jICCoefC + +#define jinit_color_converter jICColor + +#define jinit_downsampler jIDownsampler + +#define jinit_forward_dct jIFDCT + +#define jinit_huff_encoder jIHEncoder + +#define jinit_phuff_encoder jIPHEncoder + +#define jinit_marker_writer jIMWriter + +#define jinit_master_decompress jIDMaster + +#define jinit_d_main_controller jIDMainC + +#define jinit_d_coef_controller jIDCoefC + +#define jinit_d_post_controller jIDPostC + +#define jinit_input_controller jIInCtlr + +#define jinit_marker_reader jIMReader + +#define jinit_huff_decoder jIHDecoder + +#define jinit_phuff_decoder jIPHDecoder + +#define jinit_inverse_dct jIIDCT + +#define jinit_upsampler jIUpsampler + +#define jinit_color_deconverter jIDColor + +#define jinit_1pass_quantizer jI1Quant + +#define jinit_2pass_quantizer jI2Quant + +#define jinit_merged_upsampler jIMUpsampler + +#define jinit_memory_mgr jIMemMgr + +#define jdiv_round_up jDivRound + +#define jround_up jRound + +#define jcopy_sample_rows jCopySamples + +#define jcopy_block_row jCopyBlocks + +#define jzero_far jZeroFar + +#define jpeg_zigzag_order jZIGTable + +#define jpeg_natural_order jZAGTable + +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + + + + +/* Compression module initialization routines */ + +EXTERN void jinit_compress_master JPP((j_compress_ptr cinfo)); + +EXTERN void jinit_c_master_control JPP((j_compress_ptr cinfo, + + boolean transcode_only)); + +EXTERN void jinit_c_main_controller JPP((j_compress_ptr cinfo, + + boolean need_full_buffer)); + +EXTERN void jinit_c_prep_controller JPP((j_compress_ptr cinfo, + + boolean need_full_buffer)); + +EXTERN void jinit_c_coef_controller JPP((j_compress_ptr cinfo, + + boolean need_full_buffer)); + +EXTERN void jinit_color_converter JPP((j_compress_ptr cinfo)); + +EXTERN void jinit_downsampler JPP((j_compress_ptr cinfo)); + +EXTERN void jinit_forward_dct JPP((j_compress_ptr cinfo)); + +EXTERN void jinit_huff_encoder JPP((j_compress_ptr cinfo)); + +EXTERN void jinit_phuff_encoder JPP((j_compress_ptr cinfo)); + +EXTERN void jinit_marker_writer JPP((j_compress_ptr cinfo)); + +/* Decompression module initialization routines */ + +EXTERN void jinit_master_decompress JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_d_main_controller JPP((j_decompress_ptr cinfo, + + boolean need_full_buffer)); + +EXTERN void jinit_d_coef_controller JPP((j_decompress_ptr cinfo, + + boolean need_full_buffer)); + +EXTERN void jinit_d_post_controller JPP((j_decompress_ptr cinfo, + + boolean need_full_buffer)); + +EXTERN void jinit_input_controller JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_marker_reader JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_huff_decoder JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_phuff_decoder JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_inverse_dct JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_upsampler JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_color_deconverter JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_1pass_quantizer JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_2pass_quantizer JPP((j_decompress_ptr cinfo)); + +EXTERN void jinit_merged_upsampler JPP((j_decompress_ptr cinfo)); + +/* Memory manager initialization */ + +EXTERN void jinit_memory_mgr JPP((j_common_ptr cinfo)); + + + +/* Utility routines in jutils.c */ + +EXTERN long jdiv_round_up JPP((long a, long b)); + +EXTERN long jround_up JPP((long a, long b)); + +EXTERN void jcopy_sample_rows JPP((JSAMPARRAY input_array, int source_row, + + JSAMPARRAY output_array, int dest_row, + + int num_rows, JDIMENSION num_cols)); + +EXTERN void jcopy_block_row JPP((JBLOCKROW input_row, JBLOCKROW output_row, + + JDIMENSION num_blocks)); + +EXTERN void jzero_far JPP((void FAR * target, size_t bytestozero)); + +/* Constant tables in jutils.c */ + +extern const int jpeg_zigzag_order[]; /* natural coef order to zigzag order */ + +extern const int jpeg_natural_order[]; /* zigzag coef order to natural order */ + + + +/* Suppress undefined-structure complaints if necessary. */ + + + +#ifdef INCOMPLETE_TYPES_BROKEN + +#ifndef AM_MEMORY_MANAGER /* only jmemmgr.c defines these */ + +struct jvirt_sarray_control { long dummy; }; + +struct jvirt_barray_control { long dummy; }; + +#endif + +#endif /* INCOMPLETE_TYPES_BROKEN */ + diff --git a/libs/jpeg6/jpgload.cpp b/libs/jpeg6/jpgload.cpp new file mode 100644 index 00000000..02c021f6 --- /dev/null +++ b/libs/jpeg6/jpgload.cpp @@ -0,0 +1,167 @@ + + +#include "radiant_jpeglib.h" +#include "jerror.h" +#include + +GLOBAL int LoadJPGBuff(unsigned char *fbuffer, int bufsize, unsigned char **pic, int *width, int *height ) +{ + + /* This struct contains the JPEG decompression parameters and pointers to + * working space (which is allocated as needed by the JPEG library). + */ + struct jpeg_decompress_struct cinfo; + /* We use our private extension JPEG error handler. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + /* This struct represents a JPEG error handler. It is declared separately + * because applications often want to supply a specialized error handler + * (see the second half of this file for an example). But here we just + * take the easy way out and use the standard error handler, which will + * print a message on stderr and call exit() if compression fails. + * Note that this struct must live as long as the main JPEG parameter + * struct, to avoid dangling-pointer problems. + */ + + struct jpeg_error_mgr jerr; + /* More stuff */ + JSAMPARRAY buffer; /* Output row buffer */ + int row_stride; /* physical row width in output buffer */ + unsigned char *out, *bbuf; + int nSize; + int jmpret; + + // Rad additions: initialize the longjmp buffer + jmpret = setjmp( rad_loadfailed ); + if (jmpret != 0) + { + *pic = (unsigned char *)rad_errormsg; + return -1; + } + + /* Step 1: allocate and initialize JPEG decompression object */ + + /* We have to set up the error handler first, in case the initialization + * step fails. (Unlikely, but it could happen if you are out of memory.) + * This routine fills in the contents of struct jerr, and returns jerr's + * address which we place into the link field in cinfo. + */ + cinfo.err = jpeg_std_error(&jerr); + + /* Now we can initialize the JPEG decompression object. */ + jpeg_create_decompress(&cinfo); + + /* Step 2: specify data source (eg, a file) */ + + jpeg_stdio_src(&cinfo, fbuffer, bufsize); + + /* Step 3: read file parameters with jpeg_read_header() */ + + (void) jpeg_read_header(&cinfo, TRUE); + /* We can ignore the return value from jpeg_read_header since + * (a) suspension is not possible with the stdio data source, and + * (b) we passed TRUE to reject a tables-only JPEG file as an error. + * See libjpeg.doc for more info. + */ + + /* Step 4: set parameters for decompression */ + + /* In this example, we don't need to change any of the defaults set by + * jpeg_read_header(), so we do nothing here. + */ + + /* Step 5: Start decompressor */ + + (void) jpeg_start_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* ydnar: radiant only handles RGB, non-progressive format jpegs */ + if( cinfo.output_components != 4 ) + { + *pic = (unsigned char*) "Non-RGB JPEG encountered (unsupported)"; + return -1; + } + if( cinfo.progressive_mode ) + { + *pic = (unsigned char*) "Progressive JPEG encountered (unsupported)"; + return -1; + } + + /* We may need to do some setup of our own at this point before reading + * the data. After jpeg_start_decompress() we have the correct scaled + * output image dimensions available, as well as the output colormap + * if we asked for color quantization. + * In this example, we need to make an output work buffer of the right size. + */ + + /* JSAMPLEs per row in output buffer */ + row_stride = cinfo.output_width * cinfo.output_components; + nSize = cinfo.output_width*cinfo.output_height*cinfo.output_components; + + out = reinterpret_cast( malloc( nSize+ 1 ) ); + memset( out, 255, nSize + 1 ); + + *pic = out; + *width = cinfo.output_width; + *height = cinfo.output_height; + + /* Step 6: while (scan lines remain to be read) */ + /* jpeg_read_scanlines(...); */ + + /* Here we use the library's state variable cinfo.output_scanline as the + * loop counter, so that we don't have to keep track ourselves. + */ + while (cinfo.output_scanline < cinfo.output_height) + { + /* jpeg_read_scanlines expects an array of pointers to scanlines. + * Here the array is only one element long, but you could ask for + * more than one scanline at a time if that's more convenient. + */ + bbuf = out + row_stride * cinfo.output_scanline; + buffer = &bbuf; + (void) jpeg_read_scanlines( &cinfo, buffer, 1 ); + } + + // clear all the alphas to 255 + { + int i, j; + unsigned char *buf; + + buf = *pic; + + j = cinfo.output_width * cinfo.output_height * 4; + for ( i = 3 ; i < j ; i+=4 ) { + buf[i] = 255; + } + } + + /* Step 7: Finish decompression */ + + (void) jpeg_finish_decompress(&cinfo); + /* We can ignore the return value since suspension is not possible + * with the stdio data source. + */ + + /* Step 8: Release JPEG decompression object */ + + /* This is an important step since it will release a good deal of memory. */ + jpeg_destroy_decompress(&cinfo); + + /* After finish_decompress, we can close the input file. + * Here we postpone it until after no more JPEG errors are possible, + * so as to simplify the setjmp error logic above. (Actually, I don't + * think that jpeg_destroy can do an error exit, but why assume anything...) + */ + //free (fbuffer); + + /* At this point you may want to check to see whether any corrupt-data + * warnings occurred (test whether jerr.pub.num_warnings is nonzero). + */ + + /* And we're done! */ + return 0; +} + diff --git a/libs/jpeg6/jutils.cpp b/libs/jpeg6/jutils.cpp new file mode 100644 index 00000000..f5454a6e --- /dev/null +++ b/libs/jpeg6/jutils.cpp @@ -0,0 +1,350 @@ +/* + + * jutils.c + + * + + * Copyright (C) 1991-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains tables and miscellaneous utility routines needed + + * for both compression and decompression. + + * Note we prefix all global names with "j" to minimize conflicts with + + * a surrounding application. + + */ + + + +#define JPEG_INTERNALS + +#include "jinclude.h" + +#include "radiant_jpeglib.h" + + + + + +/* + + * jpeg_zigzag_order[i] is the zigzag-order position of the i'th element + + * of a DCT block read in natural order (left to right, top to bottom). + + */ + + + +const int jpeg_zigzag_order[DCTSIZE2] = { + + 0, 1, 5, 6, 14, 15, 27, 28, + + 2, 4, 7, 13, 16, 26, 29, 42, + + 3, 8, 12, 17, 25, 30, 41, 43, + + 9, 11, 18, 24, 31, 40, 44, 53, + + 10, 19, 23, 32, 39, 45, 52, 54, + + 20, 22, 33, 38, 46, 51, 55, 60, + + 21, 34, 37, 47, 50, 56, 59, 61, + + 35, 36, 48, 49, 57, 58, 62, 63 + +}; + + + +/* + + * jpeg_natural_order[i] is the natural-order position of the i'th element + + * of zigzag order. + + * + + * When reading corrupted data, the Huffman decoders could attempt + + * to reference an entry beyond the end of this array (if the decoded + + * zero run length reaches past the end of the block). To prevent + + * wild stores without adding an inner-loop test, we put some extra + + * "63"s after the real entries. This will cause the extra coefficient + + * to be stored in location 63 of the block, not somewhere random. + + * The worst case would be a run-length of 15, which means we need 16 + + * fake entries. + + */ + + + +const int jpeg_natural_order[DCTSIZE2+16] = { + + 0, 1, 8, 16, 9, 2, 3, 10, + + 17, 24, 32, 25, 18, 11, 4, 5, + + 12, 19, 26, 33, 40, 48, 41, 34, + + 27, 20, 13, 6, 7, 14, 21, 28, + + 35, 42, 49, 56, 57, 50, 43, 36, + + 29, 22, 15, 23, 30, 37, 44, 51, + + 58, 59, 52, 45, 38, 31, 39, 46, + + 53, 60, 61, 54, 47, 55, 62, 63, + + 63, 63, 63, 63, 63, 63, 63, 63, /* extra entries for safety in decoder */ + + 63, 63, 63, 63, 63, 63, 63, 63 + +}; + + + + + +/* + + * Arithmetic utilities + + */ + + + +GLOBAL long + +jdiv_round_up (long a, long b) + +/* Compute a/b rounded up to next integer, ie, ceil(a/b) */ + +/* Assumes a >= 0, b > 0 */ + +{ + + return (a + b - 1L) / b; + +} + + + + + +GLOBAL long + +jround_up (long a, long b) + +/* Compute a rounded up to next multiple of b, ie, ceil(a/b)*b */ + +/* Assumes a >= 0, b > 0 */ + +{ + + a += b - 1L; + + return a - (a % b); + +} + + + + + +/* On normal machines we can apply MEMCOPY() and MEMZERO() to sample arrays + + * and coefficient-block arrays. This won't work on 80x86 because the arrays + + * are FAR and we're assuming a small-pointer memory model. However, some + + * DOS compilers provide far-pointer versions of memcpy() and memset() even + + * in the small-model libraries. These will be used if USE_FMEM is defined. + + * Otherwise, the routines below do it the hard way. (The performance cost + + * is not all that great, because these routines aren't very heavily used.) + + */ + + + +#ifndef NEED_FAR_POINTERS /* normal case, same as regular macros */ + +#define FMEMCOPY(dest,src,size) MEMCOPY(dest,src,size) + +#define FMEMZERO(target,size) MEMZERO(target,size) + +#else /* 80x86 case, define if we can */ + +#ifdef USE_FMEM + +#define FMEMCOPY(dest,src,size) _fmemcpy((void FAR *)(dest), (const void FAR *)(src), (size_t)(size)) + +#define FMEMZERO(target,size) _fmemset((void FAR *)(target), 0, (size_t)(size)) + +#endif + +#endif + + + + + +GLOBAL void + +jcopy_sample_rows (JSAMPARRAY input_array, int source_row, + + JSAMPARRAY output_array, int dest_row, + + int num_rows, JDIMENSION num_cols) + +/* Copy some rows of samples from one place to another. + + * num_rows rows are copied from input_array[source_row++] + + * to output_array[dest_row++]; these areas may overlap for duplication. + + * The source and destination arrays must be at least as wide as num_cols. + + */ + +{ + + register JSAMPROW inptr, outptr; + +#ifdef FMEMCOPY + + register size_t count = (size_t) (num_cols * SIZEOF(JSAMPLE)); + +#else + + register JDIMENSION count; + +#endif + + register int row; + + + + input_array += source_row; + + output_array += dest_row; + + + + for (row = num_rows; row > 0; row--) { + + inptr = *input_array++; + + outptr = *output_array++; + +#ifdef FMEMCOPY + + FMEMCOPY(outptr, inptr, count); + +#else + + for (count = num_cols; count > 0; count--) + + *outptr++ = *inptr++; /* needn't bother with GETJSAMPLE() here */ + +#endif + + } + +} + + + + + +GLOBAL void + +jcopy_block_row (JBLOCKROW input_row, JBLOCKROW output_row, + + JDIMENSION num_blocks) + +/* Copy a row of coefficient blocks from one place to another. */ + +{ + +#ifdef FMEMCOPY + + FMEMCOPY(output_row, input_row, num_blocks * (DCTSIZE2 * SIZEOF(JCOEF))); + +#else + + register JCOEFPTR inptr, outptr; + + register long count; + + + + inptr = (JCOEFPTR) input_row; + + outptr = (JCOEFPTR) output_row; + + for (count = (long) num_blocks * DCTSIZE2; count > 0; count--) { + + *outptr++ = *inptr++; + + } + +#endif + +} + + + + + +GLOBAL void + +jzero_far (void FAR * target, size_t bytestozero) + +/* Zero out a chunk of FAR memory. */ + +/* This might be sample-array data, block-array data, or alloc_large data. */ + +{ + +#ifdef FMEMZERO + + FMEMZERO(target, bytestozero); + +#else + + register char FAR * ptr = (char FAR *) target; + + register size_t count; + + + + for (count = bytestozero; count > 0; count--) { + + *ptr++ = 0; + + } + +#endif + +} + diff --git a/libs/jpeg6/jversion.h b/libs/jpeg6/jversion.h new file mode 100644 index 00000000..784a088c --- /dev/null +++ b/libs/jpeg6/jversion.h @@ -0,0 +1,28 @@ +/* + + * jversion.h + + * + + * Copyright (C) 1991-1995, Thomas G. Lane. + + * This file is part of the Independent JPEG Group's software. + + * For conditions of distribution and use, see the accompanying README file. + + * + + * This file contains software version identification. + + */ + + + + + +#define JVERSION "6 2-Aug-95" + + + +#define JCOPYRIGHT "Copyright (C) 1995, Thomas G. Lane" + diff --git a/libs/jpeglib.h b/libs/jpeglib.h new file mode 100644 index 00000000..7dece342 --- /dev/null +++ b/libs/jpeglib.h @@ -0,0 +1,1123 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +/* + * jpeglib.h + * + * Copyright (C) 1991-1995, Thomas G. Lane. + * This file is part of the Independent JPEG Group's software. + * For conditions of distribution and use, see the accompanying README file. + * + * This file defines the application interface for the JPEG library. + * Most applications using the library need only include this file, + * and perhaps jerror.h if they want to know the exact error codes. + */ + +#ifndef JPEGLIB_H +#define JPEGLIB_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +// LZ: linux stuff +#if defined (__linux__) || defined (__APPLE__) + +#include +#include + +#ifndef boolean +#ifdef __cplusplus +#define boolean bool +#else +typedef int boolean; +#endif +#endif + +#endif + +#ifdef __MACOS__ + +// JDC: stuff to make mac version compile +#define boolean qboolean +#define register +#define INT32 int + +#endif + +// rad additions +// 11.29.99 + +//#include "cmdlib.h" +#ifdef _WIN32 +#include "windows.h" +#include "stdio.h" +#endif + +#ifndef INT32 +#define INT32 int +#endif + +// TTimo: if LoadJPGBuff returns -1, *pic is the error message +extern int LoadJPGBuff(unsigned char *fbuffer, int bufsize, unsigned char **pic, int *width, int *height ); +// rad end + + +/* + * First we include the configuration files that record how this + * installation of the JPEG library is set up. jconfig.h can be + * generated automatically for many systems. jmorecfg.h contains + * manual configuration options that most people need not worry about. + */ + +#ifndef JCONFIG_INCLUDED /* in case jinclude.h already did */ +#include "jpeg6/jconfig.h" /* widely used configuration options */ +#endif +#include "jpeg6/jmorecfg.h" /* seldom changed options */ + + +/* Version ID for the JPEG library. + * Might be useful for tests like "#if JPEG_LIB_VERSION >= 60". + */ + +#define JPEG_LIB_VERSION 60 /* Version 6 */ + + +/* Various constants determining the sizes of things. + * All of these are specified by the JPEG standard, so don't change them + * if you want to be compatible. + */ + +#define DCTSIZE 8 /* The basic DCT block is 8x8 samples */ +#define DCTSIZE2 64 /* DCTSIZE squared; # of elements in a block */ +#define NUM_QUANT_TBLS 4 /* Quantization tables are numbered 0..3 */ +#define NUM_HUFF_TBLS 4 /* Huffman tables are numbered 0..3 */ +#define NUM_ARITH_TBLS 16 /* Arith-coding tables are numbered 0..15 */ +#define MAX_COMPS_IN_SCAN 4 /* JPEG limit on # of components in one scan */ +#define MAX_SAMP_FACTOR 4 /* JPEG limit on sampling factors */ +/* Unfortunately, some bozo at Adobe saw no reason to be bound by the standard; + * the PostScript DCT filter can emit files with many more than 10 blocks/MCU. + * If you happen to run across such a file, you can up D_MAX_BLOCKS_IN_MCU + * to handle it. We even let you do this from the jconfig.h file. However, + * we strongly discourage changing C_MAX_BLOCKS_IN_MCU; just because Adobe + * sometimes emits noncompliant files doesn't mean you should too. + */ +#define C_MAX_BLOCKS_IN_MCU 10 /* compressor's limit on blocks per MCU */ +#ifndef D_MAX_BLOCKS_IN_MCU +#define D_MAX_BLOCKS_IN_MCU 10 /* decompressor's limit on blocks per MCU */ +#endif + + +/* This macro is used to declare a "method", that is, a function pointer. + * We want to supply prototype parameters if the compiler can cope. + * Note that the arglist parameter must be parenthesized! + */ + +#ifdef HAVE_PROTOTYPES +#define JMETHOD(type,methodname,arglist) type (*methodname) arglist +#else +#define JMETHOD(type,methodname,arglist) type (*methodname) () +#endif + + +/* Data structures for images (arrays of samples and of DCT coefficients). + * On 80x86 machines, the image arrays are too big for near pointers, + * but the pointer arrays can fit in near memory. + */ + +typedef JSAMPLE FAR *JSAMPROW; /* ptr to one image row of pixel samples. */ +typedef JSAMPROW *JSAMPARRAY; /* ptr to some rows (a 2-D sample array) */ +typedef JSAMPARRAY *JSAMPIMAGE; /* a 3-D sample array: top index is color */ + +typedef JCOEF JBLOCK[DCTSIZE2]; /* one block of coefficients */ +typedef JBLOCK FAR *JBLOCKROW; /* pointer to one row of coefficient blocks */ +typedef JBLOCKROW *JBLOCKARRAY; /* a 2-D array of coefficient blocks */ +typedef JBLOCKARRAY *JBLOCKIMAGE; /* a 3-D array of coefficient blocks */ + +typedef JCOEF FAR *JCOEFPTR; /* useful in a couple of places */ + + +/* Types for JPEG compression parameters and working tables. */ + + +/* DCT coefficient quantization tables. */ + +typedef struct { + /* This field directly represents the contents of a JPEG DQT marker. + * Note: the values are always given in zigzag order. + */ + UINT16 quantval[DCTSIZE2]; /* quantization step for each coefficient */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JQUANT_TBL; + + +/* Huffman coding tables. */ + +typedef struct { + /* These two fields directly represent the contents of a JPEG DHT marker */ + UINT8 bits[17]; /* bits[k] = # of symbols with codes of */ + /* length k bits; bits[0] is unused */ + UINT8 huffval[256]; /* The symbols, in order of incr code length */ + /* This field is used only during compression. It's initialized FALSE when + * the table is created, and set TRUE when it's been output to the file. + * You could suppress output of a table by setting this to TRUE. + * (See jpeg_suppress_tables for an example.) + */ + boolean sent_table; /* TRUE when table has been output */ +} JHUFF_TBL; + + +/* Basic info about one component (color channel). */ + +typedef struct { + /* These values are fixed over the whole image. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOF marker. */ + int component_id; /* identifier for this component (0..255) */ + int component_index; /* its index in SOF or cinfo->comp_info[] */ + int h_samp_factor; /* horizontal sampling factor (1..4) */ + int v_samp_factor; /* vertical sampling factor (1..4) */ + int quant_tbl_no; /* quantization table selector (0..3) */ + /* These values may vary between scans. */ + /* For compression, they must be supplied by parameter setup; */ + /* for decompression, they are read from the SOS marker. */ + /* The decompressor output side may not use these variables. */ + int dc_tbl_no; /* DC entropy table selector (0..3) */ + int ac_tbl_no; /* AC entropy table selector (0..3) */ + + /* Remaining fields should be treated as private by applications. */ + + /* These values are computed during compression or decompression startup: */ + /* Component's size in DCT blocks. + * Any dummy blocks added to complete an MCU are not counted; therefore + * these values do not depend on whether a scan is interleaved or not. + */ + JDIMENSION width_in_blocks; + JDIMENSION height_in_blocks; + /* Size of a DCT block in samples. Always DCTSIZE for compression. + * For decompression this is the size of the output from one DCT block, + * reflecting any scaling we choose to apply during the IDCT step. + * Values of 1,2,4,8 are likely to be supported. Note that different + * components may receive different IDCT scalings. + */ + int DCT_scaled_size; + /* The downsampled dimensions are the component's actual, unpadded number + * of samples at the main buffer (preprocessing/compression interface), thus + * downsampled_width = ceil(image_width * Hi/Hmax) + * and similarly for height. For decompression, IDCT scaling is included, so + * downsampled_width = ceil(image_width * Hi/Hmax * DCT_scaled_size/DCTSIZE) + */ + JDIMENSION downsampled_width; /* actual width in samples */ + JDIMENSION downsampled_height; /* actual height in samples */ + /* This flag is used only for decompression. In cases where some of the + * components will be ignored (eg grayscale output from YCbCr image), + * we can skip most computations for the unused components. + */ + boolean component_needed; /* do we need the value of this component? */ + + /* These values are computed before starting a scan of the component. */ + /* The decompressor output side may not use these variables. */ + int MCU_width; /* number of blocks per MCU, horizontally */ + int MCU_height; /* number of blocks per MCU, vertically */ + int MCU_blocks; /* MCU_width * MCU_height */ + int MCU_sample_width; /* MCU width in samples, MCU_width*DCT_scaled_size */ + int last_col_width; /* # of non-dummy blocks across in last MCU */ + int last_row_height; /* # of non-dummy blocks down in last MCU */ + + /* Saved quantization table for component; NULL if none yet saved. + * See jdinput.c comments about the need for this information. + * This field is not currently used by the compressor. + */ + JQUANT_TBL * quant_table; + + /* Private per-component storage for DCT or IDCT subsystem. */ + void * dct_table; +} jpeg_component_info; + + +/* The script for encoding a multiple-scan file is an array of these: */ + +typedef struct { + int comps_in_scan; /* number of components encoded in this scan */ + int component_index[MAX_COMPS_IN_SCAN]; /* their SOF/comp_info[] indexes */ + int Ss, Se; /* progressive JPEG spectral selection parms */ + int Ah, Al; /* progressive JPEG successive approx. parms */ +} jpeg_scan_info; + + +/* Known color spaces. */ + +typedef enum { + JCS_UNKNOWN, /* error/unspecified */ + JCS_GRAYSCALE, /* monochrome */ + JCS_RGB, /* red/green/blue */ + JCS_YCbCr, /* Y/Cb/Cr (also known as YUV) */ + JCS_CMYK, /* C/M/Y/K */ + JCS_YCCK /* Y/Cb/Cr/K */ +} J_COLOR_SPACE; + +/* DCT/IDCT algorithm options. */ + +typedef enum { + JDCT_ISLOW, /* slow but accurate integer algorithm */ + JDCT_IFAST, /* faster, less accurate integer method */ + JDCT_FLOAT /* floating-point: accurate, fast on fast HW */ +} J_DCT_METHOD; + +#ifndef JDCT_DEFAULT /* may be overridden in jconfig.h */ +#define JDCT_DEFAULT JDCT_ISLOW +#endif +#ifndef JDCT_FASTEST /* may be overridden in jconfig.h */ +#define JDCT_FASTEST JDCT_IFAST +#endif + +/* Dithering options for decompression. */ + +typedef enum { + JDITHER_NONE, /* no dithering */ + JDITHER_ORDERED, /* simple ordered dither */ + JDITHER_FS /* Floyd-Steinberg error diffusion dither */ +} J_DITHER_MODE; + + +/* Common fields between JPEG compression and decompression master structs. */ + +#define jpeg_common_fields \ + struct jpeg_error_mgr * err; /* Error handler module */\ + struct jpeg_memory_mgr * mem; /* Memory manager module */\ + struct jpeg_progress_mgr * progress; /* Progress monitor, or NULL if none */\ + boolean is_decompressor; /* so common code can tell which is which */\ + int global_state /* for checking call sequence validity */ + +/* Routines that are to be used by both halves of the library are declared + * to receive a pointer to this structure. There are no actual instances of + * jpeg_common_struct, only of jpeg_compress_struct and jpeg_decompress_struct. + */ +struct jpeg_common_struct { + jpeg_common_fields; /* Fields common to both master struct types */ + /* Additional fields follow in an actual jpeg_compress_struct or + * jpeg_decompress_struct. All three structs must agree on these + * initial fields! (This would be a lot cleaner in C++.) + */ +}; + +typedef struct jpeg_common_struct * j_common_ptr; +typedef struct jpeg_compress_struct * j_compress_ptr; +typedef struct jpeg_decompress_struct * j_decompress_ptr; + + +/* Master record for a compression instance */ + +struct jpeg_compress_struct { + jpeg_common_fields; /* Fields shared with jpeg_decompress_struct */ + + /* Destination for compressed data */ + struct jpeg_destination_mgr * dest; + + /* Description of source image --- these fields must be filled in by + * outer application before starting compression. in_color_space must + * be correct before you can even call jpeg_set_defaults(). + */ + + JDIMENSION image_width; /* input image width */ + JDIMENSION image_height; /* input image height */ + int input_components; /* # of color components in input image */ + J_COLOR_SPACE in_color_space; /* colorspace of input image */ + + double input_gamma; /* image gamma of input image */ + + /* Compression parameters --- these fields must be set before calling + * jpeg_start_compress(). We recommend calling jpeg_set_defaults() to + * initialize everything to reasonable defaults, then changing anything + * the application specifically wants to change. That way you won't get + * burnt when new parameters are added. Also note that there are several + * helper routines to simplify changing parameters. + */ + + int data_precision; /* bits of precision in image data */ + + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + int num_scans; /* # of entries in scan_info array */ + const jpeg_scan_info * scan_info; /* script for multi-scan file, or NULL */ + /* The default value of scan_info is NULL, which causes a single-scan + * sequential JPEG file to be emitted. To create a multi-scan file, + * set num_scans and scan_info to point to an array of scan definitions. + */ + + boolean raw_data_in; /* TRUE=caller supplies downsampled data */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + boolean optimize_coding; /* TRUE=optimize entropy encoding parms */ + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + int smoothing_factor; /* 1..100, or 0 for no input smoothing */ + J_DCT_METHOD dct_method; /* DCT algorithm selector */ + + /* The restart interval can be specified in absolute MCUs by setting + * restart_interval, or in MCU rows by setting restart_in_rows + * (in which case the correct restart_interval will be figured + * for each scan). + */ + unsigned int restart_interval; /* MCUs per restart, or 0 for no restart */ + int restart_in_rows; /* if > 0, MCU rows per restart interval */ + + /* Parameters controlling emission of special markers. */ + + boolean write_JFIF_header; /* should a JFIF marker be written? */ + /* These three values are not used by the JPEG code, merely copied */ + /* into the JFIF APP0 marker. density_unit can be 0 for unknown, */ + /* 1 for dots/inch, or 2 for dots/cm. Note that the pixel aspect */ + /* ratio is defined by X_density/Y_density even when density_unit=0. */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean write_Adobe_marker; /* should an Adobe marker be written? */ + + /* State variable: index of next scanline to be written to + * jpeg_write_scanlines(). Application may use this to control its + * processing loop, e.g., "while (next_scanline < image_height)". + */ + + JDIMENSION next_scanline; /* 0 .. image_height-1 */ + + /* Remaining fields are known throughout compressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during compression startup + */ + boolean progressive_mode; /* TRUE if scan script uses progressive mode */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows to be input to coef ctlr */ + /* The coefficient controller receives data in units of MCU rows as defined + * for fully interleaved scans (whether the JPEG file is interleaved or not). + * There are v_samp_factor * DCTSIZE sample rows of each component in an + * "iMCU" (interleaved MCU) row. + */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[C_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* + * Links to compression subobjects (methods and private variables of modules) + */ + struct jpeg_comp_master * master; + struct jpeg_c_main_controller * main; + struct jpeg_c_prep_controller * prep; + struct jpeg_c_coef_controller * coef; + struct jpeg_marker_writer * marker; + struct jpeg_color_converter * cconvert; + struct jpeg_downsampler * downsample; + struct jpeg_forward_dct * fdct; + struct jpeg_entropy_encoder * entropy; +}; + + +/* Master record for a decompression instance */ + +struct jpeg_decompress_struct { + jpeg_common_fields; /* Fields shared with jpeg_compress_struct */ + + /* Source of compressed data */ + struct jpeg_source_mgr * src; + + /* Basic description of image --- filled in by jpeg_read_header(). */ + /* Application may inspect these values to decide how to process image. */ + + JDIMENSION image_width; /* nominal image width (from SOF marker) */ + JDIMENSION image_height; /* nominal image height */ + int num_components; /* # of color components in JPEG image */ + J_COLOR_SPACE jpeg_color_space; /* colorspace of JPEG image */ + + /* Decompression processing parameters --- these fields must be set before + * calling jpeg_start_decompress(). Note that jpeg_read_header() initializes + * them to default values. + */ + + J_COLOR_SPACE out_color_space; /* colorspace for output */ + + unsigned int scale_num, scale_denom; /* fraction by which to scale image */ + + double output_gamma; /* image gamma wanted in output */ + + boolean buffered_image; /* TRUE=multiple output passes */ + boolean raw_data_out; /* TRUE=downsampled data wanted */ + + J_DCT_METHOD dct_method; /* IDCT algorithm selector */ + boolean do_fancy_upsampling; /* TRUE=apply fancy upsampling */ + boolean do_block_smoothing; /* TRUE=apply interblock smoothing */ + + boolean quantize_colors; /* TRUE=colormapped output wanted */ + /* the following are ignored if not quantize_colors: */ + J_DITHER_MODE dither_mode; /* type of color dithering to use */ + boolean two_pass_quantize; /* TRUE=use two-pass color quantization */ + int desired_number_of_colors; /* max # colors to use in created colormap */ + /* these are significant only in buffered-image mode: */ + boolean enable_1pass_quant; /* enable future use of 1-pass quantizer */ + boolean enable_external_quant;/* enable future use of external colormap */ + boolean enable_2pass_quant; /* enable future use of 2-pass quantizer */ + + /* Description of actual output image that will be returned to application. + * These fields are computed by jpeg_start_decompress(). + * You can also use jpeg_calc_output_dimensions() to determine these values + * in advance of calling jpeg_start_decompress(). + */ + + JDIMENSION output_width; /* scaled image width */ + JDIMENSION output_height; /* scaled image height */ + int out_color_components; /* # of color components in out_color_space */ + int output_components; /* # of color components returned */ + /* output_components is 1 (a colormap index) when quantizing colors; + * otherwise it equals out_color_components. + */ + int rec_outbuf_height; /* min recommended height of scanline buffer */ + /* If the buffer passed to jpeg_read_scanlines() is less than this many rows + * high, space and time will be wasted due to unnecessary data copying. + * Usually rec_outbuf_height will be 1 or 2, at most 4. + */ + + /* When quantizing colors, the output colormap is described by these fields. + * The application can supply a colormap by setting colormap non-NULL before + * calling jpeg_start_decompress; otherwise a colormap is created during + * jpeg_start_decompress or jpeg_start_output. + * The map has out_color_components rows and actual_number_of_colors columns. + */ + int actual_number_of_colors; /* number of entries in use */ + JSAMPARRAY colormap; /* The color map as a 2-D pixel array */ + + /* State variables: these variables indicate the progress of decompression. + * The application may examine these but must not modify them. + */ + + /* Row index of next scanline to be read from jpeg_read_scanlines(). + * Application may use this to control its processing loop, e.g., + * "while (output_scanline < output_height)". + */ + JDIMENSION output_scanline; /* 0 .. output_height-1 */ + + /* Current input scan number and number of iMCU rows completed in scan. + * These indicate the progress of the decompressor input side. + */ + int input_scan_number; /* Number of SOS markers seen so far */ + JDIMENSION input_iMCU_row; /* Number of iMCU rows completed */ + + /* The "output scan number" is the notional scan being displayed by the + * output side. The decompressor will not allow output scan/row number + * to get ahead of input scan/row, but it can fall arbitrarily far behind. + */ + int output_scan_number; /* Nominal scan number being displayed */ + JDIMENSION output_iMCU_row; /* Number of iMCU rows read */ + + /* Current progression status. coef_bits[c][i] indicates the precision + * with which component c's DCT coefficient i (in zigzag order) is known. + * It is -1 when no data has yet been received, otherwise it is the point + * transform (shift) value for the most recent scan of the coefficient + * (thus, 0 at completion of the progression). + * This pointer is NULL when reading a non-progressive file. + */ + int (*coef_bits)[DCTSIZE2]; /* -1 or current Al value for each coef */ + + /* Internal JPEG parameters --- the application usually need not look at + * these fields. Note that the decompressor output side may not use + * any parameters that can change between scans. + */ + + /* Quantization and Huffman tables are carried forward across input + * datastreams when processing abbreviated JPEG datastreams. + */ + + JQUANT_TBL * quant_tbl_ptrs[NUM_QUANT_TBLS]; + /* ptrs to coefficient quantization tables, or NULL if not defined */ + + JHUFF_TBL * dc_huff_tbl_ptrs[NUM_HUFF_TBLS]; + JHUFF_TBL * ac_huff_tbl_ptrs[NUM_HUFF_TBLS]; + /* ptrs to Huffman coding tables, or NULL if not defined */ + + /* These parameters are never carried across datastreams, since they + * are given in SOF/SOS markers or defined to be reset by SOI. + */ + + int data_precision; /* bits of precision in image data */ + + jpeg_component_info * comp_info; + /* comp_info[i] describes component that appears i'th in SOF */ + + boolean progressive_mode; /* TRUE if SOFn specifies progressive mode */ + boolean arith_code; /* TRUE=arithmetic coding, FALSE=Huffman */ + + UINT8 arith_dc_L[NUM_ARITH_TBLS]; /* L values for DC arith-coding tables */ + UINT8 arith_dc_U[NUM_ARITH_TBLS]; /* U values for DC arith-coding tables */ + UINT8 arith_ac_K[NUM_ARITH_TBLS]; /* Kx values for AC arith-coding tables */ + + unsigned int restart_interval; /* MCUs per restart interval, or 0 for no restart */ + + /* These fields record data obtained from optional markers recognized by + * the JPEG library. + */ + boolean saw_JFIF_marker; /* TRUE iff a JFIF APP0 marker was found */ + /* Data copied from JFIF marker: */ + UINT8 density_unit; /* JFIF code for pixel size units */ + UINT16 X_density; /* Horizontal pixel density */ + UINT16 Y_density; /* Vertical pixel density */ + boolean saw_Adobe_marker; /* TRUE iff an Adobe APP14 marker was found */ + UINT8 Adobe_transform; /* Color transform code from Adobe marker */ + + boolean CCIR601_sampling; /* TRUE=first samples are cosited */ + + /* Remaining fields are known throughout decompressor, but generally + * should not be touched by a surrounding application. + */ + + /* + * These fields are computed during decompression startup + */ + int max_h_samp_factor; /* largest h_samp_factor */ + int max_v_samp_factor; /* largest v_samp_factor */ + + int min_DCT_scaled_size; /* smallest DCT_scaled_size of any component */ + + JDIMENSION total_iMCU_rows; /* # of iMCU rows in image */ + /* The coefficient controller's input and output progress is measured in + * units of "iMCU" (interleaved MCU) rows. These are the same as MCU rows + * in fully interleaved JPEG scans, but are used whether the scan is + * interleaved or not. We define an iMCU row as v_samp_factor DCT block + * rows of each component. Therefore, the IDCT output contains + * v_samp_factor*DCT_scaled_size sample rows of a component per iMCU row. + */ + + JSAMPLE * sample_range_limit; /* table for fast range-limiting */ + + /* + * These fields are valid during any one scan. + * They describe the components and MCUs actually appearing in the scan. + * Note that the decompressor output side must not use these fields. + */ + int comps_in_scan; /* # of JPEG components in this scan */ + jpeg_component_info * cur_comp_info[MAX_COMPS_IN_SCAN]; + /* *cur_comp_info[i] describes component that appears i'th in SOS */ + + JDIMENSION MCUs_per_row; /* # of MCUs across the image */ + JDIMENSION MCU_rows_in_scan; /* # of MCU rows in the image */ + + int blocks_in_MCU; /* # of DCT blocks per MCU */ + int MCU_membership[D_MAX_BLOCKS_IN_MCU]; + /* MCU_membership[i] is index in cur_comp_info of component owning */ + /* i'th block in an MCU */ + + int Ss, Se, Ah, Al; /* progressive JPEG parameters for scan */ + + /* This field is shared between entropy decoder and marker parser. + * It is either zero or the code of a JPEG marker that has been + * read from the data source, but has not yet been processed. + */ + int unread_marker; + + /* + * Links to decompression subobjects (methods, private variables of modules) + */ + struct jpeg_decomp_master * master; + struct jpeg_d_main_controller * main; + struct jpeg_d_coef_controller * coef; + struct jpeg_d_post_controller * post; + struct jpeg_input_controller * inputctl; + struct jpeg_marker_reader * marker; + struct jpeg_entropy_decoder * entropy; + struct jpeg_inverse_dct * idct; + struct jpeg_upsampler * upsample; + struct jpeg_color_deconverter * cconvert; + struct jpeg_color_quantizer * cquantize; +}; + + +/* "Object" declarations for JPEG modules that may be supplied or called + * directly by the surrounding application. + * As with all objects in the JPEG library, these structs only define the + * publicly visible methods and state variables of a module. Additional + * private fields may exist after the public ones. + */ + + +/* Error handler object */ + +struct jpeg_error_mgr { + /* Error exit handler: does not return to caller */ + JMETHOD(void, error_exit, (j_common_ptr cinfo)); + /* Conditionally emit a trace or warning message */ + JMETHOD(void, emit_message, (j_common_ptr cinfo, int msg_level)); + /* Routine that actually outputs a trace or error message */ + JMETHOD(void, output_message, (j_common_ptr cinfo)); + /* Format a message string for the most recent JPEG error or message */ + JMETHOD(void, format_message, (j_common_ptr cinfo, char * buffer)); +#define JMSG_LENGTH_MAX 200 /* recommended size of format_message buffer */ + /* Reset error state variables at start of a new image */ + JMETHOD(void, reset_error_mgr, (j_common_ptr cinfo)); + + /* The message ID code and any parameters are saved here. + * A message can have one string parameter or up to 8 int parameters. + */ + int msg_code; +#define JMSG_STR_PARM_MAX 80 + union { + int i[8]; + char s[JMSG_STR_PARM_MAX]; + } msg_parm; + + /* Standard state variables for error facility */ + + int trace_level; /* max msg_level that will be displayed */ + + /* For recoverable corrupt-data errors, we emit a warning message, + * but keep going unless emit_message chooses to abort. emit_message + * should count warnings in num_warnings. The surrounding application + * can check for bad data by seeing if num_warnings is nonzero at the + * end of processing. + */ + long num_warnings; /* number of corrupt-data warnings */ + + /* These fields point to the table(s) of error message strings. + * An application can change the table pointer to switch to a different + * message list (typically, to change the language in which errors are + * reported). Some applications may wish to add additional error codes + * that will be handled by the JPEG library error mechanism; the second + * table pointer is used for this purpose. + * + * First table includes all errors generated by JPEG library itself. + * Error code 0 is reserved for a "no such error string" message. + */ + const char * const * jpeg_message_table; /* Library errors */ + int last_jpeg_message; /* Table contains strings 0..last_jpeg_message */ + /* Second table can be added by application (see cjpeg/djpeg for example). + * It contains strings numbered first_addon_message..last_addon_message. + */ + const char * const * addon_message_table; /* Non-library errors */ + int first_addon_message; /* code for first string in addon table */ + int last_addon_message; /* code for last string in addon table */ +}; + + +/* Progress monitor object */ + +struct jpeg_progress_mgr { + JMETHOD(void, progress_monitor, (j_common_ptr cinfo)); + + long pass_counter; /* work units completed in this pass */ + long pass_limit; /* total number of work units in this pass */ + int completed_passes; /* passes completed so far */ + int total_passes; /* total number of passes expected */ +}; + + +/* Data destination object for compression */ + +struct jpeg_destination_mgr { + JOCTET * next_output_byte; /* => next byte to write in buffer */ + size_t free_in_buffer; /* # of byte spaces remaining in buffer */ + + JMETHOD(void, init_destination, (j_compress_ptr cinfo)); + JMETHOD(boolean, empty_output_buffer, (j_compress_ptr cinfo)); + JMETHOD(void, term_destination, (j_compress_ptr cinfo)); +}; + + +/* Data source object for decompression */ + +struct jpeg_source_mgr { + const JOCTET * next_input_byte; /* => next byte to read from buffer */ + size_t bytes_in_buffer; /* # of bytes remaining in buffer */ + + JMETHOD(void, init_source, (j_decompress_ptr cinfo)); + JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo)); + JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes)); + JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired)); + JMETHOD(void, term_source, (j_decompress_ptr cinfo)); +}; + + +/* Memory manager object. + * Allocates "small" objects (a few K total), "large" objects (tens of K), + * and "really big" objects (virtual arrays with backing store if needed). + * The memory manager does not allow individual objects to be freed; rather, + * each created object is assigned to a pool, and whole pools can be freed + * at once. This is faster and more convenient than remembering exactly what + * to free, especially where malloc()/free() are not too speedy. + * NB: alloc routines never return NULL. They exit to error_exit if not + * successful. + */ + +#define JPOOL_PERMANENT 0 /* lasts until master record is destroyed */ +#define JPOOL_IMAGE 1 /* lasts until done with image/datastream */ +#define JPOOL_NUMPOOLS 2 + +typedef struct jvirt_sarray_control * jvirt_sarray_ptr; +typedef struct jvirt_barray_control * jvirt_barray_ptr; + + +struct jpeg_memory_mgr { + /* Method pointers */ + JMETHOD(void *, alloc_small, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(void FAR *, alloc_large, (j_common_ptr cinfo, int pool_id, + size_t sizeofobject)); + JMETHOD(JSAMPARRAY, alloc_sarray, (j_common_ptr cinfo, int pool_id, + JDIMENSION samplesperrow, + JDIMENSION numrows)); + JMETHOD(JBLOCKARRAY, alloc_barray, (j_common_ptr cinfo, int pool_id, + JDIMENSION blocksperrow, + JDIMENSION numrows)); + JMETHOD(jvirt_sarray_ptr, request_virt_sarray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION samplesperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(jvirt_barray_ptr, request_virt_barray, (j_common_ptr cinfo, + int pool_id, + boolean pre_zero, + JDIMENSION blocksperrow, + JDIMENSION numrows, + JDIMENSION maxaccess)); + JMETHOD(void, realize_virt_arrays, (j_common_ptr cinfo)); + JMETHOD(JSAMPARRAY, access_virt_sarray, (j_common_ptr cinfo, + jvirt_sarray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(JBLOCKARRAY, access_virt_barray, (j_common_ptr cinfo, + jvirt_barray_ptr ptr, + JDIMENSION start_row, + JDIMENSION num_rows, + boolean writable)); + JMETHOD(void, free_pool, (j_common_ptr cinfo, int pool_id)); + JMETHOD(void, self_destruct, (j_common_ptr cinfo)); + + /* Limit on memory allocation for this JPEG object. (Note that this is + * merely advisory, not a guaranteed maximum; it only affects the space + * used for virtual-array buffers.) May be changed by outer application + * after creating the JPEG object. + */ + long max_memory_to_use; +}; + + +/* Routine signature for application-supplied marker processing methods. + * Need not pass marker code since it is stored in cinfo->unread_marker. + */ +typedef JMETHOD(boolean, jpeg_marker_parser_method, (j_decompress_ptr cinfo)); + + +/* Declarations for routines called by application. + * The JPP macro hides prototype parameters from compilers that can't cope. + * Note JPP requires double parentheses. + */ + +#ifdef HAVE_PROTOTYPES +#define JPP(arglist) arglist +#else +#define JPP(arglist) () +#endif + + +/* Short forms of external names for systems with brain-damaged linkers. + * We shorten external names to be unique in the first six letters, which + * is good enough for all known systems. + * (If your compiler itself needs names to be unique in less than 15 + * characters, you are out of luck. Get a better compiler.) + */ + +#ifdef NEED_SHORT_EXTERNAL_NAMES +#define jpeg_std_error jStdError +#define jpeg_create_compress jCreaCompress +#define jpeg_create_decompress jCreaDecompress +#define jpeg_destroy_compress jDestCompress +#define jpeg_destroy_decompress jDestDecompress +#define jpeg_stdio_dest jStdDest +#define jpeg_stdio_src jStdSrc +#define jpeg_set_defaults jSetDefaults +#define jpeg_set_colorspace jSetColorspace +#define jpeg_default_colorspace jDefColorspace +#define jpeg_set_quality jSetQuality +#define jpeg_set_linear_quality jSetLQuality +#define jpeg_add_quant_table jAddQuantTable +#define jpeg_quality_scaling jQualityScaling +#define jpeg_simple_progression jSimProgress +#define jpeg_suppress_tables jSuppressTables +#define jpeg_alloc_quant_table jAlcQTable +#define jpeg_alloc_huff_table jAlcHTable +#define jpeg_start_compress jStrtCompress +#define jpeg_write_scanlines jWrtScanlines +#define jpeg_finish_compress jFinCompress +#define jpeg_write_raw_data jWrtRawData +#define jpeg_write_marker jWrtMarker +#define jpeg_write_tables jWrtTables +#define jpeg_read_header jReadHeader +#define jpeg_start_decompress jStrtDecompress +#define jpeg_read_scanlines jReadScanlines +#define jpeg_finish_decompress jFinDecompress +#define jpeg_read_raw_data jReadRawData +#define jpeg_has_multiple_scans jHasMultScn +#define jpeg_start_output jStrtOutput +#define jpeg_finish_output jFinOutput +#define jpeg_input_complete jInComplete +#define jpeg_new_colormap jNewCMap +#define jpeg_consume_input jConsumeInput +#define jpeg_calc_output_dimensions jCalcDimensions +#define jpeg_set_marker_processor jSetMarker +#define jpeg_read_coefficients jReadCoefs +#define jpeg_write_coefficients jWrtCoefs +#define jpeg_copy_critical_parameters jCopyCrit +#define jpeg_abort_compress jAbrtCompress +#define jpeg_abort_decompress jAbrtDecompress +#define jpeg_abort jAbort +#define jpeg_destroy jDestroy +#define jpeg_resync_to_restart jResyncRestart +#endif /* NEED_SHORT_EXTERNAL_NAMES */ + + +/* Default error-management setup */ +EXTERN struct jpeg_error_mgr *jpeg_std_error JPP((struct jpeg_error_mgr *err)); + +/* Initialization and destruction of JPEG compression objects */ +/* NB: you must set up the error-manager BEFORE calling jpeg_create_xxx */ +EXTERN void jpeg_create_compress JPP((j_compress_ptr cinfo)); +EXTERN void jpeg_create_decompress JPP((j_decompress_ptr cinfo)); +EXTERN void jpeg_destroy_compress JPP((j_compress_ptr cinfo)); +EXTERN void jpeg_destroy_decompress JPP((j_decompress_ptr cinfo)); + +/* Standard data source and destination managers: stdio streams. */ +/* Caller is responsible for opening the file before and closing after. */ +EXTERN void jpeg_stdio_dest JPP((j_compress_ptr cinfo, FILE * outfile)); +EXTERN void jpeg_stdio_src JPP((j_decompress_ptr cinfo, unsigned char *infile, int bufsize)); + +/* Default parameter setup for compression */ +EXTERN void jpeg_set_defaults JPP((j_compress_ptr cinfo)); +/* Compression parameter setup aids */ +EXTERN void jpeg_set_colorspace JPP((j_compress_ptr cinfo, + J_COLOR_SPACE colorspace)); +EXTERN void jpeg_default_colorspace JPP((j_compress_ptr cinfo)); +EXTERN void jpeg_set_quality JPP((j_compress_ptr cinfo, int quality, + boolean force_baseline)); +EXTERN void jpeg_set_linear_quality JPP((j_compress_ptr cinfo, + int scale_factor, + boolean force_baseline)); +EXTERN void jpeg_add_quant_table JPP((j_compress_ptr cinfo, int which_tbl, + const unsigned int *basic_table, + int scale_factor, + boolean force_baseline)); +EXTERN int jpeg_quality_scaling JPP((int quality)); +EXTERN void jpeg_simple_progression JPP((j_compress_ptr cinfo)); +EXTERN void jpeg_suppress_tables JPP((j_compress_ptr cinfo, + boolean suppress)); +EXTERN JQUANT_TBL * jpeg_alloc_quant_table JPP((j_common_ptr cinfo)); +EXTERN JHUFF_TBL * jpeg_alloc_huff_table JPP((j_common_ptr cinfo)); + +/* Main entry points for compression */ +EXTERN void jpeg_start_compress JPP((j_compress_ptr cinfo, + boolean write_all_tables)); +EXTERN JDIMENSION jpeg_write_scanlines JPP((j_compress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION num_lines)); +EXTERN void jpeg_finish_compress JPP((j_compress_ptr cinfo)); + +/* Replaces jpeg_write_scanlines when writing raw downsampled data. */ +EXTERN JDIMENSION jpeg_write_raw_data JPP((j_compress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION num_lines)); + +/* Write a special marker. See libjpeg.doc concerning safe usage. */ +EXTERN void jpeg_write_marker JPP((j_compress_ptr cinfo, int marker, + const JOCTET *dataptr, unsigned int datalen)); + +/* Alternate compression function: just write an abbreviated table file */ +EXTERN void jpeg_write_tables JPP((j_compress_ptr cinfo)); + +/* Decompression startup: read start of JPEG datastream to see what's there */ +EXTERN int jpeg_read_header JPP((j_decompress_ptr cinfo, + boolean require_image)); +/* Return value is one of: */ +#define JPEG_SUSPENDED 0 /* Suspended due to lack of input data */ +#define JPEG_HEADER_OK 1 /* Found valid image datastream */ +#define JPEG_HEADER_TABLES_ONLY 2 /* Found valid table-specs-only datastream */ +/* If you pass require_image = TRUE (normal case), you need not check for + * a TABLES_ONLY return code; an abbreviated file will cause an error exit. + * JPEG_SUSPENDED is only possible if you use a data source module that can + * give a suspension return (the stdio source module doesn't). + */ + +/* Main entry points for decompression */ +EXTERN boolean jpeg_start_decompress JPP((j_decompress_ptr cinfo)); +EXTERN JDIMENSION jpeg_read_scanlines JPP((j_decompress_ptr cinfo, + JSAMPARRAY scanlines, + JDIMENSION max_lines)); +EXTERN boolean jpeg_finish_decompress JPP((j_decompress_ptr cinfo)); + +/* Replaces jpeg_read_scanlines when reading raw downsampled data. */ +EXTERN JDIMENSION jpeg_read_raw_data JPP((j_decompress_ptr cinfo, + JSAMPIMAGE data, + JDIMENSION max_lines)); + +/* Additional entry points for buffered-image mode. */ +EXTERN boolean jpeg_has_multiple_scans JPP((j_decompress_ptr cinfo)); +EXTERN boolean jpeg_start_output JPP((j_decompress_ptr cinfo, + int scan_number)); +EXTERN boolean jpeg_finish_output JPP((j_decompress_ptr cinfo)); +EXTERN boolean jpeg_input_complete JPP((j_decompress_ptr cinfo)); +EXTERN void jpeg_new_colormap JPP((j_decompress_ptr cinfo)); +EXTERN int jpeg_consume_input JPP((j_decompress_ptr cinfo)); +/* Return value is one of: */ +/* #define JPEG_SUSPENDED 0 Suspended due to lack of input data */ +#define JPEG_REACHED_SOS 1 /* Reached start of new scan */ +#define JPEG_REACHED_EOI 2 /* Reached end of image */ +#define JPEG_ROW_COMPLETED 3 /* Completed one iMCU row */ +#define JPEG_SCAN_COMPLETED 4 /* Completed last iMCU row of a scan */ + +/* Precalculate output dimensions for current decompression parameters. */ +EXTERN void jpeg_calc_output_dimensions JPP((j_decompress_ptr cinfo)); + +/* Install a special processing method for COM or APPn markers. */ +EXTERN void jpeg_set_marker_processor JPP((j_decompress_ptr cinfo, + int marker_code, + jpeg_marker_parser_method routine)); + +/* Read or write raw DCT coefficients --- useful for lossless transcoding. */ +EXTERN jvirt_barray_ptr * jpeg_read_coefficients JPP((j_decompress_ptr cinfo)); +EXTERN void jpeg_write_coefficients JPP((j_compress_ptr cinfo, + jvirt_barray_ptr * coef_arrays)); +EXTERN void jpeg_copy_critical_parameters JPP((j_decompress_ptr srcinfo, + j_compress_ptr dstinfo)); + +/* If you choose to abort compression or decompression before completing + * jpeg_finish_(de)compress, then you need to clean up to release memory, + * temporary files, etc. You can just call jpeg_destroy_(de)compress + * if you're done with the JPEG object, but if you want to clean it up and + * reuse it, call this: + */ +EXTERN void jpeg_abort_compress JPP((j_compress_ptr cinfo)); +EXTERN void jpeg_abort_decompress JPP((j_decompress_ptr cinfo)); + +/* Generic versions of jpeg_abort and jpeg_destroy that work on either + * flavor of JPEG object. These may be more convenient in some places. + */ +EXTERN void jpeg_abort JPP((j_common_ptr cinfo)); +EXTERN void jpeg_destroy JPP((j_common_ptr cinfo)); + +/* Default restart-marker-resync procedure for use by data source modules */ +EXTERN boolean jpeg_resync_to_restart JPP((j_decompress_ptr cinfo, + int desired)); + + +/* These marker codes are exported since applications and data source modules + * are likely to want to use them. + */ + +#define JPEG_RST0 0xD0 /* RST0 marker code */ +#define JPEG_EOI 0xD9 /* EOI marker code */ +#define JPEG_APP0 0xE0 /* APP0 marker code */ +#define JPEG_COM 0xFE /* COM marker code */ + + +/* If we have a brain-damaged compiler that emits warnings (or worse, errors) + * for structure definitions that are never filled in, keep it quiet by + * supplying dummy definitions for the various substructures. + */ + +#ifdef INCOMPLETE_TYPES_BROKEN +#ifndef JPEG_INTERNALS /* will be defined in jpegint.h */ +struct jvirt_sarray_control { long dummy; }; +struct jvirt_barray_control { long dummy; }; +struct jpeg_comp_master { long dummy; }; +struct jpeg_c_main_controller { long dummy; }; +struct jpeg_c_prep_controller { long dummy; }; +struct jpeg_c_coef_controller { long dummy; }; +struct jpeg_marker_writer { long dummy; }; +struct jpeg_color_converter { long dummy; }; +struct jpeg_downsampler { long dummy; }; +struct jpeg_forward_dct { long dummy; }; +struct jpeg_entropy_encoder { long dummy; }; +struct jpeg_decomp_master { long dummy; }; +struct jpeg_d_main_controller { long dummy; }; +struct jpeg_d_coef_controller { long dummy; }; +struct jpeg_d_post_controller { long dummy; }; +struct jpeg_input_controller { long dummy; }; +struct jpeg_marker_reader { long dummy; }; +struct jpeg_entropy_decoder { long dummy; }; +struct jpeg_inverse_dct { long dummy; }; +struct jpeg_upsampler { long dummy; }; +struct jpeg_color_deconverter { long dummy; }; +struct jpeg_color_quantizer { long dummy; }; +#endif /* JPEG_INTERNALS */ +#endif /* INCOMPLETE_TYPES_BROKEN */ + + +/* + * The JPEG library modules define JPEG_INTERNALS before including this file. + * The internal structure declarations are read only when that is true. + * Applications using the library should not include jpegint.h, but may wish + * to include jerror.h. + */ + +#ifdef JPEG_INTERNALS +#include "jpegint.h" /* fetch private declarations */ +#include "jerror.h" /* fetch error codes too */ +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* JPEGLIB_H */ diff --git a/libs/l_net/.cvsignore b/libs/l_net/.cvsignore new file mode 100644 index 00000000..877bc8c4 --- /dev/null +++ b/libs/l_net/.cvsignore @@ -0,0 +1,5 @@ +Debug +Release +*.plg +*.BAK +.consign diff --git a/libs/l_net/l_net.c b/libs/l_net/l_net.c new file mode 100644 index 00000000..fed856b5 --- /dev/null +++ b/libs/l_net/l_net.c @@ -0,0 +1,627 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//==================================================================== +// +// Name: l_net.c +// Function: - +// Programmer: MrElusive +// Last update: - +// Tab size: 3 +// Notes: +//==================================================================== + +#include +#include +#include +#include +#include "l_net.h" +#include "l_net_wins.h" + +#define GetMemory malloc +#define FreeMemory free + +#define qtrue 1 +#define qfalse 0 + +#ifdef _DEBUG +void WinPrint(char *str, ...) +{ + va_list argptr; + char text[4096]; + + va_start (argptr,str); + vsprintf (text, str, argptr); + va_end (argptr); + + printf(text); +} +#else +void WinPrint(char *str, ...) +{ +} +#endif + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_SetAddressPort(address_t *address, int port) +{ + sockaddr_t addr; + + WINS_StringToAddr(address->ip, &addr); + WINS_SetSocketPort(&addr, port); + strcpy(address->ip, WINS_AddrToString(&addr)); +} //end of the function Net_SetAddressPort +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Net_AddressCompare(address_t *addr1, address_t *addr2) +{ +#ifdef _WIN32 + return stricmp(addr1->ip, addr2->ip); +#endif +#ifdef __linux__ + return strcasecmp(addr1->ip, addr2->ip); +#endif +} //end of the function Net_AddressCompare +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_SocketToAddress(socket_t *sock, address_t *address) +{ + strcpy(address->ip, WINS_AddrToString(&sock->addr)); +} //end of the function Net_SocketToAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Net_Send(socket_t *sock, netmessage_t *msg) +{ + int size; + + size = msg->size; + msg->size = 0; + NMSG_WriteLong(msg, size-4); + msg->size = size; + //WinPrint("Net_Send: message of size %d\n", sendmsg.size); + return WINS_Write(sock->socket, msg->data, msg->size, NULL); +} //end of the function Net_SendSocketReliable +//=========================================================================== +// returns the number of bytes recieved +// -1 on error +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Net_Receive(socket_t *sock, netmessage_t *msg) +{ + int curread; + + if (sock->remaining > 0) + { + curread = WINS_Read(sock->socket, &sock->msg.data[sock->msg.size], sock->remaining, NULL); + if (curread == -1) + { + WinPrint("Net_Receive: read error\n"); + return -1; + } //end if + sock->remaining -= curread; + sock->msg.size += curread; + if (sock->remaining <= 0) + { + sock->remaining = 0; + memcpy(msg, &sock->msg, sizeof(netmessage_t)); + sock->msg.size = 0; + return msg->size - 4; + } //end if + return 0; + } //end if + sock->msg.size = WINS_Read(sock->socket, sock->msg.data, 4, NULL); + if (sock->msg.size == 0) return 0; + if (sock->msg.size == -1) + { + WinPrint("Net_Receive: size header read error\n"); + return -1; + } //end if + //WinPrint("Net_Receive: message size header %d\n", msg->size); + sock->msg.read = 0; + sock->remaining = NMSG_ReadLong(&sock->msg); + if (sock->remaining == 0) return 0; + if (sock->remaining < 0 || sock->remaining > MAX_NETMESSAGE) + { + WinPrint("Net_Receive: invalid message size %d\n", sock->remaining); + return -1; + } //end if + //try to read the message + curread = WINS_Read(sock->socket, &sock->msg.data[sock->msg.size], sock->remaining, NULL); + if (curread == -1) + { + WinPrint("Net_Receive: read error\n"); + return -1; + } //end if + sock->remaining -= curread; + sock->msg.size += curread; + if (sock->remaining <= 0) + { + sock->remaining = 0; + memcpy(msg, &sock->msg, sizeof(netmessage_t)); + sock->msg.size = 0; + return msg->size - 4; + } //end if + //the message has not been completely read yet +#ifdef _DEBUG + printf("++timo TODO: debug the Net_Receive on big size messages\n"); +#endif + return 0; +} //end of the function Net_Receive +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +socket_t *Net_AllocSocket(void) +{ + socket_t *sock; + + sock = (socket_t *) GetMemory(sizeof(socket_t)); + memset(sock, 0, sizeof(socket_t)); + return sock; +} //end of the function Net_AllocSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_FreeSocket(socket_t *sock) +{ + FreeMemory(sock); +} //end of the function Net_FreeSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +socket_t *Net_Connect(address_t *address, int port) +{ + int newsock; + socket_t *sock; + sockaddr_t sendaddr; + + // see if we can resolve the host name + WINS_StringToAddr(address->ip, &sendaddr); + + newsock = WINS_OpenReliableSocket(port); + if (newsock == -1) return NULL; + + sock = Net_AllocSocket(); + if (sock == NULL) + { + WINS_CloseSocket(newsock); + return NULL; + } //end if + sock->socket = newsock; + + //connect to the host + if (WINS_Connect(newsock, &sendaddr) == -1) + { + Net_FreeSocket(sock); + WINS_CloseSocket(newsock); + WinPrint("Net_Connect: error connecting\n"); + return NULL; + } //end if + + memcpy(&sock->addr, &sendaddr, sizeof(sockaddr_t)); + //now we can send messages + // + return sock; +} //end of the function Net_Connect + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +socket_t *Net_ListenSocket(int port) +{ + int newsock; + socket_t *sock; + + newsock = WINS_OpenReliableSocket(port); + if (newsock == -1) return NULL; + + if (WINS_Listen(newsock) == -1) + { + WINS_CloseSocket(newsock); + return NULL; + } //end if + sock = Net_AllocSocket(); + if (sock == NULL) + { + WINS_CloseSocket(newsock); + return NULL; + } //end if + sock->socket = newsock; + WINS_GetSocketAddr(newsock, &sock->addr); + WinPrint("listen socket opened at %s\n", WINS_AddrToString(&sock->addr)); + // + return sock; +} //end of the function Net_ListenSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +socket_t *Net_Accept(socket_t *sock) +{ + int newsocket; + sockaddr_t sendaddr; + socket_t *newsock; + + newsocket = WINS_Accept(sock->socket, &sendaddr); + if (newsocket == -1) return NULL; + + newsock = Net_AllocSocket(); + if (newsock == NULL) + { + WINS_CloseSocket(newsocket); + return NULL; + } //end if + newsock->socket = newsocket; + memcpy(&newsock->addr, &sendaddr, sizeof(sockaddr_t)); + // + return newsock; +} //end of the function Net_Accept +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_Disconnect(socket_t *sock) +{ + WINS_CloseSocket(sock->socket); + Net_FreeSocket(sock); +} //end of the function Net_Disconnect +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_StringToAddress(char *string, address_t *address) +{ + strcpy(address->ip, string); +} //end of the function Net_StringToAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_MyAddress(address_t *address) +{ + strcpy(address->ip, WINS_MyAddress()); +} //end of the function Net_MyAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int Net_Setup(void) +{ + WINS_Init(); + // + WinPrint("my address is %s\n", WINS_MyAddress()); + // + return qtrue; +} //end of the function Net_Setup +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void Net_Shutdown(void) +{ + WINS_Shutdown(); +} //end of the function Net_Shutdown +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_Clear(netmessage_t *msg) +{ + msg->size = 4; +} //end of the function NMSG_Clear +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_WriteChar (netmessage_t *msg, int c) +{ + if (c < -128 || c > 127) + WinPrint("NMSG_WriteChar: range error\n"); + + if (msg->size >= MAX_NETMESSAGE) + { + WinPrint("NMSG_WriteChar: overflow\n"); + return; + } //end if + msg->data[msg->size] = c; + msg->size++; +} //end of the function NMSG_WriteChar +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_WriteByte(netmessage_t *msg, int c) +{ + if (c < -128 || c > 127) + WinPrint("NMSG_WriteByte: range error\n"); + + if (msg->size + 1 >= MAX_NETMESSAGE) + { + WinPrint("NMSG_WriteByte: overflow\n"); + return; + } //end if + msg->data[msg->size] = c; + msg->size++; +} //end of the function NMSG_WriteByte +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_WriteShort(netmessage_t *msg, int c) +{ + if (c < ((short)0x8000) || c > (short)0x7fff) + WinPrint("NMSG_WriteShort: range error"); + + if (msg->size + 2 >= MAX_NETMESSAGE) + { + WinPrint("NMSG_WriteShort: overflow\n"); + return; + } //end if + msg->data[msg->size] = c&0xff; + msg->data[msg->size+1] = c>>8; + msg->size += 2; +} //end of the function NMSG_WriteShort +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_WriteLong(netmessage_t *msg, int c) +{ + if (msg->size + 4 >= MAX_NETMESSAGE) + { + WinPrint("NMSG_WriteLong: overflow\n"); + return; + } //end if + msg->data[msg->size] = c&0xff; + msg->data[msg->size+1] = (c>>8)&0xff; + msg->data[msg->size+2] = (c>>16)&0xff; + msg->data[msg->size+3] = c>>24; + msg->size += 4; +} //end of the function NMSG_WriteLong +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_WriteFloat(netmessage_t *msg, float c) +{ + if (msg->size + 4 >= MAX_NETMESSAGE) + { + WinPrint("NMSG_WriteLong: overflow\n"); + return; + } //end if + msg->data[msg->size] = *((int *)&c)&0xff; + msg->data[msg->size+1] = (*((int *)&c)>>8)&0xff; + msg->data[msg->size+2] = (*((int *)&c)>>16)&0xff; + msg->data[msg->size+3] = *((int *)&c)>>24; + msg->size += 4; +} //end of the function NMSG_WriteFloat +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_WriteString(netmessage_t *msg, char *string) +{ + if (msg->size + strlen(string) + 1 >= MAX_NETMESSAGE) + { + WinPrint("NMSG_WriteString: overflow\n"); + return; + } //end if + strcpy(&msg->data[msg->size], string); + msg->size += strlen(string) + 1; +} //end of the function NMSG_WriteString +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void NMSG_ReadStart(netmessage_t *msg) +{ + msg->readoverflow = qfalse; + msg->read = 4; +} //end of the function NMSG_ReadStart +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int NMSG_ReadChar(netmessage_t *msg) +{ + if (msg->size + 1 > msg->size) + { + msg->readoverflow = qtrue; + WinPrint("NMSG_ReadChar: read overflow\n"); + return 0; + } //end if + msg->read++; + return msg->data[msg->read-1]; +} //end of the function NMSG_ReadChar +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int NMSG_ReadByte(netmessage_t *msg) +{ + if (msg->read + 1 > msg->size) + { + msg->readoverflow = qtrue; + WinPrint("NMSG_ReadByte: read overflow\n"); + return 0; + } //end if + msg->read++; + return msg->data[msg->read-1]; +} //end of the function NMSG_ReadByte +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int NMSG_ReadShort(netmessage_t *msg) +{ + int c; + + if (msg->read + 2 > msg->size) + { + msg->readoverflow = qtrue; + WinPrint("NMSG_ReadShort: read overflow\n"); + return 0; + } //end if + c = (short)(msg->data[msg->read] + (msg->data[msg->read+1]<<8)); + msg->read += 2; + return c; +} //end of the function NMSG_ReadShort +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int NMSG_ReadLong(netmessage_t *msg) +{ + int c; + + if (msg->read + 4 > msg->size) + { + msg->readoverflow = qtrue; + WinPrint("NMSG_ReadLong: read overflow\n"); + return 0; + } //end if + c = msg->data[msg->read] + + (msg->data[msg->read+1]<<8) + + (msg->data[msg->read+2]<<16) + + (msg->data[msg->read+3]<<24); + msg->read += 4; + return c; +} //end of the function NMSG_ReadLong +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +float NMSG_ReadFloat(netmessage_t *msg) +{ + int c; + + if (msg->read + 4 > msg->size) + { + msg->readoverflow = qtrue; + WinPrint("NMSG_ReadLong: read overflow\n"); + return 0; + } //end if + c = msg->data[msg->read] + + (msg->data[msg->read+1]<<8) + + (msg->data[msg->read+2]<<16) + + (msg->data[msg->read+3]<<24); + msg->read += 4; + return *(float *)&c; +} //end of the function NMSG_ReadFloat +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *NMSG_ReadString(netmessage_t *msg) +{ + static char string[2048]; + int l, c; + + l = 0; + do + { + if (msg->read + 1 > msg->size) + { + msg->readoverflow = qtrue; + WinPrint("NMSG_ReadString: read overflow\n"); + string[l] = 0; + return string; + } //end if + c = msg->data[msg->read]; + msg->read++; + if (c == 0) break; + string[l] = c; + l++; + } while (l < sizeof(string)-1); + string[l] = 0; + return string; +} //end of the function NMSG_ReadString diff --git a/libs/l_net/l_net.h b/libs/l_net/l_net.h new file mode 100644 index 00000000..dd27d38b --- /dev/null +++ b/libs/l_net/l_net.h @@ -0,0 +1,125 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//==================================================================== +// +// Name: l_net.h +// Function: - +// Programmer: MrElusive +// Last update: TTimo: cross-platform version, l_net library +// Tab size: 2 +// Notes: +//==================================================================== + +//++timo FIXME: the l_net code understands that as the max size for the netmessage_s structure +// we have defined unsigned char data[MAX_NETMESSAGE] in netmessage_s but actually it cannot be filled completely +// we need to introduce a new #define and adapt to data[MAX_NETBUFFER] +#define MAX_NETMESSAGE 1024 +#define MAX_NETADDRESS 32 + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __BYTEBOOL__ +#define __BYTEBOOL__ +typedef enum { qfalse, qtrue } qboolean; +typedef unsigned char byte; +#endif + +typedef struct address_s +{ + char ip[MAX_NETADDRESS]; +} address_t; + +typedef struct sockaddr_s +{ + short sa_family; + unsigned char sa_data[14]; +} sockaddr_t; + +typedef struct netmessage_s +{ + unsigned char data[MAX_NETMESSAGE]; + int size; + int read; + int readoverflow; +} netmessage_t; + +typedef struct socket_s +{ + int socket; //socket number + sockaddr_t addr; //socket address + netmessage_t msg; //current message being read + int remaining; //remaining bytes to read for the current message + struct socket_s *prev, *next; //prev and next socket in a list +} socket_t; + +//compare addresses +int Net_AddressCompare(address_t *addr1, address_t *addr2); +//gives the address of a socket +void Net_SocketToAddress(socket_t *sock, address_t *address); +//converts a string to an address +void Net_StringToAddress(char *string, address_t *address); +//set the address ip port +void Net_SetAddressPort(address_t *address, int port); +//send a message to the given socket +int Net_Send(socket_t *sock, netmessage_t *msg); +//recieve a message from the given socket +int Net_Receive(socket_t *sock, netmessage_t *msg); +//connect to a host +// NOTE: port is the localhost port, usually 0 +// ex: Net_Connect( "192.168.0.1:39000", 0 ) +socket_t *Net_Connect(address_t *address, int port); +//disconnect from a host +void Net_Disconnect(socket_t *sock); +//returns the local address +void Net_MyAddress(address_t *address); +//listen at the given port +socket_t *Net_ListenSocket(int port); +//accept new connections at the given socket +socket_t *Net_Accept(socket_t *sock); +//setup networking +int Net_Setup(void); +//shutdown networking +void Net_Shutdown(void); +//message handling +void NMSG_Clear(netmessage_t *msg); +void NMSG_WriteChar(netmessage_t *msg, int c); +void NMSG_WriteByte(netmessage_t *msg, int c); +void NMSG_WriteShort(netmessage_t *msg, int c); +void NMSG_WriteLong(netmessage_t *msg, int c); +void NMSG_WriteFloat(netmessage_t *msg, float c); +void NMSG_WriteString(netmessage_t *msg, char *string); +void NMSG_ReadStart(netmessage_t *msg); +int NMSG_ReadChar(netmessage_t *msg); +int NMSG_ReadByte(netmessage_t *msg); +int NMSG_ReadShort(netmessage_t *msg); +int NMSG_ReadLong(netmessage_t *msg); +float NMSG_ReadFloat(netmessage_t *msg); +char *NMSG_ReadString(netmessage_t *msg); + +//++timo FIXME: the WINS_ things are not necessary, they can be made portable arther easily +char *WINS_ErrorMessage(int error); + +#ifdef __cplusplus +} +#endif diff --git a/libs/l_net/l_net.vcproj b/libs/l_net/l_net.vcproj new file mode 100644 index 00000000..b9ff7052 --- /dev/null +++ b/libs/l_net/l_net.vcproj @@ -0,0 +1,61 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/l_net/l_net_berkley.c b/libs/l_net/l_net_berkley.c new file mode 100644 index 00000000..60912aee --- /dev/null +++ b/libs/l_net/l_net_berkley.c @@ -0,0 +1,770 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//=========================================================================== +// +// Name: l_net_wins.c +// Function: WinSock +// Programmer: MrElusive +// Last update: TTimo: cross-platform version, l_net library +// Tab Size: 2 +// Notes: +//=========================================================================== + +//#include +#include +#include +#include +#include +#include "l_net.h" +#include "l_net_wins.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#define SOCKET_ERROR -1 +#define INVALID_SOCKET -1 + +extern void WinPrint(char *str, ...); + +#define WinError WinPrint + +#define qtrue 1 +#define qfalse 0 + +#define ioctlsocket ioctl +#define closesocket close + +int WSAGetLastError() +{ + return errno; +} + +/* +typedef struct tag_error_struct +{ + int errnum; + LPSTR errstr; +} ERROR_STRUCT; +*/ + +typedef struct tag_error_struct +{ + int errnum; + const char *errstr; +} ERROR_STRUCT; + +#define NET_NAMELEN 64 + +static char my_tcpip_address[NET_NAMELEN]; + +#define DEFAULTnet_hostport 26000 + +#define MAXHOSTNAMELEN 256 + +static int net_acceptsocket = -1; // socket for fielding new connections +static int net_controlsocket; +static int net_hostport; // udp port number for acceptsocket +static int net_broadcastsocket = 0; +//static qboolean ifbcastinit = qfalse; +//static struct sockaddr_s broadcastaddr; +static struct sockaddr_s broadcastaddr; + +static unsigned long myAddr; + +ERROR_STRUCT errlist[] = { + {EACCES,"EACCES - The address is protected, user is not root"}, + {EAGAIN,"EAGAIN - Operation on non-blocking socket that cannot return immediatly"}, + {EBADF, "EBADF - sockfd is not a valid descriptor"}, + {EFAULT, "EFAULT - The parameter is not in a writable part of the user address space"}, + {EINVAL,"EINVAL - The socket is already bound to an address"}, + {ENOBUFS,"ENOBUFS - not enough memory"}, + {ENOMEM, "ENOMEM - not enough memory"}, + {ENOTCONN, "ENOTCONN - not connected"}, + {ENOTSOCK,"ENOTSOCK - Argument is file descriptor not a socket"}, + {EOPNOTSUPP,"ENOTSUPP - The referenced socket is not of type SOCK_STREAM"}, + {EPERM, "EPERM - Firewall rules forbid connection"}, + {-1, NULL} +}; + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *WINS_ErrorMessage(int error) +{ + int search = 0; + + if (!error) return "No error occurred"; + + for (search = 0; errlist[search].errstr; search++) + { + if (error == errlist[search].errnum) + return (char *)errlist[search].errstr; + } //end for + + return "Unknown error"; +} //end of the function WINS_ErrorMessage +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Init(void) +{ + int i; + struct hostent *local; + char buff[MAXHOSTNAMELEN]; + struct sockaddr_s addr; + char *p; + int r; +/* + linux doesn't have anything to initialize for the net + "Windows .. built for the internet .. the internet .. built with unix" + */ +#if 0 + WORD wVersionRequested; + + wVersionRequested = MAKEWORD(2, 2); + + r = WSAStartup (wVersionRequested, &winsockdata); + + if (r) + { + WinPrint("Winsock initialization failed.\n"); + return -1; + } +#endif + /* + i = COM_CheckParm ("-udpport"); + if (i == 0)*/ + net_hostport = DEFAULTnet_hostport; + /* + else if (i < com_argc-1) + net_hostport = Q_atoi (com_argv[i+1]); + else + Sys_Error ("WINS_Init: you must specify a number after -udpport"); + */ + + // determine my name & address + gethostname(buff, MAXHOSTNAMELEN); + local = gethostbyname(buff); + myAddr = *(int *)local->h_addr_list[0]; + + // if the quake hostname isn't set, set it to the machine name +// if (Q_strcmp(hostname.string, "UNNAMED") == 0) + { + // see if it's a text IP address (well, close enough) + for (p = buff; *p; p++) + if ((*p < '0' || *p > '9') && *p != '.') + break; + + // if it is a real name, strip off the domain; we only want the host + if (*p) + { + for (i = 0; i < 15; i++) + if (buff[i] == '.') + break; + buff[i] = 0; + } +// Cvar_Set ("hostname", buff); + } + + //++timo WTF is that net_controlsocket? it's sole purpose is to retrieve the local IP? + if ((net_controlsocket = WINS_OpenSocket (0)) == SOCKET_ERROR) + WinError("WINS_Init: Unable to open control socket\n"); + + ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET; + ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST; + ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons((u_short)net_hostport); + + WINS_GetSocketAddr (net_controlsocket, &addr); + strcpy(my_tcpip_address, WINS_AddrToString (&addr)); + p = strrchr (my_tcpip_address, ':'); + if (p) *p = 0; + WinPrint("Winsock Initialized\n"); + + return net_controlsocket; +} //end of the function WINS_Init +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *WINS_MyAddress(void) +{ + return my_tcpip_address; +} //end of the function WINS_MyAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void WINS_Shutdown(void) +{ + //WINS_Listen(0); + WINS_CloseSocket(net_controlsocket); +// WSACleanup(); + // + WinPrint("Winsock Shutdown\n"); +} //end of the function WINS_Shutdown +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +/* +void WINS_Listen(int state) +{ + // enable listening + if (state) + { + if (net_acceptsocket != -1) + return; + if ((net_acceptsocket = WINS_OpenSocket (net_hostport)) == -1) + WinError ("WINS_Listen: Unable to open accept socket\n"); + return; + } + + // disable listening + if (net_acceptsocket == -1) + return; + WINS_CloseSocket (net_acceptsocket); + net_acceptsocket = -1; +} //end of the function WINS_Listen*/ +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_OpenSocket(int port) +{ + int newsocket; + struct sockaddr_in address; + u_long _true = 1; + + if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == SOCKET_ERROR) + { + WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + + if (ioctlsocket (newsocket, FIONBIO, &_true) == SOCKET_ERROR) + { + WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + closesocket(newsocket); + return -1; + } //end if + + memset((char *) &address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons((u_short)port); + if( bind (newsocket, (void *)&address, sizeof(address)) == -1) + { + WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + closesocket(newsocket); + return -1; + } //end if + + return newsocket; +} //end of the function WINS_OpenSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_OpenReliableSocket(int port) +{ + int newsocket; + struct sockaddr_in address; + qboolean _true = 0xFFFFFFFF; + + //IPPROTO_TCP + // + if ((newsocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) + { + WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + + memset((char *) &address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = htonl(INADDR_ANY); + address.sin_port = htons((u_short)port); + if (bind(newsocket, (void *)&address, sizeof(address)) == -1) + { + WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + closesocket(newsocket); + return -1; + } //end if + + // + if (setsockopt(newsocket, IPPROTO_TCP, TCP_NODELAY, (void *) &_true, sizeof(int)) == -1) + { + WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + WinPrint("setsockopt error\n"); + } //end if + + return newsocket; +} //end of the function WINS_OpenReliableSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Listen(int socket) +{ + u_long _true = 1; + + if (ioctlsocket(socket, FIONBIO, &_true) == -1) + { + WinPrint("WINS_Listen: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + if (listen(socket, SOMAXCONN) == SOCKET_ERROR) + { + WinPrint("WINS_Listen: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + return 0; +} //end of the function WINS_Listen +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Accept(int socket, struct sockaddr_s *addr) +{ + int addrlen = sizeof (struct sockaddr_s); + int newsocket; + qboolean _true = 1; + + newsocket = accept(socket, (struct sockaddr *)addr, &addrlen); + if (newsocket == INVALID_SOCKET) + { + if (errno == EAGAIN) return -1; + WinPrint("WINS_Accept: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + // + if (setsockopt(newsocket, IPPROTO_TCP, TCP_NODELAY, (void *) &_true, sizeof(int)) == SOCKET_ERROR) + { + WinPrint("WINS_Accept: %s\n", WINS_ErrorMessage(WSAGetLastError())); + WinPrint("setsockopt error\n"); + } //end if + return newsocket; +} //end of the function WINS_Accept +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_CloseSocket(int socket) +{ + /* + if (socket == net_broadcastsocket) + net_broadcastsocket = 0; + */ +// shutdown(socket, SD_SEND); + + if (closesocket(socket) == SOCKET_ERROR) + { + WinPrint("WINS_CloseSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return SOCKET_ERROR; + } //end if + return 0; +} //end of the function WINS_CloseSocket +//=========================================================================== +// this lets you type only as much of the net address as required, using +// the local network components to fill in the rest +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +static int PartialIPAddress (char *in, struct sockaddr_s *hostaddr) +{ + char buff[256]; + char *b; + int addr; + int num; + int mask; + + buff[0] = '.'; + b = buff; + strcpy(buff+1, in); + if (buff[1] == '.') b++; + + addr = 0; + mask=-1; + while (*b == '.') + { + num = 0; + if (*++b < '0' || *b > '9') return -1; + while (!( *b < '0' || *b > '9')) + num = num*10 + *(b++) - '0'; + mask<<=8; + addr = (addr<<8) + num; + } + + hostaddr->sa_family = AF_INET; + ((struct sockaddr_in *)hostaddr)->sin_port = htons((u_short)net_hostport); + ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr); + + return 0; +} //end of the function PartialIPAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Connect(int socket, struct sockaddr_s *addr) +{ + int ret; + u_long _true2 = 0xFFFFFFFF; + + ret = connect(socket, (struct sockaddr *)addr, sizeof(struct sockaddr_s)); + if (ret == SOCKET_ERROR) + { + WinPrint("WINS_Connect: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + if (ioctlsocket(socket, FIONBIO, &_true2) == -1) + { + WinPrint("WINS_Connect: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + return 0; +} //end of the function WINS_Connect +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_CheckNewConnections(void) +{ + char buf[4]; + + if (net_acceptsocket == -1) + return -1; + + if (recvfrom(net_acceptsocket, buf, 4, MSG_PEEK, NULL, NULL) > 0) + return net_acceptsocket; + return -1; +} //end of the function WINS_CheckNewConnections +//=========================================================================== +// returns the number of bytes read +// 0 if no bytes available +// -1 on failure +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Read(int socket, byte *buf, int len, struct sockaddr_s *addr) +{ + int addrlen = sizeof (struct sockaddr_s); + int ret; + + if (addr) + { + ret = recvfrom(socket, buf, len, 0, (struct sockaddr *)addr, &addrlen); + if (ret == -1) + { +// errno = WSAGetLastError(); + + if (errno == EAGAIN || errno == ENOTCONN) + return 0; + } //end if + } //end if + else + { + ret = recv(socket, buf, len, 0); + // if there's no data on the socket ret == -1 and errno == EAGAIN + // MSDN states that if ret == 0 the socket has been closed + // man recv doesn't say anything + if (ret == 0) + return -1; + if (ret == SOCKET_ERROR) + { +// errno = WSAGetLastError(); + + if (errno == EAGAIN || errno == ENOTCONN) + return 0; + } //end if + } //end else + if (ret == SOCKET_ERROR) + { + WinPrint("WINS_Read: %s\n", WINS_ErrorMessage(WSAGetLastError())); + } //end if + return ret; +} //end of the function WINS_Read +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_MakeSocketBroadcastCapable (int socket) +{ + int i = 1; + + // make this socket broadcast capable + if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0) + return -1; + net_broadcastsocket = socket; + + return 0; +} //end of the function WINS_MakeSocketBroadcastCapable +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Broadcast (int socket, byte *buf, int len) +{ + int ret; + + if (socket != net_broadcastsocket) + { + if (net_broadcastsocket != 0) + WinError("Attempted to use multiple broadcasts sockets\n"); + ret = WINS_MakeSocketBroadcastCapable (socket); + if (ret == -1) + { + WinPrint("Unable to make socket broadcast capable\n"); + return ret; + } + } + + return WINS_Write (socket, buf, len, &broadcastaddr); +} //end of the function WINS_Broadcast +//=========================================================================== +// returns qtrue on success or qfalse on failure +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Write(int socket, byte *buf, int len, struct sockaddr_s *addr) +{ + int ret, written; + + if (addr) + { + written = 0; + while(written < len) + { + ret = sendto (socket, &buf[written], len-written, 0, (struct sockaddr *)addr, sizeof(struct sockaddr_s)); + if (ret == SOCKET_ERROR) + { + if (WSAGetLastError() != EAGAIN) + return qfalse; + //++timo FIXME: what is this used for? +// Sleep(1000); + } //end if + else + { + written += ret; + } + } + } //end if + else + { + written = 0; + while(written < len) + { + ret = send(socket, buf, len, 0); + if (ret == SOCKET_ERROR) + { + if (WSAGetLastError() != EAGAIN) + return qfalse; + //++timo FIXME: what is this used for? +// Sleep(1000); + } //end if + else + { + written += ret; + } + } + } //end else + if (ret == SOCKET_ERROR) + { + WinPrint("WINS_Write: %s\n", WINS_ErrorMessage(WSAGetLastError())); + } //end if + return (ret == len); +} //end of the function WINS_Write +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *WINS_AddrToString (struct sockaddr_s *addr) +{ + static char buffer[22]; + int haddr; + + haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr); + sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port)); + return buffer; +} //end of the function WINS_AddrToString +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_StringToAddr(char *string, struct sockaddr_s *addr) +{ + int ha1, ha2, ha3, ha4, hp; + int ipaddr; + + sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp); + ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4; + + addr->sa_family = AF_INET; + ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr); + ((struct sockaddr_in *)addr)->sin_port = htons((u_short)hp); + return 0; +} //end of the function WINS_StringToAddr +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetSocketAddr(int socket, struct sockaddr_s *addr) +{ + int addrlen = sizeof(struct sockaddr_s); + unsigned int a; + + memset(addr, 0, sizeof(struct sockaddr_s)); + getsockname(socket, (struct sockaddr *)addr, &addrlen); + a = ((struct sockaddr_in *)addr)->sin_addr.s_addr; + if (a == 0 || a == inet_addr("127.0.0.1")) + ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr; + + return 0; +} //end of the function WINS_GetSocketAddr +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetNameFromAddr (struct sockaddr_s *addr, char *name) +{ + struct hostent *hostentry; + + hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET); + if (hostentry) + { + strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1); + return 0; + } + + strcpy (name, WINS_AddrToString (addr)); + return 0; +} //end of the function WINS_GetNameFromAddr +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetAddrFromName(char *name, struct sockaddr_s *addr) +{ + struct hostent *hostentry; + + if (name[0] >= '0' && name[0] <= '9') + return PartialIPAddress (name, addr); + + hostentry = gethostbyname (name); + if (!hostentry) + return -1; + + addr->sa_family = AF_INET; + ((struct sockaddr_in *)addr)->sin_port = htons((u_short)net_hostport); + ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0]; + + return 0; +} //end of the function WINS_GetAddrFromName +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_AddrCompare (struct sockaddr_s *addr1, struct sockaddr_s *addr2) +{ + if (addr1->sa_family != addr2->sa_family) + return -1; + + if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr) + return -1; + + if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port) + return 1; + + return 0; +} //end of the function WINS_AddrCompare +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetSocketPort (struct sockaddr_s *addr) +{ + return ntohs(((struct sockaddr_in *)addr)->sin_port); +} //end of the function WINS_GetSocketPort +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_SetSocketPort (struct sockaddr_s *addr, int port) +{ + ((struct sockaddr_in *)addr)->sin_port = htons((u_short)port); + return 0; +} //end of the function WINS_SetSocketPort diff --git a/libs/l_net/l_net_wins.c b/libs/l_net/l_net_wins.c new file mode 100644 index 00000000..56ee6789 --- /dev/null +++ b/libs/l_net/l_net_wins.c @@ -0,0 +1,789 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//=========================================================================== +// +// Name: l_net_wins.c +// Function: WinSock +// Programmer: MrElusive +// Last update: - +// Tab Size: 3 +// Notes: +//=========================================================================== + +#include +#include +#include +#include +#include "l_net.h" +#include "l_net_wins.h" +//#include +//#include "mpdosock.h" + +#define WinError WinPrint + +#define qtrue 1 +#define qfalse 0 + +typedef struct tag_error_struct +{ + int errnum; + LPSTR errstr; +} ERROR_STRUCT; + +#define NET_NAMELEN 64 + +char my_tcpip_address[NET_NAMELEN]; + +#define DEFAULTnet_hostport 26000 + +#define MAXHOSTNAMELEN 256 + +static int net_acceptsocket = -1; // socket for fielding new connections +static int net_controlsocket; +static int net_hostport; // udp port number for acceptsocket +static int net_broadcastsocket = 0; +//static qboolean ifbcastinit = qfalse; +static struct sockaddr_s broadcastaddr; + +static unsigned long myAddr; + +WSADATA winsockdata; + +ERROR_STRUCT errlist[] = { + {WSAEINTR, "WSAEINTR - Interrupted"}, + {WSAEBADF, "WSAEBADF - Bad file number"}, + {WSAEFAULT, "WSAEFAULT - Bad address"}, + {WSAEINVAL, "WSAEINVAL - Invalid argument"}, + {WSAEMFILE, "WSAEMFILE - Too many open files"}, + +/* +* Windows Sockets definitions of regular Berkeley error constants +*/ + + {WSAEWOULDBLOCK, "WSAEWOULDBLOCK - Socket marked as non-blocking"}, + {WSAEINPROGRESS, "WSAEINPROGRESS - Blocking call in progress"}, + {WSAEALREADY, "WSAEALREADY - Command already completed"}, + {WSAENOTSOCK, "WSAENOTSOCK - Descriptor is not a socket"}, + {WSAEDESTADDRREQ, "WSAEDESTADDRREQ - Destination address required"}, + {WSAEMSGSIZE, "WSAEMSGSIZE - Data size too large"}, + {WSAEPROTOTYPE, "WSAEPROTOTYPE - Protocol is of wrong type for this socket"}, + {WSAENOPROTOOPT, "WSAENOPROTOOPT - Protocol option not supported for this socket type"}, + {WSAEPROTONOSUPPORT, "WSAEPROTONOSUPPORT - Protocol is not supported"}, + {WSAESOCKTNOSUPPORT, "WSAESOCKTNOSUPPORT - Socket type not supported by this address family"}, + {WSAEOPNOTSUPP, "WSAEOPNOTSUPP - Option not supported"}, + {WSAEPFNOSUPPORT, "WSAEPFNOSUPPORT - "}, + {WSAEAFNOSUPPORT, "WSAEAFNOSUPPORT - Address family not supported by this protocol"}, + {WSAEADDRINUSE, "WSAEADDRINUSE - Address is in use"}, + {WSAEADDRNOTAVAIL, "WSAEADDRNOTAVAIL - Address not available from local machine"}, + {WSAENETDOWN, "WSAENETDOWN - Network subsystem is down"}, + {WSAENETUNREACH, "WSAENETUNREACH - Network cannot be reached"}, + {WSAENETRESET, "WSAENETRESET - Connection has been dropped"}, + {WSAECONNABORTED, "WSAECONNABORTED - Connection aborted"}, + {WSAECONNRESET, "WSAECONNRESET - Connection reset"}, + {WSAENOBUFS, "WSAENOBUFS - No buffer space available"}, + {WSAEISCONN, "WSAEISCONN - Socket is already connected"}, + {WSAENOTCONN, "WSAENOTCONN - Socket is not connected"}, + {WSAESHUTDOWN, "WSAESHUTDOWN - Socket has been shut down"}, + {WSAETOOMANYREFS, "WSAETOOMANYREFS - Too many references"}, + {WSAETIMEDOUT, "WSAETIMEDOUT - Command timed out"}, + {WSAECONNREFUSED, "WSAECONNREFUSED - Connection refused"}, + {WSAELOOP, "WSAELOOP - "}, + {WSAENAMETOOLONG, "WSAENAMETOOLONG - "}, + {WSAEHOSTDOWN, "WSAEHOSTDOWN - Host is down"}, + {WSAEHOSTUNREACH, "WSAEHOSTUNREACH - "}, + {WSAENOTEMPTY, "WSAENOTEMPTY - "}, + {WSAEPROCLIM, "WSAEPROCLIM - "}, + {WSAEUSERS, "WSAEUSERS - "}, + {WSAEDQUOT, "WSAEDQUOT - "}, + {WSAESTALE, "WSAESTALE - "}, + {WSAEREMOTE, "WSAEREMOTE - "}, + +/* +* Extended Windows Sockets error constant definitions +*/ + + {WSASYSNOTREADY, "WSASYSNOTREADY - Network subsystem not ready"}, + {WSAVERNOTSUPPORTED, "WSAVERNOTSUPPORTED - Version not supported"}, + {WSANOTINITIALISED, "WSANOTINITIALISED - WSAStartup() has not been successfully called"}, + +/* +* Other error constants. +*/ + + {WSAHOST_NOT_FOUND, "WSAHOST_NOT_FOUND - Host not found"}, + {WSATRY_AGAIN, "WSATRY_AGAIN - Host not found or SERVERFAIL"}, + {WSANO_RECOVERY, "WSANO_RECOVERY - Non-recoverable error"}, + {WSANO_DATA, "WSANO_DATA - (or WSANO_ADDRESS) - No data record of requested type"}, + {-1, NULL} +}; + +#ifdef _DEBUG +void WinPrint(char *str, ...); +#else +void WinPrint(char *str, ...); +#endif + +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *WINS_ErrorMessage(int error) +{ + int search = 0; + + if (!error) return "No error occurred"; + + for (search = 0; errlist[search].errstr; search++) + { + if (error == errlist[search].errnum) + return errlist[search].errstr; + } //end for + + return "Unknown error"; +} //end of the function WINS_ErrorMessage +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Init(void) +{ + int i; + struct hostent *local; + char buff[MAXHOSTNAMELEN]; + struct sockaddr_s addr; + char *p; + int r; + WORD wVersionRequested; + + wVersionRequested = MAKEWORD(1, 1); + + r = WSAStartup (wVersionRequested, &winsockdata); + + if (r) + { + WinPrint("Winsock initialization failed.\n"); + return -1; + } + + /* + i = COM_CheckParm ("-udpport"); + if (i == 0)*/ + net_hostport = DEFAULTnet_hostport; + /* + else if (i < com_argc-1) + net_hostport = Q_atoi (com_argv[i+1]); + else + Sys_Error ("WINS_Init: you must specify a number after -udpport"); + */ + + // determine my name & address + gethostname(buff, MAXHOSTNAMELEN); + local = gethostbyname(buff); + myAddr = *(int *)local->h_addr_list[0]; + + // if the quake hostname isn't set, set it to the machine name +// if (Q_strcmp(hostname.string, "UNNAMED") == 0) + { + // see if it's a text IP address (well, close enough) + for (p = buff; *p; p++) + if ((*p < '0' || *p > '9') && *p != '.') + break; + + // if it is a real name, strip off the domain; we only want the host + if (*p) + { + for (i = 0; i < 15; i++) + if (buff[i] == '.') + break; + buff[i] = 0; + } +// Cvar_Set ("hostname", buff); + } + + if ((net_controlsocket = WINS_OpenSocket (0)) == -1) + WinError("WINS_Init: Unable to open control socket\n"); + + ((struct sockaddr_in *)&broadcastaddr)->sin_family = AF_INET; + ((struct sockaddr_in *)&broadcastaddr)->sin_addr.s_addr = INADDR_BROADCAST; + ((struct sockaddr_in *)&broadcastaddr)->sin_port = htons((u_short)net_hostport); + + WINS_GetSocketAddr (net_controlsocket, &addr); + strcpy(my_tcpip_address, WINS_AddrToString (&addr)); + p = strrchr (my_tcpip_address, ':'); + if (p) *p = 0; + WinPrint("Winsock Initialized\n"); + + return net_controlsocket; +} //end of the function WINS_Init +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *WINS_MyAddress(void) +{ + return my_tcpip_address; +} //end of the function WINS_MyAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +void WINS_Shutdown(void) +{ + //WINS_Listen(0); + WINS_CloseSocket(net_controlsocket); + WSACleanup(); + // + WinPrint("Winsock Shutdown\n"); +} //end of the function WINS_Shutdown +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +/* +void WINS_Listen(int state) +{ + // enable listening + if (state) + { + if (net_acceptsocket != -1) + return; + if ((net_acceptsocket = WINS_OpenSocket (net_hostport)) == -1) + WinError ("WINS_Listen: Unable to open accept socket\n"); + return; + } + + // disable listening + if (net_acceptsocket == -1) + return; + WINS_CloseSocket (net_acceptsocket); + net_acceptsocket = -1; +} //end of the function WINS_Listen*/ +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_OpenSocket(int port) +{ + int newsocket; + struct sockaddr_in address; + u_long _true = 1; + + if ((newsocket = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) == -1) + { + WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + + if (ioctlsocket (newsocket, FIONBIO, &_true) == -1) + { + WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + closesocket(newsocket); + return -1; + } //end if + + memset((char *) &address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = INADDR_ANY; + address.sin_port = htons((u_short)port); + if( bind (newsocket, (void *)&address, sizeof(address)) == -1) + { + WinPrint("WINS_OpenSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + closesocket(newsocket); + return -1; + } //end if + + return newsocket; +} //end of the function WINS_OpenSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_OpenReliableSocket(int port) +{ + int newsocket; + struct sockaddr_in address; + BOOL _true = 0xFFFFFFFF; + + //IPPROTO_TCP + // + if ((newsocket = socket(AF_INET, SOCK_STREAM, 0)) == -1) + { + WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + + memset((char *) &address, 0, sizeof(address)); + address.sin_family = AF_INET; + address.sin_addr.s_addr = htonl(INADDR_ANY); + address.sin_port = htons((u_short)port); + if (bind(newsocket, (void *)&address, sizeof(address)) == -1) + { + WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + closesocket(newsocket); + return -1; + } //end if + + // + if (setsockopt(newsocket, IPPROTO_TCP, TCP_NODELAY, (void *) &_true, sizeof(int)) == SOCKET_ERROR) + { + WinPrint("WINS_OpenReliableSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + WinPrint("setsockopt error\n"); + } //end if + + return newsocket; +} //end of the function WINS_OpenReliableSocket +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Listen(int socket) +{ + u_long _true = 1; + + if (ioctlsocket(socket, FIONBIO, &_true) == -1) + { + WinPrint("WINS_Listen: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + if (listen(socket, SOMAXCONN) == SOCKET_ERROR) + { + WinPrint("WINS_Listen: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + return 0; +} //end of the function WINS_Listen +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Accept(int socket, struct sockaddr_s *addr) +{ + int addrlen = sizeof (struct sockaddr_s); + int newsocket; + BOOL _true = 1; + + newsocket = accept(socket, (struct sockaddr *)addr, &addrlen); + if (newsocket == INVALID_SOCKET) + { + if (WSAGetLastError() == WSAEWOULDBLOCK) return -1; + WinPrint("WINS_Accept: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + // + if (setsockopt(newsocket, IPPROTO_TCP, TCP_NODELAY, (void *) &_true, sizeof(int)) == SOCKET_ERROR) + { + WinPrint("WINS_Accept: %s\n", WINS_ErrorMessage(WSAGetLastError())); + WinPrint("setsockopt error\n"); + } //end if + return newsocket; +} //end of the function WINS_Accept +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_CloseSocket(int socket) +{ + /* + if (socket == net_broadcastsocket) + net_broadcastsocket = 0; + */ +// shutdown(socket, SD_SEND); + + if (closesocket(socket) == SOCKET_ERROR) + { + WinPrint("WINS_CloseSocket: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return SOCKET_ERROR; + } //end if + return 0; +} //end of the function WINS_CloseSocket +//=========================================================================== +// this lets you type only as much of the net address as required, using +// the local network components to fill in the rest +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +static int PartialIPAddress (char *in, struct sockaddr_s *hostaddr) +{ + char buff[256]; + char *b; + int addr; + int num; + int mask; + + buff[0] = '.'; + b = buff; + strcpy(buff+1, in); + if (buff[1] == '.') b++; + + addr = 0; + mask=-1; + while (*b == '.') + { + num = 0; + if (*++b < '0' || *b > '9') return -1; + while (!( *b < '0' || *b > '9')) + num = num*10 + *(b++) - '0'; + mask<<=8; + addr = (addr<<8) + num; + } + + hostaddr->sa_family = AF_INET; + ((struct sockaddr_in *)hostaddr)->sin_port = htons((u_short)net_hostport); + ((struct sockaddr_in *)hostaddr)->sin_addr.s_addr = (myAddr & htonl(mask)) | htonl(addr); + + return 0; +} //end of the function PartialIPAddress +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Connect(int socket, struct sockaddr_s *addr) +{ + int ret; + u_long _true2 = 0xFFFFFFFF; + + ret = connect(socket, (struct sockaddr *)addr, sizeof(struct sockaddr_s)); + if (ret == SOCKET_ERROR) + { + WinPrint("WINS_Connect: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + if (ioctlsocket(socket, FIONBIO, &_true2) == -1) + { + WinPrint("WINS_Connect: %s\n", WINS_ErrorMessage(WSAGetLastError())); + return -1; + } //end if + return 0; +} //end of the function WINS_Connect +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_CheckNewConnections(void) +{ + char buf[4]; + + if (net_acceptsocket == -1) + return -1; + + if (recvfrom(net_acceptsocket, buf, 4, MSG_PEEK, NULL, NULL) > 0) + return net_acceptsocket; + return -1; +} //end of the function WINS_CheckNewConnections +//=========================================================================== +// returns the number of bytes read +// 0 if no bytes available +// -1 on failure +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Read(int socket, byte *buf, int len, struct sockaddr_s *addr) +{ + int addrlen = sizeof (struct sockaddr_s); + int ret, errno; + + if (addr) + { + ret = recvfrom(socket, buf, len, 0, (struct sockaddr *)addr, &addrlen); + if (ret == -1) + { + errno = WSAGetLastError(); + + if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED) + return 0; + } //end if + } //end if + else + { + ret = recv(socket, buf, len, 0); + if (ret == SOCKET_ERROR) + { + errno = WSAGetLastError(); + + if (errno == WSAEWOULDBLOCK || errno == WSAECONNREFUSED) + return 0; + } //end if + } //end else + if (ret == SOCKET_ERROR) + { + WinPrint("WINS_Read: %s\n", WINS_ErrorMessage(WSAGetLastError())); + } //end if + return ret; +} //end of the function WINS_Read +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_MakeSocketBroadcastCapable (int socket) +{ + int i = 1; + + // make this socket broadcast capable + if (setsockopt(socket, SOL_SOCKET, SO_BROADCAST, (char *)&i, sizeof(i)) < 0) + return -1; + net_broadcastsocket = socket; + + return 0; +} //end of the function WINS_MakeSocketBroadcastCapable +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Broadcast (int socket, byte *buf, int len) +{ + int ret; + + if (socket != net_broadcastsocket) + { + if (net_broadcastsocket != 0) + WinError("Attempted to use multiple broadcasts sockets\n"); + ret = WINS_MakeSocketBroadcastCapable (socket); + if (ret == -1) + { + WinPrint("Unable to make socket broadcast capable\n"); + return ret; + } + } + + return WINS_Write (socket, buf, len, &broadcastaddr); +} //end of the function WINS_Broadcast +//=========================================================================== +// returns qtrue on success or qfalse on failure +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_Write(int socket, byte *buf, int len, struct sockaddr_s *addr) +{ + int ret, written; + + if (addr) + { + written = 0; + while(written < len) + { + ret = sendto (socket, &buf[written], len-written, 0, (struct sockaddr *)addr, sizeof(struct sockaddr_s)); + if (ret == SOCKET_ERROR) + { + if (WSAGetLastError() != WSAEWOULDBLOCK) + return qfalse; + Sleep(1000); + } //end if + else + { + written += ret; + } + } + } //end if + else + { + written = 0; + while(written < len) + { + ret = send(socket, buf, len, 0); + if (ret == SOCKET_ERROR) + { + if (WSAGetLastError() != WSAEWOULDBLOCK) + return qfalse; + Sleep(1000); + } //end if + else + { + written += ret; + } + } + } //end else + if (ret == SOCKET_ERROR) + { + WinPrint("WINS_Write: %s\n", WINS_ErrorMessage(WSAGetLastError())); + } //end if + return (ret == len); +} //end of the function WINS_Write +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +char *WINS_AddrToString (struct sockaddr_s *addr) +{ + static char buffer[22]; + int haddr; + + haddr = ntohl(((struct sockaddr_in *)addr)->sin_addr.s_addr); + sprintf(buffer, "%d.%d.%d.%d:%d", (haddr >> 24) & 0xff, (haddr >> 16) & 0xff, (haddr >> 8) & 0xff, haddr & 0xff, ntohs(((struct sockaddr_in *)addr)->sin_port)); + return buffer; +} //end of the function WINS_AddrToString +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_StringToAddr(char *string, struct sockaddr_s *addr) +{ + int ha1, ha2, ha3, ha4, hp; + int ipaddr; + + sscanf(string, "%d.%d.%d.%d:%d", &ha1, &ha2, &ha3, &ha4, &hp); + ipaddr = (ha1 << 24) | (ha2 << 16) | (ha3 << 8) | ha4; + + addr->sa_family = AF_INET; + ((struct sockaddr_in *)addr)->sin_addr.s_addr = htonl(ipaddr); + ((struct sockaddr_in *)addr)->sin_port = htons((u_short)hp); + return 0; +} //end of the function WINS_StringToAddr +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetSocketAddr(int socket, struct sockaddr_s *addr) +{ + int addrlen = sizeof(struct sockaddr_s); + unsigned int a; + + memset(addr, 0, sizeof(struct sockaddr_s)); + getsockname(socket, (struct sockaddr *)addr, &addrlen); + a = ((struct sockaddr_in *)addr)->sin_addr.s_addr; + if (a == 0 || a == inet_addr("127.0.0.1")) + ((struct sockaddr_in *)addr)->sin_addr.s_addr = myAddr; + + return 0; +} //end of the function WINS_GetSocketAddr +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetNameFromAddr (struct sockaddr_s *addr, char *name) +{ + struct hostent *hostentry; + + hostentry = gethostbyaddr ((char *)&((struct sockaddr_in *)addr)->sin_addr, sizeof(struct in_addr), AF_INET); + if (hostentry) + { + strncpy (name, (char *)hostentry->h_name, NET_NAMELEN - 1); + return 0; + } + + strcpy (name, WINS_AddrToString (addr)); + return 0; +} //end of the function WINS_GetNameFromAddr +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetAddrFromName(char *name, struct sockaddr_s *addr) +{ + struct hostent *hostentry; + + if (name[0] >= '0' && name[0] <= '9') + return PartialIPAddress (name, addr); + + hostentry = gethostbyname (name); + if (!hostentry) + return -1; + + addr->sa_family = AF_INET; + ((struct sockaddr_in *)addr)->sin_port = htons((u_short)net_hostport); + ((struct sockaddr_in *)addr)->sin_addr.s_addr = *(int *)hostentry->h_addr_list[0]; + + return 0; +} //end of the function WINS_GetAddrFromName +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_AddrCompare (struct sockaddr_s *addr1, struct sockaddr_s *addr2) +{ + if (addr1->sa_family != addr2->sa_family) + return -1; + + if (((struct sockaddr_in *)addr1)->sin_addr.s_addr != ((struct sockaddr_in *)addr2)->sin_addr.s_addr) + return -1; + + if (((struct sockaddr_in *)addr1)->sin_port != ((struct sockaddr_in *)addr2)->sin_port) + return 1; + + return 0; +} //end of the function WINS_AddrCompare +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_GetSocketPort (struct sockaddr_s *addr) +{ + return ntohs(((struct sockaddr_in *)addr)->sin_port); +} //end of the function WINS_GetSocketPort +//=========================================================================== +// +// Parameter: - +// Returns: - +// Changes Globals: - +//=========================================================================== +int WINS_SetSocketPort (struct sockaddr_s *addr, int port) +{ + ((struct sockaddr_in *)addr)->sin_port = htons((u_short)port); + return 0; +} //end of the function WINS_SetSocketPort diff --git a/libs/l_net/l_net_wins.h b/libs/l_net/l_net_wins.h new file mode 100644 index 00000000..0a06ea7a --- /dev/null +++ b/libs/l_net/l_net_wins.h @@ -0,0 +1,52 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +//=========================================================================== +// +// Name: l_net_wins.h +// Function: WinSock +// Programmer: MrElusive +// Last update: TTimo: cross-platform version, l_net library +// Tab Size: 3 +// Notes: +//=========================================================================== + +int WINS_Init(void); +void WINS_Shutdown(void); +char *WINS_MyAddress(void); +int WINS_Listen(int socket); +int WINS_Accept(int socket, struct sockaddr_s *addr); +int WINS_OpenSocket(int port); +int WINS_OpenReliableSocket(int port); +int WINS_CloseSocket(int socket); +int WINS_Connect (int socket, struct sockaddr_s *addr); +int WINS_CheckNewConnections(void); +int WINS_Read(int socket, byte *buf, int len, struct sockaddr_s *addr); +int WINS_Write(int socket, byte *buf, int len, struct sockaddr_s *addr); +int WINS_Broadcast (int socket, byte *buf, int len); +char *WINS_AddrToString (struct sockaddr_s *addr); +int WINS_StringToAddr (char *string, struct sockaddr_s *addr); +int WINS_GetSocketAddr (int socket, struct sockaddr_s *addr); +int WINS_GetNameFromAddr (struct sockaddr_s *addr, char *name); +int WINS_GetAddrFromName (char *name, struct sockaddr_s *addr); +int WINS_AddrCompare (struct sockaddr_s *addr1, struct sockaddr_s *addr2); +int WINS_GetSocketPort (struct sockaddr_s *addr); +int WINS_SetSocketPort (struct sockaddr_s *addr, int port); diff --git a/libs/mathlib.h b/libs/mathlib.h new file mode 100644 index 00000000..97fcf461 --- /dev/null +++ b/libs/mathlib.h @@ -0,0 +1,305 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef __MATHLIB__ +#define __MATHLIB__ + +// mathlib.h +#include + +#include "bytebool.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef float vec_t; +typedef vec_t vec3_t[3]; +typedef vec_t vec5_t[5]; +typedef vec_t vec4_t[4]; + +#define SIDE_FRONT 0 +#define SIDE_ON 2 +#define SIDE_BACK 1 +#define SIDE_CROSS -2 + +// plane types are used to speed some tests +// 0-2 are axial planes +#define PLANE_X 0 +#define PLANE_Y 1 +#define PLANE_Z 2 +#define PLANE_NON_AXIAL 3 + +#define Q_PI 3.14159265358979323846f + +extern vec3_t vec3_origin; + +#define EQUAL_EPSILON 0.001 + +#ifndef VEC_MAX +#define VEC_MAX 3.402823466e+38F +#endif + +qboolean VectorCompare (vec3_t v1, vec3_t v2); + +#define DotProduct(x,y) ((x)[0]*(y)[0]+(x)[1]*(y)[1]+(x)[2]*(y)[2]) +#define VectorSubtract(a,b,c) ((c)[0]=(a)[0]-(b)[0],(c)[1]=(a)[1]-(b)[1],(c)[2]=(a)[2]-(b)[2]) +#define VectorAdd(a,b,c) ((c)[0]=(a)[0]+(b)[0],(c)[1]=(a)[1]+(b)[1],(c)[2]=(a)[2]+(b)[2]) +#define VectorIncrement(a,b) ((b)[0]+=(a)[0],(b)[1]+=(a)[1],(b)[2]+=(a)[2]) +#define VectorCopy(a,b) ((b)[0]=(a)[0],(b)[1]=(a)[1],(b)[2]=(a)[2]) +#define VectorSet(v, a, b, c) ((v)[0]=(a),(v)[1]=(b),(v)[2]=(c)) +#define VectorScale(a,b,c) ((c)[0]=(b)*(a)[0],(c)[1]=(b)*(a)[1],(c)[2]=(b)*(a)[2]) +#define VectorMid(a,b,c) ((c)[0]=((a)[0]+(b)[0])*0.5f,(c)[1]=((a)[1]+(b)[1])*0.5f,(c)[2]=((a)[2]+(b)[2])*0.5f) +#define VectorNegative(a,b) ((b)[0]=-(a)[0],(b)[1]=-(a)[1],(b)[2]=-(a)[2]) +#define CrossProduct(a,b,c) ((c)[0]=(a)[1]*(b)[2]-(a)[2]*(b)[1],(c)[1]=(a)[2]*(b)[0]-(a)[0]*(b)[2],(c)[2]=(a)[0]*(b)[1]-(a)[1]*(b)[0]) +#define VectorClear(x) ((x)[0]=(x)[1]=(x)[2]=0) + +#define Q_rint(in) ((vec_t)floor(in+0.5)) + +vec_t VectorLength(vec3_t v); + +void VectorMA( const vec3_t va, vec_t scale, const vec3_t vb, vec3_t vc ); + +void _CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross); +vec_t VectorNormalize (const vec3_t in, vec3_t out); +vec_t ColorNormalize( const vec3_t in, vec3_t out ); +void VectorInverse (vec3_t v); +void VectorPolar(vec3_t v, float radius, float theta, float phi); + +// default snapping, to 1 +void VectorSnap(vec3_t v); + +// integer snapping +void VectorISnap(vec3_t point, int snap); + +// Gef: added snap to float for sub-integer grid sizes +// TTimo: we still use the int version of VectorSnap when possible +// to avoid potential rounding issues +// TTimo: renaming to VectorFSnap for C implementation +void VectorFSnap(vec3_t point, float snap); + +// NOTE: added these from Ritual's Q3Radiant +void ClearBounds (vec3_t mins, vec3_t maxs); +void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs); + +void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up); +void VectorToAngles( vec3_t vec, vec3_t angles ); + +#define ZERO_EPSILON 1.0E-6 +#define RAD2DEGMULT 57.29577951308232f +#define DEG2RADMULT 0.01745329251994329f +#define RAD2DEG( a ) ( (a) * RAD2DEGMULT ) +#define DEG2RAD( a ) ( (a) * DEG2RADMULT ) + +void VectorRotate (vec3_t vIn, vec3_t vRotation, vec3_t out); +void VectorRotateOrigin (vec3_t vIn, vec3_t vRotation, vec3_t vOrigin, vec3_t out); + +// some function merged from tools mathlib code + +qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c ); +void NormalToLatLong( const vec3_t normal, byte bytes[2] ); +int PlaneTypeForNormal (vec3_t normal); +void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, float degrees ); + +// Spog +// code imported from geomlib + +/*! +\todo +FIXME test calls such as intersect tests should be named test_ +*/ + +typedef vec_t m3x3_t[9]; +/*!NOTE +m4x4 looks like this.. + + x y z +x axis ( 0 1 2) +y axis ( 4 5 6) +z axis ( 8 9 10) +translation (12 13 14) +scale ( 0 5 10) +*/ +typedef vec_t m4x4_t[16]; + +#define M4X4_INDEX(m,row,col) (m[(col<<2)+row]) + +typedef enum { TRANSLATE, SCALE, ROTATE } transformtype; // legacy, used only in pmesh.cpp + +typedef enum { eXYZ, eYZX, eZXY, eXZY, eYXZ, eZYX } eulerOrder_t; + +// constructors +/*! create m4x4 as identity matrix */ +void m4x4_identity(m4x4_t matrix); +/*! create m4x4 as a translation matrix, for a translation vec3 */ +void m4x4_translation_for_vec3(m4x4_t matrix, const vec3_t translation); +/*! create m4x4 as a rotation matrix, for an euler angles (degrees) vec3 */ +void m4x4_rotation_for_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order); +/*! create m4x4 as a scaling matrix, for a scale vec3 */ +void m4x4_scale_for_vec3(m4x4_t matrix, const vec3_t scale); +/*! create m4x4 as a rotation matrix, for a quaternion vec4 */ +void m4x4_rotation_for_quat(m4x4_t matrix, const vec4_t rotation); +/*! create m4x4 as a rotation matrix, for an axis vec3 and an angle (radians) */ +void m4x4_rotation_for_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle); + +// a valid m4x4 to be modified is always first argument +/*! translate m4x4 by a translation vec3 */ +void m4x4_translate_by_vec3(m4x4_t matrix, const vec3_t translation); +/*! rotate m4x4 by a euler (degrees) vec3 */ +void m4x4_rotate_by_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order); +/*! scale m4x4 by a scaling vec3 */ +void m4x4_scale_by_vec3(m4x4_t matrix, const vec3_t scale); +/*! rotate m4x4 by a quaternion vec4 */ +void m4x4_rotate_by_quat(m4x4_t matrix, const vec4_t rotation); +/*! rotate m4x4 by an axis vec3 and an angle (radians) */ +void m4x4_rotate_by_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle); +/*! transform m4x4 by translation/euler/scaling vec3 (transform = translation.euler.scale) */ +void m4x4_transform_by_vec3(m4x4_t matrix, const vec3_t translation, const vec3_t euler, eulerOrder_t order, const vec3_t scale); +/*! rotate m4x4 around a pivot point by euler(degrees) vec3 */ +void m4x4_pivoted_rotate_by_vec3(m4x4_t matrix, const vec3_t euler, eulerOrder_t order, const vec3_t pivotpoint); +/*! scale m4x4 around a pivot point by scaling vec3 */ +void m4x4_pivoted_scale_by_vec3(m4x4_t matrix, const vec3_t scale, const vec3_t pivotpoint); +/*! transform m4x4 around a pivot point by translation/euler/scaling vec3 */ +void m4x4_pivoted_transform_by_vec3(m4x4_t matrix, const vec3_t translation, const vec3_t euler, eulerOrder_t order, const vec3_t scale, const vec3_t pivotpoint); +/*! rotate m4x4 around a pivot point by quaternion vec4 */ +void m4x4_pivoted_rotate_by_quat(m4x4_t matrix, const vec4_t rotation, const vec3_t pivotpoint); +/*! rotate m4x4 around a pivot point by axis vec3 and angle (radians) */ +void m4x4_pivoted_rotate_by_axisangle(m4x4_t matrix, const vec3_t axis, vec_t angle, const vec3_t pivotpoint); +/*! post-multiply m4x4 by another m4x4 */ +void m4x4_multiply_by_m4x4(m4x4_t matrix, const m4x4_t other); +/*! pre-multiply m4x4 by another m4x4 */ +void m4x4_premultiply_by_m4x4(m4x4_t matrix, const m4x4_t other); + +/*! multiply a point (x,y,z,1) by matrix */ +void m4x4_transform_point(const m4x4_t matrix, vec3_t point); +/*! multiply a normal (x,y,z,0) by matrix */ +void m4x4_transform_normal(const m4x4_t matrix, vec3_t normal); +/*! multiply a vec4 (x,y,z,w) by matrix */ +void m4x4_transform_vec4(const m4x4_t matrix, vec4_t vector); + +/*! multiply a point (x,y,z,1) by matrix */ +void m4x4_transform_point(const m4x4_t matrix, vec3_t point); +/*! multiply a normal (x,y,z,0) by matrix */ +void m4x4_transform_normal(const m4x4_t matrix, vec3_t normal); + +/*! transpose a m4x4 */ +void m4x4_transpose(m4x4_t matrix); +/*! invert an orthogonal 4x3 subset of a 4x4 matrix */ +void m4x4_orthogonal_invert(m4x4_t matrix); +/*! invert any m4x4 using Kramer's rule.. return 1 if matrix is singular, else return 0 */ +int m4x4_invert(m4x4_t matrix); + +/*! +\todo object/ray intersection functions should maybe return a point rather than a distance? +*/ + +/*! +aabb_t - "axis-aligned" bounding box... + origin: centre of bounding box... + extents: +/- extents of box from origin... + radius: cached length of extents vector... +*/ +typedef struct aabb_s +{ + vec3_t origin; + vec3_t extents; + vec_t radius; +} aabb_t; + +/*! +bbox_t - oriented bounding box... + aabb: axis-aligned bounding box... + axes: orientation axes... +*/ +typedef struct bbox_s +{ + aabb_t aabb; + vec3_t axes[3]; +} bbox_t; + +/*! +ray_t - origin point and direction unit-vector +*/ +typedef struct ray_s +{ + vec3_t origin; + vec3_t direction; +} ray_t; + + +/*! Generate AABB from min/max. */ +void aabb_construct_for_vec3(aabb_t *aabb, const vec3_t min, const vec3_t max); +/*! Update bounding-sphere radius. */ +void aabb_update_radius(aabb_t *aabb); +/*! Initialise AABB to negative size. */ +void aabb_clear(aabb_t *aabb); + +/*! Extend AABB to include point. */ +void aabb_extend_by_point(aabb_t *aabb, const vec3_t point); +/*! Extend AABB to include aabb_src. */ +void aabb_extend_by_aabb(aabb_t *aabb, const aabb_t *aabb_src); +/*! Extend AABB by +/- extension vector. */ +void aabb_extend_by_vec3(aabb_t *aabb, vec3_t extension); + +/*! Return 2 if point is inside, else 1 if point is on surface, else 0. */ +int aabb_intersect_point(const aabb_t *aabb, const vec3_t point); +/*! Return 2 if aabb_src intersects, else 1 if aabb_src touches exactly, else 0. */ +int aabb_intersect_aabb(const aabb_t *aabb, const aabb_t *aabb_src); +/*! Return 2 if aabb is behind plane, else 1 if aabb intersects plane, else 0. */ +int aabb_intersect_plane(const aabb_t *aabb, const float *plane); +/*! Return 1 if aabb intersects ray, else 0... dist = closest intersection. */ +int aabb_intersect_ray(const aabb_t *aabb, const ray_t *ray, vec_t *dist); +/*! Return 1 if aabb intersects ray, else 0. Faster, but does not provide point of intersection */ +int aabb_test_ray(const aabb_t* aabb, const ray_t* ray); + +/*! Generate AABB from oriented bounding box. */ +void aabb_for_bbox(aabb_t *aabb, const bbox_t *bbox); +/*! Generate AABB from 2-dimensions of min/max, specified by axis. */ +void aabb_for_area(aabb_t *aabb, vec3_t area_tl, vec3_t area_br, int axis); +/*! Generate AABB to contain src * transform. NOTE: transform must be orthogonal */ +void aabb_for_transformed_aabb(aabb_t* dst, const aabb_t* src, const m4x4_t transform); + + +/*! Generate oriented bounding box from AABB and transformation matrix. */ +/*!\todo Remove need to specify euler/scale. */ +void bbox_for_oriented_aabb(bbox_t *bbox, const aabb_t *aabb, + const m4x4_t matrix, const vec3_t euler, const vec3_t scale); +/*! Return 2 is bbox is behind plane, else return 1 if bbox intersects plane, else return 0. */ +int bbox_intersect_plane(const bbox_t *bbox, const vec_t* plane); + + +/*! Generate a ray from an origin point and a direction unit-vector */ +void ray_construct_for_vec3(ray_t *ray, const vec3_t origin, const vec3_t direction); + +/*! Transform a ray */ +void ray_transform(ray_t *ray, const m4x4_t matrix); + +/*! return true if point intersects cone formed by ray, divergence and epsilon */ +vec_t ray_intersect_point(const ray_t *ray, const vec3_t point, vec_t epsilon, vec_t divergence); +/*! return true if triangle intersects ray... dist = dist from intersection point to ray-origin */ +vec_t ray_intersect_triangle(const ray_t *ray, qboolean bCullBack, const vec3_t vert0, const vec3_t vert1, const vec3_t vert2); + +#ifdef __cplusplus +} +#endif + +#endif /* __MATHLIB__ */ diff --git a/libs/mathlib/bbox.c b/libs/mathlib/bbox.c new file mode 100644 index 00000000..510c4e7c --- /dev/null +++ b/libs/mathlib/bbox.c @@ -0,0 +1,391 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include + +#include "mathlib.h" + +void aabb_construct_for_vec3(aabb_t *aabb, const vec3_t min, const vec3_t max) +{ + VectorMid(min, max, aabb->origin); + VectorSubtract(max, aabb->origin, aabb->extents); +} + +void aabb_update_radius(aabb_t *aabb) +{ + aabb->radius = VectorLength(aabb->extents); +} + +void aabb_clear(aabb_t *aabb) +{ + aabb->origin[0] = aabb->origin[1] = aabb->origin[2] = 0; + aabb->extents[0] = aabb->extents[1] = aabb->extents[2] = -FLT_MAX; +} + +void aabb_extend_by_point(aabb_t *aabb, const vec3_t point) +{ + int i; + vec_t min, max, displacement; + for(i=0; i<3; i++) + { + displacement = point[i] - aabb->origin[i]; + if(fabs(displacement) > aabb->extents[i]) + { + if(aabb->extents[i] < 0) // degenerate + { + min = max = point[i]; + } + else if(displacement > 0) + { + min = aabb->origin[i] - aabb->extents[i]; + max = aabb->origin[i] + displacement; + } + else + { + max = aabb->origin[i] + aabb->extents[i]; + min = aabb->origin[i] + displacement; + } + aabb->origin[i] = (min + max) * 0.5f; + aabb->extents[i] = max - aabb->origin[i]; + } + } +} + +void aabb_extend_by_aabb(aabb_t *aabb, const aabb_t *aabb_src) +{ + int i; + vec_t min, max, displacement, difference; + for(i=0; i<3; i++) + { + displacement = aabb_src->origin[i] - aabb->origin[i]; + difference = aabb_src->extents[i] - aabb->extents[i]; + if(aabb->extents[i] < 0 + || difference >= fabs(displacement)) + { + // 2nd contains 1st + aabb->extents[i] = aabb_src->extents[i]; + aabb->origin[i] = aabb_src->origin[i]; + } + else if(aabb_src->extents[i] < 0 + || -difference >= fabs(displacement)) + { + // 1st contains 2nd + continue; + } + else + { + // not contained + if(displacement > 0) + { + min = aabb->origin[i] - aabb->extents[i]; + max = aabb_src->origin[i] + aabb_src->extents[i]; + } + else + { + min = aabb_src->origin[i] - aabb_src->extents[i]; + max = aabb->origin[i] + aabb->extents[i]; + } + aabb->origin[i] = (min + max) * 0.5f; + aabb->extents[i] = max - aabb->origin[i]; + } + } +} + +void aabb_extend_by_vec3(aabb_t *aabb, vec3_t extension) +{ + VectorAdd(aabb->extents, extension, aabb->extents); +} + +int aabb_intersect_point(const aabb_t *aabb, const vec3_t point) +{ + int i; + for(i=0; i<3; i++) + if(fabs(point[i] - aabb->origin[i]) >= aabb->extents[i]) + return 0; + return 1; +} + +int aabb_intersect_aabb(const aabb_t *aabb, const aabb_t *aabb_src) +{ + int i; + for (i=0; i<3; i++) + if ( fabs(aabb_src->origin[i] - aabb->origin[i]) > (fabs(aabb->extents[i]) + fabs(aabb_src->extents[i])) ) + return 0; + return 1; +} + +int aabb_intersect_plane(const aabb_t *aabb, const float *plane) +{ + float fDist, fIntersect; + + // calc distance of origin from plane + fDist = DotProduct(plane, aabb->origin) + plane[3]; + + // trivial accept/reject using bounding sphere + if (fabs(fDist) > aabb->radius) + { + if (fDist < 0) + return 2; // totally inside + else + return 0; // totally outside + } + + // calc extents distance relative to plane normal + fIntersect = (vec_t)(fabs(plane[0] * aabb->extents[0]) + fabs(plane[1] * aabb->extents[1]) + fabs(plane[2] * aabb->extents[2])); + // accept if origin is less than or equal to this distance + if (fabs(fDist) < fIntersect) return 1; // partially inside + else if (fDist < 0) return 2; // totally inside + return 0; // totally outside +} + +/* +Fast Ray-Box Intersection +by Andrew Woo +from "Graphics Gems", Academic Press, 1990 +*/ + +#define NUMDIM 3 +#define RIGHT 0 +#define LEFT 1 +#define MIDDLE 2 + +int aabb_intersect_ray(const aabb_t *aabb, const ray_t *ray, vec_t *dist) +{ + int inside = 1; + char quadrant[NUMDIM]; + register int i; + int whichPlane; + double maxT[NUMDIM]; + double candidatePlane[NUMDIM]; + vec3_t coord, segment; + + const float *origin = ray->origin; + const float *direction = ray->direction; + + /* Find candidate planes; this loop can be avoided if + rays cast all from the eye(assume perpsective view) */ + for (i=0; iorigin[i] - aabb->extents[i])) + { + quadrant[i] = LEFT; + candidatePlane[i] = (aabb->origin[i] - aabb->extents[i]); + inside = 0; + } + else if (origin[i] > (aabb->origin[i] + aabb->extents[i])) + { + quadrant[i] = RIGHT; + candidatePlane[i] = (aabb->origin[i] + aabb->extents[i]); + inside = 0; + } + else + { + quadrant[i] = MIDDLE; + } + } + + /* Ray origin inside bounding box */ + if(inside == 1) + { + *dist = 0.0f; + return 1; + } + + + /* Calculate T distances to candidate planes */ + for (i = 0; i < NUMDIM; i++) + { + if (quadrant[i] != MIDDLE && direction[i] !=0.) + maxT[i] = (candidatePlane[i] - origin[i]) / direction[i]; + else + maxT[i] = -1.; + } + + /* Get largest of the maxT's for final choice of intersection */ + whichPlane = 0; + for (i = 1; i < NUMDIM; i++) + if (maxT[whichPlane] < maxT[i]) + whichPlane = i; + + /* Check final candidate actually inside box */ + if (maxT[whichPlane] < 0.) + return 0; + for (i = 0; i < NUMDIM; i++) + { + if (whichPlane != i) + { + coord[i] = (vec_t)(origin[i] + maxT[whichPlane] * direction[i]); + if (fabs(coord[i] - aabb->origin[i]) > aabb->extents[i]) + return 0; + } + else + { + coord[i] = (vec_t)candidatePlane[i]; + } + } + + VectorSubtract(coord, origin, segment); + *dist = DotProduct(segment, direction); + + return 1; /* ray hits box */ +} + +int aabb_test_ray(const aabb_t* aabb, const ray_t* ray) +{ + vec3_t displacement, ray_absolute; + vec_t f; + + displacement[0] = ray->origin[0] - aabb->origin[0]; + if(fabs(displacement[0]) > aabb->extents[0] && displacement[0] * ray->direction[0] >= 0.0f) + return 0; + + displacement[1] = ray->origin[1] - aabb->origin[1]; + if(fabs(displacement[1]) > aabb->extents[1] && displacement[1] * ray->direction[1] >= 0.0f) + return 0; + + displacement[2] = ray->origin[2] - aabb->origin[2]; + if(fabs(displacement[2]) > aabb->extents[2] && displacement[2] * ray->direction[2] >= 0.0f) + return 0; + + ray_absolute[0] = (float)fabs(ray->direction[0]); + ray_absolute[1] = (float)fabs(ray->direction[1]); + ray_absolute[2] = (float)fabs(ray->direction[2]); + + f = ray->direction[1] * displacement[2] - ray->direction[2] * displacement[1]; + if((float)fabs(f) > aabb->extents[1] * ray_absolute[2] + aabb->extents[2] * ray_absolute[1]) + return 0; + + f = ray->direction[2] * displacement[0] - ray->direction[0] * displacement[2]; + if((float)fabs(f) > aabb->extents[0] * ray_absolute[2] + aabb->extents[2] * ray_absolute[0]) + return 0; + + f = ray->direction[0] * displacement[1] - ray->direction[1] * displacement[0]; + if((float)fabs(f) > aabb->extents[0] * ray_absolute[1] + aabb->extents[1] * ray_absolute[0]) + return 0; + + return 1; +} + +void aabb_for_bbox(aabb_t *aabb, const bbox_t *bbox) +{ + int i; + vec3_t temp[3]; + + VectorCopy(bbox->aabb.origin, aabb->origin); + + // calculate the AABB extents in local coord space from the OBB extents and axes + VectorScale(bbox->axes[0], bbox->aabb.extents[0], temp[0]); + VectorScale(bbox->axes[1], bbox->aabb.extents[1], temp[1]); + VectorScale(bbox->axes[2], bbox->aabb.extents[2], temp[2]); + for(i=0;i<3;i++) aabb->extents[i] = (vec_t)(fabs(temp[0][i]) + fabs(temp[1][i]) + fabs(temp[2][i])); +} + +void aabb_for_area(aabb_t *aabb, vec3_t area_tl, vec3_t area_br, int axis) +{ + aabb_clear(aabb); + aabb->extents[axis] = FLT_MAX; + aabb_extend_by_point(aabb, area_tl); + aabb_extend_by_point(aabb, area_br); +} + +void aabb_for_transformed_aabb(aabb_t* dst, const aabb_t* src, const m4x4_t transform) +{ + VectorCopy(src->origin, dst->origin); + m4x4_transform_point(transform, dst->origin); + + dst->extents[0] = (vec_t)(fabs(transform[0] * src->extents[0]) + + fabs(transform[4] * src->extents[1]) + + fabs(transform[8] * src->extents[2])); + dst->extents[1] = (vec_t)(fabs(transform[1] * src->extents[0]) + + fabs(transform[5] * src->extents[1]) + + fabs(transform[9] * src->extents[2])); + dst->extents[2] = (vec_t)(fabs(transform[2] * src->extents[0]) + + fabs(transform[6] * src->extents[1]) + + fabs(transform[10] * src->extents[2])); +} + + +void bbox_for_oriented_aabb(bbox_t *bbox, const aabb_t *aabb, const m4x4_t matrix, const vec3_t euler, const vec3_t scale) +{ + double rad[3]; + double pi_180 = Q_PI / 180; + double A, B, C, D, E, F, AD, BD; + + VectorCopy(aabb->origin, bbox->aabb.origin); + + m4x4_transform_point(matrix, bbox->aabb.origin); + + bbox->aabb.extents[0] = aabb->extents[0] * scale[0]; + bbox->aabb.extents[1] = aabb->extents[1] * scale[1]; + bbox->aabb.extents[2] = aabb->extents[2] * scale[2]; + + rad[0] = euler[0] * pi_180; + rad[1] = euler[1] * pi_180; + rad[2] = euler[2] * pi_180; + + A = cos(rad[0]); + B = sin(rad[0]); + C = cos(rad[1]); + D = sin(rad[1]); + E = cos(rad[2]); + F = sin(rad[2]); + + AD = A * -D; + BD = B * -D; + + bbox->axes[0][0] = (vec_t)(C*E); + bbox->axes[0][1] = (vec_t)(-BD*E + A*F); + bbox->axes[0][2] = (vec_t)(AD*E + B*F); + bbox->axes[1][0] = (vec_t)(-C*F); + bbox->axes[1][1] = (vec_t)(BD*F + A*E); + bbox->axes[1][2] = (vec_t)(-AD*F + B*E); + bbox->axes[2][0] = (vec_t)D; + bbox->axes[2][1] = (vec_t)(-B*C); + bbox->axes[2][2] = (vec_t)(A*C); + + aabb_update_radius(&bbox->aabb); +} + +int bbox_intersect_plane(const bbox_t *bbox, const vec_t* plane) +{ + vec_t fDist, fIntersect; + + // calc distance of origin from plane + fDist = DotProduct(plane, bbox->aabb.origin) + plane[3]; + + // trivial accept/reject using bounding sphere + if (fabs(fDist) > bbox->aabb.radius) + { + if (fDist < 0) + return 2; // totally inside + else + return 0; // totally outside + } + + // calc extents distance relative to plane normal + fIntersect = (vec_t)(fabs(bbox->aabb.extents[0] * DotProduct(plane, bbox->axes[0])) + + fabs(bbox->aabb.extents[1] * DotProduct(plane, bbox->axes[1])) + + fabs(bbox->aabb.extents[2] * DotProduct(plane, bbox->axes[2]))); + // accept if origin is less than this distance + if (fabs(fDist) < fIntersect) return 1; // partially inside + else if (fDist < 0) return 2; // totally inside + return 0; // totally outside +} diff --git a/libs/mathlib/linear.c b/libs/mathlib/linear.c new file mode 100644 index 00000000..bdef7145 --- /dev/null +++ b/libs/mathlib/linear.c @@ -0,0 +1,100 @@ +#ifndef __APPLE__ +#include +#else +#include +#endif +#include +#include + +#include "mathlib.h" + +#define TINY FLT_MIN + +void lubksb(float **a, int n, int *indx, float b[]) +// Solves the set of n linear equations A.X=B. Here a[n][n] is input, not as the matrix +// A but rather as its LU decomposition determined by the routine ludcmp. indx[n] is input +// as the permutation vector returned by ludcmp. b[n] is input as the right-hand side vector +// B, and returns with the solution vector X. a, n and indx are not modified by this routine +// and can be left in place for successive calls with different right-hand sides b. This routine takes +// into account the possibility that b will begin with many zero elements, so it is efficient for use +// in matrix inversion +{ + int i,ii=-1,ip,j; + float sum; + + for (i=0;i=0) + for (j=ii;j=0;i--) { + sum=b[i]; + for (j=i+1;j big) big=temp; + if (big == 0.0) return 1; + vv[i]=1.0f/big; + } + for (j=0;j= big) { + big=dum; + imax=i; + } + } + if (j != imax) { + for (k=0;k i ) + idst = ti-1; + + for ( tj = 0; tj < 4; tj++ ) + { + if ( tj < j ) + jdst = tj; + else + if ( tj > j ) + jdst = tj-1; + + if ( ti != i && tj != j ) + mb[idst*3 + jdst] = mr[ti*4 + tj ]; + } + } +} + +float m4_det( m4x4_t mr ) +{ + float det, result = 0, i = 1; + m3x3_t msub3; + int n; + + for ( n = 0; n < 4; n++, i *= -1 ) + { + m4_submat( mr, msub3, 0, n ); + + det = m3_det( msub3 ); + result += mr[n] * det * i; + } + + return result; +} + +int m4x4_invert(m4x4_t matrix) +{ + float mdet = m4_det( matrix ); + m3x3_t mtemp; + int i, j, sign; + m4x4_t m4x4_temp; + + if ( fabs( mdet ) < 0.0000000001 ) //% 0.0005 + return 1; + + memcpy(m4x4_temp, matrix, sizeof(m4x4_t)); + + for ( i = 0; i < 4; i++ ) + for ( j = 0; j < 4; j++ ) + { + sign = 1 - ( (i +j) % 2 ) * 2; + + m4_submat( m4x4_temp, mtemp, i, j ); + + matrix[i+j*4] = ( m3_det( mtemp ) * sign ) / mdet; + } + + return 0; +} diff --git a/libs/mathlib/mathlib.c b/libs/mathlib/mathlib.c new file mode 100644 index 00000000..0c26a963 --- /dev/null +++ b/libs/mathlib/mathlib.c @@ -0,0 +1,593 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +// mathlib.c -- math primitives +#include "mathlib.h" +// we use memcpy and memset +#include + +vec3_t vec3_origin = {0.0f,0.0f,0.0f}; + +/* +================ +MakeNormalVectors + +Given a normalized forward vector, create two +other perpendicular vectors +================ +*/ +void MakeNormalVectors (vec3_t forward, vec3_t right, vec3_t up) +{ + float d; + + // this rotate and negate guarantees a vector + // not colinear with the original + right[1] = -forward[0]; + right[2] = forward[1]; + right[0] = forward[2]; + + d = DotProduct (right, forward); + VectorMA (right, -d, forward, right); + VectorNormalize (right, right); + CrossProduct (right, forward, up); +} + +vec_t VectorLength(vec3_t v) +{ + int i; + float length; + + length = 0.0f; + for (i=0 ; i< 3 ; i++) + length += v[i]*v[i]; + length = (float)sqrt (length); + + return length; +} + +qboolean VectorCompare (vec3_t v1, vec3_t v2) +{ + int i; + + for (i=0 ; i<3 ; i++) + if (fabs(v1[i]-v2[i]) > EQUAL_EPSILON) + return qfalse; + + return qtrue; +} + +/* +// FIXME TTimo this implementation has to be particular to radiant +// through another name I'd say +vec_t Q_rint (vec_t in) +{ + if (g_PrefsDlg.m_bNoClamp) + return in; + else + return (float)floor (in + 0.5); +} +*/ + +void VectorMA( const vec3_t va, vec_t scale, const vec3_t vb, vec3_t vc ) +{ + vc[0] = va[0] + scale*vb[0]; + vc[1] = va[1] + scale*vb[1]; + vc[2] = va[2] + scale*vb[2]; +} + +void _CrossProduct (vec3_t v1, vec3_t v2, vec3_t cross) +{ + cross[0] = v1[1]*v2[2] - v1[2]*v2[1]; + cross[1] = v1[2]*v2[0] - v1[0]*v2[2]; + cross[2] = v1[0]*v2[1] - v1[1]*v2[0]; +} + +vec_t _DotProduct (vec3_t v1, vec3_t v2) +{ + return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2]; +} + +void _VectorSubtract (vec3_t va, vec3_t vb, vec3_t out) +{ + out[0] = va[0]-vb[0]; + out[1] = va[1]-vb[1]; + out[2] = va[2]-vb[2]; +} + +void _VectorAdd (vec3_t va, vec3_t vb, vec3_t out) +{ + out[0] = va[0]+vb[0]; + out[1] = va[1]+vb[1]; + out[2] = va[2]+vb[2]; +} + +void _VectorCopy (vec3_t in, vec3_t out) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} + +vec_t VectorNormalize( const vec3_t in, vec3_t out ) { + vec_t length, ilength; + + length = (vec_t)sqrt (in[0]*in[0] + in[1]*in[1] + in[2]*in[2]); + if (length == 0) + { + VectorClear (out); + return 0; + } + + ilength = 1.0f/length; + out[0] = in[0]*ilength; + out[1] = in[1]*ilength; + out[2] = in[2]*ilength; + + return length; +} + +vec_t ColorNormalize( const vec3_t in, vec3_t out ) { + float max, scale; + + max = in[0]; + if (in[1] > max) + max = in[1]; + if (in[2] > max) + max = in[2]; + + if (max == 0) { + out[0] = out[1] = out[2] = 1.0; + return 0; + } + + scale = 1.0f / max; + + VectorScale (in, scale, out); + + return max; +} + +void VectorInverse (vec3_t v) +{ + v[0] = -v[0]; + v[1] = -v[1]; + v[2] = -v[2]; +} + +/* +void VectorScale (vec3_t v, vec_t scale, vec3_t out) +{ + out[0] = v[0] * scale; + out[1] = v[1] * scale; + out[2] = v[2] * scale; +} +*/ + +void VectorRotate (vec3_t vIn, vec3_t vRotation, vec3_t out) +{ + vec3_t vWork, va; + int nIndex[3][2]; + int i; + + VectorCopy(vIn, va); + VectorCopy(va, vWork); + nIndex[0][0] = 1; nIndex[0][1] = 2; + nIndex[1][0] = 2; nIndex[1][1] = 0; + nIndex[2][0] = 0; nIndex[2][1] = 1; + + for (i = 0; i < 3; i++) + { + if (vRotation[i] != 0) + { + float dAngle = vRotation[i] * Q_PI / 180.0f; + float c = (vec_t)cos(dAngle); + float s = (vec_t)sin(dAngle); + vWork[nIndex[i][0]] = va[nIndex[i][0]] * c - va[nIndex[i][1]] * s; + vWork[nIndex[i][1]] = va[nIndex[i][0]] * s + va[nIndex[i][1]] * c; + } + VectorCopy(vWork, va); + } + VectorCopy(vWork, out); +} + +void VectorRotateOrigin (vec3_t vIn, vec3_t vRotation, vec3_t vOrigin, vec3_t out) +{ + vec3_t vTemp, vTemp2; + + VectorSubtract(vIn, vOrigin, vTemp); + VectorRotate(vTemp, vRotation, vTemp2); + VectorAdd(vTemp2, vOrigin, out); +} + +void VectorPolar(vec3_t v, float radius, float theta, float phi) +{ + v[0]=(float)(radius * cos(theta) * cos(phi)); + v[1]=(float)(radius * sin(theta) * cos(phi)); + v[2]=(float)(radius * sin(phi)); +} + +void VectorSnap(vec3_t v) +{ + int i; + for (i = 0; i < 3; i++) + { + v[i] = (vec_t)floor (v[i] + 0.5); + } +} + +void VectorISnap(vec3_t point, int snap) +{ + int i; + for (i = 0 ;i < 3 ; i++) + { + point[i] = (vec_t)floor (point[i] / snap + 0.5) * snap; + } +} + +void VectorFSnap(vec3_t point, float snap) +{ + int i; + for (i = 0 ;i < 3 ; i++) + { + point[i] = (vec_t)floor (point[i] / snap + 0.5) * snap; + } +} + +void _Vector5Add (vec5_t va, vec5_t vb, vec5_t out) +{ + out[0] = va[0]+vb[0]; + out[1] = va[1]+vb[1]; + out[2] = va[2]+vb[2]; + out[3] = va[3]+vb[3]; + out[4] = va[4]+vb[4]; +} + +void _Vector5Scale (vec5_t v, vec_t scale, vec5_t out) +{ + out[0] = v[0] * scale; + out[1] = v[1] * scale; + out[2] = v[2] * scale; + out[3] = v[3] * scale; + out[4] = v[4] * scale; +} + +void _Vector53Copy (vec5_t in, vec3_t out) +{ + out[0] = in[0]; + out[1] = in[1]; + out[2] = in[2]; +} + +// NOTE: added these from Ritual's Q3Radiant +void ClearBounds (vec3_t mins, vec3_t maxs) +{ + mins[0] = mins[1] = mins[2] = 99999; + maxs[0] = maxs[1] = maxs[2] = -99999; +} + +void AddPointToBounds (vec3_t v, vec3_t mins, vec3_t maxs) +{ + int i; + vec_t val; + + for (i=0 ; i<3 ; i++) + { + val = v[i]; + if (val < mins[i]) + mins[i] = val; + if (val > maxs[i]) + maxs[i] = val; + } +} + +#define PITCH 0 // up / down +#define YAW 1 // left / right +#define ROLL 2 // fall over +#ifndef M_PI +#define M_PI 3.14159265358979323846f // matches value in gcc v2 math.h +#endif + +void AngleVectors (vec3_t angles, vec3_t forward, vec3_t right, vec3_t up) +{ + float angle; + static float sr, sp, sy, cr, cp, cy; + // static to help MS compiler fp bugs + + angle = angles[YAW] * (M_PI*2.0f / 360.0f); + sy = (vec_t)sin(angle); + cy = (vec_t)cos(angle); + angle = angles[PITCH] * (M_PI*2.0f / 360.0f); + sp = (vec_t)sin(angle); + cp = (vec_t)cos(angle); + angle = angles[ROLL] * (M_PI*2.0f / 360.0f); + sr = (vec_t)sin(angle); + cr = (vec_t)cos(angle); + + if (forward) + { + forward[0] = cp*cy; + forward[1] = cp*sy; + forward[2] = -sp; + } + if (right) + { + right[0] = -sr*sp*cy+cr*sy; + right[1] = -sr*sp*sy-cr*cy; + right[2] = -sr*cp; + } + if (up) + { + up[0] = cr*sp*cy+sr*sy; + up[1] = cr*sp*sy-sr*cy; + up[2] = cr*cp; + } +} + +void VectorToAngles( vec3_t vec, vec3_t angles ) +{ + float forward; + float yaw, pitch; + + if ( ( vec[ 0 ] == 0 ) && ( vec[ 1 ] == 0 ) ) + { + yaw = 0; + if ( vec[ 2 ] > 0 ) + { + pitch = 90; + } + else + { + pitch = 270; + } + } + else + { + yaw = (vec_t)atan2( vec[ 1 ], vec[ 0 ] ) * 180 / M_PI; + if ( yaw < 0 ) + { + yaw += 360; + } + + forward = ( float )sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] ); + pitch = (vec_t)atan2( vec[ 2 ], forward ) * 180 / M_PI; + if ( pitch < 0 ) + { + pitch += 360; + } + } + + angles[ 0 ] = pitch; + angles[ 1 ] = yaw; + angles[ 2 ] = 0; +} + +/* +===================== +PlaneFromPoints + +Returns false if the triangle is degenrate. +The normal will point out of the clock for clockwise ordered points +===================== +*/ +qboolean PlaneFromPoints( vec4_t plane, const vec3_t a, const vec3_t b, const vec3_t c ) { + vec3_t d1, d2; + + VectorSubtract( b, a, d1 ); + VectorSubtract( c, a, d2 ); + CrossProduct( d2, d1, plane ); + if ( VectorNormalize( plane, plane ) == 0 ) { + return qfalse; + } + + plane[3] = DotProduct( a, plane ); + return qtrue; +} + +/* +** NormalToLatLong +** +** We use two byte encoded normals in some space critical applications. +** Lat = 0 at (1,0,0) to 360 (-1,0,0), encoded in 8-bit sine table format +** Lng = 0 at (0,0,1) to 180 (0,0,-1), encoded in 8-bit sine table format +** +*/ +void NormalToLatLong( const vec3_t normal, byte bytes[2] ) { + // check for singularities + if ( normal[0] == 0 && normal[1] == 0 ) { + if ( normal[2] > 0 ) { + bytes[0] = 0; + bytes[1] = 0; // lat = 0, long = 0 + } else { + bytes[0] = 128; + bytes[1] = 0; // lat = 0, long = 128 + } + } else { + int a, b; + + a = (int)( RAD2DEG( atan2( normal[1], normal[0] ) ) * (255.0f / 360.0f ) ); + a &= 0xff; + + b = (int)( RAD2DEG( acos( normal[2] ) ) * ( 255.0f / 360.0f ) ); + b &= 0xff; + + bytes[0] = b; // longitude + bytes[1] = a; // lattitude + } +} + +/* +================= +PlaneTypeForNormal +================= +*/ +int PlaneTypeForNormal (vec3_t normal) { + if (normal[0] == 1.0 || normal[0] == -1.0) + return PLANE_X; + if (normal[1] == 1.0 || normal[1] == -1.0) + return PLANE_Y; + if (normal[2] == 1.0 || normal[2] == -1.0) + return PLANE_Z; + + return PLANE_NON_AXIAL; +} + +/* +================ +MatrixMultiply +================ +*/ +void MatrixMultiply(float in1[3][3], float in2[3][3], float out[3][3]) { + out[0][0] = in1[0][0] * in2[0][0] + in1[0][1] * in2[1][0] + + in1[0][2] * in2[2][0]; + out[0][1] = in1[0][0] * in2[0][1] + in1[0][1] * in2[1][1] + + in1[0][2] * in2[2][1]; + out[0][2] = in1[0][0] * in2[0][2] + in1[0][1] * in2[1][2] + + in1[0][2] * in2[2][2]; + out[1][0] = in1[1][0] * in2[0][0] + in1[1][1] * in2[1][0] + + in1[1][2] * in2[2][0]; + out[1][1] = in1[1][0] * in2[0][1] + in1[1][1] * in2[1][1] + + in1[1][2] * in2[2][1]; + out[1][2] = in1[1][0] * in2[0][2] + in1[1][1] * in2[1][2] + + in1[1][2] * in2[2][2]; + out[2][0] = in1[2][0] * in2[0][0] + in1[2][1] * in2[1][0] + + in1[2][2] * in2[2][0]; + out[2][1] = in1[2][0] * in2[0][1] + in1[2][1] * in2[1][1] + + in1[2][2] * in2[2][1]; + out[2][2] = in1[2][0] * in2[0][2] + in1[2][1] * in2[1][2] + + in1[2][2] * in2[2][2]; +} + +void ProjectPointOnPlane( vec3_t dst, const vec3_t p, const vec3_t normal ) +{ + float d; + vec3_t n; + float inv_denom; + + inv_denom = 1.0F / DotProduct( normal, normal ); + + d = DotProduct( normal, p ) * inv_denom; + + n[0] = normal[0] * inv_denom; + n[1] = normal[1] * inv_denom; + n[2] = normal[2] * inv_denom; + + dst[0] = p[0] - d * n[0]; + dst[1] = p[1] - d * n[1]; + dst[2] = p[2] - d * n[2]; +} + +/* +** assumes "src" is normalized +*/ +void PerpendicularVector( vec3_t dst, const vec3_t src ) +{ + int pos; + int i; + vec_t minelem = 1.0F; + vec3_t tempvec; + + /* + ** find the smallest magnitude axially aligned vector + */ + for ( pos = 0, i = 0; i < 3; i++ ) + { + if ( fabs( src[i] ) < minelem ) + { + pos = i; + minelem = (vec_t)fabs( src[i] ); + } + } + tempvec[0] = tempvec[1] = tempvec[2] = 0.0F; + tempvec[pos] = 1.0F; + + /* + ** project the point onto the plane defined by src + */ + ProjectPointOnPlane( dst, tempvec, src ); + + /* + ** normalize the result + */ + VectorNormalize( dst, dst ); +} + +/* +=============== +RotatePointAroundVector + +This is not implemented very well... +=============== +*/ +void RotatePointAroundVector( vec3_t dst, const vec3_t dir, const vec3_t point, + float degrees ) { + float m[3][3]; + float im[3][3]; + float zrot[3][3]; + float tmpmat[3][3]; + float rot[3][3]; + int i; + vec3_t vr, vup, vf; + float rad; + + vf[0] = dir[0]; + vf[1] = dir[1]; + vf[2] = dir[2]; + + PerpendicularVector( vr, dir ); + CrossProduct( vr, vf, vup ); + + m[0][0] = vr[0]; + m[1][0] = vr[1]; + m[2][0] = vr[2]; + + m[0][1] = vup[0]; + m[1][1] = vup[1]; + m[2][1] = vup[2]; + + m[0][2] = vf[0]; + m[1][2] = vf[1]; + m[2][2] = vf[2]; + + memcpy( im, m, sizeof( im ) ); + + im[0][1] = m[1][0]; + im[0][2] = m[2][0]; + im[1][0] = m[0][1]; + im[1][2] = m[2][1]; + im[2][0] = m[0][2]; + im[2][1] = m[1][2]; + + memset( zrot, 0, sizeof( zrot ) ); + zrot[0][0] = zrot[1][1] = zrot[2][2] = 1.0F; + + rad = DEG2RAD( degrees ); + zrot[0][0] = (vec_t)cos( rad ); + zrot[0][1] = (vec_t)sin( rad ); + zrot[1][0] = (vec_t)-sin( rad ); + zrot[1][1] = (vec_t)cos( rad ); + + MatrixMultiply( m, zrot, tmpmat ); + MatrixMultiply( tmpmat, im, rot ); + + for ( i = 0; i < 3; i++ ) { + dst[i] = rot[i][0] * point[0] + rot[i][1] * point[1] + rot[i][2] * point[2]; + } +} diff --git a/libs/mathlib/mathlib.vcproj b/libs/mathlib/mathlib.vcproj new file mode 100644 index 00000000..4dfa2c0e --- /dev/null +++ b/libs/mathlib/mathlib.vcproj @@ -0,0 +1,65 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/mathlib/ray.c b/libs/mathlib/ray.c new file mode 100644 index 00000000..08cb9f87 --- /dev/null +++ b/libs/mathlib/ray.c @@ -0,0 +1,135 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include "mathlib.h" +/*! for memcpy */ +#include + +vec3_t identity = { 0,0,0 }; + +void ray_construct_for_vec3(ray_t *ray, const vec3_t origin, const vec3_t direction) +{ + VectorCopy(origin, ray->origin); + VectorCopy(direction, ray->direction); +} + +void ray_transform(ray_t *ray, const m4x4_t matrix) +{ + m4x4_transform_point(matrix, ray->origin); + m4x4_transform_normal(matrix, ray->direction); +} + +vec_t ray_intersect_point(const ray_t *ray, const vec3_t point, vec_t epsilon, vec_t divergence) +{ + vec3_t displacement; + vec_t depth; + + // calc displacement of test point from ray origin + VectorSubtract(point, ray->origin, displacement); + // calc length of displacement vector along ray direction + depth = DotProduct(displacement, ray->direction); + if(depth < 0.0f) return (vec_t)VEC_MAX; + // calc position of closest point on ray to test point + VectorMA (ray->origin, depth, ray->direction, displacement); + // calc displacement of test point from closest point + VectorSubtract(point, displacement, displacement); + // calc length of displacement, subtract depth-dependant epsilon + if (VectorLength(displacement) - (epsilon + (depth * divergence)) > 0.0f) return (vec_t)VEC_MAX; + return depth; +} + +// Tomas Moller and Ben Trumbore. Fast, minimum storage ray-triangle intersection. Journal of graphics tools, 2(1):21-28, 1997 + +#define EPSILON 0.000001 + +vec_t ray_intersect_triangle(const ray_t *ray, qboolean bCullBack, const vec3_t vert0, const vec3_t vert1, const vec3_t vert2) +{ + float edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; + float det,inv_det; + float u, v; + vec_t depth = (vec_t)VEC_MAX; + + /* find vectors for two edges sharing vert0 */ + VectorSubtract(vert1, vert0, edge1); + VectorSubtract(vert2, vert0, edge2); + + /* begin calculating determinant - also used to calculate U parameter */ + CrossProduct(ray->direction, edge2, pvec); + + /* if determinant is near zero, ray lies in plane of triangle */ + det = DotProduct(edge1, pvec); + + if (bCullBack == qtrue) + { + if (det < EPSILON) + return depth; + + // calculate distance from vert0 to ray origin + VectorSubtract(ray->origin, vert0, tvec); + + // calculate U parameter and test bounds + u = DotProduct(tvec, pvec); + if (u < 0.0 || u > det) + return depth; + + // prepare to test V parameter + CrossProduct(tvec, edge1, qvec); + + // calculate V parameter and test bounds + v = DotProduct(ray->direction, qvec); + if (v < 0.0 || u + v > det) + return depth; + + // calculate t, scale parameters, ray intersects triangle + depth = DotProduct(edge2, qvec); + inv_det = 1.0f / det; + depth *= inv_det; + //u *= inv_det; + //v *= inv_det; + } + else + { + /* the non-culling branch */ + if (det > -EPSILON && det < EPSILON) + return depth; + inv_det = 1.0f / det; + + /* calculate distance from vert0 to ray origin */ + VectorSubtract(ray->origin, vert0, tvec); + + /* calculate U parameter and test bounds */ + u = DotProduct(tvec, pvec) * inv_det; + if (u < 0.0 || u > 1.0) + return depth; + + /* prepare to test V parameter */ + CrossProduct(tvec, edge1, qvec); + + /* calculate V parameter and test bounds */ + v = DotProduct(ray->direction, qvec) * inv_det; + if (v < 0.0 || u + v > 1.0) + return depth; + + /* calculate t, ray intersects triangle */ + depth = DotProduct(edge2, qvec) * inv_det; + } + return depth; +} diff --git a/libs/md5lib.h b/libs/md5lib.h new file mode 100644 index 00000000..32963357 --- /dev/null +++ b/libs/md5lib.h @@ -0,0 +1,91 @@ +/* + Copyright (C) 1999, 2002 Aladdin Enterprises. All rights reserved. + + 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. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5lib.h,v 1.1 2003/07/18 04:24:39 ydnar Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.h is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2002-04-13 lpd Removed support for non-ANSI compilers; removed + references to Ghostscript; clarified derivation from RFC 1321; + now handles byte order either statically or dynamically. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5); + added conditionalization for C++ compilation from Martin + Purschke . + 1999-05-03 lpd Original version. + */ + +#ifndef md5_INCLUDED +# define md5_INCLUDED + +/* + * This package supports both compile-time and run-time determination of CPU + * byte order. If ARCH_IS_BIG_ENDIAN is defined as 0, the code will be + * compiled to run only on little-endian CPUs; if ARCH_IS_BIG_ENDIAN is + * defined as non-zero, the code will be compiled to run only on big-endian + * CPUs; if ARCH_IS_BIG_ENDIAN is not defined, the code will be compiled to + * run on either big- or little-endian CPUs, but will run slightly less + * efficiently on either one than if ARCH_IS_BIG_ENDIAN is defined. + */ + +typedef unsigned char md5_byte_t; /* 8-bit byte */ +typedef unsigned int md5_word_t; /* 32-bit word */ + +/* Define the state of the MD5 Algorithm. */ +typedef struct md5_state_s { + md5_word_t count[2]; /* message length in bits, lsw first */ + md5_word_t abcd[4]; /* digest buffer */ + md5_byte_t buf[64]; /* accumulate block */ +} md5_state_t; + +#ifdef __cplusplus +extern "C" +{ +#endif + +/* Initialize the algorithm. */ +void md5_init(md5_state_t *pms); + +/* Append a string to the message. */ +void md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes); + +/* Finish the message and return the digest. */ +void md5_finish(md5_state_t *pms, md5_byte_t digest[16]); + +#ifdef __cplusplus +} /* end extern "C" */ +#endif + +#endif /* md5_INCLUDED */ diff --git a/libs/md5lib/Conscript b/libs/md5lib/Conscript new file mode 100644 index 00000000..63db5316 --- /dev/null +++ b/libs/md5lib/Conscript @@ -0,0 +1,11 @@ +Import qw( BASE_CFLAGS CC ); + +$env = new cons +( + ENV => { PATH => $ENV{PATH}, HOME => $ENV{HOME} }, + CC => $CC, + CPPPATH => "#libs", + CFLAGS => $BASE_CFLAGS +); +Library $env 'md5lib', 'md5lib.c'; +Install $env '..', 'md5lib.a'; diff --git a/libs/md5lib/md5lib.c b/libs/md5lib/md5lib.c new file mode 100644 index 00000000..6fb45f13 --- /dev/null +++ b/libs/md5lib/md5lib.c @@ -0,0 +1,395 @@ +/* + Copyright (C) 1999, 2000, 2002 Aladdin Enterprises. All rights reserved. + + 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. + + L. Peter Deutsch + ghost@aladdin.com + + */ +/* $Id: md5lib.c,v 1.1 2003/07/18 04:24:39 ydnar Exp $ */ +/* + Independent implementation of MD5 (RFC 1321). + + This code implements the MD5 Algorithm defined in RFC 1321, whose + text is available at + http://www.ietf.org/rfc/rfc1321.txt + The code is derived from the text of the RFC, including the test suite + (section A.5) but excluding the rest of Appendix A. It does not include + any code or documentation that is identified in the RFC as being + copyrighted. + + The original and principal author of md5.c is L. Peter Deutsch + . Other authors are noted in the change history + that follows (in reverse chronological order): + + 2003-07-17 ydnar added to gtkradiant project from + http://sourceforge.net/projects/libmd5-rfc/ + 2002-04-13 lpd Clarified derivation from RFC 1321; now handles byte order + either statically or dynamically; added missing #include + in library. + 2002-03-11 lpd Corrected argument list for main(), and added int return + type, in test program and T value program. + 2002-02-21 lpd Added missing #include in test program. + 2000-07-03 lpd Patched to eliminate warnings about "constant is + unsigned in ANSI C, signed in traditional"; made test program + self-checking. + 1999-11-04 lpd Edited comments slightly for automatic TOC extraction. + 1999-10-18 lpd Fixed typo in header comment (ansi2knr rather than md5). + 1999-05-03 lpd Original version. + */ + +#include "md5lib.h" /* ydnar */ +#include + +/* ydnar: gtkradiant endian picking */ +#ifdef _SGI_SOURCE +#define __BIG_ENDIAN__ +#endif + +#ifdef __BIG_ENDIAN__ +#define ARCH_IS_BIG_ENDIAN 1 +#else +#define ARCH_IS_BIG_ENDIAN 0 +#endif +/* ydnar: end */ + +#undef BYTE_ORDER /* 1 = big-endian, -1 = little-endian, 0 = unknown */ +#ifdef ARCH_IS_BIG_ENDIAN +# define BYTE_ORDER (ARCH_IS_BIG_ENDIAN ? 1 : -1) +#else +# define BYTE_ORDER 0 +#endif + +#define T_MASK ((md5_word_t)~0) +#define T1 /* 0xd76aa478 */ (T_MASK ^ 0x28955b87) +#define T2 /* 0xe8c7b756 */ (T_MASK ^ 0x173848a9) +#define T3 0x242070db +#define T4 /* 0xc1bdceee */ (T_MASK ^ 0x3e423111) +#define T5 /* 0xf57c0faf */ (T_MASK ^ 0x0a83f050) +#define T6 0x4787c62a +#define T7 /* 0xa8304613 */ (T_MASK ^ 0x57cfb9ec) +#define T8 /* 0xfd469501 */ (T_MASK ^ 0x02b96afe) +#define T9 0x698098d8 +#define T10 /* 0x8b44f7af */ (T_MASK ^ 0x74bb0850) +#define T11 /* 0xffff5bb1 */ (T_MASK ^ 0x0000a44e) +#define T12 /* 0x895cd7be */ (T_MASK ^ 0x76a32841) +#define T13 0x6b901122 +#define T14 /* 0xfd987193 */ (T_MASK ^ 0x02678e6c) +#define T15 /* 0xa679438e */ (T_MASK ^ 0x5986bc71) +#define T16 0x49b40821 +#define T17 /* 0xf61e2562 */ (T_MASK ^ 0x09e1da9d) +#define T18 /* 0xc040b340 */ (T_MASK ^ 0x3fbf4cbf) +#define T19 0x265e5a51 +#define T20 /* 0xe9b6c7aa */ (T_MASK ^ 0x16493855) +#define T21 /* 0xd62f105d */ (T_MASK ^ 0x29d0efa2) +#define T22 0x02441453 +#define T23 /* 0xd8a1e681 */ (T_MASK ^ 0x275e197e) +#define T24 /* 0xe7d3fbc8 */ (T_MASK ^ 0x182c0437) +#define T25 0x21e1cde6 +#define T26 /* 0xc33707d6 */ (T_MASK ^ 0x3cc8f829) +#define T27 /* 0xf4d50d87 */ (T_MASK ^ 0x0b2af278) +#define T28 0x455a14ed +#define T29 /* 0xa9e3e905 */ (T_MASK ^ 0x561c16fa) +#define T30 /* 0xfcefa3f8 */ (T_MASK ^ 0x03105c07) +#define T31 0x676f02d9 +#define T32 /* 0x8d2a4c8a */ (T_MASK ^ 0x72d5b375) +#define T33 /* 0xfffa3942 */ (T_MASK ^ 0x0005c6bd) +#define T34 /* 0x8771f681 */ (T_MASK ^ 0x788e097e) +#define T35 0x6d9d6122 +#define T36 /* 0xfde5380c */ (T_MASK ^ 0x021ac7f3) +#define T37 /* 0xa4beea44 */ (T_MASK ^ 0x5b4115bb) +#define T38 0x4bdecfa9 +#define T39 /* 0xf6bb4b60 */ (T_MASK ^ 0x0944b49f) +#define T40 /* 0xbebfbc70 */ (T_MASK ^ 0x4140438f) +#define T41 0x289b7ec6 +#define T42 /* 0xeaa127fa */ (T_MASK ^ 0x155ed805) +#define T43 /* 0xd4ef3085 */ (T_MASK ^ 0x2b10cf7a) +#define T44 0x04881d05 +#define T45 /* 0xd9d4d039 */ (T_MASK ^ 0x262b2fc6) +#define T46 /* 0xe6db99e5 */ (T_MASK ^ 0x1924661a) +#define T47 0x1fa27cf8 +#define T48 /* 0xc4ac5665 */ (T_MASK ^ 0x3b53a99a) +#define T49 /* 0xf4292244 */ (T_MASK ^ 0x0bd6ddbb) +#define T50 0x432aff97 +#define T51 /* 0xab9423a7 */ (T_MASK ^ 0x546bdc58) +#define T52 /* 0xfc93a039 */ (T_MASK ^ 0x036c5fc6) +#define T53 0x655b59c3 +#define T54 /* 0x8f0ccc92 */ (T_MASK ^ 0x70f3336d) +#define T55 /* 0xffeff47d */ (T_MASK ^ 0x00100b82) +#define T56 /* 0x85845dd1 */ (T_MASK ^ 0x7a7ba22e) +#define T57 0x6fa87e4f +#define T58 /* 0xfe2ce6e0 */ (T_MASK ^ 0x01d3191f) +#define T59 /* 0xa3014314 */ (T_MASK ^ 0x5cfebceb) +#define T60 0x4e0811a1 +#define T61 /* 0xf7537e82 */ (T_MASK ^ 0x08ac817d) +#define T62 /* 0xbd3af235 */ (T_MASK ^ 0x42c50dca) +#define T63 0x2ad7d2bb +#define T64 /* 0xeb86d391 */ (T_MASK ^ 0x14792c6e) + + +static void +md5_process(md5_state_t *pms, const md5_byte_t *data /*[64]*/) +{ + md5_word_t + a = pms->abcd[0], b = pms->abcd[1], + c = pms->abcd[2], d = pms->abcd[3]; + md5_word_t t; +#if BYTE_ORDER > 0 + /* Define storage only for big-endian CPUs. */ + md5_word_t X[16]; +#else + /* Define storage for little-endian or both types of CPUs. */ + md5_word_t xbuf[16]; + const md5_word_t *X; +#endif + + { +#if BYTE_ORDER == 0 + /* + * Determine dynamically whether this is a big-endian or + * little-endian machine, since we can use a more efficient + * algorithm on the latter. + */ + static const int w = 1; + + if (*((const md5_byte_t *)&w)) /* dynamic little-endian */ +#endif +#if BYTE_ORDER <= 0 /* little-endian */ + { + /* + * On little-endian machines, we can process properly aligned + * data without copying it. + */ + if (!((data - (const md5_byte_t *)0) & 3)) { + /* data are properly aligned */ + X = (const md5_word_t *)data; + } else { + /* not aligned */ + memcpy(xbuf, data, 64); + X = xbuf; + } + } +#endif +#if BYTE_ORDER == 0 + else /* dynamic big-endian */ +#endif +#if BYTE_ORDER >= 0 /* big-endian */ + { + /* + * On big-endian machines, we must arrange the bytes in the + * right order. + */ + const md5_byte_t *xp = data; + int i; + +# if BYTE_ORDER == 0 + X = xbuf; /* (dynamic only) */ +# else +# define xbuf X /* (static only) */ +# endif + for (i = 0; i < 16; ++i, xp += 4) + xbuf[i] = xp[0] + (xp[1] << 8) + (xp[2] << 16) + (xp[3] << 24); + } +#endif + } + +#define ROTATE_LEFT(x, n) (((x) << (n)) | ((x) >> (32 - (n)))) + + /* Round 1. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + F(b,c,d) + X[k] + T[i]) <<< s). */ +#define F(x, y, z) (((x) & (y)) | (~(x) & (z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + F(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 7, T1); + SET(d, a, b, c, 1, 12, T2); + SET(c, d, a, b, 2, 17, T3); + SET(b, c, d, a, 3, 22, T4); + SET(a, b, c, d, 4, 7, T5); + SET(d, a, b, c, 5, 12, T6); + SET(c, d, a, b, 6, 17, T7); + SET(b, c, d, a, 7, 22, T8); + SET(a, b, c, d, 8, 7, T9); + SET(d, a, b, c, 9, 12, T10); + SET(c, d, a, b, 10, 17, T11); + SET(b, c, d, a, 11, 22, T12); + SET(a, b, c, d, 12, 7, T13); + SET(d, a, b, c, 13, 12, T14); + SET(c, d, a, b, 14, 17, T15); + SET(b, c, d, a, 15, 22, T16); +#undef SET + + /* Round 2. */ + /* Let [abcd k s i] denote the operation + a = b + ((a + G(b,c,d) + X[k] + T[i]) <<< s). */ +#define G(x, y, z) (((x) & (z)) | ((y) & ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + G(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 1, 5, T17); + SET(d, a, b, c, 6, 9, T18); + SET(c, d, a, b, 11, 14, T19); + SET(b, c, d, a, 0, 20, T20); + SET(a, b, c, d, 5, 5, T21); + SET(d, a, b, c, 10, 9, T22); + SET(c, d, a, b, 15, 14, T23); + SET(b, c, d, a, 4, 20, T24); + SET(a, b, c, d, 9, 5, T25); + SET(d, a, b, c, 14, 9, T26); + SET(c, d, a, b, 3, 14, T27); + SET(b, c, d, a, 8, 20, T28); + SET(a, b, c, d, 13, 5, T29); + SET(d, a, b, c, 2, 9, T30); + SET(c, d, a, b, 7, 14, T31); + SET(b, c, d, a, 12, 20, T32); +#undef SET + + /* Round 3. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + H(b,c,d) + X[k] + T[i]) <<< s). */ +#define H(x, y, z) ((x) ^ (y) ^ (z)) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + H(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 5, 4, T33); + SET(d, a, b, c, 8, 11, T34); + SET(c, d, a, b, 11, 16, T35); + SET(b, c, d, a, 14, 23, T36); + SET(a, b, c, d, 1, 4, T37); + SET(d, a, b, c, 4, 11, T38); + SET(c, d, a, b, 7, 16, T39); + SET(b, c, d, a, 10, 23, T40); + SET(a, b, c, d, 13, 4, T41); + SET(d, a, b, c, 0, 11, T42); + SET(c, d, a, b, 3, 16, T43); + SET(b, c, d, a, 6, 23, T44); + SET(a, b, c, d, 9, 4, T45); + SET(d, a, b, c, 12, 11, T46); + SET(c, d, a, b, 15, 16, T47); + SET(b, c, d, a, 2, 23, T48); +#undef SET + + /* Round 4. */ + /* Let [abcd k s t] denote the operation + a = b + ((a + I(b,c,d) + X[k] + T[i]) <<< s). */ +#define I(x, y, z) ((y) ^ ((x) | ~(z))) +#define SET(a, b, c, d, k, s, Ti)\ + t = a + I(b,c,d) + X[k] + Ti;\ + a = ROTATE_LEFT(t, s) + b + /* Do the following 16 operations. */ + SET(a, b, c, d, 0, 6, T49); + SET(d, a, b, c, 7, 10, T50); + SET(c, d, a, b, 14, 15, T51); + SET(b, c, d, a, 5, 21, T52); + SET(a, b, c, d, 12, 6, T53); + SET(d, a, b, c, 3, 10, T54); + SET(c, d, a, b, 10, 15, T55); + SET(b, c, d, a, 1, 21, T56); + SET(a, b, c, d, 8, 6, T57); + SET(d, a, b, c, 15, 10, T58); + SET(c, d, a, b, 6, 15, T59); + SET(b, c, d, a, 13, 21, T60); + SET(a, b, c, d, 4, 6, T61); + SET(d, a, b, c, 11, 10, T62); + SET(c, d, a, b, 2, 15, T63); + SET(b, c, d, a, 9, 21, T64); +#undef SET + + /* Then perform the following additions. (That is increment each + of the four registers by the value it had before this block + was started.) */ + pms->abcd[0] += a; + pms->abcd[1] += b; + pms->abcd[2] += c; + pms->abcd[3] += d; +} + +void +md5_init(md5_state_t *pms) +{ + pms->count[0] = pms->count[1] = 0; + pms->abcd[0] = 0x67452301; + pms->abcd[1] = /*0xefcdab89*/ T_MASK ^ 0x10325476; + pms->abcd[2] = /*0x98badcfe*/ T_MASK ^ 0x67452301; + pms->abcd[3] = 0x10325476; +} + +void +md5_append(md5_state_t *pms, const md5_byte_t *data, int nbytes) +{ + const md5_byte_t *p = data; + int left = nbytes; + int offset = (pms->count[0] >> 3) & 63; + md5_word_t nbits = (md5_word_t)(nbytes << 3); + + if (nbytes <= 0) + return; + + /* Update the message length. */ + pms->count[1] += nbytes >> 29; + pms->count[0] += nbits; + if (pms->count[0] < nbits) + pms->count[1]++; + + /* Process an initial partial block. */ + if (offset) { + int copy = (offset + nbytes > 64 ? 64 - offset : nbytes); + + memcpy(pms->buf + offset, p, copy); + if (offset + copy < 64) + return; + p += copy; + left -= copy; + md5_process(pms, pms->buf); + } + + /* Process full blocks. */ + for (; left >= 64; p += 64, left -= 64) + md5_process(pms, p); + + /* Process a final partial block. */ + if (left) + memcpy(pms->buf, p, left); +} + +void +md5_finish(md5_state_t *pms, md5_byte_t digest[16]) +{ + static const md5_byte_t pad[64] = { + 0x80, 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 + }; + md5_byte_t data[8]; + int i; + + /* Save the length before padding. */ + for (i = 0; i < 8; ++i) + data[i] = (md5_byte_t)(pms->count[i >> 2] >> ((i & 3) << 3)); + /* Pad to 56 bytes mod 64. */ + md5_append(pms, pad, ((55 - (pms->count[0] >> 3)) & 63) + 1); + /* Append the length. */ + md5_append(pms, data, 8); + for (i = 0; i < 16; ++i) + digest[i] = (md5_byte_t)(pms->abcd[i >> 2] >> ((i & 3) << 3)); +} diff --git a/libs/md5lib/md5lib.vcproj b/libs/md5lib/md5lib.vcproj new file mode 100644 index 00000000..e1e603f4 --- /dev/null +++ b/libs/md5lib/md5lib.vcproj @@ -0,0 +1,57 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/missing.h b/libs/missing.h new file mode 100644 index 00000000..a9288d5c --- /dev/null +++ b/libs/missing.h @@ -0,0 +1,212 @@ +/* +Copyright (c) 2001, Loki software, inc. +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 Loki software 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 REGENTS 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. +*/ + +#ifndef _MISSING_H_ +#define _MISSING_H_ + +// NOTE TTimo +// this goes along with str.h and provides various utility classes +// and portability defines +// the filename is a legecy issue, it would be better to clean that up +// in a central 'portability' lib + +#include +#include + +#ifdef _WIN32 +#include +#include + +#define MyCopyFile(a,b) CopyFile(a,b,FALSE) + +#define S_ISDIR(mode) (mode & _S_IFDIR) +#define R_OK 04 +#define mymkdir(a,b) _mkdir(a) + +#else + +#define MyCopyFile CopyFile +#define mymkdir(a,b) mkdir(a,b) + +#endif + +#ifndef _WIN32 + +// LZ: very ugly hacks +inline int GetLastError () { return 0; }; + +// temp stuff +inline int GetPrivateProfileInt(char* a, char* b, int i, char* c) { return i; }; +#define VERIFY(a) a; +int GetFullPathName(const char *lpFileName, int nBufferLength, char *lpBuffer, char **lpFilePart); +bool CopyFile(const char *lpExistingFileName, const char *lpNewFileName); + +#ifndef APIENTRY +#define APIENTRY +#endif + +int MemorySize(void *ptr); +#define _msize MemorySize + +#define MK_LBUTTON 0x0001 +#define MK_RBUTTON 0x0002 +#define MK_SHIFT 0x0004 +#define MK_CONTROL 0x0008 +#define MK_MBUTTON 0x0010 + +#endif + +#define CString Str +#include "str.h" + +class CPtrArray +{ +public: + CPtrArray () + { m_ptrs = g_ptr_array_new (); }; + virtual ~CPtrArray () + { g_ptr_array_free (m_ptrs, TRUE); }; + + void* operator[](int i) const + { return g_ptr_array_index (m_ptrs,i); }; + void* GetAt(int i) const + { return g_ptr_array_index (m_ptrs,i); }; + int GetSize () const + { return m_ptrs->len; }; + void Add (void* ptr) + { g_ptr_array_add (m_ptrs, ptr); }; + void RemoveAll () + { g_ptr_array_set_size (m_ptrs, 0); }; + void RemoveAt(int index, int count = 1) + { + if ((index < 0) || (count < 0) || (count + index > (int)m_ptrs->len)) + return; + for (; count > 0; count--) + g_ptr_array_remove_index (m_ptrs, index); + } + void InsertAt(int nStartIndex, CPtrArray* pNewArray) + { + for (int i = 0; i < pNewArray->GetSize(); i++) + InsertAt(nStartIndex+i, pNewArray->GetAt(i)); + } + void InsertAt(int nIndex, void* newElement, int nCount = 1) + { + if ((guint32)nIndex >= m_ptrs->len) + { + g_ptr_array_set_size (m_ptrs, nIndex + nCount); // grow so nIndex is valid + } + else + { + // inserting in the middle of the array + int nOldSize = m_ptrs->len; + g_ptr_array_set_size (m_ptrs, m_ptrs->len + nCount); + // shift old data up to fill gap + memmove(&m_ptrs->pdata[nIndex+nCount], &m_ptrs->pdata[nIndex], + (nOldSize-nIndex) * sizeof(gpointer)); + + memset(&m_ptrs->pdata[nIndex], 0, nCount * sizeof(gpointer)); + } + + // insert new value in the gap + while (nCount--) + m_ptrs->pdata[nIndex++] = newElement; + } + void Copy(const CPtrArray& src) + { + g_ptr_array_set_size (m_ptrs, src.m_ptrs->len); + memcpy (m_ptrs->pdata, src.m_ptrs->pdata, m_ptrs->len*sizeof(gpointer)); + } + +protected: + GPtrArray* m_ptrs; +}; + +typedef struct stringmap_s +{ + char* key; + char* value; +} stringmap_t; + +class CMapStringToString +{ +public: + CMapStringToString () + { m_map = g_ptr_array_new (); }; + ~CMapStringToString () + { + for (guint32 i = 0; i < m_map->len; i++) + FreeElement ((stringmap_t*)g_ptr_array_index (m_map,i)); + g_ptr_array_set_size (m_map, 0); + g_ptr_array_free (m_map, TRUE); + }; + void SetAt(char* key, char* newValue) + { + for (guint32 i = 0; i < m_map->len; i++) + { + stringmap_t* entry = (stringmap_t*)g_ptr_array_index (m_map,i); + if (strcmp (entry->key, key) == 0) + { + g_free (entry->value); + entry->value = g_strdup (newValue); + return; + } + } + stringmap_t* entry = (stringmap_t*)g_malloc (sizeof (stringmap_t)); + entry->key = g_strdup (key); + entry->value = g_strdup (newValue); + g_ptr_array_add (m_map, entry); + } + + bool Lookup(const char* key, CString& rValue) const + { + for (guint32 i = 0; i < m_map->len; i++) + { + stringmap_t* entry = (stringmap_t*)g_ptr_array_index (m_map,i); + if (strcmp (entry->key, key) == 0) + { + rValue = entry->value; + return true; + } + } + return false; + } + +protected: + GPtrArray* m_map; + + void FreeElement(stringmap_t* elem) + { + g_free (elem->key); + g_free (elem->value); + g_free (elem); + }; +}; + +#endif // _MISSING_H_ diff --git a/libs/multimon.h b/libs/multimon.h new file mode 100644 index 00000000..9a4e9ad7 --- /dev/null +++ b/libs/multimon.h @@ -0,0 +1,381 @@ +#ifndef __MULTIMON_H +#define __MULTIMON_H + +#ifdef _WIN32 + +//============================================================================= +// +// MULTIMON +// stub module that "stubs" multiple monitor APIs on pre-Memphis Win32 OSes +// +// By using this header your code will work unchanged on Win95, +// you will get back correct values from GetSystemMetrics() for new metrics +// and the new APIs will act like only one display is present. +// +// exactly one source must include this with COMPILE_MULTIMON_STUBS defined +// +//============================================================================= + +#ifdef __cplusplus +extern "C" { /* Assume C declarations for C++ */ +#endif /* __cplusplus */ + +// +// if we are building on Win95/NT4 headers we need to declare this stuff ourselves +// +#ifndef SM_CMONITORS + +#define SM_XVIRTUALSCREEN 76 +#define SM_YVIRTUALSCREEN 77 +#define SM_CXVIRTUALSCREEN 78 +#define SM_CYVIRTUALSCREEN 79 +#define SM_CMONITORS 80 +#define SM_SAMEDISPLAYFORMAT 81 + +DECLARE_HANDLE(HMONITOR); + +#define MONITOR_DEFAULTTONULL 0x00000000 +#define MONITOR_DEFAULTTOPRIMARY 0x00000001 +#define MONITOR_DEFAULTTONEAREST 0x00000002 + +#define MONITORINFOF_PRIMARY 0x00000001 + +typedef struct tagMONITORINFO +{ + DWORD cbSize; + RECT rcMonitor; + RECT rcWork; + DWORD dwFlags; +} MONITORINFO, *LPMONITORINFO; + +#define CCHDEVICENAME 32 + +#ifdef __cplusplus +typedef struct tagMONITORINFOEX : public tagMONITORINFO +{ + TCHAR szDevice[CCHDEVICENAME]; +} MONITORINFOEX, *LPMONITORINFOEX; +#else +typedef struct +{ + MONITORINFO; + TCHAR szDevice[CCHDEVICENAME]; +} MONITORINFOEX, *LPMONITORINFOEX; +#endif + +typedef BOOL (CALLBACK* MONITORENUMPROC)(HMONITOR, HDC, LPRECT, LPARAM); + +#endif // SM_CMONITORS + +#ifndef DISPLAY_DEVICE_ATTACHED_TO_DESKTOP + +typedef struct { + DWORD cb; + CHAR DeviceName[32]; + CHAR DeviceString[128]; + DWORD StateFlags; +} DISPLAY_DEVICE; + +#define DISPLAY_DEVICE_ATTACHED_TO_DESKTOP 0x00000001 +#define DISPLAY_DEVICE_MULTI_DRIVER 0x00000002 +#define DISPLAY_DEVICE_PRIMARY_DEVICE 0x00000004 +#define DISPLAY_DEVICE_MIRRORING_DRIVER 0x00000008 + +#endif +#define DISPLAY_DEVICE_VGA 0x00000010 + +#ifndef ENUM_CURRENT_SETTINGS +#define ENUM_CURRENT_SETTINGS ((DWORD)-1) +#define ENUM_REGISTRY_SETTINGS ((DWORD)-2) +#endif + +#undef GetMonitorInfo +#undef GetSystemMetrics +#undef MonitorFromWindow +#undef MonitorFromRect +#undef MonitorFromPoint +#undef EnumDisplayMonitors +#undef EnumDisplayDevices + +// +// define this to compile the stubs +// otherwise you get the declarations +// +#ifdef COMPILE_MULTIMON_STUBS + + //--------------------------------------------------------------------------- + // + // Implement the API stubs. + // + //--------------------------------------------------------------------------- + + int (WINAPI* g_pfnGetSystemMetrics)(int); + HMONITOR (WINAPI* g_pfnMonitorFromWindow)(HWND, BOOL); + HMONITOR (WINAPI* g_pfnMonitorFromRect)(LPCRECT, BOOL); + HMONITOR (WINAPI* g_pfnMonitorFromPoint)(POINT, BOOL); + BOOL (WINAPI* g_pfnGetMonitorInfo)(HMONITOR, LPMONITORINFO); + BOOL (WINAPI* g_pfnEnumDisplayMonitors)(HDC, LPCRECT, MONITORENUMPROC, LPARAM); + BOOL (WINAPI *g_pfnEnumDisplayDevices)(LPVOID, int, DISPLAY_DEVICE *, DWORD); + + BOOL InitMultipleMonitorStubs(void) + { + HMODULE hUser32; + static BOOL fInitDone; + + if (fInitDone) + { + return g_pfnGetMonitorInfo != NULL; + } + + if ((hUser32 = GetModuleHandle(TEXT("USER32"))) && + (*(FARPROC*)&g_pfnGetSystemMetrics = GetProcAddress(hUser32,"GetSystemMetrics")) && + (*(FARPROC*)&g_pfnMonitorFromWindow = GetProcAddress(hUser32,"MonitorFromWindow")) && + (*(FARPROC*)&g_pfnMonitorFromRect = GetProcAddress(hUser32,"MonitorFromRect")) && + (*(FARPROC*)&g_pfnMonitorFromPoint = GetProcAddress(hUser32,"MonitorFromPoint")) && + (*(FARPROC*)&g_pfnEnumDisplayMonitors = GetProcAddress(hUser32,"EnumDisplayMonitors")) && + #ifdef UNICODE + (*(FARPROC*)&g_pfnGetMonitorInfo = GetProcAddress(hUser32,"GetMonitorInfoW")) && + (*(FARPROC*)&g_pfnEnumDisplayDevices = GetProcAddress(hUser32,"EnumDisplayDevicesW")) && + #else + (*(FARPROC*)&g_pfnGetMonitorInfo = GetProcAddress(hUser32,"GetMonitorInfoA")) && + (*(FARPROC*)&g_pfnEnumDisplayDevices = GetProcAddress(hUser32,"EnumDisplayDevicesA")) && + #endif + (GetSystemMetrics(SM_CXVIRTUALSCREEN) >= GetSystemMetrics(SM_CXSCREEN)) && + (GetSystemMetrics(SM_CYVIRTUALSCREEN) >= GetSystemMetrics(SM_CYSCREEN)) ) + { + fInitDone = TRUE; + return TRUE; + } + else + { + g_pfnGetSystemMetrics = NULL; + g_pfnMonitorFromWindow = NULL; + g_pfnMonitorFromRect = NULL; + g_pfnMonitorFromPoint = NULL; + g_pfnGetMonitorInfo = NULL; + g_pfnEnumDisplayMonitors = NULL; + g_pfnEnumDisplayDevices = NULL; + + fInitDone = TRUE; + return FALSE; + } + } + + //--------------------------------------------------------------------------- + // + // "stubbed" implementations of Monitor APIs that work with the primary // display + // + //--------------------------------------------------------------------------- + + int WINAPI + xGetSystemMetrics(int nIndex) + { + if (InitMultipleMonitorStubs()) + return g_pfnGetSystemMetrics(nIndex); + + switch (nIndex) + { + case SM_CMONITORS: + case SM_SAMEDISPLAYFORMAT: + return 1; + + case SM_XVIRTUALSCREEN: + case SM_YVIRTUALSCREEN: + return 0; + + case SM_CXVIRTUALSCREEN: + nIndex = SM_CXSCREEN; + break; + + case SM_CYVIRTUALSCREEN: + nIndex = SM_CYSCREEN; + break; + } + + return GetSystemMetrics(nIndex); + } + + #define xPRIMARY_MONITOR ((HMONITOR)0x42) + + HMONITOR WINAPI + xMonitorFromRect(LPCRECT lprcScreenCoords, + UINT uFlags) + { + if (InitMultipleMonitorStubs()) + return g_pfnMonitorFromRect(lprcScreenCoords, uFlags); + + if ((uFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST)) || + ((lprcScreenCoords->right > 0) && + (lprcScreenCoords->bottom > 0) && + (lprcScreenCoords->left < GetSystemMetrics(SM_CXSCREEN)) && + (lprcScreenCoords->top < GetSystemMetrics(SM_CYSCREEN)))) + { + return xPRIMARY_MONITOR; + } + + return NULL; + } + + HMONITOR WINAPI + xMonitorFromWindow(HWND hWnd, + UINT uFlags) + { + RECT rc; + + if (InitMultipleMonitorStubs()) + return g_pfnMonitorFromWindow(hWnd, uFlags); + + if (uFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST)) + return xPRIMARY_MONITOR; + + if (GetWindowRect(hWnd, &rc)) + return xMonitorFromRect(&rc, uFlags); + + return NULL; + } + + HMONITOR WINAPI + xMonitorFromPoint(POINT ptScreenCoords, + UINT uFlags) + { + if (InitMultipleMonitorStubs()) + return g_pfnMonitorFromPoint(ptScreenCoords, uFlags); + + if ((uFlags & (MONITOR_DEFAULTTOPRIMARY | MONITOR_DEFAULTTONEAREST)) || + ((ptScreenCoords.x >= 0) && + (ptScreenCoords.x < GetSystemMetrics(SM_CXSCREEN)) && + (ptScreenCoords.y >= 0) && + (ptScreenCoords.y < GetSystemMetrics(SM_CYSCREEN)))) + { + return xPRIMARY_MONITOR; + } + + return NULL; + } + + BOOL WINAPI + xGetMonitorInfo(HMONITOR hMonitor, + LPMONITORINFO lpMonitorInfo) + { + RECT rcWork; + + if (InitMultipleMonitorStubs()) + return g_pfnGetMonitorInfo(hMonitor, lpMonitorInfo); + + if ((hMonitor == xPRIMARY_MONITOR) && lpMonitorInfo && + (lpMonitorInfo->cbSize >= sizeof(MONITORINFO)) && + SystemParametersInfo(SPI_GETWORKAREA, 0, &rcWork, 0)) + { + lpMonitorInfo->rcMonitor.left = 0; + lpMonitorInfo->rcMonitor.top = 0; + lpMonitorInfo->rcMonitor.right = GetSystemMetrics(SM_CXSCREEN); + lpMonitorInfo->rcMonitor.bottom = GetSystemMetrics(SM_CYSCREEN); + lpMonitorInfo->rcWork = rcWork; + lpMonitorInfo->dwFlags = MONITORINFOF_PRIMARY; + + if (lpMonitorInfo->cbSize >= sizeof(MONITORINFOEX)) + lstrcpy(((MONITORINFOEX*)lpMonitorInfo)->szDevice, + TEXT("DISPLAY")); + + return TRUE; + } + + return FALSE; + } + + BOOL WINAPI + xEnumDisplayMonitors(HDC hdc, + LPCRECT lprcIntersect, + MONITORENUMPROC lpfnEnumProc, + LPARAM lData) + { + RECT rcCallback, rcLimit; + + if (InitMultipleMonitorStubs()) + return g_pfnEnumDisplayMonitors(hdc, lprcIntersect, lpfnEnumProc, lData); + + if (!lpfnEnumProc) + return FALSE; + + rcLimit.left = 0; + rcLimit.top = 0; + rcLimit.right = GetSystemMetrics(SM_CXSCREEN); + rcLimit.bottom = GetSystemMetrics(SM_CYSCREEN); + + if (hdc) + { + RECT rcClip; + HWND hWnd; + + if ((hWnd = WindowFromDC(hdc)) == NULL) + return FALSE; + + switch (GetClipBox(hdc, &rcClip)) + { + default: + MapWindowPoints(NULL, hWnd, (LPPOINT)&rcLimit, 2); + if (IntersectRect(&rcCallback, &rcClip, &rcLimit)) + break; + //fall thru + case NULLREGION: + return TRUE; + case ERROR: + return FALSE; + } + + rcLimit = rcCallback; + } + + if (!lprcIntersect || IntersectRect(&rcCallback, lprcIntersect, &rcLimit)) + { + lpfnEnumProc(xPRIMARY_MONITOR, hdc, &rcCallback, lData); + } + + return TRUE; + } + + BOOL WINAPI + xEnumDisplayDevices(LPVOID lpReserved, + int iDeviceNum, + DISPLAY_DEVICE * pDisplayDevice, + DWORD dwFlags) + { + if (InitMultipleMonitorStubs()) + return g_pfnEnumDisplayDevices(lpReserved, iDeviceNum, pDisplayDevice, dwFlags); + + return FALSE; + } + + #undef xPRIMARY_MONITOR + #undef COMPILE_MULTIMON_STUBS + +#else // COMPILE_MULTIMON_STUBS + + extern int WINAPI xGetSystemMetrics(int); + extern HMONITOR WINAPI xMonitorFromWindow(HWND, UINT); + extern HMONITOR WINAPI xMonitorFromRect(LPCRECT, UINT); + extern HMONITOR WINAPI xMonitorFromPoint(POINT, UINT); + extern BOOL WINAPI xGetMonitorInfo(HMONITOR, LPMONITORINFO); + extern BOOL WINAPI xEnumDisplayMonitors(HDC, LPCRECT, MONITORENUMPROC, LPARAM); + extern BOOL WINAPI xEnumDisplayDevices(LPVOID, int, DISPLAY_DEVICE *, DWORD); + +#endif // COMPILE_MULTIMON_STUBS + +// +// build defines that replace the regular APIs with our versions +// +#define GetSystemMetrics xGetSystemMetrics +#define MonitorFromWindow xMonitorFromWindow +#define MonitorFromRect xMonitorFromRect +#define MonitorFromPoint xMonitorFromPoint +#define GetMonitorInfo xGetMonitorInfo +#define EnumDisplayMonitors xEnumDisplayMonitors +#define EnumDisplayDevices xEnumDisplayDevices + +#ifdef __cplusplus +} +#endif // __cplusplus + +#endif // WIN32 + +#endif // __MULTIMON_H \ No newline at end of file diff --git a/libs/pak/.cvsignore b/libs/pak/.cvsignore new file mode 100644 index 00000000..b5ee5ae1 --- /dev/null +++ b/libs/pak/.cvsignore @@ -0,0 +1 @@ +Debug Release *.ncb *.opt *.plg *.001 *.BAK \ No newline at end of file diff --git a/libs/pak/.cvswrappers b/libs/pak/.cvswrappers new file mode 100644 index 00000000..cdfd6d4a --- /dev/null +++ b/libs/pak/.cvswrappers @@ -0,0 +1,3 @@ +*.dsp -m 'COPY' -k 'b' +*.dsw -m 'COPY' -k 'b' +*.scc -m 'COPY' -k 'b' diff --git a/libs/pak/pakstuff.cpp b/libs/pak/pakstuff.cpp new file mode 100644 index 00000000..f3ae725e --- /dev/null +++ b/libs/pak/pakstuff.cpp @@ -0,0 +1,979 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#include +#include +#include +#include +#if defined (__linux__) || defined (__APPLE__) +#include +#endif +#ifdef _WIN32 +#include +#endif +#include "pakstuff.h" +#include "unzip.h" +#include "str.h" + +#ifndef TRUE +#define TRUE 1 +#define FALSE 0 +#endif + +int m_nPAKIndex; +FILE* pakfile[16]; +struct PACKDirectory pakdir; +PACKDirPtr pakdirptr = &pakdir; +UInt16 dirsize; +bool pakopen = false; +int f_type; +DIRECTORY *paktextures = NULL; +UInt32 PakColormapOffset; +UInt32 PakColormapSize; +DIRECTORY *dirhead = NULL; +bool g_bPK3 = false; +char g_strBasePaths[16][1024]; +int g_numBasePaths = 0; + +struct PK3FileInfo +{ + unzFile m_zFile; + char *m_pName; + unz_s m_zInfo; + long m_lSize; + ~PK3FileInfo() + { + delete []m_pName; + } + bool operator ==(const PK3FileInfo& rhs) const { return strcmp(m_pName, rhs.m_pName) == 0; } +}; + +#define __PATHSEPERATOR '/' + +//#define LOG_PAKFAIL + +#ifdef LOG_PAKFAIL + +#if defined (__linux__) || defined (__APPLE__) +#include +#include +#endif +#include + +class LogFile +{ +public: + FILE *m_pFile; + LogFile(const char* pName) + { +#if defined (__linux__) || defined (__APPLE__) + // leo: use ~/.q3a/radiant/paklog instead of /tmp/paklog.txt + char *home = NULL; + + home = getenv("HOME"); + if ( home == NULL ) + { + uid_t id = getuid(); + struct passwd *pwd; + + setpwent(); + while( (pwd = getpwent()) != NULL ) + if( pwd->pw_uid == id ) + { + home = pwd->pw_dir; + break; + } + endpwent(); + } + + if (home != NULL) + { + char path[PATH_MAX]; + strcpy (path, home); + if (path[strlen(path)-1] != '/') + strcat (path, "/"); + strcat (path, ".q3a/radiant/paklog"); + m_pFile = fopen(path, "w"); + } + else +#endif + m_pFile = fopen(pName, "w"); + } + ~LogFile() + { + if (m_pFile) + { + fclose(m_pFile); + } + } + void Log(const char *pFormat, ...) + { + if (m_pFile == NULL) + return; + + va_list arg_ptr; + va_start(arg_ptr, pFormat); + fprintf(m_pFile, pFormat, arg_ptr); + va_end(arg_ptr); + } +}; + +LogFile g_LogFile("/tmp/paklog.txt"); +#endif + +template class StrPtr : public Str +{ +protected: + T* m_pPtr; + StrPtr() + { + m_pPtr = NULL; + } + + StrPtr(const char *pStr, T *p) : Str(pStr) + { + m_pPtr = p; + } + + T* Ptr() + { + return m_pPtr; + } + + T& Ref() + { + return *m_pPtr; + } + + +}; +// PtrList +// a list of ptrs +// +template class PtrList +{ +protected: + T *m_pPtr; + PtrList *m_pNext; + +public: + + PtrList() + { + m_pNext = NULL; + m_pPtr = NULL; + } + + PtrList(T *ip) + { + m_pNext = NULL; + m_pPtr = ip; + } + + virtual ~PtrList() + { + delete m_pPtr; + } + + PtrList* Next() + { + return m_pNext; + } + + void Add(T *ip) + { + PtrList *pl = this; + while (pl && pl->m_pNext) + { + pl = pl->Next(); + } + pl->m_pNext = new PtrList(ip); + } + + void Remove() + { + PtrList *p = m_pNext; + if (p) + { + while (p->m_pNext != this && p->m_pNext != NULL) + { + p = p->m_pNext; + } + if (p->m_pNext == this) + { + p->m_pNext = m_pNext; + } + } + } + + virtual PtrList* Find(T *ip) + { + PtrList *p = m_pNext; + while (p) + { + if (*p->m_pPtr == *ip) + { + return p; + } + p = p->m_pNext; + } + return NULL; + } + + // remove vp from the list + void Remove(T *ip) + { + PtrList *p = Find(ip); + if (p) + { + p->Remove(); + } + } + + T* Ptr() + { + return m_pPtr; + } + + T& Ref() + { + return *m_pPtr; + } + + void RemoveAll() + { + PtrList *p = m_pNext; + while (p) + { + PtrList *p2 = p; + p = p->m_pNext; + delete p2; + } + } +}; + + +typedef PtrList ZFileList; +typedef PtrList StrList; +typedef PtrList PK3List; + + +StrList g_PK3TexturePaths; +PK3List g_PK3Files; +ZFileList g_zFiles; +#define WORK_LEN 1024 +#define TEXTURE_PATH "textures" +#define PATH_SEPERATORS "/\\:\0" + +/* +char* __StrDup(char* pStr) +{ + if (pStr == NULL) + pStr = ""; + + return strcpy(new char[strlen(pStr)+1], pStr); +} + +char* __StrDup(const char* pStr) +{ + if (pStr == NULL) + pStr = ""; + + return strcpy(new char[strlen(pStr)+1], pStr); +} +*/ + +#define MEM_BLOCKSIZE 4096 +void* __qblockmalloc(size_t nSize) +{ + void *b; + // round up to threshold + int nAllocSize = nSize % MEM_BLOCKSIZE; + if ( nAllocSize > 0) + { + nSize += MEM_BLOCKSIZE - nAllocSize; + } + b = malloc(nSize + 1); + memset (b, 0, nSize); + return b; +} + +void* __qmalloc (size_t nSize) +{ + void *b; + b = malloc(nSize + 1); + memset (b, 0, nSize); + return b; +} + + +/* +==================== +Extract file parts +==================== +*/ +void __ExtractFilePath (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != __PATHSEPERATOR) + src--; + + memcpy (dest, path, src-path); + dest[src-path] = 0; +} + +void __ExtractFileName (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' + && *(src-1) != '\\' ) + src--; + + while (*src) + { + *dest++ = *src++; + } + *dest = 0; +} + +void __ExtractFileBase (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a \ or the start +// + while (src != path && *(src-1) != '/' + && *(src-1) != '\\' ) + src--; + + while (*src && *src != '.') + { + *dest++ = *src++; + } + *dest = 0; +} + +void __ExtractFileExtension (const char *path, char *dest) +{ + const char *src; + + src = path + strlen(path) - 1; + +// +// back up until a . or the start +// + while (src != path && *(src-1) != '.') + src--; + if (src == path) + { + *dest = 0; // no extension + return; + } + + strcpy (dest,src); +} + + +void __ConvertDOSToUnixName( char *dst, const char *src ) +{ + while ( *src ) + { + if ( *src == '\\' ) + *dst = '/'; + else + *dst = *src; + dst++; src++; + } + *dst = 0; +} + + + + + +static void AddSlash(Str& str) +{ + int nLen = str.GetLength(); + if (nLen > 0) + { + if (str[nLen-1] != '\\' && str[nLen-1] != '/') + str += '\\'; + } +} + +static void FindReplace(Str& strContents, const char* pTag, const char* pValue) +{ + if (strcmp(pTag, pValue) == 0) + return; + for (int nPos = strContents.Find(pTag); nPos >= 0; nPos = strContents.Find(pTag)) + { + int nRightLen = strContents.GetLength() - strlen(pTag) - nPos; + Str strLeft(strContents.Left(nPos)); + Str strRight(strContents.Right(nRightLen)); + strLeft += pValue; + strLeft += strRight; + strContents = strLeft; + } +} + + + + + +void ClearFileList(FILELIST **list) +{ + FILELIST *temp; + + while(*list) + { + temp = *list; + *list = (*list)->next; + free(temp); + } +} + +void ClearDirList(DIRLIST **list) +{ + DIRLIST *temp; + + while(*list) + { + temp = *list; + *list = (*list)->next; + free(temp); + } +} + +DIRECTORY *FindPakDir(DIRECTORY *dir, char *name) +{ + DIRECTORY *currentPtr; + + for(currentPtr = dir; currentPtr; currentPtr = currentPtr->next) + { + if(!stricmp(name, currentPtr->name)) + { + return currentPtr; + } + } + return NULL; +} + + +// LoadPK3FileList +// --------------- +// +// This gets passed a file mask which we want to remove as +// we are only interested in the directory name and any given +// extension. Only handles explicit filenames or *.something +// +bool LoadPK3FileList(FILELIST **filelist, const char *pattern) +{ + char cSearch[WORK_LEN]; + __ConvertDOSToUnixName( cSearch, pattern ); + char cPath[WORK_LEN]; + char cExt[WORK_LEN]; + char cFile[WORK_LEN]; + char cWork[WORK_LEN]; + __ExtractFilePath(pattern, cPath); + __ExtractFileName(pattern, cFile); + __ExtractFileExtension(pattern, cExt); + const char *pCompare = (strnicmp(cFile, "*.", 2) == 0) ? cExt : cFile; + + PK3List *p = g_PK3Files.Next(); + while (p != NULL) + { + // qualify the path + PK3FileInfo *pKey = p->Ptr(); + if (strstr(pKey->m_pName, cPath) && strstr(pKey->m_pName, pCompare)) + { + __ExtractFileName(pKey->m_pName, cWork); + AddToFileListAlphabetized(filelist, cWork, 0, 0, false); + } + p = p->Next(); + } + return (*filelist) != NULL; +} + +bool GetPackFileList(FILELIST **filelist, char *pattern) +{ + char *str1, *str2; + int i; + DIRECTORY *dummy = paktextures; + FILELIST *temp; + + if (!pakopen) + return false; + + if (g_bPK3) + { + return LoadPK3FileList(filelist, pattern); + } + + str1 = pattern; + + for(i = 0; pattern[i] != '\0'; i++) + { + if(pattern[i] == '\\') + pattern[i] = '/'; + } + + while(strchr(str1, '/')) + { + str2 = strchr(str1, '/'); + *str2++ = '\0'; + dummy = FindPakDir(dummy, str1); + if(!dummy) + return false; + str1 = str2; + } + for(temp = dummy->files; temp; temp=temp->next) + { + AddToFileListAlphabetized(filelist, temp->filename, temp->offset, 0, false); + } + return true; +} + +bool GetPackTextureDirs(DIRLIST **dirlist) +{ + UInt16 i; + char buf[57]; + + if (!pakopen) + return 1; + + if (g_bPK3) + { + StrList *pl = g_PK3TexturePaths.Next(); + while (pl != NULL) + { + AddToDirListAlphabetized(dirlist, pl->Ref(), 0); + pl = pl->Next(); + } + return true; + } + + for (i = 0; i < dirsize; i++) + { + if(!strnicmp(pakdirptr[i].name, "textures", 8)) + { + strncpy(buf, &(pakdirptr[i].name[9]), 46); + if(strchr(buf, '\\')) + *strchr(buf, '\\') = '\0'; + else if(strchr(buf, '/')) + *strchr(buf, '/') = '\0'; + else + buf[56] = '\0'; + + if(strchr(buf, '.')) + continue; + + AddToDirListAlphabetized(dirlist, buf, 0); + } + } + return true; +} + +bool AddToDirListAlphabetized(DIRLIST **list, char *dirname, int from) +{ + DIRLIST *currentPtr, *previousPtr, *newPtr; + + strlwr(dirname); + for(currentPtr = *list; currentPtr; currentPtr = currentPtr->next) + { + if(!stricmp(dirname, currentPtr->dirname)) + { + return false; + } + } + previousPtr = NULL; + currentPtr = *list; + + if((newPtr = (DIRLIST *)__qmalloc(sizeof(DIRLIST))) == NULL) + return false; + + strcpy(newPtr->dirname, dirname); + newPtr->from = from; + + while(currentPtr != NULL && stricmp(dirname, currentPtr->dirname) > 0) + { + previousPtr = currentPtr; + currentPtr = currentPtr->next; + } //End while + if(previousPtr == NULL) + { + newPtr->next = *list; + *list = newPtr; + } //End if + else + { + previousPtr->next = newPtr; + newPtr->next = currentPtr; + } //End else + return true; +} + +bool AddToFileListAlphabetized(FILELIST **list, char *filename, UInt32 offset, UInt32 size, bool dirs) +{ + FILELIST *currentPtr, *previousPtr, *newPtr; + + for(currentPtr = *list; currentPtr; currentPtr = currentPtr->next) + { + if(!stricmp(filename, currentPtr->filename)) + { + return false; + } + } + previousPtr = NULL; + currentPtr = *list; + + if((newPtr = (FILELIST *)__qmalloc(sizeof(FILELIST))) == NULL) + return false; + + strcpy(newPtr->filename, filename); + newPtr->offset = offset; + newPtr->size = size; + + while(currentPtr != NULL && stricmp(filename, currentPtr->filename) > 0) + { + previousPtr = currentPtr; + currentPtr = currentPtr->next; + } //End while + if(previousPtr == NULL) + { + newPtr->next = *list; + *list = newPtr; + } //End if + else + { + previousPtr->next = newPtr; + newPtr->next = currentPtr; + } //End else + return true; +} + +int PakLoadAnyFile(const char *filename, void **bufferptr) +{ + char cWork[WORK_LEN]; + if (g_bPK3) + { + // leo: hack to be able to use pak files from multiple directories + for (int i = 0; i < g_numBasePaths; i++) + { + PK3FileInfo *pInfo; + Str strKey; + // need to lookup the file without the base/texture path on it + Str strBase(g_strBasePaths[i]); + AddSlash(strBase); + __ConvertDOSToUnixName(cWork, strBase); + Str strFile(filename); + __ConvertDOSToUnixName(strFile, strFile); + strFile.MakeLower(); + strlwr(cWork); + FindReplace(strFile, cWork, ""); + + PK3FileInfo infoFind; + infoFind.m_pName = __StrDup(strFile.GetBuffer()); + PK3List *pList = g_PK3Files.Find(&infoFind); + if (pList) + { + pInfo = pList->Ptr(); + memcpy(pInfo->m_zFile, &pInfo->m_zInfo, sizeof(unz_s)); + if (unzOpenCurrentFile(pInfo->m_zFile) == UNZ_OK) + { + void *buffer = __qblockmalloc(pInfo->m_lSize+1); + int n = unzReadCurrentFile(pInfo->m_zFile , buffer, pInfo->m_lSize); + *bufferptr = buffer; + unzCloseCurrentFile(pInfo->m_zFile); + return n; + } + } + } + +#ifdef LOG_PAKFAIL + sprintf(cWork, "PAK failed on %s\n", filename); + g_LogFile.Log(cWork); +#endif + return -1; + } + + for (int i = 0; i < dirsize; i++) + { + if(!stricmp(filename, pakdirptr[i].name)) + { + if (fseek(pakfile[m_nPAKIndex], pakdirptr[i].offset, SEEK_SET) >= 0) + { + void *buffer = __qmalloc (pakdirptr[i].size+1); + ((char *)buffer)[pakdirptr[i].size] = 0; + if (fread(buffer, 1, pakdirptr[i].size, pakfile[m_nPAKIndex]) == pakdirptr[i].size) + { + *bufferptr = buffer; + return pakdirptr[i].size; + } + } + } + } +#ifdef LOG_PAKFAIL + sprintf(cWork, "PAK failed on %s\n", filename); + g_LogFile.Log(cWork); +#endif + return -1; +} + + + +DIRECTORY *AddPakDir(DIRECTORY **dir, char *name) +{ + DIRECTORY *currentPtr, *previousPtr, *newPtr; + + for(currentPtr = *dir; currentPtr; currentPtr = currentPtr->next) + { + if(!stricmp(name, currentPtr->name)) + { + return currentPtr; + } + } + previousPtr = NULL; + currentPtr = *dir; + + if((newPtr = (DIRECTORY *)__qmalloc(sizeof(DIRECTORY))) == NULL) + return NULL; + + strcpy(newPtr->name, name); + newPtr->files = NULL; + + while(currentPtr != NULL && stricmp(name, currentPtr->name) > 0) + { + previousPtr = currentPtr; + currentPtr = currentPtr->next; + } + if(previousPtr == NULL) + { + newPtr->next = *dir; + *dir = newPtr; + } + else + { + previousPtr->next = newPtr; + newPtr->next = currentPtr; + } + return newPtr; +} + + +// OpenPK3 +// ------- +// Opens a PK3 ( or zip ) file and creates a list of filenames +// and zip info structures +// +bool OpenPK3(const char *filename) +{ + char cFilename[WORK_LEN]; + char cName[WORK_LEN]; + char cWork[WORK_LEN]; + unz_file_info zInfo; + unzFile *zFile = new unzFile(unzOpen(filename)); + g_zFiles.Add(zFile); + if (zFile != NULL) + { + int nStatus = unzGoToFirstFile(*zFile); + while (nStatus == UNZ_OK) + { + cFilename[0] = '\0'; + unzGetCurrentFileInfo(*zFile, &zInfo, cFilename, WORK_LEN, NULL, 0, NULL, 0); + strlwr(cFilename); + __ConvertDOSToUnixName( cWork, cFilename); + if (strstr(cWork, ".") != NULL) + { + PK3FileInfo *pInfo = new PK3FileInfo(); + pInfo->m_pName = __StrDup(cWork); + memcpy(&pInfo->m_zInfo, (unz_s*)*zFile, sizeof(unz_s)); + pInfo->m_lSize = zInfo.uncompressed_size; + pInfo->m_zFile = *zFile; + g_PK3Files.Add(pInfo); + } + char *p = strstr(cFilename, TEXTURE_PATH); + if (p != NULL) + { + // FIXME: path differences per os ? + // catch solo directory entry + if (strlen(p) > strlen(TEXTURE_PATH) + 1) + { + // skip textures + path seperator + p += strlen(TEXTURE_PATH) + 1; + int nEnd = strcspn(p, PATH_SEPERATORS); + strncpy(cName, p, nEnd); + cName[nEnd] = '\0'; + + bool bFound = false; + StrList *pl = g_PK3TexturePaths.Next(); + while (pl != NULL) + { + if (strcmpi(pl->Ref(), cName) == 0) + { + // already have this, continue + bFound = true; + break; + } + pl = pl->Next(); + } + if (!bFound) + { + g_PK3TexturePaths.Add(new Str(cName)); + } + } + } + nStatus = unzGoToNextFile(*zFile); + } + } + return (zFile != NULL); +} + +void closePK3(unzFile zf) +{ + unzClose(zf); +} + +void OpenPakFile(const char *filename) +{ + if(!pakopen) + paktextures = NULL; + + pakopen = g_bPK3 = OpenPK3(filename); +} + +void ClearPaKDir(DIRECTORY **dir) +{ + DIRECTORY *d1 = *dir, *d2; + + while(d1) + { + ClearFileList(&(d1->files)); + d2 = d1; + d1 = d1->next; + free(d2); + } +} + +void CleanUpPakDirs() +{ + ClearPaKDir(&paktextures); + paktextures = NULL; + dirhead = NULL; + g_PK3TexturePaths.RemoveAll(); + g_PK3Files.RemoveAll(); +} + +void ClosePakFile(void) +{ + if(pakopen) + { + if (g_bPK3) + { + ZFileList *p = g_zFiles.Next(); + while (p != NULL) + { + unzFile uz = p->Ref(); + closePK3(uz); + p = p->Next(); + } + } + else + { + fclose(pakfile[m_nPAKIndex]); + } + } + pakopen = false; + CleanUpPakDirs(); +} + + +void WINAPI InitPakFile(const char * pBasePath, const char *pName) +{ + if (g_numBasePaths == 0) + { + m_nPAKIndex = 0; + pakopen = false; + paktextures = NULL; + } + strcpy(g_strBasePaths[g_numBasePaths], pBasePath); + g_numBasePaths++; + + if (pName == NULL) + { + //++timo FIXME: use some kind of compatibility lib here! +#if defined (__linux__) || defined (__APPLE__) + char cWork[WORK_LEN]; + struct dirent *dirlist; + DIR *dir; + + dir = opendir (pBasePath); + if (dir != NULL) + { + while ((dirlist = readdir (dir)) != NULL) + { + if (strstr (dirlist->d_name, ".pk3") == NULL) + continue; + sprintf(cWork, "%s/%s", pBasePath, dirlist->d_name); + OpenPakFile(cWork); + } + closedir (dir); + } +#endif +#ifdef _WIN32 + char cWork[WORK_LEN]; + Str strPath(pBasePath); + AddSlash(strPath); + strPath += "*.pk3"; + bool bGo = true; + struct _finddata_t fileinfo; + int handle = _findfirst (strPath, &fileinfo); + if (handle != -1) + { + do + { + sprintf(cWork, "%s/%s", pBasePath, fileinfo.name); + OpenPakFile(cWork); + } while (_findnext( handle, &fileinfo ) != -1); + _findclose (handle); + } +#endif + } + else + { + OpenPakFile(pName); + } +} + diff --git a/libs/pak/unzip.cpp b/libs/pak/unzip.cpp new file mode 100644 index 00000000..304dc6d3 --- /dev/null +++ b/libs/pak/unzip.cpp @@ -0,0 +1,4534 @@ +/***************************************************************************** + * name: unzip.c + * + * desc: IO on .zip files using portions of zlib + * + * + *****************************************************************************/ + +#include +#include +#include +#include "unzip.h" + +typedef unsigned char byte; + +/* unzip.h -- IO for uncompress .zip files using zlib + Version 0.15 beta, Mar 19th, 1998, + + Copyright (C) 1998 Gilles Vollant + + This unzip package allow extract file from .ZIP file, compatible with PKZip 2.04g + WinZip, InfoZip tools and compatible. + Encryption and multi volume ZipFile (span) are not supported. + Old compressions used by old PKZip 1.x are not supported + + THIS IS AN ALPHA VERSION. AT THIS STAGE OF DEVELOPPEMENT, SOMES API OR STRUCTURE + CAN CHANGE IN FUTURE VERSION !! + I WAIT FEEDBACK at mail info@winimage.com + Visit also http://www.winimage.com/zLibDll/unzip.htm for evolution + + Condition of use and distribution are the same than zlib : + + 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. + + +*/ +/* for more info about .ZIP format, see + ftp://ftp.cdrom.com/pub/infozip/doc/appnote-970311-iz.zip + PkWare has also a specification at : + ftp://ftp.pkware.com/probdesc.zip */ + +/* zlib.h -- interface of the 'zlib' general purpose compression library + version 1.1.3, July 9th, 1998 + + Copyright (C) 1995-1998 Jean-loup Gailly and Mark Adler + + 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. + + Jean-loup Gailly Mark Adler + jloup@gzip.org madler@alumni.caltech.edu + + + The data format used by the zlib library is described by RFCs (Request for + Comments) 1950 to 1952 in the files ftp://ds.internic.net/rfc/rfc1950.txt + (zlib format), rfc1951.txt (deflate format) and rfc1952.txt (gzip format). +*/ + +/* zconf.h -- configuration of the zlib compression library + * Copyright (C) 1995-1998 Jean-loup Gailly. + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifndef _ZCONF_H +#define _ZCONF_H + +/* Maximum value for memLevel in deflateInit2 */ +#ifndef MAX_MEM_LEVEL +# ifdef MAXSEG_64K +# define MAX_MEM_LEVEL 8 +# else +# define MAX_MEM_LEVEL 9 +# endif +#endif + +/* Maximum value for windowBits in deflateInit2 and inflateInit2. + * WARNING: reducing MAX_WBITS makes minigzip unable to extract .gz files + * created by gzip. (Files created by minigzip can still be extracted by + * gzip.) + */ +#ifndef MAX_WBITS +# define MAX_WBITS 15 /* 32K LZ77 window */ +#endif + +/* The memory requirements for deflate are (in bytes): + (1 << (windowBits+2)) + (1 << (memLevel+9)) + that is: 128K for windowBits=15 + 128K for memLevel = 8 (default values) + plus a few kilobytes for small objects. For example, if you want to reduce + the default memory requirements from 256K to 128K, compile with + make CFLAGS="-O -DMAX_WBITS=14 -DMAX_MEM_LEVEL=7" + Of course this will generally degrade compression (there's no free lunch). + + The memory requirements for inflate are (in bytes) 1 << windowBits + that is, 32K for windowBits=15 (default value) plus a few kilobytes + for small objects. +*/ + + /* Type declarations */ + +#ifndef OF /* function prototypes */ +#define OF(args) args +#endif + +typedef unsigned char Byte; /* 8 bits */ +typedef unsigned int uInt; /* 16 bits or more */ +typedef unsigned long uLong; /* 32 bits or more */ +typedef Byte *voidp; + +#ifndef SEEK_SET +# define SEEK_SET 0 /* Seek from beginning of file. */ +# define SEEK_CUR 1 /* Seek from current position. */ +# define SEEK_END 2 /* Set file pointer to EOF plus "offset" */ +#endif + +#endif /* _ZCONF_H */ + +#define ZLIB_VERSION "1.1.3" + +/* + The 'zlib' compression library provides in-memory compression and + decompression functions, including integrity checks of the uncompressed + data. This version of the library supports only one compression method + (deflation) but other algorithms will be added later and will have the same + stream interface. + + Compression can be done in a single step if the buffers are large + enough (for example if an input file is mmap'ed), or can be done by + repeated calls of the compression function. In the latter case, the + application must provide more input and/or consume the output + (providing more output space) before each call. + + The library also supports reading and writing files in gzip (.gz) format + with an interface similar to that of stdio. + + The library does not install any signal handler. The decoder checks + the consistency of the compressed data, so the library should never + crash even in case of corrupted input. +*/ + +/* + The application must update next_in and avail_in when avail_in has + dropped to zero. It must update next_out and avail_out when avail_out + has dropped to zero. The application must initialize zalloc, zfree and + opaque before calling the init function. All other fields are set by the + compression library and must not be updated by the application. + + The opaque value provided by the application will be passed as the first + parameter for calls of zalloc and zfree. This can be useful for custom + memory management. The compression library attaches no meaning to the + opaque value. + + zalloc must return Z_NULL if there is not enough memory for the object. + If zlib is used in a multi-threaded application, zalloc and zfree must be + thread safe. + + On 16-bit systems, the functions zalloc and zfree must be able to allocate + exactly 65536 bytes, but will not be required to allocate more than this + if the symbol MAXSEG_64K is defined (see zconf.h). WARNING: On MSDOS, + pointers returned by zalloc for objects of exactly 65536 bytes *must* + have their offset normalized to zero. The default allocation function + provided by this library ensures this (see zutil.c). To reduce memory + requirements and avoid any allocation of 64K objects, at the expense of + compression ratio, compile the library with -DMAX_WBITS=14 (see zconf.h). + + The fields total_in and total_out can be used for statistics or + progress reports. After compression, total_in holds the total size of + the uncompressed data and may be saved for use in the decompressor + (particularly if the decompressor wants to decompress everything in + a single step). +*/ + + /* constants */ + +#define Z_NO_FLUSH 0 +#define Z_PARTIAL_FLUSH 1 /* will be removed, use Z_SYNC_FLUSH instead */ +#define Z_SYNC_FLUSH 2 +#define Z_FULL_FLUSH 3 +#define Z_FINISH 4 +/* Allowed flush values; see deflate() below for details */ + +#define Z_OK 0 +#define Z_STREAM_END 1 +#define Z_NEED_DICT 2 +#define Z_ERRNO (-1) +#define Z_STREAM_ERROR (-2) +#define Z_DATA_ERROR (-3) +#define Z_MEM_ERROR (-4) +#define Z_BUF_ERROR (-5) +#define Z_VERSION_ERROR (-6) +/* Return codes for the compression/decompression functions. Negative + * values are errors, positive values are used for special but normal events. + */ + +#define Z_NO_COMPRESSION 0 +#define Z_BEST_SPEED 1 +#define Z_BEST_COMPRESSION 9 +#define Z_DEFAULT_COMPRESSION (-1) +/* compression levels */ + +#define Z_FILTERED 1 +#define Z_HUFFMAN_ONLY 2 +#define Z_DEFAULT_STRATEGY 0 +/* compression strategy; see deflateInit2() below for details */ + +#define Z_BINARY 0 +#define Z_ASCII 1 +#define Z_UNKNOWN 2 +/* Possible values of the data_type field */ + +#define Z_DEFLATED 8 +/* The deflate compression method (the only one supported in this version) */ + +#define Z_NULL 0 /* for initializing zalloc, zfree, opaque */ + +#define zlib_version zlibVersion() +/* for compatibility with versions < 1.0.2 */ + + /* basic functions */ + +const char * zlibVersion OF((void)); +/* The application can compare zlibVersion and ZLIB_VERSION for consistency. + If the first character differs, the library code actually used is + not compatible with the zlib.h header file used by the application. + This check is automatically made by deflateInit and inflateInit. + */ + +/* +int deflateInit OF((z_streamp strm, int level)); + + Initializes the internal stream state for compression. The fields + zalloc, zfree and opaque must be initialized before by the caller. + If zalloc and zfree are set to Z_NULL, deflateInit updates them to + use default allocation functions. + + The compression level must be Z_DEFAULT_COMPRESSION, or between 0 and 9: + 1 gives best speed, 9 gives best compression, 0 gives no compression at + all (the input data is simply copied a block at a time). + Z_DEFAULT_COMPRESSION requests a default compromise between speed and + compression (currently equivalent to level 6). + + deflateInit returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if level is not a valid compression level, + Z_VERSION_ERROR if the zlib library version (zlib_version) is incompatible + with the version assumed by the caller (ZLIB_VERSION). + msg is set to null if there is no error message. deflateInit does not + perform any compression: this will be done by deflate(). +*/ + + +int deflate OF((z_streamp strm, int flush)); +/* + deflate compresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may introduce some + output latency (reading input without producing any output) except when + forced to flush. + + The detailed semantics are as follows. deflate performs one or both of the + following actions: + + - Compress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in and avail_in are updated and + processing will resume at this point for the next call of deflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. This action is forced if the parameter flush is non zero. + Forcing flush frequently degrades the compression ratio, so this parameter + should be set only when necessary (in interactive applications). + Some output may be provided even if flush is not set. + + Before the call of deflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating avail_in or avail_out accordingly; avail_out + should never be zero before the call. The application can consume the + compressed output when it wants, for example when the output buffer is full + (avail_out == 0), or after each call of deflate(). If deflate returns Z_OK + and with zero avail_out, it must be called again after making room in the + output buffer because there might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, all pending output is + flushed to the output buffer and the output is aligned on a byte boundary, so + that the decompressor can get all input data available so far. (In particular + avail_in is zero after the call if enough output space has been provided + before the call.) Flushing may degrade compression for some compression + algorithms and so it should be used only when necessary. + + If flush is set to Z_FULL_FLUSH, all output is flushed as with + Z_SYNC_FLUSH, and the compression state is reset so that decompression can + restart from this point if previous compressed data has been damaged or if + random access is desired. Using Z_FULL_FLUSH too often can seriously degrade + the compression. + + If deflate returns with avail_out == 0, this function must be called again + with the same value of the flush parameter and more output space (updated + avail_out), until the flush is complete (deflate returns with non-zero + avail_out). + + If the parameter flush is set to Z_FINISH, pending input is processed, + pending output is flushed and deflate returns with Z_STREAM_END if there + was enough output space; if deflate returns with Z_OK, this function must be + called again with Z_FINISH and more output space (updated avail_out) but no + more input data, until it returns with Z_STREAM_END or an error. After + deflate has returned Z_STREAM_END, the only possible operations on the + stream are deflateReset or deflateEnd. + + Z_FINISH can be used immediately after deflateInit if all the compression + is to be done in a single step. In this case, avail_out must be at least + 0.1% larger than avail_in plus 12 bytes. If deflate does not return + Z_STREAM_END, then it must be called again as described above. + + deflate() sets strm->adler to the adler32 checksum of all input read + so (that is, total_in bytes). + + deflate() may update data_type if it can make a good guess about + the input data type (Z_ASCII or Z_BINARY). In doubt, the data is considered + binary. This field is only for information purposes and does not affect + the compression algorithm in any manner. + + deflate() returns Z_OK if some progress has been made (more input + processed or more output produced), Z_STREAM_END if all input has been + consumed and all output has been produced (only when flush is set to + Z_FINISH), Z_STREAM_ERROR if the stream state was inconsistent (for example + if next_in or next_out was NULL), Z_BUF_ERROR if no progress is possible + (for example avail_in or avail_out was zero). +*/ + + +int deflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + deflateEnd returns Z_OK if success, Z_STREAM_ERROR if the + stream state was inconsistent, Z_DATA_ERROR if the stream was freed + prematurely (some input or output was discarded). In the error case, + msg may be set but then points to a static string (which must not be + deallocated). +*/ + + +/* +int inflateInit OF((z_streamp strm)); + + Initializes the internal stream state for decompression. The fields + next_in, avail_in, zalloc, zfree and opaque must be initialized before by + the caller. If next_in is not Z_NULL and avail_in is large enough (the exact + value depends on the compression method), inflateInit determines the + compression method from the zlib header and allocates all data structures + accordingly; otherwise the allocation will be deferred to the first call of + inflate. If zalloc and zfree are set to Z_NULL, inflateInit updates them to + use default allocation functions. + + inflateInit returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_VERSION_ERROR if the zlib library version is incompatible with the + version assumed by the caller. msg is set to null if there is no error + message. inflateInit does not perform any decompression apart from reading + the zlib header if present: this will be done by inflate(). (So next_in and + avail_in may be modified, but next_out and avail_out are unchanged.) +*/ + + +int inflate OF((z_streamp strm, int flush)); +/* + inflate decompresses as much data as possible, and stops when the input + buffer becomes empty or the output buffer becomes full. It may some + introduce some output latency (reading input without producing any output) + except when forced to flush. + + The detailed semantics are as follows. inflate performs one or both of the + following actions: + + - Decompress more input starting at next_in and update next_in and avail_in + accordingly. If not all input can be processed (because there is not + enough room in the output buffer), next_in is updated and processing + will resume at this point for the next call of inflate(). + + - Provide more output starting at next_out and update next_out and avail_out + accordingly. inflate() provides as much output as possible, until there + is no more input data or no more space in the output buffer (see below + about the flush parameter). + + Before the call of inflate(), the application should ensure that at least + one of the actions is possible, by providing more input and/or consuming + more output, and updating the next_* and avail_* values accordingly. + The application can consume the uncompressed output when it wants, for + example when the output buffer is full (avail_out == 0), or after each + call of inflate(). If inflate returns Z_OK and with zero avail_out, it + must be called again after making room in the output buffer because there + might be more output pending. + + If the parameter flush is set to Z_SYNC_FLUSH, inflate flushes as much + output as possible to the output buffer. The flushing behavior of inflate is + not specified for values of the flush parameter other than Z_SYNC_FLUSH + and Z_FINISH, but the current implementation actually flushes as much output + as possible anyway. + + inflate() should normally be called until it returns Z_STREAM_END or an + error. However if all decompression is to be performed in a single step + (a single call of inflate), the parameter flush should be set to + Z_FINISH. In this case all pending input is processed and all pending + output is flushed; avail_out must be large enough to hold all the + uncompressed data. (The size of the uncompressed data may have been saved + by the compressor for this purpose.) The next operation on this stream must + be inflateEnd to deallocate the decompression state. The use of Z_FINISH + is never required, but can be used to inform inflate that a faster routine + may be used for the single inflate() call. + + If a preset dictionary is needed at this point (see inflateSetDictionary + below), inflate sets strm-adler to the adler32 checksum of the + dictionary chosen by the compressor and returns Z_NEED_DICT; otherwise + it sets strm->adler to the adler32 checksum of all output produced + so (that is, total_out bytes) and returns Z_OK, Z_STREAM_END or + an error code as described below. At the end of the stream, inflate() + checks that its computed adler32 checksum is equal to that saved by the + compressor and returns Z_STREAM_END only if the checksum is correct. + + inflate() returns Z_OK if some progress has been made (more input processed + or more output produced), Z_STREAM_END if the end of the compressed data has + been reached and all uncompressed output has been produced, Z_NEED_DICT if a + preset dictionary is needed at this point, Z_DATA_ERROR if the input data was + corrupted (input stream not conforming to the zlib format or incorrect + adler32 checksum), Z_STREAM_ERROR if the stream structure was inconsistent + (for example if next_in or next_out was NULL), Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if no progress is possible or if there was not + enough room in the output buffer when Z_FINISH is used. In the Z_DATA_ERROR + case, the application may then call inflateSync to look for a good + compression block. +*/ + + +int inflateEnd OF((z_streamp strm)); +/* + All dynamically allocated data structures for this stream are freed. + This function discards any unprocessed input and does not flush any + pending output. + + inflateEnd returns Z_OK if success, Z_STREAM_ERROR if the stream state + was inconsistent. In the error case, msg may be set but then points to a + static string (which must not be deallocated). +*/ + + /* Advanced functions */ + +/* + The following functions are needed only in some special applications. +*/ + +/* +int deflateInit2 OF((z_streamp strm, + int level, + int method, + int windowBits, + int memLevel, + int strategy)); + + This is another version of deflateInit with more compression options. The + fields next_in, zalloc, zfree and opaque must be initialized before by + the caller. + + The method parameter is the compression method. It must be Z_DEFLATED in + this version of the library. + + The windowBits parameter is the base two logarithm of the window size + (the size of the history buffer). It should be in the range 8..15 for this + version of the library. Larger values of this parameter result in better + compression at the expense of memory usage. The default value is 15 if + deflateInit is used instead. + + The memLevel parameter specifies how much memory should be allocated + for the internal compression state. memLevel=1 uses minimum memory but + is slow and reduces compression ratio; memLevel=9 uses maximum memory + for optimal speed. The default value is 8. See zconf.h for total memory + usage as a function of windowBits and memLevel. + + The strategy parameter is used to tune the compression algorithm. Use the + value Z_DEFAULT_STRATEGY for normal data, Z_FILTERED for data produced by a + filter (or predictor), or Z_HUFFMAN_ONLY to force Huffman encoding only (no + string match). Filtered data consists mostly of small values with a + somewhat random distribution. In this case, the compression algorithm is + tuned to compress them better. The effect of Z_FILTERED is to force more + Huffman coding and less string matching; it is somewhat intermediate + between Z_DEFAULT and Z_HUFFMAN_ONLY. The strategy parameter only affects + the compression ratio but not the correctness of the compressed output even + if it is not set appropriately. + + deflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as an invalid + method). msg is set to null if there is no error message. deflateInit2 does + not perform any compression: this will be done by deflate(). +*/ + +int deflateSetDictionary OF((z_streamp strm, + const Byte *dictionary, + uInt dictLength)); +/* + Initializes the compression dictionary from the given byte sequence + without producing any compressed output. This function must be called + immediately after deflateInit, deflateInit2 or deflateReset, before any + call of deflate. The compressor and decompressor must use exactly the same + dictionary (see inflateSetDictionary). + + The dictionary should consist of strings (byte sequences) that are likely + to be encountered later in the data to be compressed, with the most commonly + used strings preferably put towards the end of the dictionary. Using a + dictionary is most useful when the data to be compressed is short and can be + predicted with good accuracy; the data can then be compressed better than + with the default empty dictionary. + + Depending on the size of the compression data structures selected by + deflateInit or deflateInit2, a part of the dictionary may in effect be + discarded, for example if the dictionary is larger than the window size in + deflate or deflate2. Thus the strings most likely to be useful should be + put at the end of the dictionary, not at the front. + + Upon return of this function, strm->adler is set to the Adler32 value + of the dictionary; the decompressor may later use this value to determine + which dictionary has been used by the compressor. (The Adler32 value + applies to the whole dictionary even if only a subset of the dictionary is + actually used by the compressor.) + + deflateSetDictionary returns Z_OK if success, or Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent (for example if deflate has already been called for this stream + or if the compression method is bsort). deflateSetDictionary does not + perform any compression: this will be done by deflate(). +*/ + +int deflateCopy OF((z_streamp dest, + z_streamp source)); +/* + Sets the destination stream as a complete copy of the source stream. + + This function can be useful when several compression strategies will be + tried, for example when there are several ways of pre-processing the input + data with a filter. The streams that will be discarded should then be freed + by calling deflateEnd. Note that deflateCopy duplicates the internal + compression state which can be quite large, so this strategy is slow and + can consume lots of memory. + + deflateCopy returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_STREAM_ERROR if the source stream state was inconsistent + (such as zalloc being NULL). msg is left unchanged in both source and + destination. +*/ + +int deflateReset OF((z_streamp strm)); +/* + This function is equivalent to deflateEnd followed by deflateInit, + but does not free and reallocate all the internal compression state. + The stream will keep the same compression level and any other attributes + that may have been set by deflateInit2. + + deflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + +int deflateParams OF((z_streamp strm, + int level, + int strategy)); +/* + Dynamically update the compression level and compression strategy. The + interpretation of level and strategy is as in deflateInit2. This can be + used to switch between compression and straight copy of the input data, or + to switch to a different kind of input data requiring a different + strategy. If the compression level is changed, the input available so far + is compressed with the old level (and may be flushed); the new level will + take effect only at the next call of deflate(). + + Before the call of deflateParams, the stream state must be set as for + a call of deflate(), since the currently available input may have to + be compressed and flushed. In particular, strm->avail_out must be non-zero. + + deflateParams returns Z_OK if success, Z_STREAM_ERROR if the source + stream state was inconsistent or if a parameter was invalid, Z_BUF_ERROR + if strm->avail_out was zero. +*/ + +/* +int inflateInit2 OF((z_streamp strm, + int windowBits)); + + This is another version of inflateInit with an extra parameter. The + fields next_in, avail_in, zalloc, zfree and opaque must be initialized + before by the caller. + + The windowBits parameter is the base two logarithm of the maximum window + size (the size of the history buffer). It should be in the range 8..15 for + this version of the library. The default value is 15 if inflateInit is used + instead. If a compressed stream with a larger window size is given as + input, inflate() will return with the error code Z_DATA_ERROR instead of + trying to allocate a larger window. + + inflateInit2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_STREAM_ERROR if a parameter is invalid (such as a negative + memLevel). msg is set to null if there is no error message. inflateInit2 + does not perform any decompression apart from reading the zlib header if + present: this will be done by inflate(). (So next_in and avail_in may be + modified, but next_out and avail_out are unchanged.) +*/ + +int inflateSetDictionary OF((z_streamp strm, + const Byte *dictionary, + uInt dictLength)); +/* + Initializes the decompression dictionary from the given uncompressed byte + sequence. This function must be called immediately after a call of inflate + if this call returned Z_NEED_DICT. The dictionary chosen by the compressor + can be determined from the Adler32 value returned by this call of + inflate. The compressor and decompressor must use exactly the same + dictionary (see deflateSetDictionary). + + inflateSetDictionary returns Z_OK if success, Z_STREAM_ERROR if a + parameter is invalid (such as NULL dictionary) or the stream state is + inconsistent, Z_DATA_ERROR if the given dictionary doesn't match the + expected one (incorrect Adler32 value). inflateSetDictionary does not + perform any decompression: this will be done by subsequent calls of + inflate(). +*/ + +int inflateSync OF((z_streamp strm)); +/* + Skips invalid compressed data until a full flush point (see above the + description of deflate with Z_FULL_FLUSH) can be found, or until all + available input is skipped. No output is provided. + + inflateSync returns Z_OK if a full flush point has been found, Z_BUF_ERROR + if no more input was provided, Z_DATA_ERROR if no flush point has been found, + or Z_STREAM_ERROR if the stream structure was inconsistent. In the success + case, the application may save the current current value of total_in which + indicates where valid compressed data was found. In the error case, the + application may repeatedly call inflateSync, providing more input each time, + until success or end of the input data. +*/ + +int inflateReset OF((z_streamp strm)); +/* + This function is equivalent to inflateEnd followed by inflateInit, + but does not free and reallocate all the internal decompression state. + The stream will keep attributes that may have been set by inflateInit2. + + inflateReset returns Z_OK if success, or Z_STREAM_ERROR if the source + stream state was inconsistent (such as zalloc or state being NULL). +*/ + + + /* utility functions */ + +/* + The following utility functions are implemented on top of the + basic stream-oriented functions. To simplify the interface, some + default options are assumed (compression level and memory usage, + standard memory allocation functions). The source code of these + utility functions can easily be modified if you need special options. +*/ + +int compress OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen)); +/* + Compresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be at least 0.1% larger than + sourceLen plus 12 bytes. Upon exit, destLen is the actual size of the + compressed buffer. + This function can be used to compress a whole file at once if the + input file is mmap'ed. + compress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer. +*/ + +int compress2 OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen, + int level)); +/* + Compresses the source buffer into the destination buffer. The level + parameter has the same meaning as in deflateInit. sourceLen is the byte + length of the source buffer. Upon entry, destLen is the total size of the + destination buffer, which must be at least 0.1% larger than sourceLen plus + 12 bytes. Upon exit, destLen is the actual size of the compressed buffer. + + compress2 returns Z_OK if success, Z_MEM_ERROR if there was not enough + memory, Z_BUF_ERROR if there was not enough room in the output buffer, + Z_STREAM_ERROR if the level parameter is invalid. +*/ + +int uncompress OF((Byte *dest, uLong *destLen, + const Byte *source, uLong sourceLen)); +/* + Decompresses the source buffer into the destination buffer. sourceLen is + the byte length of the source buffer. Upon entry, destLen is the total + size of the destination buffer, which must be large enough to hold the + entire uncompressed data. (The size of the uncompressed data must have + been saved previously by the compressor and transmitted to the decompressor + by some mechanism outside the scope of this compression library.) + Upon exit, destLen is the actual size of the compressed buffer. + This function can be used to decompress a whole file at once if the + input file is mmap'ed. + + uncompress returns Z_OK if success, Z_MEM_ERROR if there was not + enough memory, Z_BUF_ERROR if there was not enough room in the output + buffer, or Z_DATA_ERROR if the input data was corrupted. +*/ + + +typedef voidp gzFile; + +gzFile gzopen OF((const char *path, const char *mode)); +/* + Opens a gzip (.gz) file for reading or writing. The mode parameter + is as in fopen ("rb" or "wb") but can also include a compression level + ("wb9") or a strategy: 'f' for filtered data as in "wb6f", 'h' for + Huffman only compression as in "wb1h". (See the description + of deflateInit2 for more information about the strategy parameter.) + + gzopen can be used to read a file which is not in gzip format; in this + case gzread will directly read from the file without decompression. + + gzopen returns NULL if the file could not be opened or if there was + insufficient memory to allocate the (de)compression state; errno + can be checked to distinguish the two cases (if errno is zero, the + zlib error is Z_MEM_ERROR). */ + +gzFile gzdopen OF((int fd, const char *mode)); +/* + gzdopen() associates a gzFile with the file descriptor fd. File + descriptors are obtained from calls like open, dup, creat, pipe or + fileno (in the file has been previously opened with fopen). + The mode parameter is as in gzopen. + The next call of gzclose on the returned gzFile will also close the + file descriptor fd, just like fclose(fdopen(fd), mode) closes the file + descriptor fd. If you want to keep fd open, use gzdopen(dup(fd), mode). + gzdopen returns NULL if there was insufficient memory to allocate + the (de)compression state. +*/ + +int gzsetparams OF((gzFile file, int level, int strategy)); +/* + Dynamically update the compression level or strategy. See the description + of deflateInit2 for the meaning of these parameters. + gzsetparams returns Z_OK if success, or Z_STREAM_ERROR if the file was not + opened for writing. +*/ + +int gzread OF((gzFile file, voidp buf, unsigned len)); +/* + Reads the given number of uncompressed bytes from the compressed file. + If the input file was not in gzip format, gzread copies the given number + of bytes into the buffer. + gzread returns the number of uncompressed bytes actually read (0 for + end of file, -1 for error). */ + +int gzwrite OF((gzFile file, + const voidp buf, unsigned len)); +/* + Writes the given number of uncompressed bytes into the compressed file. + gzwrite returns the number of uncompressed bytes actually written + (0 in case of error). +*/ + +int gzprintf OF((gzFile file, const char *format, ...)); +/* + Converts, formats, and writes the args to the compressed file under + control of the format string, as in fprintf. gzprintf returns the number of + uncompressed bytes actually written (0 in case of error). +*/ + +int gzputs OF((gzFile file, const char *s)); +/* + Writes the given null-terminated string to the compressed file, excluding + the terminating null character. + gzputs returns the number of characters written, or -1 in case of error. +*/ + +char * gzgets OF((gzFile file, char *buf, int len)); +/* + Reads bytes from the compressed file until len-1 characters are read, or + a newline character is read and transferred to buf, or an end-of-file + condition is encountered. The string is then terminated with a null + character. + gzgets returns buf, or Z_NULL in case of error. +*/ + +int gzputc OF((gzFile file, int c)); +/* + Writes c, converted to an unsigned char, into the compressed file. + gzputc returns the value that was written, or -1 in case of error. +*/ + +int gzgetc OF((gzFile file)); +/* + Reads one byte from the compressed file. gzgetc returns this byte + or -1 in case of end of file or error. +*/ + +int gzflush OF((gzFile file, int flush)); +/* + Flushes all pending output into the compressed file. The parameter + flush is as in the deflate() function. The return value is the zlib + error number (see function gzerror below). gzflush returns Z_OK if + the flush parameter is Z_FINISH and all output could be flushed. + gzflush should be called only when strictly necessary because it can + degrade compression. +*/ + +long gzseek OF((gzFile file, + long offset, int whence)); +/* + Sets the starting position for the next gzread or gzwrite on the + given compressed file. The offset represents a number of bytes in the + uncompressed data stream. The whence parameter is defined as in lseek(2); + the value SEEK_END is not supported. + If the file is opened for reading, this function is emulated but can be + extremely slow. If the file is opened for writing, only forward seeks are + supported; gzseek then compresses a sequence of zeroes up to the new + starting position. + + gzseek returns the resulting offset location as measured in bytes from + the beginning of the uncompressed stream, or -1 in case of error, in + particular if the file is opened for writing and the new starting position + would be before the current position. +*/ + +int gzrewind OF((gzFile file)); +/* + Rewinds the given file. This function is supported only for reading. + + gzrewind(file) is equivalent to (int)gzseek(file, 0L, SEEK_SET) +*/ + +long gztell OF((gzFile file)); +/* + Returns the starting position for the next gzread or gzwrite on the + given compressed file. This position represents a number of bytes in the + uncompressed data stream. + + gztell(file) is equivalent to gzseek(file, 0L, SEEK_CUR) +*/ + +int gzeof OF((gzFile file)); +/* + Returns 1 when EOF has previously been detected reading the given + input stream, otherwise zero. +*/ + +int gzclose OF((gzFile file)); +/* + Flushes all pending output if necessary, closes the compressed file + and deallocates all the (de)compression state. The return value is the zlib + error number (see function gzerror below). +*/ + +const char * gzerror OF((gzFile file, int *errnum)); +/* + Returns the error message for the last error which occurred on the + given compressed file. errnum is set to zlib error number. If an + error occurred in the file system and not in the compression library, + errnum is set to Z_ERRNO and the application may consult errno + to get the exact error code. +*/ + + /* checksum functions */ + +/* + These functions are not related to compression but are exported + anyway because they might be useful in applications using the + compression library. +*/ + +uLong adler32 OF((uLong adler, const Byte *buf, uInt len)); + +/* + Update a running Adler-32 checksum with the bytes buf[0..len-1] and + return the updated checksum. If buf is NULL, this function returns + the required initial value for the checksum. + An Adler-32 checksum is almost as reliable as a CRC32 but can be computed + much faster. Usage example: + + uLong adler = adler32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + adler = adler32(adler, buffer, length); + } + if (adler != original_adler) error(); +*/ + +uLong crc32 OF((uLong crc, const Byte *buf, uInt len)); +/* + Update a running crc with the bytes buf[0..len-1] and return the updated + crc. If buf is NULL, this function returns the required initial value + for the crc. Pre- and post-conditioning (one's complement) is performed + within this function so it shouldn't be done by the application. + Usage example: + + uLong crc = crc32(0L, Z_NULL, 0); + + while (read_buffer(buffer, length) != EOF) { + crc = crc32(crc, buffer, length); + } + if (crc != original_crc) error(); +*/ + +// private stuff to not include cmdlib.h +/* +============================================================================ + + BYTE ORDER FUNCTIONS + +============================================================================ +*/ + +#ifdef _SGI_SOURCE +#define __BIG_ENDIAN__ +#endif + +#ifdef __BIG_ENDIAN__ + +short __LittleShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short __BigShort (short l) +{ + return l; +} + + +int __LittleLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int __BigLong (int l) +{ + return l; +} + + +float __LittleFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float __BigFloat (float l) +{ + return l; +} + + +#else + + +short __BigShort (short l) +{ + byte b1,b2; + + b1 = l&255; + b2 = (l>>8)&255; + + return (b1<<8) + b2; +} + +short __LittleShort (short l) +{ + return l; +} + + +int __BigLong (int l) +{ + byte b1,b2,b3,b4; + + b1 = l&255; + b2 = (l>>8)&255; + b3 = (l>>16)&255; + b4 = (l>>24)&255; + + return ((int)b1<<24) + ((int)b2<<16) + ((int)b3<<8) + b4; +} + +int __LittleLong (int l) +{ + return l; +} + +float __BigFloat (float l) +{ + union {byte b[4]; float f;} in, out; + + in.f = l; + out.b[0] = in.b[3]; + out.b[1] = in.b[2]; + out.b[2] = in.b[1]; + out.b[3] = in.b[0]; + + return out.f; +} + +float __LittleFloat (float l) +{ + return l; +} + + + +#endif + + + + + /* various hacks, don't look :) */ + +/* deflateInit and inflateInit are macros to allow checking the zlib version + * and the compiler's view of z_stream: + */ +int deflateInit_ OF((z_streamp strm, int level, + const char *version, int stream_size)); +int inflateInit_ OF((z_streamp strm, + const char *version, int stream_size)); +int deflateInit2_ OF((z_streamp strm, int level, int method, + int windowBits, int memLevel, + int strategy, const char *version, + int stream_size)); +int inflateInit2_ OF((z_streamp strm, int windowBits, + const char *version, int stream_size)); +#define deflateInit(strm, level) \ + deflateInit_((strm), (level), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit(strm) \ + inflateInit_((strm), ZLIB_VERSION, sizeof(z_stream)) +#define deflateInit2(strm, level, method, windowBits, memLevel, strategy) \ + deflateInit2_((strm),(level),(method),(windowBits),(memLevel),\ + (strategy), ZLIB_VERSION, sizeof(z_stream)) +#define inflateInit2(strm, windowBits) \ + inflateInit2_((strm), (windowBits), ZLIB_VERSION, sizeof(z_stream)) + + +const char * zError OF((int err)); +int inflateSyncPoint OF((z_streamp z)); +const uLong * get_crc_table OF((void)); + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +extern const char *z_errmsg[10]; /* indexed by 2-zlib_error */ +/* (size given to avoid silly warnings with Visual C++) */ + +#define ERR_MSG(err) z_errmsg[Z_NEED_DICT-(err)] + +#define ERR_RETURN(strm,err) \ + return (strm->msg = (char*)ERR_MSG(err), (err)) +/* To be used only when the state is known to be valid */ + + /* common constants */ + +#ifndef DEF_WBITS +# define DEF_WBITS MAX_WBITS +#endif +/* default windowBits for decompression. MAX_WBITS is for compression only */ + +#if MAX_MEM_LEVEL >= 8 +# define DEF_MEM_LEVEL 8 +#else +# define DEF_MEM_LEVEL MAX_MEM_LEVEL +#endif +/* default memLevel */ + +#define STORED_BLOCK 0 +#define STATIC_TREES 1 +#define DYN_TREES 2 +/* The three kinds of block type */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define PRESET_DICT 0x20 /* preset dictionary flag in zlib header */ + + /* target dependencies */ + + /* Common defaults */ + +#ifndef OS_CODE +# define OS_CODE 0x03 /* assume Unix */ +#endif + +#ifndef F_OPEN +# define F_OPEN(name, mode) fopen((name), (mode)) +#endif + + /* functions */ + +#ifdef HAVE_STRERROR + extern char *strerror OF((int)); +# define zstrerror(errnum) strerror(errnum) +#else +# define zstrerror(errnum) "" +#endif + +#define zmemcpy memcpy +#define zmemcmp memcmp +#define zmemzero(dest, len) memset(dest, 0, len) + +/* Diagnostic functions */ +#ifdef _ZIP_DEBUG_ + int z_verbose = 0; +# define Assert(cond,msg) assert(cond); + //{if(!(cond)) Sys_Error(msg);} +# define Trace(x) {if (z_verbose>=0) Sys_Error x ;} +# define Tracev(x) {if (z_verbose>0) Sys_Error x ;} +# define Tracevv(x) {if (z_verbose>1) Sys_Error x ;} +# define Tracec(c,x) {if (z_verbose>0 && (c)) Sys_Error x ;} +# define Tracecv(c,x) {if (z_verbose>1 && (c)) Sys_Error x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + +typedef uLong (*check_func) OF((uLong check, const Byte *buf, uInt len)); +voidp zcalloc OF((voidp opaque, unsigned items, unsigned size)); +void zcfree OF((voidp opaque, voidp ptr)); + +#define ZALLOC(strm, items, size) \ + (*((strm)->zalloc))((strm)->opaque, (items), (size)) +#define ZFREE(strm, addr) (*((strm)->zfree))((strm)->opaque, (voidp)(addr)) +#define TRY_FREE(s, p) {if (p) ZFREE(s, p);} + + +#if !defined(unix) && !defined(CASESENSITIVITYDEFAULT_YES) && \ + !defined(CASESENSITIVITYDEFAULT_NO) +#define CASESENSITIVITYDEFAULT_NO +#endif + + +#ifndef UNZ_BUFSIZE +#define UNZ_BUFSIZE (65536) +#endif + +#ifndef UNZ_MAXFILENAMEINZIP +#define UNZ_MAXFILENAMEINZIP (256) +#endif + +#ifndef ALLOC +# define ALLOC(size) (malloc(size)) +#endif +#ifndef TRYFREE +# define TRYFREE(p) {if (p) free(p);} +#endif + +#define SIZECENTRALDIRITEM (0x2e) +#define SIZEZIPLOCALHEADER (0x1e) + + + +/* =========================================================================== + Read a byte from a gz_stream; update next_in and avail_in. Return EOF + for end of file. + IN assertion: the stream s has been sucessfully opened for reading. +*/ + +/* +static int unzlocal_getByte(FILE *fin,int *pi) +{ + unsigned char c; + int err = fread(&c, 1, 1, fin); + if (err==1) + { + *pi = (int)c; + return UNZ_OK; + } + else + { + if (ferror(fin)) + return UNZ_ERRNO; + else + return UNZ_EOF; + } +} +*/ + +/* =========================================================================== + Reads a long in LSB order from the given gz_stream. Sets +*/ +static int unzlocal_getShort (FILE* fin, uLong *pX) +{ + short v; + + fread( &v, sizeof(v), 1, fin ); + + *pX = __LittleShort( v); + return UNZ_OK; + +/* + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +*/ +} + +static int unzlocal_getLong (FILE *fin, uLong *pX) +{ + int v; + + fread( &v, sizeof(v), 1, fin ); + + *pX = __LittleLong( v); + return UNZ_OK; + +/* + uLong x ; + int i; + int err; + + err = unzlocal_getByte(fin,&i); + x = (uLong)i; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<8; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<16; + + if (err==UNZ_OK) + err = unzlocal_getByte(fin,&i); + x += ((uLong)i)<<24; + + if (err==UNZ_OK) + *pX = x; + else + *pX = 0; + return err; +*/ +} + + +/* My own strcmpi / strcasecmp */ +static int strcmpcasenosensitive_internal (const char* fileName1,const char* fileName2) +{ + for (;;) + { + char c1=*(fileName1++); + char c2=*(fileName2++); + if ((c1>='a') && (c1<='z')) + c1 -= 0x20; + if ((c2>='a') && (c2<='z')) + c2 -= 0x20; + if (c1=='\0') + return ((c2=='\0') ? 0 : -1); + if (c2=='\0') + return 1; + if (c1c2) + return 1; + } +} + + +#ifdef CASESENSITIVITYDEFAULT_NO +#define CASESENSITIVITYDEFAULTVALUE 2 +#else +#define CASESENSITIVITYDEFAULTVALUE 1 +#endif + +#ifndef STRCMPCASENOSENTIVEFUNCTION +#define STRCMPCASENOSENTIVEFUNCTION strcmpcasenosensitive_internal +#endif + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) + +*/ +extern int unzStringFileNameCompare (const char* fileName1,const char* fileName2,int iCaseSensitivity) +{ + if (iCaseSensitivity==0) + iCaseSensitivity=CASESENSITIVITYDEFAULTVALUE; + + if (iCaseSensitivity==1) + return strcmp(fileName1,fileName2); + + return STRCMPCASENOSENTIVEFUNCTION(fileName1,fileName2); +} + +#define BUFREADCOMMENT (0x400) + +/* + Locate the Central directory of a zipfile (at the end, just before + the global comment) +*/ +static uLong unzlocal_SearchCentralDir(FILE *fin) +{ + unsigned char* buf; + uLong uSizeFile; + uLong uBackRead; + uLong uMaxBack=0xffff; /* maximum size of global comment */ + uLong uPosFound=0; + + if (fseek(fin,0,SEEK_END) != 0) + return 0; + + + uSizeFile = ftell( fin ); + + if (uMaxBack>uSizeFile) + uMaxBack = uSizeFile; + + buf = (unsigned char*)malloc(BUFREADCOMMENT+4); + if (buf==NULL) + return 0; + + uBackRead = 4; + while (uBackReaduMaxBack) + uBackRead = uMaxBack; + else + uBackRead+=BUFREADCOMMENT; + uReadPos = uSizeFile-uBackRead ; + + uReadSize = ((BUFREADCOMMENT+4) < (uSizeFile-uReadPos)) ? + (BUFREADCOMMENT+4) : (uSizeFile-uReadPos); + if (fseek(fin,uReadPos,SEEK_SET)!=0) + break; + + if (fread(buf,(uInt)uReadSize,1,fin)!=1) + break; + + for (i=(int)uReadSize-3; (i--)>0;) + if (((*(buf+i))==0x50) && ((*(buf+i+1))==0x4b) && + ((*(buf+i+2))==0x05) && ((*(buf+i+3))==0x06)) + { + uPosFound = uReadPos+i; + break; + } + + if (uPosFound!=0) + break; + } + free(buf); + return uPosFound; +} + +extern unzFile unzReOpen (const char* path, unzFile file) +{ + unz_s *s; + FILE * fin; + + fin=fopen(path,"rb"); + if (fin==NULL) + return NULL; + + s=(unz_s*)malloc(sizeof(unz_s)); + memcpy(s, (unz_s*)file, sizeof(unz_s)); + + s->file = fin; + return (unzFile)s; +} + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\test\\zlib109.zip" or on an Unix computer + "zlib/zlib109.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ +extern unzFile unzOpen (const char* path) +{ + unz_s us; + unz_s *s; + uLong central_pos,uL; + FILE * fin ; + + uLong number_disk; /* number of the current dist, used for + spaning ZIP, unsupported, always 0*/ + uLong number_disk_with_CD; /* number the the disk with central dir, used + for spaning ZIP, unsupported, always 0*/ + uLong number_entry_CD; /* total number of entries in + the central dir + (same than number_entry on nospan) */ + + int err=UNZ_OK; + + fin=fopen(path,"rb"); + if (fin==NULL) + return NULL; + + central_pos = unzlocal_SearchCentralDir(fin); + if (central_pos==0) + err=UNZ_ERRNO; + + if (fseek(fin,central_pos,SEEK_SET)!=0) + err=UNZ_ERRNO; + + /* the signature, already checked */ + if (unzlocal_getLong(fin,&uL)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of this disk */ + if (unzlocal_getShort(fin,&number_disk)!=UNZ_OK) + err=UNZ_ERRNO; + + /* number of the disk with the start of the central directory */ + if (unzlocal_getShort(fin,&number_disk_with_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir on this disk */ + if (unzlocal_getShort(fin,&us.gi.number_entry)!=UNZ_OK) + err=UNZ_ERRNO; + + /* total number of entries in the central dir */ + if (unzlocal_getShort(fin,&number_entry_CD)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((number_entry_CD!=us.gi.number_entry) || + (number_disk_with_CD!=0) || + (number_disk!=0)) + err=UNZ_BADZIPFILE; + + /* size of the central directory */ + if (unzlocal_getLong(fin,&us.size_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* offset of start of central directory with respect to the + starting disk number */ + if (unzlocal_getLong(fin,&us.offset_central_dir)!=UNZ_OK) + err=UNZ_ERRNO; + + /* zipfile comment length */ + if (unzlocal_getShort(fin,&us.gi.size_comment)!=UNZ_OK) + err=UNZ_ERRNO; + + if ((central_pospfile_in_zip_read!=NULL) + unzCloseCurrentFile(file); + + fclose(s->file); + free(s); + return UNZ_OK; +} + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ +extern int unzGetGlobalInfo (unzFile file,unz_global_info *pglobal_info) +{ + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + *pglobal_info=s->gi; + return UNZ_OK; +} + + +/* + Translate date/time from Dos format to tm_unz (readable more easilty) +*/ +static void unzlocal_DosDateToTmuDate (uLong ulDosDate, tm_unz* ptm) +{ + uLong uDate; + uDate = (uLong)(ulDosDate>>16); + ptm->tm_mday = (uInt)(uDate&0x1f) ; + ptm->tm_mon = (uInt)((((uDate)&0x1E0)/0x20)-1) ; + ptm->tm_year = (uInt)(((uDate&0x0FE00)/0x0200)+1980) ; + + ptm->tm_hour = (uInt) ((ulDosDate &0xF800)/0x800); + ptm->tm_min = (uInt) ((ulDosDate&0x7E0)/0x20) ; + ptm->tm_sec = (uInt) (2*(ulDosDate&0x1f)) ; +} + +/* + Get Info about the current file in the zipfile, with internal only info +*/ +static int unzlocal_GetCurrentFileInfoInternal (unzFile file, + unz_file_info *pfile_info, + unz_file_info_internal + *pfile_info_internal, + char *szFileName, + uLong fileNameBufferSize, + void *extraField, + uLong extraFieldBufferSize, + char *szComment, + uLong commentBufferSize) +{ + unz_s* s; + unz_file_info file_info; + unz_file_info_internal file_info_internal; + int err=UNZ_OK; + uLong uMagic; + long lSeek=0; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (fseek(s->file,s->pos_in_central_dir+s->byte_before_the_zipfile,SEEK_SET)!=0) + err=UNZ_ERRNO; + + + /* we check the magic */ + if (err==UNZ_OK) + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x02014b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(s->file,&file_info.version) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.version_needed) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.flag) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.compression_method) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.dosDate) != UNZ_OK) + err=UNZ_ERRNO; + + unzlocal_DosDateToTmuDate(file_info.dosDate,&file_info.tmu_date); + + if (unzlocal_getLong(s->file,&file_info.crc) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.compressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.uncompressed_size) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_filename) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_extra) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.size_file_comment) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.disk_num_start) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&file_info.internal_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info.external_fa) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&file_info_internal.offset_curfile) != UNZ_OK) + err=UNZ_ERRNO; + + lSeek+=file_info.size_filename; + if ((err==UNZ_OK) && (szFileName!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_filename0) && (fileNameBufferSize>0)) + if (fread(szFileName,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek -= uSizeRead; + } + + + if ((err==UNZ_OK) && (extraField!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_extrafile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_extra>0) && (extraFieldBufferSize>0)) + if (fread(extraField,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek += file_info.size_file_extra - uSizeRead; + } + else + lSeek+=file_info.size_file_extra; + + + if ((err==UNZ_OK) && (szComment!=NULL)) + { + uLong uSizeRead ; + if (file_info.size_file_commentfile,lSeek,SEEK_CUR)==0) + lSeek=0; + else + err=UNZ_ERRNO; + if ((file_info.size_file_comment>0) && (commentBufferSize>0)) + if (fread(szComment,(uInt)uSizeRead,1,s->file)!=1) + err=UNZ_ERRNO; + lSeek+=file_info.size_file_comment - uSizeRead; + } + else + lSeek+=file_info.size_file_comment; + + if ((err==UNZ_OK) && (pfile_info!=NULL)) + *pfile_info=file_info; + + if ((err==UNZ_OK) && (pfile_info_internal!=NULL)) + *pfile_info_internal=file_info_internal; + + return err; +} + + + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. +*/ +extern int unzGetCurrentFileInfo ( unzFile file, unz_file_info *pfile_info, + char *szFileName, uLong fileNameBufferSize, + void *extraField, uLong extraFieldBufferSize, + char *szComment, uLong commentBufferSize) +{ + return unzlocal_GetCurrentFileInfoInternal(file,pfile_info,NULL, + szFileName,fileNameBufferSize, + extraField,extraFieldBufferSize, + szComment,commentBufferSize); +} + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ +extern int unzGoToFirstFile (unzFile file) +{ + int err=UNZ_OK; + unz_s* s; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + s->pos_in_central_dir=s->offset_central_dir; + s->num_file=0; + err=unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ +extern int unzGoToNextFile (unzFile file) +{ + unz_s* s; + int err; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + if (s->num_file+1==s->gi.number_entry) + return UNZ_END_OF_LIST_OF_FILE; + + s->pos_in_central_dir += SIZECENTRALDIRITEM + s->cur_file_info.size_filename + + s->cur_file_info.size_file_extra + s->cur_file_info.size_file_comment ; + s->num_file++; + err = unzlocal_GetCurrentFileInfoInternal(file,&s->cur_file_info, + &s->cur_file_info_internal, + NULL,0,NULL,0,NULL,0); + s->current_file_ok = (err == UNZ_OK); + return err; +} + + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzipStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ +extern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity) +{ + unz_s* s; + int err; + + + uLong num_fileSaved; + uLong pos_in_central_dirSaved; + + + if (file==NULL) + return UNZ_PARAMERROR; + + if (strlen(szFileName)>=UNZ_MAXFILENAMEINZIP) + return UNZ_PARAMERROR; + + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_END_OF_LIST_OF_FILE; + + num_fileSaved = s->num_file; + pos_in_central_dirSaved = s->pos_in_central_dir; + + err = unzGoToFirstFile(file); + + while (err == UNZ_OK) + { + char szCurrentFileName[UNZ_MAXFILENAMEINZIP+1]; + unzGetCurrentFileInfo(file,NULL, + szCurrentFileName,sizeof(szCurrentFileName)-1, + NULL,0,NULL,0); + if (unzStringFileNameCompare(szCurrentFileName, + szFileName,iCaseSensitivity)==0) + return UNZ_OK; + err = unzGoToNextFile(file); + } + + s->num_file = num_fileSaved ; + s->pos_in_central_dir = pos_in_central_dirSaved ; + return err; +} + + +/* + Read the static header of the current zipfile + Check the coherency of the static header and info in the end of central + directory about this file + store in *piSizeVar the size of extra info in static header + (filename and size of extra field data) +*/ +static int unzlocal_CheckCurrentFileCoherencyHeader (unz_s* s, uInt* piSizeVar, + uLong *poffset_local_extrafield, + uInt *psize_local_extrafield) +{ + uLong uMagic,uData,uFlags; + uLong size_filename; + uLong size_extra_field; + int err=UNZ_OK; + + *piSizeVar = 0; + *poffset_local_extrafield = 0; + *psize_local_extrafield = 0; + + if (fseek(s->file,s->cur_file_info_internal.offset_curfile + + s->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + + + if (err==UNZ_OK) + if (unzlocal_getLong(s->file,&uMagic) != UNZ_OK) + err=UNZ_ERRNO; + else if (uMagic!=0x04034b50) + err=UNZ_BADZIPFILE; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; +/* + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.wVersion)) + err=UNZ_BADZIPFILE; +*/ + if (unzlocal_getShort(s->file,&uFlags) != UNZ_OK) + err=UNZ_ERRNO; + + if (unzlocal_getShort(s->file,&uData) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compression_method)) + err=UNZ_BADZIPFILE; + + if ((err==UNZ_OK) && (s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* date/time */ + err=UNZ_ERRNO; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* crc */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.crc) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size compr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.compressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + if (unzlocal_getLong(s->file,&uData) != UNZ_OK) /* size uncompr */ + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (uData!=s->cur_file_info.uncompressed_size) && + ((uFlags & 8)==0)) + err=UNZ_BADZIPFILE; + + + if (unzlocal_getShort(s->file,&size_filename) != UNZ_OK) + err=UNZ_ERRNO; + else if ((err==UNZ_OK) && (size_filename!=s->cur_file_info.size_filename)) + err=UNZ_BADZIPFILE; + + *piSizeVar += (uInt)size_filename; + + if (unzlocal_getShort(s->file,&size_extra_field) != UNZ_OK) + err=UNZ_ERRNO; + *poffset_local_extrafield= s->cur_file_info_internal.offset_curfile + + SIZEZIPLOCALHEADER + size_filename; + *psize_local_extrafield = (uInt)size_extra_field; + + *piSizeVar += (uInt)size_extra_field; + + return err; +} + +/* + Open for reading data the current file in the zipfile. + If there is no error and the file is opened, the return value is UNZ_OK. +*/ +extern int unzOpenCurrentFile (unzFile file) +{ + int err=UNZ_OK; + int Store; + uInt iSizeVar; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uLong offset_local_extrafield; /* offset of the static extra field */ + uInt size_local_extrafield; /* size of the static extra field */ + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + if (!s->current_file_ok) + return UNZ_PARAMERROR; + + if (s->pfile_in_zip_read != NULL) + unzCloseCurrentFile(file); + + if (unzlocal_CheckCurrentFileCoherencyHeader(s,&iSizeVar, + &offset_local_extrafield,&size_local_extrafield)!=UNZ_OK) + return UNZ_BADZIPFILE; + + pfile_in_zip_read_info = (file_in_zip_read_info_s*) + malloc(sizeof(file_in_zip_read_info_s)); + if (pfile_in_zip_read_info==NULL) + return UNZ_INTERNALERROR; + + pfile_in_zip_read_info->read_buffer=(char*)malloc(UNZ_BUFSIZE); + pfile_in_zip_read_info->offset_local_extrafield = offset_local_extrafield; + pfile_in_zip_read_info->size_local_extrafield = size_local_extrafield; + pfile_in_zip_read_info->pos_local_extrafield=0; + + if (pfile_in_zip_read_info->read_buffer==NULL) + { + free(pfile_in_zip_read_info); + return UNZ_INTERNALERROR; + } + + pfile_in_zip_read_info->stream_initialised=0; + + if ((s->cur_file_info.compression_method!=0) && + (s->cur_file_info.compression_method!=Z_DEFLATED)) + err=UNZ_BADZIPFILE; + Store = s->cur_file_info.compression_method==0; + + pfile_in_zip_read_info->crc32_wait=s->cur_file_info.crc; + pfile_in_zip_read_info->crc32=0; + pfile_in_zip_read_info->compression_method = + s->cur_file_info.compression_method; + pfile_in_zip_read_info->file=s->file; + pfile_in_zip_read_info->byte_before_the_zipfile=s->byte_before_the_zipfile; + + pfile_in_zip_read_info->stream.total_out = 0; + + if (!Store) + { + pfile_in_zip_read_info->stream.zalloc = (alloc_func)0; + pfile_in_zip_read_info->stream.zfree = (free_func)0; + pfile_in_zip_read_info->stream.opaque = (voidp)0; + + err=inflateInit2(&pfile_in_zip_read_info->stream, -MAX_WBITS); + if (err == Z_OK) + pfile_in_zip_read_info->stream_initialised=1; + /* windowBits is passed < 0 to tell that there is no zlib header. + * Note that in this case inflate *requires* an extra "dummy" byte + * after the compressed stream in order to complete decompression and + * return Z_STREAM_END. + * In unzip, i don't wait absolutely Z_STREAM_END because I known the + * size of both compressed and uncompressed data + */ + } + pfile_in_zip_read_info->rest_read_compressed = + s->cur_file_info.compressed_size ; + pfile_in_zip_read_info->rest_read_uncompressed = + s->cur_file_info.uncompressed_size ; + + + pfile_in_zip_read_info->pos_in_zipfile = + s->cur_file_info_internal.offset_curfile + SIZEZIPLOCALHEADER + + iSizeVar; + + pfile_in_zip_read_info->stream.avail_in = (uInt)0; + + + s->pfile_in_zip_read = pfile_in_zip_read_info; + return UNZ_OK; +} + + +/* + Read bytes from the current file. + buf contain buffer where data must be copied + len the size of buf. + + return the number of byte copied if somes bytes are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ +extern int unzReadCurrentFile (unzFile file, void *buf, unsigned len) +{ + int err=UNZ_OK; + uInt iRead = 0; + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if ((pfile_in_zip_read_info->read_buffer == NULL)) + return UNZ_END_OF_LIST_OF_FILE; + if (len==0) + return 0; + + pfile_in_zip_read_info->stream.next_out = (Byte*)buf; + + pfile_in_zip_read_info->stream.avail_out = (uInt)len; + + if (len>pfile_in_zip_read_info->rest_read_uncompressed) + pfile_in_zip_read_info->stream.avail_out = + (uInt)pfile_in_zip_read_info->rest_read_uncompressed; + + while (pfile_in_zip_read_info->stream.avail_out>0) + { + if ((pfile_in_zip_read_info->stream.avail_in==0) && + (pfile_in_zip_read_info->rest_read_compressed>0)) + { + uInt uReadThis = UNZ_BUFSIZE; + if (pfile_in_zip_read_info->rest_read_compressedrest_read_compressed; + if (uReadThis == 0) + return UNZ_EOF; + if (s->cur_file_info.compressed_size == pfile_in_zip_read_info->rest_read_compressed) + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->pos_in_zipfile + + pfile_in_zip_read_info->byte_before_the_zipfile,SEEK_SET)!=0) + return UNZ_ERRNO; + if (fread(pfile_in_zip_read_info->read_buffer,uReadThis,1, + pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + pfile_in_zip_read_info->pos_in_zipfile += uReadThis; + + pfile_in_zip_read_info->rest_read_compressed-=uReadThis; + + pfile_in_zip_read_info->stream.next_in = + (Byte*)pfile_in_zip_read_info->read_buffer; + pfile_in_zip_read_info->stream.avail_in = (uInt)uReadThis; + } + + if (pfile_in_zip_read_info->compression_method==0) + { + uInt uDoCopy,i ; + if (pfile_in_zip_read_info->stream.avail_out < + pfile_in_zip_read_info->stream.avail_in) + uDoCopy = pfile_in_zip_read_info->stream.avail_out ; + else + uDoCopy = pfile_in_zip_read_info->stream.avail_in ; + + for (i=0;istream.next_out+i) = + *(pfile_in_zip_read_info->stream.next_in+i); + + pfile_in_zip_read_info->crc32 = crc32(pfile_in_zip_read_info->crc32, + pfile_in_zip_read_info->stream.next_out, + uDoCopy); + pfile_in_zip_read_info->rest_read_uncompressed-=uDoCopy; + pfile_in_zip_read_info->stream.avail_in -= uDoCopy; + pfile_in_zip_read_info->stream.avail_out -= uDoCopy; + pfile_in_zip_read_info->stream.next_out += uDoCopy; + pfile_in_zip_read_info->stream.next_in += uDoCopy; + pfile_in_zip_read_info->stream.total_out += uDoCopy; + iRead += uDoCopy; + } + else + { + uLong uTotalOutBefore,uTotalOutAfter; + const Byte *bufBefore; + uLong uOutThis; + int flush=Z_SYNC_FLUSH; + + uTotalOutBefore = pfile_in_zip_read_info->stream.total_out; + bufBefore = pfile_in_zip_read_info->stream.next_out; + + /* + if ((pfile_in_zip_read_info->rest_read_uncompressed == + pfile_in_zip_read_info->stream.avail_out) && + (pfile_in_zip_read_info->rest_read_compressed == 0)) + flush = Z_FINISH; + */ + err=inflate(&pfile_in_zip_read_info->stream,flush); + + uTotalOutAfter = pfile_in_zip_read_info->stream.total_out; + uOutThis = uTotalOutAfter-uTotalOutBefore; + + pfile_in_zip_read_info->crc32 = + crc32(pfile_in_zip_read_info->crc32,bufBefore, + (uInt)(uOutThis)); + + pfile_in_zip_read_info->rest_read_uncompressed -= + uOutThis; + + iRead += (uInt)(uTotalOutAfter - uTotalOutBefore); + + if (err==Z_STREAM_END) + return (iRead==0) ? UNZ_EOF : iRead; + if (err!=Z_OK) + break; + } + } + + if (err==Z_OK) + return iRead; + return err; +} + + +/* + Give the current position in uncompressed data +*/ +extern long unztell (unzFile file) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + return (long)pfile_in_zip_read_info->stream.total_out; +} + + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ +extern int unzeof (unzFile file) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + return 1; + else + return 0; +} + + + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the static-header version of the extra field (sometimes, there is + more info in the static-header version than in the central-header) + + if buf==NULL, it return the size of the static extra field that can be read + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of bytes copied in buf, or (if <0) + the error code +*/ +extern int unzGetLocalExtrafield (unzFile file,void *buf,unsigned len) +{ + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + uInt read_now; + uLong size_to_read; + + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + size_to_read = (pfile_in_zip_read_info->size_local_extrafield - + pfile_in_zip_read_info->pos_local_extrafield); + + if (buf==NULL) + return (int)size_to_read; + + if (len>size_to_read) + read_now = (uInt)size_to_read; + else + read_now = (uInt)len ; + + if (read_now==0) + return 0; + + if (fseek(pfile_in_zip_read_info->file, + pfile_in_zip_read_info->offset_local_extrafield + + pfile_in_zip_read_info->pos_local_extrafield,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (fread(buf,(uInt)size_to_read,1,pfile_in_zip_read_info->file)!=1) + return UNZ_ERRNO; + + return (int)read_now; +} + +/* + Close the file in zip opened with unzipOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ +extern int unzCloseCurrentFile (unzFile file) +{ + int err=UNZ_OK; + + unz_s* s; + file_in_zip_read_info_s* pfile_in_zip_read_info; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + pfile_in_zip_read_info=s->pfile_in_zip_read; + + if (pfile_in_zip_read_info==NULL) + return UNZ_PARAMERROR; + + + if (pfile_in_zip_read_info->rest_read_uncompressed == 0) + { + if (pfile_in_zip_read_info->crc32 != pfile_in_zip_read_info->crc32_wait) + err=UNZ_CRCERROR; + } + + + free(pfile_in_zip_read_info->read_buffer); + pfile_in_zip_read_info->read_buffer = NULL; + if (pfile_in_zip_read_info->stream_initialised) + inflateEnd(&pfile_in_zip_read_info->stream); + + pfile_in_zip_read_info->stream_initialised = 0; + free(pfile_in_zip_read_info); + + s->pfile_in_zip_read=NULL; + + return err; +} + + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of byte copied or an error code <0 +*/ +extern int unzGetGlobalComment (unzFile file, char *szComment, uLong uSizeBuf) +{ + unz_s* s; + uLong uReadThis ; + if (file==NULL) + return UNZ_PARAMERROR; + s=(unz_s*)file; + + uReadThis = uSizeBuf; + if (uReadThis>s->gi.size_comment) + uReadThis = s->gi.size_comment; + + if (fseek(s->file,s->central_pos+22,SEEK_SET)!=0) + return UNZ_ERRNO; + + if (uReadThis>0) + { + *szComment='\0'; + if (fread(szComment,(uInt)uReadThis,1,s->file)!=1) + return UNZ_ERRNO; + } + + if ((szComment != NULL) && (uSizeBuf > s->gi.size_comment)) + *(szComment+s->gi.size_comment)='\0'; + return (int)uReadThis; +} + +/* crc32.c -- compute the CRC-32 of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#ifdef DYNAMIC_CRC_TABLE + +static int crc_table_empty = 1; +static uLong crc_table[256]; +static void make_crc_table OF((void)); + +/* + Generate a table for a byte-wise 32-bit CRC calculation on the polynomial: + x^32+x^26+x^23+x^22+x^16+x^12+x^11+x^10+x^8+x^7+x^5+x^4+x^2+x+1. + + Polynomials over GF(2) are represented in binary, one bit per coefficient, + with the lowest powers in the most significant bit. Then adding polynomials + is just exclusive-or, and multiplying a polynomial by x is a right shift by + one. If we call the above polynomial p, and represent a byte as the + polynomial q, also with the lowest power in the most significant bit (so the + byte 0xb1 is the polynomial x^7+x^3+x+1), then the CRC is (q*x^32) mod p, + where a mod b means the remainder after dividing a by b. + + This calculation is done using the shift-register method of multiplying and + taking the remainder. The register is initialized to zero, and for each + incoming bit, x^32 is added mod p to the register if the bit is a one (where + x^32 mod p is p+x^32 = x^26+...+1), and the register is multiplied mod p by + x (which is shifting right by one and adding x^32 mod p if the bit shifted + out is a one). We start with the highest power (least significant bit) of + q and repeat for all eight bits of q. + + The table is simply the CRC of all possible eight bit values. This is all + the information needed to generate CRC's on data a byte at a time for all + combinations of CRC register values and incoming bytes. +*/ +static void make_crc_table() +{ + uLong c; + int n, k; + uLong poly; /* polynomial exclusive-or pattern */ + /* terms of polynomial defining this crc (except x^32): */ + static const Byte p[] = {0,1,2,4,5,7,8,10,11,12,16,22,23,26}; + + /* make exclusive-or pattern from polynomial (0xedb88320L) */ + poly = 0L; + for (n = 0; n < sizeof(p)/sizeof(Byte); n++) + poly |= 1L << (31 - p[n]); + + for (n = 0; n < 256; n++) + { + c = (uLong)n; + for (k = 0; k < 8; k++) + c = c & 1 ? poly ^ (c >> 1) : c >> 1; + crc_table[n] = c; + } + crc_table_empty = 0; +} +#else +/* ======================================================================== + * Table of CRC-32's of all single-byte values (made by make_crc_table) + */ +static const uLong crc_table[256] = { + 0x00000000L, 0x77073096L, 0xee0e612cL, 0x990951baL, 0x076dc419L, + 0x706af48fL, 0xe963a535L, 0x9e6495a3L, 0x0edb8832L, 0x79dcb8a4L, + 0xe0d5e91eL, 0x97d2d988L, 0x09b64c2bL, 0x7eb17cbdL, 0xe7b82d07L, + 0x90bf1d91L, 0x1db71064L, 0x6ab020f2L, 0xf3b97148L, 0x84be41deL, + 0x1adad47dL, 0x6ddde4ebL, 0xf4d4b551L, 0x83d385c7L, 0x136c9856L, + 0x646ba8c0L, 0xfd62f97aL, 0x8a65c9ecL, 0x14015c4fL, 0x63066cd9L, + 0xfa0f3d63L, 0x8d080df5L, 0x3b6e20c8L, 0x4c69105eL, 0xd56041e4L, + 0xa2677172L, 0x3c03e4d1L, 0x4b04d447L, 0xd20d85fdL, 0xa50ab56bL, + 0x35b5a8faL, 0x42b2986cL, 0xdbbbc9d6L, 0xacbcf940L, 0x32d86ce3L, + 0x45df5c75L, 0xdcd60dcfL, 0xabd13d59L, 0x26d930acL, 0x51de003aL, + 0xc8d75180L, 0xbfd06116L, 0x21b4f4b5L, 0x56b3c423L, 0xcfba9599L, + 0xb8bda50fL, 0x2802b89eL, 0x5f058808L, 0xc60cd9b2L, 0xb10be924L, + 0x2f6f7c87L, 0x58684c11L, 0xc1611dabL, 0xb6662d3dL, 0x76dc4190L, + 0x01db7106L, 0x98d220bcL, 0xefd5102aL, 0x71b18589L, 0x06b6b51fL, + 0x9fbfe4a5L, 0xe8b8d433L, 0x7807c9a2L, 0x0f00f934L, 0x9609a88eL, + 0xe10e9818L, 0x7f6a0dbbL, 0x086d3d2dL, 0x91646c97L, 0xe6635c01L, + 0x6b6b51f4L, 0x1c6c6162L, 0x856530d8L, 0xf262004eL, 0x6c0695edL, + 0x1b01a57bL, 0x8208f4c1L, 0xf50fc457L, 0x65b0d9c6L, 0x12b7e950L, + 0x8bbeb8eaL, 0xfcb9887cL, 0x62dd1ddfL, 0x15da2d49L, 0x8cd37cf3L, + 0xfbd44c65L, 0x4db26158L, 0x3ab551ceL, 0xa3bc0074L, 0xd4bb30e2L, + 0x4adfa541L, 0x3dd895d7L, 0xa4d1c46dL, 0xd3d6f4fbL, 0x4369e96aL, + 0x346ed9fcL, 0xad678846L, 0xda60b8d0L, 0x44042d73L, 0x33031de5L, + 0xaa0a4c5fL, 0xdd0d7cc9L, 0x5005713cL, 0x270241aaL, 0xbe0b1010L, + 0xc90c2086L, 0x5768b525L, 0x206f85b3L, 0xb966d409L, 0xce61e49fL, + 0x5edef90eL, 0x29d9c998L, 0xb0d09822L, 0xc7d7a8b4L, 0x59b33d17L, + 0x2eb40d81L, 0xb7bd5c3bL, 0xc0ba6cadL, 0xedb88320L, 0x9abfb3b6L, + 0x03b6e20cL, 0x74b1d29aL, 0xead54739L, 0x9dd277afL, 0x04db2615L, + 0x73dc1683L, 0xe3630b12L, 0x94643b84L, 0x0d6d6a3eL, 0x7a6a5aa8L, + 0xe40ecf0bL, 0x9309ff9dL, 0x0a00ae27L, 0x7d079eb1L, 0xf00f9344L, + 0x8708a3d2L, 0x1e01f268L, 0x6906c2feL, 0xf762575dL, 0x806567cbL, + 0x196c3671L, 0x6e6b06e7L, 0xfed41b76L, 0x89d32be0L, 0x10da7a5aL, + 0x67dd4accL, 0xf9b9df6fL, 0x8ebeeff9L, 0x17b7be43L, 0x60b08ed5L, + 0xd6d6a3e8L, 0xa1d1937eL, 0x38d8c2c4L, 0x4fdff252L, 0xd1bb67f1L, + 0xa6bc5767L, 0x3fb506ddL, 0x48b2364bL, 0xd80d2bdaL, 0xaf0a1b4cL, + 0x36034af6L, 0x41047a60L, 0xdf60efc3L, 0xa867df55L, 0x316e8eefL, + 0x4669be79L, 0xcb61b38cL, 0xbc66831aL, 0x256fd2a0L, 0x5268e236L, + 0xcc0c7795L, 0xbb0b4703L, 0x220216b9L, 0x5505262fL, 0xc5ba3bbeL, + 0xb2bd0b28L, 0x2bb45a92L, 0x5cb36a04L, 0xc2d7ffa7L, 0xb5d0cf31L, + 0x2cd99e8bL, 0x5bdeae1dL, 0x9b64c2b0L, 0xec63f226L, 0x756aa39cL, + 0x026d930aL, 0x9c0906a9L, 0xeb0e363fL, 0x72076785L, 0x05005713L, + 0x95bf4a82L, 0xe2b87a14L, 0x7bb12baeL, 0x0cb61b38L, 0x92d28e9bL, + 0xe5d5be0dL, 0x7cdcefb7L, 0x0bdbdf21L, 0x86d3d2d4L, 0xf1d4e242L, + 0x68ddb3f8L, 0x1fda836eL, 0x81be16cdL, 0xf6b9265bL, 0x6fb077e1L, + 0x18b74777L, 0x88085ae6L, 0xff0f6a70L, 0x66063bcaL, 0x11010b5cL, + 0x8f659effL, 0xf862ae69L, 0x616bffd3L, 0x166ccf45L, 0xa00ae278L, + 0xd70dd2eeL, 0x4e048354L, 0x3903b3c2L, 0xa7672661L, 0xd06016f7L, + 0x4969474dL, 0x3e6e77dbL, 0xaed16a4aL, 0xd9d65adcL, 0x40df0b66L, + 0x37d83bf0L, 0xa9bcae53L, 0xdebb9ec5L, 0x47b2cf7fL, 0x30b5ffe9L, + 0xbdbdf21cL, 0xcabac28aL, 0x53b39330L, 0x24b4a3a6L, 0xbad03605L, + 0xcdd70693L, 0x54de5729L, 0x23d967bfL, 0xb3667a2eL, 0xc4614ab8L, + 0x5d681b02L, 0x2a6f2b94L, 0xb40bbe37L, 0xc30c8ea1L, 0x5a05df1bL, + 0x2d02ef8dL +}; +#endif + +/* ========================================================================= + * This function can be used by asm versions of crc32() + */ +const uLong * get_crc_table() +{ +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) make_crc_table(); +#endif + return (const uLong *)crc_table; +} + +/* ========================================================================= */ +#define DO1(buf) crc = crc_table[((int)crc ^ (*buf++)) & 0xff] ^ (crc >> 8); +#define DO2(buf) DO1(buf); DO1(buf); +#define DO4(buf) DO2(buf); DO2(buf); +#define DO8(buf) DO4(buf); DO4(buf); + +/* ========================================================================= */ +uLong crc32(uLong crc, const Byte *buf, uInt len) +{ + if (buf == Z_NULL) return 0L; +#ifdef DYNAMIC_CRC_TABLE + if (crc_table_empty) + make_crc_table(); +#endif + crc = crc ^ 0xffffffffL; + while (len >= 8) + { + DO8(buf); + len -= 8; + } + if (len) do { + DO1(buf); + } while (--len); + return crc ^ 0xffffffffL; +} + +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_blocks_state; +typedef struct inflate_blocks_state inflate_blocks_statef; + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLong *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Byte *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* Table for deflate from PKZIP's appnote.txt. */ +static const uInt border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; + +/* inftrees.h -- header to use inftrees.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +/* Huffman code lookup table entry--this entry is four bytes for machines + that have 16-bit pointers (e.g. PC's in the small or medium model). */ + +typedef struct inflate_huft_s inflate_huft; + +struct inflate_huft_s { + union { + struct { + Byte Exop; /* number of extra bits or operation */ + Byte Bits; /* number of bits in this code or subcode */ + } what; + uInt pad; /* pad structure to a power of 2 (4 bytes for */ + } word; /* 16-bit, 8 bytes for 32-bit int's) */ + uInt base; /* literal, length base, distance base, + or table offset */ +}; + +/* Maximum size of dynamic tree. The maximum found in a long but non- + exhaustive search was 1004 huft structures (850 for length/literals + and 154 for distances, the latter actually the result of an + exhaustive search). The actual maximum is not known, but the + value below is more than safe. */ +#define MANY 1440 + +extern int inflate_trees_bits OF(( + uInt *, /* 19 code lengths */ + uInt *, /* bits tree desired/actual depth */ + inflate_huft * *, /* bits tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_dynamic OF(( + uInt, /* number of literal/length codes */ + uInt, /* number of distance codes */ + uInt *, /* that many (total) code lengths */ + uInt *, /* literal desired/actual bit depth */ + uInt *, /* distance desired/actual bit depth */ + inflate_huft * *, /* literal/length tree result */ + inflate_huft * *, /* distance tree result */ + inflate_huft *, /* space for trees */ + z_streamp)); /* for messages */ + +extern int inflate_trees_fixed OF(( + uInt *, /* literal desired/actual bit depth */ + uInt *, /* distance desired/actual bit depth */ + inflate_huft * *, /* literal/length tree result */ + inflate_huft * *, /* distance tree result */ + z_streamp)); /* for memory allocation */ + + +/* infcodes.h -- header to use infcodes.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +struct inflate_codes_state; +typedef struct inflate_codes_state inflate_codes_statef; + +extern inflate_codes_statef *inflate_codes_new OF(( + uInt, uInt, + inflate_huft *, inflate_huft *, + z_streamp )); + +extern int inflate_codes OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +extern void inflate_codes_free OF(( + inflate_codes_statef *, + z_streamp )); + +/* infutil.h -- types and macros common to blocks and codes + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +#ifndef _INFUTIL_H +#define _INFUTIL_H + +typedef enum { + TYPE, /* get type bits (3, including end bit) */ + LENS, /* get lengths for stored */ + STORED, /* processing stored block */ + TABLE, /* get table lengths */ + BTREE, /* get bit lengths tree for a dynamic block */ + DTREE, /* get length, distance trees for a dynamic block */ + CODES, /* processing fixed or dynamic block */ + DRY, /* output remaining window bytes */ + DONE, /* finished last block, done */ + BAD} /* got a data error--stuck here */ +inflate_block_mode; + +/* inflate blocks semi-private state */ +struct inflate_blocks_state { + + /* mode */ + inflate_block_mode mode; /* current inflate_block mode */ + + /* mode dependent information */ + union { + uInt left; /* if STORED, bytes left to copy */ + struct { + uInt table; /* table lengths (14 bits) */ + uInt index; /* index into blens (or border) */ + uInt *blens; /* bit lengths of codes */ + uInt bb; /* bit length tree depth */ + inflate_huft *tb; /* bit length decoding tree */ + } trees; /* if DTREE, decoding info for trees */ + struct { + inflate_codes_statef + *codes; + } decode; /* if CODES, current state */ + } sub; /* submode */ + uInt last; /* true if this block is the last block */ + + /* mode independent information */ + uInt bitk; /* bits in bit buffer */ + uLong bitb; /* bit buffer */ + inflate_huft *hufts; /* single malloc for tree space */ + Byte *window; /* sliding window */ + Byte *end; /* one byte after sliding window */ + Byte *read; /* window read pointer */ + Byte *write; /* window write pointer */ + check_func checkfn; /* check function */ + uLong check; /* check on output */ + +}; + + +/* defines for inflate input/output */ +/* update pointers and return */ +#define UPDBITS {s->bitb=b;s->bitk=k;} +#define UPDIN {z->avail_in=n;z->total_in+=p-z->next_in;z->next_in=p;} +#define UPDOUT {s->write=q;} +#define UPDATE {UPDBITS UPDIN UPDOUT} +#define LEAVE {UPDATE return inflate_flush(s,z,r);} +/* get bytes and bits */ +#define LOADIN {p=z->next_in;n=z->avail_in;b=s->bitb;k=s->bitk;} +#define NEEDBYTE {if(n)r=Z_OK;else LEAVE} +#define NEXTBYTE (n--,*p++) +#define NEEDBITS(j) {while(k<(j)){NEEDBYTE;b|=((uLong)NEXTBYTE)<>=(j);k-=(j);} +/* output bytes */ +#define WAVAIL (uInt)(qread?s->read-q-1:s->end-q) +#define LOADOUT {q=s->write;m=(uInt)WAVAIL;} +#define WRAP {if(q==s->end&&s->read!=s->window){q=s->window;m=(uInt)WAVAIL;}} +#define FLUSH {UPDOUT r=inflate_flush(s,z,r); LOADOUT} +#define NEEDOUT {if(m==0){WRAP if(m==0){FLUSH WRAP if(m==0) LEAVE}}r=Z_OK;} +#define OUTBYTE(a) {*q++=(Byte)(a);m--;} +/* load static pointers */ +#define LOAD {LOADIN LOADOUT} + +/* masks for lower bits (size given to avoid silly warnings with Visual C++) */ +extern uInt inflate_mask[17]; + +/* copy as much as possible from the sliding window to the output area */ +extern int inflate_flush OF(( + inflate_blocks_statef *, + z_streamp , + int)); + +#endif + + +/* + Notes beyond the 1.93a appnote.txt: + + 1. Distance pointers never point before the beginning of the output + stream. + 2. Distance pointers can point back across blocks, up to 32k away. + 3. There is an implied maximum of 7 bits for the bit length table and + 15 bits for the actual data. + 4. If only one code exists, then it is encoded using one bit. (Zero + would be more efficient, but perhaps a little confusing.) If two + codes exist, they are coded using one bit each (0 and 1). + 5. There is no way of sending zero distance codes--a dummy must be + sent if there are none. (History: a pre 2.0 version of PKZIP would + store blocks with no distance codes, but this was discovered to be + too harsh a criterion.) Valid only for 1.93a. 2.04c does allow + zero distance codes, which is sent as one code of zero bits in + length. + 6. There are up to 286 literal/length codes. Code 256 represents the + end-of-block. Note however that the static length tree defines + 288 codes just to fill out the Huffman codes. Codes 286 and 287 + cannot be used though, since there is no length base or extra bits + defined for them. Similarily, there are up to 30 distance codes. + However, static trees define 32 codes (all 5 bits) to fill out the + Huffman codes, but the last two had better not show up in the data. + 7. Unzip can check dynamic Huffman blocks for complete code sets. + The exception is that a single code would not be complete (see #4). + 8. The five bits following the block type is really the number of + literal codes sent minus 257. + 9. Length codes 8,16,16 are interpreted as 13 length codes of 8 bits + (1+6+6). Therefore, to output three times the length, you output + three codes (1+1+1), whereas to output four times the same length, + you only need two codes (1+3). Hmm. + 10. In the tree reconstruction algorithm, Code = Code + Increment + only if BitLength(i) is not zero. (Pretty obvious.) + 11. Correction: 4 Bits: # of Bit Length codes - 4 (4 - 19) + 12. Note: length code 284 can represent 227-258, but length code 285 + really is 258. The last length deserves its own, short code + since it gets used a lot in very redundant files. The length + 258 is special since 258 - 3 (the min match length) is 255. + 13. The literal/length and distance code bit lengths are read as a + single stream of lengths. It is possible (and advantageous) for + a repeat code (16, 17, or 18) to go across the boundary between + the two sets of lengths. + */ + + +void inflate_blocks_reset(inflate_blocks_statef *s, z_streamp z, uLong *c) +{ + if (c != Z_NULL) + *c = s->check; + if (s->mode == BTREE || s->mode == DTREE) + ZFREE(z, s->sub.trees.blens); + if (s->mode == CODES) + inflate_codes_free(s->sub.decode.codes, z); + s->mode = TYPE; + s->bitk = 0; + s->bitb = 0; + s->read = s->write = s->window; + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(0L, (const Byte *)Z_NULL, 0); + Tracev(("inflate: blocks reset\n")); +} + + +inflate_blocks_statef *inflate_blocks_new(z_streamp z, check_func c, uInt w) +{ + inflate_blocks_statef *s; + + if ((s = (inflate_blocks_statef *)ZALLOC + (z,1,sizeof(struct inflate_blocks_state))) == Z_NULL) + return s; + if ((s->hufts = + (inflate_huft *)ZALLOC(z, sizeof(inflate_huft), MANY)) == Z_NULL) + { + ZFREE(z, s); + return Z_NULL; + } + if ((s->window = (Byte *)ZALLOC(z, 1, w)) == Z_NULL) + { + ZFREE(z, s->hufts); + ZFREE(z, s); + return Z_NULL; + } + s->end = s->window + w; + s->checkfn = c; + s->mode = TYPE; + Tracev(("inflate: blocks allocated\n")); + inflate_blocks_reset(s, z, Z_NULL); + return s; +} + + +int inflate_blocks(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt t; /* temporary storage */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input based on current state */ + while (1) switch (s->mode) + { + case TYPE: + NEEDBITS(3) + t = (uInt)b & 7; + s->last = t & 1; + switch (t >> 1) + { + case 0: /* stored */ + Tracev(("inflate: stored block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + t = k & 7; /* go to byte boundary */ + DUMPBITS(t) + s->mode = LENS; /* get length of stored block */ + break; + case 1: /* fixed */ + Tracev(("inflate: fixed codes block%s\n", + s->last ? " (last)" : "")); + { + uInt bl, bd; + inflate_huft *tl, *td; + + inflate_trees_fixed(&bl, &bd, &tl, &td, z); + s->sub.decode.codes = inflate_codes_new(bl, bd, tl, td, z); + if (s->sub.decode.codes == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + } + DUMPBITS(3) + s->mode = CODES; + break; + case 2: /* dynamic */ + Tracev(("inflate: dynamic codes block%s\n", + s->last ? " (last)" : "")); + DUMPBITS(3) + s->mode = TABLE; + break; + case 3: /* illegal */ + DUMPBITS(3) + s->mode = BAD; + z->msg = (char*)"invalid block type"; + r = Z_DATA_ERROR; + LEAVE + } + break; + case LENS: + NEEDBITS(32) + if ((((~b) >> 16) & 0xffff) != (b & 0xffff)) + { + s->mode = BAD; + z->msg = (char*)"invalid stored block lengths"; + r = Z_DATA_ERROR; + LEAVE + } + s->sub.left = (uInt)b & 0xffff; + b = k = 0; /* dump bits */ + Tracev(("inflate: stored length %u\n", s->sub.left)); + s->mode = s->sub.left ? STORED : (s->last ? DRY : TYPE); + break; + case STORED: + if (n == 0) + LEAVE + NEEDOUT + t = s->sub.left; + if (t > n) t = n; + if (t > m) t = m; + zmemcpy(q, p, t); + p += t; n -= t; + q += t; m -= t; + if ((s->sub.left -= t) != 0) + break; + Tracev(("inflate: stored end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + s->mode = s->last ? DRY : TYPE; + break; + case TABLE: + NEEDBITS(14) + s->sub.trees.table = t = (uInt)b & 0x3fff; +#ifndef PKZIP_BUG_WORKAROUND + if ((t & 0x1f) > 29 || ((t >> 5) & 0x1f) > 29) + { + s->mode = BAD; + z->msg = (char*)"too many length or distance symbols"; + r = Z_DATA_ERROR; + LEAVE + } +#endif + t = 258 + (t & 0x1f) + ((t >> 5) & 0x1f); + if ((s->sub.trees.blens = (uInt*)ZALLOC(z, t, sizeof(uInt))) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + DUMPBITS(14) + s->sub.trees.index = 0; + Tracev(("inflate: table sizes ok\n")); + s->mode = BTREE; + case BTREE: + while (s->sub.trees.index < 4 + (s->sub.trees.table >> 10)) + { + NEEDBITS(3) + s->sub.trees.blens[border[s->sub.trees.index++]] = (uInt)b & 7; + DUMPBITS(3) + } + while (s->sub.trees.index < 19) + s->sub.trees.blens[border[s->sub.trees.index++]] = 0; + s->sub.trees.bb = 7; + t = inflate_trees_bits(s->sub.trees.blens, &s->sub.trees.bb, + &s->sub.trees.tb, s->hufts, z); + if (t != Z_OK) + { + ZFREE(z, s->sub.trees.blens); + r = t; + if (r == Z_DATA_ERROR) + s->mode = BAD; + LEAVE + } + s->sub.trees.index = 0; + Tracev(("inflate: bits tree ok\n")); + s->mode = DTREE; + case DTREE: + while (t = s->sub.trees.table, + s->sub.trees.index < 258 + (t & 0x1f) + ((t >> 5) & 0x1f)) + { + inflate_huft *h; + uInt i, j, c; + + t = s->sub.trees.bb; + NEEDBITS(t) + h = s->sub.trees.tb + ((uInt)b & inflate_mask[t]); + t = h->bits; + c = h->base; + if (c < 16) + { + DUMPBITS(t) + s->sub.trees.blens[s->sub.trees.index++] = c; + } + else /* c == 16..18 */ + { + i = c == 18 ? 7 : c - 14; + j = c == 18 ? 11 : 3; + NEEDBITS(t + i) + DUMPBITS(t) + j += (uInt)b & inflate_mask[i]; + DUMPBITS(i) + i = s->sub.trees.index; + t = s->sub.trees.table; + if (i + j > 258 + (t & 0x1f) + ((t >> 5) & 0x1f) || + (c == 16 && i < 1)) + { + ZFREE(z, s->sub.trees.blens); + s->mode = BAD; + z->msg = (char*)"invalid bit length repeat"; + r = Z_DATA_ERROR; + LEAVE + } + c = c == 16 ? s->sub.trees.blens[i - 1] : 0; + do { + s->sub.trees.blens[i++] = c; + } while (--j); + s->sub.trees.index = i; + } + } + s->sub.trees.tb = Z_NULL; + { + uInt bl, bd; + inflate_huft *tl, *td; + inflate_codes_statef *c; + + bl = 9; /* must be <= 9 for lookahead assumptions */ + bd = 6; /* must be <= 9 for lookahead assumptions */ + t = s->sub.trees.table; + t = inflate_trees_dynamic(257 + (t & 0x1f), 1 + ((t >> 5) & 0x1f), + s->sub.trees.blens, &bl, &bd, &tl, &td, + s->hufts, z); + ZFREE(z, s->sub.trees.blens); + if (t != Z_OK) + { + if (t == (uInt)Z_DATA_ERROR) + s->mode = BAD; + r = t; + LEAVE + } + Tracev(("inflate: trees ok\n")); + if ((c = inflate_codes_new(bl, bd, tl, td, z)) == Z_NULL) + { + r = Z_MEM_ERROR; + LEAVE + } + s->sub.decode.codes = c; + } + s->mode = CODES; + case CODES: + UPDATE + if ((r = inflate_codes(s, z, r)) != Z_STREAM_END) + return inflate_flush(s, z, r); + r = Z_OK; + inflate_codes_free(s->sub.decode.codes, z); + LOAD + Tracev(("inflate: codes end, %lu total out\n", + z->total_out + (q >= s->read ? q - s->read : + (s->end - s->read) + (q - s->window)))); + if (!s->last) + { + s->mode = TYPE; + break; + } + s->mode = DRY; + case DRY: + FLUSH + if (s->read != s->write) + LEAVE + s->mode = DONE; + case DONE: + r = Z_STREAM_END; + LEAVE + case BAD: + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +} + + +int inflate_blocks_free(inflate_blocks_statef *s, z_streamp z) +{ + inflate_blocks_reset(s, z, Z_NULL); + ZFREE(z, s->window); + ZFREE(z, s->hufts); + ZFREE(z, s); + Tracev(("inflate: blocks freed\n")); + return Z_OK; +} + + +void inflate_set_dictionary(inflate_blocks_statef *s, const Byte *d, uInt n) +{ + zmemcpy(s->window, d, n); + s->read = s->write = s->window + n; +} + + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. + * IN assertion: s != Z_NULL + */ +int inflate_blocks_sync_point(inflate_blocks_statef *s) +{ + return s->mode == LENS; +} + +/* And'ing with mask[n] masks the lower n bits */ +uInt inflate_mask[17] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +/* copy as much as possible from the sliding window to the output area */ +int inflate_flush(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt n; + Byte *p; + Byte *q; + + /* static copies of source and destination pointers */ + p = z->next_out; + q = s->read; + + /* compute number of bytes to copy as as end of window */ + n = (uInt)((q <= s->write ? s->write : s->end) - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy as as end of window */ + zmemcpy(p, q, n); + p += n; + q += n; + + /* see if more to copy at beginning of window */ + if (q == s->end) + { + /* wrap pointers */ + q = s->window; + if (s->write == s->end) + s->write = s->window; + + /* compute bytes to copy */ + n = (uInt)(s->write - q); + if (n > z->avail_out) n = z->avail_out; + if (n && r == Z_BUF_ERROR) r = Z_OK; + + /* update counters */ + z->avail_out -= n; + z->total_out += n; + + /* update check information */ + if (s->checkfn != Z_NULL) + z->adler = s->check = (*s->checkfn)(s->check, q, n); + + /* copy */ + zmemcpy(p, q, n); + p += n; + q += n; + } + + /* update pointers */ + z->next_out = p; + s->read = q; + + /* done */ + return r; +} + +/* inftrees.c -- generate Huffman trees for efficient decoding + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +const char inflate_copyright[] = + " inflate 1.1.3 Copyright 1995-1998 Mark Adler "; +/* + If you use the zlib library in a product, an acknowledgment is welcome + in the documentation of your product. If for some reason you cannot + include such an acknowledgment, I would appreciate that you keep this + copyright string in the executable of your product. + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + + +static int huft_build OF(( + uInt *, /* code lengths in bits */ + uInt, /* number of codes */ + uInt, /* number of "simple" codes */ + const uInt *, /* list of base values for non-simple codes */ + const uInt *, /* list of extra bits for non-simple codes */ + inflate_huft **, /* result: starting table */ + uInt *, /* maximum lookup bits (returns actual) */ + inflate_huft *, /* space for trees */ + uInt *, /* hufts used in space */ + uInt * )); /* space for values */ + +/* Tables for deflate from PKZIP's appnote.txt. */ +static const uInt cplens[31] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* see note #13 above about 258 */ +static const uInt cplext[31] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 112, 112}; /* 112==invalid */ +static const uInt cpdist[30] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +static const uInt cpdext[30] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + +/* + Huffman code decoding is performed using a multi-level table lookup. + The fastest way to decode is to simply build a lookup table whose + size is determined by the longest code. However, the time it takes + to build this table can also be a factor if the data being decoded + is not very long. The most common codes are necessarily the + shortest codes, so those codes dominate the decoding time, and hence + the speed. The idea is you can have a shorter table that decodes the + shorter, more probable codes, and then point to subsidiary tables for + the longer codes. The time it costs to decode the longer codes is + then traded against the time it takes to make longer tables. + + This results of this trade are in the variables lbits and dbits + below. lbits is the number of bits the first level table for literal/ + length codes can decode in one step, and dbits is the same thing for + the distance codes. Subsequent tables are also less than or equal to + those sizes. These values may be adjusted either when all of the + codes are shorter than that, in which case the longest code length in + bits is used, or when the shortest code is *longer* than the requested + table size, in which case the length of the shortest code in bits is + used. + + There are two different values for the two tables, since they code a + different number of possibilities each. The literal/length table + codes 286 possible values, or in a flat code, a little over eight + bits. The distance table codes 30 possible values, or a little less + than five bits, flat. The optimum values for speed end up being + about one bit more than those, so lbits is 8+1 and dbits is 5+1. + The optimum values may differ though from machine to machine, and + possibly even between compilers. Your mileage may vary. + */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be uLong. */ +#define BMAX 15 /* maximum bit length of any code */ + +static int huft_build(uInt *b, uInt n, uInt s, const uInt *d, const uInt *e, inflate_huft ** t, uInt *m, inflate_huft *hp, uInt *hn, uInt *v) +//uInt *b; /* code lengths in bits (all assumed <= BMAX) */ +//uInt n; /* number of codes (assumed <= 288) */ +//uInt s; /* number of simple-valued codes (0..s-1) */ +//const uInt *d; /* list of base values for non-simple codes */ +//const uInt *e; /* list of extra bits for non-simple codes */ +//inflate_huft ** t; /* result: starting table */ +//uInt *m; /* maximum lookup bits, returns actual */ +//inflate_huft *hp; /* space for trees */ +//uInt *hn; /* hufts used in space */ +//uInt *v; /* working area: values in order of bit length */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return Z_OK on success, Z_BUF_ERROR + if the given code set is incomplete (the tables are still built in this + case), Z_DATA_ERROR if the input is invalid (an over-subscribed set of + lengths), or Z_MEM_ERROR if not enough memory. */ +{ + + uInt a; /* counter for codes of length k */ + uInt c[BMAX+1]; /* bit length count table */ + uInt f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register uInt i; /* counter, current code */ + register uInt j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + uInt mask; /* (1 << w) - 1, to avoid cc -O bug on HP */ + register uInt *p; /* pointer into c[], b[], or v[] */ + inflate_huft *q; /* points to current table */ + struct inflate_huft_s r; /* table entry for structure assignment */ + inflate_huft *u[BMAX]; /* table stack */ + register int w; /* bits before this table == (l * h) */ + uInt x[BMAX+1]; /* bit offsets, then code stack */ + uInt *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + uInt z; /* number of entries in current table */ + + + /* Generate counts for each bit length */ + p = c; +#define C0 *p++ = 0; +#define C2 C0 C0 C0 C0 +#define C4 C2 C2 C2 C2 + C4 /* clear c[]--assume BMAX+1 is 16 */ + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (inflate_huft *)Z_NULL; + *m = 0; + return Z_OK; + } + + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((uInt)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((uInt)l > i) + l = i; + *m = l; + + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return Z_DATA_ERROR; + if ((y -= c[i]) < 0) + return Z_DATA_ERROR; + c[i] += y; + + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + n = x[g]; /* set n to length of v */ + + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (inflate_huft *)Z_NULL; /* just to keep compilers happy */ + q = (inflate_huft *)Z_NULL; /* ditto */ + z = 0; /* ditto */ + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { + a = c[k]; + while (a--) + { + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = g - w; + z = z > (uInt)l ? l : z; /* table size upper limit */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + if (j < z) + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } + z = 1 << j; /* table entries for j-bit table */ + + /* allocate new table */ + if (*hn + z > MANY) /* (note: doesn't matter for fixed) */ + return Z_MEM_ERROR; /* not enough memory */ + u[h] = q = hp + *hn; + *hn += z; + + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.bits = (Byte)l; /* bits to dump before this table */ + r.exop = (Byte)j; /* bits in this table */ + j = i >> (w - l); + r.base = (uInt)(q - u[h-1] - j); /* offset to this table */ + u[h-1][j] = r; /* connect to last table */ + } + else + *t = q; /* first table is returned result */ + } + + /* set up table entry in r */ + r.bits = (Byte)(k - w); + if (p >= v + n) + r.exop = 128 + 64; /* out of values--invalid code */ + else if (*p < s) + { + r.exop = (Byte)(*p < 256 ? 0 : 32 + 64); /* 256 is end-of-block */ + r.base = *p++; /* simple code is just the value */ + } + else + { + r.exop = (Byte)(e[*p - s] + 16 + 64);/* non-simple--look up in lists */ + r.base = d[*p++ - s]; + } + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + mask = (1 << w) - 1; /* needed on HP, cc -O bug */ + while ((i & mask) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + mask = (1 << w) - 1; + } + } + } + + + /* Return Z_BUF_ERROR if we were given an incomplete table */ + return y != 0 && g != 1 ? Z_BUF_ERROR : Z_OK; +} + + +int inflate_trees_bits(uInt *c, uInt *bb, inflate_huft * *tb, inflate_huft *hp, z_streamp z) +//uInt *c; /* 19 code lengths */ +//uInt *bb; /* bits tree desired/actual depth */ +//inflate_huft * *tb; /* bits tree result */ +//inflate_huft *hp; /* space for trees */ +//z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uInt *v; /* work area for huft_build */ + + if ((v = (uInt*)ZALLOC(z, 19, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + r = huft_build(c, 19, 19, (uInt*)Z_NULL, (uInt*)Z_NULL, + tb, bb, hp, &hn, v); + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed dynamic bit lengths tree"; + else if (r == Z_BUF_ERROR || *bb == 0) + { + z->msg = (char*)"incomplete dynamic bit lengths tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +} + + +int inflate_trees_dynamic(uInt nl, uInt nd, uInt *c, uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, inflate_huft *hp, z_streamp z) +//uInt nl; /* number of literal/length codes */ +//uInt nd; /* number of distance codes */ +//uInt *c; /* that many (total) code lengths */ +//uInt *bl; /* literal desired/actual bit depth */ +//uInt *bd; /* distance desired/actual bit depth */ +//inflate_huft * *tl; /* literal/length tree result */ +//inflate_huft * *td; /* distance tree result */ +//inflate_huft *hp; /* space for trees */ +//z_streamp z; /* for messages */ +{ + int r; + uInt hn = 0; /* hufts used in space */ + uInt *v; /* work area for huft_build */ + + /* allocate work area */ + if ((v = (uInt*)ZALLOC(z, 288, sizeof(uInt))) == Z_NULL) + return Z_MEM_ERROR; + + /* build literal/length tree */ + r = huft_build(c, nl, 257, cplens, cplext, tl, bl, hp, &hn, v); + if (r != Z_OK || *bl == 0) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed literal/length tree"; + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"incomplete literal/length tree"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; + } + + /* build distance tree */ + r = huft_build(c + nl, nd, 0, cpdist, cpdext, td, bd, hp, &hn, v); + if (r != Z_OK || (*bd == 0 && nl > 257)) + { + if (r == Z_DATA_ERROR) + z->msg = (char*)"oversubscribed distance tree"; + else if (r == Z_BUF_ERROR) { +#ifdef PKZIP_BUG_WORKAROUND + r = Z_OK; + } +#else + z->msg = (char*)"incomplete distance tree"; + r = Z_DATA_ERROR; + } + else if (r != Z_MEM_ERROR) + { + z->msg = (char*)"empty distance tree with lengths"; + r = Z_DATA_ERROR; + } + ZFREE(z, v); + return r; +#endif + } + + /* done */ + ZFREE(z, v); + return Z_OK; +} + +/* inffixed.h -- table for decoding fixed codes + * Generated automatically by the maketree.c program + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +static uInt fixed_bl = 9; +static uInt fixed_bd = 5; +static inflate_huft fixed_tl[] = { + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},192}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},160}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},224}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},144}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},208}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},176}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},240}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},200}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},168}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},232}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},152}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},216}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},184}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},248}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},196}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},164}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},228}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},148}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},212}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},180}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},244}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},204}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},172}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},236}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},156}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},220}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},188}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},252}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},194}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},162}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},226}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},146}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},210}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},178}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},242}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},202}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},170}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},234}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},154}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},218}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},186}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},250}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},198}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},166}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},230}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},150}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},214}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},182}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},246}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},206}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},174}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},238}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},158}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},222}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},190}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},254}, + {{{96,7}},256}, {{{0,8}},80}, {{{0,8}},16}, {{{84,8}},115}, + {{{82,7}},31}, {{{0,8}},112}, {{{0,8}},48}, {{{0,9}},193}, + {{{80,7}},10}, {{{0,8}},96}, {{{0,8}},32}, {{{0,9}},161}, + {{{0,8}},0}, {{{0,8}},128}, {{{0,8}},64}, {{{0,9}},225}, + {{{80,7}},6}, {{{0,8}},88}, {{{0,8}},24}, {{{0,9}},145}, + {{{83,7}},59}, {{{0,8}},120}, {{{0,8}},56}, {{{0,9}},209}, + {{{81,7}},17}, {{{0,8}},104}, {{{0,8}},40}, {{{0,9}},177}, + {{{0,8}},8}, {{{0,8}},136}, {{{0,8}},72}, {{{0,9}},241}, + {{{80,7}},4}, {{{0,8}},84}, {{{0,8}},20}, {{{85,8}},227}, + {{{83,7}},43}, {{{0,8}},116}, {{{0,8}},52}, {{{0,9}},201}, + {{{81,7}},13}, {{{0,8}},100}, {{{0,8}},36}, {{{0,9}},169}, + {{{0,8}},4}, {{{0,8}},132}, {{{0,8}},68}, {{{0,9}},233}, + {{{80,7}},8}, {{{0,8}},92}, {{{0,8}},28}, {{{0,9}},153}, + {{{84,7}},83}, {{{0,8}},124}, {{{0,8}},60}, {{{0,9}},217}, + {{{82,7}},23}, {{{0,8}},108}, {{{0,8}},44}, {{{0,9}},185}, + {{{0,8}},12}, {{{0,8}},140}, {{{0,8}},76}, {{{0,9}},249}, + {{{80,7}},3}, {{{0,8}},82}, {{{0,8}},18}, {{{85,8}},163}, + {{{83,7}},35}, {{{0,8}},114}, {{{0,8}},50}, {{{0,9}},197}, + {{{81,7}},11}, {{{0,8}},98}, {{{0,8}},34}, {{{0,9}},165}, + {{{0,8}},2}, {{{0,8}},130}, {{{0,8}},66}, {{{0,9}},229}, + {{{80,7}},7}, {{{0,8}},90}, {{{0,8}},26}, {{{0,9}},149}, + {{{84,7}},67}, {{{0,8}},122}, {{{0,8}},58}, {{{0,9}},213}, + {{{82,7}},19}, {{{0,8}},106}, {{{0,8}},42}, {{{0,9}},181}, + {{{0,8}},10}, {{{0,8}},138}, {{{0,8}},74}, {{{0,9}},245}, + {{{80,7}},5}, {{{0,8}},86}, {{{0,8}},22}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},118}, {{{0,8}},54}, {{{0,9}},205}, + {{{81,7}},15}, {{{0,8}},102}, {{{0,8}},38}, {{{0,9}},173}, + {{{0,8}},6}, {{{0,8}},134}, {{{0,8}},70}, {{{0,9}},237}, + {{{80,7}},9}, {{{0,8}},94}, {{{0,8}},30}, {{{0,9}},157}, + {{{84,7}},99}, {{{0,8}},126}, {{{0,8}},62}, {{{0,9}},221}, + {{{82,7}},27}, {{{0,8}},110}, {{{0,8}},46}, {{{0,9}},189}, + {{{0,8}},14}, {{{0,8}},142}, {{{0,8}},78}, {{{0,9}},253}, + {{{96,7}},256}, {{{0,8}},81}, {{{0,8}},17}, {{{85,8}},131}, + {{{82,7}},31}, {{{0,8}},113}, {{{0,8}},49}, {{{0,9}},195}, + {{{80,7}},10}, {{{0,8}},97}, {{{0,8}},33}, {{{0,9}},163}, + {{{0,8}},1}, {{{0,8}},129}, {{{0,8}},65}, {{{0,9}},227}, + {{{80,7}},6}, {{{0,8}},89}, {{{0,8}},25}, {{{0,9}},147}, + {{{83,7}},59}, {{{0,8}},121}, {{{0,8}},57}, {{{0,9}},211}, + {{{81,7}},17}, {{{0,8}},105}, {{{0,8}},41}, {{{0,9}},179}, + {{{0,8}},9}, {{{0,8}},137}, {{{0,8}},73}, {{{0,9}},243}, + {{{80,7}},4}, {{{0,8}},85}, {{{0,8}},21}, {{{80,8}},258}, + {{{83,7}},43}, {{{0,8}},117}, {{{0,8}},53}, {{{0,9}},203}, + {{{81,7}},13}, {{{0,8}},101}, {{{0,8}},37}, {{{0,9}},171}, + {{{0,8}},5}, {{{0,8}},133}, {{{0,8}},69}, {{{0,9}},235}, + {{{80,7}},8}, {{{0,8}},93}, {{{0,8}},29}, {{{0,9}},155}, + {{{84,7}},83}, {{{0,8}},125}, {{{0,8}},61}, {{{0,9}},219}, + {{{82,7}},23}, {{{0,8}},109}, {{{0,8}},45}, {{{0,9}},187}, + {{{0,8}},13}, {{{0,8}},141}, {{{0,8}},77}, {{{0,9}},251}, + {{{80,7}},3}, {{{0,8}},83}, {{{0,8}},19}, {{{85,8}},195}, + {{{83,7}},35}, {{{0,8}},115}, {{{0,8}},51}, {{{0,9}},199}, + {{{81,7}},11}, {{{0,8}},99}, {{{0,8}},35}, {{{0,9}},167}, + {{{0,8}},3}, {{{0,8}},131}, {{{0,8}},67}, {{{0,9}},231}, + {{{80,7}},7}, {{{0,8}},91}, {{{0,8}},27}, {{{0,9}},151}, + {{{84,7}},67}, {{{0,8}},123}, {{{0,8}},59}, {{{0,9}},215}, + {{{82,7}},19}, {{{0,8}},107}, {{{0,8}},43}, {{{0,9}},183}, + {{{0,8}},11}, {{{0,8}},139}, {{{0,8}},75}, {{{0,9}},247}, + {{{80,7}},5}, {{{0,8}},87}, {{{0,8}},23}, {{{192,8}},0}, + {{{83,7}},51}, {{{0,8}},119}, {{{0,8}},55}, {{{0,9}},207}, + {{{81,7}},15}, {{{0,8}},103}, {{{0,8}},39}, {{{0,9}},175}, + {{{0,8}},7}, {{{0,8}},135}, {{{0,8}},71}, {{{0,9}},239}, + {{{80,7}},9}, {{{0,8}},95}, {{{0,8}},31}, {{{0,9}},159}, + {{{84,7}},99}, {{{0,8}},127}, {{{0,8}},63}, {{{0,9}},223}, + {{{82,7}},27}, {{{0,8}},111}, {{{0,8}},47}, {{{0,9}},191}, + {{{0,8}},15}, {{{0,8}},143}, {{{0,8}},79}, {{{0,9}},255} + }; +static inflate_huft fixed_td[] = { + {{{80,5}},1}, {{{87,5}},257}, {{{83,5}},17}, {{{91,5}},4097}, + {{{81,5}},5}, {{{89,5}},1025}, {{{85,5}},65}, {{{93,5}},16385}, + {{{80,5}},3}, {{{88,5}},513}, {{{84,5}},33}, {{{92,5}},8193}, + {{{82,5}},9}, {{{90,5}},2049}, {{{86,5}},129}, {{{192,5}},24577}, + {{{80,5}},2}, {{{87,5}},385}, {{{83,5}},25}, {{{91,5}},6145}, + {{{81,5}},7}, {{{89,5}},1537}, {{{85,5}},97}, {{{93,5}},24577}, + {{{80,5}},4}, {{{88,5}},769}, {{{84,5}},49}, {{{92,5}},12289}, + {{{82,5}},13}, {{{90,5}},3073}, {{{86,5}},193}, {{{192,5}},24577} + }; + +int inflate_trees_fixed(uInt *bl, uInt *bd, inflate_huft * *tl, inflate_huft * *td, z_streamp z) +//uInt *bl; /* literal desired/actual bit depth */ +//uInt *bd; /* distance desired/actual bit depth */ +//inflate_huft * *tl; /* literal/length tree result */ +//inflate_huft * *td; /* distance tree result */ +//z_streamp z; /* for memory allocation */ +{ + *bl = fixed_bl; + *bd = fixed_bd; + *tl = fixed_tl; + *td = fixed_td; + return Z_OK; +} + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +/* macros for bit input with no checking and for returning unused bytes */ +#define GRABBITS(j) {while(k<(j)){b|=((uLong)NEXTBYTE)<avail_in-n;c=(k>>3)>3:c;n+=c;p-=c;k-=c<<3;} + +/* Called with number of bytes left to write in window at least 258 + (the maximum string length) and number of input bytes available + at least ten. The ten bytes are six bytes for the longest length/ + distance pair plus four bytes for overloading the bit buffer. */ + +int inflate_fast(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, inflate_blocks_statef *s, z_streamp z) +{ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + uInt ml; /* mask for literal/length tree */ + uInt md; /* mask for distance tree */ + uInt c; /* bytes to copy */ + uInt d; /* distance back to copy from */ + Byte *r; /* copy source pointer */ + + /* load input, output, bit values */ + LOAD + + /* initialize masks */ + ml = inflate_mask[bl]; + md = inflate_mask[bd]; + + /* do until not enough input or output space for fast loop */ + do { /* assume called with m >= 258 && n >= 10 */ + /* get literal/length code */ + GRABBITS(20) /* max bits for literal/length code */ + if ((e = (t = tl + ((uInt)b & ml))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + continue; + } + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits for length */ + e &= 15; + c = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv(("inflate: * length %u\n", c)); + + /* decode distance base of block to copy */ + GRABBITS(15); /* max bits for distance code */ + e = (t = td + ((uInt)b & md))->exop; + do { + DUMPBITS(t->bits) + if (e & 16) + { + /* get extra bits to add to distance base */ + e &= 15; + GRABBITS(e) /* get extra bits (up to 13) */ + d = t->base + ((uInt)b & inflate_mask[e]); + DUMPBITS(e) + Tracevv(("inflate: * distance %u\n", d)); + + /* do the copy */ + m -= c; + if ((uInt)(q - s->window) >= d) /* offset before dest */ + { /* just copy */ + r = q - d; + *q++ = *r++; c--; /* minimum count is three, */ + *q++ = *r++; c--; /* so unroll loop a little */ + } + else /* else offset after destination */ + { + e = d - (uInt)(q - s->window); /* bytes from offset to end */ + r = s->end - e; /* pointer to offset */ + if (c > e) /* if source crosses, */ + { + c -= e; /* copy to end of window */ + do { + *q++ = *r++; + } while (--e); + r = s->window; /* copy rest from start of window */ + } + } + do { /* copy all or what's left */ + *q++ = *r++; + } while (--c); + break; + } + else if ((e & 64) == 0) + { + t += t->base; + e = (t += ((uInt)b & inflate_mask[e]))->exop; + } + else + { + z->msg = (char*)"invalid distance code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + break; + } + if ((e & 64) == 0) + { + t += t->base; + if ((e = (t += ((uInt)b & inflate_mask[e]))->exop) == 0) + { + DUMPBITS(t->bits) + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: * literal '%c'\n" : + "inflate: * literal 0x%02x\n", t->base)); + *q++ = (Byte)t->base; + m--; + break; + } + } + else if (e & 32) + { + Tracevv(("inflate: * end of block\n")); + UNGRAB + UPDATE + return Z_STREAM_END; + } + else + { + z->msg = (char*)"invalid literal/length code"; + UNGRAB + UPDATE + return Z_DATA_ERROR; + } + } while (1); + } while (m >= 258 && n >= 10); + + /* not enough input or output--restore pointers and return */ + UNGRAB + UPDATE + return Z_OK; +} + +/* infcodes.c -- process literals and length/distance pairs + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* simplify the use of the inflate_huft type with some defines */ +#define exop word.what.Exop +#define bits word.what.Bits + +typedef enum { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + START, /* x: set up for LEN */ + LEN, /* i: get length/literal/eob next */ + LENEXT, /* i: getting length extra (have base) */ + DIST, /* i: get distance next */ + DISTEXT, /* i: getting distance extra */ + COPY, /* o: copying bytes in window, waiting for space */ + LIT, /* o: got literal, waiting for output space */ + WASH, /* o: got eob, possibly still output waiting */ + END, /* x: got eob and all data flushed */ + BADCODE} /* x: got error */ +inflate_codes_mode; + +/* inflate codes private state */ +struct inflate_codes_state { + + /* mode */ + inflate_codes_mode mode; /* current inflate_codes mode */ + + /* mode dependent information */ + uInt len; + union { + struct { + inflate_huft *tree; /* pointer into tree */ + uInt need; /* bits needed */ + } code; /* if LEN or DIST, where in tree */ + uInt lit; /* if LIT, literal */ + struct { + uInt get; /* bits to get for extra */ + uInt dist; /* distance back to copy from */ + } copy; /* if EXT or COPY, where and how much */ + } sub; /* submode */ + + /* mode independent information */ + Byte lbits; /* ltree bits decoded per branch */ + Byte dbits; /* dtree bits decoder per branch */ + inflate_huft *ltree; /* literal/length/eob tree */ + inflate_huft *dtree; /* distance tree */ + +}; + + +inflate_codes_statef *inflate_codes_new(uInt bl, uInt bd, inflate_huft *tl, inflate_huft *td, z_streamp z) +{ + inflate_codes_statef *c; + + if ((c = (inflate_codes_statef *) + ZALLOC(z,1,sizeof(struct inflate_codes_state))) != Z_NULL) + { + c->mode = START; + c->lbits = (Byte)bl; + c->dbits = (Byte)bd; + c->ltree = tl; + c->dtree = td; + Tracev(("inflate: codes new\n")); + } + return c; +} + + +int inflate_codes(inflate_blocks_statef *s, z_streamp z, int r) +{ + uInt j; /* temporary storage */ + inflate_huft *t; /* temporary pointer */ + uInt e; /* extra bits or operation */ + uLong b; /* bit buffer */ + uInt k; /* bits in bit buffer */ + Byte *p; /* input data pointer */ + uInt n; /* bytes available there */ + Byte *q; /* output window write pointer */ + uInt m; /* bytes to end of window or read pointer */ + Byte *f; /* pointer to copy strings from */ + inflate_codes_statef *c = s->sub.decode.codes; /* codes state */ + + /* copy input/output information to locals (UPDATE macro restores) */ + LOAD + + /* process input and output based on current state */ + while (1) switch (c->mode) + { /* waiting for "i:"=input, "o:"=output, "x:"=nothing */ + case START: /* x: set up for LEN */ +#ifndef SLOW + if (m >= 258 && n >= 10) + { + UPDATE + r = inflate_fast(c->lbits, c->dbits, c->ltree, c->dtree, s, z); + LOAD + if (r != Z_OK) + { + c->mode = r == Z_STREAM_END ? WASH : BADCODE; + break; + } + } +#endif /* !SLOW */ + c->sub.code.need = c->lbits; + c->sub.code.tree = c->ltree; + c->mode = LEN; + case LEN: /* i: get length/literal/eob next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e == 0) /* literal */ + { + c->sub.lit = t->base; + Tracevv((t->base >= 0x20 && t->base < 0x7f ? + "inflate: literal '%c'\n" : + "inflate: literal 0x%02x\n", t->base)); + c->mode = LIT; + break; + } + if (e & 16) /* length */ + { + c->sub.copy.get = e & 15; + c->len = t->base; + c->mode = LENEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + if (e & 32) /* end of block */ + { + Tracevv(("inflate: end of block\n")); + c->mode = WASH; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid literal/length code"; + r = Z_DATA_ERROR; + LEAVE + case LENEXT: /* i: getting length extra (have base) */ + j = c->sub.copy.get; + NEEDBITS(j) + c->len += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + c->sub.code.need = c->dbits; + c->sub.code.tree = c->dtree; + Tracevv(("inflate: length %u\n", c->len)); + c->mode = DIST; + case DIST: /* i: get distance next */ + j = c->sub.code.need; + NEEDBITS(j) + t = c->sub.code.tree + ((uInt)b & inflate_mask[j]); + DUMPBITS(t->bits) + e = (uInt)(t->exop); + if (e & 16) /* distance */ + { + c->sub.copy.get = e & 15; + c->sub.copy.dist = t->base; + c->mode = DISTEXT; + break; + } + if ((e & 64) == 0) /* next table */ + { + c->sub.code.need = e; + c->sub.code.tree = t + t->base; + break; + } + c->mode = BADCODE; /* invalid code */ + z->msg = (char*)"invalid distance code"; + r = Z_DATA_ERROR; + LEAVE + case DISTEXT: /* i: getting distance extra */ + j = c->sub.copy.get; + NEEDBITS(j) + c->sub.copy.dist += (uInt)b & inflate_mask[j]; + DUMPBITS(j) + Tracevv(("inflate: distance %u\n", c->sub.copy.dist)); + c->mode = COPY; + case COPY: /* o: copying bytes in window, waiting for space */ +#ifndef __TURBOC__ /* Turbo C bug for following expression */ + f = (uInt)(q - s->window) < c->sub.copy.dist ? + s->end - (c->sub.copy.dist - (q - s->window)) : + q - c->sub.copy.dist; +#else + f = q - c->sub.copy.dist; + if ((uInt)(q - s->window) < c->sub.copy.dist) + f = s->end - (c->sub.copy.dist - (uInt)(q - s->window)); +#endif + while (c->len) + { + NEEDOUT + OUTBYTE(*f++) + if (f == s->end) + f = s->window; + c->len--; + } + c->mode = START; + break; + case LIT: /* o: got literal, waiting for output space */ + NEEDOUT + OUTBYTE(c->sub.lit) + c->mode = START; + break; + case WASH: /* o: got eob, possibly more output */ + if (k > 7) /* return unused byte, if any */ + { + Assert(k < 16, "inflate_codes grabbed too many bytes") + k -= 8; + n++; + p--; /* can always return one */ + } + FLUSH + if (s->read != s->write) + LEAVE + c->mode = END; + case END: + r = Z_STREAM_END; + LEAVE + case BADCODE: /* x: got error */ + r = Z_DATA_ERROR; + LEAVE + default: + r = Z_STREAM_ERROR; + LEAVE + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +void inflate_codes_free(inflate_codes_statef *c, z_streamp z) +{ + ZFREE(z, c); + Tracev(("inflate: codes free\n")); +} + +/* adler32.c -- compute the Adler-32 checksum of a data stream + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +#define BASE 65521L /* largest prime smaller than 65536 */ +#define NMAX 5552 +/* NMAX is the largest n such that 255n(n+1)/2 + (n+1)(BASE-1) <= 2^32-1 */ + +#undef DO1 +#undef DO2 +#undef DO4 +#undef DO8 + +#define DO1(buf,i) {s1 += buf[i]; s2 += s1;} +#define DO2(buf,i) DO1(buf,i); DO1(buf,i+1); +#define DO4(buf,i) DO2(buf,i); DO2(buf,i+2); +#define DO8(buf,i) DO4(buf,i); DO4(buf,i+4); +#define DO16(buf) DO8(buf,0); DO8(buf,8); + +/* ========================================================================= */ +uLong adler32(uLong adler, const Byte *buf, uInt len) +{ + unsigned long s1 = adler & 0xffff; + unsigned long s2 = (adler >> 16) & 0xffff; + int k; + + if (buf == Z_NULL) return 1L; + + while (len > 0) { + k = len < NMAX ? len : NMAX; + len -= k; + while (k >= 16) { + DO16(buf); + buf += 16; + k -= 16; + } + if (k != 0) do { + s1 += *buf++; + s2 += s1; + } while (--k); + s1 %= BASE; + s2 %= BASE; + } + return (s2 << 16) | s1; +} + +/* infblock.h -- header to use infblock.c + * Copyright (C) 1995-1998 Mark Adler + * For conditions of distribution and use, see copyright notice in zlib.h + */ + +/* WARNING: this file should *not* be used by applications. It is + part of the implementation of the compression library and is + subject to change. Applications should only use zlib.h. + */ + +extern inflate_blocks_statef * inflate_blocks_new OF(( + z_streamp z, + check_func c, /* check function */ + uInt w)); /* window size */ + +extern int inflate_blocks OF(( + inflate_blocks_statef *, + z_streamp , + int)); /* initial return code */ + +extern void inflate_blocks_reset OF(( + inflate_blocks_statef *, + z_streamp , + uLong *)); /* check value on output */ + +extern int inflate_blocks_free OF(( + inflate_blocks_statef *, + z_streamp)); + +extern void inflate_set_dictionary OF(( + inflate_blocks_statef *s, + const Byte *d, /* dictionary */ + uInt n)); /* dictionary length */ + +extern int inflate_blocks_sync_point OF(( + inflate_blocks_statef *s)); + +typedef enum { + imMETHOD, /* waiting for method byte */ + imFLAG, /* waiting for flag byte */ + imDICT4, /* four dictionary check bytes to go */ + imDICT3, /* three dictionary check bytes to go */ + imDICT2, /* two dictionary check bytes to go */ + imDICT1, /* one dictionary check byte to go */ + imDICT0, /* waiting for inflateSetDictionary */ + imBLOCKS, /* decompressing blocks */ + imCHECK4, /* four check bytes to go */ + imCHECK3, /* three check bytes to go */ + imCHECK2, /* two check bytes to go */ + imCHECK1, /* one check byte to go */ + imDONE, /* finished check, done */ + imBAD} /* got an error--stay here */ +inflate_mode; + +/* inflate private state */ +struct internal_state { + + /* mode */ + inflate_mode mode; /* current inflate mode */ + + /* mode dependent information */ + union { + uInt method; /* if FLAGS, method byte */ + struct { + uLong was; /* computed check value */ + uLong need; /* stream check value */ + } check; /* if CHECK, check values to compare */ + uInt marker; /* if BAD, inflateSync's marker bytes count */ + } sub; /* submode */ + + /* mode independent information */ + int nowrap; /* flag for no wrapper */ + uInt wbits; /* log2(window size) (8..15, defaults to 15) */ + inflate_blocks_statef + *blocks; /* current inflate_blocks state */ + +}; + + +int inflateReset(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + z->total_in = z->total_out = 0; + z->msg = Z_NULL; + z->state->mode = z->state->nowrap ? imBLOCKS : imMETHOD; + inflate_blocks_reset(z->state->blocks, z, Z_NULL); + Tracev(("inflate: reset\n")); + return Z_OK; +} + + +int inflateEnd(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL || z->zfree == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->blocks != Z_NULL) + inflate_blocks_free(z->state->blocks, z); + ZFREE(z, z->state); + z->state = Z_NULL; + Tracev(("inflate: end\n")); + return Z_OK; +} + + + +int inflateInit2_(z_streamp z, int w, const char *version, int stream_size) +{ + if (version == Z_NULL || version[0] != ZLIB_VERSION[0] || + stream_size != sizeof(z_stream)) + return Z_VERSION_ERROR; + + /* initialize state */ + if (z == Z_NULL) + return Z_STREAM_ERROR; + z->msg = Z_NULL; + if (z->zalloc == Z_NULL) + { + z->zalloc = (void *(*)(void *, unsigned, unsigned))zcalloc; + z->opaque = (voidp)0; + } + if (z->zfree == Z_NULL) z->zfree = (void (*)(void *, void *))zcfree; + if ((z->state = (struct internal_state *) + ZALLOC(z,1,sizeof(struct internal_state))) == Z_NULL) + return Z_MEM_ERROR; + z->state->blocks = Z_NULL; + + /* handle undocumented nowrap option (no zlib header or check) */ + z->state->nowrap = 0; + if (w < 0) + { + w = - w; + z->state->nowrap = 1; + } + + /* set window size */ + if (w < 8 || w > 15) + { + inflateEnd(z); + return Z_STREAM_ERROR; + } + z->state->wbits = (uInt)w; + + /* create inflate_blocks state */ + if ((z->state->blocks = + inflate_blocks_new(z, z->state->nowrap ? Z_NULL : adler32, (uInt)1 << w)) + == Z_NULL) + { + inflateEnd(z); + return Z_MEM_ERROR; + } + Tracev(("inflate: allocated\n")); + + /* reset state */ + inflateReset(z); + return Z_OK; +} + + +int inflateInit_(z_streamp z, const char *version, int stream_size) +{ + return inflateInit2_(z, DEF_WBITS, version, stream_size); +} + + +#define iNEEDBYTE {if(z->avail_in==0)return r;r=f;} +#define iNEXTBYTE (z->avail_in--,z->total_in++,*z->next_in++) + +int inflate(z_streamp z, int f) +{ + int r; + uInt b; + + if (z == Z_NULL || z->state == Z_NULL || z->next_in == Z_NULL) + return Z_STREAM_ERROR; + f = f == Z_FINISH ? Z_BUF_ERROR : Z_OK; + r = Z_BUF_ERROR; + while (1) switch (z->state->mode) + { + case imMETHOD: + iNEEDBYTE + if (((z->state->sub.method = iNEXTBYTE) & 0xf) != Z_DEFLATED) + { + z->state->mode = imBAD; + z->msg = (char*)"unknown compression method"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + if ((z->state->sub.method >> 4) + 8 > z->state->wbits) + { + z->state->mode = imBAD; + z->msg = (char*)"invalid window size"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + z->state->mode = imFLAG; + case imFLAG: + iNEEDBYTE + b = iNEXTBYTE; + if (((z->state->sub.method << 8) + b) % 31) + { + z->state->mode = imBAD; + z->msg = (char*)"incorrect header check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev(("inflate: zlib header ok\n")); + if (!(b & PRESET_DICT)) + { + z->state->mode = imBLOCKS; + break; + } + z->state->mode = imDICT4; + case imDICT4: + iNEEDBYTE + z->state->sub.check.need = (uLong)iNEXTBYTE << 24; + z->state->mode = imDICT3; + case imDICT3: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 16; + z->state->mode = imDICT2; + case imDICT2: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 8; + z->state->mode = imDICT1; + case imDICT1: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE; + z->adler = z->state->sub.check.need; + z->state->mode = imDICT0; + return Z_NEED_DICT; + case imDICT0: + z->state->mode = imBAD; + z->msg = (char*)"need dictionary"; + z->state->sub.marker = 0; /* can try inflateSync */ + return Z_STREAM_ERROR; + case imBLOCKS: + r = inflate_blocks(z->state->blocks, z, r); + if (r == Z_DATA_ERROR) + { + z->state->mode = imBAD; + z->state->sub.marker = 0; /* can try inflateSync */ + break; + } + if (r == Z_OK) + r = f; + if (r != Z_STREAM_END) + return r; + r = f; + inflate_blocks_reset(z->state->blocks, z, &z->state->sub.check.was); + if (z->state->nowrap) + { + z->state->mode = imDONE; + break; + } + z->state->mode = imCHECK4; + case imCHECK4: + iNEEDBYTE + z->state->sub.check.need = (uLong)iNEXTBYTE << 24; + z->state->mode = imCHECK3; + case imCHECK3: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 16; + z->state->mode = imCHECK2; + case imCHECK2: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE << 8; + z->state->mode = imCHECK1; + case imCHECK1: + iNEEDBYTE + z->state->sub.check.need += (uLong)iNEXTBYTE; + + if (z->state->sub.check.was != z->state->sub.check.need) + { + z->state->mode = imBAD; + z->msg = (char*)"incorrect data check"; + z->state->sub.marker = 5; /* can't try inflateSync */ + break; + } + Tracev(("inflate: zlib check ok\n")); + z->state->mode = imDONE; + case imDONE: + return Z_STREAM_END; + case imBAD: + return Z_DATA_ERROR; + default: + return Z_STREAM_ERROR; + } +#ifdef NEED_DUMMY_RETURN + return Z_STREAM_ERROR; /* Some dumb compilers complain without this */ +#endif +} + + +int inflateSetDictionary(z_streamp z, const Byte *dictionary, uInt dictLength) +{ + uInt length = dictLength; + + if (z == Z_NULL || z->state == Z_NULL || z->state->mode != imDICT0) + return Z_STREAM_ERROR; + + if (adler32(1L, dictionary, dictLength) != z->adler) return Z_DATA_ERROR; + z->adler = 1L; + + if (length >= ((uInt)1<state->wbits)) + { + length = (1<state->wbits)-1; + dictionary += dictLength - length; + } + inflate_set_dictionary(z->state->blocks, dictionary, length); + z->state->mode = imBLOCKS; + return Z_OK; +} + + +int inflateSync(z_streamp z) +{ + uInt n; /* number of bytes to look at */ + Byte *p; /* pointer to bytes */ + uInt m; /* number of marker bytes found in a row */ + uLong r, w; /* temporaries to save total_in and total_out */ + + /* set up */ + if (z == Z_NULL || z->state == Z_NULL) + return Z_STREAM_ERROR; + if (z->state->mode != imBAD) + { + z->state->mode = imBAD; + z->state->sub.marker = 0; + } + if ((n = z->avail_in) == 0) + return Z_BUF_ERROR; + p = z->next_in; + m = z->state->sub.marker; + + /* search */ + while (n && m < 4) + { + static const Byte mark[4] = {0, 0, 0xff, 0xff}; + if (*p == mark[m]) + m++; + else if (*p) + m = 0; + else + m = 4 - m; + p++, n--; + } + + /* restore */ + z->total_in += p - z->next_in; + z->next_in = p; + z->avail_in = n; + z->state->sub.marker = m; + + /* return no joy or set up to restart on a new block */ + if (m != 4) + return Z_DATA_ERROR; + r = z->total_in; w = z->total_out; + inflateReset(z); + z->total_in = r; z->total_out = w; + z->state->mode = imBLOCKS; + return Z_OK; +} + + +/* Returns true if inflate is currently at the end of a block generated + * by Z_SYNC_FLUSH or Z_FULL_FLUSH. This function is used by one PPP + * implementation to provide an additional safety check. PPP uses Z_SYNC_FLUSH + * but removes the length bytes of the resulting empty stored block. When + * decompressing, PPP checks that at the end of input packet, inflate is + * waiting for these length bytes. + */ +int inflateSyncPoint(z_streamp z) +{ + if (z == Z_NULL || z->state == Z_NULL || z->state->blocks == Z_NULL) + return Z_STREAM_ERROR; + return inflate_blocks_sync_point(z->state->blocks); +} + +voidp zcalloc (voidp opaque, unsigned items, unsigned size) +{ + if (opaque) items += size - size; /* make compiler happy */ + return (voidp)malloc(items*size); +} + +void zcfree (voidp opaque, voidp ptr) +{ + free(ptr); + if (opaque) return; /* make compiler happy */ +} + diff --git a/libs/pak/unzip.h b/libs/pak/unzip.h new file mode 100644 index 00000000..d5c165dc --- /dev/null +++ b/libs/pak/unzip.h @@ -0,0 +1,300 @@ + +#if defined(STRICTUNZIP) || defined(STRICTZIPUNZIP) +/* like the STRICT of WIN32, we define a pointer that cannot be converted + from (void*) without cast */ +typedef struct TagunzFile__ { int unused; } unzFile__; +typedef unzFile__ *unzFile; +#else +typedef void* unzFile; +#endif + + +/* tm_unz contain date/time info */ +typedef struct tm_unz_s +{ + unsigned int tm_sec; /* seconds after the minute - [0,59] */ + unsigned int tm_min; /* minutes after the hour - [0,59] */ + unsigned int tm_hour; /* hours since midnight - [0,23] */ + unsigned int tm_mday; /* day of the month - [1,31] */ + unsigned int tm_mon; /* months since January - [0,11] */ + unsigned int tm_year; /* years - [1980..2044] */ +} tm_unz; + +/* unz_global_info structure contain global data about the ZIPfile + These data comes from the end of central dir */ +typedef struct unz_global_info_s +{ + unsigned long number_entry; /* total number of entries in the central dir on this disk */ + unsigned long size_comment; /* size of the global comment of the zipfile */ +} unz_global_info; + + +/* unz_file_info contain information about a file in the zipfile */ +typedef struct unz_file_info_s +{ + unsigned long version; /* version made by 2 unsigned chars */ + unsigned long version_needed; /* version needed to extract 2 unsigned chars */ + unsigned long flag; /* general purpose bit flag 2 unsigned chars */ + unsigned long compression_method; /* compression method 2 unsigned chars */ + unsigned long dosDate; /* last mod file date in Dos fmt 4 unsigned chars */ + unsigned long crc; /* crc-32 4 unsigned chars */ + unsigned long compressed_size; /* compressed size 4 unsigned chars */ + unsigned long uncompressed_size; /* uncompressed size 4 unsigned chars */ + unsigned long size_filename; /* filename length 2 unsigned chars */ + unsigned long size_file_extra; /* extra field length 2 unsigned chars */ + unsigned long size_file_comment; /* file comment length 2 unsigned chars */ + + unsigned long disk_num_start; /* disk number start 2 unsigned chars */ + unsigned long internal_fa; /* internal file attributes 2 unsigned chars */ + unsigned long external_fa; /* external file attributes 4 unsigned chars */ + + tm_unz tmu_date; +} unz_file_info; + +/* unz_file_info_interntal contain internal info about a file in zipfile*/ +typedef struct unz_file_info_internal_s +{ + unsigned long offset_curfile;/* relative offset of static header 4 unsigned chars */ +} unz_file_info_internal; + +typedef void* (*alloc_func) (void* opaque, unsigned int items, unsigned int size); +typedef void (*free_func) (void* opaque, void* address); + +struct internal_state; + +typedef struct z_stream_s { + unsigned char *next_in; /* next input unsigned char */ + unsigned int avail_in; /* number of unsigned chars available at next_in */ + unsigned long total_in; /* total nb of input unsigned chars read so */ + + unsigned char *next_out; /* next output unsigned char should be put there */ + unsigned int avail_out; /* remaining free space at next_out */ + unsigned long total_out; /* total nb of unsigned chars output so */ + + char *msg; /* last error message, NULL if no error */ + struct internal_state *state; /* not visible by applications */ + + alloc_func zalloc; /* used to allocate the internal state */ + free_func zfree; /* used to free the internal state */ + unsigned char* opaque; /* private data object passed to zalloc and zfree */ + + int data_type; /* best guess about the data type: ascii or binary */ + unsigned long adler; /* adler32 value of the uncompressed data */ + unsigned long reserved; /* reserved for future use */ +} z_stream; + +typedef z_stream *z_streamp; + + +/* file_in_zip_read_info_s contain internal information about a file in zipfile, + when reading and decompress it */ +typedef struct +{ + char *read_buffer; /* internal buffer for compressed data */ + z_stream stream; /* zLib stream structure for inflate */ + + unsigned long pos_in_zipfile; /* position in unsigned char on the zipfile, for fseek*/ + unsigned long stream_initialised; /* flag set if stream structure is initialised*/ + + unsigned long offset_local_extrafield;/* offset of the static extra field */ + unsigned int size_local_extrafield;/* size of the static extra field */ + unsigned long pos_local_extrafield; /* position in the static extra field in read*/ + + unsigned long crc32; /* crc32 of all data uncompressed */ + unsigned long crc32_wait; /* crc32 we must obtain after decompress all */ + unsigned long rest_read_compressed; /* number of unsigned char to be decompressed */ + unsigned long rest_read_uncompressed;/*number of unsigned char to be obtained after decomp*/ + FILE* file; /* io structore of the zipfile */ + unsigned long compression_method; /* compression method (0==store) */ + unsigned long byte_before_the_zipfile;/* unsigned char before the zipfile, (>0 for sfx)*/ +} file_in_zip_read_info_s; + + +/* unz_s contain internal information about the zipfile +*/ +typedef struct +{ + FILE* file; /* io structore of the zipfile */ + unz_global_info gi; /* public global information */ + unsigned long byte_before_the_zipfile;/* unsigned char before the zipfile, (>0 for sfx)*/ + unsigned long num_file; /* number of the current file in the zipfile*/ + unsigned long pos_in_central_dir; /* pos of the current file in the central dir*/ + unsigned long current_file_ok; /* flag about the usability of the current file*/ + unsigned long central_pos; /* position of the beginning of the central dir*/ + + unsigned long size_central_dir; /* size of the central directory */ + unsigned long offset_central_dir; /* offset of start of central directory with + respect to the starting disk number */ + + unz_file_info cur_file_info; /* public info about the current file in zip*/ + unz_file_info_internal cur_file_info_internal; /* private info about it*/ + file_in_zip_read_info_s* pfile_in_zip_read; /* structure about the current + file if we are decompressing it */ +} unz_s; + +#define UNZ_OK (0) +#define UNZ_END_OF_LIST_OF_FILE (-100) +#define UNZ_ERRNO (Z_ERRNO) +#define UNZ_EOF (0) +#define UNZ_PARAMERROR (-102) +#define UNZ_BADZIPFILE (-103) +#define UNZ_INTERNALERROR (-104) +#define UNZ_CRCERROR (-105) + +#define UNZ_CASESENSITIVE 1 +#define UNZ_NOTCASESENSITIVE 2 +#define UNZ_OSDEFAULTCASE 0 + +extern int unzStringFileNameCompare (const char* fileName1, const char* fileName2, int iCaseSensitivity); + +/* + Compare two filename (fileName1,fileName2). + If iCaseSenisivity = 1, comparision is case sensitivity (like strcmp) + If iCaseSenisivity = 2, comparision is not case sensitivity (like strcmpi + or strcasecmp) + If iCaseSenisivity = 0, case sensitivity is defaut of your operating system + (like 1 on Unix, 2 on Windows) +*/ + +extern unzFile unzOpen (const char *path); +extern unzFile unzReOpen (const char* path, unzFile file); + +/* + Open a Zip file. path contain the full pathname (by example, + on a Windows NT computer "c:\\zlib\\zlib111.zip" or on an Unix computer + "zlib/zlib111.zip". + If the zipfile cannot be opened (file don't exist or in not valid), the + return value is NULL. + Else, the return value is a unzFile Handle, usable with other function + of this unzip package. +*/ + +extern int unzClose (unzFile file); + +/* + Close a ZipFile opened with unzipOpen. + If there is files inside the .Zip opened with unzOpenCurrentFile (see later), + these files MUST be closed with unzipCloseCurrentFile before call unzipClose. + return UNZ_OK if there is no problem. */ + +extern int unzGetGlobalInfo (unzFile file, unz_global_info *pglobal_info); + +/* + Write info about the ZipFile in the *pglobal_info structure. + No preparation of the structure is needed + return UNZ_OK if there is no problem. */ + + +extern int unzGetGlobalComment (unzFile file, char *szComment, unsigned long uSizeBuf); + +/* + Get the global comment string of the ZipFile, in the szComment buffer. + uSizeBuf is the size of the szComment buffer. + return the number of unsigned char copied or an error code <0 +*/ + + +/***************************************************************************/ +/* Unzip package allow you browse the directory of the zipfile */ + +extern int unzGoToFirstFile (unzFile file); + +/* + Set the current file of the zipfile to the first file. + return UNZ_OK if there is no problem +*/ + +extern int unzGoToNextFile (unzFile file); + +/* + Set the current file of the zipfile to the next file. + return UNZ_OK if there is no problem + return UNZ_END_OF_LIST_OF_FILE if the actual file was the latest. +*/ + +extern int unzLocateFile (unzFile file, const char *szFileName, int iCaseSensitivity); + +/* + Try locate the file szFileName in the zipfile. + For the iCaseSensitivity signification, see unzStringFileNameCompare + + return value : + UNZ_OK if the file is found. It becomes the current file. + UNZ_END_OF_LIST_OF_FILE if the file is not found +*/ + + +extern int unzGetCurrentFileInfo (unzFile file, unz_file_info *pfile_info, char *szFileName, unsigned long fileNameBufferSize, void *extraField, unsigned long extraFieldBufferSize, char *szComment, unsigned long commentBufferSize); + +/* + Get Info about the current file + if pfile_info!=NULL, the *pfile_info structure will contain somes info about + the current file + if szFileName!=NULL, the filemane string will be copied in szFileName + (fileNameBufferSize is the size of the buffer) + if extraField!=NULL, the extra field information will be copied in extraField + (extraFieldBufferSize is the size of the buffer). + This is the Central-header version of the extra field + if szComment!=NULL, the comment string of the file will be copied in szComment + (commentBufferSize is the size of the buffer) +*/ + +/***************************************************************************/ +/* for reading the content of the current zipfile, you can open it, read data + from it, and close it (you can close it before reading all the file) + */ + +extern int unzOpenCurrentFile (unzFile file); + +/* + Open for reading data the current file in the zipfile. + If there is no error, the return value is UNZ_OK. +*/ + +extern int unzCloseCurrentFile (unzFile file); + +/* + Close the file in zip opened with unzOpenCurrentFile + Return UNZ_CRCERROR if all the file was read but the CRC is not good +*/ + + +extern int unzReadCurrentFile (unzFile file, void* buf, unsigned len); + +/* + Read unsigned chars from the current file (opened by unzOpenCurrentFile) + buf contain buffer where data must be copied + len the size of buf. + + return the number of unsigned char copied if somes unsigned chars are copied + return 0 if the end of file was reached + return <0 with error code if there is an error + (UNZ_ERRNO for IO error, or zLib error for uncompress error) +*/ + +extern long unztell(unzFile file); + +/* + Give the current position in uncompressed data +*/ + +extern int unzeof (unzFile file); + +/* + return 1 if the end of file was reached, 0 elsewhere +*/ + +extern int unzGetLocalExtrafield (unzFile file, void* buf, unsigned len); + +/* + Read extra field from the current file (opened by unzOpenCurrentFile) + This is the local-header version of the extra field (sometimes, there is + more info in the local-header version than in the central-header) + + if buf==NULL, it return the size of the local extra field + + if buf!=NULL, len is the size of the buffer, the extra header is copied in + buf. + the return value is the number of unsigned chars copied in buf, or (if <0) + the error code +*/ diff --git a/libs/pakstuff.h b/libs/pakstuff.h new file mode 100644 index 00000000..4c709cae --- /dev/null +++ b/libs/pakstuff.h @@ -0,0 +1,150 @@ +/* +Copyright (C) 1999-2007 id Software, Inc. and contributors. +For a list of contributors, see the accompanying CONTRIBUTORS file. + +This file is part of GtkRadiant. + +GtkRadiant is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +GtkRadiant is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GtkRadiant; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +*/ + +#ifndef _PAKSTUFF_H_ +#define _PAKSTUFF_H_ + +#ifndef _WIN32 +#define WINAPI +#else +#include +#endif + +#ifndef __cplusplus +typedef int bool; // leo +#endif + +#ifdef __cplusplus +extern "C" +{ +#endif + +typedef char Int8; +typedef short Int16; +typedef long Int32; +typedef unsigned char UInt8; +typedef unsigned short UInt16; +typedef unsigned long UInt32; +typedef float Float32; +typedef double Float64; +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) +#define RANDOM(x) (random() % (x)) +#define RANDOMIZE() srand((int) time(NULL)) + +#define FTYPE_UNKNOWN 0 +#define FTYPE_IWAD 1 /* .wad "IWAD" */ +#define FTYPE_PWAD 2 /* .wad "PWAD" */ +#define FTYPE_PACK 3 /* .pak "PACK" */ +#define FTYPE_WAD2 4 /* .wad "WAD2" */ +#define FTYPE_BSP 10 /* .bsp (0x17 0x00 0x00 0x00) */ +#define FTYPE_MODEL 11 /* .mdl "IDPO" */ +#define FTYPE_SPRITE 12 /* .spr "IDSP" */ +#define FTYPE_WAV 20 /* .wav "RIFF" */ +#define FTYPE_AU 21 /* .au ".snd" */ +#define FTYPE_VOC 22 /* .voc ? */ +#define FTYPE_PBM_ASC 30 /* .pbm "P1" */ +#define FTYPE_PGM_ASC 31 /* .pgm "P2" */ +#define FTYPE_PPM_ASC 32 /* .ppm "P3" */ +#define FTYPE_PBM_RAW 33 /* .pbm "P4" */ +#define FTYPE_PGM_RAW 34 /* .pgm "P5" */ +#define FTYPE_PPM_RAW 35 /* .ppm "P6" */ +#define FTYPE_BMP 36 /* .bmp "BM" */ +#define FTYPE_GIF 37 /* .gif "GIF8" */ +#define FTYPE_PCX 38 /* .pcx (0x0a 0x05 0x01 0x08) */ +#define FTYPE_ERROR -1 + +#ifdef FAT_ENDIAN +Bool ReadInt16 (FILE *file, UInt16 huge *x); +Bool ReadInt32 (FILE *file, UInt32 huge *x); +Bool ReadFloat32 (FILE *file, Float32 huge *x); +Bool WriteInt16 (FILE *file, UInt16 huge *x); +Bool WriteInt32 (FILE *file, UInt32 huge *x); +Bool WriteFloat32 (FILE *file, Float32 huge *x); +UInt16 SwapInt16 (UInt16 x); +UInt32 SwapInt32 (UInt32 x); +Float32 SwapFloat32 (Float32 x); +#else +#define ReadInt16(f, p) ReadBytes((f), (p), 2L) +#define ReadInt32(f, p) ReadBytes((f), (p), 4L) +#define ReadFloat32(f, p) ReadBytes((f), (p), 4L) +#define WriteInt16(f, p) WriteBytes((f), (p), 2L) +#define WriteInt32(f, p) WriteBytes((f), (p), 4L) +#define WriteFloat32(f, p) WriteBytes((f), (p), 4L) +#define SwapInt16(x) (x) +#define SwapInt32(x) (x) +#define SwapFloat32(x) (x) +#endif /* FAT_ENDIAN */ + +#define FROMDISK -1 +struct PACKDirectory +{ + char name[56]; /* name of file */ + UInt32 offset; /* offset to start of data */ + UInt32 size; /* byte size of data */ +}; +typedef struct PACKDirectory *PACKDirPtr; + +typedef struct DirListStruct +{ + char dirname[1024]; + int from; + struct DirListStruct *next; +} DIRLIST; + +typedef struct FileListStruct +{ + char filename[1024]; + UInt32 offset; + UInt32 size; + struct FileListStruct *next; +} FILELIST; + +typedef struct DirStruct +{ + char name[1024]; + FILELIST *files; + struct DirStruct *next; +} DIRECTORY; + + +extern int m_nPAKIndex; +extern FILE* pakfile[16]; +extern bool pakopen; +extern DIRECTORY *paktextures; + +void ClearFileList (FILELIST **); +void ClearDirList (DIRLIST **); +bool GetPackFileList (FILELIST **, char *); +bool GetPackTextureDirs (DIRLIST **); +bool AddToDirListAlphabetized (DIRLIST **, char *, int); +bool AddToFileListAlphabetized (FILELIST **t, char *, UInt32, UInt32, bool); +bool PakLoadFile (const char *, void **); +void OpenPakFile (const char *); +void ClosePakFile (void); +int PakLoadAnyFile(const char *filename, void **bufferptr); +void WINAPI InitPakFile(const char * pBasePath, const char *pName); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/picomodel.h b/libs/picomodel.h new file mode 100644 index 00000000..8642527a --- /dev/null +++ b/libs/picomodel.h @@ -0,0 +1,345 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +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 names of the copyright holders 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. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef PICOMODEL_H +#define PICOMODEL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + + + +/* version */ +#define PICOMODEL_VERSION "0.8.20" + + +/* constants */ +#define PICO_GROW_SHADERS 16 +#define PICO_GROW_SURFACES 16 +#define PICO_GROW_VERTEXES 1024 +#define PICO_GROW_INDEXES 1024 +#define PICO_GROW_ARRAYS 8 +#define PICO_GROW_FACES 256 +#define PICO_MAX_SPECIAL 8 +#define PICO_MAX_DEFAULT_EXTS 4 /* max default extensions per module */ + + +/* types */ +typedef unsigned char picoByte_t; +typedef float picoVec_t; +typedef float picoVec2_t[ 2 ]; +typedef float picoVec3_t[ 3 ]; +typedef float picoVec4_t[ 4 ]; +typedef picoByte_t picoColor_t[ 4 ]; +typedef int picoIndex_t; + +typedef enum +{ + PICO_BAD, + PICO_TRIANGLES, + PICO_PATCH +} +picoSurfaceType_t; + +typedef enum +{ + PICO_NORMAL, + PICO_VERBOSE, + PICO_WARNING, + PICO_ERROR, + PICO_FATAL +} +picoPrintLevel_t; + +typedef struct picoSurface_s picoSurface_t; +typedef struct picoShader_s picoShader_t; +typedef struct picoModel_s picoModel_t; +typedef struct picoModule_s picoModule_t; + +struct picoSurface_s +{ + void *data; + + picoModel_t *model; /* owner model */ + + picoSurfaceType_t type; + char *name; /* sea: surface name */ + picoShader_t *shader; /* ydnar: changed to ptr */ + + int numVertexes, maxVertexes; + picoVec3_t *xyz; + picoVec3_t *normal; + + int numSTArrays, maxSTArrays; + picoVec2_t **st; + + int numColorArrays, maxColorArrays; + picoColor_t **color; + + int numIndexes, maxIndexes; + picoIndex_t *index; + + int numFaceNormals, maxFaceNormals; + picoVec3_t *faceNormal; + + int special[ PICO_MAX_SPECIAL ]; +}; + + +/* seaw0lf */ +struct picoShader_s +{ + picoModel_t *model; /* owner model */ + + char *name; /* shader name */ + char *mapName; /* shader file name (name of diffuse texturemap) */ + picoColor_t ambientColor; /* ambient color of mesh (rgba) */ + picoColor_t diffuseColor; /* diffuse color of mesh (rgba) */ + picoColor_t specularColor; /* specular color of mesh (rgba) */ + float transparency; /* transparency (0..1; 1 = 100% transparent) */ + float shininess; /* shininess (0..128; 128 = 100% shiny) */ +}; + +struct picoModel_s +{ + void *data; + char *name; /* model name */ + char *fileName; /* sea: model file name */ + int frameNum; /* sea: renamed to frameNum */ + int numFrames; /* sea: number of frames */ + picoVec3_t mins; + picoVec3_t maxs; + + int numShaders, maxShaders; + picoShader_t **shader; + + int numSurfaces, maxSurfaces; + picoSurface_t **surface; + + const picoModule_t *module; /* sea */ +}; + + +/* seaw0lf */ +/* return codes used by the validation callbacks; pmv is short */ +/* for 'pico module validation'. everything >PICO_PMV_OK means */ +/* that there was an error. */ +enum +{ + PICO_PMV_OK, /* file valid */ + PICO_PMV_ERROR, /* file not valid */ + PICO_PMV_ERROR_IDENT, /* unknown file magic (aka ident) */ + PICO_PMV_ERROR_VERSION, /* unsupported file version */ + PICO_PMV_ERROR_SIZE, /* file size error */ + PICO_PMV_ERROR_MEMORY, /* out of memory error */ +}; + +/* convenience (makes it easy to add new params to the callbacks) */ +#define PM_PARAMS_CANLOAD \ + char *fileName, const void *buffer, int bufSize + +#define PM_PARAMS_LOAD \ + char *fileName, int frameNum, const void *buffer, int bufSize + +#define PM_PARAMS_CANSAVE \ + void + +#define PM_PARAMS_SAVE \ + char *fileName, picoModel_t *model + +/* pico file format module structure */ +struct picoModule_s +{ + char *version; /* internal module version (e.g. '1.5-b2') */ + + char *displayName; /* string used to display in guis, etc. */ + char *authorName; /* author name (eg. 'My Real Name') */ + char *copyright; /* copyright year and holder (eg. '2002 My Company') */ + + char *defaultExts[ PICO_MAX_DEFAULT_EXTS ]; /* default file extensions used by this file type */ + int (*canload)( PM_PARAMS_CANLOAD ); /* checks whether module can load given file (returns PMVR_*) */ + picoModel_t *(*load)( PM_PARAMS_LOAD ); /* parses model file data */ + int (*cansave)( PM_PARAMS_CANSAVE ); /* checks whether module can save (returns 1 or 0 and might spit out a message) */ + int (*save)( PM_PARAMS_SAVE ); /* saves a pico model in module's native model format */ +}; + + + +/* general functions */ +int PicoInit( void ); +void PicoShutdown( void ); +int PicoError( void ); + +void PicoSetMallocFunc( void *(*func)( size_t ) ); +void PicoSetFreeFunc( void (*func)( void* ) ); +void PicoSetLoadFileFunc( void (*func)( char*, unsigned char**, int* ) ); +void PicoSetFreeFileFunc( void (*func)( void* ) ); +void PicoSetPrintFunc( void (*func)( int, const char* ) ); + +const picoModule_t **PicoModuleList( int *numModules ); + +picoModel_t *PicoLoadModel( char *name, int frameNum ); + + +/* model functions */ +picoModel_t *PicoNewModel( void ); +void PicoFreeModel( picoModel_t *model ); +int PicoAdjustModel( picoModel_t *model, int numShaders, int numSurfaces ); + + +/* shader functions */ +picoShader_t *PicoNewShader( picoModel_t *model ); +void PicoFreeShader( picoShader_t *shader ); +picoShader_t *PicoFindShader( picoModel_t *model, char *name, int caseSensitive ); + + +/* surface functions */ +picoSurface_t *PicoNewSurface( picoModel_t *model ); +void PicoFreeSurface( picoSurface_t *surface ); +picoSurface_t *PicoFindSurface( picoModel_t *model, char *name, int caseSensitive ); +int PicoAdjustSurface( picoSurface_t *surface, int numVertexes, int numSTArrays, int numColorArrays, int numIndexes, int numFaceNormals ); + + +/* setter functions */ +void PicoSetModelName( picoModel_t *model, char *name ); +void PicoSetModelFileName( picoModel_t *model, char *fileName ); +void PicoSetModelFrameNum( picoModel_t *model, int frameNum ); +void PicoSetModelNumFrames( picoModel_t *model, int numFrames ); +void PicoSetModelData( picoModel_t *model, void *data ); + +void PicoSetShaderName( picoShader_t *shader, char *name ); +void PicoSetShaderMapName( picoShader_t *shader, char *mapName ); +void PicoSetShaderAmbientColor( picoShader_t *shader, picoColor_t color ); +void PicoSetShaderDiffuseColor( picoShader_t *shader, picoColor_t color ); +void PicoSetShaderSpecularColor( picoShader_t *shader, picoColor_t color ); +void PicoSetShaderTransparency( picoShader_t *shader, float value ); +void PicoSetShaderShininess( picoShader_t *shader, float value ); + +void PicoSetSurfaceData( picoSurface_t *surface, void *data ); +void PicoSetSurfaceType( picoSurface_t *surface, picoSurfaceType_t type ); +void PicoSetSurfaceName( picoSurface_t *surface, char *name ); +void PicoSetSurfaceShader( picoSurface_t *surface, picoShader_t *shader ); +void PicoSetSurfaceXYZ( picoSurface_t *surface, int num, picoVec3_t xyz ); +void PicoSetSurfaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ); +void PicoSetSurfaceST( picoSurface_t *surface, int array, int num, picoVec2_t st ); +void PicoSetSurfaceColor( picoSurface_t *surface, int array, int num, picoColor_t color ); +void PicoSetSurfaceIndex( picoSurface_t *surface, int num, picoIndex_t index ); +void PicoSetSurfaceIndexes( picoSurface_t *surface, int num, picoIndex_t *index, int count ); +void PicoSetFaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ); +void PicoSetSurfaceSpecial( picoSurface_t *surface, int num, int special ); + + +/* getter functions */ +char *PicoGetModelName( picoModel_t *model ); +char *PicoGetModelFileName( picoModel_t *model ); +int PicoGetModelFrameNum( picoModel_t *model ); +int PicoGetModelNumFrames( picoModel_t *model ); +void *PicoGetModelData( picoModel_t *model ); +int PicoGetModelNumShaders( picoModel_t *model ); +picoShader_t *PicoGetModelShader( picoModel_t *model, int num ); /* sea */ +int PicoGetModelNumSurfaces( picoModel_t *model ); +picoSurface_t *PicoGetModelSurface( picoModel_t *model, int num ); +int PicoGetModelTotalVertexes( picoModel_t *model ); +int PicoGetModelTotalIndexes( picoModel_t *model ); + +char *PicoGetShaderName( picoShader_t *shader ); +char *PicoGetShaderMapName( picoShader_t *shader ); +picoByte_t *PicoGetShaderAmbientColor( picoShader_t *shader ); +picoByte_t *PicoGetShaderDiffuseColor( picoShader_t *shader ); +picoByte_t *PicoGetShaderSpecularColor( picoShader_t *shader ); +float PicoGetShaderTransparency( picoShader_t *shader ); +float PicoGetShaderShininess( picoShader_t *shader ); + +void *PicoGetSurfaceData( picoSurface_t *surface ); +char *PicoGetSurfaceName( picoSurface_t *surface ); /* sea */ +picoSurfaceType_t PicoGetSurfaceType( picoSurface_t *surface ); +char *PicoGetSurfaceName( picoSurface_t *surface ); +picoShader_t *PicoGetSurfaceShader( picoSurface_t *surface ); /* sea */ + +int PicoGetSurfaceNumVertexes( picoSurface_t *surface ); +picoVec_t *PicoGetSurfaceXYZ( picoSurface_t *surface, int num ); +picoVec_t *PicoGetSurfaceNormal( picoSurface_t *surface, int num ); +picoVec_t *PicoGetSurfaceST( picoSurface_t *surface, int array, int num ); +picoByte_t *PicoGetSurfaceColor( picoSurface_t *surface, int array, int num ); +int PicoGetSurfaceNumIndexes( picoSurface_t *surface ); +picoIndex_t PicoGetSurfaceIndex( picoSurface_t *surface, int num ); +picoIndex_t *PicoGetSurfaceIndexes( picoSurface_t *surface, int num ); +picoVec_t *PicoGetFaceNormal( picoSurface_t *surface, int num ); +int PicoGetSurfaceSpecial( picoSurface_t *surface, int num ); + + +/* hashtable related functions */ +typedef struct picoVertexCombinationData_s +{ + picoVec3_t xyz, normal; + picoVec2_t st; + picoColor_t color; +} picoVertexCombinationData_t; + +typedef struct picoVertexCombinationHash_s +{ + picoVertexCombinationData_t vcd; + picoIndex_t index; + + void *data; + + struct picoVertexCombinationHash_s *next; +} picoVertexCombinationHash_t; + +int PicoGetHashTableSize( void ); +unsigned int PicoVertexCoordGenerateHash( picoVec3_t xyz ); +picoVertexCombinationHash_t **PicoNewVertexCombinationHashTable( void ); +void PicoFreeVertexCombinationHashTable( picoVertexCombinationHash_t **hashTable ); +picoVertexCombinationHash_t *PicoFindVertexCombinationInHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color ); +picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index ); + +/* specialized functions */ +int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color ); +void PicoFixSurfaceNormals( picoSurface_t *surface ); +int PicoRemapModel( picoModel_t *model, char *remapFile ); + + +void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals, int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors, picoShader_t* shader ); + +/* end marker */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/picomodel/lwo/clip.c b/libs/picomodel/lwo/clip.c new file mode 100644 index 00000000..349222a4 --- /dev/null +++ b/libs/picomodel/lwo/clip.c @@ -0,0 +1,249 @@ +/* +====================================================================== +clip.c + +Functions for LWO2 image references. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + + +/* +====================================================================== +lwFreeClip() + +Free memory used by an lwClip. +====================================================================== */ + +void lwFreeClip( lwClip *clip ) +{ + if ( clip ) { + lwListFree( (void*) clip->ifilter, lwFreePlugin ); + lwListFree( (void*) clip->pfilter, lwFreePlugin ); + _pico_free( clip ); + } +} + + +/* +====================================================================== +lwGetClip() + +Read image references from a CLIP chunk in an LWO2 file. +====================================================================== */ + +lwClip *lwGetClip( picoMemStream_t *fp, int cksize ) +{ + lwClip *clip; + lwPlugin *filt; + unsigned int id; + unsigned short sz; + int pos, rlen; + + + /* allocate the Clip structure */ + + clip = _pico_calloc( 1, sizeof( lwClip )); + if ( !clip ) goto Fail; + + clip->contrast.val = 1.0f; + clip->brightness.val = 1.0f; + clip->saturation.val = 1.0f; + clip->gamma.val = 1.0f; + + /* remember where we started */ + + set_flen( 0 ); + pos = _pico_memstream_tell( fp ); + + /* index */ + + clip->index = getI4( fp ); + + /* first subchunk header */ + + clip->type = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + sz += sz & 1; + set_flen( 0 ); + + switch ( clip->type ) { + case ID_STIL: + clip->source.still.name = getS0( fp ); + break; + + case ID_ISEQ: + clip->source.seq.digits = getU1( fp ); + clip->source.seq.flags = getU1( fp ); + clip->source.seq.offset = getI2( fp ); + getU2( fp ); /* not sure what this is yet */ + clip->source.seq.start = getI2( fp ); + clip->source.seq.end = getI2( fp ); + clip->source.seq.prefix = getS0( fp ); + clip->source.seq.suffix = getS0( fp ); + break; + + case ID_ANIM: + clip->source.anim.name = getS0( fp ); + clip->source.anim.server = getS0( fp ); + rlen = get_flen(); + clip->source.anim.data = getbytes( fp, sz - rlen ); + break; + + case ID_XREF: + clip->source.xref.index = getI4( fp ); + clip->source.xref.string = getS0( fp ); + break; + + case ID_STCC: + clip->source.cycle.lo = getI2( fp ); + clip->source.cycle.hi = getI2( fp ); + clip->source.cycle.name = getS0( fp ); + break; + + default: + break; + } + + /* error while reading current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) goto Fail; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the CLIP chunk? */ + + rlen = _pico_memstream_tell( fp ) - pos; + if ( cksize < rlen ) goto Fail; + if ( cksize == rlen ) + return clip; + + /* process subchunks as they're encountered */ + + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_TIME: + clip->start_time = getF4( fp ); + clip->duration = getF4( fp ); + clip->frame_rate = getF4( fp ); + break; + + case ID_CONT: + clip->contrast.val = getF4( fp ); + clip->contrast.eindex = getVX( fp ); + break; + + case ID_BRIT: + clip->brightness.val = getF4( fp ); + clip->brightness.eindex = getVX( fp ); + break; + + case ID_SATR: + clip->saturation.val = getF4( fp ); + clip->saturation.eindex = getVX( fp ); + break; + + case ID_HUE: + clip->hue.val = getF4( fp ); + clip->hue.eindex = getVX( fp ); + break; + + case ID_GAMM: + clip->gamma.val = getF4( fp ); + clip->gamma.eindex = getVX( fp ); + break; + + case ID_NEGA: + clip->negative = getU2( fp ); + break; + + case ID_IFLT: + case ID_PFLT: + filt = _pico_calloc( 1, sizeof( lwPlugin )); + if ( !filt ) goto Fail; + + filt->name = getS0( fp ); + filt->flags = getU2( fp ); + rlen = get_flen(); + filt->data = getbytes( fp, sz - rlen ); + + if ( id == ID_IFLT ) { + lwListAdd( &clip->ifilter, filt ); + clip->nifilters++; + } + else { + lwListAdd( &clip->pfilter, filt ); + clip->npfilters++; + } + break; + + default: + break; + } + + /* error while reading current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) goto Fail; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the CLIP chunk? */ + + rlen = _pico_memstream_tell( fp ) - pos; + if ( cksize < rlen ) goto Fail; + if ( cksize == rlen ) break; + + /* get the next chunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) goto Fail; + } + + return clip; + +Fail: + lwFreeClip( clip ); + return NULL; +} + + +/* +====================================================================== +lwFindClip() + +Returns an lwClip pointer, given a clip index. +====================================================================== */ + +lwClip *lwFindClip( lwClip *list, int index ) +{ + lwClip *clip; + + clip = list; + while ( clip ) { + if ( clip->index == index ) break; + clip = clip->next; + } + return clip; +} diff --git a/libs/picomodel/lwo/envelope.c b/libs/picomodel/lwo/envelope.c new file mode 100644 index 00000000..4ece5951 --- /dev/null +++ b/libs/picomodel/lwo/envelope.c @@ -0,0 +1,600 @@ +/* +====================================================================== +envelope.c + +Envelope functions for an LWO2 reader. + +Ernie Wright 16 Nov 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + +/* +====================================================================== +lwFreeEnvelope() + +Free the memory used by an lwEnvelope. +====================================================================== */ + +void lwFreeEnvelope( lwEnvelope *env ) +{ + if ( env ) { + if ( env->name ) _pico_free( env->name ); + lwListFree( env->key, _pico_free ); + lwListFree( env->cfilter, lwFreePlugin ); + _pico_free( env ); + } +} + + +static int compare_keys( lwKey *k1, lwKey *k2 ) +{ + return k1->time > k2->time ? 1 : k1->time < k2->time ? -1 : 0; +} + + +/* +====================================================================== +lwGetEnvelope() + +Read an ENVL chunk from an LWO2 file. +====================================================================== */ + +lwEnvelope *lwGetEnvelope( picoMemStream_t *fp, int cksize ) +{ + lwEnvelope *env; + lwKey *key; + lwPlugin *plug; + unsigned int id; + unsigned short sz; + float f[ 4 ]; + int i, nparams, pos, rlen; + + + /* allocate the Envelope structure */ + + env = _pico_calloc( 1, sizeof( lwEnvelope )); + if ( !env ) goto Fail; + + /* remember where we started */ + + set_flen( 0 ); + pos = _pico_memstream_tell( fp ); + + /* index */ + + env->index = getVX( fp ); + + /* first subchunk header */ + + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + /* process subchunks as they're encountered */ + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_TYPE: + env->type = getU2( fp ); + break; + + case ID_NAME: + env->name = getS0( fp ); + break; + + case ID_PRE: + env->behavior[ 0 ] = getU2( fp ); + break; + + case ID_POST: + env->behavior[ 1 ] = getU2( fp ); + break; + + case ID_KEY: + key = _pico_calloc( 1, sizeof( lwKey )); + if ( !key ) goto Fail; + key->time = getF4( fp ); + key->value = getF4( fp ); + lwListInsert( &env->key, key, compare_keys ); + env->nkeys++; + break; + + case ID_SPAN: + if ( !key ) goto Fail; + key->shape = getU4( fp ); + + nparams = ( sz - 4 ) / 4; + if ( nparams > 4 ) nparams = 4; + for ( i = 0; i < nparams; i++ ) + f[ i ] = getF4( fp ); + + switch ( key->shape ) { + case ID_TCB: + key->tension = f[ 0 ]; + key->continuity = f[ 1 ]; + key->bias = f[ 2 ]; + break; + + case ID_BEZI: + case ID_HERM: + case ID_BEZ2: + for ( i = 0; i < nparams; i++ ) + key->param[ i ] = f[ i ]; + break; + } + break; + + case ID_CHAN: + plug = _pico_calloc( 1, sizeof( lwPlugin )); + if ( !plug ) goto Fail; + + plug->name = getS0( fp ); + plug->flags = getU2( fp ); + plug->data = getbytes( fp, sz - get_flen() ); + + lwListAdd( &env->cfilter, plug ); + env->ncfilters++; + break; + + default: + break; + } + + /* error while reading current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) goto Fail; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the ENVL chunk? */ + + rlen = _pico_memstream_tell( fp ) - pos; + if ( cksize < rlen ) goto Fail; + if ( cksize == rlen ) break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) goto Fail; + } + + return env; + +Fail: + lwFreeEnvelope( env ); + return NULL; +} + + +/* +====================================================================== +lwFindEnvelope() + +Returns an lwEnvelope pointer, given an envelope index. +====================================================================== */ + +lwEnvelope *lwFindEnvelope( lwEnvelope *list, int index ) +{ + lwEnvelope *env; + + env = list; + while ( env ) { + if ( env->index == index ) break; + env = env->next; + } + return env; +} + + +/* +====================================================================== +range() + +Given the value v of a periodic function, returns the equivalent value +v2 in the principal interval [lo, hi]. If i isn't NULL, it receives +the number of wavelengths between v and v2. + + v2 = v - i * (hi - lo) + +For example, range( 3 pi, 0, 2 pi, i ) returns pi, with i = 1. +====================================================================== */ + +static float range( float v, float lo, float hi, int *i ) +{ + float v2, r = hi - lo; + + if ( r == 0.0 ) { + if ( i ) *i = 0; + return lo; + } + + v2 = lo + v - r * ( float ) floor(( double ) v / r ); + if ( i ) *i = -( int )(( v2 - v ) / r + ( v2 > v ? 0.5 : -0.5 )); + + return v2; +} + + +/* +====================================================================== +hermite() + +Calculate the Hermite coefficients. +====================================================================== */ + +static void hermite( float t, float *h1, float *h2, float *h3, float *h4 ) +{ + float t2, t3; + + t2 = t * t; + t3 = t * t2; + + *h2 = 3.0f * t2 - t3 - t3; + *h1 = 1.0f - *h2; + *h4 = t3 - t2; + *h3 = *h4 - t2 + t; +} + + +/* +====================================================================== +bezier() + +Interpolate the value of a 1D Bezier curve. +====================================================================== */ + +static float bezier( float x0, float x1, float x2, float x3, float t ) +{ + float a, b, c, t2, t3; + + t2 = t * t; + t3 = t2 * t; + + c = 3.0f * ( x1 - x0 ); + b = 3.0f * ( x2 - x1 ) - c; + a = x3 - x0 - c - b; + + return a * t3 + b * t2 + c * t + x0; +} + + +/* +====================================================================== +bez2_time() + +Find the t for which bezier() returns the input time. The handle +endpoints of a BEZ2 curve represent the control points, and these have +(time, value) coordinates, so time is used as both a coordinate and a +parameter for this curve type. +====================================================================== */ + +static float bez2_time( float x0, float x1, float x2, float x3, float time, + float *t0, float *t1 ) +{ + float v, t; + + t = *t0 + ( *t1 - *t0 ) * 0.5f; + v = bezier( x0, x1, x2, x3, t ); + if ( fabs( time - v ) > .0001f ) { + if ( v > time ) + *t1 = t; + else + *t0 = t; + return bez2_time( x0, x1, x2, x3, time, t0, t1 ); + } + else + return t; +} + + +/* +====================================================================== +bez2() + +Interpolate the value of a BEZ2 curve. +====================================================================== */ + +static float bez2( lwKey *key0, lwKey *key1, float time ) +{ + float x, y, t, t0 = 0.0f, t1 = 1.0f; + + if ( key0->shape == ID_BEZ2 ) + x = key0->time + key0->param[ 2 ]; + else + x = key0->time + ( key1->time - key0->time ) / 3.0f; + + t = bez2_time( key0->time, x, key1->time + key1->param[ 0 ], key1->time, + time, &t0, &t1 ); + + if ( key0->shape == ID_BEZ2 ) + y = key0->value + key0->param[ 3 ]; + else + y = key0->value + key0->param[ 1 ] / 3.0f; + + return bezier( key0->value, y, key1->param[ 1 ] + key1->value, key1->value, t ); +} + + +/* +====================================================================== +outgoing() + +Return the outgoing tangent to the curve at key0. The value returned +for the BEZ2 case is used when extrapolating a linear pre behavior and +when interpolating a non-BEZ2 span. +====================================================================== */ + +static float outgoing( lwKey *key0, lwKey *key1 ) +{ + float a, b, d, t, out; + + switch ( key0->shape ) + { + case ID_TCB: + a = ( 1.0f - key0->tension ) + * ( 1.0f + key0->continuity ) + * ( 1.0f + key0->bias ); + b = ( 1.0f - key0->tension ) + * ( 1.0f - key0->continuity ) + * ( 1.0f - key0->bias ); + d = key1->value - key0->value; + + if ( key0->prev ) { + t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time ); + out = t * ( a * ( key0->value - key0->prev->value ) + b * d ); + } + else + out = b * d; + break; + + case ID_LINE: + d = key1->value - key0->value; + if ( key0->prev ) { + t = ( key1->time - key0->time ) / ( key1->time - key0->prev->time ); + out = t * ( key0->value - key0->prev->value + d ); + } + else + out = d; + break; + + case ID_BEZI: + case ID_HERM: + out = key0->param[ 1 ]; + if ( key0->prev ) + out *= ( key1->time - key0->time ) / ( key1->time - key0->prev->time ); + break; + + case ID_BEZ2: + out = key0->param[ 3 ] * ( key1->time - key0->time ); + if ( fabs( key0->param[ 2 ] ) > 1e-5f ) + out /= key0->param[ 2 ]; + else + out *= 1e5f; + break; + + case ID_STEP: + default: + out = 0.0f; + break; + } + + return out; +} + + +/* +====================================================================== +incoming() + +Return the incoming tangent to the curve at key1. The value returned +for the BEZ2 case is used when extrapolating a linear post behavior. +====================================================================== */ + +static float incoming( lwKey *key0, lwKey *key1 ) +{ + float a, b, d, t, in; + + switch ( key1->shape ) + { + case ID_LINE: + d = key1->value - key0->value; + if ( key1->next ) { + t = ( key1->time - key0->time ) / ( key1->next->time - key0->time ); + in = t * ( key1->next->value - key1->value + d ); + } + else + in = d; + break; + + case ID_TCB: + a = ( 1.0f - key1->tension ) + * ( 1.0f - key1->continuity ) + * ( 1.0f + key1->bias ); + b = ( 1.0f - key1->tension ) + * ( 1.0f + key1->continuity ) + * ( 1.0f - key1->bias ); + d = key1->value - key0->value; + + if ( key1->next ) { + t = ( key1->time - key0->time ) / ( key1->next->time - key0->time ); + in = t * ( b * ( key1->next->value - key1->value ) + a * d ); + } + else + in = a * d; + break; + + case ID_BEZI: + case ID_HERM: + in = key1->param[ 0 ]; + if ( key1->next ) + in *= ( key1->time - key0->time ) / ( key1->next->time - key0->time ); + break; + return in; + + case ID_BEZ2: + in = key1->param[ 1 ] * ( key1->time - key0->time ); + if ( fabs( key1->param[ 0 ] ) > 1e-5f ) + in /= key1->param[ 0 ]; + else + in *= 1e5f; + break; + + case ID_STEP: + default: + in = 0.0f; + break; + } + + return in; +} + + +/* +====================================================================== +evalEnvelope() + +Given a list of keys and a time, returns the interpolated value of the +envelope at that time. +====================================================================== */ + +float evalEnvelope( lwEnvelope *env, float time ) +{ + lwKey *key0, *key1, *skey, *ekey; + float t, h1, h2, h3, h4, in, out, offset = 0.0f; + int noff; + + + /* if there's no key, the value is 0 */ + + if ( env->nkeys == 0 ) return 0.0f; + + /* if there's only one key, the value is constant */ + + if ( env->nkeys == 1 ) + return env->key->value; + + /* find the first and last keys */ + + skey = ekey = env->key; + while ( ekey->next ) ekey = ekey->next; + + /* use pre-behavior if time is before first key time */ + + if ( time < skey->time ) { + switch ( env->behavior[ 0 ] ) + { + case BEH_RESET: + return 0.0f; + + case BEH_CONSTANT: + return skey->value; + + case BEH_REPEAT: + time = range( time, skey->time, ekey->time, NULL ); + break; + + case BEH_OSCILLATE: + time = range( time, skey->time, ekey->time, &noff ); + if ( noff % 2 ) + time = ekey->time - skey->time - time; + break; + + case BEH_OFFSET: + time = range( time, skey->time, ekey->time, &noff ); + offset = noff * ( ekey->value - skey->value ); + break; + + case BEH_LINEAR: + out = outgoing( skey, skey->next ) + / ( skey->next->time - skey->time ); + return out * ( time - skey->time ) + skey->value; + } + } + + /* use post-behavior if time is after last key time */ + + else if ( time > ekey->time ) { + switch ( env->behavior[ 1 ] ) + { + case BEH_RESET: + return 0.0f; + + case BEH_CONSTANT: + return ekey->value; + + case BEH_REPEAT: + time = range( time, skey->time, ekey->time, NULL ); + break; + + case BEH_OSCILLATE: + time = range( time, skey->time, ekey->time, &noff ); + if ( noff % 2 ) + time = ekey->time - skey->time - time; + break; + + case BEH_OFFSET: + time = range( time, skey->time, ekey->time, &noff ); + offset = noff * ( ekey->value - skey->value ); + break; + + case BEH_LINEAR: + in = incoming( ekey->prev, ekey ) + / ( ekey->time - ekey->prev->time ); + return in * ( time - ekey->time ) + ekey->value; + } + } + + /* get the endpoints of the interval being evaluated */ + + key0 = env->key; + while ( time > key0->next->time ) + key0 = key0->next; + key1 = key0->next; + + /* check for singularities first */ + + if ( time == key0->time ) + return key0->value + offset; + else if ( time == key1->time ) + return key1->value + offset; + + /* get interval length, time in [0, 1] */ + + t = ( time - key0->time ) / ( key1->time - key0->time ); + + /* interpolate */ + + switch ( key1->shape ) + { + case ID_TCB: + case ID_BEZI: + case ID_HERM: + out = outgoing( key0, key1 ); + in = incoming( key0, key1 ); + hermite( t, &h1, &h2, &h3, &h4 ); + return h1 * key0->value + h2 * key1->value + h3 * out + h4 * in + offset; + + case ID_BEZ2: + return bez2( key0, key1, time ) + offset; + + case ID_LINE: + return key0->value + t * ( key1->value - key0->value ) + offset; + + case ID_STEP: + return key0->value + offset; + + default: + return offset; + } +} diff --git a/libs/picomodel/lwo/list.c b/libs/picomodel/lwo/list.c new file mode 100644 index 00000000..d07b0337 --- /dev/null +++ b/libs/picomodel/lwo/list.c @@ -0,0 +1,101 @@ +/* +====================================================================== +list.c + +Generic linked list operations. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + + +/* +====================================================================== +lwListFree() + +Free the items in a list. +====================================================================== */ + +void lwListFree( void *list, void ( *freeNode )( void * )) +{ + lwNode *node, *next; + + node = ( lwNode * ) list; + while ( node ) { + next = node->next; + freeNode( node ); + node = next; + } +} + + +/* +====================================================================== +lwListAdd() + +Append a node to a list. +====================================================================== */ + +void lwListAdd( void **list, void *node ) +{ + lwNode *head, *tail; + + head = *(( lwNode ** ) list ); + if ( !head ) { + *list = node; + return; + } + while ( head ) { + tail = head; + head = head->next; + } + tail->next = ( lwNode * ) node; + (( lwNode * ) node )->prev = tail; +} + + +/* +====================================================================== +lwListInsert() + +Insert a node into a list in sorted order. +====================================================================== */ + +void lwListInsert( void **vlist, void *vitem, int ( *compare )( void *, void * )) +{ + lwNode **list, *item, *node, *prev; + + if ( !*vlist ) { + *vlist = vitem; + return; + } + + list = ( lwNode ** ) vlist; + item = ( lwNode * ) vitem; + node = *list; + prev = NULL; + + while ( node ) { + if ( 0 < compare( node, item )) break; + prev = node; + node = node->next; + } + + if ( !prev ) { + *list = item; + node->prev = item; + item->next = node; + } + else if ( !node ) { + prev->next = item; + item->prev = prev; + } + else { + item->next = node; + item->prev = prev; + prev->next = item; + node->prev = item; + } +} diff --git a/libs/picomodel/lwo/lwio.c b/libs/picomodel/lwo/lwio.c new file mode 100644 index 00000000..eea380bf --- /dev/null +++ b/libs/picomodel/lwo/lwio.c @@ -0,0 +1,442 @@ +/* +====================================================================== +lwio.c + +Functions for reading basic LWO2 data types. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + + +/* +====================================================================== +flen + +This accumulates a count of the number of bytes read. Callers can set +it at the beginning of a sequence of reads and then retrieve it to get +the number of bytes actually read. If one of the I/O functions fails, +flen is set to an error code, after which the I/O functions ignore +read requests until flen is reset. +====================================================================== */ + +#define INT_MIN (-2147483647 - 1) /* minimum (signed) int value */ +#define FLEN_ERROR INT_MIN + +static int flen; + +void set_flen( int i ) { flen = i; } + +int get_flen( void ) { return flen; } + + +#ifdef _WIN32 +/* +===================================================================== +revbytes() + +Reverses byte order in place. + +INPUTS + bp bytes to reverse + elsize size of the underlying data type + elcount number of elements to swap + +RESULTS + Reverses the byte order in each of elcount elements. + +This only needs to be defined on little-endian platforms, most +notably Windows. lwo2.h replaces this with a #define on big-endian +platforms. +===================================================================== */ + +void revbytes( void *bp, int elsize, int elcount ) +{ + register unsigned char *p, *q; + + p = ( unsigned char * ) bp; + + if ( elsize == 2 ) { + q = p + 1; + while ( elcount-- ) { + *p ^= *q; + *q ^= *p; + *p ^= *q; + p += 2; + q += 2; + } + return; + } + + while ( elcount-- ) { + q = p + elsize - 1; + while ( p < q ) { + *p ^= *q; + *q ^= *p; + *p ^= *q; + ++p; + --q; + } + p += elsize >> 1; + } +} +#endif + + +void *getbytes( picoMemStream_t *fp, int size ) +{ + void *data; + + if ( flen == FLEN_ERROR ) return NULL; + if ( size < 0 ) { + flen = FLEN_ERROR; + return NULL; + } + data = _pico_alloc( size ); + if ( !data ) { + flen = FLEN_ERROR; + return NULL; + } + if ( 1 != _pico_memstream_read( fp, data, size )) { + flen = FLEN_ERROR; + _pico_free( data ); + return NULL; + } + + flen += size; + return data; +} + + +void skipbytes( picoMemStream_t *fp, int n ) +{ + if ( flen == FLEN_ERROR ) return; + if ( _pico_memstream_seek( fp, n, PICO_SEEK_CUR )) + flen = FLEN_ERROR; + else + flen += n; +} + + +int getI1( picoMemStream_t *fp ) +{ + int i; + + if ( flen == FLEN_ERROR ) return 0; + i = _pico_memstream_getc( fp ); + if ( i < 0 ) { + flen = FLEN_ERROR; + return 0; + } + if ( i > 127 ) i -= 256; + flen += 1; + return i; +} + + +short getI2( picoMemStream_t *fp ) +{ + short i; + + if ( flen == FLEN_ERROR ) return 0; + if ( 1 != _pico_memstream_read( fp, &i, 2 )) { + flen = FLEN_ERROR; + return 0; + } + revbytes( &i, 2, 1 ); + flen += 2; + return i; +} + + +int getI4( picoMemStream_t *fp ) +{ + int i; + + if ( flen == FLEN_ERROR ) return 0; + if ( 1 != _pico_memstream_read( fp, &i, 4 )) { + flen = FLEN_ERROR; + return 0; + } + revbytes( &i, 4, 1 ); + flen += 4; + return i; +} + + +unsigned char getU1( picoMemStream_t *fp ) +{ + int i; + + if ( flen == FLEN_ERROR ) return 0; + i = _pico_memstream_getc( fp ); + if ( i < 0 ) { + flen = FLEN_ERROR; + return 0; + } + flen += 1; + return i; +} + + +unsigned short getU2( picoMemStream_t *fp ) +{ + unsigned short i; + + if ( flen == FLEN_ERROR ) return 0; + if ( 1 != _pico_memstream_read( fp, &i, 2 )) { + flen = FLEN_ERROR; + return 0; + } + revbytes( &i, 2, 1 ); + flen += 2; + return i; +} + + +unsigned int getU4( picoMemStream_t *fp ) +{ + unsigned int i; + + if ( flen == FLEN_ERROR ) return 0; + if ( 1 != _pico_memstream_read( fp, &i, 4 )) { + flen = FLEN_ERROR; + return 0; + } + revbytes( &i, 4, 1 ); + flen += 4; + return i; +} + + +int getVX( picoMemStream_t *fp ) +{ + int i, c; + + if ( flen == FLEN_ERROR ) return 0; + + c = _pico_memstream_getc( fp ); + if ( c != 0xFF ) { + i = c << 8; + c = _pico_memstream_getc( fp ); + i |= c; + flen += 2; + } + else { + c = _pico_memstream_getc( fp ); + i = c << 16; + c = _pico_memstream_getc( fp ); + i |= c << 8; + c = _pico_memstream_getc( fp ); + i |= c; + flen += 4; + } + + if ( _pico_memstream_error( fp )) { + flen = FLEN_ERROR; + return 0; + } + return i; +} + + +float getF4( picoMemStream_t *fp ) +{ + float f; + + if ( flen == FLEN_ERROR ) return 0.0f; + if ( 1 != _pico_memstream_read( fp, &f, 4 )) { + flen = FLEN_ERROR; + return 0.0f; + } + revbytes( &f, 4, 1 ); + flen += 4; + return f; +} + + +char *getS0( picoMemStream_t *fp ) +{ + char *s; + int i, c, len, pos; + + if ( flen == FLEN_ERROR ) return NULL; + + pos = _pico_memstream_tell( fp ); + for ( i = 1; ; i++ ) { + c = _pico_memstream_getc( fp ); + if ( c <= 0 ) break; + } + if ( c < 0 ) { + flen = FLEN_ERROR; + return NULL; + } + + if ( i == 1 ) { + if ( _pico_memstream_seek( fp, pos + 2, PICO_SEEK_SET )) + flen = FLEN_ERROR; + else + flen += 2; + return NULL; + } + + len = i + ( i & 1 ); + s = _pico_alloc( len ); + if ( !s ) { + flen = FLEN_ERROR; + return NULL; + } + + if ( _pico_memstream_seek( fp, pos, PICO_SEEK_SET )) { + flen = FLEN_ERROR; + return NULL; + } + if ( 1 != _pico_memstream_read( fp, s, len )) { + flen = FLEN_ERROR; + return NULL; + } + + flen += len; + return s; +} + + +int sgetI1( unsigned char **bp ) +{ + int i; + + if ( flen == FLEN_ERROR ) return 0; + i = **bp; + if ( i > 127 ) i -= 256; + flen += 1; + *bp++; + return i; +} + + +short sgetI2( unsigned char **bp ) +{ + short i; + + if ( flen == FLEN_ERROR ) return 0; + memcpy( &i, *bp, 2 ); + revbytes( &i, 2, 1 ); + flen += 2; + *bp += 2; + return i; +} + + +int sgetI4( unsigned char **bp ) +{ + int i; + + if ( flen == FLEN_ERROR ) return 0; + memcpy( &i, *bp, 4 ); + revbytes( &i, 4, 1 ); + flen += 4; + *bp += 4; + return i; +} + + +unsigned char sgetU1( unsigned char **bp ) +{ + unsigned char c; + + if ( flen == FLEN_ERROR ) return 0; + c = **bp; + flen += 1; + *bp++; + return c; +} + + +unsigned short sgetU2( unsigned char **bp ) +{ + unsigned char *buf = *bp; + unsigned short i; + + if ( flen == FLEN_ERROR ) return 0; + i = ( buf[ 0 ] << 8 ) | buf[ 1 ]; + flen += 2; + *bp += 2; + return i; +} + + +unsigned int sgetU4( unsigned char **bp ) +{ + unsigned int i; + + if ( flen == FLEN_ERROR ) return 0; + memcpy( &i, *bp, 4 ); + revbytes( &i, 4, 1 ); + flen += 4; + *bp += 4; + return i; +} + + +int sgetVX( unsigned char **bp ) +{ + unsigned char *buf = *bp; + int i; + + if ( flen == FLEN_ERROR ) return 0; + + if ( buf[ 0 ] != 0xFF ) { + i = buf[ 0 ] << 8 | buf[ 1 ]; + flen += 2; + *bp += 2; + } + else { + i = ( buf[ 1 ] << 16 ) | ( buf[ 2 ] << 8 ) | buf[ 3 ]; + flen += 4; + *bp += 4; + } + return i; +} + + +float sgetF4( unsigned char **bp ) +{ + float f; + + if ( flen == FLEN_ERROR ) return 0.0f; + memcpy( &f, *bp, 4 ); + revbytes( &f, 4, 1 ); + flen += 4; + *bp += 4; + return f; +} + + +char *sgetS0( unsigned char **bp ) +{ + char *s; + unsigned char *buf = *bp; + int len; + + if ( flen == FLEN_ERROR ) return NULL; + + len = strlen( buf ) + 1; + if ( len == 1 ) { + flen += 2; + *bp += 2; + return NULL; + } + len += len & 1; + s = _pico_alloc( len ); + if ( !s ) { + flen = FLEN_ERROR; + return NULL; + } + + memcpy( s, buf, len ); + flen += len; + *bp += len; + return s; +} diff --git a/libs/picomodel/lwo/lwo2.c b/libs/picomodel/lwo/lwo2.c new file mode 100644 index 00000000..1d72af7d --- /dev/null +++ b/libs/picomodel/lwo/lwo2.c @@ -0,0 +1,308 @@ +/* +====================================================================== +lwo2.c + +The entry point for loading LightWave object files. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + +/* disable warnings */ +#ifdef _WIN32 +#pragma warning( disable:4018 ) /* signed/unsigned mismatch */ +#endif + + +/* +====================================================================== +lwFreeLayer() + +Free memory used by an lwLayer. +====================================================================== */ + +void lwFreeLayer( lwLayer *layer ) +{ + if ( layer ) { + if ( layer->name ) _pico_free( layer->name ); + lwFreePoints( &layer->point ); + lwFreePolygons( &layer->polygon ); + lwListFree( layer->vmap, lwFreeVMap ); + _pico_free( layer ); + } +} + + +/* +====================================================================== +lwFreeObject() + +Free memory used by an lwObject. +====================================================================== */ + +void lwFreeObject( lwObject *object ) +{ + if ( object ) { + lwListFree( object->layer, lwFreeLayer ); + lwListFree( object->env, lwFreeEnvelope ); + lwListFree( object->clip, lwFreeClip ); + lwListFree( object->surf, lwFreeSurface ); + lwFreeTags( &object->taglist ); + _pico_free( object ); + } +} + + +/* +====================================================================== +lwGetObject() + +Returns the contents of a LightWave object, given its filename, or +NULL if the file couldn't be loaded. On failure, failID and failpos +can be used to diagnose the cause. + +1. If the file isn't an LWO2 or an LWOB, failpos will contain 12 and + failID will be unchanged. + +2. If an error occurs while reading, failID will contain the most + recently read IFF chunk ID, and failpos will contain the value + returned by _pico_memstream_tell() at the time of the failure. + +3. If the file couldn't be opened, or an error occurs while reading + the first 12 bytes, both failID and failpos will be unchanged. + +If you don't need this information, failID and failpos can be NULL. +====================================================================== */ + +lwObject *lwGetObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ) +{ + lwObject *object; + lwLayer *layer; + lwNode *node; + unsigned int id, formsize, type, cksize; + int i, rlen; + + /* open the file */ + + if ( !fp ) return NULL; + + /* read the first 12 bytes */ + + set_flen( 0 ); + id = getU4( fp ); + formsize = getU4( fp ); + type = getU4( fp ); + if ( 12 != get_flen() ) { + return NULL; + } + + /* is this a LW object? */ + + if ( id != ID_FORM ) { + if ( failpos ) *failpos = 12; + return NULL; + } + + if ( type != ID_LWO2 ) { + if ( type == ID_LWOB ) + return lwGetObject5( filename, fp, failID, failpos ); + else { + if ( failpos ) *failpos = 12; + return NULL; + } + } + + /* allocate an object and a default layer */ + + object = _pico_calloc( 1, sizeof( lwObject )); + if ( !object ) goto Fail; + + layer = _pico_calloc( 1, sizeof( lwLayer )); + if ( !layer ) goto Fail; + object->layer = layer; + + /* get the first chunk header */ + + id = getU4( fp ); + cksize = getU4( fp ); + if ( 0 > get_flen() ) goto Fail; + + /* process chunks as they're encountered */ + + while ( 1 ) { + cksize += cksize & 1; + + switch ( id ) + { + case ID_LAYR: + if ( object->nlayers > 0 ) { + layer = _pico_calloc( 1, sizeof( lwLayer )); + if ( !layer ) goto Fail; + lwListAdd( &object->layer, layer ); + } + object->nlayers++; + + set_flen( 0 ); + layer->index = getU2( fp ); + layer->flags = getU2( fp ); + layer->pivot[ 0 ] = getF4( fp ); + layer->pivot[ 1 ] = getF4( fp ); + layer->pivot[ 2 ] = getF4( fp ); + layer->name = getS0( fp ); + + rlen = get_flen(); + if ( rlen < 0 || rlen > cksize ) goto Fail; + if ( rlen <= cksize - 2 ) + layer->parent = getU2( fp ); + rlen = get_flen(); + if ( rlen < cksize ) + _pico_memstream_seek( fp, cksize - rlen, PICO_SEEK_CUR ); + break; + + case ID_PNTS: + if ( !lwGetPoints( fp, cksize, &layer->point )) + goto Fail; + break; + + case ID_POLS: + if ( !lwGetPolygons( fp, cksize, &layer->polygon, + layer->point.offset )) + goto Fail; + break; + + case ID_VMAP: + case ID_VMAD: + node = ( lwNode * ) lwGetVMap( fp, cksize, layer->point.offset, + layer->polygon.offset, id == ID_VMAD ); + if ( !node ) goto Fail; + lwListAdd( &layer->vmap, node ); + layer->nvmaps++; + break; + + case ID_PTAG: + if ( !lwGetPolygonTags( fp, cksize, &object->taglist, + &layer->polygon )) + goto Fail; + break; + + case ID_BBOX: + set_flen( 0 ); + for ( i = 0; i < 6; i++ ) + layer->bbox[ i ] = getF4( fp ); + rlen = get_flen(); + if ( rlen < 0 || rlen > cksize ) goto Fail; + if ( rlen < cksize ) + _pico_memstream_seek( fp, cksize - rlen, PICO_SEEK_CUR ); + break; + + case ID_TAGS: + if ( !lwGetTags( fp, cksize, &object->taglist )) + goto Fail; + break; + + case ID_ENVL: + node = ( lwNode * ) lwGetEnvelope( fp, cksize ); + if ( !node ) goto Fail; + lwListAdd( &object->env, node ); + object->nenvs++; + break; + + case ID_CLIP: + node = ( lwNode * ) lwGetClip( fp, cksize ); + if ( !node ) goto Fail; + lwListAdd( &object->clip, node ); + object->nclips++; + break; + + case ID_SURF: + node = ( lwNode * ) lwGetSurface( fp, cksize ); + if ( !node ) goto Fail; + lwListAdd( &object->surf, node ); + object->nsurfs++; + break; + + case ID_DESC: + case ID_TEXT: + case ID_ICON: + default: + _pico_memstream_seek( fp, cksize, PICO_SEEK_CUR ); + break; + } + + /* end of the file? */ + + if ( formsize <= _pico_memstream_tell( fp ) - 8 ) break; + + /* get the next chunk header */ + + set_flen( 0 ); + id = getU4( fp ); + cksize = getU4( fp ); + if ( 8 != get_flen() ) goto Fail; + } + + if ( object->nlayers == 0 ) + object->nlayers = 1; + + layer = object->layer; + while ( layer ) { + lwGetBoundingBox( &layer->point, layer->bbox ); + lwGetPolyNormals( &layer->point, &layer->polygon ); + if ( !lwGetPointPolygons( &layer->point, &layer->polygon )) goto Fail; + if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist, + &object->surf, &object->nsurfs )) goto Fail; + lwGetVertNormals( &layer->point, &layer->polygon ); + if ( !lwGetPointVMaps( &layer->point, layer->vmap )) goto Fail; + if ( !lwGetPolyVMaps( &layer->polygon, layer->vmap )) goto Fail; + layer = layer->next; + } + + return object; + +Fail: + if ( failID ) *failID = id; + if ( fp ) { + if ( failpos ) *failpos = _pico_memstream_tell( fp ); + } + lwFreeObject( object ); + return NULL; +} + +int lwValidateObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ) +{ + unsigned int id, formsize, type; + + /* open the file */ + + if ( !fp ) return PICO_PMV_ERROR_MEMORY; + + /* read the first 12 bytes */ + + set_flen( 0 ); + id = getU4( fp ); + formsize = getU4( fp ); + type = getU4( fp ); + if ( 12 != get_flen() ) { + return PICO_PMV_ERROR_SIZE; + } + + /* is this a LW object? */ + + if ( id != ID_FORM ) { + if ( failpos ) *failpos = 12; + return PICO_PMV_ERROR_SIZE; + } + + if ( type != ID_LWO2 ) { + if ( type == ID_LWOB ) + return lwValidateObject5( filename, fp, failID, failpos ); + else { + if ( failpos ) *failpos = 12; + return PICO_PMV_ERROR_IDENT; + } + } + + return PICO_PMV_OK; +} diff --git a/libs/picomodel/lwo/lwo2.h b/libs/picomodel/lwo/lwo2.h new file mode 100644 index 00000000..1fe1dd97 --- /dev/null +++ b/libs/picomodel/lwo/lwo2.h @@ -0,0 +1,651 @@ +/* +====================================================================== +lwo2.h + +Definitions and typedefs for LWO2 files. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#ifndef LWO2_H +#define LWO2_H + +/* chunk and subchunk IDs */ + +#define LWID_(a,b,c,d) (((a)<<24)|((b)<<16)|((c)<<8)|(d)) + +#define ID_FORM LWID_('F','O','R','M') +#define ID_LWO2 LWID_('L','W','O','2') +#define ID_LWOB LWID_('L','W','O','B') + +/* top-level chunks */ +#define ID_LAYR LWID_('L','A','Y','R') +#define ID_TAGS LWID_('T','A','G','S') +#define ID_PNTS LWID_('P','N','T','S') +#define ID_BBOX LWID_('B','B','O','X') +#define ID_VMAP LWID_('V','M','A','P') +#define ID_VMAD LWID_('V','M','A','D') +#define ID_POLS LWID_('P','O','L','S') +#define ID_PTAG LWID_('P','T','A','G') +#define ID_ENVL LWID_('E','N','V','L') +#define ID_CLIP LWID_('C','L','I','P') +#define ID_SURF LWID_('S','U','R','F') +#define ID_DESC LWID_('D','E','S','C') +#define ID_TEXT LWID_('T','E','X','T') +#define ID_ICON LWID_('I','C','O','N') + +/* polygon types */ +#define ID_FACE LWID_('F','A','C','E') +#define ID_CURV LWID_('C','U','R','V') +#define ID_PTCH LWID_('P','T','C','H') +#define ID_MBAL LWID_('M','B','A','L') +#define ID_BONE LWID_('B','O','N','E') + +/* polygon tags */ +#define ID_SURF LWID_('S','U','R','F') +#define ID_PART LWID_('P','A','R','T') +#define ID_SMGP LWID_('S','M','G','P') + +/* envelopes */ +#define ID_PRE LWID_('P','R','E',' ') +#define ID_POST LWID_('P','O','S','T') +#define ID_KEY LWID_('K','E','Y',' ') +#define ID_SPAN LWID_('S','P','A','N') +#define ID_TCB LWID_('T','C','B',' ') +#define ID_HERM LWID_('H','E','R','M') +#define ID_BEZI LWID_('B','E','Z','I') +#define ID_BEZ2 LWID_('B','E','Z','2') +#define ID_LINE LWID_('L','I','N','E') +#define ID_STEP LWID_('S','T','E','P') + +/* clips */ +#define ID_STIL LWID_('S','T','I','L') +#define ID_ISEQ LWID_('I','S','E','Q') +#define ID_ANIM LWID_('A','N','I','M') +#define ID_XREF LWID_('X','R','E','F') +#define ID_STCC LWID_('S','T','C','C') +#define ID_TIME LWID_('T','I','M','E') +#define ID_CONT LWID_('C','O','N','T') +#define ID_BRIT LWID_('B','R','I','T') +#define ID_SATR LWID_('S','A','T','R') +#define ID_HUE LWID_('H','U','E',' ') +#define ID_GAMM LWID_('G','A','M','M') +#define ID_NEGA LWID_('N','E','G','A') +#define ID_IFLT LWID_('I','F','L','T') +#define ID_PFLT LWID_('P','F','L','T') + +/* surfaces */ +#define ID_COLR LWID_('C','O','L','R') +#define ID_LUMI LWID_('L','U','M','I') +#define ID_DIFF LWID_('D','I','F','F') +#define ID_SPEC LWID_('S','P','E','C') +#define ID_GLOS LWID_('G','L','O','S') +#define ID_REFL LWID_('R','E','F','L') +#define ID_RFOP LWID_('R','F','O','P') +#define ID_RIMG LWID_('R','I','M','G') +#define ID_RSAN LWID_('R','S','A','N') +#define ID_TRAN LWID_('T','R','A','N') +#define ID_TROP LWID_('T','R','O','P') +#define ID_TIMG LWID_('T','I','M','G') +#define ID_RIND LWID_('R','I','N','D') +#define ID_TRNL LWID_('T','R','N','L') +#define ID_BUMP LWID_('B','U','M','P') +#define ID_SMAN LWID_('S','M','A','N') +#define ID_SIDE LWID_('S','I','D','E') +#define ID_CLRH LWID_('C','L','R','H') +#define ID_CLRF LWID_('C','L','R','F') +#define ID_ADTR LWID_('A','D','T','R') +#define ID_SHRP LWID_('S','H','R','P') +#define ID_LINE LWID_('L','I','N','E') +#define ID_LSIZ LWID_('L','S','I','Z') +#define ID_ALPH LWID_('A','L','P','H') +#define ID_AVAL LWID_('A','V','A','L') +#define ID_GVAL LWID_('G','V','A','L') +#define ID_BLOK LWID_('B','L','O','K') + +/* texture layer */ +#define ID_TYPE LWID_('T','Y','P','E') +#define ID_CHAN LWID_('C','H','A','N') +#define ID_NAME LWID_('N','A','M','E') +#define ID_ENAB LWID_('E','N','A','B') +#define ID_OPAC LWID_('O','P','A','C') +#define ID_FLAG LWID_('F','L','A','G') +#define ID_PROJ LWID_('P','R','O','J') +#define ID_STCK LWID_('S','T','C','K') +#define ID_TAMP LWID_('T','A','M','P') + +/* texture coordinates */ +#define ID_TMAP LWID_('T','M','A','P') +#define ID_AXIS LWID_('A','X','I','S') +#define ID_CNTR LWID_('C','N','T','R') +#define ID_SIZE LWID_('S','I','Z','E') +#define ID_ROTA LWID_('R','O','T','A') +#define ID_OREF LWID_('O','R','E','F') +#define ID_FALL LWID_('F','A','L','L') +#define ID_CSYS LWID_('C','S','Y','S') + +/* image map */ +#define ID_IMAP LWID_('I','M','A','P') +#define ID_IMAG LWID_('I','M','A','G') +#define ID_WRAP LWID_('W','R','A','P') +#define ID_WRPW LWID_('W','R','P','W') +#define ID_WRPH LWID_('W','R','P','H') +#define ID_VMAP LWID_('V','M','A','P') +#define ID_AAST LWID_('A','A','S','T') +#define ID_PIXB LWID_('P','I','X','B') + +/* procedural */ +#define ID_PROC LWID_('P','R','O','C') +#define ID_COLR LWID_('C','O','L','R') +#define ID_VALU LWID_('V','A','L','U') +#define ID_FUNC LWID_('F','U','N','C') +#define ID_FTPS LWID_('F','T','P','S') +#define ID_ITPS LWID_('I','T','P','S') +#define ID_ETPS LWID_('E','T','P','S') + +/* gradient */ +#define ID_GRAD LWID_('G','R','A','D') +#define ID_GRST LWID_('G','R','S','T') +#define ID_GREN LWID_('G','R','E','N') +#define ID_PNAM LWID_('P','N','A','M') +#define ID_INAM LWID_('I','N','A','M') +#define ID_GRPT LWID_('G','R','P','T') +#define ID_FKEY LWID_('F','K','E','Y') +#define ID_IKEY LWID_('I','K','E','Y') + +/* shader */ +#define ID_SHDR LWID_('S','H','D','R') +#define ID_DATA LWID_('D','A','T','A') + + +/* generic linked list */ + +typedef struct st_lwNode { + struct st_lwNode *next, *prev; + void *data; +} lwNode; + + +/* plug-in reference */ + +typedef struct st_lwPlugin { + struct st_lwPlugin *next, *prev; + char *ord; + char *name; + int flags; + void *data; +} lwPlugin; + + +/* envelopes */ + +typedef struct st_lwKey { + struct st_lwKey *next, *prev; + float value; + float time; + unsigned int shape; /* ID_TCB, ID_BEZ2, etc. */ + float tension; + float continuity; + float bias; + float param[ 4 ]; +} lwKey; + +typedef struct st_lwEnvelope { + struct st_lwEnvelope *next, *prev; + int index; + int type; + char *name; + lwKey *key; /* linked list of keys */ + int nkeys; + int behavior[ 2 ]; /* pre and post (extrapolation) */ + lwPlugin *cfilter; /* linked list of channel filters */ + int ncfilters; +} lwEnvelope; + +#define BEH_RESET 0 +#define BEH_CONSTANT 1 +#define BEH_REPEAT 2 +#define BEH_OSCILLATE 3 +#define BEH_OFFSET 4 +#define BEH_LINEAR 5 + + +/* values that can be enveloped */ + +typedef struct st_lwEParam { + float val; + int eindex; +} lwEParam; + +typedef struct st_lwVParam { + float val[ 3 ]; + int eindex; +} lwVParam; + + +/* clips */ + +typedef struct st_lwClipStill { + char *name; +} lwClipStill; + +typedef struct st_lwClipSeq { + char *prefix; /* filename before sequence digits */ + char *suffix; /* after digits, e.g. extensions */ + int digits; + int flags; + int offset; + int start; + int end; +} lwClipSeq; + +typedef struct st_lwClipAnim { + char *name; + char *server; /* anim loader plug-in */ + void *data; +} lwClipAnim; + +typedef struct st_lwClipXRef { + char *string; + int index; + struct st_lwClip *clip; +} lwClipXRef; + +typedef struct st_lwClipCycle { + char *name; + int lo; + int hi; +} lwClipCycle; + +typedef struct st_lwClip { + struct st_lwClip *next, *prev; + int index; + unsigned int type; /* ID_STIL, ID_ISEQ, etc. */ + union { + lwClipStill still; + lwClipSeq seq; + lwClipAnim anim; + lwClipXRef xref; + lwClipCycle cycle; + } source; + float start_time; + float duration; + float frame_rate; + lwEParam contrast; + lwEParam brightness; + lwEParam saturation; + lwEParam hue; + lwEParam gamma; + int negative; + lwPlugin *ifilter; /* linked list of image filters */ + int nifilters; + lwPlugin *pfilter; /* linked list of pixel filters */ + int npfilters; +} lwClip; + + +/* textures */ + +typedef struct st_lwTMap { + lwVParam size; + lwVParam center; + lwVParam rotate; + lwVParam falloff; + int fall_type; + char *ref_object; + int coord_sys; +} lwTMap; + +typedef struct st_lwImageMap { + int cindex; + int projection; + char *vmap_name; + int axis; + int wrapw_type; + int wraph_type; + lwEParam wrapw; + lwEParam wraph; + float aa_strength; + int aas_flags; + int pblend; + lwEParam stck; + lwEParam amplitude; +} lwImageMap; + +#define PROJ_PLANAR 0 +#define PROJ_CYLINDRICAL 1 +#define PROJ_SPHERICAL 2 +#define PROJ_CUBIC 3 +#define PROJ_FRONT 4 + +#define WRAP_NONE 0 +#define WRAP_EDGE 1 +#define WRAP_REPEAT 2 +#define WRAP_MIRROR 3 + +typedef struct st_lwProcedural { + int axis; + float value[ 3 ]; + char *name; + void *data; +} lwProcedural; + +typedef struct st_lwGradKey { + struct st_lwGradKey *next, *prev; + float value; + float rgba[ 4 ]; +} lwGradKey; + +typedef struct st_lwGradient { + char *paramname; + char *itemname; + float start; + float end; + int repeat; + lwGradKey *key; /* array of gradient keys */ + short *ikey; /* array of interpolation codes */ +} lwGradient; + +typedef struct st_lwTexture { + struct st_lwTexture *next, *prev; + char *ord; + unsigned int type; + unsigned int chan; + lwEParam opacity; + short opac_type; + short enabled; + short negative; + short axis; + union { + lwImageMap imap; + lwProcedural proc; + lwGradient grad; + } param; + lwTMap tmap; +} lwTexture; + + +/* values that can be textured */ + +typedef struct st_lwTParam { + float val; + int eindex; + lwTexture *tex; /* linked list of texture layers */ +} lwTParam; + +typedef struct st_lwCParam { + float rgb[ 3 ]; + int eindex; + lwTexture *tex; /* linked list of texture layers */ +} lwCParam; + + +/* surfaces */ + +typedef struct st_lwGlow { + short enabled; + short type; + lwEParam intensity; + lwEParam size; +} Glow; + +typedef struct st_lwRMap { + lwTParam val; + int options; + int cindex; + float seam_angle; +} lwRMap; + +typedef struct st_lwLine { + short enabled; + unsigned short flags; + lwEParam size; +} lwLine; + +typedef struct st_lwSurface { + struct st_lwSurface *next, *prev; + char *name; + char *srcname; + lwCParam color; + lwTParam luminosity; + lwTParam diffuse; + lwTParam specularity; + lwTParam glossiness; + lwRMap reflection; + lwRMap transparency; + lwTParam eta; + lwTParam translucency; + lwTParam bump; + float smooth; + int sideflags; + float alpha; + int alpha_mode; + lwEParam color_hilite; + lwEParam color_filter; + lwEParam add_trans; + lwEParam dif_sharp; + lwEParam glow; + lwLine line; + lwPlugin *shader; /* linked list of shaders */ + int nshaders; +} lwSurface; + + +/* vertex maps */ + +typedef struct st_lwVMap { + struct st_lwVMap *next, *prev; + char *name; + unsigned int type; + int dim; + int nverts; + int perpoly; + int *vindex; /* array of point indexes */ + int *pindex; /* array of polygon indexes */ + float **val; +} lwVMap; + +typedef struct st_lwVMapPt { + lwVMap *vmap; + int index; /* vindex or pindex element */ +} lwVMapPt; + + +/* points and polygons */ + +typedef struct st_lwPoint { + float pos[ 3 ]; + int npols; /* number of polygons sharing the point */ + int *pol; /* array of polygon indexes */ + int nvmaps; + lwVMapPt *vm; /* array of vmap references */ +} lwPoint; + +typedef struct st_lwPolVert { + int index; /* index into the point array */ + float norm[ 3 ]; + int nvmaps; + lwVMapPt *vm; /* array of vmap references */ +} lwPolVert; + +typedef struct st_lwPolygon { + lwSurface *surf; + int part; /* part index */ + int smoothgrp; /* smoothing group */ + int flags; + unsigned int type; + float norm[ 3 ]; + int nverts; + lwPolVert *v; /* array of vertex records */ +} lwPolygon; + +typedef struct st_lwPointList { + int count; + int offset; /* only used during reading */ + lwPoint *pt; /* array of points */ +} lwPointList; + +typedef struct st_lwPolygonList { + int count; + int offset; /* only used during reading */ + int vcount; /* total number of vertices */ + int voffset; /* only used during reading */ + lwPolygon *pol; /* array of polygons */ +} lwPolygonList; + + +/* geometry layers */ + +typedef struct st_lwLayer { + struct st_lwLayer *next, *prev; + char *name; + int index; + int parent; + int flags; + float pivot[ 3 ]; + float bbox[ 6 ]; + lwPointList point; + lwPolygonList polygon; + int nvmaps; + lwVMap *vmap; /* linked list of vmaps */ +} lwLayer; + + +/* tag strings */ + +typedef struct st_lwTagList { + int count; + int offset; /* only used during reading */ + char **tag; /* array of strings */ +} lwTagList; + + +/* an object */ + +typedef struct st_lwObject { + lwLayer *layer; /* linked list of layers */ + lwEnvelope *env; /* linked list of envelopes */ + lwClip *clip; /* linked list of clips */ + lwSurface *surf; /* linked list of surfaces */ + lwTagList taglist; + int nlayers; + int nenvs; + int nclips; + int nsurfs; +} lwObject; + + +/* lwo2.c */ + +void lwFreeLayer( lwLayer *layer ); +void lwFreeObject( lwObject *object ); +lwObject *lwGetObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ); +int lwValidateObject( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ); + +/* pntspols.c */ + +void lwFreePoints( lwPointList *point ); +void lwFreePolygons( lwPolygonList *plist ); +int lwGetPoints( picoMemStream_t *fp, int cksize, lwPointList *point ); +void lwGetBoundingBox( lwPointList *point, float bbox[] ); +int lwAllocPolygons( lwPolygonList *plist, int npols, int nverts ); +int lwGetPolygons( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ); +void lwGetPolyNormals( lwPointList *point, lwPolygonList *polygon ); +int lwGetPointPolygons( lwPointList *point, lwPolygonList *polygon ); +int lwResolvePolySurfaces( lwPolygonList *polygon, lwTagList *tlist, + lwSurface **surf, int *nsurfs ); +void lwGetVertNormals( lwPointList *point, lwPolygonList *polygon ); +void lwFreeTags( lwTagList *tlist ); +int lwGetTags( picoMemStream_t *fp, int cksize, lwTagList *tlist ); +int lwGetPolygonTags( picoMemStream_t *fp, int cksize, lwTagList *tlist, + lwPolygonList *plist ); + +/* vmap.c */ + +void lwFreeVMap( lwVMap *vmap ); +lwVMap *lwGetVMap( picoMemStream_t *fp, int cksize, int ptoffset, int poloffset, + int perpoly ); +int lwGetPointVMaps( lwPointList *point, lwVMap *vmap ); +int lwGetPolyVMaps( lwPolygonList *polygon, lwVMap *vmap ); + +/* clip.c */ + +void lwFreeClip( lwClip *clip ); +lwClip *lwGetClip( picoMemStream_t *fp, int cksize ); +lwClip *lwFindClip( lwClip *list, int index ); + +/* envelope.c */ + +void lwFreeEnvelope( lwEnvelope *env ); +lwEnvelope *lwGetEnvelope( picoMemStream_t *fp, int cksize ); +lwEnvelope *lwFindEnvelope( lwEnvelope *list, int index ); +float lwEvalEnvelope( lwEnvelope *env, float time ); + +/* surface.c */ + +void lwFreePlugin( lwPlugin *p ); +void lwFreeTexture( lwTexture *t ); +void lwFreeSurface( lwSurface *surf ); +int lwGetTHeader( picoMemStream_t *fp, int hsz, lwTexture *tex ); +int lwGetTMap( picoMemStream_t *fp, int tmapsz, lwTMap *tmap ); +int lwGetImageMap( picoMemStream_t *fp, int rsz, lwTexture *tex ); +int lwGetProcedural( picoMemStream_t *fp, int rsz, lwTexture *tex ); +int lwGetGradient( picoMemStream_t *fp, int rsz, lwTexture *tex ); +lwTexture *lwGetTexture( picoMemStream_t *fp, int bloksz, unsigned int type ); +lwPlugin *lwGetShader( picoMemStream_t *fp, int bloksz ); +lwSurface *lwGetSurface( picoMemStream_t *fp, int cksize ); +lwSurface *lwDefaultSurface( void ); + +/* lwob.c */ + +lwSurface *lwGetSurface5( picoMemStream_t *fp, int cksize, lwObject *obj ); +int lwGetPolygons5( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ); +lwObject *lwGetObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ); +int lwValidateObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ); + +/* list.c */ + +void lwListFree( void *list, void ( *freeNode )( void * )); +void lwListAdd( void **list, void *node ); +void lwListInsert( void **vlist, void *vitem, + int ( *compare )( void *, void * )); + +/* vecmath.c */ + +float dot( float a[], float b[] ); +void cross( float a[], float b[], float c[] ); +void normalize( float v[] ); +#define vecangle( a, b ) ( float ) acos( dot( a, b )) + +/* lwio.c */ + +void set_flen( int i ); +int get_flen( void ); +void *getbytes( picoMemStream_t *fp, int size ); +void skipbytes( picoMemStream_t *fp, int n ); +int getI1( picoMemStream_t *fp ); +short getI2( picoMemStream_t *fp ); +int getI4( picoMemStream_t *fp ); +unsigned char getU1( picoMemStream_t *fp ); +unsigned short getU2( picoMemStream_t *fp ); +unsigned int getU4( picoMemStream_t *fp ); +int getVX( picoMemStream_t *fp ); +float getF4( picoMemStream_t *fp ); +char *getS0( picoMemStream_t *fp ); +int sgetI1( unsigned char **bp ); +short sgetI2( unsigned char **bp ); +int sgetI4( unsigned char **bp ); +unsigned char sgetU1( unsigned char **bp ); +unsigned short sgetU2( unsigned char **bp ); +unsigned int sgetU4( unsigned char **bp ); +int sgetVX( unsigned char **bp ); +float sgetF4( unsigned char **bp ); +char *sgetS0( unsigned char **bp ); + +#ifdef _WIN32 + void revbytes( void *bp, int elsize, int elcount ); +#else + #define revbytes( b, s, c ) +#endif + +#endif diff --git a/libs/picomodel/lwo/lwob.c b/libs/picomodel/lwo/lwob.c new file mode 100644 index 00000000..0e386a30 --- /dev/null +++ b/libs/picomodel/lwo/lwob.c @@ -0,0 +1,723 @@ +/* +====================================================================== +lwob.c + +Functions for an LWOB reader. LWOB is the LightWave object format +for versions of LW prior to 6.0. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + +/* disable warnings */ +#ifdef _WIN32 +#pragma warning( disable:4018 ) /* signed/unsigned mismatch */ +#endif + + +/* IDs specific to LWOB */ + +#define ID_SRFS LWID_('S','R','F','S') +#define ID_FLAG LWID_('F','L','A','G') +#define ID_VLUM LWID_('V','L','U','M') +#define ID_VDIF LWID_('V','D','I','F') +#define ID_VSPC LWID_('V','S','P','C') +#define ID_RFLT LWID_('R','F','L','T') +#define ID_BTEX LWID_('B','T','E','X') +#define ID_CTEX LWID_('C','T','E','X') +#define ID_DTEX LWID_('D','T','E','X') +#define ID_LTEX LWID_('L','T','E','X') +#define ID_RTEX LWID_('R','T','E','X') +#define ID_STEX LWID_('S','T','E','X') +#define ID_TTEX LWID_('T','T','E','X') +#define ID_TFLG LWID_('T','F','L','G') +#define ID_TSIZ LWID_('T','S','I','Z') +#define ID_TCTR LWID_('T','C','T','R') +#define ID_TFAL LWID_('T','F','A','L') +#define ID_TVEL LWID_('T','V','E','L') +#define ID_TCLR LWID_('T','C','L','R') +#define ID_TVAL LWID_('T','V','A','L') +#define ID_TAMP LWID_('T','A','M','P') +#define ID_TIMG LWID_('T','I','M','G') +#define ID_TAAS LWID_('T','A','A','S') +#define ID_TREF LWID_('T','R','E','F') +#define ID_TOPC LWID_('T','O','P','C') +#define ID_SDAT LWID_('S','D','A','T') +#define ID_TFP0 LWID_('T','F','P','0') +#define ID_TFP1 LWID_('T','F','P','1') + + +/* +====================================================================== +add_clip() + +Add a clip to the clip list. Used to store the contents of an RIMG or +TIMG surface subchunk. +====================================================================== */ + +static int add_clip( char *s, lwClip **clist, int *nclips ) +{ + lwClip *clip; + char *p; + + clip = _pico_calloc( 1, sizeof( lwClip )); + if ( !clip ) return 0; + + clip->contrast.val = 1.0f; + clip->brightness.val = 1.0f; + clip->saturation.val = 1.0f; + clip->gamma.val = 1.0f; + + if ( p = strstr( s, "(sequence)" )) { + p[ -1 ] = 0; + clip->type = ID_ISEQ; + clip->source.seq.prefix = s; + clip->source.seq.digits = 3; + } + else { + clip->type = ID_STIL; + clip->source.still.name = s; + } + + *nclips++; + clip->index = *nclips; + + lwListAdd( clist, clip ); + + return clip->index; +} + + +/* +====================================================================== +add_tvel() + +Add a triple of envelopes to simulate the old texture velocity +parameters. +====================================================================== */ + +static int add_tvel( float pos[], float vel[], lwEnvelope **elist, int *nenvs ) +{ + lwEnvelope *env; + lwKey *key0, *key1; + int i; + + for ( i = 0; i < 3; i++ ) { + env = _pico_calloc( 1, sizeof( lwEnvelope )); + key0 = _pico_calloc( 1, sizeof( lwKey )); + key1 = _pico_calloc( 1, sizeof( lwKey )); + if ( !env || !key0 || !key1 ) return 0; + + key0->next = key1; + key0->value = pos[ i ]; + key0->time = 0.0f; + key1->prev = key0; + key1->value = pos[ i ] + vel[ i ] * 30.0f; + key1->time = 1.0f; + key0->shape = key1->shape = ID_LINE; + + env->index = *nenvs + i + 1; + env->type = 0x0301 + i; + env->name = _pico_alloc( 11 ); + if ( env->name ) { + strcpy( env->name, "Position.X" ); + env->name[ 9 ] += i; + } + env->key = key0; + env->nkeys = 2; + env->behavior[ 0 ] = BEH_LINEAR; + env->behavior[ 1 ] = BEH_LINEAR; + + lwListAdd( elist, env ); + } + + *nenvs += 3; + return env->index - 2; +} + + +/* +====================================================================== +get_texture() + +Create a new texture for BTEX, CTEX, etc. subchunks. +====================================================================== */ + +static lwTexture *get_texture( char *s ) +{ + lwTexture *tex; + + tex = _pico_calloc( 1, sizeof( lwTexture )); + if ( !tex ) return NULL; + + tex->tmap.size.val[ 0 ] = + tex->tmap.size.val[ 1 ] = + tex->tmap.size.val[ 2 ] = 1.0f; + tex->opacity.val = 1.0f; + tex->enabled = 1; + + if ( strstr( s, "Image Map" )) { + tex->type = ID_IMAP; + if ( strstr( s, "Planar" )) tex->param.imap.projection = 0; + else if ( strstr( s, "Cylindrical" )) tex->param.imap.projection = 1; + else if ( strstr( s, "Spherical" )) tex->param.imap.projection = 2; + else if ( strstr( s, "Cubic" )) tex->param.imap.projection = 3; + else if ( strstr( s, "Front" )) tex->param.imap.projection = 4; + tex->param.imap.aa_strength = 1.0f; + tex->param.imap.amplitude.val = 1.0f; + _pico_free( s ); + } + else { + tex->type = ID_PROC; + tex->param.proc.name = s; + } + + return tex; +} + + +/* +====================================================================== +lwGetSurface5() + +Read an lwSurface from an LWOB file. +====================================================================== */ + +lwSurface *lwGetSurface5( picoMemStream_t *fp, int cksize, lwObject *obj ) +{ + lwSurface *surf; + lwTexture *tex; + lwPlugin *shdr; + char *s; + float v[ 3 ]; + unsigned int id, flags; + unsigned short sz; + int pos, rlen, i; + + + /* allocate the Surface structure */ + + surf = _pico_calloc( 1, sizeof( lwSurface )); + if ( !surf ) goto Fail; + + /* non-zero defaults */ + + surf->color.rgb[ 0 ] = 0.78431f; + surf->color.rgb[ 1 ] = 0.78431f; + surf->color.rgb[ 2 ] = 0.78431f; + surf->diffuse.val = 1.0f; + surf->glossiness.val = 0.4f; + surf->bump.val = 1.0f; + surf->eta.val = 1.0f; + surf->sideflags = 1; + + /* remember where we started */ + + set_flen( 0 ); + pos = _pico_memstream_tell( fp ); + + /* name */ + + surf->name = getS0( fp ); + + /* first subchunk header */ + + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + /* process subchunks as they're encountered */ + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_COLR: + surf->color.rgb[ 0 ] = getU1( fp ) / 255.0f; + surf->color.rgb[ 1 ] = getU1( fp ) / 255.0f; + surf->color.rgb[ 2 ] = getU1( fp ) / 255.0f; + break; + + case ID_FLAG: + flags = getU2( fp ); + if ( flags & 4 ) surf->smooth = 1.56207f; + if ( flags & 8 ) surf->color_hilite.val = 1.0f; + if ( flags & 16 ) surf->color_filter.val = 1.0f; + if ( flags & 128 ) surf->dif_sharp.val = 0.5f; + if ( flags & 256 ) surf->sideflags = 3; + if ( flags & 512 ) surf->add_trans.val = 1.0f; + break; + + case ID_LUMI: + surf->luminosity.val = getI2( fp ) / 256.0f; + break; + + case ID_VLUM: + surf->luminosity.val = getF4( fp ); + break; + + case ID_DIFF: + surf->diffuse.val = getI2( fp ) / 256.0f; + break; + + case ID_VDIF: + surf->diffuse.val = getF4( fp ); + break; + + case ID_SPEC: + surf->specularity.val = getI2( fp ) / 256.0f; + break; + + case ID_VSPC: + surf->specularity.val = getF4( fp ); + break; + + case ID_GLOS: + surf->glossiness.val = ( float ) log( getU2( fp )) / 20.7944f; + break; + + case ID_SMAN: + surf->smooth = getF4( fp ); + break; + + case ID_REFL: + surf->reflection.val.val = getI2( fp ) / 256.0f; + break; + + case ID_RFLT: + surf->reflection.options = getU2( fp ); + break; + + case ID_RIMG: + s = getS0( fp ); + surf->reflection.cindex = add_clip( s, &obj->clip, &obj->nclips ); + surf->reflection.options = 3; + break; + + case ID_RSAN: + surf->reflection.seam_angle = getF4( fp ); + break; + + case ID_TRAN: + surf->transparency.val.val = getI2( fp ) / 256.0f; + break; + + case ID_RIND: + surf->eta.val = getF4( fp ); + break; + + case ID_BTEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->bump.tex, tex ); + break; + + case ID_CTEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->color.tex, tex ); + break; + + case ID_DTEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->diffuse.tex, tex ); + break; + + case ID_LTEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->luminosity.tex, tex ); + break; + + case ID_RTEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->reflection.val.tex, tex ); + break; + + case ID_STEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->specularity.tex, tex ); + break; + + case ID_TTEX: + s = getbytes( fp, sz ); + tex = get_texture( s ); + lwListAdd( &surf->transparency.val.tex, tex ); + break; + + case ID_TFLG: + flags = getU2( fp ); + + if ( flags & 1 ) i = 0; + if ( flags & 2 ) i = 1; + if ( flags & 4 ) i = 2; + tex->axis = i; + if ( tex->type == ID_IMAP ) + tex->param.imap.axis = i; + else + tex->param.proc.axis = i; + + if ( flags & 8 ) tex->tmap.coord_sys = 1; + if ( flags & 16 ) tex->negative = 1; + if ( flags & 32 ) tex->param.imap.pblend = 1; + if ( flags & 64 ) { + tex->param.imap.aa_strength = 1.0f; + tex->param.imap.aas_flags = 1; + } + break; + + case ID_TSIZ: + for ( i = 0; i < 3; i++ ) + tex->tmap.size.val[ i ] = getF4( fp ); + break; + + case ID_TCTR: + for ( i = 0; i < 3; i++ ) + tex->tmap.center.val[ i ] = getF4( fp ); + break; + + case ID_TFAL: + for ( i = 0; i < 3; i++ ) + tex->tmap.falloff.val[ i ] = getF4( fp ); + break; + + case ID_TVEL: + for ( i = 0; i < 3; i++ ) + v[ i ] = getF4( fp ); + tex->tmap.center.eindex = add_tvel( tex->tmap.center.val, v, + &obj->env, &obj->nenvs ); + break; + + case ID_TCLR: + if ( tex->type == ID_PROC ) + for ( i = 0; i < 3; i++ ) + tex->param.proc.value[ i ] = getU1( fp ) / 255.0f; + break; + + case ID_TVAL: + tex->param.proc.value[ 0 ] = getI2( fp ) / 256.0f; + break; + + case ID_TAMP: + if ( tex->type == ID_IMAP ) + tex->param.imap.amplitude.val = getF4( fp ); + break; + + case ID_TIMG: + s = getS0( fp ); + tex->param.imap.cindex = add_clip( s, &obj->clip, &obj->nclips ); + break; + + case ID_TAAS: + tex->param.imap.aa_strength = getF4( fp ); + tex->param.imap.aas_flags = 1; + break; + + case ID_TREF: + tex->tmap.ref_object = getbytes( fp, sz ); + break; + + case ID_TOPC: + tex->opacity.val = getF4( fp ); + break; + + case ID_TFP0: + if ( tex->type == ID_IMAP ) + tex->param.imap.wrapw.val = getF4( fp ); + break; + + case ID_TFP1: + if ( tex->type == ID_IMAP ) + tex->param.imap.wraph.val = getF4( fp ); + break; + + case ID_SHDR: + shdr = _pico_calloc( 1, sizeof( lwPlugin )); + if ( !shdr ) goto Fail; + shdr->name = getbytes( fp, sz ); + lwListAdd( &surf->shader, shdr ); + surf->nshaders++; + break; + + case ID_SDAT: + shdr->data = getbytes( fp, sz ); + break; + + default: + break; + } + + /* error while reading current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) goto Fail; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the SURF chunk? */ + + if ( cksize <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) goto Fail; + } + + return surf; + +Fail: + if ( surf ) lwFreeSurface( surf ); + return NULL; +} + + +/* +====================================================================== +lwGetPolygons5() + +Read polygon records from a POLS chunk in an LWOB file. The polygons +are added to the array in the lwPolygonList. +====================================================================== */ + +int lwGetPolygons5( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ) +{ + lwPolygon *pp; + lwPolVert *pv; + unsigned char *buf, *bp; + int i, j, nv, nverts, npols; + + + if ( cksize == 0 ) return 1; + + /* read the whole chunk */ + + set_flen( 0 ); + buf = getbytes( fp, cksize ); + if ( !buf ) goto Fail; + + /* count the polygons and vertices */ + + nverts = 0; + npols = 0; + bp = buf; + + while ( bp < buf + cksize ) { + nv = sgetU2( &bp ); + nverts += nv; + npols++; + bp += 2 * nv; + i = sgetI2( &bp ); + if ( i < 0 ) bp += 2; /* detail polygons */ + } + + if ( !lwAllocPolygons( plist, npols, nverts )) + goto Fail; + + /* fill in the new polygons */ + + bp = buf; + pp = plist->pol + plist->offset; + pv = plist->pol[ 0 ].v + plist->voffset; + + for ( i = 0; i < npols; i++ ) { + nv = sgetU2( &bp ); + + pp->nverts = nv; + pp->type = ID_FACE; + if ( !pp->v ) pp->v = pv; + for ( j = 0; j < nv; j++ ) + pv[ j ].index = sgetU2( &bp ) + ptoffset; + j = sgetI2( &bp ); + if ( j < 0 ) { + j = -j; + bp += 2; + } + j -= 1; + pp->surf = ( lwSurface * ) j; + + pp++; + pv += nv; + } + + _pico_free( buf ); + return 1; + +Fail: + if ( buf ) _pico_free( buf ); + lwFreePolygons( plist ); + return 0; +} + + +/* +====================================================================== +getLWObject5() + +Returns the contents of an LWOB, given its filename, or NULL if the +file couldn't be loaded. On failure, failID and failpos can be used +to diagnose the cause. + +1. If the file isn't an LWOB, failpos will contain 12 and failID will + be unchanged. + +2. If an error occurs while reading an LWOB, failID will contain the + most recently read IFF chunk ID, and failpos will contain the + value returned by _pico_memstream_tell() at the time of the failure. + +3. If the file couldn't be opened, or an error occurs while reading + the first 12 bytes, both failID and failpos will be unchanged. + +If you don't need this information, failID and failpos can be NULL. +====================================================================== */ + +lwObject *lwGetObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ) +{ + lwObject *object; + lwLayer *layer; + lwNode *node; + unsigned int id, formsize, type, cksize; + + + /* open the file */ + + if ( !fp ) return NULL; + + /* read the first 12 bytes */ + + set_flen( 0 ); + id = getU4( fp ); + formsize = getU4( fp ); + type = getU4( fp ); + if ( 12 != get_flen() ) { + return NULL; + } + + /* LWOB? */ + + if ( id != ID_FORM || type != ID_LWOB ) { + if ( failpos ) *failpos = 12; + return NULL; + } + + /* allocate an object and a default layer */ + + object = _pico_calloc( 1, sizeof( lwObject )); + if ( !object ) goto Fail; + + layer = _pico_calloc( 1, sizeof( lwLayer )); + if ( !layer ) goto Fail; + object->layer = layer; + object->nlayers = 1; + + /* get the first chunk header */ + + id = getU4( fp ); + cksize = getU4( fp ); + if ( 0 > get_flen() ) goto Fail; + + /* process chunks as they're encountered */ + + while ( 1 ) { + cksize += cksize & 1; + + switch ( id ) + { + case ID_PNTS: + if ( !lwGetPoints( fp, cksize, &layer->point )) + goto Fail; + break; + + case ID_POLS: + if ( !lwGetPolygons5( fp, cksize, &layer->polygon, + layer->point.offset )) + goto Fail; + break; + + case ID_SRFS: + if ( !lwGetTags( fp, cksize, &object->taglist )) + goto Fail; + break; + + case ID_SURF: + node = ( lwNode * ) lwGetSurface5( fp, cksize, object ); + if ( !node ) goto Fail; + lwListAdd( &object->surf, node ); + object->nsurfs++; + break; + + default: + _pico_memstream_seek( fp, cksize, PICO_SEEK_CUR ); + break; + } + + /* end of the file? */ + + if ( formsize <= _pico_memstream_tell( fp ) - 8 ) break; + + /* get the next chunk header */ + + set_flen( 0 ); + id = getU4( fp ); + cksize = getU4( fp ); + if ( 8 != get_flen() ) goto Fail; + } + + lwGetBoundingBox( &layer->point, layer->bbox ); + lwGetPolyNormals( &layer->point, &layer->polygon ); + if ( !lwGetPointPolygons( &layer->point, &layer->polygon )) goto Fail; + if ( !lwResolvePolySurfaces( &layer->polygon, &object->taglist, + &object->surf, &object->nsurfs )) goto Fail; + lwGetVertNormals( &layer->point, &layer->polygon ); + + return object; + +Fail: + if ( failID ) *failID = id; + if ( fp ) { + if ( failpos ) *failpos = _pico_memstream_tell( fp ); + } + lwFreeObject( object ); + return NULL; +} + +int lwValidateObject5( char *filename, picoMemStream_t *fp, unsigned int *failID, int *failpos ) +{ + unsigned int id, formsize, type; + + + /* open the file */ + + if ( !fp ) return PICO_PMV_ERROR_MEMORY; + + /* read the first 12 bytes */ + + set_flen( 0 ); + id = getU4( fp ); + formsize = getU4( fp ); + type = getU4( fp ); + if ( 12 != get_flen() ) { + return PICO_PMV_ERROR_SIZE; + } + + /* LWOB? */ + + if ( id != ID_FORM || type != ID_LWOB ) { + if ( failpos ) *failpos = 12; + return PICO_PMV_ERROR_IDENT; + } + + return PICO_PMV_OK; +} diff --git a/libs/picomodel/lwo/pntspols.c b/libs/picomodel/lwo/pntspols.c new file mode 100644 index 00000000..d6c3152d --- /dev/null +++ b/libs/picomodel/lwo/pntspols.c @@ -0,0 +1,537 @@ +/* +====================================================================== +pntspols.c + +Point and polygon functions for an LWO2 reader. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + + +/* +====================================================================== +lwFreePoints() + +Free the memory used by an lwPointList. +====================================================================== */ + +void lwFreePoints( lwPointList *point ) +{ + int i; + + if ( point ) { + if ( point->pt ) { + for ( i = 0; i < point->count; i++ ) { + if ( point->pt[ i ].pol ) _pico_free( point->pt[ i ].pol ); + if ( point->pt[ i ].vm ) _pico_free( point->pt[ i ].vm ); + } + _pico_free( point->pt ); + } + memset( point, 0, sizeof( lwPointList )); + } +} + + +/* +====================================================================== +lwFreePolygons() + +Free the memory used by an lwPolygonList. +====================================================================== */ + +void lwFreePolygons( lwPolygonList *plist ) +{ + int i, j; + + if ( plist ) { + if ( plist->pol ) { + for ( i = 0; i < plist->count; i++ ) { + if ( plist->pol[ i ].v ) { + for ( j = 0; j < plist->pol[ i ].nverts; j++ ) + if ( plist->pol[ i ].v[ j ].vm ) + _pico_free( plist->pol[ i ].v[ j ].vm ); + } + } + if ( plist->pol[ 0 ].v ) + _pico_free( plist->pol[ 0 ].v ); + _pico_free( plist->pol ); + } + memset( plist, 0, sizeof( lwPolygonList )); + } +} + + +/* +====================================================================== +lwGetPoints() + +Read point records from a PNTS chunk in an LWO2 file. The points are +added to the array in the lwPointList. +====================================================================== */ + +int lwGetPoints( picoMemStream_t *fp, int cksize, lwPointList *point ) +{ + float *f; + int np, i, j; + + if ( cksize == 1 ) return 1; + + /* extend the point array to hold the new points */ + + np = cksize / 12; + point->offset = point->count; + point->count += np; + if ( !_pico_realloc( (void *) &point->pt, (point->count - np) * sizeof( lwPoint ), point->count * sizeof( lwPoint )) ) + return 0; + memset( &point->pt[ point->offset ], 0, np * sizeof( lwPoint )); + + /* read the whole chunk */ + + f = ( float * ) getbytes( fp, cksize ); + if ( !f ) return 0; + revbytes( f, 4, np * 3 ); + + /* assign position values */ + + for ( i = 0, j = 0; i < np; i++, j += 3 ) { + point->pt[ i ].pos[ 0 ] = f[ j ]; + point->pt[ i ].pos[ 1 ] = f[ j + 1 ]; + point->pt[ i ].pos[ 2 ] = f[ j + 2 ]; + } + + _pico_free( f ); + return 1; +} + + +/* +====================================================================== +lwGetBoundingBox() + +Calculate the bounding box for a point list, but only if the bounding +box hasn't already been initialized. +====================================================================== */ + +void lwGetBoundingBox( lwPointList *point, float bbox[] ) +{ + int i, j; + + if ( point->count == 0 ) return; + + for ( i = 0; i < 6; i++ ) + if ( bbox[ i ] != 0.0f ) return; + + bbox[ 0 ] = bbox[ 1 ] = bbox[ 2 ] = 1e20f; + bbox[ 3 ] = bbox[ 4 ] = bbox[ 5 ] = -1e20f; + for ( i = 0; i < point->count; i++ ) { + for ( j = 0; j < 3; j++ ) { + if ( bbox[ j ] > point->pt[ i ].pos[ j ] ) + bbox[ j ] = point->pt[ i ].pos[ j ]; + if ( bbox[ j + 3 ] < point->pt[ i ].pos[ j ] ) + bbox[ j + 3 ] = point->pt[ i ].pos[ j ]; + } + } +} + + +/* +====================================================================== +lwAllocPolygons() + +Allocate or extend the polygon arrays to hold new records. +====================================================================== */ + +int lwAllocPolygons( lwPolygonList *plist, int npols, int nverts ) +{ + int i; + + plist->offset = plist->count; + plist->count += npols; + if ( !_pico_realloc( (void *) &plist->pol, (plist->count - npols) * sizeof( lwPolygon ), plist->count * sizeof( lwPolygon )) ) + return 0; + memset( plist->pol + plist->offset, 0, npols * sizeof( lwPolygon )); + + plist->voffset = plist->vcount; + plist->vcount += nverts; + if ( !_pico_realloc( (void *) &plist->pol[ 0 ].v, (plist->vcount - nverts) * sizeof( lwPolVert ), plist->vcount * sizeof( lwPolVert )) ) + return 0; + memset( plist->pol[ 0 ].v + plist->voffset, 0, nverts * sizeof( lwPolVert )); + + /* fix up the old vertex pointers */ + + for ( i = 1; i < plist->offset; i++ ) + plist->pol[ i ].v = plist->pol[ i - 1 ].v + plist->pol[ i - 1 ].nverts; + + return 1; +} + + +/* +====================================================================== +lwGetPolygons() + +Read polygon records from a POLS chunk in an LWO2 file. The polygons +are added to the array in the lwPolygonList. +====================================================================== */ + +int lwGetPolygons( picoMemStream_t *fp, int cksize, lwPolygonList *plist, int ptoffset ) +{ + lwPolygon *pp; + lwPolVert *pv; + unsigned char *buf, *bp; + int i, j, flags, nv, nverts, npols; + unsigned int type; + + + if ( cksize == 0 ) return 1; + + /* read the whole chunk */ + + set_flen( 0 ); + type = getU4( fp ); + buf = getbytes( fp, cksize - 4 ); + if ( cksize != get_flen() ) goto Fail; + + /* count the polygons and vertices */ + + nverts = 0; + npols = 0; + bp = buf; + + while ( bp < buf + cksize - 4 ) { + nv = sgetU2( &bp ); + nv &= 0x03FF; + nverts += nv; + npols++; + for ( i = 0; i < nv; i++ ) + j = sgetVX( &bp ); + } + + if ( !lwAllocPolygons( plist, npols, nverts )) + goto Fail; + + /* fill in the new polygons */ + + bp = buf; + pp = plist->pol + plist->offset; + pv = plist->pol[ 0 ].v + plist->voffset; + + for ( i = 0; i < npols; i++ ) { + nv = sgetU2( &bp ); + flags = nv & 0xFC00; + nv &= 0x03FF; + + pp->nverts = nv; + pp->flags = flags; + pp->type = type; + if ( !pp->v ) pp->v = pv; + for ( j = 0; j < nv; j++ ) + pp->v[ j ].index = sgetVX( &bp ) + ptoffset; + + pp++; + pv += nv; + } + + _pico_free( buf ); + return 1; + +Fail: + if ( buf ) _pico_free( buf ); + lwFreePolygons( plist ); + return 0; +} + + +/* +====================================================================== +lwGetPolyNormals() + +Calculate the polygon normals. By convention, LW's polygon normals +are found as the cross product of the first and last edges. It's +undefined for one- and two-point polygons. +====================================================================== */ + +void lwGetPolyNormals( lwPointList *point, lwPolygonList *polygon ) +{ + int i, j; + float p1[ 3 ], p2[ 3 ], pn[ 3 ], v1[ 3 ], v2[ 3 ]; + + for ( i = 0; i < polygon->count; i++ ) { + if ( polygon->pol[ i ].nverts < 3 ) continue; + for ( j = 0; j < 3; j++ ) { + p1[ j ] = point->pt[ polygon->pol[ i ].v[ 0 ].index ].pos[ j ]; + p2[ j ] = point->pt[ polygon->pol[ i ].v[ 1 ].index ].pos[ j ]; + pn[ j ] = point->pt[ polygon->pol[ i ].v[ + polygon->pol[ i ].nverts - 1 ].index ].pos[ j ]; + } + + for ( j = 0; j < 3; j++ ) { + v1[ j ] = p2[ j ] - p1[ j ]; + v2[ j ] = pn[ j ] - p1[ j ]; + } + + cross( v1, v2, polygon->pol[ i ].norm ); + normalize( polygon->pol[ i ].norm ); + } +} + + +/* +====================================================================== +lwGetPointPolygons() + +For each point, fill in the indexes of the polygons that share the +point. Returns 0 if any of the memory allocations fail, otherwise +returns 1. +====================================================================== */ + +int lwGetPointPolygons( lwPointList *point, lwPolygonList *polygon ) +{ + int i, j, k; + + /* count the number of polygons per point */ + + for ( i = 0; i < polygon->count; i++ ) + for ( j = 0; j < polygon->pol[ i ].nverts; j++ ) + ++point->pt[ polygon->pol[ i ].v[ j ].index ].npols; + + /* alloc per-point polygon arrays */ + + for ( i = 0; i < point->count; i++ ) { + if ( point->pt[ i ].npols == 0 ) continue; + point->pt[ i ].pol = _pico_calloc( point->pt[ i ].npols, sizeof( int )); + if ( !point->pt[ i ].pol ) return 0; + point->pt[ i ].npols = 0; + } + + /* fill in polygon array for each point */ + + for ( i = 0; i < polygon->count; i++ ) { + for ( j = 0; j < polygon->pol[ i ].nverts; j++ ) { + k = polygon->pol[ i ].v[ j ].index; + point->pt[ k ].pol[ point->pt[ k ].npols ] = i; + ++point->pt[ k ].npols; + } + } + + return 1; +} + + +/* +====================================================================== +lwResolvePolySurfaces() + +Convert tag indexes into actual lwSurface pointers. If any polygons +point to tags for which no corresponding surface can be found, a +default surface is created. +====================================================================== */ + +int lwResolvePolySurfaces( lwPolygonList *polygon, lwTagList *tlist, + lwSurface **surf, int *nsurfs ) +{ + lwSurface **s, *st; + int i, index; + + if ( tlist->count == 0 ) return 1; + + s = _pico_calloc( tlist->count, sizeof( lwSurface * )); + if ( !s ) return 0; + + for ( i = 0; i < tlist->count; i++ ) { + st = *surf; + while ( st ) { + if ( !strcmp( st->name, tlist->tag[ i ] )) { + s[ i ] = st; + break; + } + st = st->next; + } + } + + for ( i = 0; i < polygon->count; i++ ) { + index = ( int ) polygon->pol[ i ].surf; + if ( index < 0 || index > tlist->count ) return 0; + if ( !s[ index ] ) { + s[ index ] = lwDefaultSurface(); + if ( !s[ index ] ) return 0; + s[ index ]->name = _pico_alloc( strlen( tlist->tag[ index ] ) + 1 ); + if ( !s[ index ]->name ) return 0; + strcpy( s[ index ]->name, tlist->tag[ index ] ); + lwListAdd( surf, s[ index ] ); + *nsurfs = *nsurfs + 1; + } + polygon->pol[ i ].surf = s[ index ]; + } + + _pico_free( s ); + return 1; +} + + +/* +====================================================================== +lwGetVertNormals() + +Calculate the vertex normals. For each polygon vertex, sum the +normals of the polygons that share the point. If the normals of the +current and adjacent polygons form an angle greater than the max +smoothing angle for the current polygon's surface, the normal of the +adjacent polygon is excluded from the sum. It's also excluded if the +polygons aren't in the same smoothing group. + +Assumes that lwGetPointPolygons(), lwGetPolyNormals() and +lwResolvePolySurfaces() have already been called. +====================================================================== */ + +void lwGetVertNormals( lwPointList *point, lwPolygonList *polygon ) +{ + int j, k, n, g, h, p; + float a; + + for ( j = 0; j < polygon->count; j++ ) { + for ( n = 0; n < polygon->pol[ j ].nverts; n++ ) { + for ( k = 0; k < 3; k++ ) + polygon->pol[ j ].v[ n ].norm[ k ] = polygon->pol[ j ].norm[ k ]; + + if ( polygon->pol[ j ].surf->smooth <= 0 ) continue; + + p = polygon->pol[ j ].v[ n ].index; + + for ( g = 0; g < point->pt[ p ].npols; g++ ) { + h = point->pt[ p ].pol[ g ]; + if ( h == j ) continue; + + if ( polygon->pol[ j ].smoothgrp != polygon->pol[ h ].smoothgrp ) + continue; + a = vecangle( polygon->pol[ j ].norm, polygon->pol[ h ].norm ); + if ( a > polygon->pol[ j ].surf->smooth ) continue; + + for ( k = 0; k < 3; k++ ) + polygon->pol[ j ].v[ n ].norm[ k ] += polygon->pol[ h ].norm[ k ]; + } + + normalize( polygon->pol[ j ].v[ n ].norm ); + } + } +} + + +/* +====================================================================== +lwFreeTags() + +Free memory used by an lwTagList. +====================================================================== */ + +void lwFreeTags( lwTagList *tlist ) +{ + int i; + + if ( tlist ) { + if ( tlist->tag ) { + for ( i = 0; i < tlist->count; i++ ) + if ( tlist->tag[ i ] ) _pico_free( tlist->tag[ i ] ); + _pico_free( tlist->tag ); + } + memset( tlist, 0, sizeof( lwTagList )); + } +} + + +/* +====================================================================== +lwGetTags() + +Read tag strings from a TAGS chunk in an LWO2 file. The tags are +added to the lwTagList array. +====================================================================== */ + +int lwGetTags( picoMemStream_t *fp, int cksize, lwTagList *tlist ) +{ + char *buf, *bp; + int i, len, ntags; + + if ( cksize == 0 ) return 1; + + /* read the whole chunk */ + + set_flen( 0 ); + buf = getbytes( fp, cksize ); + if ( !buf ) return 0; + + /* count the strings */ + + ntags = 0; + bp = buf; + while ( bp < buf + cksize ) { + len = strlen( bp ) + 1; + len += len & 1; + bp += len; + ++ntags; + } + + /* expand the string array to hold the new tags */ + + tlist->offset = tlist->count; + tlist->count += ntags; + if ( !_pico_realloc( (void *) &tlist->tag, (tlist->count - ntags) * sizeof( char * ), tlist->count * sizeof( char * )) ) + goto Fail; + memset( &tlist->tag[ tlist->offset ], 0, ntags * sizeof( char * )); + + /* copy the new tags to the tag array */ + + bp = buf; + for ( i = 0; i < ntags; i++ ) + tlist->tag[ i + tlist->offset ] = sgetS0( &bp ); + + _pico_free( buf ); + return 1; + +Fail: + if ( buf ) _pico_free( buf ); + return 0; +} + + +/* +====================================================================== +lwGetPolygonTags() + +Read polygon tags from a PTAG chunk in an LWO2 file. +====================================================================== */ + +int lwGetPolygonTags( picoMemStream_t *fp, int cksize, lwTagList *tlist, + lwPolygonList *plist ) +{ + unsigned int type; + int rlen = 0, i, j; + + set_flen( 0 ); + type = getU4( fp ); + rlen = get_flen(); + if ( rlen < 0 ) return 0; + + if ( type != ID_SURF && type != ID_PART && type != ID_SMGP ) { + _pico_memstream_seek( fp, cksize - 4, PICO_SEEK_CUR ); + return 1; + } + + while ( rlen < cksize ) { + i = getVX( fp ) + plist->offset; + j = getVX( fp ) + tlist->offset; + rlen = get_flen(); + if ( rlen < 0 || rlen > cksize ) return 0; + + switch ( type ) { + case ID_SURF: plist->pol[ i ].surf = ( lwSurface * ) j; break; + case ID_PART: plist->pol[ i ].part = j; break; + case ID_SMGP: plist->pol[ i ].smoothgrp = j; break; + } + } + + return 1; +} diff --git a/libs/picomodel/lwo/surface.c b/libs/picomodel/lwo/surface.c new file mode 100644 index 00000000..6456a957 --- /dev/null +++ b/libs/picomodel/lwo/surface.c @@ -0,0 +1,1004 @@ +/* +====================================================================== +surface.c + +Surface functions for an LWO2 reader. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + + +/* +====================================================================== +lwFreePlugin() + +Free the memory used by an lwPlugin. +====================================================================== */ + +void lwFreePlugin( lwPlugin *p ) +{ + if ( p ) { + if ( p->ord ) _pico_free( p->ord ); + if ( p->name ) _pico_free( p->name ); + if ( p->data ) _pico_free( p->data ); + _pico_free( p ); + } +} + + +/* +====================================================================== +lwFreeTexture() + +Free the memory used by an lwTexture. +====================================================================== */ + +void lwFreeTexture( lwTexture *t ) +{ + if ( t ) { + if ( t->ord ) _pico_free( t->ord ); + switch ( t->type ) { + case ID_IMAP: + if ( t->param.imap.vmap_name ) _pico_free( t->param.imap.vmap_name ); + break; + case ID_PROC: + if ( t->param.proc.name ) _pico_free( t->param.proc.name ); + if ( t->param.proc.data ) _pico_free( t->param.proc.data ); + break; + case ID_GRAD: + if ( t->param.grad.key ) _pico_free( t->param.grad.key ); + if ( t->param.grad.ikey ) _pico_free( t->param.grad.ikey ); + break; + } + _pico_free( t ); + } +} + + +/* +====================================================================== +lwFreeSurface() + +Free the memory used by an lwSurface. +====================================================================== */ + +void lwFreeSurface( lwSurface *surf ) +{ + if ( surf ) { + if ( surf->name ) _pico_free( surf->name ); + if ( surf->srcname ) _pico_free( surf->srcname ); + + lwListFree( surf->shader, lwFreePlugin ); + + lwListFree( surf->color.tex, lwFreeTexture ); + lwListFree( surf->luminosity.tex, lwFreeTexture ); + lwListFree( surf->diffuse.tex, lwFreeTexture ); + lwListFree( surf->specularity.tex, lwFreeTexture ); + lwListFree( surf->glossiness.tex, lwFreeTexture ); + lwListFree( surf->reflection.val.tex, lwFreeTexture ); + lwListFree( surf->transparency.val.tex, lwFreeTexture ); + lwListFree( surf->eta.tex, lwFreeTexture ); + lwListFree( surf->translucency.tex, lwFreeTexture ); + lwListFree( surf->bump.tex, lwFreeTexture ); + + _pico_free( surf ); + } +} + + +/* +====================================================================== +lwGetTHeader() + +Read a texture map header from a SURF.BLOK in an LWO2 file. This is +the first subchunk in a BLOK, and its contents are common to all three +texture types. +====================================================================== */ + +int lwGetTHeader( picoMemStream_t *fp, int hsz, lwTexture *tex ) +{ + unsigned int id; + unsigned short sz; + int pos, rlen; + + + /* remember where we started */ + + set_flen( 0 ); + pos = _pico_memstream_tell( fp ); + + /* ordinal string */ + + tex->ord = getS0( fp ); + + /* first subchunk header */ + + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) return 0; + + /* process subchunks as they're encountered */ + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_CHAN: + tex->chan = getU4( fp ); + break; + + case ID_OPAC: + tex->opac_type = getU2( fp ); + tex->opacity.val = getF4( fp ); + tex->opacity.eindex = getVX( fp ); + break; + + case ID_ENAB: + tex->enabled = getU2( fp ); + break; + + case ID_NEGA: + tex->negative = getU2( fp ); + break; + + case ID_AXIS: + tex->axis = getU2( fp ); + break; + + default: + break; + } + + /* error while reading current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) return 0; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the texture header subchunk? */ + + if ( hsz <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) return 0; + } + + set_flen( _pico_memstream_tell( fp ) - pos ); + return 1; +} + + +/* +====================================================================== +lwGetTMap() + +Read a texture map from a SURF.BLOK in an LWO2 file. The TMAP +defines the mapping from texture to world or object coordinates. +====================================================================== */ + +int lwGetTMap( picoMemStream_t *fp, int tmapsz, lwTMap *tmap ) +{ + unsigned int id; + unsigned short sz; + int rlen, pos, i; + + pos = _pico_memstream_tell( fp ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) return 0; + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_SIZE: + for ( i = 0; i < 3; i++ ) + tmap->size.val[ i ] = getF4( fp ); + tmap->size.eindex = getVX( fp ); + break; + + case ID_CNTR: + for ( i = 0; i < 3; i++ ) + tmap->center.val[ i ] = getF4( fp ); + tmap->center.eindex = getVX( fp ); + break; + + case ID_ROTA: + for ( i = 0; i < 3; i++ ) + tmap->rotate.val[ i ] = getF4( fp ); + tmap->rotate.eindex = getVX( fp ); + break; + + case ID_FALL: + tmap->fall_type = getU2( fp ); + for ( i = 0; i < 3; i++ ) + tmap->falloff.val[ i ] = getF4( fp ); + tmap->falloff.eindex = getVX( fp ); + break; + + case ID_OREF: + tmap->ref_object = getS0( fp ); + break; + + case ID_CSYS: + tmap->coord_sys = getU2( fp ); + break; + + default: + break; + } + + /* error while reading the current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) return 0; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the TMAP subchunk? */ + + if ( tmapsz <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) return 0; + } + + set_flen( _pico_memstream_tell( fp ) - pos ); + return 1; +} + + +/* +====================================================================== +lwGetImageMap() + +Read an lwImageMap from a SURF.BLOK in an LWO2 file. +====================================================================== */ + +int lwGetImageMap( picoMemStream_t *fp, int rsz, lwTexture *tex ) +{ + unsigned int id; + unsigned short sz; + int rlen, pos; + + pos = _pico_memstream_tell( fp ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) return 0; + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_TMAP: + if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0; + break; + + case ID_PROJ: + tex->param.imap.projection = getU2( fp ); + break; + + case ID_VMAP: + tex->param.imap.vmap_name = getS0( fp ); + break; + + case ID_AXIS: + tex->param.imap.axis = getU2( fp ); + break; + + case ID_IMAG: + tex->param.imap.cindex = getVX( fp ); + break; + + case ID_WRAP: + tex->param.imap.wrapw_type = getU2( fp ); + tex->param.imap.wraph_type = getU2( fp ); + break; + + case ID_WRPW: + tex->param.imap.wrapw.val = getF4( fp ); + tex->param.imap.wrapw.eindex = getVX( fp ); + break; + + case ID_WRPH: + tex->param.imap.wraph.val = getF4( fp ); + tex->param.imap.wraph.eindex = getVX( fp ); + break; + + case ID_AAST: + tex->param.imap.aas_flags = getU2( fp ); + tex->param.imap.aa_strength = getF4( fp ); + break; + + case ID_PIXB: + tex->param.imap.pblend = getU2( fp ); + break; + + case ID_STCK: + tex->param.imap.stck.val = getF4( fp ); + tex->param.imap.stck.eindex = getVX( fp ); + break; + + case ID_TAMP: + tex->param.imap.amplitude.val = getF4( fp ); + tex->param.imap.amplitude.eindex = getVX( fp ); + break; + + default: + break; + } + + /* error while reading the current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) return 0; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the image map? */ + + if ( rsz <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) return 0; + } + + set_flen( _pico_memstream_tell( fp ) - pos ); + return 1; +} + + +/* +====================================================================== +lwGetProcedural() + +Read an lwProcedural from a SURF.BLOK in an LWO2 file. +====================================================================== */ + +int lwGetProcedural( picoMemStream_t *fp, int rsz, lwTexture *tex ) +{ + unsigned int id; + unsigned short sz; + int rlen, pos; + + pos = _pico_memstream_tell( fp ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) return 0; + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_TMAP: + if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0; + break; + + case ID_AXIS: + tex->param.proc.axis = getU2( fp ); + break; + + case ID_VALU: + tex->param.proc.value[ 0 ] = getF4( fp ); + if ( sz >= 8 ) tex->param.proc.value[ 1 ] = getF4( fp ); + if ( sz >= 12 ) tex->param.proc.value[ 2 ] = getF4( fp ); + break; + + case ID_FUNC: + tex->param.proc.name = getS0( fp ); + rlen = get_flen(); + tex->param.proc.data = getbytes( fp, sz - rlen ); + break; + + default: + break; + } + + /* error while reading the current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) return 0; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the procedural block? */ + + if ( rsz <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) return 0; + } + + set_flen( _pico_memstream_tell( fp ) - pos ); + return 1; +} + + +/* +====================================================================== +lwGetGradient() + +Read an lwGradient from a SURF.BLOK in an LWO2 file. +====================================================================== */ + +int lwGetGradient( picoMemStream_t *fp, int rsz, lwTexture *tex ) +{ + unsigned int id; + unsigned short sz; + int rlen, pos, i, j, nkeys; + + pos = _pico_memstream_tell( fp ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) return 0; + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_TMAP: + if ( !lwGetTMap( fp, sz, &tex->tmap )) return 0; + break; + + case ID_PNAM: + tex->param.grad.paramname = getS0( fp ); + break; + + case ID_INAM: + tex->param.grad.itemname = getS0( fp ); + break; + + case ID_GRST: + tex->param.grad.start = getF4( fp ); + break; + + case ID_GREN: + tex->param.grad.end = getF4( fp ); + break; + + case ID_GRPT: + tex->param.grad.repeat = getU2( fp ); + break; + + case ID_FKEY: + nkeys = sz / sizeof( lwGradKey ); + tex->param.grad.key = _pico_calloc( nkeys, sizeof( lwGradKey )); + if ( !tex->param.grad.key ) return 0; + for ( i = 0; i < nkeys; i++ ) { + tex->param.grad.key[ i ].value = getF4( fp ); + for ( j = 0; j < 4; j++ ) + tex->param.grad.key[ i ].rgba[ j ] = getF4( fp ); + } + break; + + case ID_IKEY: + nkeys = sz / 2; + tex->param.grad.ikey = _pico_calloc( nkeys, sizeof( short )); + if ( !tex->param.grad.ikey ) return 0; + for ( i = 0; i < nkeys; i++ ) + tex->param.grad.ikey[ i ] = getU2( fp ); + break; + + default: + break; + } + + /* error while reading the current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) return 0; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the gradient? */ + + if ( rsz <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) return 0; + } + + set_flen( _pico_memstream_tell( fp ) - pos ); + return 1; +} + + +/* +====================================================================== +lwGetTexture() + +Read an lwTexture from a SURF.BLOK in an LWO2 file. +====================================================================== */ + +lwTexture *lwGetTexture( picoMemStream_t *fp, int bloksz, unsigned int type ) +{ + lwTexture *tex; + unsigned short sz; + int ok; + + tex = _pico_calloc( 1, sizeof( lwTexture )); + if ( !tex ) return NULL; + + tex->type = type; + tex->tmap.size.val[ 0 ] = + tex->tmap.size.val[ 1 ] = + tex->tmap.size.val[ 2 ] = 1.0f; + tex->opacity.val = 1.0f; + tex->enabled = 1; + + sz = getU2( fp ); + if ( !lwGetTHeader( fp, sz, tex )) { + _pico_free( tex ); + return NULL; + } + + sz = bloksz - sz - 6; + switch ( type ) { + case ID_IMAP: ok = lwGetImageMap( fp, sz, tex ); break; + case ID_PROC: ok = lwGetProcedural( fp, sz, tex ); break; + case ID_GRAD: ok = lwGetGradient( fp, sz, tex ); break; + default: + ok = !_pico_memstream_seek( fp, sz, PICO_SEEK_CUR ); + } + + if ( !ok ) { + lwFreeTexture( tex ); + return NULL; + } + + set_flen( bloksz ); + return tex; +} + + +/* +====================================================================== +lwGetShader() + +Read a shader record from a SURF.BLOK in an LWO2 file. +====================================================================== */ + +lwPlugin *lwGetShader( picoMemStream_t *fp, int bloksz ) +{ + lwPlugin *shdr; + unsigned int id; + unsigned short sz; + int hsz, rlen, pos; + + shdr = _pico_calloc( 1, sizeof( lwPlugin )); + if ( !shdr ) return NULL; + + pos = _pico_memstream_tell( fp ); + set_flen( 0 ); + hsz = getU2( fp ); + shdr->ord = getS0( fp ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + while ( hsz > 0 ) { + sz += sz & 1; + hsz -= sz; + if ( id == ID_ENAB ) { + shdr->flags = getU2( fp ); + break; + } + else { + _pico_memstream_seek( fp, sz, PICO_SEEK_CUR ); + id = getU4( fp ); + sz = getU2( fp ); + } + } + + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_FUNC: + shdr->name = getS0( fp ); + rlen = get_flen(); + shdr->data = getbytes( fp, sz - rlen ); + break; + + default: + break; + } + + /* error while reading the current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) goto Fail; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the shader block? */ + + if ( bloksz <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) goto Fail; + } + + set_flen( _pico_memstream_tell( fp ) - pos ); + return shdr; + +Fail: + lwFreePlugin( shdr ); + return NULL; +} + + +/* +====================================================================== +compare_textures() +compare_shaders() + +Callbacks for the lwListInsert() function, which is called to add +textures to surface channels and shaders to surfaces. +====================================================================== */ + +static int compare_textures( lwTexture *a, lwTexture *b ) +{ + return strcmp( a->ord, b->ord ); +} + + +static int compare_shaders( lwPlugin *a, lwPlugin *b ) +{ + return strcmp( a->ord, b->ord ); +} + + +/* +====================================================================== +add_texture() + +Finds the surface channel (lwTParam or lwCParam) to which a texture is +applied, then calls lwListInsert(). +====================================================================== */ + +static int add_texture( lwSurface *surf, lwTexture *tex ) +{ + lwTexture **list; + + switch ( tex->chan ) { + case ID_COLR: list = &surf->color.tex; break; + case ID_LUMI: list = &surf->luminosity.tex; break; + case ID_DIFF: list = &surf->diffuse.tex; break; + case ID_SPEC: list = &surf->specularity.tex; break; + case ID_GLOS: list = &surf->glossiness.tex; break; + case ID_REFL: list = &surf->reflection.val.tex; break; + case ID_TRAN: list = &surf->transparency.val.tex; break; + case ID_RIND: list = &surf->eta.tex; break; + case ID_TRNL: list = &surf->translucency.tex; break; + case ID_BUMP: list = &surf->bump.tex; break; + default: return 0; + } + + lwListInsert( list, tex, compare_textures ); + return 1; +} + + +/* +====================================================================== +lwDefaultSurface() + +Allocate and initialize a surface. +====================================================================== */ + +lwSurface *lwDefaultSurface( void ) +{ + lwSurface *surf; + + surf = _pico_calloc( 1, sizeof( lwSurface )); + if ( !surf ) return NULL; + + surf->color.rgb[ 0 ] = 0.78431f; + surf->color.rgb[ 1 ] = 0.78431f; + surf->color.rgb[ 2 ] = 0.78431f; + surf->diffuse.val = 1.0f; + surf->glossiness.val = 0.4f; + surf->bump.val = 1.0f; + surf->eta.val = 1.0f; + surf->sideflags = 1; + + return surf; +} + + +/* +====================================================================== +lwGetSurface() + +Read an lwSurface from an LWO2 file. +====================================================================== */ + +lwSurface *lwGetSurface( picoMemStream_t *fp, int cksize ) +{ + lwSurface *surf; + lwTexture *tex; + lwPlugin *shdr; + unsigned int id, type; + unsigned short sz; + int pos, rlen; + + + /* allocate the Surface structure */ + + surf = _pico_calloc( 1, sizeof( lwSurface )); + if ( !surf ) goto Fail; + + /* non-zero defaults */ + + surf->color.rgb[ 0 ] = 0.78431f; + surf->color.rgb[ 1 ] = 0.78431f; + surf->color.rgb[ 2 ] = 0.78431f; + surf->diffuse.val = 1.0f; + surf->glossiness.val = 0.4f; + surf->bump.val = 1.0f; + surf->eta.val = 1.0f; + surf->sideflags = 1; + + /* remember where we started */ + + set_flen( 0 ); + pos = _pico_memstream_tell( fp ); + + /* names */ + + surf->name = getS0( fp ); + surf->srcname = getS0( fp ); + + /* first subchunk header */ + + id = getU4( fp ); + sz = getU2( fp ); + if ( 0 > get_flen() ) goto Fail; + + /* process subchunks as they're encountered */ + + while ( 1 ) { + sz += sz & 1; + set_flen( 0 ); + + switch ( id ) { + case ID_COLR: + surf->color.rgb[ 0 ] = getF4( fp ); + surf->color.rgb[ 1 ] = getF4( fp ); + surf->color.rgb[ 2 ] = getF4( fp ); + surf->color.eindex = getVX( fp ); + break; + + case ID_LUMI: + surf->luminosity.val = getF4( fp ); + surf->luminosity.eindex = getVX( fp ); + break; + + case ID_DIFF: + surf->diffuse.val = getF4( fp ); + surf->diffuse.eindex = getVX( fp ); + break; + + case ID_SPEC: + surf->specularity.val = getF4( fp ); + surf->specularity.eindex = getVX( fp ); + break; + + case ID_GLOS: + surf->glossiness.val = getF4( fp ); + surf->glossiness.eindex = getVX( fp ); + break; + + case ID_REFL: + surf->reflection.val.val = getF4( fp ); + surf->reflection.val.eindex = getVX( fp ); + break; + + case ID_RFOP: + surf->reflection.options = getU2( fp ); + break; + + case ID_RIMG: + surf->reflection.cindex = getVX( fp ); + break; + + case ID_RSAN: + surf->reflection.seam_angle = getF4( fp ); + break; + + case ID_TRAN: + surf->transparency.val.val = getF4( fp ); + surf->transparency.val.eindex = getVX( fp ); + break; + + case ID_TROP: + surf->transparency.options = getU2( fp ); + break; + + case ID_TIMG: + surf->transparency.cindex = getVX( fp ); + break; + + case ID_RIND: + surf->eta.val = getF4( fp ); + surf->eta.eindex = getVX( fp ); + break; + + case ID_TRNL: + surf->translucency.val = getF4( fp ); + surf->translucency.eindex = getVX( fp ); + break; + + case ID_BUMP: + surf->bump.val = getF4( fp ); + surf->bump.eindex = getVX( fp ); + break; + + case ID_SMAN: + surf->smooth = getF4( fp ); + break; + + case ID_SIDE: + surf->sideflags = getU2( fp ); + break; + + case ID_CLRH: + surf->color_hilite.val = getF4( fp ); + surf->color_hilite.eindex = getVX( fp ); + break; + + case ID_CLRF: + surf->color_filter.val = getF4( fp ); + surf->color_filter.eindex = getVX( fp ); + break; + + case ID_ADTR: + surf->add_trans.val = getF4( fp ); + surf->add_trans.eindex = getVX( fp ); + break; + + case ID_SHRP: + surf->dif_sharp.val = getF4( fp ); + surf->dif_sharp.eindex = getVX( fp ); + break; + + case ID_GVAL: + surf->glow.val = getF4( fp ); + surf->glow.eindex = getVX( fp ); + break; + + case ID_LINE: + surf->line.enabled = 1; + if ( sz >= 2 ) surf->line.flags = getU2( fp ); + if ( sz >= 6 ) surf->line.size.val = getF4( fp ); + if ( sz >= 8 ) surf->line.size.eindex = getVX( fp ); + break; + + case ID_ALPH: + surf->alpha_mode = getU2( fp ); + surf->alpha = getF4( fp ); + break; + + case ID_AVAL: + surf->alpha = getF4( fp ); + break; + + case ID_BLOK: + type = getU4( fp ); + + switch ( type ) { + case ID_IMAP: + case ID_PROC: + case ID_GRAD: + tex = lwGetTexture( fp, sz - 4, type ); + if ( !tex ) goto Fail; + if ( !add_texture( surf, tex )) + lwFreeTexture( tex ); + set_flen( 4 + get_flen() ); + break; + case ID_SHDR: + shdr = lwGetShader( fp, sz - 4 ); + if ( !shdr ) goto Fail; + lwListInsert( &surf->shader, shdr, compare_shaders ); + ++surf->nshaders; + set_flen( 4 + get_flen() ); + break; + } + break; + + default: + break; + } + + /* error while reading current subchunk? */ + + rlen = get_flen(); + if ( rlen < 0 || rlen > sz ) goto Fail; + + /* skip unread parts of the current subchunk */ + + if ( rlen < sz ) + _pico_memstream_seek( fp, sz - rlen, PICO_SEEK_CUR ); + + /* end of the SURF chunk? */ + + if ( cksize <= _pico_memstream_tell( fp ) - pos ) + break; + + /* get the next subchunk header */ + + set_flen( 0 ); + id = getU4( fp ); + sz = getU2( fp ); + if ( 6 != get_flen() ) goto Fail; + } + + return surf; + +Fail: + if ( surf ) lwFreeSurface( surf ); + return NULL; +} diff --git a/libs/picomodel/lwo/vecmath.c b/libs/picomodel/lwo/vecmath.c new file mode 100644 index 00000000..44d317b0 --- /dev/null +++ b/libs/picomodel/lwo/vecmath.c @@ -0,0 +1,37 @@ +/* +====================================================================== +vecmath.c + +Basic vector and matrix functions. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include + + +float dot( float a[], float b[] ) +{ + return a[ 0 ] * b[ 0 ] + a[ 1 ] * b[ 1 ] + a[ 2 ] * b[ 2 ]; +} + + +void cross( float a[], float b[], float c[] ) +{ + c[ 0 ] = a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ]; + c[ 1 ] = a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ]; + c[ 2 ] = a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ]; +} + + +void normalize( float v[] ) +{ + float r; + + r = ( float ) sqrt( dot( v, v )); + if ( r > 0 ) { + v[ 0 ] /= r; + v[ 1 ] /= r; + v[ 2 ] /= r; + } +} diff --git a/libs/picomodel/lwo/vmap.c b/libs/picomodel/lwo/vmap.c new file mode 100644 index 00000000..1a24bee0 --- /dev/null +++ b/libs/picomodel/lwo/vmap.c @@ -0,0 +1,243 @@ +/* +====================================================================== +vmap.c + +Vertex map functions for an LWO2 reader. + +Ernie Wright 17 Sep 00 +====================================================================== */ + +#include "../picointernal.h" +#include "lwo2.h" + + +/* +====================================================================== +lwFreeVMap() + +Free memory used by an lwVMap. +====================================================================== */ + +void lwFreeVMap( lwVMap *vmap ) +{ + if ( vmap ) { + if ( vmap->name ) _pico_free( vmap->name ); + if ( vmap->vindex ) _pico_free( vmap->vindex ); + if ( vmap->pindex ) _pico_free( vmap->pindex ); + if ( vmap->val ) { + if ( vmap->val[ 0 ] ) _pico_free( vmap->val[ 0 ] ); + _pico_free( vmap->val ); + } + _pico_free( vmap ); + } +} + + +/* +====================================================================== +lwGetVMap() + +Read an lwVMap from a VMAP or VMAD chunk in an LWO2. +====================================================================== */ + +lwVMap *lwGetVMap( picoMemStream_t *fp, int cksize, int ptoffset, int poloffset, + int perpoly ) +{ + unsigned char *buf, *bp; + lwVMap *vmap; + float *f; + int i, j, npts, rlen; + + + /* read the whole chunk */ + + set_flen( 0 ); + buf = getbytes( fp, cksize ); + if ( !buf ) return NULL; + + vmap = _pico_calloc( 1, sizeof( lwVMap )); + if ( !vmap ) { + _pico_free( buf ); + return NULL; + } + + /* initialize the vmap */ + + vmap->perpoly = perpoly; + + bp = buf; + set_flen( 0 ); + vmap->type = sgetU4( &bp ); + vmap->dim = sgetU2( &bp ); + vmap->name = sgetS0( &bp ); + rlen = get_flen(); + + /* count the vmap records */ + + npts = 0; + while ( bp < buf + cksize ) { + i = sgetVX( &bp ); + if ( perpoly ) + i = sgetVX( &bp ); + bp += vmap->dim * sizeof( float ); + ++npts; + } + + /* allocate the vmap */ + + vmap->nverts = npts; + vmap->vindex = _pico_calloc( npts, sizeof( int )); + if ( !vmap->vindex ) goto Fail; + if ( perpoly ) { + vmap->pindex = _pico_calloc( npts, sizeof( int )); + if ( !vmap->pindex ) goto Fail; + } + + if ( vmap->dim > 0 ) { + vmap->val = _pico_calloc( npts, sizeof( float * )); + if ( !vmap->val ) goto Fail; + f = _pico_alloc( npts * vmap->dim * sizeof( float )); + if ( !f ) goto Fail; + for ( i = 0; i < npts; i++ ) + vmap->val[ i ] = f + i * vmap->dim; + } + + /* fill in the vmap values */ + + bp = buf + rlen; + for ( i = 0; i < npts; i++ ) { + vmap->vindex[ i ] = sgetVX( &bp ); + if ( perpoly ) + vmap->pindex[ i ] = sgetVX( &bp ); + for ( j = 0; j < vmap->dim; j++ ) + vmap->val[ i ][ j ] = sgetF4( &bp ); + } + + _pico_free( buf ); + return vmap; + +Fail: + if ( buf ) _pico_free( buf ); + lwFreeVMap( vmap ); + return NULL; +} + + +/* +====================================================================== +lwGetPointVMaps() + +Fill in the lwVMapPt structure for each point. +====================================================================== */ + +int lwGetPointVMaps( lwPointList *point, lwVMap *vmap ) +{ + lwVMap *vm; + int i, j, n; + + /* count the number of vmap values for each point */ + + vm = vmap; + while ( vm ) { + if ( !vm->perpoly ) + for ( i = 0; i < vm->nverts; i++ ) + ++point->pt[ vm->vindex[ i ]].nvmaps; + vm = vm->next; + } + + /* allocate vmap references for each mapped point */ + + for ( i = 0; i < point->count; i++ ) { + if ( point->pt[ i ].nvmaps ) { + point->pt[ i ].vm = _pico_calloc( point->pt[ i ].nvmaps, sizeof( lwVMapPt )); + if ( !point->pt[ i ].vm ) return 0; + point->pt[ i ].nvmaps = 0; + } + } + + /* fill in vmap references for each mapped point */ + + vm = vmap; + while ( vm ) { + if ( !vm->perpoly ) { + for ( i = 0; i < vm->nverts; i++ ) { + j = vm->vindex[ i ]; + n = point->pt[ j ].nvmaps; + point->pt[ j ].vm[ n ].vmap = vm; + point->pt[ j ].vm[ n ].index = i; + ++point->pt[ j ].nvmaps; + } + } + vm = vm->next; + } + + return 1; +} + + +/* +====================================================================== +lwGetPolyVMaps() + +Fill in the lwVMapPt structure for each polygon vertex. +====================================================================== */ + +int lwGetPolyVMaps( lwPolygonList *polygon, lwVMap *vmap ) +{ + lwVMap *vm; + lwPolVert *pv; + int i, j; + + /* count the number of vmap values for each polygon vertex */ + + vm = vmap; + while ( vm ) { + if ( vm->perpoly ) { + for ( i = 0; i < vm->nverts; i++ ) { + for ( j = 0; j < polygon->pol[ vm->pindex[ i ]].nverts; j++ ) { + pv = &polygon->pol[ vm->pindex[ i ]].v[ j ]; + if ( vm->vindex[ i ] == pv->index ) { + ++pv->nvmaps; + break; + } + } + } + } + vm = vm->next; + } + + /* allocate vmap references for each mapped vertex */ + + for ( i = 0; i < polygon->count; i++ ) { + for ( j = 0; j < polygon->pol[ i ].nverts; j++ ) { + pv = &polygon->pol[ i ].v[ j ]; + if ( pv->nvmaps ) { + pv->vm = _pico_calloc( pv->nvmaps, sizeof( lwVMapPt )); + if ( !pv->vm ) return 0; + pv->nvmaps = 0; + } + } + } + + /* fill in vmap references for each mapped point */ + + vm = vmap; + while ( vm ) { + if ( vm->perpoly ) { + for ( i = 0; i < vm->nverts; i++ ) { + for ( j = 0; j < polygon->pol[ vm->pindex[ i ]].nverts; j++ ) { + pv = &polygon->pol[ vm->pindex[ i ]].v[ j ]; + if ( vm->vindex[ i ] == pv->index ) { + pv->vm[ pv->nvmaps ].vmap = vm; + pv->vm[ pv->nvmaps ].index = i; + ++pv->nvmaps; + break; + } + } + } + } + vm = vm->next; + } + + return 1; +} diff --git a/libs/picomodel/picointernal.c b/libs/picomodel/picointernal.c new file mode 100644 index 00000000..6afae90a --- /dev/null +++ b/libs/picomodel/picointernal.c @@ -0,0 +1,1353 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +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 names of the copyright holders 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. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PICOINTERNAL_C + + + +/* todo: + * - fix p->curLine for parser routines. increased twice + */ + +/* dependencies */ +#include +#include "picointernal.h" + + + +/* function pointers */ +void *(*_pico_ptr_malloc )( size_t ) = malloc; +void (*_pico_ptr_free )( void* ) = free; +void (*_pico_ptr_load_file )( char*, unsigned char**, int* ) = NULL; +void (*_pico_ptr_free_file )( void* ) = NULL; +void (*_pico_ptr_print )( int, const char* ) = NULL; + +typedef union +{ + float f; + char c[4]; +} +floatSwapUnion; + +/* _pico_alloc: + * kludged memory allocation wrapper + */ +void *_pico_alloc( size_t size ) +{ + void *ptr; + + /* some sanity checks */ + if( size == 0 ) + return NULL; + if (_pico_ptr_malloc == NULL) + return NULL; + + /* allocate memory */ + ptr = _pico_ptr_malloc(size); + if (ptr == NULL) + return NULL; + + /* zero out allocated memory */ + memset(ptr,0,size); + + /* return pointer to allocated memory */ + return ptr; +} + +/* _pico_calloc: + * _pico_calloc wrapper + */ +void *_pico_calloc( size_t num, size_t size ) +{ + void *ptr; + + /* some sanity checks */ + if( num == 0 || size == 0 ) + return NULL; + if (_pico_ptr_malloc == NULL) + return NULL; + + /* allocate memory */ + ptr = _pico_ptr_malloc(num*size); + if (ptr == NULL) + return NULL; + + /* zero out allocated memory */ + memset(ptr,0,num*size); + + /* return pointer to allocated memory */ + return ptr; +} + +/* _pico_realloc: + * memory reallocation wrapper (note: only grows, + * but never shrinks or frees) + */ +void *_pico_realloc( void **ptr, size_t oldSize, size_t newSize ) +{ + void *ptr2; + + /* sanity checks */ + if( ptr == NULL ) + return NULL; + if( newSize < oldSize ) + return *ptr; + if (_pico_ptr_malloc == NULL) + return NULL; + + /* allocate new pointer */ + ptr2 = _pico_alloc( newSize ); + if( ptr2 == NULL ) + return NULL; + + /* copy */ + if( *ptr != NULL ) + { + memcpy( ptr2, *ptr, oldSize ); + _pico_free( *ptr ); + } + + /* fix up and return */ + *ptr = ptr2; + return *ptr; +} + +/* _pico_clone_alloc: + * handy function for quick string allocation/copy. it clones + * the given string and returns a pointer to the new allocated + * clone (which must be freed by caller of course) or returns + * NULL on memory alloc or param errors. if 'size' is -1 the + * length of the input string is used, otherwise 'size' is used + * as custom clone size (the string is cropped to fit into mem + * if needed). -sea + */ +char *_pico_clone_alloc( char *str, int size ) +{ + char *cloned; + size_t cloneSize; + + /* sanity check */ + if (str == NULL) return NULL; + + /* set real size of cloned string */ + cloneSize = (size < 0) ? strlen(str) : size; + + /* allocate memory */ + cloned = _pico_alloc( cloneSize+1 ); /* bugfix! */ + if (cloned == NULL) + return NULL; + + /* zero out memory allocated by cloned string */ + memset( cloned,0,cloneSize ); + + /* copy input string to cloned string */ + if (cloneSize < strlen( str )) { + memcpy( cloned,str,cloneSize ); + cloned[ cloneSize ] = '\0'; + } else { + strcpy( cloned,str ); + } + /* return ptr to cloned string */ + return cloned; +} + +/* _pico_free: + * wrapper around the free function pointer + */ +void _pico_free( void *ptr ) +{ + /* sanity checks */ + if( ptr == NULL ) + return; + if (_pico_ptr_free == NULL) + return; + + /* free the allocated memory */ + _pico_ptr_free( ptr ); +} + +/* _pico_load_file: + * wrapper around the loadfile function pointer + */ +void _pico_load_file( char *name, unsigned char **buffer, int *bufSize ) +{ + /* sanity checks */ + if( name == NULL ) + { + *bufSize = -1; + return; + } + if (_pico_ptr_load_file == NULL) + { + *bufSize = -1; + return; + } + /* do the actual call to read in the file; */ + /* BUFFER IS ALLOCATED BY THE EXTERNAL LOADFILE FUNC */ + _pico_ptr_load_file( name,buffer,bufSize ); +} + +/* _pico_free_file: + * wrapper around the file free function pointer + */ +void _pico_free_file( void *buffer ) +{ + /* sanity checks */ + if( buffer == NULL ) + return; + + /* use default free */ + if( _pico_ptr_free_file == NULL ) + { + free( buffer ); + return; + } + /* free the allocated file */ + _pico_ptr_free_file( buffer ); +} + +/* _pico_printf: + * wrapper around the print function pointer -sea + */ +void _pico_printf( int level, const char *format, ...) +{ + char str[4096]; + va_list argptr; + + /* sanity checks */ + if( format == NULL ) + return; + if (_pico_ptr_print == NULL) + return; + + /* format string */ + va_start( argptr,format ); + vsprintf( str,format,argptr ); + va_end( argptr ); + + /* remove linefeeds */ + if (str[ strlen(str)-1 ] == '\n') + str[ strlen(str)-1 ] = '\0'; + + /* do the actual call */ + _pico_ptr_print( level,str ); +} + +/* _pico_strltrim: + * left trims the given string -sea + */ +char *_pico_strltrim( char *str ) +{ + char *str1 = str, *str2 = str; + + while (isspace(*str2)) str2++; + if( str2 != str ) + while( *str2 != '\0' ) /* fix: ydnar */ + *str1++ = *str2++; + return str; +} + +/* _pico_strrtrim: + * right trims the given string -sea + */ +char *_pico_strrtrim( char *str ) +{ + if (str && *str) + { + char *str1 = str; + int allspace = 1; + + while (*str1) + { + if (allspace && !isspace(*str1)) allspace = 0; + str1++; + } + if (allspace) *str = '\0'; + else { + str1--; + while ((isspace(*str1)) && (str1 >= str)) + *str1-- = '\0'; + } + } + return str; +} + +/* _pico_strlwr: + * pico internal string-to-lower routine. + */ +char *_pico_strlwr( char *str ) +{ + char *cp; + for (cp=str; *cp; ++cp) + { + if ('A' <= *cp && *cp <= 'Z') + { + *cp += ('a' - 'A'); + } + } + return str; +} + +/* _pico_strchcount: + * counts how often the given char appears in str. -sea + */ +int _pico_strchcount( char *str, int ch ) +{ + int count = 0; + while (*str++) if (*str == ch) count++; + return count; +} + +void _pico_zero_bounds( picoVec3_t mins, picoVec3_t maxs ) +{ + int i; + for (i=0; i<3; i++) + { + mins[i] = +999999; + maxs[i] = -999999; + } +} + +void _pico_expand_bounds( picoVec3_t p, picoVec3_t mins, picoVec3_t maxs ) +{ + int i; + for (i=0; i<3; i++) + { + float value = p[i]; + if (value < mins[i]) mins[i] = value; + if (value > maxs[i]) maxs[i] = value; + } +} + +void _pico_zero_vec( picoVec3_t vec ) +{ + vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = 0; +} + +void _pico_zero_vec2( picoVec2_t vec ) +{ + vec[ 0 ] = vec[ 1 ] = 0; +} + +void _pico_zero_vec4( picoVec4_t vec ) +{ + vec[ 0 ] = vec[ 1 ] = vec[ 2 ] = vec[ 3 ] = 0; +} + +void _pico_set_vec( picoVec3_t v, float a, float b, float c ) +{ + v[ 0 ] = a; + v[ 1 ] = b; + v[ 2 ] = c; +} + +void _pico_set_vec4( picoVec4_t v, float a, float b, float c, float d ) +{ + v[ 0 ] = a; + v[ 1 ] = b; + v[ 2 ] = c; + v[ 3 ] = d; +} + +void _pico_copy_vec( picoVec3_t src, picoVec3_t dest ) +{ + dest[ 0 ] = src[ 0 ]; + dest[ 1 ] = src[ 1 ]; + dest[ 2 ] = src[ 2 ]; +} + +void _pico_copy_vec2( picoVec2_t src, picoVec2_t dest ) +{ + dest[ 0 ] = src[ 0 ]; + dest[ 1 ] = src[ 1 ]; +} + +void _pico_copy_vec4( picoVec4_t src, picoVec4_t dest ) +{ + dest[ 0 ] = src[ 0 ]; + dest[ 1 ] = src[ 1 ]; + dest[ 2 ] = src[ 2 ]; + dest[ 3 ] = src[ 3 ]; +} + +/* ydnar */ +picoVec_t _pico_normalize_vec( picoVec3_t vec ) +{ + double len, ilen; + + len = sqrt( vec[ 0 ] * vec[ 0 ] + vec[ 1 ] * vec[ 1 ] + vec[ 2 ] * vec[ 2 ] ); + if( len == 0.0 ) return 0.0; + ilen = 1.0 / len; + vec[ 0 ] *= (picoVec_t) ilen; + vec[ 1 ] *= (picoVec_t) ilen; + vec[ 2 ] *= (picoVec_t) ilen; + return (picoVec_t) len; +} + +void _pico_add_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ) +{ + dest[ 0 ] = a[ 0 ] + b[ 0 ]; + dest[ 1 ] = a[ 1 ] + b[ 1 ]; + dest[ 2 ] = a[ 2 ] + b[ 2 ]; +} + +void _pico_subtract_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ) +{ + dest[ 0 ] = a[ 0 ] - b[ 0 ]; + dest[ 1 ] = a[ 1 ] - b[ 1 ]; + dest[ 2 ] = a[ 2 ] - b[ 2 ]; +} + +void _pico_scale_vec( picoVec3_t v, float scale, picoVec3_t dest ) +{ + dest[ 0 ] = v[ 0 ] * scale; + dest[ 1 ] = v[ 1 ] * scale; + dest[ 2 ] = v[ 2 ] * scale; +} + +void _pico_scale_vec4( picoVec4_t v, float scale, picoVec4_t dest ) +{ + dest[ 0 ] = v[ 0 ] * scale; + dest[ 1 ] = v[ 1 ] * scale; + dest[ 2 ] = v[ 2 ] * scale; + dest[ 3 ] = v[ 3 ] * scale; +} + +picoVec_t _pico_dot_vec( picoVec3_t a, picoVec3_t b ) +{ + return a[ 0 ] * b[ 0 ] + a[ 1 ] * b[ 1 ] + a[ 2 ] * b[ 2 ]; +} + +void _pico_cross_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ) +{ + dest[ 0 ] = a[ 1 ] * b[ 2 ] - a[ 2 ] * b[ 1 ]; + dest[ 1 ] = a[ 2 ] * b[ 0 ] - a[ 0 ] * b[ 2 ]; + dest[ 2 ] = a[ 0 ] * b[ 1 ] - a[ 1 ] * b[ 0 ]; +} + +picoVec_t _pico_calc_plane( picoVec4_t plane, picoVec3_t a, picoVec3_t b, picoVec3_t c ) +{ + picoVec3_t ba, ca; + + _pico_subtract_vec( b, a, ba ); + _pico_subtract_vec( c, a, ca ); + _pico_cross_vec( ca, ba, plane ); + plane[ 3 ] = _pico_dot_vec( a, plane ); + return _pico_normalize_vec( plane ); +} + +/* separate from _pico_set_vec4 */ +void _pico_set_color( picoColor_t c, int r, int g, int b, int a ) +{ + c[ 0 ] = r; + c[ 1 ] = g; + c[ 2 ] = b; + c[ 3 ] = a; +} + +void _pico_copy_color( picoColor_t src, picoColor_t dest ) +{ + dest[ 0 ] = src[ 0 ]; + dest[ 1 ] = src[ 1 ]; + dest[ 2 ] = src[ 2 ]; + dest[ 3 ] = src[ 3 ]; +} + +#ifdef __BIG_ENDIAN__ + +int _pico_big_long ( int src ) { return src; } +short _pico_big_short( short src ) { return src; } +float _pico_big_float( float src ) { return src; } + +int _pico_little_long( int src ) +{ + return ((src & 0xFF000000) >> 24) | + ((src & 0x00FF0000) >> 8) | + ((src & 0x0000FF00) << 8) | + ((src & 0x000000FF) << 24); +} + +short _pico_little_short( short src ) +{ + return ((src & 0xFF00) >> 8) | + ((src & 0x00FF) << 8); +} + +float _pico_little_float( float src ) +{ + floatSwapUnion in,out; + in.f = src; + out.c[ 0 ] = in.c[ 3 ]; + out.c[ 1 ] = in.c[ 2 ]; + out.c[ 2 ] = in.c[ 1 ]; + out.c[ 3 ] = in.c[ 0 ]; + return out.f; +} +#else /*__BIG_ENDIAN__*/ + +int _pico_little_long ( int src ) { return src; } +short _pico_little_short( short src ) { return src; } +float _pico_little_float( float src ) { return src; } + +int _pico_big_long( int src ) +{ + return ((src & 0xFF000000) >> 24) | + ((src & 0x00FF0000) >> 8) | + ((src & 0x0000FF00) << 8) | + ((src & 0x000000FF) << 24); +} + +short _pico_big_short( short src ) +{ + return ((src & 0xFF00) >> 8) | + ((src & 0x00FF) << 8); +} + +float _pico_big_float( float src ) +{ + floatSwapUnion in,out; + in.f = src; + out.c[ 0 ] = in.c[ 3 ]; + out.c[ 1 ] = in.c[ 2 ]; + out.c[ 2 ] = in.c[ 1 ]; + out.c[ 3 ] = in.c[ 0 ]; + return out.f; +} +#endif /*__BIG_ENDIAN__*/ + +/* _pico_stristr: + * case-insensitive strstr. -sea + */ +char *_pico_stristr( char *str, const char *substr ) +{ + const int sublen = strlen(substr); + while (*str) + { + if (!_pico_strnicmp(str,substr,sublen)) break; + str++; + } + if (!(*str)) str = NULL; + return str; +} + +/* +_pico_unixify() +changes dos \ style path separators to / +*/ + +void _pico_unixify( char *path ) +{ + if( path == NULL ) + return; + while( *path ) + { + if( *path == '\\' ) + *path = '/'; + path++; + } +} + +/* _pico_nofname: + * removes file name portion from given file path and converts + * the directory separators to un*x style. returns 1 on success + * or 0 when 'destSize' was exceeded. -sea + */ +int _pico_nofname( const char *path, char *dest, int destSize ) +{ + int left = destSize; + char *temp = dest; + + while ((*dest = *path) != '\0') + { + if (*dest == '/' || *dest == '\\') + { + temp = (dest + 1); + *dest = '/'; + } + dest++; path++; + + if (--left < 1) + { + *temp = '\0'; + return 0; + } + } + *temp = '\0'; + return 1; +} + +/* _pico_nopath: + * returns ptr to filename portion in given path or an empty + * string otherwise. given 'path' is not altered. -sea + */ +char *_pico_nopath( const char *path ) +{ + char *src; + src = (char *)path + (strlen(path) - 1); + + if (path == NULL) return (char *)""; + if (!strchr((char *)path,'/') && !strchr((char *)path,'\\')) + return ((char *)path); + + while ((src--) != path) + { + if (*src == '/' || *src == '\\') + return (++src); + } + return (char *)""; +} + +/* _pico_setfext: + * sets/changes the file extension for the given filename + * or filepath's filename portion. the given 'path' *is* + * altered. leave 'ext' empty to remove extension. -sea + */ +char *_pico_setfext( char *path, const char *ext ) +{ + char *src; + int remfext = 0; + + src = path + (strlen(path) - 1); + + if (ext == NULL) ext = ""; + if (strlen(ext ) < 1) remfext = 1; + if (strlen(path) < 1) + return path; + + while ((src--) != path) + { + if (*src == '/' || *src == '\\') + return path; + + if (*src == '.') + { + if (remfext) + { + *src = '\0'; + return path; + } + *(++src) = '\0'; + break; + } + } + strcat(path,ext); + return path; +} + +/* _pico_getline: + * extracts one line from the given buffer and stores it in dest. + * returns -1 on error or the length of the line on success. i've + * removed string trimming here. this can be done manually by the + * calling func. + */ +int _pico_getline( char *buf, int bufsize, char *dest, int destsize ) +{ + int pos; + + /* check output */ + if (dest == NULL || destsize < 1) return -1; + memset( dest,0,destsize ); + + /* check input */ + if (buf == NULL || bufsize < 1) + return -1; + + /* get next line */ + for (pos=0; poscursor == NULL) + return; + + /* skin white spaces */ + while( 1 ) + { + /* sanity checks */ + if (p->cursor < p->buffer || + p->cursor >= p->max) + { + return; + } + /* break for chars other than white spaces */ + if (*p->cursor > 0x20) break; + if (*p->cursor == 0x00) return; + + /* a bit of linefeed handling */ + if (*p->cursor == '\n') + { + *hasLFs = 1; + p->curLine++; + } + /* go to next character */ + p->cursor++; + } +} + +/* _pico_new_parser: + * allocates a new ascii parser object. + */ +picoParser_t *_pico_new_parser( picoByte_t *buffer, int bufSize ) +{ + picoParser_t *p; + + /* sanity check */ + if( buffer == NULL || bufSize <= 0 ) + return NULL; + + /* allocate reader */ + p = _pico_alloc( sizeof(picoParser_t) ); + if (p == NULL) return NULL; + memset( p,0,sizeof(picoParser_t) ); + + /* allocate token space */ + p->tokenSize = 0; + p->tokenMax = 1024; + p->token = _pico_alloc( p->tokenMax ); + if( p->token == NULL ) + { + _pico_free( p ); + return NULL; + } + /* setup */ + p->buffer = buffer; + p->cursor = buffer; + p->bufSize = bufSize; + p->max = p->buffer + bufSize; + p->curLine = 1; /* sea: new */ + + /* return ptr to parser */ + return p; +} + +/* _pico_free_parser: + * frees an existing pico parser object. + */ +void _pico_free_parser( picoParser_t *p ) +{ + /* sanity check */ + if (p == NULL) return; + + /* free the parser */ + if (p->token != NULL) + { + _pico_free( p->token ); + } + _pico_free( p ); +} + +/* _pico_parse_ex: + * reads the next token from given pico parser object. if param + * 'allowLFs' is 1 it will read beyond linefeeds and return 0 when + * the EOF is reached. if 'allowLFs' is 0 it will return 0 when + * the EOL is reached. if 'handleQuoted' is 1 the parser function + * will handle "quoted" strings and return the data between the + * quotes as token. returns 0 on end/error or 1 on success. -sea + */ +int _pico_parse_ex( picoParser_t *p, int allowLFs, int handleQuoted ) +{ + int hasLFs = 0; + char *old; + + /* sanity checks */ + if( p == NULL || p->buffer == NULL || + p->cursor < p->buffer || + p->cursor >= p->max ) + { + return 0; + } + /* clear parser token */ + p->tokenSize = 0; + p->token[ 0 ] = '\0'; + old = p->cursor; + + /* skip whitespaces */ + while( p->cursor < p->max && *p->cursor <= 32 ) + { + if (*p->cursor == '\n') + { + p->curLine++; + hasLFs++; + } + p->cursor++; + } + /* return if we're not allowed to go beyond lfs */ + if ((hasLFs > 0) && !allowLFs) + { + p->cursor = old; + return 0; + } + /* get next quoted string */ + if (*p->cursor == '\"' && handleQuoted) + { + p->cursor++; + while (p->cursor < p->max && *p->cursor) + { + if (*p->cursor == '\\') + { + if (*(p->cursor+1) == '"') + { + p->cursor++; + } + p->token[ p->tokenSize++ ] = *p->cursor++; + continue; + } + else if (*p->cursor == '\"') + { + p->cursor++; + break; + } + else if (*p->cursor == '\n') + { + p->curLine++; + } + p->token[ p->tokenSize++ ] = *p->cursor++; + } + /* terminate token */ + p->token[ p->tokenSize ] = '\0'; + return 1; + } + /* otherwise get next word */ + while( p->cursor < p->max && *p->cursor > 32 ) + { + if (*p->cursor == '\n') + { + p->curLine++; + } + p->token[ p->tokenSize++ ] = *p->cursor++; + } + /* terminate token */ + p->token[ p->tokenSize ] = '\0'; + return 1; +} + +/* _pico_parse_first: + * reads the first token from the next line and returns + * a pointer to it. returns NULL on EOL or EOF. -sea + */ +char *_pico_parse_first( picoParser_t *p ) +{ + /* sanity check */ + if (p == NULL) return NULL; + + /* try to read next token (with lfs & quots) */ + if (!_pico_parse_ex( p,1,1 )) + return NULL; + + /* return ptr to the token string */ + return p->token; +} + +/* _pico_parse: + * reads the next token from the parser and returns a pointer + * to it. quoted strings are handled as usual. returns NULL + * on EOL or EOF. -sea + */ +char *_pico_parse( picoParser_t *p, int allowLFs ) +{ + /* sanity check */ + if (p == NULL) return NULL; + + /* try to read next token (with quots) */ + if (!_pico_parse_ex( p,allowLFs,1 )) + return NULL; + + /* return ptr to the token string */ + return p->token; +} + +/* _pico_parse_skip_rest: + * skips the rest of the current line in parser. + */ +void _pico_parse_skip_rest( picoParser_t *p ) +{ + while( _pico_parse_ex( p,0,0 ) ) ; +} + +/* _pico_parse_skip_braced: + * parses/skips over a braced section. returns 1 on success + * or 0 on error (when there was no closing bracket and the + * end of buffer was reached or when the opening bracket was + * missing). + */ +int _pico_parse_skip_braced( picoParser_t *p ) +{ + int firstToken = 1; + int level; + + /* sanity check */ + if (p == NULL) return 0; + + /* set the initial level for parsing */ + level = 0; + + /* skip braced section */ + while( 1 ) + { + /* read next token (lfs allowed) */ + if (!_pico_parse_ex( p,1,1 )) + { + /* end of parser buffer reached */ + return 0; + } + /* first token must be an opening bracket */ + if (firstToken && p->token[0] != '{') + { + /* opening bracket missing */ + return 0; + } + /* we only check this once */ + firstToken = 0; + + /* update level */ + if (p->token[1] == '\0') + { + if (p->token[0] == '{') level++; + if (p->token[0] == '}') level--; + } + /* break if we're back at our starting level */ + if (level == 0) break; + } + /* successfully skipped braced section */ + return 1; +} + +int _pico_parse_check( picoParser_t *p, int allowLFs, char *str ) +{ + if (!_pico_parse_ex( p,allowLFs,1 )) + return 0; + if (!strcmp(p->token,str)) + return 1; + return 0; +} + +int _pico_parse_checki( picoParser_t *p, int allowLFs, char *str ) +{ + if (!_pico_parse_ex( p,allowLFs,1 )) + return 0; + if (!_pico_stricmp(p->token,str)) + return 1; + return 0; +} + +int _pico_parse_int( picoParser_t *p, int *out ) +{ + char *token; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* get token and turn it into an integer */ + *out = 0; + token = _pico_parse( p,0 ); + if (token == NULL) return 0; + *out = atoi( token ); + + /* success */ + return 1; +} + +int _pico_parse_int_def( picoParser_t *p, int *out, int def ) +{ + char *token; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* get token and turn it into an integer */ + *out = def; + token = _pico_parse( p,0 ); + if (token == NULL) return 0; + *out = atoi( token ); + + /* success */ + return 1; +} + +int _pico_parse_float( picoParser_t *p, float *out ) +{ + char *token; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* get token and turn it into a float */ + *out = 0.0f; + token = _pico_parse( p,0 ); + if (token == NULL) return 0; + *out = (float) atof( token ); + + /* success */ + return 1; +} + +int _pico_parse_float_def( picoParser_t *p, float *out, float def ) +{ + char *token; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* get token and turn it into a float */ + *out = def; + token = _pico_parse( p,0 ); + if (token == NULL) return 0; + *out = (float) atof( token ); + + /* success */ + return 1; +} + +int _pico_parse_vec( picoParser_t *p, picoVec3_t out ) +{ + char *token; + int i; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* zero out outination vector */ + _pico_zero_vec( out ); + + /* parse three vector components */ + for (i=0; i<3; i++) + { + token = _pico_parse( p,0 ); + if (token == NULL) + { + _pico_zero_vec( out ); + return 0; + } + out[ i ] = (float) atof( token ); + } + /* success */ + return 1; +} + +int _pico_parse_vec_def( picoParser_t *p, picoVec3_t out, picoVec3_t def ) +{ + char *token; + int i; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* assign default vector value */ + _pico_copy_vec( def,out ); + + /* parse three vector components */ + for (i=0; i<3; i++) + { + token = _pico_parse( p,0 ); + if (token == NULL) + { + _pico_copy_vec( def,out ); + return 0; + } + out[ i ] = (float) atof( token ); + } + /* success */ + return 1; +} + +int _pico_parse_vec2( picoParser_t *p, picoVec2_t out ) +{ + char *token; + int i; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* zero out outination vector */ + _pico_zero_vec2( out ); + + /* parse two vector components */ + for (i=0; i<2; i++) + { + token = _pico_parse( p,0 ); + if (token == NULL) + { + _pico_zero_vec2( out ); + return 0; + } + out[ i ] = (float) atof( token ); + } + /* success */ + return 1; +} + +int _pico_parse_vec2_def( picoParser_t *p, picoVec2_t out, picoVec2_t def ) +{ + char *token; + int i; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* assign default vector value */ + _pico_copy_vec2( def,out ); + + /* parse two vector components */ + for (i=0; i<2; i++) + { + token = _pico_parse( p,0 ); + if (token == NULL) + { + _pico_copy_vec2( def,out ); + return 0; + } + out[ i ] = (float) atof( token ); + } + /* success */ + return 1; +} + +int _pico_parse_vec4( picoParser_t *p, picoVec4_t out ) +{ + char *token; + int i; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* zero out outination vector */ + _pico_zero_vec4( out ); + + /* parse four vector components */ + for (i=0; i<4; i++) + { + token = _pico_parse( p,0 ); + if (token == NULL) + { + _pico_zero_vec4( out ); + return 0; + } + out[ i ] = (float) atof( token ); + } + /* success */ + return 1; +} + +int _pico_parse_vec4_def( picoParser_t *p, picoVec4_t out, picoVec4_t def ) +{ + char *token; + int i; + + /* sanity checks */ + if (p == NULL || out == NULL) + return 0; + + /* assign default vector value */ + _pico_copy_vec4( def,out ); + + /* parse four vector components */ + for (i=0; i<4; i++) + { + token = _pico_parse( p,0 ); + if (token == NULL) + { + _pico_copy_vec4( def,out ); + return 0; + } + out[ i ] = (float) atof( token ); + } + /* success */ + return 1; +} + +/* _pico_new_memstream: + * allocates a new memorystream object. + */ +picoMemStream_t *_pico_new_memstream( picoByte_t *buffer, int bufSize ) +{ + picoMemStream_t *s; + + /* sanity check */ + if( buffer == NULL || bufSize <= 0 ) + return NULL; + + /* allocate stream */ + s = _pico_alloc( sizeof(picoMemStream_t) ); + if (s == NULL) return NULL; + memset( s,0,sizeof(picoMemStream_t) ); + + /* setup */ + s->buffer = buffer; + s->curPos = buffer; + s->bufSize = bufSize; + s->flag = 0; + + /* return ptr to stream */ + return s; +} + +/* _pico_free_memstream: + * frees an existing pico memorystream object. + */ +void _pico_free_memstream( picoMemStream_t *s ) +{ + /* sanity check */ + if (s == NULL) return; + + /* free the stream */ + _pico_free( s ); +} + +/* _pico_memstream_read: + * reads data from a pico memorystream into a buffer. + */ +int _pico_memstream_read( picoMemStream_t *s, void *buffer, int len ) +{ + int ret = 1; + + /* sanity checks */ + if (s == NULL || buffer == NULL) + return 0; + + if (s->curPos + len > s->buffer + s->bufSize) + { + s->flag |= PICO_IOEOF; + len = s->buffer + s->bufSize - s->curPos; + ret = 0; + } + + /* read the data */ + memcpy( buffer, s->curPos, len ); + s->curPos += len; + return ret; +} + +/* _pico_memstream_read: + * reads a character from a pico memorystream + */ +int _pico_memstream_getc( picoMemStream_t *s ) +{ + int c = 0; + + /* sanity check */ + if (s == NULL) + return -1; + + /* read the character */ + if (_pico_memstream_read( s, &c, 1) == 0) + return -1; + + return c; +} + +/* _pico_memstream_seek: + * sets the current read position to a different location + */ +int _pico_memstream_seek( picoMemStream_t *s, long offset, int origin ) +{ + int overflow; + + /* sanity check */ + if (s == NULL) + return -1; + + if (origin == PICO_SEEK_SET) + { + s->curPos = s->buffer + offset; + overflow = s->curPos - ( s->buffer + s->bufSize ); + if (overflow > 0) + { + s->curPos = s->buffer + s->bufSize; + return offset - overflow; + } + return 0; + } + else if (origin == PICO_SEEK_CUR) + { + s->curPos += offset; + overflow = s->curPos - ( s->buffer + s->bufSize ); + if (overflow > 0) + { + s->curPos = s->buffer + s->bufSize; + return offset - overflow; + } + return 0; + } + else if (origin == PICO_SEEK_END) + { + s->curPos = ( s->buffer + s->bufSize ) - offset; + overflow = s->buffer - s->curPos; + if (overflow > 0) + { + s->curPos = s->buffer; + return offset - overflow; + } + return 0; + } + + return -1; +} + +/* _pico_memstream_tell: + * returns the current read position in the pico memorystream + */ +long _pico_memstream_tell( picoMemStream_t *s ) +{ + /* sanity check */ + if (s == NULL) + return -1; + + return s->curPos - s->buffer; +} diff --git a/libs/picomodel/picointernal.h b/libs/picomodel/picointernal.h new file mode 100644 index 00000000..37686ce1 --- /dev/null +++ b/libs/picomodel/picointernal.h @@ -0,0 +1,205 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +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 names of the copyright holders 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. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#ifndef PICOINTERNAL_H +#define PICOINTERNAL_H + +#ifdef __cplusplus +extern "C" +{ +#endif + + +/* dependencies */ +#include +#include +#include +#include +#include +#include + +#include "picomodel.h" + + +/* os dependant replacements */ +#if WIN32 || _WIN32 + #define _pico_stricmp stricmp + #define _pico_strnicmp strnicmp +#else + #define _pico_stricmp strcasecmp + #define _pico_strnicmp strncasecmp +#endif + + +/* constants */ +#define PICO_PI 3.14159265358979323846 + +#define PICO_SEEK_SET 0 +#define PICO_SEEK_CUR 1 +#define PICO_SEEK_END 2 + +#define PICO_IOEOF 1 +#define PICO_IOERR 2 + +/* types */ +typedef struct picoParser_s +{ + char *buffer; + int bufSize; + char *token; + int tokenSize; + int tokenMax; + char *cursor; + char *max; + int curLine; +} +picoParser_t; + +typedef struct picoMemStream_s +{ + picoByte_t *buffer; + int bufSize; + picoByte_t *curPos; + int flag; +} +picoMemStream_t; + + +/* variables */ +extern const picoModule_t *picoModules[]; + +extern void *(*_pico_ptr_malloc)( size_t ); +extern void (*_pico_ptr_free)( void* ); +extern void (*_pico_ptr_load_file)( char*, unsigned char**, int* ); +extern void (*_pico_ptr_free_file)( void* ); +extern void (*_pico_ptr_print)( int, const char* ); + + + +/* prototypes */ + +/* memory */ +void *_pico_alloc( size_t size ); +void *_pico_calloc( size_t num, size_t size ); +void *_pico_realloc( void **ptr, size_t oldSize, size_t newSize ); +char *_pico_clone_alloc( char *str, int size ); +void _pico_free( void *ptr ); + +/* files */ +void _pico_load_file( char *name, unsigned char **buffer, int *bufSize ); +void _pico_free_file( void *buffer ); + +/* strings */ +char *_pico_strltrim( char *str ); +char *_pico_strrtrim( char *str ); +int _pico_strchcount( char *str, int ch ); +void _pico_printf( int level, const char *format, ... ); +char *_pico_stristr( char *str, const char *substr ); +void _pico_unixify( char *path ); +int _pico_nofname( const char *path, char *dest, int destSize ); +char *_pico_nopath( const char *path ); +char *_pico_setfext( char *path, const char *ext ); +int _pico_getline( char *buf, int bufsize, char *dest, int destsize ); +char *_pico_strlwr( char *str ); + +/* vectors */ +void _pico_zero_bounds( picoVec3_t mins, picoVec3_t maxs ); +void _pico_expand_bounds( picoVec3_t p, picoVec3_t mins, picoVec3_t maxs ); +void _pico_zero_vec( picoVec3_t vec ); +void _pico_zero_vec2( picoVec2_t vec ); +void _pico_zero_vec4( picoVec4_t vec ); +void _pico_set_vec( picoVec3_t v, float a, float b, float c ); +void _pico_set_vec4( picoVec4_t v, float a, float b, float c, float d ); +void _pico_set_color( picoColor_t c, int r, int g, int b, int a ); +void _pico_copy_color( picoColor_t src, picoColor_t dest ); +void _pico_copy_vec( picoVec3_t src, picoVec3_t dest ); +void _pico_copy_vec2( picoVec2_t src, picoVec2_t dest ); +picoVec_t _pico_normalize_vec( picoVec3_t vec ); +void _pico_add_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ); +void _pico_subtract_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ); +picoVec_t _pico_dot_vec( picoVec3_t a, picoVec3_t b ); +void _pico_cross_vec( picoVec3_t a, picoVec3_t b, picoVec3_t dest ); +picoVec_t _pico_calc_plane( picoVec4_t plane, picoVec3_t a, picoVec3_t b, picoVec3_t c ); +void _pico_scale_vec( picoVec3_t v, float scale, picoVec3_t dest ); +void _pico_scale_vec4( picoVec4_t v, float scale, picoVec4_t dest ); + +/* endian */ +int _pico_big_long( int src ); +short _pico_big_short( short src ); +float _pico_big_float( float src ); + +int _pico_little_long( int src ); +short _pico_little_short( short src ); +float _pico_little_float( float src ); + +/* pico ascii parser */ +picoParser_t *_pico_new_parser( picoByte_t *buffer, int bufSize ); +void _pico_free_parser( picoParser_t *p ); +int _pico_parse_ex( picoParser_t *p, int allowLFs, int handleQuoted ); +char *_pico_parse_first( picoParser_t *p ); +char *_pico_parse( picoParser_t *p, int allowLFs ); +void _pico_parse_skip_rest( picoParser_t *p ); +int _pico_parse_skip_braced( picoParser_t *p ); +int _pico_parse_check( picoParser_t *p, int allowLFs, char *str ); +int _pico_parse_checki( picoParser_t *p, int allowLFs, char *str ); +int _pico_parse_int( picoParser_t *p, int *out ); +int _pico_parse_int_def( picoParser_t *p, int *out, int def ); +int _pico_parse_float( picoParser_t *p, float *out ); +int _pico_parse_float_def( picoParser_t *p, float *out, float def ); +int _pico_parse_vec( picoParser_t *p, picoVec3_t out); +int _pico_parse_vec_def( picoParser_t *p, picoVec3_t out, picoVec3_t def); +int _pico_parse_vec2( picoParser_t *p, picoVec2_t out ); +int _pico_parse_vec2_def( picoParser_t *p, picoVec2_t out, picoVec2_t def ); +int _pico_parse_vec4( picoParser_t *p, picoVec4_t out); +int _pico_parse_vec4_def( picoParser_t *p, picoVec4_t out, picoVec4_t def); + +/* pico memory stream */ +picoMemStream_t *_pico_new_memstream( picoByte_t *buffer, int bufSize ); +void _pico_free_memstream( picoMemStream_t *s ); +int _pico_memstream_read( picoMemStream_t *s, void *buffer, int len ); +int _pico_memstream_getc( picoMemStream_t *s ); +int _pico_memstream_seek( picoMemStream_t *s, long offset, int origin ); +long _pico_memstream_tell( picoMemStream_t *s ); +#define _pico_memstream_eof( _pico_memstream ) ((_pico_memstream)->flag & PICO_IOEOF) +#define _pico_memstream_error( _pico_memstream ) ((_pico_memstream)->flag & PICO_IOERR) + +/* end marker */ +#ifdef __cplusplus +} +#endif + +#endif diff --git a/libs/picomodel/picomodel.c b/libs/picomodel/picomodel.c new file mode 100644 index 00000000..ed4f8b21 --- /dev/null +++ b/libs/picomodel/picomodel.c @@ -0,0 +1,1995 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +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 names of the copyright holders 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. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PICOMODEL_C + + + +/* dependencies */ +#include "picointernal.h" + + + +/* +PicoInit() +initializes the picomodel library +*/ + +int PicoInit( void ) +{ + /* successfully initialized -sea */ + return 1; +} + + + +/* +PicoShutdown() +shuts the pico model library down +*/ + +void PicoShutdown( void ) +{ + /* do something interesting here in the future */ + return; +} + + + +/* +PicoError() +returns last picomodel error code (see PME_* defines) +*/ + +int PicoError( void ) +{ + /* todo: do something here */ + return 0; +} + + + +/* +PicoSetMallocFunc() +sets the ptr to the malloc function +*/ + +void PicoSetMallocFunc( void *(*func)( size_t ) ) +{ + if( func != NULL ) + _pico_ptr_malloc = func; +} + + + +/* +PicoSetFreeFunc() +sets the ptr to the free function +*/ + +void PicoSetFreeFunc( void (*func)( void* ) ) +{ + if( func != NULL ) + _pico_ptr_free = func; +} + + + +/* +PicoSetLoadFileFunc() +sets the ptr to the file load function +*/ + +void PicoSetLoadFileFunc( void (*func)( char*, unsigned char**, int* ) ) +{ + if( func != NULL ) + _pico_ptr_load_file = func; +} + + + +/* +PicoSetFreeFileFunc() +sets the ptr to the free function +*/ + +void PicoSetFreeFileFunc( void (*func)( void* ) ) +{ + if( func != NULL ) + _pico_ptr_free_file = func; +} + + + +/* +PicoSetPrintFunc() +sets the ptr to the print function +*/ + +void PicoSetPrintFunc( void (*func)( int, const char* ) ) +{ + if( func != NULL ) + _pico_ptr_print = func; +} + + + +/* +PicoLoadModel() +the meat and potatoes function +*/ + +picoModel_t *PicoLoadModel( char *fileName, int frameNum ) +{ + const picoModule_t **modules, *pm; + picoModel_t *model; + picoByte_t *buffer; + int bufSize; + char *modelFileName, *remapFileName; + + + /* init */ + model = NULL; + + /* make sure we've got a file name */ + if( fileName == NULL ) + { + _pico_printf( PICO_ERROR, "PicoLoadModel: No filename given (fileName == NULL)" ); + return NULL; + } + + /* load file data (buffer is allocated by host app) */ + _pico_load_file( fileName, &buffer, &bufSize ); + if( bufSize < 0 ) + { + _pico_printf( PICO_ERROR, "PicoLoadModel: Failed loading model %s", fileName ); + return NULL; + } + + /* get ptr to list of supported modules */ + modules = PicoModuleList( NULL ); + + /* run it through the various loader functions and try */ + /* to find a loader that fits the given file data */ + for( ; *modules != NULL; modules++ ) + { + /* get module */ + pm = *modules; + + /* sanity check */ + if( pm == NULL) + break; + + /* module must be able to load */ + if( pm->canload == NULL || pm->load == NULL ) + continue; + + /* see whether this module can load the model file or not */ + if( pm->canload( fileName, buffer, bufSize ) == PICO_PMV_OK ) + { + /* use loader provided by module to read the model data */ + model = pm->load( fileName, frameNum, buffer, bufSize ); + if( model == NULL ) + { + _pico_free_file( buffer ); + return NULL; + } + + /* assign pointer to file format module */ + model->module = pm; + + /* get model file name */ + modelFileName = PicoGetModelFileName( model ); + + /* apply model remappings from .remap */ + if( strlen( modelFileName ) ) + { + /* alloc copy of model file name */ + remapFileName = _pico_alloc( strlen( modelFileName ) + 20 ); + if( remapFileName != NULL ) + { + /* copy model file name and change extension */ + strcpy( remapFileName, modelFileName ); + _pico_setfext( remapFileName, "remap" ); + + /* try to remap model; we don't handle the result */ + PicoRemapModel( model, remapFileName ); + + /* free the remap file name string */ + _pico_free( remapFileName ); + } + } + + /* model was loaded, so break out of loop */ + break; + } + } + + /* free memory used by file buffer */ + if( buffer) + _pico_free_file( buffer ); + + /* return */ + return model; +} + + + +/* ---------------------------------------------------------------------------- +models +---------------------------------------------------------------------------- */ + +/* +PicoNewModel() +creates a new pico model +*/ + +picoModel_t *PicoNewModel( void ) +{ + picoModel_t *model; + + /* allocate */ + model = _pico_alloc( sizeof(picoModel_t) ); + if( model == NULL ) + return NULL; + + /* clear */ + memset( model,0,sizeof(picoModel_t) ); + + /* model set up */ + _pico_zero_bounds( model->mins,model->maxs ); + + /* set initial frame count to 1 -sea */ + model->numFrames = 1; + + /* return ptr to new model */ + return model; +} + + + +/* +PicoFreeModel() +frees a model and all associated data +*/ + +void PicoFreeModel( picoModel_t *model ) +{ + int i; + + + /* sanity check */ + if( model == NULL ) + return; + + /* free bits */ + if( model->name ) + _pico_free( model->name ); + + /* free shaders */ + for( i = 0; i < model->numShaders; i++ ) + PicoFreeShader( model->shader[ i ] ); + free( model->shader ); + + /* free surfaces */ + for( i = 0; i < model->numSurfaces; i++ ) + PicoFreeSurface( model->surface[ i ] ); + free( model->surface ); + + /* free the model */ + _pico_free( model ); +} + + + +/* +PicoAdjustModel() +adjusts a models's memory allocations to handle the requested sizes. +will always grow, never shrink +*/ + +int PicoAdjustModel( picoModel_t *model, int numShaders, int numSurfaces ) +{ + /* dummy check */ + if( model == NULL ) + return 0; + + /* bare minimums */ + /* sea: null surface/shader fix (1s=>0s) */ + if( numShaders < 0 ) + numShaders = 0; + if( numSurfaces < 0 ) + numSurfaces = 0; + + /* additional shaders? */ + while( numShaders > model->maxShaders ) + { + model->maxShaders += PICO_GROW_SHADERS; + if( !_pico_realloc( (void *) &model->shader, model->numShaders * sizeof( *model->shader ), model->maxShaders * sizeof( *model->shader ) ) ) + return 0; + } + + /* set shader count to higher */ + if( numShaders > model->numShaders ) + model->numShaders = numShaders; + + /* additional surfaces? */ + while( numSurfaces > model->maxSurfaces ) + { + model->maxSurfaces += PICO_GROW_SURFACES; + if( !_pico_realloc( (void *) &model->surface, model->numSurfaces * sizeof( *model->surface ), model->maxSurfaces * sizeof( *model->surface ) ) ) + return 0; + } + + /* set shader count to higher */ + if( numSurfaces > model->numSurfaces ) + model->numSurfaces = numSurfaces; + + /* return ok */ + return 1; +} + + + +/* ---------------------------------------------------------------------------- +shaders +---------------------------------------------------------------------------- */ + +/* +PicoNewShader() +creates a new pico shader and returns its index. -sea +*/ + +picoShader_t *PicoNewShader( picoModel_t *model ) +{ + picoShader_t *shader; + + + /* allocate and clear */ + shader = _pico_alloc( sizeof(picoShader_t) ); + if( shader == NULL ) + return NULL; + memset( shader, 0, sizeof(picoShader_t) ); + + /* attach it to the model */ + if( model != NULL ) + { + /* adjust model */ + if( !PicoAdjustModel( model, model->numShaders + 1, 0 ) ) + { + _pico_free( shader ); + return NULL; + } + /* attach */ + model->shader[ model->numShaders - 1 ] = shader; + shader->model = model; + } + /* setup default shader colors */ + _pico_set_color( shader->ambientColor,0,0,0,0 ); + _pico_set_color( shader->diffuseColor,255,255,255,1 ); + _pico_set_color( shader->specularColor,0,0,0,0 ); + + /* no need to do this, but i do it anyway */ + shader->transparency = 0; + shader->shininess = 0; + + /* return the newly created shader */ + return shader; +} + + + +/* +PicoFreeShader() +frees a shader and all associated data -sea +*/ + +void PicoFreeShader( picoShader_t *shader ) +{ + /* dummy check */ + if( shader == NULL ) + return; + + /* free bits */ + if( shader->name ) + _pico_free( shader->name ); + if( shader->mapName ) + _pico_free( shader->mapName ); + + /* free the shader */ + _pico_free( shader ); +} + + + +/* +PicoFindShader() +finds a named shader in a model +*/ + +picoShader_t *PicoFindShader( picoModel_t *model, char *name, int caseSensitive ) +{ + int i; + + + /* sanity checks */ + if( model == NULL || name == NULL ) /* sea: null name fix */ + return NULL; + + /* walk list */ + for( i = 0; i < model->numShaders; i++ ) + { + /* skip null shaders or shaders with null names */ + if( model->shader[ i ] == NULL || + model->shader[ i ]->name == NULL ) + continue; + + /* compare the shader name with name we're looking for */ + if( caseSensitive ) + { + if( !strcmp( name, model->shader[ i ]->name ) ) + return model->shader[ i ]; + } + else if( !_pico_stricmp( name, model->shader[ i ]->name ) ) + return model->shader[ i ]; + } + + /* named shader not found */ + return NULL; +} + + + +/* ---------------------------------------------------------------------------- +surfaces +---------------------------------------------------------------------------- */ + +/* +PicoNewSurface() +creates a new pico surface +*/ + +picoSurface_t *PicoNewSurface( picoModel_t *model ) +{ + picoSurface_t *surface; + char surfaceName[64]; + + /* allocate and clear */ + surface = _pico_alloc( sizeof( *surface ) ); + if( surface == NULL ) + return NULL; + memset( surface, 0, sizeof( *surface ) ); + + /* attach it to the model */ + if( model != NULL ) + { + /* adjust model */ + if( !PicoAdjustModel( model, 0, model->numSurfaces + 1 ) ) + { + _pico_free( surface ); + return NULL; + } + + /* attach */ + model->surface[ model->numSurfaces - 1 ] = surface; + surface->model = model; + + /* set default name */ + sprintf( surfaceName, "Unnamed_%d", model->numSurfaces ); + PicoSetSurfaceName( surface, surfaceName ); + } + + /* return */ + return surface; +} + + + +/* +PicoFreeSurface() +frees a surface and all associated data +*/ +void PicoFreeSurface( picoSurface_t *surface ) +{ + int i; + + + /* dummy check */ + if( surface == NULL ) + return; + + /* free bits */ + _pico_free( surface->xyz ); + _pico_free( surface->normal ); + _pico_free( surface->index ); + _pico_free( surface->faceNormal ); + + /* free arrays */ + for( i = 0; i < surface->numSTArrays; i++ ) + _pico_free( surface->st[ i ] ); + free( surface->st ); + for( i = 0; i < surface->numColorArrays; i++ ) + _pico_free( surface->color[ i ] ); + free( surface->color ); + + /* free the surface */ + _pico_free( surface ); +} + + + +/* +PicoAdjustSurface() +adjusts a surface's memory allocations to handle the requested sizes. +will always grow, never shrink +*/ + +int PicoAdjustSurface( picoSurface_t *surface, int numVertexes, int numSTArrays, int numColorArrays, int numIndexes, int numFaceNormals ) +{ + int i; + + + /* dummy check */ + if( surface == NULL ) + return 0; + + /* bare minimums */ + if( numVertexes < 1 ) + numVertexes = 1; + if( numSTArrays < 1 ) + numSTArrays = 1; + if( numColorArrays < 1 ) + numColorArrays = 1; + if( numIndexes < 1 ) + numIndexes = 1; + + /* additional vertexes? */ + while( numVertexes > surface->maxVertexes ) /* fix */ + { + surface->maxVertexes += PICO_GROW_VERTEXES; + if( !_pico_realloc( (void *) &surface->xyz, surface->numVertexes * sizeof( *surface->xyz ), surface->maxVertexes * sizeof( *surface->xyz ) ) ) + return 0; + if( !_pico_realloc( (void *) &surface->normal, surface->numVertexes * sizeof( *surface->normal ), surface->maxVertexes * sizeof( *surface->normal ) ) ) + return 0; + for( i = 0; i < surface->numSTArrays; i++ ) + if( !_pico_realloc( (void*) &surface->st[ i ], surface->numVertexes * sizeof( *surface->st[ i ] ), surface->maxVertexes * sizeof( *surface->st[ i ] ) ) ) + return 0; + for( i = 0; i < surface->numColorArrays; i++ ) + if( !_pico_realloc( (void*) &surface->color[ i ], surface->numVertexes * sizeof( *surface->color[ i ] ), surface->maxVertexes * sizeof( *surface->color[ i ] ) ) ) + return 0; + } + + /* set vertex count to higher */ + if( numVertexes > surface->numVertexes ) + surface->numVertexes = numVertexes; + + /* additional st arrays? */ + while( numSTArrays > surface->maxSTArrays ) /* fix */ + { + surface->maxSTArrays += PICO_GROW_ARRAYS; + if( !_pico_realloc( (void*) &surface->st, surface->numSTArrays * sizeof( *surface->st ), surface->maxSTArrays * sizeof( *surface->st ) ) ) + return 0; + while( surface->numSTArrays < numSTArrays ) + { + surface->st[ surface->numSTArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->st[ 0 ] ) ); + memset( surface->st[ surface->numSTArrays ], 0, surface->maxVertexes * sizeof( *surface->st[ 0 ] ) ); + surface->numSTArrays++; + } + } + + /* additional color arrays? */ + while( numColorArrays > surface->maxColorArrays ) /* fix */ + { + surface->maxColorArrays += PICO_GROW_ARRAYS; + if( !_pico_realloc( (void*) &surface->color, surface->numColorArrays * sizeof( *surface->color ), surface->maxColorArrays * sizeof( *surface->color ) ) ) + return 0; + while( surface->numColorArrays < numColorArrays ) + { + surface->color[ surface->numColorArrays ] = _pico_alloc( surface->maxVertexes * sizeof( *surface->color[ 0 ] ) ); + memset( surface->color[ surface->numColorArrays ], 0, surface->maxVertexes * sizeof( *surface->color[ 0 ] ) ); + surface->numColorArrays++; + } + } + + /* additional indexes? */ + while( numIndexes > surface->maxIndexes ) /* fix */ + { + surface->maxIndexes += PICO_GROW_INDEXES; + if( !_pico_realloc( (void*) &surface->index, surface->numIndexes * sizeof( *surface->index ), surface->maxIndexes * sizeof( *surface->index ) ) ) + return 0; + } + + /* set index count to higher */ + if( numIndexes > surface->numIndexes ) + surface->numIndexes = numIndexes; + + /* additional face normals? */ + while( numFaceNormals > surface->maxFaceNormals ) /* fix */ + { + surface->maxFaceNormals += PICO_GROW_FACES; + if( !_pico_realloc( (void *) &surface->faceNormal, surface->numFaceNormals * sizeof( *surface->faceNormal ), surface->maxFaceNormals * sizeof( *surface->faceNormal ) ) ) + return 0; + } + + /* set face normal count to higher */ + if( numFaceNormals > surface->numFaceNormals ) + surface->numFaceNormals = numFaceNormals; + + /* return ok */ + return 1; +} + + +/* PicoFindSurface: + * Finds first matching named surface in a model. + */ +picoSurface_t *PicoFindSurface( + picoModel_t *model, char *name, int caseSensitive ) +{ + int i; + + /* sanity check */ + if( model == NULL || name == NULL ) + return NULL; + + /* walk list */ + for( i = 0; i < model->numSurfaces; i++ ) + { + /* skip null surfaces or surfaces with null names */ + if( model->surface[ i ] == NULL || + model->surface[ i ]->name == NULL ) + continue; + + /* compare the surface name with name we're looking for */ + if (caseSensitive) { + if( !strcmp(name,model->surface[ i ]->name) ) + return model->surface[ i ]; + } else { + if( !_pico_stricmp(name,model->surface[ i ]->name) ) + return model->surface[ i ]; + } + } + /* named surface not found */ + return NULL; +} + + + +/*---------------------------------------------------------------------------- + PicoSet*() Setter Functions +----------------------------------------------------------------------------*/ + +void PicoSetModelName( picoModel_t *model, char *name ) +{ + if( model == NULL || name == NULL ) + return; + if( model->name != NULL ) + _pico_free( model->name ); + + model->name = _pico_clone_alloc( name,-1 ); +} + + + +void PicoSetModelFileName( picoModel_t *model, char *fileName ) +{ + if( model == NULL || fileName == NULL ) + return; + if( model->fileName != NULL ) + _pico_free( model->fileName ); + + model->fileName = _pico_clone_alloc( fileName,-1 ); +} + + + +void PicoSetModelFrameNum( picoModel_t *model, int frameNum ) +{ + if( model == NULL ) + return; + model->frameNum = frameNum; +} + + + +void PicoSetModelNumFrames( picoModel_t *model, int numFrames ) +{ + if( model == NULL ) + return; + model->numFrames = numFrames; +} + + + +void PicoSetModelData( picoModel_t *model, void *data ) +{ + if( model == NULL ) + return; + model->data = data; +} + + + +void PicoSetShaderName( picoShader_t *shader, char *name ) +{ + if( shader == NULL || name == NULL ) + return; + if( shader->name != NULL ) + _pico_free( shader->name ); + + shader->name = _pico_clone_alloc( name,-1 ); +} + + + +void PicoSetShaderMapName( picoShader_t *shader, char *mapName ) +{ + if( shader == NULL || mapName == NULL ) + return; + if( shader->mapName != NULL ) + _pico_free( shader->mapName ); + + shader->mapName = _pico_clone_alloc( mapName,-1 ); +} + + + +void PicoSetShaderAmbientColor( picoShader_t *shader, picoColor_t color ) +{ + if( shader == NULL || color == NULL ) + return; + shader->ambientColor[ 0 ] = color[ 0 ]; + shader->ambientColor[ 1 ] = color[ 1 ]; + shader->ambientColor[ 2 ] = color[ 2 ]; + shader->ambientColor[ 3 ] = color[ 3 ]; +} + + + +void PicoSetShaderDiffuseColor( picoShader_t *shader, picoColor_t color ) +{ + if( shader == NULL || color == NULL ) + return; + shader->diffuseColor[ 0 ] = color[ 0 ]; + shader->diffuseColor[ 1 ] = color[ 1 ]; + shader->diffuseColor[ 2 ] = color[ 2 ]; + shader->diffuseColor[ 3 ] = color[ 3 ]; +} + + + +void PicoSetShaderSpecularColor( picoShader_t *shader, picoColor_t color ) +{ + if( shader == NULL || color == NULL ) + return; + shader->specularColor[ 0 ] = color[ 0 ]; + shader->specularColor[ 1 ] = color[ 1 ]; + shader->specularColor[ 2 ] = color[ 2 ]; + shader->specularColor[ 3 ] = color[ 3 ]; +} + + + +void PicoSetShaderTransparency( picoShader_t *shader, float value ) +{ + if( shader == NULL ) + return; + shader->transparency = value; + + /* cap to 0..1 range */ + if (shader->transparency < 0.0) + shader->transparency = 0.0; + if (shader->transparency > 1.0) + shader->transparency = 1.0; +} + + + +void PicoSetShaderShininess( picoShader_t *shader, float value ) +{ + if( shader == NULL ) + return; + shader->shininess = value; + + /* cap to 0..127 range */ + if (shader->shininess < 0.0) + shader->shininess = 0.0; + if (shader->shininess > 127.0) + shader->shininess = 127.0; +} + + + +void PicoSetSurfaceData( picoSurface_t *surface, void *data ) +{ + if( surface == NULL ) + return; + surface->data = data; +} + + + +void PicoSetSurfaceType( picoSurface_t *surface, picoSurfaceType_t type ) +{ + if( surface == NULL ) + return; + surface->type = type; +} + + + +void PicoSetSurfaceName( picoSurface_t *surface, char *name ) +{ + if( surface == NULL || name == NULL ) + return; + if( surface->name != NULL ) + _pico_free( surface->name ); + + surface->name = _pico_clone_alloc( name,-1 ); +} + + + +void PicoSetSurfaceShader( picoSurface_t *surface, picoShader_t *shader ) +{ + if( surface == NULL ) + return; + surface->shader = shader; +} + + + +void PicoSetSurfaceXYZ( picoSurface_t *surface, int num, picoVec3_t xyz ) +{ + if( surface == NULL || num < 0 || xyz == NULL ) + return; + if( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) + return; + _pico_copy_vec( xyz, surface->xyz[ num ] ); + if( surface->model != NULL ) + _pico_expand_bounds( xyz, surface->model->mins, surface->model->maxs ); +} + + + +void PicoSetSurfaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ) +{ + if( surface == NULL || num < 0 || normal == NULL ) + return; + if( !PicoAdjustSurface( surface, num + 1, 0, 0, 0, 0 ) ) + return; + _pico_copy_vec( normal, surface->normal[ num ] ); +} + + + +void PicoSetSurfaceST( picoSurface_t *surface, int array, int num, picoVec2_t st ) +{ + if( surface == NULL || num < 0 || st == NULL ) + return; + if( !PicoAdjustSurface( surface, num + 1, array + 1, 0, 0, 0 ) ) + return; + surface->st[ array ][ num ][ 0 ] = st[ 0 ]; + surface->st[ array ][ num ][ 1 ] = st[ 1 ]; +} + + + +void PicoSetSurfaceColor( picoSurface_t *surface, int array, int num, picoColor_t color ) +{ + if( surface == NULL || num < 0 || color == NULL ) + return; + if( !PicoAdjustSurface( surface, num + 1, 0, array + 1, 0, 0 ) ) + return; + surface->color[ array ][ num ][ 0 ] = color[ 0 ]; + surface->color[ array ][ num ][ 1 ] = color[ 1 ]; + surface->color[ array ][ num ][ 2 ] = color[ 2 ]; + surface->color[ array ][ num ][ 3 ] = color[ 3 ]; +} + + + +void PicoSetSurfaceIndex( picoSurface_t *surface, int num, picoIndex_t index ) +{ + if( surface == NULL || num < 0 ) + return; + if( !PicoAdjustSurface( surface, 0, 0, 0, num + 1, 0 ) ) + return; + surface->index[ num ] = index; +} + + + +void PicoSetSurfaceIndexes( picoSurface_t *surface, int num, picoIndex_t *index, int count ) +{ + if( num < 0 || index == NULL || count < 1 ) + return; + if( !PicoAdjustSurface( surface, 0, 0, 0, num + count, 0 ) ) + return; + memcpy( &surface->index[ num ], index, count * sizeof( surface->index[ num ] ) ); +} + + + +void PicoSetFaceNormal( picoSurface_t *surface, int num, picoVec3_t normal ) +{ + if( surface == NULL || num < 0 || normal == NULL ) + return; + if( !PicoAdjustSurface( surface, 0, 0, 0, 0, num + 1 ) ) + return; + _pico_copy_vec( normal, surface->faceNormal[ num ] ); +} + + +void PicoSetSurfaceSpecial( picoSurface_t *surface, int num, int special ) +{ + if( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) + return; + surface->special[ num ] = special; +} + + + +/*---------------------------------------------------------------------------- + PicoGet*() Getter Functions +----------------------------------------------------------------------------*/ + +char *PicoGetModelName( picoModel_t *model ) +{ + if( model == NULL ) + return NULL; + if( model->name == NULL) + return (char*) ""; + return model->name; +} + + + +char *PicoGetModelFileName( picoModel_t *model ) +{ + if( model == NULL ) + return NULL; + if( model->fileName == NULL) + return (char*) ""; + return model->fileName; +} + + + +int PicoGetModelFrameNum( picoModel_t *model ) +{ + if( model == NULL ) + return 0; + return model->frameNum; +} + + + +int PicoGetModelNumFrames( picoModel_t *model ) +{ + if( model == NULL ) + return 0; + return model->numFrames; +} + + + +void *PicoGetModelData( picoModel_t *model ) +{ + if( model == NULL ) + return NULL; + return model->data; +} + + + +int PicoGetModelNumShaders( picoModel_t *model ) +{ + if( model == NULL ) + return 0; + return model->numShaders; +} + + + +picoShader_t *PicoGetModelShader( picoModel_t *model, int num ) +{ + /* a few sanity checks */ + if( model == NULL ) + return NULL; + if( model->shader == NULL) + return NULL; + if( num < 0 || num >= model->numShaders ) + return NULL; + + /* return the shader */ + return model->shader[ num ]; +} + + + +int PicoGetModelNumSurfaces( picoModel_t *model ) +{ + if( model == NULL ) + return 0; + return model->numSurfaces; +} + + + +picoSurface_t *PicoGetModelSurface( picoModel_t *model, int num ) +{ + /* a few sanity checks */ + if( model == NULL ) + return NULL; + if( model->surface == NULL) + return NULL; + if( num < 0 || num >= model->numSurfaces ) + return NULL; + + /* return the surface */ + return model->surface[ num ]; +} + + + +int PicoGetModelTotalVertexes( picoModel_t *model ) +{ + int i, count; + + + if( model == NULL ) + return 0; + if( model->surface == NULL ) + return 0; + + count = 0; + for( i = 0; i < model->numSurfaces; i++ ) + count += PicoGetSurfaceNumVertexes( model->surface[ i ] ); + + return count; +} + + + +int PicoGetModelTotalIndexes( picoModel_t *model ) +{ + int i, count; + + + if( model == NULL ) + return 0; + if( model->surface == NULL ) + return 0; + + count = 0; + for( i = 0; i < model->numSurfaces; i++ ) + count += PicoGetSurfaceNumIndexes( model->surface[ i ] ); + + return count; +} + + + +char *PicoGetShaderName( picoShader_t *shader ) +{ + if( shader == NULL ) + return NULL; + if( shader->name == NULL) + return (char*) ""; + return shader->name; +} + + + +char *PicoGetShaderMapName( picoShader_t *shader ) +{ + if( shader == NULL ) + return NULL; + if( shader->mapName == NULL) + return (char*) ""; + return shader->mapName; +} + + + +picoByte_t *PicoGetShaderAmbientColor( picoShader_t *shader ) +{ + if( shader == NULL ) + return NULL; + return shader->ambientColor; +} + + + +picoByte_t *PicoGetShaderDiffuseColor( picoShader_t *shader ) +{ + if( shader == NULL ) + return NULL; + return shader->diffuseColor; +} + + + +picoByte_t *PicoGetShaderSpecularColor( picoShader_t *shader ) +{ + if( shader == NULL ) + return NULL; + return shader->specularColor; +} + + + +float PicoGetShaderTransparency( picoShader_t *shader ) +{ + if( shader == NULL ) + return 0.0f; + return shader->transparency; +} + + + +float PicoGetShaderShininess( picoShader_t *shader ) +{ + if( shader == NULL ) + return 0.0f; + return shader->shininess; +} + + + +void *PicoGetSurfaceData( picoSurface_t *surface ) +{ + if( surface == NULL ) + return NULL; + return surface->data; +} + + + +picoSurfaceType_t PicoGetSurfaceType( picoSurface_t *surface ) +{ + if( surface == NULL ) + return PICO_BAD; + return surface->type; +} + + + +char *PicoGetSurfaceName( picoSurface_t *surface ) +{ + if( surface == NULL ) + return NULL; + if( surface->name == NULL ) + return (char*) ""; + return surface->name; +} + + + +picoShader_t *PicoGetSurfaceShader( picoSurface_t *surface ) +{ + if( surface == NULL ) + return NULL; + return surface->shader; +} + + + +int PicoGetSurfaceNumVertexes( picoSurface_t *surface ) +{ + if( surface == NULL ) + return 0; + return surface->numVertexes; +} + + + +picoVec_t *PicoGetSurfaceXYZ( picoSurface_t *surface, int num ) +{ + if( surface == NULL || num < 0 || num > surface->numVertexes ) + return NULL; + return surface->xyz[ num ]; +} + + + +picoVec_t *PicoGetSurfaceNormal( picoSurface_t *surface, int num ) +{ + if( surface == NULL || num < 0 || num > surface->numVertexes ) + return NULL; + return surface->normal[ num ]; +} + + + +picoVec_t *PicoGetSurfaceST( picoSurface_t *surface, int array, int num ) +{ + if( surface == NULL || array < 0 || array > surface->numSTArrays || num < 0 || num > surface->numVertexes ) + return NULL; + return surface->st[ array ][ num ]; +} + + + +picoByte_t *PicoGetSurfaceColor( picoSurface_t *surface, int array, int num ) +{ + if( surface == NULL || array < 0 || array > surface->numColorArrays || num < 0 || num > surface->numVertexes ) + return NULL; + return surface->color[ array ][ num ]; +} + + + +int PicoGetSurfaceNumIndexes( picoSurface_t *surface ) +{ + if( surface == NULL ) + return 0; + return surface->numIndexes; +} + + + +picoIndex_t PicoGetSurfaceIndex( picoSurface_t *surface, int num ) +{ + if( surface == NULL || num < 0 || num > surface->numIndexes ) + return 0; + return surface->index[ num ]; +} + + + +picoIndex_t *PicoGetSurfaceIndexes( picoSurface_t *surface, int num ) +{ + if( surface == NULL || num < 0 || num > surface->numIndexes ) + return NULL; + return &surface->index[ num ]; +} + + +picoVec_t *PicoGetFaceNormal( picoSurface_t *surface, int num ) +{ + if( surface == NULL || num < 0 || num > surface->numFaceNormals ) + return NULL; + return surface->faceNormal[ num ]; +} + + +int PicoGetSurfaceSpecial( picoSurface_t *surface, int num ) +{ + if( surface == NULL || num < 0 || num >= PICO_MAX_SPECIAL ) + return 0; + return surface->special[ num ]; +} + + + +/* ---------------------------------------------------------------------------- +hashtable related functions +---------------------------------------------------------------------------- */ + +/* hashtable code for faster vertex lookups */ +//#define HASHTABLE_SIZE 32768 // 2048 /* power of 2, use & */ +#define HASHTABLE_SIZE 7919 // 32749 // 2039 /* prime, use % */ + +int PicoGetHashTableSize( void ) +{ + return HASHTABLE_SIZE; +} + +#define HASH_USE_EPSILON + +#ifdef HASH_USE_EPSILON +#define HASH_XYZ_EPSILON 0.01f +#define HASH_XYZ_EPSILONSPACE_MULTIPLIER 1.f / HASH_XYZ_EPSILON +#define HASH_ST_EPSILON 0.0001f +#define HASH_NORMAL_EPSILON 0.02f +#endif + +unsigned int PicoVertexCoordGenerateHash( picoVec3_t xyz ) +{ + unsigned int hash = 0; + +#ifndef HASH_USE_EPSILON + hash += ~(*((unsigned int*) &xyz[ 0 ]) << 15); + hash ^= (*((unsigned int*) &xyz[ 0 ]) >> 10); + hash += (*((unsigned int*) &xyz[ 1 ]) << 3); + hash ^= (*((unsigned int*) &xyz[ 1 ]) >> 6); + hash += ~(*((unsigned int*) &xyz[ 2 ]) << 11); + hash ^= (*((unsigned int*) &xyz[ 2 ]) >> 16); +#else + picoVec3_t xyz_epsilonspace; + + _pico_scale_vec( xyz, HASH_XYZ_EPSILONSPACE_MULTIPLIER, xyz_epsilonspace ); + xyz_epsilonspace[ 0 ] = (float)floor(xyz_epsilonspace[ 0 ]); + xyz_epsilonspace[ 1 ] = (float)floor(xyz_epsilonspace[ 1 ]); + xyz_epsilonspace[ 2 ] = (float)floor(xyz_epsilonspace[ 2 ]); + + hash += ~(*((unsigned int*) &xyz_epsilonspace[ 0 ]) << 15); + hash ^= (*((unsigned int*) &xyz_epsilonspace[ 0 ]) >> 10); + hash += (*((unsigned int*) &xyz_epsilonspace[ 1 ]) << 3); + hash ^= (*((unsigned int*) &xyz_epsilonspace[ 1 ]) >> 6); + hash += ~(*((unsigned int*) &xyz_epsilonspace[ 2 ]) << 11); + hash ^= (*((unsigned int*) &xyz_epsilonspace[ 2 ]) >> 16); +#endif + + //hash = hash & (HASHTABLE_SIZE-1); + hash = hash % (HASHTABLE_SIZE); + return hash; +} + +picoVertexCombinationHash_t **PicoNewVertexCombinationHashTable( void ) +{ + picoVertexCombinationHash_t **hashTable = _pico_alloc( HASHTABLE_SIZE * sizeof(picoVertexCombinationHash_t*) ); + + memset( hashTable, 0, HASHTABLE_SIZE * sizeof(picoVertexCombinationHash_t*) ); + + return hashTable; +} + +void PicoFreeVertexCombinationHashTable( picoVertexCombinationHash_t **hashTable ) +{ + int i; + picoVertexCombinationHash_t *vertexCombinationHash; + picoVertexCombinationHash_t *nextVertexCombinationHash; + + /* dummy check */ + if (hashTable == NULL) + return; + + for( i = 0; i < HASHTABLE_SIZE; i++ ) + { + if (hashTable[ i ]) + { + nextVertexCombinationHash = NULL; + + for( vertexCombinationHash = hashTable[ i ]; vertexCombinationHash; vertexCombinationHash = nextVertexCombinationHash ) + { + nextVertexCombinationHash = vertexCombinationHash->next; + if (vertexCombinationHash->data != NULL) + { + _pico_free( vertexCombinationHash->data ); + } + _pico_free( vertexCombinationHash ); + } + } + } + + _pico_free( hashTable ); +} + +picoVertexCombinationHash_t *PicoFindVertexCombinationInHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color ) +{ + unsigned int hash; + picoVertexCombinationHash_t *vertexCombinationHash; + + /* dumy check */ + if (hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL ) + return NULL; + + hash = PicoVertexCoordGenerateHash( xyz ); + + for( vertexCombinationHash = hashTable[ hash ]; vertexCombinationHash; vertexCombinationHash = vertexCombinationHash->next ) + { +#ifndef HASH_USE_EPSILON + /* check xyz */ + if( (vertexCombinationHash->vcd.xyz[ 0 ] != xyz[ 0 ] || vertexCombinationHash->vcd.xyz[ 1 ] != xyz[ 1 ] || vertexCombinationHash->vcd.xyz[ 2 ] != xyz[ 2 ]) ) + continue; + + /* check normal */ + if( (vertexCombinationHash->vcd.normal[ 0 ] != normal[ 0 ] || vertexCombinationHash->vcd.normal[ 1 ] != normal[ 1 ] || vertexCombinationHash->vcd.normal[ 2 ] != normal[ 2 ]) ) + continue; + + /* check st */ + if( vertexCombinationHash->vcd.st[ 0 ] != st[ 0 ] || vertexCombinationHash->vcd.st[ 1 ] != st[ 1 ] ) + continue; +#else + /* check xyz */ + if( ( fabs(xyz[ 0 ] - vertexCombinationHash->vcd.xyz[ 0 ]) ) > HASH_XYZ_EPSILON || + ( fabs(xyz[ 1 ] - vertexCombinationHash->vcd.xyz[ 1 ]) ) > HASH_XYZ_EPSILON || + ( fabs(xyz[ 2 ] - vertexCombinationHash->vcd.xyz[ 2 ]) ) > HASH_XYZ_EPSILON ) + continue; + + /* check normal */ + if( ( fabs(normal[ 0 ] - vertexCombinationHash->vcd.normal[ 0 ]) ) > HASH_NORMAL_EPSILON || + ( fabs(normal[ 1 ] - vertexCombinationHash->vcd.normal[ 1 ]) ) > HASH_NORMAL_EPSILON || + ( fabs(normal[ 2 ] - vertexCombinationHash->vcd.normal[ 2 ]) ) > HASH_NORMAL_EPSILON ) + continue; + + /* check st */ + if( ( fabs(st[ 0 ] - vertexCombinationHash->vcd.st[ 0 ]) ) > HASH_ST_EPSILON || + ( fabs(st[ 1 ] - vertexCombinationHash->vcd.st[ 1 ]) ) > HASH_ST_EPSILON ) + continue; +#endif + + /* check color */ + if( *((int*) vertexCombinationHash->vcd.color) != *((int*) color) ) + continue; + + /* gotcha */ + return vertexCombinationHash; + } + + return NULL; +} + +picoVertexCombinationHash_t *PicoAddVertexCombinationToHashTable( picoVertexCombinationHash_t **hashTable, picoVec3_t xyz, picoVec3_t normal, picoVec3_t st, picoColor_t color, picoIndex_t index ) +{ + unsigned int hash; + picoVertexCombinationHash_t *vertexCombinationHash; + + /* dumy check */ + if (hashTable == NULL || xyz == NULL || normal == NULL || st == NULL || color == NULL ) + return NULL; + + vertexCombinationHash = _pico_alloc( sizeof(picoVertexCombinationHash_t) ); + + if (!vertexCombinationHash) + return NULL; + + hash = PicoVertexCoordGenerateHash( xyz ); + + _pico_copy_vec( xyz, vertexCombinationHash->vcd.xyz ); + _pico_copy_vec( normal, vertexCombinationHash->vcd.normal ); + _pico_copy_vec2( st, vertexCombinationHash->vcd.st ); + _pico_copy_color( color, vertexCombinationHash->vcd.color ); + vertexCombinationHash->index = index; + vertexCombinationHash->data = NULL; + vertexCombinationHash->next = hashTable[ hash ]; + hashTable[ hash ] = vertexCombinationHash; + + return vertexCombinationHash; +} + +/* ---------------------------------------------------------------------------- +specialized routines +---------------------------------------------------------------------------- */ + +/* +PicoFindSurfaceVertex() +finds a vertex matching the set parameters +fixme: needs non-naive algorithm +*/ + +int PicoFindSurfaceVertexNum( picoSurface_t *surface, picoVec3_t xyz, picoVec3_t normal, int numSTs, picoVec2_t *st, int numColors, picoColor_t *color ) +{ + int i, j; + + + /* dummy check */ + if( surface == NULL || surface->numVertexes <= 0 ) + return -1; + + /* walk vertex list */ + for( i = 0; i < surface->numVertexes; i++ ) + { + /* check xyz */ + if( xyz != NULL && (surface->xyz[ i ][ 0 ] != xyz[ 0 ] || surface->xyz[ i ][ 1 ] != xyz[ 1 ] || surface->xyz[ i ][ 2 ] != xyz[ 2 ]) ) + continue; + + /* check normal */ + if( normal != NULL && (surface->normal[ i ][ 0 ] != normal[ 0 ] || surface->normal[ i ][ 1 ] != normal[ 1 ] || surface->normal[ i ][ 2 ] != normal[ 2 ]) ) + continue; + + /* check st */ + if( numSTs > 0 && st != NULL ) + { + for( j = 0; j < numSTs; j++ ) + { + if( surface->st[ j ][ i ][ 0 ] != st[ j ][ 0 ] || surface->st[ j ][ i ][ 1 ] != st[ j ][ 1 ] ) + break; + } + if( j != numSTs ) + continue; + } + + /* check color */ + if( numColors > 0 && color != NULL ) + { + for( j = 0; j < numSTs; j++ ) + { + if( *((int*) surface->color[ j ]) != *((int*) color[ j ]) ) + break; + } + if( j != numColors ) + continue; + } + + /* vertex matches */ + return i; + } + + /* nada */ + return -1; +} + + + +/* +PicoFixSurfaceNormals() +fixes broken normals (certain formats bork normals) +*/ + +#define MAX_NORMAL_VOTES 128 +#define EQUAL_NORMAL_EPSILON 0.01 +#define BAD_NORMAL_EPSILON 0.5 + +void PicoFixSurfaceNormals( picoSurface_t *surface ) +{ + int i, j, k, a, b, c, numVotes, faceIndex; + picoVec3_t votes[ MAX_NORMAL_VOTES ]; + picoVec3_t *normals, diff; + picoVec4_t plane; + + + /* dummy check */ + if( surface == NULL || surface->numVertexes == 0 ) + return; + + /* fixme: handle other surface types */ + if( surface->type != PICO_TRIANGLES ) + return; + + /* allocate normal storage */ + normals = _pico_alloc( surface->numVertexes * sizeof( *normals ) ); + if( normals == NULL ) + { + _pico_printf( PICO_ERROR, "PicoFixSurfaceNormals: Unable to allocate memory for temporary normal storage" ); + return; + } + + /* zero it out */ + memset( normals, 0, surface->numVertexes * sizeof( *normals ) ); + + /* walk vertex list */ + for( i = 0; i < surface->numVertexes; i++ ) + { + /* zero out votes */ + numVotes = 0; + + /* find all the triangles that reference this vertex */ + for( j = 0, faceIndex = 0; j < surface->numIndexes; j += 3, faceIndex++ ) + { + /* get triangle */ + a = surface->index[ j ]; + b = surface->index[ j + 1 ]; + c = surface->index[ j + 2 ]; + + /* ignore degenerate triangles */ + if( a == b || b == c || c == a ) + continue; + + /* ignore indexes out of range */ + if( a < 0 || a >= surface->numVertexes || + b < 0 || b >= surface->numVertexes || + c < 0 || c >= surface->numVertexes ) + continue; + + /* test triangle */ + if( a == i || b == i || c == i ) + { + /* if this surface has face normals */ + if( surface->numFaceNormals && faceIndex < surface->numFaceNormals ) + { + _pico_copy_vec( surface->faceNormal[ faceIndex ], plane ); + if( plane[ 0 ] == 0.f && plane[ 1 ] == 0.f && plane[ 2 ] == 0.f ) + { + /* if null normal, make plane from the 3 points */ + if( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 ) + { + continue; + } + } + } + /* make a plane from the 3 points */ + else if( _pico_calc_plane( plane, surface->xyz[ a ], surface->xyz[ b ], surface->xyz[ c ] ) == 0 ) + { + continue; + } + + /* see if this normal has already been voted */ + for( k = 0; k < numVotes; k++ ) + { + _pico_subtract_vec( plane, votes[ k ], diff ); + if( fabs( diff[ 0 ] ) < EQUAL_NORMAL_EPSILON && + fabs( diff[ 1 ] ) < EQUAL_NORMAL_EPSILON && + fabs( diff[ 2 ] ) < EQUAL_NORMAL_EPSILON ) + break; + } + + /* add a new vote? */ + if( k == numVotes && numVotes < MAX_NORMAL_VOTES ) + { + _pico_copy_vec( plane, votes[ numVotes ] ); + numVotes++; + } + } + } + + /* tally votes */ + if( numVotes > 0 ) + { + /* create average normal */ + _pico_zero_vec( normals[ i ] ); + for( k = 0; k < numVotes; k++ ) + _pico_add_vec( normals[ i ], votes[ k ], normals[ i ] ); + + /* normalize it */ + if( _pico_normalize_vec( normals[ i ] ) ) + { + /* test against actual normal */ + if( fabs( _pico_dot_vec( normals[ i ], surface->normal[ i ] ) - 1 ) > BAD_NORMAL_EPSILON ) + { + //% printf( "Normal %8d: (%f %f %f) -> (%f %f %f)\n", i, + //% surface->normal[ i ][ 0 ], surface->normal[ i ][ 1 ], surface->normal[ i ][ 2 ], + //% normals[ i ][ 0 ], normals[ i ][ 1 ], normals[ i ][ 2 ] ); + _pico_copy_vec( normals[ i ], surface->normal[ i ] ); + } + } + } + } + + /* free normal storage */ + _pico_free( normals ); +} + + + + +/* +PicoRemapModel() - sea +remaps model material/etc. information using the remappings +contained in the given 'remapFile' (full path to the ascii file to open) +returns 1 on success or 0 on error +*/ + +#define _prm_error_return \ +{ \ + _pico_free_parser( p ); \ + _pico_free_file( remapBuffer ); \ + return 0; \ +} + +int PicoRemapModel( picoModel_t *model, char *remapFile ) +{ + picoParser_t *p; + picoByte_t *remapBuffer; + int remapBufSize; + + + /* sanity checks */ + if( model == NULL || remapFile == NULL ) + return 0; + + /* load remap file contents */ + _pico_load_file( remapFile,&remapBuffer,&remapBufSize ); + + /* check result */ + if( remapBufSize == 0 ) + return 1; /* file is empty: no error */ + if( remapBufSize < 0 ) + return 0; /* load failed: error */ + + /* create a new pico parser */ + p = _pico_new_parser( remapBuffer, remapBufSize ); + if (p == NULL) + { + /* ram is really cheap nowadays... */ + _prm_error_return; + } + + /* doo teh parse */ + while( 1 ) + { + /* get next token in remap file */ + if (!_pico_parse( p,1 )) + break; + + /* skip over c++ style comment lines */ + if (!_pico_stricmp(p->token,"//")) + { + _pico_parse_skip_rest( p ); + continue; + } + + /* block for quick material shader name remapping */ + /* materials { "m" (=>|->|=) "s" } */ + if( !_pico_stricmp(p->token, "materials" ) ) + { + int level = 1; + + /* check bracket */ + if (!_pico_parse_check( p,1,"{" )) + _prm_error_return; + + /* process assignments */ + while( 1 ) + { + picoShader_t *shader; + char *materialName; + + + /* get material name */ + if (_pico_parse( p,1 ) == NULL) break; + if (!strlen(p->token)) continue; + materialName = _pico_clone_alloc( p->token,-1 ); + if (materialName == NULL) + _prm_error_return; + + /* handle levels */ + if (p->token[0] == '{') level++; + if (p->token[0] == '}') level--; + if (!level) break; + + /* get next token (assignment token or shader name) */ + if (!_pico_parse( p,0 )) + { + _pico_free( materialName ); + _prm_error_return; + } + /* skip assignment token (if present) */ + if (!strcmp(p->token,"=>") || + !strcmp(p->token,"->") || + !strcmp(p->token,"=")) + { + /* simply grab the next token */ + if (!_pico_parse( p,0 )) + { + _pico_free( materialName ); + _prm_error_return; + } + } + /* try to find material by name */ + shader = PicoFindShader( model,materialName,0 ); + + /* we've found a material matching the name */ + if (shader != NULL) + { + PicoSetShaderName( shader,p->token ); + } + /* free memory used by material name */ + _pico_free( materialName ); + + /* skip rest */ + _pico_parse_skip_rest( p ); + } + } + /* block for detailed single material remappings */ + /* materials[ "m" ] { key data... } */ + else if (!_pico_stricmp(p->token,"materials[")) + { + picoShader_t *shader; + char *tempMaterialName; + int level = 1; + + /* get material name */ + if (!_pico_parse( p,0 )) + _prm_error_return; + + /* temporary copy of material name */ + tempMaterialName = _pico_clone_alloc( p->token,-1 ); + if (tempMaterialName == NULL) + _prm_error_return; + + /* check square closing bracket */ + if (!_pico_parse_check( p,0,"]" )) + _prm_error_return; + + /* try to find material by name */ + shader = PicoFindShader( model,tempMaterialName,0 ); + + /* free memory used by temporary material name */ + _pico_free( tempMaterialName ); + + /* we haven't found a material matching the name */ + /* so we simply skip the braced section now and */ + /* continue parsing with the next main token */ + if (shader == NULL) + { + _pico_parse_skip_braced( p ); + continue; + } + /* check opening bracket */ + if (!_pico_parse_check( p,1,"{" )) + _prm_error_return; + + /* process material info keys */ + while( 1 ) + { + /* get key name */ + if (_pico_parse( p,1 ) == NULL) break; + if (!strlen(p->token)) continue; + + /* handle levels */ + if (p->token[0] == '{') level++; + if (p->token[0] == '}') level--; + if (!level) break; + + /* remap shader name */ + if (!_pico_stricmp(p->token,"shader")) + { + if (!_pico_parse( p,0 )) _prm_error_return; + PicoSetShaderName( shader,p->token ); + } + /* remap shader map name */ + else if (!_pico_stricmp(p->token,"mapname")) + { + if (!_pico_parse( p,0 )) _prm_error_return; + PicoSetShaderMapName( shader,p->token ); + } + /* remap shader's ambient color */ + else if (!_pico_stricmp(p->token,"ambient")) + { + picoColor_t color; + picoVec3_t v; + + /* get vector from parser */ + if (!_pico_parse_vec( p,v )) _prm_error_return; + + /* store as color */ + color[ 0 ] = (picoByte_t)v[ 0 ]; + color[ 1 ] = (picoByte_t)v[ 1 ]; + color[ 2 ] = (picoByte_t)v[ 2 ]; + + /* set new ambient color */ + PicoSetShaderAmbientColor( shader,color ); + } + /* remap shader's diffuse color */ + else if (!_pico_stricmp(p->token,"diffuse")) + { + picoColor_t color; + picoVec3_t v; + + /* get vector from parser */ + if (!_pico_parse_vec( p,v )) _prm_error_return; + + /* store as color */ + color[ 0 ] = (picoByte_t)v[ 0 ]; + color[ 1 ] = (picoByte_t)v[ 1 ]; + color[ 2 ] = (picoByte_t)v[ 2 ]; + + /* set new ambient color */ + PicoSetShaderDiffuseColor( shader,color ); + } + /* remap shader's specular color */ + else if (!_pico_stricmp(p->token,"specular")) + { + picoColor_t color; + picoVec3_t v; + + /* get vector from parser */ + if (!_pico_parse_vec( p,v )) _prm_error_return; + + /* store as color */ + color[ 0 ] = (picoByte_t)v[ 0 ]; + color[ 1 ] = (picoByte_t)v[ 1 ]; + color[ 2 ] = (picoByte_t)v[ 2 ]; + + /* set new ambient color */ + PicoSetShaderSpecularColor( shader,color ); + } + /* skip rest */ + _pico_parse_skip_rest( p ); + } + } + /* end 'materials[' */ + } + + /* free both parser and file buffer */ + _pico_free_parser( p ); + _pico_free_file( remapBuffer ); + + /* return with success */ + return 1; +} + + +/* +PicoAddTriangleToModel() - jhefty +A nice way to add individual triangles to the model. +Chooses an appropriate surface based on the shader, or adds a new surface if necessary +*/ + +void PicoAddTriangleToModel( picoModel_t *model, picoVec3_t** xyz, picoVec3_t** normals, + int numSTs, picoVec2_t **st, int numColors, picoColor_t **colors, + picoShader_t* shader ) +{ + int i,j; + int vertDataIndex; + picoSurface_t* workSurface = NULL; + + /* see if a surface already has the shader */ + for ( i = 0 ; i < model->numSurfaces ; i++ ) + { + workSurface = model->surface[i]; + if ( workSurface->shader == shader ) + { + break; + } + } + + /* no surface uses this shader yet, so create a new surface */ + if ( !workSurface || i >=model->numSurfaces ) + { + /* create a new surface in the model for the unique shader */ + workSurface = PicoNewSurface(model); + if ( !workSurface ) + { + _pico_printf ( PICO_ERROR , "Could not allocate a new surface!\n" ); + return; + } + + /* do surface setup */ + PicoSetSurfaceType( workSurface, PICO_TRIANGLES ); + PicoSetSurfaceName( workSurface, shader->name ); + PicoSetSurfaceShader( workSurface, shader ); + } + + /* add the triangle data to the surface */ + for ( i = 0 ; i < 3 ; i++ ) + { + /* get the next free spot in the index array */ + int newVertIndex = PicoGetSurfaceNumIndexes ( workSurface ); + + /* get the index of the vertex that we're going to store at newVertIndex */ + vertDataIndex = PicoFindSurfaceVertexNum ( workSurface , *xyz[i] , *normals[i] , numSTs , st[i] , numColors , colors[i]); + + /* the vertex wasn't found, so create a new vertex in the pool from the data we have */ + if ( vertDataIndex == -1 ) + { + /* find the next spot for a new vertex */ + vertDataIndex = PicoGetSurfaceNumVertexes ( workSurface ); + + /* assign the data to it */ + PicoSetSurfaceXYZ ( workSurface ,vertDataIndex , *xyz[i] ); + PicoSetSurfaceNormal ( workSurface , vertDataIndex , *normals[i] ); + + /* make sure to copy over all available ST's and colors for the vertex */ + for ( j = 0 ; j < numColors ; j++ ) + { + PicoSetSurfaceColor( workSurface , j , vertDataIndex , colors[i][j] ); + } + for ( j = 0 ; j < numSTs ; j++ ) + { + PicoSetSurfaceST ( workSurface , j , vertDataIndex , st[i][j] ); + } + } + + /* add this vertex to the triangle */ + PicoSetSurfaceIndex ( workSurface , newVertIndex , vertDataIndex ); + } +} diff --git a/libs/picomodel/picomodel.vcproj b/libs/picomodel/picomodel.vcproj new file mode 100644 index 00000000..bd3edb07 --- /dev/null +++ b/libs/picomodel/picomodel.vcproj @@ -0,0 +1,107 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/libs/picomodel/picomodules.c b/libs/picomodel/picomodules.c new file mode 100644 index 00000000..060912f5 --- /dev/null +++ b/libs/picomodel/picomodules.c @@ -0,0 +1,92 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +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 names of the copyright holders 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. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PICOMODULES_C + + + +/* dependencies */ +#include "picointernal.h" + + + +/* external modules */ +extern const picoModule_t picoModuleMD3; +extern const picoModule_t picoModule3DS; +extern const picoModule_t picoModuleASE; +extern const picoModule_t picoModuleOBJ; +extern const picoModule_t picoModuleMS3D; +extern const picoModule_t picoModuleMDC; +extern const picoModule_t picoModuleMD2; +extern const picoModule_t picoModuleFM; +extern const picoModule_t picoModuleLWO; + + + +/* list of all supported file format modules */ +const picoModule_t *picoModules[] = +{ + &picoModuleMD3, /* quake3 arena md3 */ + &picoModule3DS, /* autodesk 3ds */ + &picoModuleASE, /* autodesk ase */ + &picoModuleMS3D, /* milkshape3d */ + &picoModuleMDC, /* return to castle wolfenstein mdc */ + &picoModuleMD2, /* quake2 md2 */ + &picoModuleFM, /* heretic2 fm */ + &picoModuleOBJ, /* wavefront object */ + &picoModuleLWO, /* lightwave object */ + NULL /* arnold */ +}; + + + +/* +PicoModuleList() +returns a pointer to the module list and optionally stores +the number of supported modules in 'numModules'. Note that +this param can be NULL when the count is not needed. +*/ + +const picoModule_t **PicoModuleList( int *numModules ) +{ + /* get module count */ + if( numModules != NULL ) + for( (*numModules) = 0; picoModules[ *numModules ] != NULL; (*numModules)++ ); + + /* return list of modules */ + return (const picoModule_t**) picoModules; +} diff --git a/libs/picomodel/pm_3ds.c b/libs/picomodel/pm_3ds.c new file mode 100644 index 00000000..1ad95b1c --- /dev/null +++ b/libs/picomodel/pm_3ds.c @@ -0,0 +1,771 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +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 names of the copyright holders 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. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PM_3DS_C + +/* dependencies */ +#include "picointernal.h" + +/* ydnar */ +static picoColor_t white = { 255,255,255,255 }; + +/* remarks: + * - 3ds file version is stored in pico special field 0 on load (ydnar: removed) + * todo: + * - sometimes there is one unnamed surface 0 having 0 verts as + * well as 0 faces. this error occurs since pm 0.6 (ydnar?) + */ +/* uncomment when debugging this module */ +/* #define DEBUG_PM_3DS +#define DEBUG_PM_3DS_EX */ + +/* structure holding persistent 3ds loader specific data used */ +/* to store formerly static vars to keep the module reentrant */ +/* safe. put everything that needs to be static in here. */ +typedef struct S3dsLoaderPers +{ + picoModel_t *model; /* ptr to output model */ + picoSurface_t *surface; /* ptr to current surface */ + picoShader_t *shader; /* ptr to current shader */ + picoByte_t *bufptr; /* ptr to raw data */ + char *basename; /* ptr to model base name (eg. jeep) */ + int cofs; + int maxofs; +} +T3dsLoaderPers; + +/* 3ds chunk types that we use */ +enum { + /* primary chunk */ + CHUNK_MAIN = 0x4D4D, + + /* main chunks */ + CHUNK_VERSION = 0x0002, + CHUNK_EDITOR_CONFIG = 0x3D3E, + CHUNK_EDITOR_DATA = 0x3D3D, + CHUNK_KEYFRAME_DATA = 0xB000, + + /* editor data sub chunks */ + CHUNK_MATERIAL = 0xAFFF, + CHUNK_OBJECT = 0x4000, + + /* material sub chunks */ + CHUNK_MATNAME = 0xA000, + CHUNK_MATDIFFUSE = 0xA020, + CHUNK_MATMAP = 0xA200, + CHUNK_MATMAPFILE = 0xA300, + + /* lets us know we're reading a new object */ + CHUNK_OBJECT_MESH = 0x4100, + + /* object mesh sub chunks */ + CHUNK_OBJECT_VERTICES = 0x4110, + CHUNK_OBJECT_FACES = 0x4120, + CHUNK_OBJECT_MATERIAL = 0x4130, + CHUNK_OBJECT_UV = 0x4140, +}; +#ifdef DEBUG_PM_3DS +static struct +{ + int id; + char *name; +} +debugChunkNames[] = +{ + { CHUNK_MAIN , "CHUNK_MAIN" }, + { CHUNK_VERSION , "CHUNK_VERSION" }, + { CHUNK_EDITOR_CONFIG , "CHUNK_EDITOR_CONFIG" }, + { CHUNK_EDITOR_DATA , "CHUNK_EDITOR_DATA" }, + { CHUNK_KEYFRAME_DATA , "CHUNK_KEYFRAME_DATA" }, + { CHUNK_MATERIAL , "CHUNK_MATERIAL" }, + { CHUNK_OBJECT , "CHUNK_OBJECT" }, + { CHUNK_MATNAME , "CHUNK_MATNAME" }, + { CHUNK_MATDIFFUSE , "CHUNK_MATDIFFUSE" }, + { CHUNK_MATMAP , "CHUNK_MATMAP" }, + { CHUNK_MATMAPFILE , "CHUNK_MATMAPFILE" }, + { CHUNK_OBJECT_MESH , "CHUNK_OBJECT_MESH" }, + { CHUNK_OBJECT_VERTICES , "CHUNK_OBJECT_VERTICES" }, + { CHUNK_OBJECT_FACES , "CHUNK_OBJECT_FACES" }, + { CHUNK_OBJECT_MATERIAL , "CHUNK_OBJECT_MATERIAL" }, + { CHUNK_OBJECT_UV , "CHUNK_OBJECT_UV" }, + { 0 , NULL } +}; +static char *DebugGetChunkName (int id) +{ + int i,max; /* imax? ;) */ + max = sizeof(debugChunkNames) / sizeof(debugChunkNames[0]); + + for (i=0; ilen)) + return PICO_PMV_ERROR_SIZE; + + /* check 3ds magic */ + if (_pico_little_short(chunk->id) != CHUNK_MAIN) + return PICO_PMV_ERROR_IDENT; + + /* file seems to be a valid 3ds */ + return PICO_PMV_OK; +} + +static T3dsChunk *GetChunk (T3dsLoaderPers *pers) +{ + T3dsChunk *chunk; + + /* sanity check */ + if (pers->cofs > pers->maxofs) return 0; + +#ifdef DEBUG_PM_3DS +/* printf("GetChunk: pers->cofs %x\n",pers->cofs); */ +#endif + /* fill in pointer to chunk */ + chunk = (T3dsChunk *)&pers->bufptr[ pers->cofs ]; + if (!chunk) return NULL; + + chunk->id = _pico_little_short(chunk->id ); + chunk->len = _pico_little_long (chunk->len); + + /* advance in buffer */ + pers->cofs += sizeof(T3dsChunk); + + /* this means yay */ + return chunk; +} + +static int GetASCIIZ (T3dsLoaderPers *pers, char *dest, int max) +{ + int pos = 0; + int ch; + + for (;;) + { + ch = pers->bufptr[ pers->cofs++ ]; + if (ch == '\0') break; + if (pers->cofs >= pers->maxofs) + { + dest[ pos ] = '\0'; + return 0; + } + dest[ pos++ ] = ch; + if (pos >= max) break; + } + dest[ pos ] = '\0'; + return 1; +} + +static picoByte_t GetByte (T3dsLoaderPers *pers) +{ + picoByte_t *value; + + /* sanity check */ + if (pers->cofs > pers->maxofs) return 0; + + /* get and return value */ + value = (picoByte_t *)(pers->bufptr + pers->cofs); + pers->cofs += 1; + return *value; +} + +static int GetWord (T3dsLoaderPers *pers) +{ + unsigned short *value; + + /* sanity check */ + if (pers->cofs > pers->maxofs) return 0; + + /* get and return value */ + value = (unsigned short *)(pers->bufptr + pers->cofs); + pers->cofs += 2; + return _pico_little_short(*value); +} + +static float GetFloat (T3dsLoaderPers *pers) +{ + float *value; + + /* sanity check */ + if (pers->cofs > pers->maxofs) return 0; + + /* get and return value */ + value = (float *)(pers->bufptr + pers->cofs); + pers->cofs += 4; + return _pico_little_float(*value); +} + +static int GetMeshVertices (T3dsLoaderPers *pers) +{ + int numVerts; + int i; + + /* get number of verts for this surface */ + numVerts = GetWord(pers); + +#ifdef DEBUG_PM_3DS + printf("GetMeshVertices: numverts %d\n",numVerts); +#endif + /* read in vertices for current surface */ + for (i=0; isurface,i,v ); + PicoSetSurfaceColor( pers->surface,0,i,white ); /* ydnar */ + +#ifdef DEBUG_PM_3DS_EX + printf("Vertex: x: %f y: %f z: %f\n",v[0],v[1],v[2]); +#endif + } + /* success (no errors occured) */ + return 1; +} + +static int GetMeshFaces (T3dsLoaderPers *pers) +{ + int numFaces; + int i; + + /* get number of faces for this surface */ + numFaces = GetWord(pers); + +#ifdef DEBUG_PM_3DS + printf("GetMeshFaces: numfaces %d\n",numFaces); +#endif + /* read in vertex indices for current surface */ + for (i=0; isurface, (i * 3 + 0), (picoIndex_t)face.a ); + PicoSetSurfaceIndex( pers->surface, (i * 3 + 1), (picoIndex_t)face.b ); + PicoSetSurfaceIndex( pers->surface, (i * 3 + 2), (picoIndex_t)face.c ); + +#ifdef DEBUG_PM_3DS_EX + printf("Face: a: %d b: %d c: %d (%d)\n",face.a,face.b,face.c,face.visible); +#endif + } + /* success (no errors occured) */ + return 1; +} + +static int GetMeshTexCoords (T3dsLoaderPers *pers) +{ + int numTexCoords; + int i; + + /* get number of uv coords for this surface */ + numTexCoords = GetWord(pers); + +#ifdef DEBUG_PM_3DS + printf("GetMeshTexCoords: numcoords %d\n",numTexCoords); +#endif + /* read in uv coords for current surface */ + for (i=0; isurface == NULL) + continue; + + /* add current uv */ + PicoSetSurfaceST( pers->surface,0,i,uv ); + +#ifdef DEBUG_PM_3DS_EX + printf("u: %f v: %f\n",uv[0],uv[1]); +#endif + } + /* success (no errors occured) */ + return 1; +} + +static int GetMeshShader (T3dsLoaderPers *pers) +{ + char shaderName[255] = { 0 }; + picoShader_t *shader; + int numSharedVerts; + int setShaderName = 0; + int i; + + /* the shader is either the color or the texture map of the */ + /* object. it can also hold other information like the brightness, */ + /* shine, etc. stuff we don't really care about. we just want the */ + /* color, or the texture map file name really */ + + /* get in the shader name */ + if (!GetASCIIZ(pers,shaderName,sizeof(shaderName))) + return 0; + + /* now that we have the shader name we need to go through all of */ + /* the shaders and check the name against each shader. when we */ + /* find a shader in our shader list that matches this name we */ + /* just read in, then we assign the shader's id of the object to */ + /* that shader */ + + /* get shader id for shader name */ + shader = PicoFindShader( pers->model, shaderName, 1 ); + + /* we've found a matching shader */ + if ((shader != NULL) && pers->surface) + { + char mapName[1024+1]; + char *mapNamePtr; + memset( mapName,0,sizeof(mapName) ); + + /* get ptr to shader's map name */ + mapNamePtr = PicoGetShaderMapName( shader ); + + /* we have a valid map name ptr */ + if (mapNamePtr != NULL) + { + char temp[128]; + char *name; + + /* copy map name to local buffer */ + strcpy( mapName,mapNamePtr ); + + /* extract file name */ + name = _pico_nopath( mapName ); + strncpy( temp, name, sizeof(temp) ); + + /* remove file extension */ + /* name = _pico_setfext( name,"" ); */ + + /* assign default name if no name available */ + if (strlen(temp) < 1) + strcpy(temp,pers->basename); + + /* build shader name */ + _pico_strlwr( temp ); /* gaynux update -sea */ + sprintf( mapName,"models/mapobjects/%s/%s",pers->basename,temp ); + + /* set shader name */ + /* PicoSetShaderName( shader,mapName ); */ /* ydnar: this will screw up the named shader */ + + /* set surface's shader index */ + PicoSetSurfaceShader( pers->surface, shader ); + + setShaderName = 1; + } + } + /* we didn't set a shader name; throw out warning */ + if (!setShaderName) + { + _pico_printf( PICO_WARNING,"3DS mesh is missing shader name"); + } + /* we don't process the list of shared vertices here; there is a */ + /* short int that gives the number of faces of the mesh concerned */ + /* by this shader, then there is the list itself of these faces. */ + /* 0000 means the first face of the (4120) face list */ + + /* get number of shared verts */ + numSharedVerts = GetWord(pers); + +#ifdef DEBUG_PM_3DS + printf("GetMeshShader: uses shader '%s' (nsv %d)\n",shaderName,numSharedVerts); +#endif + /* skip list of shared verts */ + for (i=0; ishader ) + { + PicoSetShaderDiffuseColor( pers->shader,color ); + } +#ifdef DEBUG_PM_3DS + printf("GetDiffuseColor: %d %d %d\n",color[0],color[1],color[2]); +#endif + /* success (no errors occured) */ + return 1; +} + +static int DoNextEditorDataChunk (T3dsLoaderPers *pers, long endofs) +{ + T3dsChunk *chunk; + +#ifdef DEBUG_PM_3DS_EX + printf("DoNextEditorDataChunk: endofs %d\n",endofs); +#endif + while (pers->cofs < endofs) + { + long nextofs = pers->cofs; + if ((chunk = GetChunk(pers)) == NULL) return 0; + if (!chunk->len) return 0; + nextofs += chunk->len; + +#ifdef DEBUG_PM_3DS_EX + printf("Chunk %04x (%s), len %d pers->cofs %x\n",chunk->id,DebugGetChunkName(chunk->id),chunk->len,pers->cofs); +#endif + /*** meshes ***/ + if (chunk->id == CHUNK_OBJECT) + { + picoSurface_t *surface; + char surfaceName[ 0xff ] = { 0 }; + + /* read in surface name */ + if( !GetASCIIZ(pers,surfaceName,sizeof(surfaceName)) ) + return 0; /* this is bad */ + +//PicoGetSurfaceName + /* ignore NULL name surfaces */ +// if( surfaceName + + /* allocate a pico surface */ + surface = PicoNewSurface( pers->model ); + if( surface == NULL ) + { + pers->surface = NULL; + return 0; /* this is bad too */ + } + /* assign ptr to current surface */ + pers->surface = surface; + + /* 3ds models surfaces are all triangle meshes */ + PicoSetSurfaceType( pers->surface,PICO_TRIANGLES ); + + /* set surface name */ + PicoSetSurfaceName( pers->surface,surfaceName ); + + /* continue mess with object's sub chunks */ + DoNextEditorDataChunk(pers,nextofs); + continue; + } + if (chunk->id == CHUNK_OBJECT_MESH) + { + /* continue mess with mesh's sub chunks */ + if (!DoNextEditorDataChunk(pers,nextofs)) return 0; + continue; + } + if (chunk->id == CHUNK_OBJECT_VERTICES) + { + if (!GetMeshVertices(pers)) return 0; + continue; + } + if (chunk->id == CHUNK_OBJECT_FACES) + { + if (!GetMeshFaces(pers)) return 0; + continue; + } + if (chunk->id == CHUNK_OBJECT_UV) + { + if (!GetMeshTexCoords(pers)) return 0; + continue; + } + if (chunk->id == CHUNK_OBJECT_MATERIAL) + { + if (!GetMeshShader(pers)) return 0; + continue; + } + /*** materials ***/ + if (chunk->id == CHUNK_MATERIAL) + { + /* new shader specific things should be */ + /* initialized right here */ + picoShader_t *shader; + + /* allocate a pico shader */ + shader = PicoNewShader( pers->model ); /* ydnar */ + if( shader == NULL ) + { + pers->shader = NULL; + return 0; /* this is bad too */ + } + + /* assign ptr to current shader */ + pers->shader = shader; + + /* continue and process the material's sub chunks */ + DoNextEditorDataChunk(pers,nextofs); + continue; + } + if (chunk->id == CHUNK_MATNAME) + { + /* new material's names should be stored here. note that */ + /* GetMeshMaterial returns the name of the material that */ + /* is used by the mesh. new material names are set HERE. */ + /* but for now we skip the new material's name ... */ + if (pers->shader) + { + char *name = (char *)(pers->bufptr + pers->cofs); + PicoSetShaderName( pers->shader,name ); +#ifdef DEBUG_PM_3DS + printf("NewShader: '%s'\n",name); +#endif + } + } + if (chunk->id == CHUNK_MATDIFFUSE) + { + /* todo: color for last inserted new material should be */ + /* stored somewhere by GetDiffuseColor */ + if (!GetDiffuseColor(pers)) return 0; + + /* rest of chunk is skipped here */ + } + if (chunk->id == CHUNK_MATMAP) + { + /* continue and process the material map sub chunks */ + DoNextEditorDataChunk(pers,nextofs); + continue; + } + if (chunk->id == CHUNK_MATMAPFILE) + { + /* map file name for last inserted new material should */ + /* be stored here. but for now we skip this too ... */ + if( pers->shader ) + { + char *name = (char *)(pers->bufptr + pers->cofs); + PicoSetShaderMapName( pers->shader,name ); +#ifdef DEBUG_PM_3DS + printf("NewShaderMapfile: '%s'\n",name); +#endif + } + } + /*** keyframes ***/ + if (chunk->id == CHUNK_KEYFRAME_DATA) + { + /* well umm, this is a bit too much since we don't really */ + /* need model animation sequences right now. we skip this */ +#ifdef DEBUG_PM_3DS + printf("KeyframeData: len %d\n",chunk->len); +#endif + } + /* skip unknown chunk */ + pers->cofs = nextofs; + if (pers->cofs >= pers->maxofs) break; + } + return 1; +} + +static int DoNextChunk (T3dsLoaderPers *pers, int endofs) +{ + T3dsChunk *chunk; + +#ifdef DEBUG_PM_3DS + printf("DoNextChunk: endofs %d\n",endofs); +#endif + while (pers->cofs < endofs) + { + long nextofs = pers->cofs; + if ((chunk = GetChunk(pers)) == NULL) return 0; + if (!chunk->len) return 0; + nextofs += chunk->len; + +#ifdef DEBUG_PM_3DS_EX + printf("Chunk %04x (%s), len %d pers->cofs %x\n",chunk->id,DebugGetChunkName(chunk->id),chunk->len,pers->cofs); +#endif + /*** version ***/ + if (chunk->id == CHUNK_VERSION) + { + /* at this point i get the 3ds file version. since there */ + /* might be new additions to the 3ds file format in 4.0 */ + /* it might be a good idea to store the version somewhere */ + /* for later handling or message displaying */ + + /* get the version */ + int version; + version = GetWord(pers); + GetWord(pers); +#ifdef DEBUG_PM_3DS + printf("FileVersion: %d\n",version); +#endif + + /* throw out a warning for version 4 models */ + if (version == 4) + { + _pico_printf( PICO_WARNING, + "3DS version is 4. Model might load incorrectly."); + } + /* store the 3ds file version in pico special field 0 */ + /* PicoSetSurfaceSpecial(pers->surface,0,version); */ /* ydnar: this was causing a crash accessing uninitialized surface */ + + /* rest of chunk is skipped here */ + } + /*** editor data ***/ + if (chunk->id == CHUNK_EDITOR_DATA) + { + if (!DoNextEditorDataChunk(pers,nextofs)) return 0; + continue; + } + /* skip unknown chunk */ + pers->cofs = nextofs; + if (pers->cofs >= pers->maxofs) break; + } + return 1; +} + +/* _3ds_load: + * loads an autodesk 3ds model file. +*/ +static picoModel_t *_3ds_load( PM_PARAMS_LOAD ) +{ + T3dsLoaderPers pers; + picoModel_t *model; + char basename[128]; + + /* create a new pico model */ + model = PicoNewModel(); + if (model == NULL) + { + /* user must have some serious ram problems ;) */ + return NULL; + } + /* get model's base name (eg. jeep from c:\models\jeep.3ds) */ + memset( basename,0,sizeof(basename) ); + strncpy( basename,_pico_nopath(fileName),sizeof(basename) ); + _pico_setfext( basename,"" ); + + /* initialize persistant vars (formerly static) */ + pers.model = model; + pers.bufptr = (picoByte_t *)buffer; + pers.basename = (char *)basename; + pers.maxofs = bufSize; + pers.cofs = 0L; + + /* do model setup */ + PicoSetModelFrameNum( model,frameNum ); + PicoSetModelName( model,fileName ); + PicoSetModelFileName( model,fileName ); + + /* skip first chunk in file (magic) */ + GetChunk(&pers); + + /* process chunks */ + if (!DoNextChunk(&pers,pers.maxofs)) + { + /* well, bleh i guess */ + PicoFreeModel(model); + return NULL; + } + /* return allocated pico model */ + return model; +} + +/* pico file format module definition */ +const picoModule_t picoModule3DS = +{ + "0.86-b", /* module version string */ + "Autodesk 3Dstudio", /* module display name */ + "seaw0lf", /* author's name */ + "2002 seaw0lf", /* module copyright */ + { + "3ds",NULL,NULL,NULL /* default extensions to use */ + }, + _3ds_canload, /* validation routine */ + _3ds_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_ase.c b/libs/picomodel/pm_ase.c new file mode 100644 index 00000000..e8c5751d --- /dev/null +++ b/libs/picomodel/pm_ase.c @@ -0,0 +1,1001 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +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 aseMaterialList provided with the distribution. + +Neither the names of the copyright holders 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. + +----------------------------------------------------------------------------- */ + + +/* marker */ +#define PM_ASE_C + +/* uncomment when debugging this module */ +//#define DEBUG_PM_ASE +//#define DEBUG_PM_ASE_EX + + +/* dependencies */ +#include "picointernal.h" + +#ifdef DEBUG_PM_ASE +#include "time.h" +#endif + +/* plain white */ +static picoColor_t white = { 255, 255, 255, 255 }; + +/* jhefty - multi-subobject material support */ + +/* Material/SubMaterial management */ +/* A material should have 1..n submaterials assigned to it */ + +typedef struct aseSubMaterial_s +{ + struct aseSubMaterial_s* next; + int subMtlId; + picoShader_t* shader; + +} aseSubMaterial_t; + +typedef struct aseMaterial_s +{ + struct aseMaterial_s* next; + struct aseSubMaterial_s* subMtls; + int mtlId; +} aseMaterial_t; + +/* Material/SubMaterial management functions */ +static aseMaterial_t* _ase_get_material ( aseMaterial_t* list , int mtlIdParent ) +{ + aseMaterial_t* mtl = list; + + while ( mtl ) + { + if ( mtlIdParent == mtl->mtlId ) + { + break; + } + mtl = mtl->next; + } + return mtl; +} + +static aseSubMaterial_t* _ase_get_submaterial ( aseMaterial_t* list, int mtlIdParent , int subMtlId ) +{ + aseMaterial_t* parent = _ase_get_material ( list , mtlIdParent ); + aseSubMaterial_t* subMtl = NULL; + + if ( !parent ) + { + _pico_printf ( PICO_ERROR , "No ASE material exists with id %i\n" , mtlIdParent ); + return NULL; + } + + subMtl = parent->subMtls; + while ( subMtl ) + { + if ( subMtlId == subMtl->subMtlId ) + { + break; + } + subMtl = subMtl->next; + } + return subMtl; +} + +static aseMaterial_t* _ase_add_material( aseMaterial_t **list, int mtlIdParent ) +{ + aseMaterial_t *mtl = _pico_calloc( 1, sizeof( aseMaterial_t ) ); + mtl->mtlId = mtlIdParent; + mtl->subMtls = NULL; + mtl->next = *list; + *list = mtl; + + return mtl; +} + +static aseSubMaterial_t* _ase_add_submaterial( aseMaterial_t **list, int mtlIdParent, int subMtlId, picoShader_t* shader ) +{ + aseMaterial_t *parent = _ase_get_material( *list, mtlIdParent ); + aseSubMaterial_t *subMtl = _pico_calloc( 1, sizeof ( aseSubMaterial_t ) ); + + if ( !parent ) + { + parent = _ase_add_material ( list , mtlIdParent ); + } + + subMtl->shader = shader; + subMtl->subMtlId = subMtlId; + subMtl->next = parent->subMtls; + parent->subMtls = subMtl; + + return subMtl; +} + +static void _ase_free_materials( aseMaterial_t **list ) +{ + aseMaterial_t* mtl = *list; + aseSubMaterial_t* subMtl = NULL; + + aseMaterial_t* mtlTemp = NULL; + aseSubMaterial_t* subMtlTemp = NULL; + + while ( mtl ) + { + subMtl = mtl->subMtls; + while ( subMtl ) + { + subMtlTemp = subMtl->next; + _pico_free ( subMtl ); + subMtl = subMtlTemp; + } + mtlTemp = mtl->next; + _pico_free ( mtl ); + mtl = mtlTemp; + } + (*list) = NULL; +} + +#ifdef DEBUG_PM_ASE +static void _ase_print_materials( aseMaterial_t *list ) +{ + aseMaterial_t* mtl = list; + aseSubMaterial_t* subMtl = NULL; + + while ( mtl ) + { + _pico_printf ( PICO_NORMAL , "ASE Material %i" , mtl->mtlId ); + subMtl = mtl->subMtls; + while ( subMtl ) + { + _pico_printf ( PICO_NORMAL , " -- ASE SubMaterial %i - %s\n" , subMtl->subMtlId , subMtl->shader->name ); + subMtl = subMtl->next; + } + mtl = mtl->next; + } +} +#endif //DEBUG_PM_ASE + +/* ASE Face management */ +/* These are used to keep an association between a submaterial and a face definition */ +/* They are kept in parallel with the current picoSurface, */ +/* and are used by _ase_submit_triangles to lookup the proper material/submaterial IDs */ +typedef struct aseFace_s +{ + struct aseFace_s* next; + int mtlId; + int subMtlId; + int index[9]; +} aseFace_t; + +/* ASE Face management functions */ +void _ase_add_face( aseFace_t **list, aseFace_t **tail, aseFace_t *newFace ) +{ + aseFace_t* face = *list; + aseFace_t* tempFace = NULL; + + /* insert as head of list */ + if ( !(*list) ) + { + *list = newFace; + } + else + { + (*tail)->next = newFace; + } + + *tail = newFace; + newFace->next = NULL; + + //tag the color indices so we can detect them and apply the default color to them + newFace->index[6] = -1; + newFace->index[7] = -1; + newFace->index[8] = -1; +} + +aseFace_t* _ase_get_face_for_index( aseFace_t *list, int index ) +{ + int counter = 0; + aseFace_t* face = list; + + while ( counter < index ) + { + face = face->next; + counter++; + } + return face; +} +static void _ase_free_faces (aseFace_t** list, aseFace_t** tail ) +{ + aseFace_t* face = *list; + aseFace_t* tempFace = NULL; + + while ( face ) + { + tempFace = face->next; + _pico_free ( face ); + face = tempFace; + } + + (*list) = NULL; + (*tail) = NULL; +} + +/* todo: + * - apply material specific uv offsets to uv coordinates + */ + +/* _ase_canload: + * validates a 3dsmax ase model file. + */ +static int _ase_canload( PM_PARAMS_CANLOAD ) +{ + picoParser_t *p; + + + /* quick data length validation */ + if( bufSize < 80 ) + return PICO_PMV_ERROR_SIZE; + + /* keep the friggin compiler happy */ + *fileName = *fileName; + + /* create pico parser */ + p = _pico_new_parser( (picoByte_t*) buffer, bufSize ); + if( p == NULL ) + return PICO_PMV_ERROR_MEMORY; + + /* get first token */ + if( _pico_parse_first( p ) == NULL) + { + return PICO_PMV_ERROR_IDENT; + } + + /* check first token */ + if( _pico_stricmp( p->token, "*3dsmax_asciiexport" ) ) + { + _pico_free_parser( p ); + return PICO_PMV_ERROR_IDENT; + } + + /* free the pico parser object */ + _pico_free_parser( p ); + + /* file seems to be a valid ase file */ + return PICO_PMV_OK; +} + + + +/* _ase_submit_triangles - jhefty + use the surface and the current face list to look up material/submaterial IDs + and submit them to the model for proper processing + +The following still holds from ydnar's _ase_make_surface: + indexes 0 1 2 = vert indexes + indexes 3 4 5 = st indexes + indexes 6 7 8 = color indexes (new) +*/ + +static void _ase_submit_triangles ( picoSurface_t* surface , picoModel_t* model , aseMaterial_t* materials , aseFace_t* faces ) +{ + aseFace_t* face; + aseSubMaterial_t* subMtl; + picoVec3_t* xyz[3]; + picoVec3_t* normal[3]; + picoVec2_t* st[3]; + picoColor_t* color[3]; + int i; + + face = faces; + while ( face != NULL ) + { + /* look up the shader for the material/submaterial pair */ + subMtl = _ase_get_submaterial( materials, face->mtlId, face->subMtlId ); + if( subMtl == NULL ) + { + /* ydnar: trying default submaterial */ + subMtl = _ase_get_submaterial( materials, face->mtlId, 0 ); + if( subMtl == NULL ) + { + _pico_printf( PICO_ERROR, "Could not find material/submaterial for id %d/%d\n", face->mtlId, face->subMtlId ); + return; + } + } + + /* we pull the data from the surface using the facelist data */ + for ( i = 0 ; i < 3 ; i ++ ) + { + xyz[i] = (picoVec3_t*) PicoGetSurfaceXYZ ( surface, face->index[ i ] ); + normal[i] = (picoVec3_t*) PicoGetSurfaceNormal( surface, face->index[ i ] ); + st[i] = (picoVec2_t*) PicoGetSurfaceST ( surface, 0, face->index[ i + 3 ] ); + + if ( face->index [ i + 6] >= 0 ) + { + color[i] = (picoColor_t*)PicoGetSurfaceColor ( surface, 0, face->index[ i + 6 ] ); + } + else + { + color[i] = &white; + } + + } + + /* submit the triangle to the model */ + PicoAddTriangleToModel ( model , xyz , normal , 1 , st , 1 , color , subMtl->shader ); + + /* advance to the next face */ + face = face->next; + } +} + +/* _ase_load: + * loads a 3dsmax ase model file. +*/ +static picoModel_t *_ase_load( PM_PARAMS_LOAD ) +{ + picoModel_t *model; + picoSurface_t *surface = NULL; + picoParser_t *p; + char lastNodeName[ 1024 ]; + + aseFace_t* faces = NULL; + aseFace_t* facesTail = NULL; + aseMaterial_t* materials = NULL; + +#ifdef DEBUG_PM_ASE + clock_t start, finish; + double elapsed; + start = clock(); +#endif + + /* helper */ + #define _ase_error_return(m) \ + { \ + _pico_printf( PICO_ERROR,"%s in ASE, line %d.",m,p->curLine); \ + _pico_free_parser( p ); \ + PicoFreeModel( model ); \ + return NULL; \ + } + /* create a new pico parser */ + p = _pico_new_parser( (picoByte_t *)buffer,bufSize ); + if (p == NULL) return NULL; + + /* create a new pico model */ + model = PicoNewModel(); + if (model == NULL) + { + _pico_free_parser( p ); + return NULL; + } + /* do model setup */ + PicoSetModelFrameNum( model, frameNum ); + PicoSetModelName( model, fileName ); + PicoSetModelFileName( model, fileName ); + + /* initialize some stuff */ + memset( lastNodeName,0,sizeof(lastNodeName) ); + + /* parse ase model file */ + while( 1 ) + { + /* get first token on line */ + if (_pico_parse_first( p ) == NULL) + break; + + /* we just skip empty lines */ + if (p->token == NULL || !strlen( p->token )) + continue; + + /* we skip invalid ase statements */ + if (p->token[0] != '*' && p->token[0] != '{' && p->token[0] != '}') + { + _pico_parse_skip_rest( p ); + continue; + } + /* remember node name */ + if (!_pico_stricmp(p->token,"*node_name")) + { + /* read node name */ + char *ptr = _pico_parse( p,0 ); + if (ptr == NULL) + _ase_error_return("Node name parse error"); + + /* remember node name */ + strncpy( lastNodeName,ptr,sizeof(lastNodeName) ); + } + /* model mesh (originally contained within geomobject) */ + else if (!_pico_stricmp(p->token,"*mesh")) + { + /* finish existing surface */ + //_ase_make_surface( model, &surface ); + _ase_submit_triangles (surface, model ,materials,faces); + _ase_free_faces (&faces,&facesTail); + + /* allocate new pico surface */ + surface = PicoNewSurface( NULL ); + if (surface == NULL) + { + PicoFreeModel( model ); + return NULL; + } + } + /* mesh material reference. this usually comes at the end of */ + /* geomobjects after the mesh blocks. we must assume that the */ + /* new mesh was already created so all we can do here is assign */ + /* the material reference id (shader index) now. */ + else if (!_pico_stricmp(p->token,"*material_ref")) + { + int mtlId; + aseFace_t* face; + + /* we must have a valid surface */ + if( surface == NULL ) + _ase_error_return("Missing mesh for material reference"); + + /* get the material ref (0..n) */ + if (!_pico_parse_int( p,&mtlId) ) + _ase_error_return("Missing material reference ID"); + + /* fix up all of the aseFaceList in the surface to point to the parent material */ + /* we've already saved off their subMtl */ + face = faces; + while ( face != NULL ) + { + face->mtlId = mtlId; + face = face->next; + } + } + /* model mesh vertex */ + else if (!_pico_stricmp(p->token,"*mesh_vertex")) + { + picoVec3_t v; + int index; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get vertex data (orig: index +y -x +z) */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("Vertex parse error"); + if (!_pico_parse_vec( p,v )) + _ase_error_return("Vertex parse error"); + + /* set vertex */ + PicoSetSurfaceXYZ( surface,index,v ); + } + /* model mesh vertex normal */ + else if (!_pico_stricmp(p->token,"*mesh_vertexnormal")) + { + picoVec3_t v; + int index; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get vertex data (orig: index +y -x +z) */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("Vertex parse error"); + if (!_pico_parse_vec( p,v )) + _ase_error_return("Vertex parse error"); + + /* set vertex */ + PicoSetSurfaceNormal( surface,index,v ); + } + /* model mesh face */ + else if (!_pico_stricmp(p->token,"*mesh_face")) + { + picoIndex_t indexes[3]; + int index; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get face index */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("Face parse error"); + + /* get 1st vertex index */ + _pico_parse( p,0 ); + if (!_pico_parse_int( p,&indexes[0] )) + _ase_error_return("Face parse error"); + + /* get 2nd vertex index */ + _pico_parse( p,0 ); + if (!_pico_parse_int( p,&indexes[1] )) + _ase_error_return("Face parse error"); + + /* get 3rd vertex index */ + _pico_parse( p,0 ); + if (!_pico_parse_int( p,&indexes[2] )) + _ase_error_return("Face parse error"); + + /* set face indexes (note interleaved offset!) */ + PicoSetSurfaceIndex( surface, (index * 9 + 0), indexes[2] ); + PicoSetSurfaceIndex( surface, (index * 9 + 1), indexes[1] ); + PicoSetSurfaceIndex( surface, (index * 9 + 2), indexes[0] ); + + /* parse to the subMaterial ID */ + while ( 1 ) + { + _pico_parse (p,0); + if (!_pico_stricmp (p->token,"*MESH_MTLID" )) + { + aseFace_t* newFace; + int subMtlId; + + _pico_parse_int ( p , &subMtlId ); + newFace = _pico_calloc ( 1 , sizeof ( aseFace_t )); + + /* we fix up the mtlId later when we parse the material_ref */ + newFace->mtlId = 0; + newFace->subMtlId = subMtlId; + newFace->index[0] = indexes[2]; + newFace->index[1] = indexes[1]; + newFace->index[2] = indexes[0]; + + _ase_add_face ( &faces,&facesTail,newFace ); + break; + } + } + + } + /* model texture vertex */ + else if (!_pico_stricmp(p->token,"*mesh_tvert")) + { + picoVec2_t uv; + int index; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get uv vertex index */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("UV vertex parse error"); + + /* get uv vertex s */ + if (!_pico_parse_float( p,&uv[0] )) + _ase_error_return("UV vertex parse error"); + + /* get uv vertex t */ + if (!_pico_parse_float( p,&uv[1] )) + _ase_error_return("UV vertex parse error"); + + /* ydnar: invert t */ + uv[ 1 ] = 1.0f - uv[ 1 ]; + + /* set texture vertex */ + PicoSetSurfaceST( surface,0,index,uv ); + } + /* ydnar: model mesh texture face */ + else if( !_pico_stricmp( p->token, "*mesh_tface" ) ) + { + picoIndex_t indexes[3]; + int index; + aseFace_t* face; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get face index */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("Texture face parse error"); + + /* get 1st vertex index */ + if (!_pico_parse_int( p,&indexes[0] )) + _ase_error_return("Texture face parse error"); + + /* get 2nd vertex index */ + if (!_pico_parse_int( p,&indexes[1] )) + _ase_error_return("Texture face parse error"); + + /* get 3rd vertex index */ + if (!_pico_parse_int( p,&indexes[2] )) + _ase_error_return("Texture face parse error"); + + /* set face indexes (note interleaved offset!) */ + PicoSetSurfaceIndex( surface, (index * 9 + 3), indexes[2] ); + PicoSetSurfaceIndex( surface, (index * 9 + 4), indexes[1] ); + PicoSetSurfaceIndex( surface, (index * 9 + 5), indexes[0] ); + + face = _ase_get_face_for_index(faces,index); + face->index[3] = indexes[2]; + face->index[4] = indexes[1]; + face->index[5] = indexes[0]; + } + /* model color vertex */ + else if (!_pico_stricmp(p->token,"*mesh_vertcol")) + { + picoColor_t color; + int index; + float colorInput; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get color vertex index */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("UV vertex parse error"); + + /* get R component */ + if (!_pico_parse_float( p,&colorInput )) + _ase_error_return("color vertex parse error"); + color[0] = (picoByte_t)(colorInput * 255); + + /* get G component */ + if (!_pico_parse_float( p,&colorInput )) + _ase_error_return("color vertex parse error"); + color[1] = (picoByte_t)(colorInput * 255); + + /* get B component */ + if (!_pico_parse_float( p,&colorInput )) + _ase_error_return("color vertex parse error"); + color[2] = (picoByte_t)(colorInput * 255); + + /* leave alpha alone since we don't get any data from the ASE format */ + color[3] = 255; + + /* set texture vertex */ + PicoSetSurfaceColor( surface,0,index,color ); + } + /* model color face */ + else if (!_pico_stricmp(p->token,"*mesh_cface")) + { + picoIndex_t indexes[3]; + int index; + aseFace_t* face; + + /* we must have a valid surface */ + if( surface == NULL ) + continue; + + /* get face index */ + if (!_pico_parse_int( p,&index )) + _ase_error_return("Face parse error"); + + /* get 1st cvertex index */ + // _pico_parse( p,0 ); + if (!_pico_parse_int( p,&indexes[0] )) + _ase_error_return("Face parse error"); + + /* get 2nd cvertex index */ + // _pico_parse( p,0 ); + if (!_pico_parse_int( p,&indexes[1] )) + _ase_error_return("Face parse error"); + + /* get 3rd cvertex index */ + // _pico_parse( p,0 ); + if (!_pico_parse_int( p,&indexes[2] )) + _ase_error_return("Face parse error"); + + /* set face indexes (note interleaved offset!) */ + PicoSetSurfaceIndex( surface, (index * 9 + 6), indexes[2] ); + PicoSetSurfaceIndex( surface, (index * 9 + 7), indexes[1] ); + PicoSetSurfaceIndex( surface, (index * 9 + 8), indexes[0] ); + + face = _ase_get_face_for_index(faces,index); + face->index[6] = indexes[2]; + face->index[7] = indexes[1]; + face->index[8] = indexes[0]; + } + /* model material */ + else if( !_pico_stricmp( p->token, "*material" ) ) + { + aseSubMaterial_t* subMaterial = NULL; + picoShader_t *shader; + int level = 1, index; + char materialName[ 1024 ]; + float transValue = 0.0f, shineValue = 1.0f; + picoColor_t ambientColor, diffuseColor, specularColor; + char *mapname = NULL; + int subMtlId, subMaterialLevel = -1; + + + /* get material index */ + _pico_parse_int( p,&index ); + + /* check brace */ + if (!_pico_parse_check(p,1,"{")) + _ase_error_return("Material missing opening brace"); + + /* parse material block */ + while( 1 ) + { + /* get next token */ + if (_pico_parse(p,1) == NULL) break; + if (!strlen(p->token)) continue; + + /* handle levels */ + if (p->token[0] == '{') level++; + if (p->token[0] == '}') level--; + if (!level) break; + + if( level == subMaterialLevel ) + { + /* set material name */ + PicoSetShaderName( shader, materialName); + + /* set shader's transparency */ + PicoSetShaderTransparency( shader,transValue ); + + /* set shader's ambient color */ + PicoSetShaderAmbientColor( shader,ambientColor ); + + /* set diffuse alpha to transparency */ + diffuseColor[3] = (picoByte_t)( transValue * 255.0 ); + + /* set shader's diffuse color */ + PicoSetShaderDiffuseColor( shader,diffuseColor ); + + /* set shader's specular color */ + PicoSetShaderSpecularColor( shader,specularColor ); + + /* set shader's shininess */ + PicoSetShaderShininess( shader,shineValue ); + + /* set material map name */ + PicoSetShaderMapName( shader, mapname ); + + subMaterial = _ase_add_submaterial( &materials, index, subMtlId, shader ); + subMaterialLevel = -1; + } + + /* parse submaterial index */ + if (!_pico_stricmp(p->token,"*submaterial")) + { + /* allocate new pico shader */ + _pico_parse_int( p , &subMtlId ); + + shader = PicoNewShader( model ); + if (shader == NULL) + { + PicoFreeModel( model ); + return NULL; + } + subMaterialLevel = level; + } + /* parse material name */ + else if (!_pico_stricmp(p->token,"*material_name")) + { + char* name = _pico_parse(p,0); + if ( name == NULL) + _ase_error_return("Missing material name"); + + strcpy ( materialName , name ); + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + /* parse material transparency */ + else if (!_pico_stricmp(p->token,"*material_transparency")) + { + /* get transparency value from ase */ + if (!_pico_parse_float( p,&transValue )) + _ase_error_return("Material transparency parse error"); + + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + /* parse material shininess */ + else if (!_pico_stricmp(p->token,"*material_shine")) + { + /* remark: + * - not sure but instead of '*material_shine' i might + * need to use '*material_shinestrength' */ + + /* get shine value from ase */ + if (!_pico_parse_float( p,&shineValue )) + _ase_error_return("Material shine parse error"); + + /* scale ase shine range 0..1 to pico range 0..127 */ + shineValue *= 128.0; + + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + /* parse ambient material color */ + else if (!_pico_stricmp(p->token,"*material_ambient")) + { + picoVec3_t vec; + /* get r,g,b float values from ase */ + if (!_pico_parse_vec( p,vec )) + _ase_error_return("Material color parse error"); + + /* setup 0..255 range color values */ + ambientColor[ 0 ] = (int)( vec[ 0 ] * 255.0 ); + ambientColor[ 1 ] = (int)( vec[ 1 ] * 255.0 ); + ambientColor[ 2 ] = (int)( vec[ 2 ] * 255.0 ); + ambientColor[ 3 ] = (int)( 255 ); + + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + /* parse diffuse material color */ + else if (!_pico_stricmp(p->token,"*material_diffuse")) + { + picoVec3_t vec; + + /* get r,g,b float values from ase */ + if (!_pico_parse_vec( p,vec )) + _ase_error_return("Material color parse error"); + + /* setup 0..255 range color */ + diffuseColor[ 0 ] = (int)( vec[ 0 ] * 255.0 ); + diffuseColor[ 1 ] = (int)( vec[ 1 ] * 255.0 ); + diffuseColor[ 2 ] = (int)( vec[ 2 ] * 255.0 ); + diffuseColor[ 3 ] = (int)( 255 ); + + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + /* parse specular material color */ + else if (!_pico_stricmp(p->token,"*material_specular")) + { + picoVec3_t vec; + + /* get r,g,b float values from ase */ + if (!_pico_parse_vec( p,vec )) + _ase_error_return("Material color parse error"); + + /* setup 0..255 range color */ + specularColor[ 0 ] = (int)( vec[ 0 ] * 255 ); + specularColor[ 1 ] = (int)( vec[ 1 ] * 255 ); + specularColor[ 2 ] = (int)( vec[ 2 ] * 255 ); + specularColor[ 3 ] = (int)( 255 ); + + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + /* material diffuse map */ + else if (!_pico_stricmp(p->token,"*map_diffuse") ) + { + int sublevel = 0; + + /* parse material block */ + while( 1 ) + { + /* get next token */ + if (_pico_parse(p,1) == NULL) break; + if (!strlen(p->token)) continue; + + /* handle levels */ + if (p->token[0] == '{') sublevel++; + if (p->token[0] == '}') sublevel--; + if (!sublevel) break; + + /* parse diffuse map bitmap */ + if (!_pico_stricmp(p->token,"*bitmap")) + { + char* name = _pico_parse(p,0); + if (name == NULL) + _ase_error_return("Missing material map bitmap name"); + mapname = _pico_alloc ( strlen ( name ) + 1 ); + strcpy ( mapname, name ); + /* skip rest and continue with next token */ + _pico_parse_skip_rest( p ); + continue; + } + } + } + /* end map_diffuse block */ + } + /* end material block */ + + if( subMaterial == NULL ) + { + /* allocate new pico shader */ + shader = PicoNewShader( model ); + if (shader == NULL) + { + PicoFreeModel( model ); + return NULL; + } + + /* set material name */ + PicoSetShaderName( shader,materialName ); + + /* set shader's transparency */ + PicoSetShaderTransparency( shader,transValue ); + + /* set shader's ambient color */ + PicoSetShaderAmbientColor( shader,ambientColor ); + + /* set diffuse alpha to transparency */ + diffuseColor[3] = (picoByte_t)( transValue * 255.0 ); + + /* set shader's diffuse color */ + PicoSetShaderDiffuseColor( shader,diffuseColor ); + + /* set shader's specular color */ + PicoSetShaderSpecularColor( shader,specularColor ); + + /* set shader's shininess */ + PicoSetShaderShininess( shader,shineValue ); + + /* set material map name */ + PicoSetShaderMapName( shader, mapname ); + + /* this is just a material with 1 submaterial */ + subMaterial = _ase_add_submaterial( &materials, index, 0, shader ); + } + + /* ydnar: free mapname */ + if( mapname != NULL ) + _pico_free( mapname ); + } // !_pico_stricmp ( "*material" ) + + /* skip unparsed rest of line and continue */ + _pico_parse_skip_rest( p ); + } + + /* ydnar: finish existing surface */ +// _ase_make_surface( model, &surface ); + _ase_submit_triangles (surface, model ,materials,faces); + _ase_free_faces (&faces,&facesTail); + +#ifdef DEBUG_PM_ASE + _ase_print_materials(materials); + finish = clock(); + elapsed = (double)(finish - start) / CLOCKS_PER_SEC; + _pico_printf( PICO_NORMAL, "Loaded model in in %-.2f second(s)\n", elapsed ); +#endif //DEBUG_PM_ASE + + _ase_free_materials(&materials); + + /* return allocated pico model */ + return model; +} + +/* pico file format module definition */ +const picoModule_t picoModuleASE = +{ + "1.0", /* module version string */ + "Autodesk 3DSMAX ASCII", /* module display name */ + "Jared Hefty, seaw0lf", /* author's name */ + "2003 Jared Hefty, 2002 seaw0lf", /* module copyright */ + { + "ase",NULL,NULL,NULL /* default extensions to use */ + }, + _ase_canload, /* validation routine */ + _ase_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_fm.c b/libs/picomodel/pm_fm.c new file mode 100644 index 00000000..c6f8e538 --- /dev/null +++ b/libs/picomodel/pm_fm.c @@ -0,0 +1,670 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +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 names of the copyright holders 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. + +----------------------------------------------------------------------------- */ + +/* +Nurail: Used pm_md3.c (Randy Reddig) as a template. +*/ + +/* marker */ +#define PM_FM_C + +/* dependencies */ +#include "pm_fm.h" + +//#define FM_VERBOSE_DBG 0 +#undef FM_VERBOSE_DBG +#undef FM_DBG + +typedef struct index_LUT_s +{ + short Vert; + short ST; + struct index_LUT_s *next; + +} index_LUT_t; + +typedef struct index_DUP_LUT_s +{ + short ST; + short OldVert; + +} index_DUP_LUT_t; + + +// _fm_canload() +static int _fm_canload( PM_PARAMS_CANLOAD ) +{ + fm_t fm; + unsigned char *bb; + int fm_file_pos; + + bb = (unsigned char *) buffer; + + // Header + fm.fm_header_hdr = (fm_chunk_header_t *) bb; + fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size; +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_VERBOSE, "IDENT: %s\n", (unsigned char *) fm.fm_header_hdr->ident ); +#endif + if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME)) ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n"); +#endif + return PICO_PMV_ERROR_IDENT; + } + + // check fm + if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Header Version incorrect\n"); +#endif + return PICO_PMV_ERROR_VERSION; + } + + // Skin + fm.fm_skin_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_skin_hdr->size; +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_VERBOSE, "SKIN: %s\n", (unsigned char *) fm.fm_skin_hdr->ident ); +#endif + if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n"); +#endif + return PICO_PMV_ERROR_IDENT; + } + + // check fm + if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n"); +#endif + return PICO_PMV_ERROR_VERSION; + } + + // st + fm.fm_st_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_st_hdr->size; +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_VERBOSE, "ST: %s\n", (unsigned char *) fm.fm_st_hdr->ident ); +#endif + if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n"); +#endif + return PICO_PMV_ERROR_IDENT; + } + + // check fm + if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM ST Version incorrect\n"); +#endif + return PICO_PMV_ERROR_VERSION; + } + + // tri + fm.fm_tri_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_tri_hdr->size; +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_VERBOSE, "TRI: %s\n", (unsigned char *) fm.fm_tri_hdr->ident ); +#endif + if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n"); +#endif + return PICO_PMV_ERROR_IDENT; + } + + // check fm + if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n"); +#endif + return PICO_PMV_ERROR_VERSION; + } + + // frame + fm.fm_frame_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t); +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_VERBOSE, "FRAME: %s\n", (unsigned char *) fm.fm_frame_hdr->ident ); +#endif + if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n"); +#endif + return PICO_PMV_ERROR_IDENT; + } + + // check fm + if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER ) + { +#ifdef FM_DBG + _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n"); +#endif + return PICO_PMV_ERROR_VERSION; + } + + // file seems to be a valid fm + return PICO_PMV_OK; +} + + + +// _fm_load() loads a Heretic 2 model file. +static picoModel_t *_fm_load( PM_PARAMS_LOAD ) +{ + int i, j, dups, dup_index; + int fm_file_pos; + short tot_numVerts; + index_LUT_t *p_index_LUT, *p_index_LUT2, *p_index_LUT3; + index_DUP_LUT_t *p_index_LUT_DUPS; + + fm_vert_normal_t *vert; + + char skinname[FM_SKINPATHSIZE]; + fm_t fm; + fm_header_t *fm_head; + fm_st_t *texCoord; + fm_xyz_st_t *tri_verts; + fm_xyz_st_t *triangle; + fm_frame_t *frame; + + picoByte_t *bb; + picoModel_t *picoModel; + picoSurface_t *picoSurface; + picoShader_t *picoShader; + picoVec3_t xyz, normal; + picoVec2_t st; + picoColor_t color; + + + // fm loading + _pico_printf( PICO_NORMAL, "Loading \"%s\"", fileName ); + + bb = (picoByte_t*) buffer; + + // Header Header + fm.fm_header_hdr = (fm_chunk_header_t *) bb; + fm_file_pos = sizeof(fm_chunk_header_t) + fm.fm_header_hdr->size; + if( (strcmp(fm.fm_header_hdr->ident, FM_HEADERCHUNKNAME)) ) + { + _pico_printf( PICO_WARNING, "FM Header Ident incorrect\n"); + return NULL; + } + + if( _pico_little_long( fm.fm_header_hdr->version ) != FM_HEADERCHUNKVER ) + { + _pico_printf( PICO_WARNING, "FM Header Version incorrect\n"); + return NULL; + } + + // Skin Header + fm.fm_skin_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_skin_hdr->size; + if( (strcmp(fm.fm_skin_hdr->ident, FM_SKINCHUNKNAME)) ) + { + _pico_printf( PICO_WARNING, "FM Skin Ident incorrect\n"); + return NULL; + } + + if( _pico_little_long( fm.fm_skin_hdr->version ) != FM_SKINCHUNKVER ) + { + _pico_printf( PICO_WARNING, "FM Skin Version incorrect\n"); + return NULL; + } + + // ST Header + fm.fm_st_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_st_hdr->size; + if( (strcmp(fm.fm_st_hdr->ident, FM_STCOORDCHUNKNAME)) ) + { + _pico_printf( PICO_WARNING, "FM ST Ident incorrect\n"); + return NULL; + } + + if( _pico_little_long( fm.fm_st_hdr->version ) != FM_STCOORDCHUNKVER ) + { + _pico_printf( PICO_WARNING, "FM ST Version incorrect\n"); + return NULL; + } + + // Tris Header + fm.fm_tri_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t) + fm.fm_tri_hdr->size; + if( (strcmp(fm.fm_tri_hdr->ident, FM_TRISCHUNKNAME)) ) + { + _pico_printf( PICO_WARNING, "FM Tri Ident incorrect\n"); + return NULL; + } + + if( _pico_little_long( fm.fm_tri_hdr->version ) != FM_TRISCHUNKVER ) + { + _pico_printf( PICO_WARNING, "FM Tri Version incorrect\n"); + return NULL; + } + + // Frame Header + fm.fm_frame_hdr = (fm_chunk_header_t *) (bb + fm_file_pos); + fm_file_pos += sizeof(fm_chunk_header_t); + if( (strcmp(fm.fm_frame_hdr->ident, FM_FRAMESCHUNKNAME)) ) + { + _pico_printf( PICO_WARNING, "FM Frame Ident incorrect\n"); + return NULL; + } + + if( _pico_little_long( fm.fm_frame_hdr->version ) != FM_FRAMESCHUNKVER ) + { + _pico_printf( PICO_WARNING, "FM Frame Version incorrect\n"); + return NULL; + } + + // Header + fm_file_pos = sizeof(fm_chunk_header_t); + fm_head = fm.fm_header = (fm_header_t *) (bb + fm_file_pos); + fm_file_pos += fm.fm_header_hdr->size; + + // Skin + fm_file_pos += sizeof(fm_chunk_header_t); + fm.fm_skin = (fm_skinpath_t *) (bb + fm_file_pos); + fm_file_pos += fm.fm_skin_hdr->size; + + // ST + fm_file_pos += sizeof(fm_chunk_header_t); + texCoord = fm.fm_st = (fm_st_t *) (bb + fm_file_pos); + fm_file_pos += fm.fm_st_hdr->size; + + // Tri + fm_file_pos += sizeof(fm_chunk_header_t); + tri_verts = fm.fm_tri = (fm_xyz_st_t *) (bb + fm_file_pos); + fm_file_pos += fm.fm_tri_hdr->size; + + // Frame + fm_file_pos += sizeof(fm_chunk_header_t); + frame = fm.fm_frame = (fm_frame_t *) (bb + fm_file_pos); + + // do frame check + if( fm_head->numFrames < 1 ) + { + _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName ); + return NULL; + } + + if( frameNum < 0 || frameNum >= fm_head->numFrames ) + { + _pico_printf( PICO_ERROR, "Invalid or out-of-range FM frame specified" ); + return NULL; + } + + // swap fm + fm_head->skinWidth = _pico_little_long( fm_head->skinWidth ); + fm_head->skinHeight = _pico_little_long( fm_head->skinHeight ); + fm_head->frameSize = _pico_little_long( fm_head->frameSize ); + + fm_head->numSkins = _pico_little_long( fm_head->numSkins ); + fm_head->numXYZ = _pico_little_long( fm_head->numXYZ ); + fm_head->numST = _pico_little_long( fm_head->numST ); + fm_head->numTris = _pico_little_long( fm_head->numTris ); + fm_head->numGLCmds = _pico_little_long( fm_head->numGLCmds ); + fm_head->numFrames = _pico_little_long( fm_head->numFrames ); + + // swap frame scale and translation + for( i = 0; i < 3; i++ ) + { + frame->header.scale[ i ] = _pico_little_float( frame->header.scale[ i ] ); + frame->header.translate[ i ] = _pico_little_float( frame->header.translate[ i ] ); + } + + // swap triangles + triangle = tri_verts; + for( i = 0; i < fm_head->numTris; i++, triangle++ ) + { + for( j = 0; j < 3; j++ ) + { + triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] ); + triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] ); + } + } + + // swap st coords + for( i = 0; i < fm_head->numST; i++ ) + { + texCoord->s = _pico_little_short( texCoord[i].s ); + texCoord->t = _pico_little_short( texCoord[i].t ); + } + // set Skin Name + strncpy(skinname, (unsigned char *) fm.fm_skin, FM_SKINPATHSIZE ); + +#ifdef FM_VERBOSE_DBG + // Print out md2 values + _pico_printf(PICO_VERBOSE,"numSkins->%d numXYZ->%d numST->%d numTris->%d numFrames->%d\nSkin Name \"%s\"\n", fm_head->numSkins, fm_head->numXYZ, fm_head->numST, fm_head->numTris, fm_head->numFrames, &skinname ); +#endif + + // detox Skin name + _pico_setfext( skinname, "" ); + _pico_unixify( skinname ); + + /* create new pico model */ + picoModel = PicoNewModel(); + if( picoModel == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); + return NULL; + } + + /* do model setup */ + PicoSetModelFrameNum( picoModel, frameNum ); + PicoSetModelNumFrames( picoModel, fm_head->numFrames ); /* sea */ + PicoSetModelName( picoModel, fileName ); + PicoSetModelFileName( picoModel, fileName ); + + // allocate new pico surface + picoSurface = PicoNewSurface( picoModel ); + if( picoSurface == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); + PicoFreeModel( picoModel ); + return NULL; + } + + + PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); + PicoSetSurfaceName( picoSurface, frame->header.name ); + picoShader = PicoNewShader( picoModel ); + if( picoShader == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); + PicoFreeModel( picoModel ); + return NULL; + } + + PicoSetShaderName( picoShader, skinname ); + + // associate current surface with newly created shader + PicoSetSurfaceShader( picoSurface, picoShader ); + + // Init LUT for Verts + p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * fm_head->numXYZ); + for(i=0; inumXYZ; i++) + { + p_index_LUT[i].Vert = -1; + p_index_LUT[i].ST = -1; + p_index_LUT[i].next = NULL; + } + + // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert. + tot_numVerts = fm_head->numXYZ; + dups = 0; + triangle = tri_verts; + + for(i=0; inumTris; i++) + { + for(j=0; j<3; j++) + { + if (p_index_LUT[triangle->index_xyz[j]].ST == -1) // No Main Entry + p_index_LUT[triangle->index_xyz[j]].ST = triangle->index_st[j]; + + else if (triangle->index_st[j] == p_index_LUT[triangle->index_xyz[j]].ST ) // Equal to Main Entry + { +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, "-> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); +#endif + continue; + } + else if ( (p_index_LUT[triangle->index_xyz[j]].next == NULL) ) // Not equal to Main entry, and no LL entry + { // Add first entry of LL from Main + p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); + if (p_index_LUT2 == NULL) + _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n"); + p_index_LUT[triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2; + p_index_LUT2->Vert = dups; + p_index_LUT2->ST = triangle->index_st[j]; + p_index_LUT2->next = NULL; +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, " ADDING first LL XYZ:%d DUP:%d ST:%d\n", triangle->index_xyz[j], dups, triangle->index_st[j]); +#endif + triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk + dups++; + } + else // Try to find in LL from Main Entry + { + p_index_LUT3 = p_index_LUT2 = p_index_LUT[triangle->index_xyz[j]].next; + while ( (p_index_LUT2 != NULL) && (triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL + { + p_index_LUT3 = p_index_LUT2; + p_index_LUT2 = p_index_LUT2->next; + } + p_index_LUT2 = p_index_LUT3; + + if ( triangle->index_st[j] == p_index_LUT2->ST ) // Found it + { + triangle->index_xyz[j] = p_index_LUT2->Vert + fm_head->numXYZ; // Make change in Tri hunk +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, "--> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); +#endif + continue; + } + + if ( p_index_LUT2->next == NULL) // Didn't find it. Add entry to LL. + { + // Add the Entry + p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); + if (p_index_LUT3 == NULL) + _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n"); + p_index_LUT2->next = (index_LUT_t *)p_index_LUT3; + p_index_LUT3->Vert = dups; + p_index_LUT3->ST = triangle->index_st[j]; + p_index_LUT3->next = NULL; +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, " ADDING additional LL XYZ:%d DUP:%d NewXYZ:%d ST:%d\n", triangle->index_xyz[j], dups, dups + (fm_head->numXYZ), triangle->index_st[j]); +#endif + triangle->index_xyz[j] = dups + fm_head->numXYZ; // Make change in Tri hunk + dups++; + } + } +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, "---> Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); +#endif + } + triangle++; + } + + // malloc and build array for Dup STs + p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups); + if (p_index_LUT_DUPS == NULL) + _pico_printf( PICO_NORMAL, " Couldn't allocate memory!\n"); + + dup_index = 0; + for(i=0; inumXYZ; i++) + { + p_index_LUT2 = p_index_LUT[i].next; + while (p_index_LUT2 != NULL) + { + p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i; + p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST; + dup_index++; + p_index_LUT2 = p_index_LUT2->next; + } + } +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, " Dups = %d\n", dups); + _pico_printf( PICO_NORMAL, " Dup Index = %d\n", dup_index); +#endif + for(i=0; inumXYZ; i++) + { +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, "Vert: %4d\t%4d",i, p_index_LUT[i].ST); +#endif + if (p_index_LUT[i].next != NULL) + { + + p_index_LUT2 = p_index_LUT[i].next; + do { +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, " %4d %4d", p_index_LUT2->Vert, p_index_LUT2->ST); +#endif + p_index_LUT2 = p_index_LUT2->next; + } while ( p_index_LUT2 != NULL); + + } +#ifdef FM_VERBOSE_DBG + _pico_printf( PICO_NORMAL, "\n"); +#endif + } + + +#ifdef FM_VERBOSE_DBG + for(i=0; inumTris; i++) + { + for(j=0; j<3; j++) + _pico_printf( PICO_NORMAL, "Tri #%d, Vert %d:\t XYZ:%d ST:%d\n", i, j, triangle->index_xyz[j], triangle->index_st[j]); + _pico_printf( PICO_NORMAL, "\n"); + triangle++; + } +#endif + // Build Picomodel + triangle = tri_verts; + for( j = 0; j < fm_head->numTris; j++, triangle++ ) + { + PicoSetSurfaceIndex( picoSurface, j*3 , triangle->index_xyz[0] ); + PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] ); + PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] ); + } + + vert = (fm_vert_normal_t*) ((picoByte_t*) (frame->verts) ); + for(i=0; i< fm_head->numXYZ; i++, vert++) + { + /* set vertex origin */ + xyz[ 0 ] = vert->v[0] * frame->header.scale[0] + frame->header.translate[0]; + xyz[ 1 ] = vert->v[1] * frame->header.scale[1] + frame->header.translate[1]; + xyz[ 2 ] = vert->v[2] * frame->header.scale[2] + frame->header.translate[2]; + PicoSetSurfaceXYZ( picoSurface, i , xyz ); + + /* set normal */ + normal[ 0 ] = fm_normals[vert->lightnormalindex][0]; + normal[ 1 ] = fm_normals[vert->lightnormalindex][1]; + normal[ 2 ] = fm_normals[vert->lightnormalindex][2]; + PicoSetSurfaceNormal( picoSurface, i , normal ); + + /* set st coords */ + st[ 0 ] = ((texCoord[p_index_LUT[i].ST].s) / ((float)fm_head->skinWidth)); + st[ 1 ] = (texCoord[p_index_LUT[i].ST].t / ((float)fm_head->skinHeight)); + PicoSetSurfaceST( picoSurface, 0, i , st ); + } + + if (dups) + { + for(i=0; iverts[j].v[0] * frame->header.scale[0] + frame->header.translate[0]; + xyz[ 1 ] = frame->verts[j].v[1] * frame->header.scale[1] + frame->header.translate[1]; + xyz[ 2 ] = frame->verts[j].v[2] * frame->header.scale[2] + frame->header.translate[2]; + PicoSetSurfaceXYZ( picoSurface, i + fm_head->numXYZ , xyz ); + + /* set normal */ + normal[ 0 ] = fm_normals[frame->verts[j].lightnormalindex][0]; + normal[ 1 ] = fm_normals[frame->verts[j].lightnormalindex][1]; + normal[ 2 ] = fm_normals[frame->verts[j].lightnormalindex][2]; + PicoSetSurfaceNormal( picoSurface, i + fm_head->numXYZ , normal ); + + /* set st coords */ + st[ 0 ] = ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)fm_head->skinWidth)); + st[ 1 ] = (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)fm_head->skinHeight)); + PicoSetSurfaceST( picoSurface, 0, i + fm_head->numXYZ , st ); + } + } + + /* set color */ + PicoSetSurfaceColor( picoSurface, 0, 0, color ); + + // Free up malloc'ed LL entries + for(i=0; inumXYZ; i++) + { + if(p_index_LUT[i].next != NULL) + { + p_index_LUT2 = p_index_LUT[i].next; + do { + p_index_LUT3 = p_index_LUT2->next; + _pico_free(p_index_LUT2); + p_index_LUT2 = p_index_LUT3; + dups--; + } while (p_index_LUT2 != NULL); + } + } + + if (dups) + _pico_printf(PICO_WARNING, " Not all LL mallocs freed\n"); + + // Free malloc'ed LUTs + _pico_free(p_index_LUT); + _pico_free(p_index_LUT_DUPS); + + /* return the new pico model */ + return picoModel; + +} + + + +/* pico file format module definition */ +const picoModule_t picoModuleFM = +{ + "0.85", /* module version string */ + "Heretic 2 FM", /* module display name */ + "Nurail", /* author's name */ + "2003 Nurail", /* module copyright */ + { + "fm", NULL, NULL, NULL /* default extensions to use */ + }, + _fm_canload, /* validation routine */ + _fm_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_fm.h b/libs/picomodel/pm_fm.h new file mode 100644 index 00000000..ce43d334 --- /dev/null +++ b/libs/picomodel/pm_fm.h @@ -0,0 +1,367 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +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 names of the copyright holders 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. + +----------------------------------------------------------------------------- */ + +// This header file is based from the following: + +/* + FlexModel.H - Header file for FlexModel file structure + + By Chris Burke + serotonin@earthlink.net +*/ + +#ifndef __PM_FM_H__ +#define __PM_FM_H__ + +#include "picointernal.h" + + +// +// Absolute limits (from QData / QMView source) +// +#define MAX_FM_TRIANGLES 2048 +#define MAX_FM_VERTS 2048 +#define MAX_FM_FRAMES 2048 +#define MAX_FM_SKINS 64 +#define MAX_FM_SKINNAME 64 +#define MAX_FM_MESH_NODES 16 + +#define DTRIVERTX_V0 0 +#define DTRIVERTX_V1 1 +#define DTRIVERTX_V2 2 +#define DTRIVERTX_LNI 3 +#define DTRIVERTX_SIZE 4 + +#define SKINPAGE_WIDTH 640 +#define SKINPAGE_HEIGHT 480 + +#define ENCODED_WIDTH_X 92 +#define ENCODED_WIDTH_Y 475 +#define ENCODED_HEIGHT_X 128 +#define ENCODED_HEIGHT_Y 475 + +#define SCALE_ADJUST_FACTOR 0.96 + +#define INFO_HEIGHT 5 +#define INFO_Y (SKINPAGE_HEIGHT-INFO_HEIGHT) + +#ifndef byte + #define byte unsigned char +#endif + + +// +// Generic header on every chunk +// +#define FM_MAXCHUNKIDENT 32L +typedef struct +{ + char ident[FM_MAXCHUNKIDENT]; + unsigned int version; + unsigned int size; +} fm_chunk_header_t; + +// +// The format of the "header" chunk +// +#define FM_HEADERCHUNKNAME "header" +#define FM_HEADERCHUNKVER 2 +#define FM_HEADERCHUNKSIZE 40 +typedef struct +{ + int skinWidth; // in pixels + int skinHeight; // in pixels + int frameSize; // size of each frame (in bytes) + int numSkins; // number of skins + int numXYZ; // number of unique vertices in 3D space + int numST; // number of unique vertices in texture space + int numTris; // number of unique triangles + int numGLCmds; // # 32-bit elements in strip/fan command list + int numFrames; // number of animation frames + int numMeshNodes; // number of mesh nodes +} fm_header_t; + +// +// The format of an entry in the "skin" chunk. +// The number of entries is given in the fmheader chunk +// +#define FM_SKINCHUNKNAME "skin" +#define FM_SKINCHUNKVER 1 +#define FM_MAXPATHLENGTH 64L +#define FM_SKINPATHSIZE (FM_MAXPATHLENGTH) +typedef struct +{ + char path[FM_SKINPATHSIZE]; // path, relative to 'base' +} fm_skinpath_t; + +// +// The format of the "st coord" chunk. This is a list +// of unique skin texture (u, v) coordinates to be mapped +// to verteces of the model +// +#define FM_STCOORDCHUNKNAME "st coord" +#define FM_STCOORDCHUNKVER 1 +#define FM_STCOORDUVSIZE (2L + 2L) + +typedef struct +{ + short s; + short t; +} fm_st_t; + +// +// The format of the "tris" chunk. This is a list of vertex indeces +// in 3D space, and the corresponding vertex indeces in texture space. +// +#define FM_TRISCHUNKNAME "tris" +#define FM_TRISCHUNKVER 1 +#define FM_TRISINFOSIZE (2L*3 + 2L*3) + +typedef struct +{ + short index_xyz[3]; + short index_st[3]; +} fm_xyz_st_t; + + +// +// The format of the "frames" chunk. This is a list of animation +// frames, each specifying the coordinates and "light normal" index +// of every vertex of the model in 3D space. +// +#define FM_FRAMESCHUNKNAME "frames" +#define FM_FRAMESCHUNKVER 1 + +#define FM_NUMVERTEXNORMALS 162 + +// Frame info +typedef struct +{ + byte v[3]; // scaled by header info + byte lightnormalindex; // index in canned table of closest vertex normal +} fm_vert_normal_t; + +typedef struct +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + char name[16]; // frame name +} fm_framehdr_t; + +typedef struct +{ + fm_framehdr_t header; // One header per frame + fm_vert_normal_t verts[1]; // variable number of these +} fm_frame_t; + +typedef struct +{ + fm_chunk_header_t *fm_header_hdr; + fm_header_t *fm_header; + fm_chunk_header_t *fm_skin_hdr; + fm_skinpath_t *fm_skin; + fm_chunk_header_t *fm_st_hdr; + fm_st_t *fm_st; + fm_chunk_header_t *fm_tri_hdr; + fm_xyz_st_t *fm_tri; + fm_chunk_header_t *fm_frame_hdr; + fm_frame_t *fm_frame; +} fm_t; + +float fm_normals[FM_NUMVERTEXNORMALS][3] = { + {-0.525731f, 0.000000f, 0.850651f}, + {-0.442863f, 0.238856f, 0.864188f}, + {-0.295242f, 0.000000f, 0.955423f}, + {-0.309017f, 0.500000f, 0.809017f}, + {-0.162460f, 0.262866f, 0.951056f}, + {0.000000f, 0.000000f, 1.000000f}, + {0.000000f, 0.850651f, 0.525731f}, + {-0.147621f, 0.716567f, 0.681718f}, + {0.147621f, 0.716567f, 0.681718f}, + {0.000000f, 0.525731f, 0.850651f}, + {0.309017f, 0.500000f, 0.809017f}, + {0.525731f, 0.000000f, 0.850651f}, + {0.295242f, 0.000000f, 0.955423f}, + {0.442863f, 0.238856f, 0.864188f}, + {0.162460f, 0.262866f, 0.951056f}, + {-0.681718f, 0.147621f, 0.716567f}, + {-0.809017f, 0.309017f, 0.500000f}, + {-0.587785f, 0.425325f, 0.688191f}, + {-0.850651f, 0.525731f, 0.000000f}, + {-0.864188f, 0.442863f, 0.238856f}, + {-0.716567f, 0.681718f, 0.147621f}, + {-0.688191f, 0.587785f, 0.425325f}, + {-0.500000f, 0.809017f, 0.309017f}, + {-0.238856f, 0.864188f, 0.442863f}, + {-0.425325f, 0.688191f, 0.587785f}, + {-0.716567f, 0.681718f, -0.147621f}, + {-0.500000f, 0.809017f, -0.309017f}, + {-0.525731f, 0.850651f, 0.000000f}, + {0.000000f, 0.850651f, -0.525731f}, + {-0.238856f, 0.864188f, -0.442863f}, + {0.000000f, 0.955423f, -0.295242f}, + {-0.262866f, 0.951056f, -0.162460f}, + {0.000000f, 1.000000f, 0.000000f}, + {0.000000f, 0.955423f, 0.295242f}, + {-0.262866f, 0.951056f, 0.162460f}, + {0.238856f, 0.864188f, 0.442863f}, + {0.262866f, 0.951056f, 0.162460f}, + {0.500000f, 0.809017f, 0.309017f}, + {0.238856f, 0.864188f, -0.442863f}, + {0.262866f, 0.951056f, -0.162460f}, + {0.500000f, 0.809017f, -0.309017f}, + {0.850651f, 0.525731f, 0.000000f}, + {0.716567f, 0.681718f, 0.147621f}, + {0.716567f, 0.681718f, -0.147621f}, + {0.525731f, 0.850651f, 0.000000f}, + {0.425325f, 0.688191f, 0.587785f}, + {0.864188f, 0.442863f, 0.238856f}, + {0.688191f, 0.587785f, 0.425325f}, + {0.809017f, 0.309017f, 0.500000f}, + {0.681718f, 0.147621f, 0.716567f}, + {0.587785f, 0.425325f, 0.688191f}, + {0.955423f, 0.295242f, 0.000000f}, + {1.000000f, 0.000000f, 0.000000f}, + {0.951056f, 0.162460f, 0.262866f}, + {0.850651f, -0.525731f, 0.000000f}, + {0.955423f, -0.295242f, 0.000000f}, + {0.864188f, -0.442863f, 0.238856f}, + {0.951056f, -0.162460f, 0.262866f}, + {0.809017f, -0.309017f, 0.500000f}, + {0.681718f, -0.147621f, 0.716567f}, + {0.850651f, 0.000000f, 0.525731f}, + {0.864188f, 0.442863f, -0.238856f}, + {0.809017f, 0.309017f, -0.500000f}, + {0.951056f, 0.162460f, -0.262866f}, + {0.525731f, 0.000000f, -0.850651f}, + {0.681718f, 0.147621f, -0.716567f}, + {0.681718f, -0.147621f, -0.716567f}, + {0.850651f, 0.000000f, -0.525731f}, + {0.809017f, -0.309017f, -0.500000f}, + {0.864188f, -0.442863f, -0.238856f}, + {0.951056f, -0.162460f, -0.262866f}, + {0.147621f, 0.716567f, -0.681718f}, + {0.309017f, 0.500000f, -0.809017f}, + {0.425325f, 0.688191f, -0.587785f}, + {0.442863f, 0.238856f, -0.864188f}, + {0.587785f, 0.425325f, -0.688191f}, + {0.688191f, 0.587785f, -0.425325f}, + {-0.147621f, 0.716567f, -0.681718f}, + {-0.309017f, 0.500000f, -0.809017f}, + {0.000000f, 0.525731f, -0.850651f}, + {-0.525731f, 0.000000f, -0.850651f}, + {-0.442863f, 0.238856f, -0.864188f}, + {-0.295242f, 0.000000f, -0.955423f}, + {-0.162460f, 0.262866f, -0.951056f}, + {0.000000f, 0.000000f, -1.000000f}, + {0.295242f, 0.000000f, -0.955423f}, + {0.162460f, 0.262866f, -0.951056f}, + {-0.442863f, -0.238856f, -0.864188f}, + {-0.309017f, -0.500000f, -0.809017f}, + {-0.162460f, -0.262866f, -0.951056f}, + {0.000000f, -0.850651f, -0.525731f}, + {-0.147621f, -0.716567f, -0.681718f}, + {0.147621f, -0.716567f, -0.681718f}, + {0.000000f, -0.525731f, -0.850651f}, + {0.309017f, -0.500000f, -0.809017f}, + {0.442863f, -0.238856f, -0.864188f}, + {0.162460f, -0.262866f, -0.951056f}, + {0.238856f, -0.864188f, -0.442863f}, + {0.500000f, -0.809017f, -0.309017f}, + {0.425325f, -0.688191f, -0.587785f}, + {0.716567f, -0.681718f, -0.147621f}, + {0.688191f, -0.587785f, -0.425325f}, + {0.587785f, -0.425325f, -0.688191f}, + {0.000000f, -0.955423f, -0.295242f}, + {0.000000f, -1.000000f, 0.000000f}, + {0.262866f, -0.951056f, -0.162460f}, + {0.000000f, -0.850651f, 0.525731f}, + {0.000000f, -0.955423f, 0.295242f}, + {0.238856f, -0.864188f, 0.442863f}, + {0.262866f, -0.951056f, 0.162460f}, + {0.500000f, -0.809017f, 0.309017f}, + {0.716567f, -0.681718f, 0.147621f}, + {0.525731f, -0.850651f, 0.000000f}, + {-0.238856f, -0.864188f, -0.442863f}, + {-0.500000f, -0.809017f, -0.309017f}, + {-0.262866f, -0.951056f, -0.162460f}, + {-0.850651f, -0.525731f, 0.000000f}, + {-0.716567f, -0.681718f, -0.147621f}, + {-0.716567f, -0.681718f, 0.147621f}, + {-0.525731f, -0.850651f, 0.000000f}, + {-0.500000f, -0.809017f, 0.309017f}, + {-0.238856f, -0.864188f, 0.442863f}, + {-0.262866f, -0.951056f, 0.162460f}, + {-0.864188f, -0.442863f, 0.238856f}, + {-0.809017f, -0.309017f, 0.500000f}, + {-0.688191f, -0.587785f, 0.425325f}, + {-0.681718f, -0.147621f, 0.716567f}, + {-0.442863f, -0.238856f, 0.864188f}, + {-0.587785f, -0.425325f, 0.688191f}, + {-0.309017f, -0.500000f, 0.809017f}, + {-0.147621f, -0.716567f, 0.681718f}, + {-0.425325f, -0.688191f, 0.587785f}, + {-0.162460f, -0.262866f, 0.951056f}, + {0.442863f, -0.238856f, 0.864188f}, + {0.162460f, -0.262866f, 0.951056f}, + {0.309017f, -0.500000f, 0.809017f}, + {0.147621f, -0.716567f, 0.681718f}, + {0.000000f, -0.525731f, 0.850651f}, + {0.425325f, -0.688191f, 0.587785f}, + {0.587785f, -0.425325f, 0.688191f}, + {0.688191f, -0.587785f, 0.425325f}, + {-0.955423f, 0.295242f, 0.000000f}, + {-0.951056f, 0.162460f, 0.262866f}, + {-1.000000f, 0.000000f, 0.000000f}, + {-0.850651f, 0.000000f, 0.525731f}, + {-0.955423f, -0.295242f, 0.000000f}, + {-0.951056f, -0.162460f, 0.262866f}, + {-0.864188f, 0.442863f, -0.238856f}, + {-0.951056f, 0.162460f, -0.262866f}, + {-0.809017f, 0.309017f, -0.500000f}, + {-0.864188f, -0.442863f, -0.238856f}, + {-0.951056f, -0.162460f, -0.262866f}, + {-0.809017f, -0.309017f, -0.500000f}, + {-0.681718f, 0.147621f, -0.716567f}, + {-0.681718f, -0.147621f, -0.716567f}, + {-0.850651f, 0.000000f, -0.525731f}, + {-0.688191f, 0.587785f, -0.425325f}, + {-0.587785f, 0.425325f, -0.688191f}, + {-0.425325f, 0.688191f, -0.587785f}, + {-0.425325f, -0.688191f, -0.587785f}, + {-0.587785f, -0.425325f, -0.688191f}, + {-0.688191f, -0.587785f, -0.425325f}, +}; + +#endif diff --git a/libs/picomodel/pm_lwo.c b/libs/picomodel/pm_lwo.c new file mode 100644 index 00000000..ba83ceb5 --- /dev/null +++ b/libs/picomodel/pm_lwo.c @@ -0,0 +1,430 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +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 names of the copyright holders 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. + +----------------------------------------------------------------------------- */ + +/* marker */ +#define PM_LWO_C + +/* dependencies */ +#include "picointernal.h" +#include "lwo/lwo2.h" + +/* uncomment when debugging this module */ +/*#define DEBUG_PM_LWO*/ + +#ifdef DEBUG_PM_LWO +#include "time.h" +#endif + +/* helper functions */ +static const char *lwo_lwIDToStr( unsigned int lwID ) +{ + static char lwIDStr[5]; + + if (!lwID) + { + return "n/a"; + } + + lwIDStr[ 0 ] = (char)((lwID) >> 24); + lwIDStr[ 1 ] = (char)((lwID) >> 16); + lwIDStr[ 2 ] = (char)((lwID) >> 8); + lwIDStr[ 3 ] = (char)((lwID)); + lwIDStr[ 4 ] = '\0'; + + return lwIDStr; +} + +/* +_lwo_canload() +validates a LightWave Object model file. btw, i use the +preceding underscore cause it's a static func referenced +by one structure only. +*/ +static int _lwo_canload( PM_PARAMS_CANLOAD ) +{ + picoMemStream_t *s; + unsigned int failID = 0; + int failpos = -1; + int ret; + + /* create a new pico memorystream */ + s = _pico_new_memstream( (picoByte_t *)buffer, bufSize ); + if (s == NULL) + { + return PICO_PMV_ERROR_MEMORY; + } + + ret = lwValidateObject( fileName, s, &failID, &failpos ); + + _pico_free_memstream( s ); + + return ret; +} + +/* +_lwo_load() +loads a LightWave Object model file. +*/ +static picoModel_t *_lwo_load( PM_PARAMS_LOAD ) +{ + picoMemStream_t *s; + unsigned int failID = 0; + int failpos = -1; + lwObject *obj; + lwSurface *surface; + lwLayer *layer; + lwPoint *pt; + lwPolygon *pol; + lwPolVert *v; + lwVMapPt *vm; + char name[ 64 ]; + int i, j, k, numverts; + + picoModel_t *picoModel; + picoSurface_t *picoSurface; + picoShader_t *picoShader; + picoVec3_t xyz, normal; + picoVec2_t st; + picoColor_t color; + + int defaultSTAxis[ 2 ]; + picoVec2_t defaultXYZtoSTScale; + + picoVertexCombinationHash_t **hashTable; + picoVertexCombinationHash_t *vertexCombinationHash; + +#ifdef DEBUG_PM_LWO + clock_t load_start, load_finish, convert_start, convert_finish; + double load_elapsed, convert_elapsed; + + load_start = clock(); +#endif + + /* do frame check */ + if( frameNum < 0 || frameNum >= 1 ) + { + _pico_printf( PICO_ERROR, "Invalid or out-of-range LWO frame specified" ); + return NULL; + } + + /* create a new pico memorystream */ + s = _pico_new_memstream( (picoByte_t *)buffer, bufSize ); + if (s == NULL) + { + return NULL; + } + + obj = lwGetObject( fileName, s, &failID, &failpos ); + + _pico_free_memstream( s ); + + if( !obj ) { + _pico_printf( PICO_ERROR, "Couldn't load LWO file, failed on ID '%s', position %d", lwo_lwIDToStr( failID ), failpos ); + return NULL; + } + +#ifdef DEBUG_PM_LWO + convert_start = load_finish = clock(); + load_elapsed = (double)(load_finish - load_start) / CLOCKS_PER_SEC; +#endif + + /* ------------------------------------------------- + pico model creation + ------------------------------------------------- */ + + /* create a new pico model */ + picoModel = PicoNewModel(); + if (picoModel == NULL) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); + return NULL; + } + + /* do model setup */ + PicoSetModelFrameNum( picoModel, frameNum ); + PicoSetModelNumFrames( picoModel, 1 ); + PicoSetModelName( picoModel, fileName ); + PicoSetModelFileName( picoModel, fileName ); + + /* create all polygons from layer[ 0 ] that belong to this surface */ + layer = &obj->layer[0]; + + /* warn the user that other layers are discarded */ + if (obj->nlayers > 1) + { + _pico_printf( PICO_WARNING, "LWO loader discards any geometry data not in Layer 1 (%d layers found)", obj->nlayers ); + } + + /* initialize dummy normal */ + normal[ 0 ] = normal[ 1 ] = normal[ 2 ] = 0.f; + + /* setup default st map */ + st[ 0 ] = st[ 1 ] = 0.f; /* st[0] holds max, st[1] holds max par one */ + defaultSTAxis[ 0 ] = 0; + defaultSTAxis[ 1 ] = 1; + for( i = 0; i < 3; i++ ) + { + float min = layer->bbox[ i ]; + float max = layer->bbox[ i + 3 ]; + float size = max - min; + + if (size > st[ 0 ]) + { + defaultSTAxis[ 1 ] = defaultSTAxis[ 0 ]; + defaultSTAxis[ 0 ] = i; + + st[ 1 ] = st[ 0 ]; + st[ 0 ] = size; + } + else if (size > st[ 1 ]) + { + defaultSTAxis[ 1 ] = i; + st[ 1 ] = size; + } + } + defaultXYZtoSTScale[ 0 ] = 4.f / st[ 0 ]; + defaultXYZtoSTScale[ 1 ] = 4.f / st[ 1 ]; + + /* LWO surfaces become pico surfaces */ + surface = obj->surf; + while (surface) + { + /* allocate new pico surface */ + picoSurface = PicoNewSurface( picoModel ); + if (picoSurface == NULL) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); + PicoFreeModel( picoModel ); + lwFreeObject( obj ); + return NULL; + } + + /* LWO model surfaces are all triangle meshes */ + PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); + + /* set surface name */ + PicoSetSurfaceName( picoSurface, surface->name ); + + /* create new pico shader */ + picoShader = PicoNewShader( picoModel ); + if (picoShader == NULL) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); + PicoFreeModel( picoModel ); + lwFreeObject( obj ); + return NULL; + } + + /* detox and set shader name */ + strncpy( name, surface->name, sizeof(name) ); + _pico_setfext( name, "" ); + _pico_unixify( name ); + PicoSetShaderName( picoShader, name ); + + /* associate current surface with newly created shader */ + PicoSetSurfaceShader( picoSurface, picoShader ); + + /* copy indices and vertex data */ + numverts = 0; + + hashTable = PicoNewVertexCombinationHashTable(); + + if (hashTable == NULL) + { + _pico_printf( PICO_ERROR, "Unable to allocate hash table" ); + PicoFreeModel( picoModel ); + lwFreeObject( obj ); + return NULL; + } + + for( i = 0, pol = layer->polygon.pol; i < layer->polygon.count; i++, pol++ ) + { + /* does this polygon belong to this surface? */ + if (pol->surf != surface) + continue; + + /* we only support polygons of the FACE type */ + if (pol->type != ID_FACE) + { + _pico_printf( PICO_WARNING, "LWO loader discarded a polygon because it's type != FACE (%s)", lwo_lwIDToStr( pol->type ) ); + continue; + } + + /* NOTE: LWO has support for non-convex polygons, do we want to store them as well? */ + if (pol->nverts != 3) + { + _pico_printf( PICO_WARNING, "LWO loader discarded a polygon because it has != 3 verts (%d)", pol->nverts ); + continue; + } + + for( j = 0, v = pol->v; j < 3; j++, v++ ) + { + pt = &layer->point.pt[ v->index ]; + + /* setup data */ + xyz[ 0 ] = pt->pos[ 0 ]; + xyz[ 1 ] = pt->pos[ 2 ]; + xyz[ 2 ] = pt->pos[ 1 ]; + + normal[ 0 ] = v->norm[ 0 ]; + normal[ 1 ] = v->norm[ 2 ]; + normal[ 2 ] = v->norm[ 1 ]; + + st[ 0 ] = xyz[ defaultSTAxis[ 0 ] ] * defaultXYZtoSTScale[ 0 ]; + st[ 1 ] = xyz[ defaultSTAxis[ 1 ] ] * defaultXYZtoSTScale[ 1 ]; + + color[ 0 ] = (picoByte_t)(surface->color.rgb[ 0 ] * surface->diffuse.val * 0xFF); + color[ 1 ] = (picoByte_t)(surface->color.rgb[ 1 ] * surface->diffuse.val * 0xFF); + color[ 2 ] = (picoByte_t)(surface->color.rgb[ 2 ] * surface->diffuse.val * 0xFF); + color[ 3 ] = 0xFF; + + /* set from points */ + for( k = 0, vm = pt->vm; k < pt->nvmaps; k++, vm++ ) + { + if (vm->vmap->type == LWID_('T','X','U','V')) + { + /* set st coords */ + st[ 0 ] = vm->vmap->val[ vm->index ][ 0 ]; + st[ 1 ] = 1.f - vm->vmap->val[ vm->index ][ 1 ]; + } + else if (vm->vmap->type == LWID_('R','G','B','A')) + { + /* set rgba */ + color[ 0 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 0 ] * surface->color.rgb[ 0 ] * surface->diffuse.val * 0xFF); + color[ 1 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 1 ] * surface->color.rgb[ 1 ] * surface->diffuse.val * 0xFF); + color[ 2 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 2 ] * surface->color.rgb[ 2 ] * surface->diffuse.val * 0xFF); + color[ 3 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 3 ] * 0xFF); + } + } + + /* override with polygon data */ + for( k = 0, vm = v->vm; k < v->nvmaps; k++, vm++ ) + { + if (vm->vmap->type == LWID_('T','X','U','V')) + { + /* set st coords */ + st[ 0 ] = vm->vmap->val[ vm->index ][ 0 ]; + st[ 1 ] = 1.f - vm->vmap->val[ vm->index ][ 1 ]; + } + else if (vm->vmap->type == LWID_('R','G','B','A')) + { + /* set rgba */ + color[ 0 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 0 ] * surface->color.rgb[ 0 ] * surface->diffuse.val * 0xFF); + color[ 1 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 1 ] * surface->color.rgb[ 1 ] * surface->diffuse.val * 0xFF); + color[ 2 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 2 ] * surface->color.rgb[ 2 ] * surface->diffuse.val * 0xFF); + color[ 3 ] = (picoByte_t)(vm->vmap->val[ vm->index ][ 3 ] * 0xFF); + } + } + + /* find vertex in this surface and if we can't find it there create it */ + vertexCombinationHash = PicoFindVertexCombinationInHashTable( hashTable, xyz, normal, st, color ); + + if (vertexCombinationHash) + { + /* found an existing one */ + PicoSetSurfaceIndex( picoSurface, (i * 3 + j ), vertexCombinationHash->index ); + } + else + { + /* it is a new one */ + vertexCombinationHash = PicoAddVertexCombinationToHashTable( hashTable, xyz, normal, st, color, (picoIndex_t) numverts ); + + if (vertexCombinationHash == NULL) + { + _pico_printf( PICO_ERROR, "Unable to allocate hash bucket entry table" ); + PicoFreeVertexCombinationHashTable( hashTable ); + PicoFreeModel( picoModel ); + lwFreeObject( obj ); + return NULL; + } + + /* add the vertex to this surface */ + PicoSetSurfaceXYZ( picoSurface, numverts, xyz ); + + /* set dummy normal */ + PicoSetSurfaceNormal( picoSurface, numverts, normal ); + + /* set color */ + PicoSetSurfaceColor( picoSurface, 0, numverts, color ); + + /* set st coords */ + PicoSetSurfaceST( picoSurface, 0, numverts, st ); + + /* set index */ + PicoSetSurfaceIndex( picoSurface, (i * 3 + j ), (picoIndex_t) numverts ); + + numverts++; + } + } + } + + /* free the hashtable */ + PicoFreeVertexCombinationHashTable( hashTable ); + + /* get next surface */ + surface = surface->next; + } + +#ifdef DEBUG_PM_LWO + load_start = convert_finish = clock(); +#endif + + lwFreeObject( obj ); + +#ifdef DEBUG_PM_LWO + load_finish = clock(); + load_elapsed += (double)(load_finish - load_start) / CLOCKS_PER_SEC; + convert_elapsed = (double)(convert_finish - convert_start) / CLOCKS_PER_SEC; + _pico_printf( PICO_NORMAL, "Loaded model in in %-.2f second(s) (loading: %-.2fs converting: %-.2fs)\n", load_elapsed + convert_elapsed, load_elapsed, convert_elapsed ); +#endif + + /* return the new pico model */ + return picoModel; +} + +/* pico file format module definition */ +const picoModule_t picoModuleLWO = +{ + "1.0", /* module version string */ + "LightWave Object", /* module display name */ + "Arnout van Meer", /* author's name */ + "2003 Arnout van Meer, 2000 Ernie Wright", /* module copyright */ + { + "lwo", NULL, NULL, NULL /* default extensions to use */ + }, + _lwo_canload, /* validation routine */ + _lwo_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_md2.c b/libs/picomodel/pm_md2.c new file mode 100644 index 00000000..2351ea58 --- /dev/null +++ b/libs/picomodel/pm_md2.c @@ -0,0 +1,670 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +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 names of the copyright holders 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. + +----------------------------------------------------------------------------- */ + +/* +Nurail: Used pm_md3.c (Randy Reddig) as a template. +*/ + + +/* marker */ +#define PM_MD2_C + +/* dependencies */ +#include "picointernal.h" + + +/* md2 model format */ +#define MD2_MAGIC "IDP2" +#define MD2_VERSION 8 + +#define MD2_NUMVERTEXNORMALS 162 +#define MD2_MAX_SKINNAME 64 +#define MD2_MAX_TRIANGLES 4096 +#define MD2_MAX_VERTS 2048 +#define MD2_MAX_FRAMES 512 +#define MD2_MAX_MD2SKINS 32 +#define MD2_MAX_SKINNAME 64 + +#ifndef byte + #define byte unsigned char +#endif + +typedef struct index_LUT_s +{ + short Vert; + short ST; + struct index_LUT_s *next; + +} index_LUT_t; + +typedef struct index_DUP_LUT_s +{ + short ST; + short OldVert; + +} index_DUP_LUT_t; + +typedef struct +{ + short s; + short t; +} md2St_t; + +typedef struct +{ + short index_xyz[3]; + short index_st[3]; +} md2Triangle_t; + +typedef struct +{ + byte v[3]; // scaled byte to fit in frame mins/maxs + byte lightnormalindex; +} md2XyzNormal_t; + +typedef struct md2Frame_s +{ + float scale[3]; // multiply byte verts by this + float translate[3]; // then add this + char name[16]; // frame name from grabbing + md2XyzNormal_t verts[1]; // variable sized +} +md2Frame_t; + + +/* md2 model file md2 structure */ +typedef struct md2_s +{ + char magic[ 4 ]; + int version; + + int skinWidth; + int skinHeight; + int frameSize; + + int numSkins; + int numXYZ; + int numST; + int numTris; + int numGLCmds; + int numFrames; + + int ofsSkins; + int ofsST; + int ofsTris; + int ofsFrames; + int ofsGLCmds; + int ofsEnd; +} +md2_t; + +float md2_normals[ MD2_NUMVERTEXNORMALS ][ 3 ] = +{ + { -0.525731f, 0.000000f, 0.850651f }, + { -0.442863f, 0.238856f, 0.864188f }, + { -0.295242f, 0.000000f, 0.955423f }, + { -0.309017f, 0.500000f, 0.809017f }, + { -0.162460f, 0.262866f, 0.951056f }, + { 0.000000f, 0.000000f, 1.000000f }, + { 0.000000f, 0.850651f, 0.525731f }, + { -0.147621f, 0.716567f, 0.681718f }, + { 0.147621f, 0.716567f, 0.681718f }, + { 0.000000f, 0.525731f, 0.850651f }, + { 0.309017f, 0.500000f, 0.809017f }, + { 0.525731f, 0.000000f, 0.850651f }, + { 0.295242f, 0.000000f, 0.955423f }, + { 0.442863f, 0.238856f, 0.864188f }, + { 0.162460f, 0.262866f, 0.951056f }, + { -0.681718f, 0.147621f, 0.716567f }, + { -0.809017f, 0.309017f, 0.500000f }, + { -0.587785f, 0.425325f, 0.688191f }, + { -0.850651f, 0.525731f, 0.000000f }, + { -0.864188f, 0.442863f, 0.238856f }, + { -0.716567f, 0.681718f, 0.147621f }, + { -0.688191f, 0.587785f, 0.425325f }, + { -0.500000f, 0.809017f, 0.309017f }, + { -0.238856f, 0.864188f, 0.442863f }, + { -0.425325f, 0.688191f, 0.587785f }, + { -0.716567f, 0.681718f, -0.147621f }, + { -0.500000f, 0.809017f, -0.309017f }, + { -0.525731f, 0.850651f, 0.000000f }, + { 0.000000f, 0.850651f, -0.525731f }, + { -0.238856f, 0.864188f, -0.442863f }, + { 0.000000f, 0.955423f, -0.295242f }, + { -0.262866f, 0.951056f, -0.162460f }, + { 0.000000f, 1.000000f, 0.000000f }, + { 0.000000f, 0.955423f, 0.295242f }, + { -0.262866f, 0.951056f, 0.162460f }, + { 0.238856f, 0.864188f, 0.442863f }, + { 0.262866f, 0.951056f, 0.162460f }, + { 0.500000f, 0.809017f, 0.309017f }, + { 0.238856f, 0.864188f, -0.442863f }, + { 0.262866f, 0.951056f, -0.162460f }, + { 0.500000f, 0.809017f, -0.309017f }, + { 0.850651f, 0.525731f, 0.000000f }, + { 0.716567f, 0.681718f, 0.147621f }, + { 0.716567f, 0.681718f, -0.147621f }, + { 0.525731f, 0.850651f, 0.000000f }, + { 0.425325f, 0.688191f, 0.587785f }, + { 0.864188f, 0.442863f, 0.238856f }, + { 0.688191f, 0.587785f, 0.425325f }, + { 0.809017f, 0.309017f, 0.500000f }, + { 0.681718f, 0.147621f, 0.716567f }, + { 0.587785f, 0.425325f, 0.688191f }, + { 0.955423f, 0.295242f, 0.000000f }, + { 1.000000f, 0.000000f, 0.000000f }, + { 0.951056f, 0.162460f, 0.262866f }, + { 0.850651f, -0.525731f, 0.000000f }, + { 0.955423f, -0.295242f, 0.000000f }, + { 0.864188f, -0.442863f, 0.238856f }, + { 0.951056f, -0.162460f, 0.262866f }, + { 0.809017f, -0.309017f, 0.500000f }, + { 0.681718f, -0.147621f, 0.716567f }, + { 0.850651f, 0.000000f, 0.525731f }, + { 0.864188f, 0.442863f, -0.238856f }, + { 0.809017f, 0.309017f, -0.500000f }, + { 0.951056f, 0.162460f, -0.262866f }, + { 0.525731f, 0.000000f, -0.850651f }, + { 0.681718f, 0.147621f, -0.716567f }, + { 0.681718f, -0.147621f, -0.716567f }, + { 0.850651f, 0.000000f, -0.525731f }, + { 0.809017f, -0.309017f, -0.500000f }, + { 0.864188f, -0.442863f, -0.238856f }, + { 0.951056f, -0.162460f, -0.262866f }, + { 0.147621f, 0.716567f, -0.681718f }, + { 0.309017f, 0.500000f, -0.809017f }, + { 0.425325f, 0.688191f, -0.587785f }, + { 0.442863f, 0.238856f, -0.864188f }, + { 0.587785f, 0.425325f, -0.688191f }, + { 0.688191f, 0.587785f, -0.425325f }, + { -0.147621f, 0.716567f, -0.681718f }, + { -0.309017f, 0.500000f, -0.809017f }, + { 0.000000f, 0.525731f, -0.850651f }, + { -0.525731f, 0.000000f, -0.850651f }, + { -0.442863f, 0.238856f, -0.864188f }, + { -0.295242f, 0.000000f, -0.955423f }, + { -0.162460f, 0.262866f, -0.951056f }, + { 0.000000f, 0.000000f, -1.000000f }, + { 0.295242f, 0.000000f, -0.955423f }, + { 0.162460f, 0.262866f, -0.951056f }, + { -0.442863f, -0.238856f, -0.864188f }, + { -0.309017f, -0.500000f, -0.809017f }, + { -0.162460f, -0.262866f, -0.951056f }, + { 0.000000f, -0.850651f, -0.525731f }, + { -0.147621f, -0.716567f, -0.681718f }, + { 0.147621f, -0.716567f, -0.681718f }, + { 0.000000f, -0.525731f, -0.850651f }, + { 0.309017f, -0.500000f, -0.809017f }, + { 0.442863f, -0.238856f, -0.864188f }, + { 0.162460f, -0.262866f, -0.951056f }, + { 0.238856f, -0.864188f, -0.442863f }, + { 0.500000f, -0.809017f, -0.309017f }, + { 0.425325f, -0.688191f, -0.587785f }, + { 0.716567f, -0.681718f, -0.147621f }, + { 0.688191f, -0.587785f, -0.425325f }, + { 0.587785f, -0.425325f, -0.688191f }, + { 0.000000f, -0.955423f, -0.295242f }, + { 0.000000f, -1.000000f, 0.000000f }, + { 0.262866f, -0.951056f, -0.162460f }, + { 0.000000f, -0.850651f, 0.525731f }, + { 0.000000f, -0.955423f, 0.295242f }, + { 0.238856f, -0.864188f, 0.442863f }, + { 0.262866f, -0.951056f, 0.162460f }, + { 0.500000f, -0.809017f, 0.309017f }, + { 0.716567f, -0.681718f, 0.147621f }, + { 0.525731f, -0.850651f, 0.000000f }, + { -0.238856f, -0.864188f, -0.442863f }, + { -0.500000f, -0.809017f, -0.309017f }, + { -0.262866f, -0.951056f, -0.162460f }, + { -0.850651f, -0.525731f, 0.000000f }, + { -0.716567f, -0.681718f, -0.147621f }, + { -0.716567f, -0.681718f, 0.147621f }, + { -0.525731f, -0.850651f, 0.000000f }, + { -0.500000f, -0.809017f, 0.309017f }, + { -0.238856f, -0.864188f, 0.442863f }, + { -0.262866f, -0.951056f, 0.162460f }, + { -0.864188f, -0.442863f, 0.238856f }, + { -0.809017f, -0.309017f, 0.500000f }, + { -0.688191f, -0.587785f, 0.425325f }, + { -0.681718f, -0.147621f, 0.716567f }, + { -0.442863f, -0.238856f, 0.864188f }, + { -0.587785f, -0.425325f, 0.688191f }, + { -0.309017f, -0.500000f, 0.809017f }, + { -0.147621f, -0.716567f, 0.681718f }, + { -0.425325f, -0.688191f, 0.587785f }, + { -0.162460f, -0.262866f, 0.951056f }, + { 0.442863f, -0.238856f, 0.864188f }, + { 0.162460f, -0.262866f, 0.951056f }, + { 0.309017f, -0.500000f, 0.809017f }, + { 0.147621f, -0.716567f, 0.681718f }, + { 0.000000f, -0.525731f, 0.850651f }, + { 0.425325f, -0.688191f, 0.587785f }, + { 0.587785f, -0.425325f, 0.688191f }, + { 0.688191f, -0.587785f, 0.425325f }, + { -0.955423f, 0.295242f, 0.000000f }, + { -0.951056f, 0.162460f, 0.262866f }, + { -1.000000f, 0.000000f, 0.000000f }, + { -0.850651f, 0.000000f, 0.525731f }, + { -0.955423f, -0.295242f, 0.000000f }, + { -0.951056f, -0.162460f, 0.262866f }, + { -0.864188f, 0.442863f, -0.238856f }, + { -0.951056f, 0.162460f, -0.262866f }, + { -0.809017f, 0.309017f, -0.500000f }, + { -0.864188f, -0.442863f, -0.238856f }, + { -0.951056f, -0.162460f, -0.262866f }, + { -0.809017f, -0.309017f, -0.500000f }, + { -0.681718f, 0.147621f, -0.716567f }, + { -0.681718f, -0.147621f, -0.716567f }, + { -0.850651f, 0.000000f, -0.525731f }, + { -0.688191f, 0.587785f, -0.425325f }, + { -0.587785f, 0.425325f, -0.688191f }, + { -0.425325f, 0.688191f, -0.587785f }, + { -0.425325f, -0.688191f, -0.587785f }, + { -0.587785f, -0.425325f, -0.688191f }, + { -0.688191f, -0.587785f, -0.425325f }, +}; + + +// _md2_canload() + +static int _md2_canload( PM_PARAMS_CANLOAD ) +{ + md2_t *md2; + + /* to keep the compiler happy */ + *fileName = *fileName; + + /* sanity check */ + if( bufSize < ( sizeof( *md2 ) * 2) ) + return PICO_PMV_ERROR_SIZE; + + /* set as md2 */ + md2 = (md2_t*) buffer; + + /* check md2 magic */ + if( *((int*) md2->magic) != *((int*) MD2_MAGIC) ) + return PICO_PMV_ERROR_IDENT; + + /* check md2 version */ + if( _pico_little_long( md2->version ) != MD2_VERSION ) + return PICO_PMV_ERROR_VERSION; + + /* file seems to be a valid md2 */ + return PICO_PMV_OK; +} + + + +// _md2_load() loads a quake2 md2 model file. + + +static picoModel_t *_md2_load( PM_PARAMS_LOAD ) +{ + int i, j, dups, dup_index; + short tot_numVerts; + index_LUT_t *p_index_LUT, *p_index_LUT2, *p_index_LUT3; + index_DUP_LUT_t *p_index_LUT_DUPS; + md2Triangle_t *p_md2Triangle; + + char skinname[ MD2_MAX_SKINNAME ]; + md2_t *md2; + md2St_t *texCoord; + md2Frame_t *frame; + md2Triangle_t *triangle; + md2XyzNormal_t *vertex; + + picoByte_t *bb; + picoModel_t *picoModel; + picoSurface_t *picoSurface; + picoShader_t *picoShader; + picoVec3_t xyz, normal; + picoVec2_t st; + picoColor_t color; + + + // md2 loading + _pico_printf( PICO_NORMAL, "Loading \"%s\"", fileName ); + + /* set as md2 */ + bb = (picoByte_t*) buffer; + md2 = (md2_t*) buffer; + + /* check ident and version */ + if( *((int*) md2->magic) != *((int*) MD2_MAGIC) || _pico_little_long( md2->version ) != MD2_VERSION ) + { + /* not an md2 file (todo: set error) */ + _pico_printf( PICO_ERROR, "%s is not an MD2 File!", fileName ); + return NULL; + } + + // swap md2 + md2->version = _pico_little_long( md2->version ); + + md2->skinWidth = _pico_little_long( md2->skinWidth ); + md2->skinHeight = _pico_little_long( md2->skinHeight ); + md2->frameSize = _pico_little_long( md2->frameSize ); + + md2->numSkins = _pico_little_long( md2->numSkins ); + md2->numXYZ = _pico_little_long( md2->numXYZ ); + md2->numST = _pico_little_long( md2->numST ); + md2->numTris = _pico_little_long( md2->numTris ); + md2->numGLCmds = _pico_little_long( md2->numGLCmds ); + md2->numFrames = _pico_little_long( md2->numFrames ); + + md2->ofsSkins = _pico_little_long( md2->ofsSkins ); + md2->ofsST = _pico_little_long( md2->ofsST ); + md2->ofsTris = _pico_little_long( md2->ofsTris ); + md2->ofsFrames = _pico_little_long( md2->ofsFrames ); + md2->ofsGLCmds = _pico_little_long( md2->ofsGLCmds ); + md2->ofsEnd = _pico_little_long( md2->ofsEnd ); + + // do frame check + if( md2->numFrames < 1 ) + { + _pico_printf( PICO_ERROR, "%s has 0 frames!", fileName ); + return NULL; + } + + if( frameNum < 0 || frameNum >= md2->numFrames ) + { + _pico_printf( PICO_ERROR, "Invalid or out-of-range MD2 frame specified" ); + return NULL; + } + + // Setup Frame + frame = (md2Frame_t *) (bb + md2->ofsFrames + (sizeof(md2Frame_t) * frameNum)); + + // swap frame scale and translation + for( i = 0; i < 3; i++ ) + { + frame->scale[ i ] = _pico_little_float( frame->scale[ i ] ); + frame->translate[ i ] = _pico_little_float( frame->translate[ i ] ); + } + + // swap triangles + triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) ); + for( i = 0; i < md2->numTris; i++, triangle++ ) + { + for( j = 0; j < 3; j++ ) + { + triangle->index_xyz[ j ] = _pico_little_short( triangle->index_xyz[ j ] ); + triangle->index_st[ j ] = _pico_little_short( triangle->index_st[ j ] ); + } + } + + // swap st coords + texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) ); + for( i = 0; i < md2->numST; i++, texCoord++ ) + { + texCoord->s = _pico_little_short( texCoord->s ); + texCoord->t = _pico_little_short( texCoord->t ); + } + + // set Skin Name + strncpy(skinname, (bb + md2->ofsSkins), MD2_MAX_SKINNAME ); + + // Print out md2 values + _pico_printf(PICO_VERBOSE,"Skins: %d Verts: %d STs: %d Triangles: %d Frames: %d\nSkin Name \"%s\"\n", md2->numSkins, md2->numXYZ, md2->numST, md2->numTris, md2->numFrames, &skinname ); + + // detox Skin name + _pico_setfext( skinname, "" ); + _pico_unixify( skinname ); + + /* create new pico model */ + picoModel = PicoNewModel(); + if( picoModel == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); + return NULL; + } + + /* do model setup */ + PicoSetModelFrameNum( picoModel, frameNum ); + PicoSetModelNumFrames( picoModel, md2->numFrames ); /* sea */ + PicoSetModelName( picoModel, fileName ); + PicoSetModelFileName( picoModel, fileName ); + + // allocate new pico surface + picoSurface = PicoNewSurface( picoModel ); + if( picoSurface == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); + PicoFreeModel( picoModel ); + return NULL; + } + + + PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); + PicoSetSurfaceName( picoSurface, frame->name ); + picoShader = PicoNewShader( picoModel ); + if( picoShader == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); + PicoFreeModel( picoModel ); + return NULL; + } + + PicoSetShaderName( picoShader, skinname ); + + // associate current surface with newly created shader + PicoSetSurfaceShader( picoSurface, picoShader ); + + // Init LUT for Verts + p_index_LUT = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t) * md2->numXYZ); + for(i=0; inumXYZ; i++) + { + p_index_LUT[i].Vert = -1; + p_index_LUT[i].ST = -1; + p_index_LUT[i].next = NULL; + } + + // Fill in Look Up Table, and allocate/fill Linked List from vert array as needed for dup STs per Vert. + tot_numVerts = md2->numXYZ; + dups = 0; + for(i=0; inumTris; i++) + { + p_md2Triangle = (md2Triangle_t *) ( bb + md2->ofsTris + (sizeof(md2Triangle_t)*i)); + for(j=0; j<3; j++) + { + if (p_index_LUT[p_md2Triangle->index_xyz[j]].ST == -1) // No Main Entry + p_index_LUT[p_md2Triangle->index_xyz[j]].ST = p_md2Triangle->index_st[j]; + + else if (p_md2Triangle->index_st[j] == p_index_LUT[p_md2Triangle->index_xyz[j]].ST ) // Equal to Main Entry + continue; + + else if ( (p_index_LUT[p_md2Triangle->index_xyz[j]].next == NULL) ) // Not equal to Main entry, and no LL entry + { // Add first entry of LL from Main + p_index_LUT2 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); + if (p_index_LUT2 == NULL) + _pico_printf( PICO_ERROR," Couldn't allocate memory!\n"); + p_index_LUT[p_md2Triangle->index_xyz[j]].next = (index_LUT_t *)p_index_LUT2; + p_index_LUT2->Vert = dups; + p_index_LUT2->ST = p_md2Triangle->index_st[j]; + p_index_LUT2->next = NULL; + p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk + dups++; + } + else // Try to find in LL from Main Entry + { + p_index_LUT3 = p_index_LUT2 = p_index_LUT[p_md2Triangle->index_xyz[j]].next; + while ( (p_index_LUT2 != NULL) && (p_md2Triangle->index_xyz[j] != p_index_LUT2->Vert) ) // Walk down LL + { + p_index_LUT3 = p_index_LUT2; + p_index_LUT2 = p_index_LUT2->next; + } + p_index_LUT2 = p_index_LUT3; + + if ( p_md2Triangle->index_st[j] == p_index_LUT2->ST ) // Found it + { + p_md2Triangle->index_xyz[j] = p_index_LUT2->Vert + md2->numXYZ; // Make change in Tri hunk + continue; + } + + if ( p_index_LUT2->next == NULL) // Didn't find it. Add entry to LL. + { + // Add the Entry + p_index_LUT3 = (index_LUT_t *)_pico_alloc(sizeof(index_LUT_t)); + if (p_index_LUT3 == NULL) + _pico_printf( PICO_ERROR," Couldn't allocate memory!\n"); + p_index_LUT2->next = (index_LUT_t *)p_index_LUT3; + p_index_LUT3->Vert = p_md2Triangle->index_xyz[j]; + p_index_LUT3->ST = p_md2Triangle->index_st[j]; + p_index_LUT3->next = NULL; + p_md2Triangle->index_xyz[j] = dups + md2->numXYZ; // Make change in Tri hunk + dups++; + } + } + } + } + + // malloc and build array for Dup STs + p_index_LUT_DUPS = (index_DUP_LUT_t *)_pico_alloc(sizeof(index_DUP_LUT_t) * dups); + if (p_index_LUT_DUPS == NULL) + _pico_printf( PICO_ERROR," Couldn't allocate memory!\n"); + + dup_index = 0; + for(i=0; inumXYZ; i++) + { + p_index_LUT2 = p_index_LUT[i].next; + while (p_index_LUT2 != NULL) + { + p_index_LUT_DUPS[p_index_LUT2->Vert].OldVert = i; + p_index_LUT_DUPS[p_index_LUT2->Vert].ST = p_index_LUT2->ST; + dup_index++; + p_index_LUT2 = p_index_LUT2->next; + } + } + + // Build Picomodel + triangle = (md2Triangle_t *) ((picoByte_t *) (bb + md2->ofsTris) ); + texCoord = (md2St_t*) ((picoByte_t *) (bb + md2->ofsST) ); + vertex = (md2XyzNormal_t*) ((picoByte_t*) (frame->verts) ); + for( j = 0; j < md2->numTris; j++, triangle++ ) + { + PicoSetSurfaceIndex( picoSurface, j*3 , triangle->index_xyz[0] ); + PicoSetSurfaceIndex( picoSurface, j*3+1 , triangle->index_xyz[1] ); + PicoSetSurfaceIndex( picoSurface, j*3+2 , triangle->index_xyz[2] ); + } + + for(i=0; i< md2->numXYZ; i++, vertex++) + { + /* set vertex origin */ + xyz[ 0 ] = vertex->v[0] * frame->scale[0] + frame->translate[0]; + xyz[ 1 ] = vertex->v[1] * frame->scale[1] + frame->translate[1]; + xyz[ 2 ] = vertex->v[2] * frame->scale[2] + frame->translate[2]; + PicoSetSurfaceXYZ( picoSurface, i , xyz ); + + /* set normal */ + normal[ 0 ] = md2_normals[vertex->lightnormalindex][0]; + normal[ 1 ] = md2_normals[vertex->lightnormalindex][1]; + normal[ 2 ] = md2_normals[vertex->lightnormalindex][2]; + PicoSetSurfaceNormal( picoSurface, i , normal ); + + /* set st coords */ + st[ 0 ] = ((texCoord[p_index_LUT[i].ST].s) / ((float)md2->skinWidth)); + st[ 1 ] = (texCoord[p_index_LUT[i].ST].t / ((float)md2->skinHeight)); + PicoSetSurfaceST( picoSurface, 0, i , st ); + } + + if (dups) + { + for(i=0; iverts[j].v[0] * frame->scale[0] + frame->translate[0]; + xyz[ 1 ] = frame->verts[j].v[1] * frame->scale[1] + frame->translate[1]; + xyz[ 2 ] = frame->verts[j].v[2] * frame->scale[2] + frame->translate[2]; + PicoSetSurfaceXYZ( picoSurface, i + md2->numXYZ , xyz ); + + /* set normal */ + normal[ 0 ] = md2_normals[frame->verts[j].lightnormalindex][0]; + normal[ 1 ] = md2_normals[frame->verts[j].lightnormalindex][1]; + normal[ 2 ] = md2_normals[frame->verts[j].lightnormalindex][2]; + PicoSetSurfaceNormal( picoSurface, i + md2->numXYZ , normal ); + + /* set st coords */ + st[ 0 ] = ((texCoord[p_index_LUT_DUPS[i].ST].s) / ((float)md2->skinWidth)); + st[ 1 ] = (texCoord[p_index_LUT_DUPS[i].ST].t / ((float)md2->skinHeight)); + PicoSetSurfaceST( picoSurface, 0, i + md2->numXYZ , st ); + } + } + + /* set color */ + PicoSetSurfaceColor( picoSurface, 0, 0, color ); + + // Free up malloc'ed LL entries + for(i=0; inumXYZ; i++) + { + if(p_index_LUT[i].next != NULL) + { + p_index_LUT2 = p_index_LUT[i].next; + do { + p_index_LUT3 = p_index_LUT2->next; + _pico_free(p_index_LUT2); + p_index_LUT2 = p_index_LUT3; + dups--; + } while (p_index_LUT2 != NULL); + } + } + + if (dups) + _pico_printf(PICO_WARNING, " Not all LL mallocs freed\n"); + + // Free malloc'ed LUTs + _pico_free(p_index_LUT); + _pico_free(p_index_LUT_DUPS); + + /* return the new pico model */ + return picoModel; + +} + + + +/* pico file format module definition */ +const picoModule_t picoModuleMD2 = +{ + "0.875", /* module version string */ + "Quake 2 MD2", /* module display name */ + "Nurail", /* author's name */ + "2003 Nurail", /* module copyright */ + { + "md2", NULL, NULL, NULL /* default extensions to use */ + }, + _md2_canload, /* validation routine */ + _md2_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_md3.c b/libs/picomodel/pm_md3.c new file mode 100644 index 00000000..6d87469d --- /dev/null +++ b/libs/picomodel/pm_md3.c @@ -0,0 +1,425 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +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 names of the copyright holders 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. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PM_MD3_C + + + +/* dependencies */ +#include "picointernal.h" + + + +/* md3 model format */ +#define MD3_MAGIC "IDP3" +#define MD3_VERSION 15 + +/* md3 vertex scale */ +#define MD3_SCALE (1.0f / 64.0f) + +/* md3 model frame information */ +typedef struct md3Frame_s +{ + float bounds[ 2 ][ 3 ]; + float localOrigin[ 3 ]; + float radius; + char creator[ 16 ]; +} +md3Frame_t; + +/* md3 model tag information */ +typedef struct md3Tag_s +{ + char name[ 64 ]; + float origin[ 3 ]; + float axis[ 3 ][ 3 ]; +} +md3Tag_t; + +/* md3 surface md3 (one object mesh) */ +typedef struct md3Surface_s +{ + char magic[ 4 ]; + char name[ 64 ]; /* polyset name */ + int flags; + int numFrames; /* all model surfaces should have the same */ + int numShaders; /* all model surfaces should have the same */ + int numVerts; + int numTriangles; + int ofsTriangles; + int ofsShaders; /* offset from start of md3Surface_t */ + int ofsSt; /* texture coords are common for all frames */ + int ofsVertexes; /* numVerts * numFrames */ + int ofsEnd; /* next surface follows */ +} +md3Surface_t; + +typedef struct md3Shader_s +{ + char name[ 64 ]; + int shaderIndex; /* for ingame use */ +} +md3Shader_t; + +typedef struct md3Triangle_s +{ + int indexes[ 3 ]; +} +md3Triangle_t; + +typedef struct md3TexCoord_s +{ + float st[ 2 ]; +} +md3TexCoord_t; + +typedef struct md3Vertex_s +{ + short xyz[ 3 ]; + short normal; +} +md3Vertex_t; + + +/* md3 model file md3 structure */ +typedef struct md3_s +{ + char magic[ 4 ]; /* MD3_MAGIC */ + int version; + char name[ 64 ]; /* model name */ + int flags; + int numFrames; + int numTags; + int numSurfaces; + int numSkins; /* number of skins for the mesh */ + int ofsFrames; /* offset for first frame */ + int ofsTags; /* numFrames * numTags */ + int ofsSurfaces; /* first surface, others follow */ + int ofsEnd; /* end of file */ +} +md3_t; + + + + +/* +_md3_canload() +validates a quake3 arena md3 model file. btw, i use the +preceding underscore cause it's a static func referenced +by one structure only. +*/ + +static int _md3_canload( PM_PARAMS_CANLOAD ) +{ + md3_t *md3; + + + /* to keep the compiler happy */ + *fileName = *fileName; + + /* sanity check */ + if( bufSize < ( sizeof( *md3 ) * 2) ) + return PICO_PMV_ERROR_SIZE; + + /* set as md3 */ + md3 = (md3_t*) buffer; + + /* check md3 magic */ + if( *((int*) md3->magic) != *((int*) MD3_MAGIC) ) + return PICO_PMV_ERROR_IDENT; + + /* check md3 version */ + if( _pico_little_long( md3->version ) != MD3_VERSION ) + return PICO_PMV_ERROR_VERSION; + + /* file seems to be a valid md3 */ + return PICO_PMV_OK; +} + + + +/* +_md3_load() +loads a quake3 arena md3 model file. +*/ + +static picoModel_t *_md3_load( PM_PARAMS_LOAD ) +{ + int i, j; + picoByte_t *bb; + md3_t *md3; + md3Surface_t *surface; + md3Shader_t *shader; + md3TexCoord_t *texCoord; + md3Frame_t *frame; + md3Triangle_t *triangle; + md3Vertex_t *vertex; + double lat, lng; + + picoModel_t *picoModel; + picoSurface_t *picoSurface; + picoShader_t *picoShader; + picoVec3_t xyz, normal; + picoVec2_t st; + picoColor_t color; + + + /* ------------------------------------------------- + md3 loading + ------------------------------------------------- */ + + + /* set as md3 */ + bb = (picoByte_t*) buffer; + md3 = (md3_t*) buffer; + + /* check ident and version */ + if( *((int*) md3->magic) != *((int*) MD3_MAGIC) || _pico_little_long( md3->version ) != MD3_VERSION ) + { + /* not an md3 file (todo: set error) */ + return NULL; + } + + /* swap md3; sea: swaps fixed */ + md3->version = _pico_little_long( md3->version ); + md3->numFrames = _pico_little_long( md3->numFrames ); + md3->numTags = _pico_little_long( md3->numTags ); + md3->numSurfaces = _pico_little_long( md3->numSurfaces ); + md3->numSkins = _pico_little_long( md3->numSkins ); + md3->ofsFrames = _pico_little_long( md3->ofsFrames ); + md3->ofsTags = _pico_little_long( md3->ofsTags ); + md3->ofsSurfaces = _pico_little_long( md3->ofsSurfaces ); + md3->ofsEnd = _pico_little_long( md3->ofsEnd ); + + /* do frame check */ + if( md3->numFrames < 1 ) + { + _pico_printf( PICO_ERROR, "MD3 with 0 frames" ); + return NULL; + } + + if( frameNum < 0 || frameNum >= md3->numFrames ) + { + _pico_printf( PICO_ERROR, "Invalid or out-of-range MD3 frame specified" ); + return NULL; + } + + /* swap frames */ + frame = (md3Frame_t*) (bb + md3->ofsFrames ); + for( i = 0; i < md3->numFrames; i++, frame++ ) + { + frame->radius = _pico_little_float( frame->radius ); + for( j = 0; j < 3; j++ ) + { + frame->bounds[ 0 ][ j ] = _pico_little_float( frame->bounds[ 0 ][ j ] ); + frame->bounds[ 1 ][ j ] = _pico_little_float( frame->bounds[ 1 ][ j ] ); + frame->localOrigin[ j ] = _pico_little_float( frame->localOrigin[ j ] ); + } + } + + /* swap surfaces */ + surface = (md3Surface_t*) (bb + md3->ofsSurfaces); + for( i = 0; i < md3->numSurfaces; i++ ) + { + /* swap surface md3; sea: swaps fixed */ + surface->flags = _pico_little_long( surface->flags ); + surface->numFrames = _pico_little_long( surface->numFrames ); + surface->numShaders = _pico_little_long( surface->numShaders ); + surface->numTriangles = _pico_little_long( surface->numTriangles ); + surface->ofsTriangles = _pico_little_long( surface->ofsTriangles ); + surface->numVerts = _pico_little_long( surface->numVerts ); + surface->ofsShaders = _pico_little_long( surface->ofsShaders ); + surface->ofsSt = _pico_little_long( surface->ofsSt ); + surface->ofsVertexes = _pico_little_long( surface->ofsVertexes ); + surface->ofsEnd = _pico_little_long( surface->ofsEnd ); + + /* swap triangles */ + triangle = (md3Triangle_t*) ((picoByte_t*) surface + surface->ofsTriangles); + for( j = 0; j < surface->numTriangles; j++, triangle++ ) + { + /* sea: swaps fixed */ + triangle->indexes[ 0 ] = _pico_little_long( triangle->indexes[ 0 ] ); + triangle->indexes[ 1 ] = _pico_little_long( triangle->indexes[ 1 ] ); + triangle->indexes[ 2 ] = _pico_little_long( triangle->indexes[ 2 ] ); + } + + /* swap st coords */ + texCoord = (md3TexCoord_t*) ((picoByte_t*) surface + surface->ofsSt); + for( j = 0; j < surface->numVerts; j++, texCoord++ ) + { + texCoord->st[ 0 ] = _pico_little_float( texCoord->st[ 0 ] ); + texCoord->st[ 1 ] = _pico_little_float( texCoord->st[ 1 ] ); + } + + /* swap xyz/normals */ + vertex = (md3Vertex_t*) ((picoByte_t*) surface + surface->ofsVertexes); + for( j = 0; j < (surface->numVerts * surface->numFrames); j++, vertex++) + { + vertex->xyz[ 0 ] = _pico_little_short( vertex->xyz[ 0 ] ); + vertex->xyz[ 1 ] = _pico_little_short( vertex->xyz[ 1 ] ); + vertex->xyz[ 2 ] = _pico_little_short( vertex->xyz[ 2 ] ); + vertex->normal = _pico_little_short( vertex->normal ); + } + + /* get next surface */ + surface = (md3Surface_t*) ((picoByte_t*) surface + surface->ofsEnd); + } + + /* ------------------------------------------------- + pico model creation + ------------------------------------------------- */ + + /* create new pico model */ + picoModel = PicoNewModel(); + if( picoModel == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); + return NULL; + } + + /* do model setup */ + PicoSetModelFrameNum( picoModel, frameNum ); + PicoSetModelNumFrames( picoModel, md3->numFrames ); /* sea */ + PicoSetModelName( picoModel, fileName ); + PicoSetModelFileName( picoModel, fileName ); + + /* md3 surfaces become picomodel surfaces */ + surface = (md3Surface_t*) (bb + md3->ofsSurfaces); + + /* run through md3 surfaces */ + for( i = 0; i < md3->numSurfaces; i++ ) + { + /* allocate new pico surface */ + picoSurface = PicoNewSurface( picoModel ); + if( picoSurface == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); + PicoFreeModel( picoModel ); /* sea */ + return NULL; + } + + /* md3 model surfaces are all triangle meshes */ + PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); + + /* set surface name */ + PicoSetSurfaceName( picoSurface, surface->name ); + + /* create new pico shader -sea */ + picoShader = PicoNewShader( picoModel ); + if( picoShader == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); + PicoFreeModel( picoModel ); + return NULL; + } + + /* detox and set shader name */ + shader = (md3Shader_t*) ((picoByte_t*) surface + surface->ofsShaders); + _pico_setfext( shader->name, "" ); + _pico_unixify( shader->name ); + PicoSetShaderName( picoShader, shader->name ); + + /* associate current surface with newly created shader */ + PicoSetSurfaceShader( picoSurface, picoShader ); + + /* copy indexes */ + triangle = (md3Triangle_t *) ((picoByte_t*) surface + surface->ofsTriangles); + + for( j = 0; j < surface->numTriangles; j++, triangle++ ) + { + PicoSetSurfaceIndex( picoSurface, (j * 3 + 0), (picoIndex_t) triangle->indexes[ 0 ] ); + PicoSetSurfaceIndex( picoSurface, (j * 3 + 1), (picoIndex_t) triangle->indexes[ 1 ] ); + PicoSetSurfaceIndex( picoSurface, (j * 3 + 2), (picoIndex_t) triangle->indexes[ 2 ] ); + } + + /* copy vertexes */ + texCoord = (md3TexCoord_t*) ((picoByte_t *) surface + surface->ofsSt); + vertex = (md3Vertex_t*) ((picoByte_t*) surface + surface->ofsVertexes + surface->numVerts * frameNum * sizeof( md3Vertex_t ) ); + _pico_set_color( color, 255, 255, 255, 255 ); + + for( j = 0; j < surface->numVerts; j++, texCoord++, vertex++ ) + { + /* set vertex origin */ + xyz[ 0 ] = MD3_SCALE * vertex->xyz[ 0 ]; + xyz[ 1 ] = MD3_SCALE * vertex->xyz[ 1 ]; + xyz[ 2 ] = MD3_SCALE * vertex->xyz[ 2 ]; + PicoSetSurfaceXYZ( picoSurface, j, xyz ); + + /* decode lat/lng normal to 3 float normal */ + lat = (float) ((vertex->normal >> 8) & 0xff); + lng = (float) (vertex->normal & 0xff); + lat *= PICO_PI / 128; + lng *= PICO_PI / 128; + normal[ 0 ] = (picoVec_t) cos( lat ) * (picoVec_t) sin( lng ); + normal[ 1 ] = (picoVec_t) sin( lat ) * (picoVec_t) sin( lng ); + normal[ 2 ] = (picoVec_t) cos( lng ); + PicoSetSurfaceNormal( picoSurface, j, normal ); + + /* set st coords */ + st[ 0 ] = texCoord->st[ 0 ]; + st[ 1 ] = texCoord->st[ 1 ]; + PicoSetSurfaceST( picoSurface, 0, j, st ); + + /* set color */ + PicoSetSurfaceColor( picoSurface, 0, j, color ); + } + + /* get next surface */ + surface = (md3Surface_t*) ((picoByte_t*) surface + surface->ofsEnd); + } + + /* return the new pico model */ + return picoModel; +} + + + +/* pico file format module definition */ +const picoModule_t picoModuleMD3 = +{ + "1.3", /* module version string */ + "Quake 3 Arena", /* module display name */ + "Randy Reddig", /* author's name */ + "2002 Randy Reddig", /* module copyright */ + { + "md3", NULL, NULL, NULL /* default extensions to use */ + }, + _md3_canload, /* validation routine */ + _md3_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_mdc.c b/libs/picomodel/pm_mdc.c new file mode 100644 index 00000000..3036d112 --- /dev/null +++ b/libs/picomodel/pm_mdc.c @@ -0,0 +1,750 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +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 names of the copyright holders 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. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PM_MDC_C + + + +/* dependencies */ +#include "picointernal.h" + +/* mdc model format */ +#define MDC_MAGIC "IDPC" +#define MDC_VERSION 2 + +/* mdc vertex scale */ +#define MDC_SCALE (1.0f / 64.0f) +#define MDC_MAX_OFS 127.0f +#define MDC_DIST_SCALE 0.05f + +/* mdc decoding normal table */ +double mdcNormals[ 256 ][ 3 ] = +{ + { 1.000000, 0.000000, 0.000000 }, + { 0.980785, 0.195090, 0.000000 }, + { 0.923880, 0.382683, 0.000000 }, + { 0.831470, 0.555570, 0.000000 }, + { 0.707107, 0.707107, 0.000000 }, + { 0.555570, 0.831470, 0.000000 }, + { 0.382683, 0.923880, 0.000000 }, + { 0.195090, 0.980785, 0.000000 }, + { -0.000000, 1.000000, 0.000000 }, + { -0.195090, 0.980785, 0.000000 }, + { -0.382683, 0.923880, 0.000000 }, + { -0.555570, 0.831470, 0.000000 }, + { -0.707107, 0.707107, 0.000000 }, + { -0.831470, 0.555570, 0.000000 }, + { -0.923880, 0.382683, 0.000000 }, + { -0.980785, 0.195090, 0.000000 }, + { -1.000000, -0.000000, 0.000000 }, + { -0.980785, -0.195090, 0.000000 }, + { -0.923880, -0.382683, 0.000000 }, + { -0.831470, -0.555570, 0.000000 }, + { -0.707107, -0.707107, 0.000000 }, + { -0.555570, -0.831469, 0.000000 }, + { -0.382684, -0.923880, 0.000000 }, + { -0.195090, -0.980785, 0.000000 }, + { 0.000000, -1.000000, 0.000000 }, + { 0.195090, -0.980785, 0.000000 }, + { 0.382684, -0.923879, 0.000000 }, + { 0.555570, -0.831470, 0.000000 }, + { 0.707107, -0.707107, 0.000000 }, + { 0.831470, -0.555570, 0.000000 }, + { 0.923880, -0.382683, 0.000000 }, + { 0.980785, -0.195090, 0.000000 }, + { 0.980785, 0.000000, -0.195090 }, + { 0.956195, 0.218245, -0.195090 }, + { 0.883657, 0.425547, -0.195090 }, + { 0.766809, 0.611510, -0.195090 }, + { 0.611510, 0.766809, -0.195090 }, + { 0.425547, 0.883657, -0.195090 }, + { 0.218245, 0.956195, -0.195090 }, + { -0.000000, 0.980785, -0.195090 }, + { -0.218245, 0.956195, -0.195090 }, + { -0.425547, 0.883657, -0.195090 }, + { -0.611510, 0.766809, -0.195090 }, + { -0.766809, 0.611510, -0.195090 }, + { -0.883657, 0.425547, -0.195090 }, + { -0.956195, 0.218245, -0.195090 }, + { -0.980785, -0.000000, -0.195090 }, + { -0.956195, -0.218245, -0.195090 }, + { -0.883657, -0.425547, -0.195090 }, + { -0.766809, -0.611510, -0.195090 }, + { -0.611510, -0.766809, -0.195090 }, + { -0.425547, -0.883657, -0.195090 }, + { -0.218245, -0.956195, -0.195090 }, + { 0.000000, -0.980785, -0.195090 }, + { 0.218245, -0.956195, -0.195090 }, + { 0.425547, -0.883657, -0.195090 }, + { 0.611510, -0.766809, -0.195090 }, + { 0.766809, -0.611510, -0.195090 }, + { 0.883657, -0.425547, -0.195090 }, + { 0.956195, -0.218245, -0.195090 }, + { 0.923880, 0.000000, -0.382683 }, + { 0.892399, 0.239118, -0.382683 }, + { 0.800103, 0.461940, -0.382683 }, + { 0.653281, 0.653281, -0.382683 }, + { 0.461940, 0.800103, -0.382683 }, + { 0.239118, 0.892399, -0.382683 }, + { -0.000000, 0.923880, -0.382683 }, + { -0.239118, 0.892399, -0.382683 }, + { -0.461940, 0.800103, -0.382683 }, + { -0.653281, 0.653281, -0.382683 }, + { -0.800103, 0.461940, -0.382683 }, + { -0.892399, 0.239118, -0.382683 }, + { -0.923880, -0.000000, -0.382683 }, + { -0.892399, -0.239118, -0.382683 }, + { -0.800103, -0.461940, -0.382683 }, + { -0.653282, -0.653281, -0.382683 }, + { -0.461940, -0.800103, -0.382683 }, + { -0.239118, -0.892399, -0.382683 }, + { 0.000000, -0.923880, -0.382683 }, + { 0.239118, -0.892399, -0.382683 }, + { 0.461940, -0.800103, -0.382683 }, + { 0.653281, -0.653282, -0.382683 }, + { 0.800103, -0.461940, -0.382683 }, + { 0.892399, -0.239117, -0.382683 }, + { 0.831470, 0.000000, -0.555570 }, + { 0.790775, 0.256938, -0.555570 }, + { 0.672673, 0.488726, -0.555570 }, + { 0.488726, 0.672673, -0.555570 }, + { 0.256938, 0.790775, -0.555570 }, + { -0.000000, 0.831470, -0.555570 }, + { -0.256938, 0.790775, -0.555570 }, + { -0.488726, 0.672673, -0.555570 }, + { -0.672673, 0.488726, -0.555570 }, + { -0.790775, 0.256938, -0.555570 }, + { -0.831470, -0.000000, -0.555570 }, + { -0.790775, -0.256938, -0.555570 }, + { -0.672673, -0.488726, -0.555570 }, + { -0.488725, -0.672673, -0.555570 }, + { -0.256938, -0.790775, -0.555570 }, + { 0.000000, -0.831470, -0.555570 }, + { 0.256938, -0.790775, -0.555570 }, + { 0.488725, -0.672673, -0.555570 }, + { 0.672673, -0.488726, -0.555570 }, + { 0.790775, -0.256938, -0.555570 }, + { 0.707107, 0.000000, -0.707107 }, + { 0.653281, 0.270598, -0.707107 }, + { 0.500000, 0.500000, -0.707107 }, + { 0.270598, 0.653281, -0.707107 }, + { -0.000000, 0.707107, -0.707107 }, + { -0.270598, 0.653282, -0.707107 }, + { -0.500000, 0.500000, -0.707107 }, + { -0.653281, 0.270598, -0.707107 }, + { -0.707107, -0.000000, -0.707107 }, + { -0.653281, -0.270598, -0.707107 }, + { -0.500000, -0.500000, -0.707107 }, + { -0.270598, -0.653281, -0.707107 }, + { 0.000000, -0.707107, -0.707107 }, + { 0.270598, -0.653281, -0.707107 }, + { 0.500000, -0.500000, -0.707107 }, + { 0.653282, -0.270598, -0.707107 }, + { 0.555570, 0.000000, -0.831470 }, + { 0.481138, 0.277785, -0.831470 }, + { 0.277785, 0.481138, -0.831470 }, + { -0.000000, 0.555570, -0.831470 }, + { -0.277785, 0.481138, -0.831470 }, + { -0.481138, 0.277785, -0.831470 }, + { -0.555570, -0.000000, -0.831470 }, + { -0.481138, -0.277785, -0.831470 }, + { -0.277785, -0.481138, -0.831470 }, + { 0.000000, -0.555570, -0.831470 }, + { 0.277785, -0.481138, -0.831470 }, + { 0.481138, -0.277785, -0.831470 }, + { 0.382683, 0.000000, -0.923880 }, + { 0.270598, 0.270598, -0.923880 }, + { -0.000000, 0.382683, -0.923880 }, + { -0.270598, 0.270598, -0.923880 }, + { -0.382683, -0.000000, -0.923880 }, + { -0.270598, -0.270598, -0.923880 }, + { 0.000000, -0.382683, -0.923880 }, + { 0.270598, -0.270598, -0.923880 }, + { 0.195090, 0.000000, -0.980785 }, + { -0.000000, 0.195090, -0.980785 }, + { -0.195090, -0.000000, -0.980785 }, + { 0.000000, -0.195090, -0.980785 }, + { 0.980785, 0.000000, 0.195090 }, + { 0.956195, 0.218245, 0.195090 }, + { 0.883657, 0.425547, 0.195090 }, + { 0.766809, 0.611510, 0.195090 }, + { 0.611510, 0.766809, 0.195090 }, + { 0.425547, 0.883657, 0.195090 }, + { 0.218245, 0.956195, 0.195090 }, + { -0.000000, 0.980785, 0.195090 }, + { -0.218245, 0.956195, 0.195090 }, + { -0.425547, 0.883657, 0.195090 }, + { -0.611510, 0.766809, 0.195090 }, + { -0.766809, 0.611510, 0.195090 }, + { -0.883657, 0.425547, 0.195090 }, + { -0.956195, 0.218245, 0.195090 }, + { -0.980785, -0.000000, 0.195090 }, + { -0.956195, -0.218245, 0.195090 }, + { -0.883657, -0.425547, 0.195090 }, + { -0.766809, -0.611510, 0.195090 }, + { -0.611510, -0.766809, 0.195090 }, + { -0.425547, -0.883657, 0.195090 }, + { -0.218245, -0.956195, 0.195090 }, + { 0.000000, -0.980785, 0.195090 }, + { 0.218245, -0.956195, 0.195090 }, + { 0.425547, -0.883657, 0.195090 }, + { 0.611510, -0.766809, 0.195090 }, + { 0.766809, -0.611510, 0.195090 }, + { 0.883657, -0.425547, 0.195090 }, + { 0.956195, -0.218245, 0.195090 }, + { 0.923880, 0.000000, 0.382683 }, + { 0.892399, 0.239118, 0.382683 }, + { 0.800103, 0.461940, 0.382683 }, + { 0.653281, 0.653281, 0.382683 }, + { 0.461940, 0.800103, 0.382683 }, + { 0.239118, 0.892399, 0.382683 }, + { -0.000000, 0.923880, 0.382683 }, + { -0.239118, 0.892399, 0.382683 }, + { -0.461940, 0.800103, 0.382683 }, + { -0.653281, 0.653281, 0.382683 }, + { -0.800103, 0.461940, 0.382683 }, + { -0.892399, 0.239118, 0.382683 }, + { -0.923880, -0.000000, 0.382683 }, + { -0.892399, -0.239118, 0.382683 }, + { -0.800103, -0.461940, 0.382683 }, + { -0.653282, -0.653281, 0.382683 }, + { -0.461940, -0.800103, 0.382683 }, + { -0.239118, -0.892399, 0.382683 }, + { 0.000000, -0.923880, 0.382683 }, + { 0.239118, -0.892399, 0.382683 }, + { 0.461940, -0.800103, 0.382683 }, + { 0.653281, -0.653282, 0.382683 }, + { 0.800103, -0.461940, 0.382683 }, + { 0.892399, -0.239117, 0.382683 }, + { 0.831470, 0.000000, 0.555570 }, + { 0.790775, 0.256938, 0.555570 }, + { 0.672673, 0.488726, 0.555570 }, + { 0.488726, 0.672673, 0.555570 }, + { 0.256938, 0.790775, 0.555570 }, + { -0.000000, 0.831470, 0.555570 }, + { -0.256938, 0.790775, 0.555570 }, + { -0.488726, 0.672673, 0.555570 }, + { -0.672673, 0.488726, 0.555570 }, + { -0.790775, 0.256938, 0.555570 }, + { -0.831470, -0.000000, 0.555570 }, + { -0.790775, -0.256938, 0.555570 }, + { -0.672673, -0.488726, 0.555570 }, + { -0.488725, -0.672673, 0.555570 }, + { -0.256938, -0.790775, 0.555570 }, + { 0.000000, -0.831470, 0.555570 }, + { 0.256938, -0.790775, 0.555570 }, + { 0.488725, -0.672673, 0.555570 }, + { 0.672673, -0.488726, 0.555570 }, + { 0.790775, -0.256938, 0.555570 }, + { 0.707107, 0.000000, 0.707107 }, + { 0.653281, 0.270598, 0.707107 }, + { 0.500000, 0.500000, 0.707107 }, + { 0.270598, 0.653281, 0.707107 }, + { -0.000000, 0.707107, 0.707107 }, + { -0.270598, 0.653282, 0.707107 }, + { -0.500000, 0.500000, 0.707107 }, + { -0.653281, 0.270598, 0.707107 }, + { -0.707107, -0.000000, 0.707107 }, + { -0.653281, -0.270598, 0.707107 }, + { -0.500000, -0.500000, 0.707107 }, + { -0.270598, -0.653281, 0.707107 }, + { 0.000000, -0.707107, 0.707107 }, + { 0.270598, -0.653281, 0.707107 }, + { 0.500000, -0.500000, 0.707107 }, + { 0.653282, -0.270598, 0.707107 }, + { 0.555570, 0.000000, 0.831470 }, + { 0.481138, 0.277785, 0.831470 }, + { 0.277785, 0.481138, 0.831470 }, + { -0.000000, 0.555570, 0.831470 }, + { -0.277785, 0.481138, 0.831470 }, + { -0.481138, 0.277785, 0.831470 }, + { -0.555570, -0.000000, 0.831470 }, + { -0.481138, -0.277785, 0.831470 }, + { -0.277785, -0.481138, 0.831470 }, + { 0.000000, -0.555570, 0.831470 }, + { 0.277785, -0.481138, 0.831470 }, + { 0.481138, -0.277785, 0.831470 }, + { 0.382683, 0.000000, 0.923880 }, + { 0.270598, 0.270598, 0.923880 }, + { -0.000000, 0.382683, 0.923880 }, + { -0.270598, 0.270598, 0.923880 }, + { -0.382683, -0.000000, 0.923880 }, + { -0.270598, -0.270598, 0.923880 }, + { 0.000000, -0.382683, 0.923880 }, + { 0.270598, -0.270598, 0.923880 }, + { 0.195090, 0.000000, 0.980785 }, + { -0.000000, 0.195090, 0.980785 }, + { -0.195090, -0.000000, 0.980785 }, + { 0.000000, -0.195090, 0.980785 } +}; + +/* mdc model frame information */ +typedef struct mdcFrame_s +{ + float bounds[ 2 ][ 3 ]; + float localOrigin[ 3 ]; + float radius; + char creator[ 16 ]; +} +mdcFrame_t; + +/* mdc model tag information */ +typedef struct mdcTag_s +{ + short xyz[3]; + short angles[3]; +} +mdcTag_t; + +/* mdc surface mdc (one object mesh) */ +typedef struct mdcSurface_s +{ + char magic[ 4 ]; + char name[ 64 ]; /* polyset name */ + int flags; + int numCompFrames; /* all surfaces in a model should have the same */ + int numBaseFrames; /* ditto */ + int numShaders; /* all model surfaces should have the same */ + int numVerts; + int numTriangles; + int ofsTriangles; + int ofsShaders; /* offset from start of mdcSurface_t */ + int ofsSt; /* texture coords are common for all frames */ + int ofsXyzNormals; /* numVerts * numBaseFrames */ + int ofsXyzCompressed; /* numVerts * numCompFrames */ + + int ofsFrameBaseFrames; /* numFrames */ + int ofsFrameCompFrames; /* numFrames */ + int ofsEnd; /* next surface follows */ +} +mdcSurface_t; + +typedef struct mdcShader_s +{ + char name[ 64 ]; + int shaderIndex; /* for ingame use */ +} +mdcShader_t; + +typedef struct mdcTriangle_s +{ + int indexes[ 3 ]; +} +mdcTriangle_t; + +typedef struct mdcTexCoord_s +{ + float st[ 2 ]; +} +mdcTexCoord_t; + +typedef struct mdcVertex_s +{ + short xyz[ 3 ]; + short normal; +} +mdcVertex_t; + +typedef struct mdcXyzCompressed_s +{ + unsigned int ofsVec; /* offset direction from the last base frame */ +} +mdcXyzCompressed_t; + + +/* mdc model file mdc structure */ +typedef struct mdc_s +{ + char magic[ 4 ]; /* MDC_MAGIC */ + int version; + char name[ 64 ]; /* model name */ + int flags; + int numFrames; + int numTags; + int numSurfaces; + int numSkins; /* number of skins for the mesh */ + int ofsFrames; /* offset for first frame */ + int ofsTagNames; /* numTags */ + int ofsTags; /* numFrames * numTags */ + int ofsSurfaces; /* first surface, others follow */ + int ofsEnd; /* end of file */ +} +mdc_t; + + + + +/* +_mdc_canload() +validates a Return to Castle Wolfenstein model file. btw, i use the +preceding underscore cause it's a static func referenced +by one structure only. +*/ + +static int _mdc_canload( PM_PARAMS_CANLOAD ) +{ + mdc_t *mdc; + + + /* to keep the compiler happy */ + *fileName = *fileName; + + /* sanity check */ + if( bufSize < ( sizeof( *mdc ) * 2) ) + return PICO_PMV_ERROR_SIZE; + + /* set as mdc */ + mdc = (mdc_t*) buffer; + + /* check mdc magic */ + if( *((int*) mdc->magic) != *((int*) MDC_MAGIC) ) + return PICO_PMV_ERROR_IDENT; + + /* check mdc version */ + if( _pico_little_long( mdc->version ) != MDC_VERSION ) + return PICO_PMV_ERROR_VERSION; + + /* file seems to be a valid mdc */ + return PICO_PMV_OK; +} + + + +/* +_mdc_load() +loads a Return to Castle Wolfenstein mdc model file. +*/ + +static picoModel_t *_mdc_load( PM_PARAMS_LOAD ) +{ + int i, j; + picoByte_t *bb; + mdc_t *mdc; + mdcSurface_t *surface; + mdcShader_t *shader; + mdcTexCoord_t *texCoord; + mdcFrame_t *frame; + mdcTriangle_t *triangle; + mdcVertex_t *vertex; + mdcXyzCompressed_t *vertexComp; + short *mdcShort, *mdcCompVert; + double lat, lng; + + picoModel_t *picoModel; + picoSurface_t *picoSurface; + picoShader_t *picoShader; + picoVec3_t xyz, normal; + picoVec2_t st; + picoColor_t color; + + + /* ------------------------------------------------- + mdc loading + ------------------------------------------------- */ + + + /* set as mdc */ + bb = (picoByte_t*) buffer; + mdc = (mdc_t*) buffer; + + /* check ident and version */ + if( *((int*) mdc->magic) != *((int*) MDC_MAGIC) || _pico_little_long( mdc->version ) != MDC_VERSION ) + { + /* not an mdc file (todo: set error) */ + return NULL; + } + + /* swap mdc */ + mdc->version = _pico_little_long( mdc->version ); + mdc->numFrames = _pico_little_long( mdc->numFrames ); + mdc->numTags = _pico_little_long( mdc->numTags ); + mdc->numSurfaces = _pico_little_long( mdc->numSurfaces ); + mdc->numSkins = _pico_little_long( mdc->numSkins ); + mdc->ofsFrames = _pico_little_long( mdc->ofsFrames ); + mdc->ofsTags = _pico_little_long( mdc->ofsTags ); + mdc->ofsTagNames = _pico_little_long( mdc->ofsTagNames ); + mdc->ofsSurfaces = _pico_little_long( mdc->ofsSurfaces ); + mdc->ofsEnd = _pico_little_long( mdc->ofsEnd ); + + /* do frame check */ + if( mdc->numFrames < 1 ) + { + _pico_printf( PICO_ERROR, "MDC with 0 frames" ); + return NULL; + } + + if( frameNum < 0 || frameNum >= mdc->numFrames ) + { + _pico_printf( PICO_ERROR, "Invalid or out-of-range MDC frame specified" ); + return NULL; + } + + /* swap frames */ + frame = (mdcFrame_t*) (bb + mdc->ofsFrames ); + for( i = 0; i < mdc->numFrames; i++, frame++ ) + { + frame->radius = _pico_little_float( frame->radius ); + for( j = 0; j < 3; j++ ) + { + frame->bounds[ 0 ][ j ] = _pico_little_float( frame->bounds[ 0 ][ j ] ); + frame->bounds[ 1 ][ j ] = _pico_little_float( frame->bounds[ 1 ][ j ] ); + frame->localOrigin[ j ] = _pico_little_float( frame->localOrigin[ j ] ); + } + } + + /* swap surfaces */ + surface = (mdcSurface_t*) (bb + mdc->ofsSurfaces); + for( i = 0; i < mdc->numSurfaces; i++ ) + { + /* swap surface mdc */ + surface->flags = _pico_little_long( surface->flags ); + surface->numBaseFrames = _pico_little_long( surface->numBaseFrames ); + surface->numCompFrames = _pico_little_long( surface->numCompFrames ); + surface->numShaders = _pico_little_long( surface->numShaders ); + surface->numTriangles = _pico_little_long( surface->numTriangles ); + surface->ofsTriangles = _pico_little_long( surface->ofsTriangles ); + surface->numVerts = _pico_little_long( surface->numVerts ); + surface->ofsShaders = _pico_little_long( surface->ofsShaders ); + surface->ofsSt = _pico_little_long( surface->ofsSt ); + surface->ofsXyzNormals = _pico_little_long( surface->ofsXyzNormals ); + surface->ofsXyzCompressed = _pico_little_long( surface->ofsXyzCompressed ); + surface->ofsFrameBaseFrames = _pico_little_long( surface->ofsFrameBaseFrames ); + surface->ofsFrameCompFrames = _pico_little_long( surface->ofsFrameCompFrames ); + surface->ofsEnd = _pico_little_long( surface->ofsEnd ); + + /* swap triangles */ + triangle = (mdcTriangle_t*) ((picoByte_t*) surface + surface->ofsTriangles); + for( j = 0; j < surface->numTriangles; j++, triangle++ ) + { + /* sea: swaps fixed */ + triangle->indexes[ 0 ] = _pico_little_long( triangle->indexes[ 0 ] ); + triangle->indexes[ 1 ] = _pico_little_long( triangle->indexes[ 1 ] ); + triangle->indexes[ 2 ] = _pico_little_long( triangle->indexes[ 2 ] ); + } + + /* swap st coords */ + texCoord = (mdcTexCoord_t*) ((picoByte_t*) surface + surface->ofsSt); + for( j = 0; j < surface->numVerts; j++, texCoord++ ) + { + texCoord->st[ 0 ] = _pico_little_float( texCoord->st[ 0 ] ); + texCoord->st[ 1 ] = _pico_little_float( texCoord->st[ 1 ] ); + } + + /* swap xyz/normals */ + vertex = (mdcVertex_t*) ((picoByte_t*) surface + surface->ofsXyzNormals); + for( j = 0; j < (surface->numVerts * surface->numBaseFrames); j++, vertex++) + { + vertex->xyz[ 0 ] = _pico_little_short( vertex->xyz[ 0 ] ); + vertex->xyz[ 1 ] = _pico_little_short( vertex->xyz[ 1 ] ); + vertex->xyz[ 2 ] = _pico_little_short( vertex->xyz[ 2 ] ); + vertex->normal = _pico_little_short( vertex->normal ); + } + + /* swap xyz/compressed */ + vertexComp = (mdcXyzCompressed_t*) ((picoByte_t*) surface + surface->ofsXyzCompressed); + for( j = 0; j < (surface->numVerts * surface->numCompFrames); j++, vertexComp++) + { + vertexComp->ofsVec = _pico_little_long( vertexComp->ofsVec ); + } + + /* swap base frames */ + mdcShort = (short *) ((picoByte_t*) surface + surface->ofsFrameBaseFrames); + for( j = 0; j < mdc->numFrames; j++, mdcShort++) + { + *mdcShort = _pico_little_short( *mdcShort ); + } + + /* swap compressed frames */ + mdcShort = (short *) ((picoByte_t*) surface + surface->ofsFrameCompFrames); + for( j = 0; j < mdc->numFrames; j++, mdcShort++) + { + *mdcShort = _pico_little_short( *mdcShort ); + } + + /* get next surface */ + surface = (mdcSurface_t*) ((picoByte_t*) surface + surface->ofsEnd); + } + + /* ------------------------------------------------- + pico model creation + ------------------------------------------------- */ + + /* create new pico model */ + picoModel = PicoNewModel(); + if( picoModel == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model" ); + return NULL; + } + + /* do model setup */ + PicoSetModelFrameNum( picoModel, frameNum ); + PicoSetModelNumFrames( picoModel, mdc->numFrames ); /* sea */ + PicoSetModelName( picoModel, fileName ); + PicoSetModelFileName( picoModel, fileName ); + + /* mdc surfaces become picomodel surfaces */ + surface = (mdcSurface_t*) (bb + mdc->ofsSurfaces); + + /* run through mdc surfaces */ + for( i = 0; i < mdc->numSurfaces; i++ ) + { + /* allocate new pico surface */ + picoSurface = PicoNewSurface( picoModel ); + if( picoSurface == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model surface" ); + PicoFreeModel( picoModel ); /* sea */ + return NULL; + } + + /* mdc model surfaces are all triangle meshes */ + PicoSetSurfaceType( picoSurface, PICO_TRIANGLES ); + + /* set surface name */ + PicoSetSurfaceName( picoSurface, surface->name ); + + /* create new pico shader -sea */ + picoShader = PicoNewShader( picoModel ); + if( picoShader == NULL ) + { + _pico_printf( PICO_ERROR, "Unable to allocate a new model shader" ); + PicoFreeModel( picoModel ); + return NULL; + } + + /* detox and set shader name */ + shader = (mdcShader_t*) ((picoByte_t*) surface + surface->ofsShaders); + _pico_setfext( shader->name, "" ); + _pico_unixify( shader->name ); + PicoSetShaderName( picoShader, shader->name ); + + /* associate current surface with newly created shader */ + PicoSetSurfaceShader( picoSurface, picoShader ); + + /* copy indexes */ + triangle = (mdcTriangle_t *) ((picoByte_t*) surface + surface->ofsTriangles); + + for( j = 0; j < surface->numTriangles; j++, triangle++ ) + { + PicoSetSurfaceIndex( picoSurface, (j * 3 + 0), (picoIndex_t) triangle->indexes[ 0 ] ); + PicoSetSurfaceIndex( picoSurface, (j * 3 + 1), (picoIndex_t) triangle->indexes[ 1 ] ); + PicoSetSurfaceIndex( picoSurface, (j * 3 + 2), (picoIndex_t) triangle->indexes[ 2 ] ); + } + + /* copy vertexes */ + texCoord = (mdcTexCoord_t*) ((picoByte_t *) surface + surface->ofsSt); + mdcShort = (short *) ((picoByte_t *) surface + surface->ofsXyzNormals) + ((int)*((short *) ((picoByte_t *) surface + surface->ofsFrameBaseFrames) + frameNum) * surface->numVerts * 4); + if( surface->numCompFrames > 0 ) + { + mdcCompVert = (short *) ((picoByte_t *) surface + surface->ofsFrameCompFrames) + frameNum; + if( *mdcCompVert >= 0 ) + vertexComp = (mdcXyzCompressed_t *) ((picoByte_t *) surface + surface->ofsXyzCompressed) + (*mdcCompVert * surface->numVerts); + } + _pico_set_color( color, 255, 255, 255, 255 ); + + for( j = 0; j < surface->numVerts; j++, texCoord++, mdcShort+=4 ) + { + /* set vertex origin */ + xyz[ 0 ] = MDC_SCALE * mdcShort[ 0 ]; + xyz[ 1 ] = MDC_SCALE * mdcShort[ 1 ]; + xyz[ 2 ] = MDC_SCALE * mdcShort[ 2 ]; + + /* add compressed ofsVec */ + if( surface->numCompFrames > 0 && *mdcCompVert >= 0 ) + { + xyz[ 0 ] += ((float) ((vertexComp->ofsVec) & 255) - MDC_MAX_OFS) * MDC_DIST_SCALE; + xyz[ 1 ] += ((float) ((vertexComp->ofsVec >> 8) & 255) - MDC_MAX_OFS) * MDC_DIST_SCALE; + xyz[ 2 ] += ((float) ((vertexComp->ofsVec >> 16) & 255) - MDC_MAX_OFS) * MDC_DIST_SCALE; + PicoSetSurfaceXYZ( picoSurface, j, xyz ); + + normal[ 0 ] = (float) mdcNormals[ (vertexComp->ofsVec >> 24) ][ 0 ]; + normal[ 1 ] = (float) mdcNormals[ (vertexComp->ofsVec >> 24) ][ 1 ]; + normal[ 2 ] = (float) mdcNormals[ (vertexComp->ofsVec >> 24) ][ 2 ]; + PicoSetSurfaceNormal( picoSurface, j, normal ); + + vertexComp++; + } + else + { + PicoSetSurfaceXYZ( picoSurface, j, xyz ); + + /* decode lat/lng normal to 3 float normal */ + lat = (float) ((*(mdcShort + 3) >> 8) & 0xff); + lng = (float) (*(mdcShort + 3) & 0xff); + lat *= PICO_PI / 128; + lng *= PICO_PI / 128; + normal[ 0 ] = (picoVec_t) cos( lat ) * (picoVec_t) sin( lng ); + normal[ 1 ] = (picoVec_t) sin( lat ) * (picoVec_t) sin( lng ); + normal[ 2 ] = (picoVec_t) cos( lng ); + PicoSetSurfaceNormal( picoSurface, j, normal ); + } + + /* set st coords */ + st[ 0 ] = texCoord->st[ 0 ]; + st[ 1 ] = texCoord->st[ 1 ]; + PicoSetSurfaceST( picoSurface, 0, j, st ); + + /* set color */ + PicoSetSurfaceColor( picoSurface, 0, j, color ); + } + + /* get next surface */ + surface = (mdcSurface_t*) ((picoByte_t*) surface + surface->ofsEnd); + } + + /* return the new pico model */ + return picoModel; +} + + + +/* pico file format module definition */ +const picoModule_t picoModuleMDC = +{ + "1.3", /* module version string */ + "RtCW MDC", /* module display name */ + "Arnout van Meer", /* author's name */ + "2002 Arnout van Meer", /* module copyright */ + { + "mdc", NULL, NULL, NULL /* default extensions to use */ + }, + _mdc_canload, /* validation routine */ + _mdc_load, /* load routine */ + NULL, /* save validation routine */ + NULL /* save routine */ +}; diff --git a/libs/picomodel/pm_ms3d.c b/libs/picomodel/pm_ms3d.c new file mode 100644 index 00000000..4bbd9b38 --- /dev/null +++ b/libs/picomodel/pm_ms3d.c @@ -0,0 +1,494 @@ +/* ----------------------------------------------------------------------------- + +PicoModel Library + +Copyright (c) 2002, Randy Reddig & seaw0lf +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 names of the copyright holders 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. + +----------------------------------------------------------------------------- */ + + + +/* marker */ +#define PM_MS3D_C + +/* dependencies */ +#include "picointernal.h" + +/* disable warnings */ +#ifdef _WIN32 +#pragma warning( disable:4100 ) /* unref param */ +#endif + +/* remarks: + * - loader seems stable + * todo: + * - fix uv coordinate problem + * - check for buffer overflows ('bufptr' accesses) + */ +/* uncomment when debugging this module */ + #define DEBUG_PM_MS3D + #define DEBUG_PM_MS3D_EX + +/* plain white */ +static picoColor_t white = { 255,255,255,255 }; + +/* ms3d limits */ +#define MS3D_MAX_VERTS 8192 +#define MS3D_MAX_TRIS 16384 +#define MS3D_MAX_GROUPS 128 +#define MS3D_MAX_MATERIALS 128 +#define MS3D_MAX_JOINTS 128 +#define MS3D_MAX_KEYFRAMES 216 + +/* ms3d flags */ +#define MS3D_SELECTED 1 +#define MS3D_HIDDEN 2 +#define MS3D_SELECTED2 4 +#define MS3D_DIRTY 8 + +/* this freaky loader needs byte alignment */ +#pragma pack(push, 1) + +/* ms3d header */ +typedef struct SMsHeader +{ + char magic[10]; + int version; +} +TMsHeader; + +/* ms3d vertex */ +typedef struct SMsVertex +{ + unsigned char flags; /* sel, sel2, or hidden */ + float xyz[3]; + char boneID; /* -1 means 'no bone' */ + unsigned char refCount; +} +TMsVertex; + +/* ms3d triangle */ +typedef struct SMsTriangle +{ + unsigned short flags; /* sel, sel2, or hidden */ + unsigned short vertexIndices[3]; + float vertexNormals[3][3]; + float s[3]; + float t[3]; + unsigned char smoothingGroup; /* 1 - 32 */ + unsigned char groupIndex; +} +TMsTriangle; + +/* ms3d material */ +typedef struct SMsMaterial +{ + char name[32]; + float ambient[4]; + float diffuse[4]; + float specular[4]; + float emissive[4]; + float shininess; /* range 0..128 */ + float transparency; /* range 0..1 */ + unsigned char mode; + char texture [128]; /* texture.bmp */ + char alphamap[128]; /* alpha.bmp */ +} +TMsMaterial; + +// ms3d group (static part) +// followed by a variable size block (see below) +typedef struct SMsGroup +{ + unsigned char flags; // sel, hidden + char name[32]; + unsigned short numTriangles; +/* + unsigned short triangleIndices[ numTriangles ]; + char materialIndex; // -1 means 'no material' +*/ +} +TMsGroup; + +// ms3d joint +typedef struct SMsJoint +{ + unsigned char flags; + char name[32]; + char parentName[32]; + float rotation[3]; + float translation[3]; + unsigned short numRotationKeyframes; + unsigned short numTranslationKeyframes; +} +TMsJoint; + +// ms3d keyframe +typedef struct SMsKeyframe +{ + float time; + float parameter[3]; +} +TMsKeyframe; + +/* restore previous data alignment */ +#pragma pack(pop) + +/* _ms3d_canload: + * validates a milkshape3d model file. + */ +static int _ms3d_canload( PM_PARAMS_CANLOAD ) +{ + TMsHeader *hdr; + + + /* to keep the compiler happy */ + *fileName = *fileName; + + /* sanity check */ + if (bufSize < sizeof(TMsHeader)) + return PICO_PMV_ERROR_SIZE; + + /* get ms3d header */ + hdr = (TMsHeader *)buffer; + + /* check ms3d magic */ + if (strncmp(hdr->magic,"MS3D000000",10) != 0) + return PICO_PMV_ERROR_IDENT; + + /* check ms3d version */ + if (_pico_little_long(hdr->version) < 3 || + _pico_little_long(hdr->version) > 4) + { + _pico_printf( PICO_ERROR,"MS3D file ignored. Only MS3D 1.3 and 1.4 is supported." ); + return PICO_PMV_ERROR_VERSION; + } + /* file seems to be a valid ms3d */ + return PICO_PMV_OK; +} + +static unsigned char *GetWord( unsigned char *bufptr, int *out ) +{ + if (bufptr == NULL) return NULL; + *out = _pico_little_short( *(unsigned short *)bufptr ); + return( bufptr + 2 ); +} + +/* _ms3d_load: + * loads a milkshape3d model file. +*/ +static picoModel_t *_ms3d_load( PM_PARAMS_LOAD ) +{ + picoModel_t *model; + unsigned char *bufptr; + int shaderRefs[ MS3D_MAX_GROUPS ]; + int numGroups; + int numMaterials; +// unsigned char *ptrToGroups; + int numVerts; + unsigned char *ptrToVerts; + int numTris; + unsigned char *ptrToTris; + int i,k,m; + + /* create new pico model */ + model = PicoNewModel(); + if (model == NULL) return NULL; + + /* do model setup */ + PicoSetModelFrameNum( model, frameNum ); + PicoSetModelName( model, fileName ); + PicoSetModelFileName( model, fileName ); + + /* skip header */ + bufptr = (unsigned char *)buffer + sizeof(TMsHeader); + + /* get number of vertices */ + bufptr = GetWord( bufptr,&numVerts ); + ptrToVerts = bufptr; + +#ifdef DEBUG_PM_MS3D + printf("NumVertices: %d\n",numVerts); +#endif + /* swap verts */ + for (i=0; ixyz[ 0 ] = _pico_little_float( vertex->xyz[ 0 ] ); + vertex->xyz[ 1 ] = _pico_little_float( vertex->xyz[ 1 ] ); + vertex->xyz[ 2 ] = _pico_little_float( vertex->xyz[ 2 ] ); + +#ifdef DEBUG_PM_MS3D_EX_ + printf("Vertex: x: %f y: %f z: %f\n", + msvd[i]->vertex[0], + msvd[i]->vertex[1], + msvd[i]->vertex[2]); +#endif + } + /* get number of triangles */ + bufptr = GetWord( bufptr,&numTris ); + ptrToTris = bufptr; + +#ifdef DEBUG_PM_MS3D + printf("NumTriangles: %d\n",numTris); +#endif + /* swap tris */ + for (i=0; iflags = _pico_little_short( triangle->flags ); + + /* run through all tri verts */ + for (k=0; k<3; k++) + { + /* swap tex coords */ + triangle->s[ k ] = _pico_little_float( triangle->s[ k ] ); + triangle->t[ k ] = _pico_little_float( triangle->t[ k ] ); + + /* swap fields */ + triangle->vertexIndices[ k ] = _pico_little_short( triangle->vertexIndices[ k ] ); + triangle->vertexNormals[ 0 ][ k ] = _pico_little_float( triangle->vertexNormals[ 0 ][ k ] ); + triangle->vertexNormals[ 1 ][ k ] = _pico_little_float( triangle->vertexNormals[ 1 ][ k ] ); + triangle->vertexNormals[ 2 ][ k ] = _pico_little_float( triangle->vertexNormals[ 2 ][ k ] ); + + /* check for out of range indices */ + if (triangle->vertexIndices[ k ] >= numVerts) + { + _pico_printf( PICO_ERROR,"Vertex %d index %d out of range (%d, max %d)",i,k,triangle->vertexIndices[k],numVerts-1); + PicoFreeModel( model ); + return NULL; /* yuck */ + } + } + } + /* get number of groups */ + bufptr = GetWord( bufptr,&numGroups ); +// ptrToGroups = bufptr; + +#ifdef DEBUG_PM_MS3D + printf("NumGroups: %d\n",numGroups); +#endif + /* run through all groups in model */ + for (i=0; i