In 1990 my friends and I started a company called Echidna. At that time we created some libraries of routines that we all shared. We needed to create titles for both the Amiga and the PC and so we wanted to create a set of libraries that would allows us to write the game once and just use a different version of the libraries for the game to run on a different platform.
Since that time, some of those routines have turned out to be more re-usable then others. Routines to do things like:
And a few other things like
These libraries are far from perfect especially since they have been updated for many years. There is still code in them for things we needed in 1990.
We learned many things on the way. One of the biggest is never use a common name. For example calling something a "Point" pretty much guarantees that someday youll have to change that code when you try to use some example 3D program you found on the net with your libraries because they also declared a type called Point.
Another example, having a define called DEBUG, TEST, WIN, MAC, WINDOWS, WIN, USA, JAPAN, FINAL, STATUS, X, Y, Z, ROM, will almost surely clash with somebody someday. The easiest solution we found is to use a prefix.
We find these libraries very useful no matter where we are working or who we are working for, yet they are our libraries and as such, when we are working for somebody else they get tense about us using them. They feel if they dont own them outright somehow that sets them up for losing out in someway even though weve assured them they can do anything they want with them.
So, in the self-interest of wanting to be able to use our libraries when and where we please we are making them copyrighted freeware. That means the copyright stays with us but anybody can use them royalty free and without restriction. We are not doing this to help others with cool routines. We are doing this solely out of self-interest. It sucks to have to re-write code. Our libraries make us more efficient and so we want to use them. This should allow us to use them anywhere unrestricted.
For those people that just dont get it and still feel they need to own the code if it is used in their product consider these facts. You dont own the code to the C library that came with your compiler nor do you own the startup code that gets linked into your program to start it nor do you own libraries like MFC, STL, OpenGL or DirectX some or all of which you are using in your code. Yet somehow that doesnt seem to bother you. Please consider our libraries to be exactly the same as those. If you want to use them go ahead and use them and dont worry about it.
You are free to download them and see if there is anything useful in them that you would like to use. Please do not ask us to support them. That is not why they are here.
These tools and libraries started in the early 1990 so some parts of it are more relevant to today then others. The parts you might find interesting
There are also several utilities written with these libraries that we find useful. Consider them the same as the libraries. They are also copyrighted freeware. Use them if you find them useful, take some code out of them and stick them in your code, you have our permission.
A lot of them were written back in the DOS days. Currently we do most of our scripting in Perl so there isn't as much of a reason for things like sizefile, longest, change, newer and riteargs but you might get some ideas for your own scripts by reading what they do.
Examples of some of the utilities:
|Bin2list||Copies a bunch of files into one file with offset pointers to them as a header table at the top of the file or as constants in a separate file.|
|Bump||Increments a version number in a .c/.h file|
|Change||Searches and replaces text.
Only simple search and replace, no fancy expressions
|Copyframes||Copies a bunch of files in alphabetical order.
This was useful for copying files to the DPS Perception video card because if you used Windows to copy the files they might not get copied in alphabetical order and the card didnt like that when assembling a new video.
|Cutbytes||Copies a specified number of bytes out of a file starting at a specified offset|
|Definer||Generates .h,.inc and other types of files
based on a .def (definition) file and an input file.
The most common use for this would be to have one .d header file to define a structure and then have definer generate the .h and .inc files for C and assembly language. This prevents a common programming error where you change a structure or constant on your .h file but forget to change it in your .inc file and then spend hours or days trying to find the bug.
This is also useful for generating .c/.h files from tables so for example of you want to make a table of monsters you can make a .md file and have definer generate a .c, .h, .inc files that have both the table and constants created. That way you only have to edit one file (.md) instead of 3 files when adding a monster to your game.
|Echecksize||Adds up the sizes of a bunch of files and
returns an error if they are over a certain size
This is useful in a build process were you want to make sure the total size of some data is not larger than some specified size. For example you want to make sure all your sounds are not more than 512K.
|Ecompare||Does a binary compare of two files and returns
error if they are different.
Useful in a build process for checking if something actually changed. For example, lets say you create a new palette and then all of your graphics need to be remapped. Well instead you could keep a copy of the old palette, generate the new palette, then use ecompare. If the new palette happens to be the same as the old palette then you dont need to re-map all your graphics.
|Egetsetdate||Copies the date from one file to another|
|Eggsfilt||Converts a C / C++ file from DOS/Unix/Mac
style to the native or specified style.
In otherwords if you run it on DOS it will default to converting the file to DOS. That means changing the line endings to DOS style endings and changing #includes from
While at the same time keeping the date the same as the original
|Elcopy||Copies a directory tree with options to copy
only newer files and files that dont exist in the destination.
It doesnt fail on exit. This is useful for copying a very large directory on a regular basis like backing up your entire project from one server to another every night.
|Etap||Same as unix tap. Copies stdin to a file and to stdout|
|Fixlines||Converts line ending from DOS/Unix/Mac to the native or specified format.|
|Hexdump||Prints a Hexdump of a file with various options for BYTE, WORDs, LONGs etc.|
|Largest||Checks the size of a file and if its
larger than the size saved in another file it updates that size.
In other words you can use it to generate a constant the size of the largest file. For example if you want to allocate a buffer the size of the largest image you could run all images through largest during your build processes and then use the result to allocate your buffer.
|Makelib||Makelib splits a .C/.CPP file into a bunch of temporary files by looking for lines that start with "/**# MODULE". The area before the first "/**# MODULE" and areas that start with "/** GLOBAL" are put in all temporary files. This allows you to create a library using one file but have it split up by routine so that when you link you get only those routines you actually use. Since the time this was written, some compiler companies do this for you automatically. Unfortunately I dont think Microsoft is one of them yet.|
|Makelist||Makes a list based on a word table.
Example. You have a file that looks like this (myspecfile)
Explosion d:\sound\exl2.wav 44k
You have another that looks like this (mywordfile)
If you run makelist like this:
Makelist myspecfile "nothing 0k" mywordfile myresult
Then myresult will look like this
|Mkloadob||Takes a "linker file" and builds a loadable binary file with lots of pointers that need to be fixed up :-)|
|Mutate||Renames files using numbers.
This was used to solve the problem that some 3D program numbered frames 0,1,2,...9,10,11...,99,100,101 which means they didn't actually sort correctly. Mutate was used to change them to 0001,0002,...0009,0010,0011 etc.
|Newer||Checks if one file is newer than another. Used in batch files to check for dependencies except now I use Perl instead|
|Parallel||Creates parallel arrays from tabular data|
|Riteargs||Writes arguments to stdout and interprets C style escape sequences|
|Sizefile||Writes the size of one file as text into
Useful for computing the exact size needed for a buffer at compile time.
|Gfxinout||Converts images to and from .PSD, .PCX, .TGA, .GFF (gff is our internal format)|
|Gfshrink||Shrinks a .GFF file|
|Gf16bit||Converts a .GFF file to a raw 16 bit per pixel file|
|Gfpal||Converts a .GFF file to a paletted file with a
There are options to:
All utilities that use the echidna argument parsing functions can take response files. If you use an @ sign on the command line the tool will read each line in that file as part of command line. Since it is parsing it as a command line that means that if it encounters another @ symbol inside that file it will start parsing that file also. This is most useful for passing lots of arguments to programs like bin2list and echecksize. Example:
--file-everylevelstuff.arp-- ; ; these files need to be in every level ; %myprojectdatadir%\mainpalette.pal %myprojectdatadir%\statusbar.img %myprojectdatadir%\player.img --file-level1.arp ; ; these files are used in level 1 ; %myprojectdatadir%\level1tiles.img %myprojectdatadir%\level1snds.snd
Now, you can run bin2list like this
Bin2list level1.dat @%myprojectdatadir%everylevelstuff.arp @%myprojectdatadir%\level1.arp
As you can see you can use multiple response files and environment variables will get expanded. (Note: Environment variables can also get expanded in our .INI file routines). You can also use a semicolon for comments.
The argument routines decide which "argument position" to assign your arguments to by filling them in from left to right. For example if you have a program that takes an INFILE and an OUTFILE and you supply two arguments then the first argument will go to INFILE and the second to OUTFILE. Arguments can be forced to a particular argument position by prefixing it with the name of the position. Example:
Myprogram OUTFILE mynewfile INFILE myoldfile
Myprogram OUTFILE=mynewfile INFILE=myoldfile
This is important especially in programs that can take multiple files in multiple positions. In order for the program to know which position to put your arguments you may have to prefix all arguments. For example of you had a program called imageprocess that could take multiple files in for both images and palettes and you wanted to use a response file it might need to look like this:
INFILE=myimage1.tga INFILE=myimage2.tga INFILE=myimage3.tga PALETTE=mypalette1.pcx PALETTE=mypalette2.pcx PALETTE=mypalette3.pcx
And then you might run the program like this
Imageprocess @response.arp myoutfile
As we are usually using these libraries on someone elses behalf as well as ours we expect that minor updates to them will not be considered proprietary to the company we are working for at the time.
Expect us to update them from time to time though not often. Some examples, there are still some defines and names that are too generic that need to be changed. For example ERRORS should be changed to EL_ERRORS and GetLine() could be changed to EL_GetLine or INI_GetLine etc. If we start using a new platform expect us to add support to these libraries. If we run into another image format that we have to read/write expect it to get added. Now that we are using C++ expect C++ classes for strings, lists, maps, arrays etc. (unless someone can teach me STL :-)
Well that depends on what your goals are. For most game companies that goal should be to make great games (and with the least amount of money). I worked for at least one company that didnt take that goal into consideration when setting their utility policy. They had an image processing utility. It ran from the command line and was script driven and would convert images to several target formats with lots of various and useful options specifically for games. Yet they would not let anybody outside of the company use that tool including outside developers working for them. In their mind this utility was a competitive advantage that they couldnt afford to let others see lest they develop something similar. But wait a minute, name one game company that doesnt have image processing tools? You cant! Why, because its impossible to make a game without them. Any and every game company will have image processing tools. If you hire an outside developer who doesnt have them or doesnt have some that will generate data for the target platform he will have to write them.
Now back to our goal. Youve hired an outside developer and given him 9 months to make a simple game for you. You have image processing tools. You have two choices: (1) Make him write his own image processing tools. Result: He spends 1 month writing image processing tools and 8 months making your game. (2) You let him use your tools. Result: He gets 9 months to write the game meaning in case 2 the game will have 1 more month of polish, or one more month of features or one more month of levels etc. Which policy meets your companys goals better?
Now expand that to include other tools. Maybe your company has sound tools or a sound library or level editing tools or 3D character exporting tools etc. Every tool/utility you can supply gives your developer that much more time to spend on the actual game instead of tools. Not giving him the tools means he had to write is own which means that not only did you not protect any technology (since he now has the same tools even if you think yours are cooler) but ultimately you screwed yourself by getting a worse game and hence worse sales than you could have.
Now Im not saying you should give your tools away publicly like we are here. Im saying that you should always think of what makes your bottom line: "I can make the most money by creating great games." Now, every decision should be based on will it make the game BETTER! If sharing your tools will make the game better then DO IT! "Trade Secrets" do not help you make money if the way you make money is by making GREAT games.
This partly explains why we made our libraries public. Our goals are also to make great games. Since we work for various different companies, in order to spend more time making games and less time writing utilities its important that we be able to use our existing libraries and utilities. If we kept them proprietary then we couldnt use them. That would hurt nobody but us. Since it is not practical for us to market, sell and support these tools, we are not losing money by making them free but we are allowing ourselves to work more efficiently wherever we are.
These are very brief and probably incomplete.
On any platform you install the libraries you will need to set the environment variable ELIBS equal to the path to the directory of the libraries. Example: You installed them in d:\work\elibs then
In unix CSH (currently Irix only)
setenv ELIBS ~/work/elibs
Every .c/.cpp/.h file must have at the top
#include "platform.h" #include "switches.h" #include <echidna\ensure.h>
The header file "platform.h" in your local directory should look like this
There needs to be a switches.h in your local directory. I can be empty but you can use it to set the following switches.
|EL_NO_ENSURE||There are a bunch of macros we call ENSURE macros (ensure.h). They are very similar to the ASSERT macro that C has but ours print more information and can be compiled out if this switch is set to 1|
|EL_DEBUG_MESSAGES||There are several macros for printing diagnostic messages (dbmess.h). Setting this to 1 will turn them on. Do not use these for printing errors for the user as they will print too much information depending on the settings.|
|EL_USE_FUNC_NAMES||The ENSURE macros have the option to print the current function by setting this to 1|
|EL_CALLTRACE_ON||The ENSURE macros have the ability to print the entire call stack if this is set to 1. You must use the BEGINFUNC/ ENDFUNC/ BEGINPROC/ ENDPROC macros and you must use them consistently in order for this to work.|
|EL_DEBUG_MEMORY||The memory routines can print allocation/de-allocation info as well as attempt to track memory over writing, double freeing, etc if this is set to 1.|
|EL_ERRORS_OFF||Many routines use the error reporting mechanism in eerrors.h. Setting this to 1 turns the messages from those errors off.|
To build the libraries:
From Windows VC++ 5.0 load the project in <installdir>/lib/echidna and compile it. You must have added <installdir>inc to your include path in the configuration settings in VC++. To build any of the utilities you will need to also put <installdir>/lib in your library path.
From an SGI go to the <installdir>/lib/echidna directory and type make f makefile.sgi
Thats about it. The rest, youre on your own.
Copyright (c) 2001-2008, Echidna
All rights reserved.
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
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.
The latest versions are available on Sourceforge.net here.